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/
/* 
 * MusicMUD - Mail module
 * Copyright (C) 1998-2003 Abigail Brady
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 * 
 */

#include <dirent.h>
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <sys/stat.h>
#include <errno.h>
#include <ctype.h>

#include "musicmud.h"
#include "util.h"
#include "verbs.h"
#include "State.h"
#include "Player.h"
#include "zoneload.h"
#include "misc.h"
#include "aberchat.h"
#include "pflags.h"
#include "paths.h"
#include "musictok.h"
#include "mailboard.h"

#define MODULE "mail"

static set<int> parse_set(const char *str)
{
  set<int> s;
  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++)
      s.insert(i);
  }
  return s;
}

static string make_set(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);
    return st;
  }
  return st;
}

static void check_mail(MudObject *who) {
    MessageFile testing(DATA_MAIL, who->id);
    if (!testing.count_messages()) {
      who->printf("You have no mail.\n");
      return;
    }

    who->printf("%s\n", title_for("Mail", who).c_str());
    who->printf("^BNew No From           Subject\n");
    string mid = "^B";
    int width = columns(who)-1;
    int i =0;
    while (width>0) {
      if (i==3 || i==6 || i==21)
	mid += "^+";
      else
	mid  += "^-";
      width--;
      i++;
    }
    mid += "^n";
    who->printf("%s\n", mid.c_str());
    set<int> todelete = parse_set(who->get("mail.todelete"));
    testing.list_contents(who, 0, &todelete);
    who->printf("%s\n", footer_for(who).c_str());
    return;
}

static void read_mail(MudObject *who, int which) {
    MessageFile testing(DATA_MAIL, who->id);
    if (!testing.show_message(who, which))
	who->printf("That message does not exist.\n");
}

static void delete_mail(MudObject *who, int which) 
{
  MessageFile testing(DATA_MAIL, who->id);
  int nth = testing.index2id(which);
  if (nth==-1) {
    who->printf("No such message.\n");
    return;
  }
  set<int> todelete = parse_set(who->get("mail.todelete"));
  todelete.insert(nth);
  who->set("mail.todelete", make_set(todelete).c_str());
  who->printf("Marked message %i to be deleted.\n", which);
}

static void undelete_mail(MudObject *who, int which) {
  MessageFile testing(DATA_MAIL, who->id);
  int nth = testing.index2id(which);
  if (nth==-1) {
    who->printf("No such message.\n");
    return;
  }
  set<int> todelete = parse_set(who->get("mail.todelete"));
  todelete.erase(nth);
  who->set("mail.todelete", make_set(todelete).c_str());
  who->printf("Marked message %i not to be deleted.\n", which);
}

static void actually_delete(MudObject *who)
{
  MessageFile testing(DATA_MAIL, who->id);
  set<int> todelete = parse_set(who->get("mail.todelete"));
  for (set<int>::iterator i=todelete.begin();i!=todelete.end();i++) {
    testing.delete_message(testing.id2index(*i));
  }
}

static string the_date() {
  return ssprintf("%i", (int)time(NULL));
}

static void compose_mail(Player *who, const char *what) {
  if (streq(what, ".") || streq(what, "**")) { 

      const char *reason = sendmail(who->get("!mail.to"),
				    bwname(who),
				    who->get("!mail.subject"),
				    the_date().c_str(),
				    who->get("!mail.buffer"));
      
      if (reason) who->printf("Can't send mail : reason : %s\n", reason);
      else who->printf("Mail sent.\n");

      who->pop_state();
      who->unset("!mail.to");
      who->unset("!mail.subject");
      who->unset("!mail.buffer");
      
      return;
      
  }

  if (streq(what, "!") || streq(what, "~")) {
    who->printf("OK. abandoning mail\n");
    who->pop_state();
    return;
  }
  
  string mailbuffer = who->get("!mail.buffer");
  mailbuffer += what;
  mailbuffer += "\n";
  who->set("!mail.buffer", mailbuffer.c_str());
}

static void subject_mail(Player *who, const char *what) {
     who->set("!mail.subject", what);
     who->set("!mail.buffer", "");
     who->set_state("mail");
     who->printf("^W.^n to send mail. ^W~^n to abandon this mail.^n\n");
}

static void start_mail(Player *who, const char *to) {

  if (!to || !strlen(to)) {
    who->printf("Mail who?\n");
    return;
  }

    string name = make_lower(to);

    if (name == "me") 
      name = who->id;

    if (!to || !player_exist(name.c_str()) && name.find('@')==string::npos) {
	who->printf("Player not found.\n");
	return;
    }
    
    who->push_state("mail.subject");
    who->set("!mail.to", name);
    who->set("!mail.buffer", "");
}

static void start_reply(Player *who, int which) {
	
    MessageFile test(DATA_MAIL, who->id);
    if (!which) {
        who->printf("syntax : r <number>\n");
        return;
    }
    if (which > test.count_messages() || which < 1) {
        who->printf("Can't find message to reply to.\n");
        return;
    }
    const char *subject = test.get_header(which, "subject");
    
    if (!subject || !strlen(subject)) {
	who->printf("Can't find message to reply to.\n");
	return;
    }
    
    const char *to = test.get_header(which, "owner");
    
    if (!to || !strlen(to)) return;
    
    who->push_state("mail");
    who->printf("^W.^n = send mail. ^W~^n to abandon this mail.^n\n");
    
    string thing;
    if (strncmp(subject, "Re:", 3)==0) 
      thing = subject;
    else 
      thing = string("Re: ") + subject;
    
    who->set("!mail.subject", thing.c_str());
    who->set("!mail.buffer", "");
    who->set("!mail.to", make_lower(to));
    
    who->printf("To: ^p%s^n\nSubject: %s\n", to, subject);
    
}

static void forward_mail(Player *who, const char *what) {

    if (!what) {
	who->printf("syntax : f <number> <who>\n");
	return;
    }
    
    int which = atoi(what);
    
    what = strchr(what, ' '); if (what) what++;
    
    if (!what || !player_exist(what)) {
	who->printf("syntax : f <number> <who>\n");
	return;
    }
    
    MessageFile test(DATA_MAIL, who->id);
    const Message *mail = test.get(which);
    
    if (!mail) {
      who->printf("Cannot find that mail...\n");
    }
		
    string subject = ssprintf("%s (Fwd)", mail->header("subject"));
    
    string buffer = ssprintf("(----forwarded message----)\n"
			     "From: %s\n"
			     "Subject: %s\n",
			     mail->header("from"), mail->header("subject")
			     );
    buffer += "\n";
    buffer += mail->data;
    
    if (const char *reason = sendmail(what,
				      bwname(who),
				      subject.c_str(),
				      the_date().c_str(),
				      buffer.c_str())) {
      who->printf("Can't send mail : reason : %s\n", reason);
    }
}

struct command {
  char c;
  string arg;

  command(char c, string arg) : c(c), arg(arg) {
  }
};

command find_command(const char *str) {
  string cmd = make_lower(str);
  string arg = "";
  if (cmd.find(' ')!=string::npos) {
    arg = cmd.substr(cmd.find(' ')+1);
    cmd = cmd.substr(0, cmd.find(' '));
  }

  struct {
    const char *command;
    char c;
  } com[] = {
    { "mail",     'm' },
    { "quit",     'q' },
    { "exit",     'x' },
    { "x",        'x' },
    { "reply",    'r' },
    { "delete",   'd' },
    { "undelete", 'u' },
    { "forward",  'f' },
    { "headers",  'h' },
    { "?",        '?' },
    { "help",     '?' },
    { NULL, },
  };

  for (size_t i=0;com[i].command;i++) {
    if (string(com[i].command, cmd.length())==cmd)
      return command(com[i].c, arg);
  }

  return command(0, "");
}

int atoi(string s) {
  return atoi(s.c_str());
}

static void state_mail(Player *who, const char *what) {
  if (!what) {
    check_mail(who);
    return;
  }
  
  who->set_bflag(FL_HASMAIL, 0);
  if (!*what) return;
	
  command cmd = find_command(what);
  switch (cmd.c) 
    {
    case 'm':
      start_mail(who, cmd.arg.c_str());
      return;

    case 'x':
      who->printf("Exiting without save.\n");
      who->pop_state();
      return;
      
    case 'q':
      who->printf("Quitting with save.\n");
      actually_delete(who);
      who->pop_state();
      return;
     
    case 'h':
      check_mail(who);
      return;

    case 'r':
      start_reply(who, atoi(cmd.arg));
      return;
      
    case 'd':
      delete_mail(who, atoi(cmd.arg));
      return;

    case 'u':
      undelete_mail(who, atoi(cmd.arg));
      return;

    case 'f':
      forward_mail(who, cmd.arg.c_str());
      return;
      
    case '?':
      who->spewfile(DATA_INFO, "mail.i");
      return;
    }
  
  int number = atoi(what);
  if (number >= 1) {
    read_mail(who, number);
  } else {
    who->printf("Not understood : %s\n", what);
  }
}


static bool verb_mail(Player *who, int argc, const char *argv[]) {
  if (argc<2) {
    who->push_state("mail.general");
    state_mail(who, 0);
    return true;
  }
  
  start_mail(who, argv[1]);
  return true;
}





#include "verbmodule.h"
void startup() {

	AUTO_VERB(mail, 4, 0, PFL_MAIL);

	ADD_STATE("mail.general", "^RMail: ^n", state_mail, false);
	ADD_STATE("mail", "Mail> ^n", compose_mail, false);
	ADD_STATE("mail.subject", "Subject: ^n", subject_mail, false);


}