musicmud-2.1.6/data/
musicmud-2.1.6/data/help/
musicmud-2.1.6/data/policy/
musicmud-2.1.6/data/wild/
musicmud-2.1.6/data/world/
musicmud-2.1.6/doc/
musicmud-2.1.6/src/ident/
musicmud-2.1.6/src/lua/
musicmud-2.1.6/src/lua/include/
musicmud-2.1.6/src/lua/src/lib/
musicmud-2.1.6/src/lua/src/lua/
musicmud-2.1.6/src/lua/src/luac/
#include <map>
#include <string>
#include <list>
#include <cctype>
#include <cstdio>

#include "musicmud.h"
#include "util.h"
#include "misc.h"
#include "musictok.h"
#include "aberchat.h"
#include "mailboard.h"
#include "zoneload.h"

using namespace std;

static void notify_mail(const char *who, const char *from) {
  MudObject *what = planet->get(who);
  if (what) {
    what->set_bflag(FL_HASMAIL, 1);
    what->printf("^YYou have new mail from %s!^n\a\n", from);
    return;
    } else {
      FILE *f = xopen(".", ssprintf(DATA_MAIL"/%s.new", who).c_str(), "w");
      if (f) {
	fprintf(f, ".\n");
	fclose(f);
      }
    }
}

static string many_of(string a, int width) {
  string f = "";
  while (width>0) {
    f += a;
    width--;
  }
  return f;
}

const char *Message::header(const char *n) const {
  if (find(n)!=end())
    return find(n)->second.c_str();
  return 0;
}

void Message::show(MudObject *who) {
  int width = columns(who)-1;
  string rule = many_of("^=", width);
  string rule2 = many_of("^-", width);
  
  who->printf("^B%s^n\n", rule.c_str());
  who->printf("From:    ^p%s^n\n", header("from"));
  who->printf("Subject: ^Z%s\n", header("subject"));
  
  struct tm tm;
  strptime(header("date"), "%c", &tm);
  time_t newtime = mktime(&tm);
  
  who->printf("Date:    %s\n", ctime_for(who, &newtime));
  who->printf("^B%s^n\n", rule2.c_str());
  who->printf("%s", data.c_str());
  who->printf("^B%s^n\n", rule.c_str());
}

const Message *MessageFile::get(int idx) {
  list<Message>::iterator i = msg.begin();
  int count = 1;
  while (i != msg.end()) {
    if (count == idx)
      return &*i;
    
    i++;
    count++;
  }
  return 0;
}

set<int> MessageFile::get_seen(MudObject *who, int min)
{
  set<int> s;
  if (!who)
    return s;
  const char *str = who->get(propname());
  if (!str)
    return s;
  StrTok t(str);
  while (const char *a=t.next(",")) {
    int an = atoi(a), tn = an;
    char *hyp = strchr(a, '-');
    if (hyp)
      tn = atoi(hyp+1);
    
    for (int i=an;i<=tn;i++)
      if (i >= min)
	s.insert(i);
  }
  return s;
}

void MessageFile::set_seen(MudObject *who, const set<int> &s)
{
  set<int>::iterator i = s.begin();
  string st = "";
  int spanfirst = -1;
  int spanlast = -1;
  while (i != s.end()) {
    int thisi = *i;
    if (spanfirst == -1) {
      spanfirst = thisi;
      spanlast = thisi;
      i++;
      continue;
    }
    if (thisi == (spanlast+1)) {
      spanlast = thisi;
    } else {
      st += ssprintf(spanfirst==spanlast?"%i,":"%i-%i,", spanfirst, spanlast);
      spanfirst = thisi;
      spanlast = thisi;
    }
    i++;
  }
    if (spanlast != -1)
      st += ssprintf(spanfirst==spanlast?"%i,":"%i-%i,", spanfirst, spanlast);
    if (st.length()) {
      st.erase(st.length()-1);
      who->set(propname(), st.c_str());
    } else {
      who->unset(propname());
    }
}

int MessageFile::count_messages() {
  return msg.size();
}

int MessageFile::count_new(MudObject *who)
{
  set<int> seen = get_seen(who);
  int news = 0;
  list<Message>::iterator i = msg.begin();
  while (i != msg.end()) {
    int id = atoi(i->header("id"));
    if (seen.find(id) == seen.end()) {
      news++;
    }
    i++;
  }
  return news;
}

int MessageFile::index2id(int idx) {
  list<Message>::iterator i = msg.begin();
  int count = 1;
  while (i != msg.end()) {
    if (count == idx)
      return atoi(i->header("id"));
    
      i++;
      count++;
  }
  return -1;
}

int MessageFile::id2index(int id) {
  list<Message>::iterator i = msg.begin();
  int count = 1;
  while (i != msg.end()) {
    int thisid = atoi(i->header("id"));
    if (thisid == id)
      return count;
    
    i++;
    count++;
    }
  return -1;
}

void MessageFile::list_contents(MudObject *who, const char *cmd, set<int> *td)
{
  int count = 1;
  set<int> seen = get_seen(who);
  list<Message>::iterator i = msg.begin();
  while (i != msg.end()) {
    const char *m = " ";
      int id = atoi(i->header("id"));
      if (seen.find(id) == seen.end()) {
      	m = "^Y*^n";
      }
      if (td && td->find(id) != td->end()) {
	m = "^RD^n";
      }
      string link = ssprintf("\3send href='%s%i'\4%i^n\3/send\4", cmd, count, count);
      who->printf(" %s ^G%3s ^p%-14s^n ^Z%s\n", 
		  m,
		  link.c_str(),
		  i->header("from"),
		  i->header("subject"));
      count++;
      i++;
    }
  }

  bool MessageFile::show_message(MudObject *who, int which)
  {
    /// XXX : implement "read first new" as which==-1
    list<Message>::iterator i = msg.begin();
    set<int> seen = get_seen(who);
    int count = 1;
    while (i != msg.end()) {
      if (count == which) {
	i->show(who);
	
	seen.insert(atoi(i->header("id")));
	set_seen(who, seen);

	return 1;
      }
      i++;
      count++;
    }
    return 0;
  }

  void MessageFile::send_message(const char *name, const char *owner,
		    const char *subject, const char *date,
		    const char *data) {
    Message m;
    m.data = data;
    m["from"] = name;
    m["owner"] = owner;
    m["subject"] = subject;
    string dat = date;
    if (dat.find('\n')!=string::npos) {
      dat = dat.substr(0, dat.find('\n'));
      date = dat.c_str();
    }
    
    m["date"] = date;
    
    maxid++;

    m["id"] = ssprintf("%i", maxid);

    msg.push_back(m);

    output();
  }

  const char *MessageFile::get_header(int which, const char *b)
  {
    list<Message>::iterator i = msg.begin();
    int count = 1;
    while (i != msg.end()) {
      if (count == which) {
	return i->header(b);
      }
      i++;
      count++;
    }
    return 0;
  }

  void MessageFile::delete_message(int id)
  {
    list<Message>::iterator i = msg.begin();
    int count = 1;
    while (i != msg.end()) {
      if (count == id) {
	msg.erase(i);
	output();
	return;
      }

      i++;
      count++;
    }
  }

  void MessageFile::output() {
    FILE *f = xopen(m_dir.c_str(), (m_file+".tmp").c_str(), "w");
    if (!f)
      return;

    fprintf(f, "%06i\n\n", maxid);
    list<Message>::iterator i = msg.begin();
    while (i != msg.end()) {
      Message a = *i;
      fprintf(f, "__POST\n");
      fprintf(f, "From: %s\n", a["from"].c_str());
      fprintf(f, "Owner: %s\n", a["owner"].c_str());
      fprintf(f, "Subject: %s\n", a["subject"].c_str());
      fprintf(f, "Date: %s\n", a["date"].c_str());
      fprintf(f, "ID: %s\n", a["id"].c_str());

      a.erase("from");
      a.erase("owner");
      a.erase("subject");
      a.erase("date");
      a.erase("id");

      fprintf(f, "\n");
      fprintf(f, "%s", a.data.c_str());

      i++;
    }
    
    fclose(f);
    rename((m_dir+"/"+m_file+".tmp").c_str(), (m_dir+"/"+m_file).c_str());
  }

  MessageFile::MessageFile(const char *dir, const char *file) : maxid(0) {
    this->prop = "seen-";
    if (strstr(dir, "news")) {
      this->prop += "news-";
      this->prop += file;
    }
    if (strstr(dir, "mail"))
      this->prop += "mail";

    m_dir = dir;
    m_file = file;
	
    FILE *f = xopen(dir, file, "r");
    if (!f) {
      maxid = 0;
      return;
    }

    maxid = atoi(getline(f).c_str());

    while (getline(f) != "");

    while (1) {
      string s = getline(f);
      if (feof(f))
	break;
    eep:
      if (s == "__POST") {
	Message m;
	while (1) {
	  s = getline(f);
	  if (feof(f))
	    break;
	  string field = s.substr(0, s.find(':'));
	  for (size_t i=0;i<field.length();i++) {
	    field[i] = tolower(field[i]);
	  }
	  if (s == "")
	    break;
	  m[field] = s.substr(s.find(':')+2);
	}
	string data;
	while (1) {
	  string tl = getline(f);
	  if (feof(f)) {
	    break;
	  }
	  if (tl == "__POST") {
	    s = tl;
	    m.data = data;
	    msg.push_back(m);
	    goto eep;
	  }
	  data += tl;
	  data += "\n";
	}

	m.data = data;
	msg.push_back(m);
      }
    }

    xclose(f);
  }

const char *sendmail(const char *to, const char *from,
	      const char *subj, const char *date,
	      const char *data) {
  if (strlen(to)>100)
    return 0;

  if (strchr(to, '.'))
    return 0;

  if (strchr(to, '/'))
    return 0;

  string t = to;
  for (size_t i=0;i<t.length();i++) t[i] = tolower(t[i]);

  if (strchr(to, '@')) {
    string tomud = t.substr(t.find('@')+1);
    string touse = t.substr(0, t.find('@'));

    if (abermail_hook) {
      abermail_hook(from, touse.c_str(), tomud.c_str(), subj, date, data);
      return 0;
    }

    return "oops";
  }

  MessageFile f(DATA_MAIL, to);

  time_t when = (time_t)atoi(date);
  if (!when) when = now;

  f.send_message(from, from, subj, ctime(&when), data);
  notify_mail(to, from);
  return 0;
}