#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <string.h> #include "externs.h" #include "db.h" #include "mail.h" int num_mail = 0; MLIST *mlist_list = NULL; extern int quiet_reboot; int mail_size(OBJ *player) { long size = 0; MAIL *m; for(m = player->mail;m;m = m->next) size += sizeof(MAIL)+strlen(m->message)+1; return(size); } void check_mail(OBJ *player, int new_only) { int new = 0, total = 0; MAIL *m; char buf[4096]; for(m = player->mail;m;m = m->next) { total++; if(m->flags & MF_NEW) new++; } if(new_only && !new) return; sprintf(buf, "|+W|You have |+Y|%d|+W| message%s.", total, check_plural(total, "", "s")); if(new) sprintf(buf+strlen(buf), " |+G|%d|+W| of them %s new.", new, check_plural(new, "is", "are")); notify(player, buf); } MAIL *new_mail(OBJ *player) { MAIL *m, *new; new = (MAIL *)stack_alloc(sizeof(MAIL), 1, 0); new->next = NULL; if(!player->mail) player->mail = new; else { for(m = player->mail;m->next;m = m->next); m->next = new; } num_mail++; return(new); } static void send_mail_as(OBJ *from, OBJ *recip, char *message, time_t when, int donotify, int flags) { MAIL *m; m = new_mail(recip); m->from = from; m->date = when; m->rdate = (time_t)0; /* Hasn't been read yet */ m->flags = flags; m->message = stack_string_alloc(message, 1); notify(recip, tprintf("You have new mail from %s.", unparse_object(recip, from))); } static void send_mail(OBJ *from, char *recip, char *message, int maillist) { int flags = MF_NEW; OBJ *who; who = match_player(NULL, recip); if(maillist == 2) { if(!who) return; flags |= MF_MAILLIST; } if(maillist == 1) { if(!who) { notify(from, no_match(recip)); return; } if(!could_doit(from, who, "LPAGE")) { notify(from, tprintf("%s isn't accepting +mail from you.", unparse_object(from, who))); return; } } send_mail_as(from, who, message, now, maillist, flags); if(maillist == 1) notify(from, tprintf("You mailed %s with: %s", unparse_object(from, who), message)); } static MAIL *get_mail(OBJ *player, int msgnum) { MAIL *m; int i = 1; if(msgnum < 1) return((MAIL *)NULL); for(m = player->mail;m && i < msgnum;m = m->next) i++; return(m); } static void do_protect_mail(OBJ *player, char *arg) { int msgnum = atoi(arg); MAIL *m; if(!(m = get_mail(player, msgnum))) { notify(player, "No such message number."); return; } if(m->flags & MF_PROTECTED) { m->flags &= ~MF_PROTECTED; notify(player, tprintf("Message %d has been unprotected.", msgnum)); } else { m->flags |= MF_PROTECTED; notify(player, tprintf("Message %d has been protected.", msgnum)); } } static void delete_mail(OBJ *player, MAIL *mail) { MAIL *m, *mprev = NULL; for(m = player->mail;m;m = m->next) { if(m == mail) break; mprev = m; } if(!m) return; if(mprev) mprev->next = m->next; else player->mail = m->next; if(m->message) stack_free(m->message); stack_free(m); num_mail--; } static void del_msg(OBJ *player, char *arg) { MAIL *m; int msgnum = atoi(arg); int protected = 0; int deleted = 0; if(string_compare(arg, "all")) { if(!(m = get_mail(player, msgnum))) { notify(player, "No such message number."); return; } if(m->flags & MF_PROTECTED) { notify(player, "You can't delete a protected message!"); return; } delete_mail(player, m); notify(player, tprintf("Message %d deleted.", msgnum)); return; } for(m = player->mail;m;m = m->next) { if(m->flags & MF_PROTECTED) { protected++; continue; } deleted++; delete_mail(player, m); } notify(player, tprintf("%d message%s deleted.", deleted, check_plural(deleted, " was", "s were"))); if(protected) notify(player, tprintf("You have %d protected message%s.", protected, check_plural(protected, "", "s"))); } static void show_mail(OBJ *player, char *arg) { MAIL *m; int msgnum = atoi(arg); char buf[4096]; if(!(m = get_mail(player, msgnum))) { notify(player, "No such message number."); return; } notify(player, tprintf("Message %d:", msgnum)); notify(player, tprintf("To: %s", name(player))); notify(player, tprintf("From: %s", unparse_object(player, m->from))); notify(player, tprintf("Date: %s", mktm(m->date, "D", player))); if(m->flags & MF_READ) notify(player, tprintf("Read: %s", mktm(m->rdate, "D", player))); strcpy(buf, "Flags:"); if(m->flags & MF_READ) strcat(buf, " read"); if(m->flags & MF_NEW) strcat(buf, " new"); if(m->flags & MF_MAILLIST) strcat(buf, " maillist"); if(m->flags & MF_PROTECTED) strcat(buf, " protected"); notify(player, buf); notify(player, ""); notify(player, m->message); m->flags &= ~MF_NEW; m->flags |= MF_READ; m->rdate = now; } static void list_mail(OBJ *player) { char status[20]; MAIL *m; int ctr = 0; for(m = player->mail;m;m = m->next) { status[0] = (m->flags & MF_PROTECTED)?'P':' '; status[1] = (m->flags & MF_MAILLIST)?'M':' '; status[2] = (m->flags & MF_NEW)?'*':' '; status[3] = '\0'; ctr++; notify(player, tprintf("%3d) %s %s %s", ctr, status, unparse_object(player, m->from), mktm(m->date, "D", player))); } if(!ctr) notify(player, "You have no mail."); } void do_mailcmd(OBJ *player, char *arg1, char *arg2) { do_mail(player, arg1, arg2, 1); } void do_mail(OBJ *player, char *arg1, char *arg2, int donotify) { if(Typeof(player) != TYPE_PLAYER || Guest(player)) { notify(player, "Sorry, only real players can use mail."); return; } if(!*arg1) list_mail(player); else if(!*arg2) show_mail(player, arg1); else if(string_prefix("delete", arg1)) del_msg(player, arg2); else if(string_prefix("protect", arg1)) do_protect_mail(player, arg2); else send_mail(player, arg1, arg2, donotify); } void write_mail() { FILE *fp; OBJ *o; MAIL *m; int num; if((fp = fopen(config.maildb_name, "w")) == NULL) { log_error("Mail save failed! Uh oh!"); return; } fprintf(fp, "%d\n", num_mail); for(o = player_list;o;o = o->next) { for(m = o->mail, num = 0;m;m = m->next, num++); if(!num) continue; fprintf(fp, "%d\n", o->dbref); fprintf(fp, "%d\n", num); for(m = o->mail;m;m = m->next) { fprintf(fp, "%d\n", m->from->dbref); fprintf(fp, "%ld\n", m->date); fprintf(fp, "%ld\n", m->rdate); fprintf(fp, "%d\n", m->flags); fprintf(fp, "%s\n", m->message); } } fclose(fp); } void read_mail() { FILE *fp; char buf[1024]; int total = 0; int total_mail; int num; OBJ *player; MAIL *m; if((fp = fopen(config.maildb_name, "r")) == NULL) { log_error("Couldn't open maildb for reading!"); return; } fgets(buf, sizeof(buf), fp); total_mail = atoi(buf); while(total++ < total_mail) { fgets(buf, sizeof(buf), fp); player = find_object(atoi(buf)); fgets(buf, sizeof(buf), fp); num = atoi(buf); while(num--) { if(!player) { fgets(buf, sizeof(buf), fp); fgets(buf, sizeof(buf), fp); fgets(buf, sizeof(buf), fp); fgets(buf, sizeof(buf), fp); fgets(buf, sizeof(buf), fp); continue; } m = new_mail(player); fgets(buf, sizeof(buf), fp); if(!(m->from = find_object(atoi(buf)))) { m->message = NULL; delete_mail(player, m); /* Bad, bad, bad */ fgets(buf, sizeof(buf), fp); fgets(buf, sizeof(buf), fp); fgets(buf, sizeof(buf), fp); fgets(buf, sizeof(buf), fp); continue; } fgets(buf, sizeof(buf), fp); m->date = atol(buf); fgets(buf, sizeof(buf), fp); m->rdate = atol(buf); fgets(buf, sizeof(buf), fp); m->flags = atoi(buf); fgets(buf, sizeof(buf), fp); *(buf+strlen(buf)-1) = '\0'; m->message = stack_string_alloc(buf, 1); } } fclose(fp); if(!quiet_reboot) { notify_all2(tprintf("%s total message%s (%s bytes).", comma(tprintf("%d", num_mail)), check_plural(num_mail, "", "s"), comma(tprintf("%ld", file_size(config.maildb_name)))), NULL); flush_all_output(); } } void free_mail(OBJ *player) { MAIL *m, *mnext; for(m = player->mail;m;m = mnext) { mnext = m->next; stack_free(m->message); stack_free(m); } } void clear_old_mail() { OBJ *o; int num_msgs; MAIL *m; time_t diff; /* Clears old read mail from the database, using the value set in * * config.c as the age of the mail. If the age is 0, nothing is deleted * * at all. */ if(config.max_mail_age == 0) return; for(o = player_list;o;o = o->next) { num_msgs = 0; for(m = o->mail;m;m = m->next) if(m->flags & MF_READ && !(m->flags & MF_PROTECTED)) { diff = now-m->rdate; if(diff >= config.max_mail_age) { delete_mail(o, m); num_msgs++; } } if(num_msgs > 0) { notify(o, tprintf("%d of your old, read +mail messages %s deleted.", num_msgs, check_plural(num_msgs, "was", "were"))); log_important(tprintf("Cleared %d message%s from %s.", num_msgs, check_plural(num_msgs, "", "s"), unparse_object(o, o))); } } } MLIST *find_mlist(char *arg) { MLIST *m; for(m = mlist_list;m;m = m->next) if(!string_compare(m->name, arg)) break; return(m); } char is_on_mlist(OBJ *player, MLIST *mlist) { int i; for(i = 0;mlist->members[i];i++) if(mlist->members[i] == player) return(1); return(0); } static MLIST *new_mlist(char *mlist_name) { MLIST *mnew; mnew = (MLIST *)stack_alloc(sizeof(MLIST), 1, 0); mnew->name = stack_string_alloc(mlist_name, 1); mnew->members = (OBJ **)stack_alloc(sizeof(OBJ *), 1, 0); mnew->members[0] = NULL; mnew->last_post = 0; if(!mlist_list) { mnew->next = NULL; mlist_list = mnew; } else { mnew->next = mlist_list; mlist_list = mnew; } return(mnew); } static void add_to_mlist(OBJ *player, MLIST *m) { int i; /* Just in case someone's a moron */ if(is_on_mlist(player, m)) return; for(i = 0;m->members[i];++i); /* Whole loop */ if(!m->members) m->members = (OBJ **)stack_alloc(sizeof(OBJ *), 1, 0); else m->members = (OBJ **)stack_realloc(m->members, sizeof(OBJ *)*(i+2)); m->members[i] = player; m->members[i+1] = NULL; } static void do_join_mlist(OBJ *player, char *mlist_name) { MLIST *m; if(!(m = find_mlist(mlist_name))) { notify(player, tprintf("Mailing list \"%s\" doesn't exist.", mlist_name)); return; } if(is_on_mlist(player, m)) { notify(player, tprintf("You're already on the \"%s\" mailing list!", mlist_name)); return; } add_to_mlist(player, m); notify(player, tprintf("You have joined the \"%s\" mailing list.", m->name)); } static void del_from_mlist(OBJ *player, MLIST *m) { int i, j; for(i = 0;m->members[i];i++) if(m->members[i] == player) break; if(!m->members[i]) return; for(j = i+1;m->members[j];j++, i++) m->members[i] = m->members[j]; m->members[i] = NULL; m->members = (OBJ **)stack_realloc(m->members, sizeof(OBJ *)*j); } static void del_mlist(MLIST *mlist) { MLIST *m, *mprev = NULL; for(m = mlist_list;m;m = m->next) { if(m == mlist) break; mprev = m; } if(!m) return; if(!mprev) mlist_list = mlist_list->next; else mprev->next = m->next; stack_free(m->name); stack_free(m->members); stack_free(m); } static void do_leave_mlist(OBJ *player, char *mlist_name) { MLIST *m; if(!(m = find_mlist(mlist_name))) { notify(player, tprintf("Mailing list \"%s\" doesn't exist.", mlist_name)); return; } if(!is_on_mlist(player, m)) { notify(player, tprintf("You're not on the \"%s\" mailing list!", mlist_name)); return; } del_from_mlist(player, m); notify(player, tprintf("You have left the \"%s\" mailing list.", mlist_name)); /* See if it should be destroyed */ if(!m->members[0]) { del_mlist(m); notify(player, tprintf("Mailing list \"%s\" has been destroyed.", mlist_name)); } } static void do_create_mlist(OBJ *player, char *mlist_name) { MLIST *mnew; strcpy(mlist_name, strip_color(mlist_name)); if(find_mlist(mlist_name)) { notify(player, tprintf("Mailing list \"%s\" already exists.", mlist_name)); return; } if(!string_compare("create", mlist_name) || *mlist_name == '+' || *mlist_name == '-') { notify(player, tprintf("Sorry, \"%s\" is an illegal name.", mlist_name)); return; } mnew = new_mlist(mlist_name); add_to_mlist(player, mnew); notify(player, tprintf("Mailing list \"%s\" has been created.", mlist_name)); } static void do_del_mlist(OBJ *player, char *mlist_name) { MLIST *m; int i; char buf[4096]; if(!(m = find_mlist(mlist_name))) { notify(player, tprintf("Mailing list \"%s\" doesn't exist.", mlist_name)); return; } if(!power(player, POW_SECURITY)) { notify(player, "A mailing list will be automatically deleted when there are no players on the list."); return; } sprintf(buf, "The mailing list \"%s\" was deleted.", m->name); for(i = 0;m->members[i];++i) send_mail_as(root_obj, m->members[i], buf, now, 0, MF_NEW); del_mlist(m); notify(player, buf); } static void do_list_mlist(OBJ *player, char *mlist) { MLIST *m; int i; if(!mlist_list) { notify(player, "There aren't any mailing lists."); return; } if(!*mlist) { notify(player, tprintf("|+B|.%s.", my_string("-", 49))); notify(player, tprintf("|+B|||+W|%s|+B||", my_center("Mailing Lists", 49))); notify(player, tprintf("|+B||%s|", my_string("-", 49))); notify(player, tprintf("|+B|||+W|%s|+B|| |+W|Mbrs |+B|||+W|%s|+B||", my_center("Name", 15), my_center("Last Posted To", 26))); notify(player, tprintf("|+B||%s|------|%s|", my_string("-", 15), my_string("-", 26))); for(m = mlist_list;m;m = m->next) { for(i = 0;m->members[i];i++); notify(player, tprintf("|+B|||+W|%c|+B|%s|+B|||+Y| %4d |+B|| |+C|%s |+B||", (is_on_mlist(player, m))?'*':' ', my_ljust(m->name, 14), i, (!(m->last_post))?my_ljust("NEVER", 24): mktm(m->last_post, "D", player))); } notify(player, tprintf("|+B|`%s'", my_string("-", 49))); return; } if(!(m = find_mlist(mlist))) { notify(player, tprintf("Mailing list \"%s\" doesn't exist!", mlist)); return; } notify(player, tprintf("|+W|Members of the \"%s\" mailing list:", m->name)); for(i = 0;m->members[i];++i) notify(player, unparse_object(player, m->members[i])); notify(player, tprintf("|+W|%d |+B|Total Member%s", i, check_plural(i, "", "s"))); } static void do_send_to_mlist(OBJ *player, char *arg1, char *arg2) { MLIST *m; int i; char buf[4096]; if(!(m = find_mlist(arg1))) { notify(player, tprintf("Mailing list \"%s\" doesn't exist!", arg1)); return; } if(!is_on_mlist(player, m)) { notify(player, tprintf("You're not on the \"%s\" mailing list!", m->name)); return; } if(!*arg2) { notify(player, "You must include a message!"); return; } sprintf(buf, "|+B|Mailing list|+W|: |+Y|%s|n| |+W|-|n| ", m->name); if(*arg2 == POSE_TOKEN) sprintf(buf+strlen(buf), "%s %s", name(player), arg2+1); else if(*arg2 == POSS_TOKEN) sprintf(buf+strlen(buf), "%s %s", poss(player), arg2+1); else strcat(buf, arg2); for(i = 0;m->members[i];++i) send_mail(player, tprintf("#%d", m->members[i]->dbref), buf, 2); notify(player, tprintf("Your message was posted to the \"%s\" mailing list.", m->name)); m->last_post = now; } void do_mlist(OBJ *player, char *arg1, char *arg2) { int help; SUBCOMMAND *sc, commands[] = { { "create", do_create_mlist, 0 }, { "delete", do_del_mlist, 0 }, { "list", do_list_mlist, 0 }, { NULL } }; if(*arg1 == '+') { do_join_mlist(player, arg1+1); return; } if(*arg1 == '-') { do_leave_mlist(player, arg1+1); return; } if(!(sc = subcommand_match(player, arg1, commands, &help))) { if(help) subcommand_print(player, "+mlist", commands); else do_send_to_mlist(player, arg1, arg2); } else sc->func(player, arg2); } void load_maillists() { char buf[4096]; char *filename = "db/mlist.db"; FILE *fp; int total, members; MLIST *m; if(!quiet_reboot) { notify_all2("Loading maillists...", NULL); flush_all_output(); } if(!(fp = fopen(filename, "r"))) { log_error(tprintf("Couldn't open \"%s\" for reading!", filename)); return; } fgets(buf, sizeof(buf), fp); total = atoi(buf); while(total--) { fgets(buf, sizeof(buf), fp); *(buf+strlen(buf)-1) = '\0'; m = new_mlist(buf); fgets(buf, sizeof(buf), fp); m->last_post = atol(buf); fgets(buf, sizeof(buf), fp); members = atoi(buf); while(members--) { fgets(buf, sizeof(buf), fp); add_to_mlist(find_object(atoi(buf)), m); } } fclose(fp); } void save_maillists() { MLIST *m; char *filename = "db/mlist.db"; FILE *fp; int total = 0, members; if(!(fp = fopen(filename, "w"))) { log_error(tprintf("Couldn't open \"%s\" for writing!", filename)); return; } for(m = mlist_list;m;m = m->next) total++; fprintf(fp, "%d\n", total); for(m = mlist_list;m;m = m->next) { fprintf(fp, "%s\n", m->name); fprintf(fp, "%ld\n", m->last_post); for(members = 0;m->members[members];members++); fprintf(fp, "%d\n", members); for(members = 0;m->members[members];members++) fprintf(fp, "%d\n", m->members[members]->dbref); } fclose(fp); } void remove_from_mlists(OBJ *player) { MLIST *m; for(m = mlist_list;m;m = m->next) if(is_on_mlist(player, m)) del_from_mlist(player, m); } void do_dirmail(OBJ *player, char *arg) { OBJ *o; int ctr = 0; char buf[1000]; if(!power(player, POW_BROADCAST)) { notify(player, perm_denied()); return; } if(!*arg) { notify(player, "You must include a message!"); return; } sprintf(buf, "--- DirMail --- %s", arg); for(o = player_list;o;o = o->next) if(!is_root(o) && o != player) if(Wizard(o)) { ctr++; send_mail(player, tprintf("#%d", o->dbref), buf, 0); } if(!ctr) notify(player, "There's no one to send the mail to!"); else { notify(player, tprintf("|+W|You mailed every %s with:", class_to_name(CLASS_DIR))); notify(player, arg); } } void do_massmail(OBJ *player, char *msg) { OBJ *o; char buf[4096]; if(!power(player, POW_BROADCAST)) { notify(player, perm_denied()); return; } if(!*msg) { notify(player, "You must include a message!"); return; } for(o = player_list;o;o = o->next) if(!is_root(o) && o != player) { sprintf(buf, "--- MassMail --- %s", msg); send_mail(player, tprintf("#%d", o->dbref), buf, 0); } notify(player, "|+W|You mailed everyone with:"); notify(player, msg); } void free_mlists(void) { MLIST *m, *mnext; for(m = mlist_list;m;m = mnext) { mnext = m->next; stack_free(m->name); stack_free(m->members); stack_free(m); } }