/* * 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); }