#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include "externs.h" #include "db.h" #include "nalloc.h" int mdb_alloc; int mdb_top; int mdb_first_free; extern NALLOC *glurp; typedef int mdbref; #define NOMAIL ((mdbref)-1) struct mdb_entry { dbref from; long date; int flags; /* see the following. */ #define MF_DELETED 1 #define MF_READ 2 #define MF_NEW 4 char *message; /* null if unused entry */ mdbref next; /* next garbage, or next message. */ } *mdb; static #ifdef __GNUC__ inline #endif mdbref get_mailk(player) dbref player; { char *i; if (!*(i=atr_get(player,A_MAILK))) return NOMAIL; else return atoi(i); } static #ifdef __GNUC__ inline #endif void set_mailk(player, mailk) dbref player; mdbref mailk; { char buf[20]; sprintf(buf,"%d",mailk); atr_add(player,A_MAILK,buf); } void check_mail(player) dbref player; { if (get_mailk(player) != NOMAIL) { int read=0, new=0, tot=0; char buf[1024]; mdbref i; for(i=get_mailk(player); i != NOMAIL; i=mdb[i].next) { if (mdb[i].flags&MF_READ) read++; if (mdb[i].flags&MF_NEW) new++; if (!(mdb[i].flags&MF_DELETED)) tot++; } sprintf(buf,"You have %d message%s.",tot,(tot==1)?"":"s"); if (new) { sprintf(buf+strlen(buf)," %d of them %s new.",new,(new==1)?"is":"are"); if ((tot-read-new)>0) sprintf(buf+strlen(buf)-1,"; %d other%s unread.",tot-read-new,(tot-read-new==1)?" is":"s are"); } else if ((tot-read)>0) sprintf(buf+strlen(buf)," %d of them %s unread.",tot-read,(tot-read==1)?"is":"are"); notify(player,buf); } } static mdbref grab_free_mail_slot() { if (mdb_first_free != NOMAIL) if (mdb[mdb_first_free].message) { log_error("+mail's first_free's message isn't null!"); mdb_first_free = NOMAIL; } else { mdbref z=mdb_first_free; mdb_first_free = mdb[mdb_first_free].next; return z; } if (++mdb_top >= mdb_alloc) { mdb_alloc *= 2; mdb = realloc(mdb,sizeof(struct mdb_entry) * mdb_alloc); } mdb[mdb_top-1].message = NULL; return mdb_top-1; } static void make_free_mail_slot(i) mdbref i; { if (mdb[i].message) free(mdb[i].message); mdb[i].message = NULL; mdb[i].next = mdb_first_free; mdb_first_free = i; } void init_mail() { mdb_top = 0; mdb_alloc = 512; mdb = malloc(sizeof(struct mdb_entry)*mdb_alloc); mdb_first_free = NOMAIL; } void free_mail() { int i; for (i=0; i<mdb_top; i++) if (mdb[i].message) free(mdb[i].message); if (mdb) free(mdb); } static void send_mail_as(from,recip,message,when,flags) dbref from,recip; char *message; time_t when; int flags; { mdbref i, prev=NOMAIL; int msgno=1; for (i=get_mailk(recip); i!=NOMAIL; i=mdb[i].next) if (mdb[i].flags&MF_DELETED) { /* we found a spot! */ break; } else { prev=i; msgno++; } if (i == NOMAIL) { /* sigh. no deleted messages to fill in. we'll have to tack a */ /* new one on the end. */ if (prev == NOMAIL) { /* they've got no mail at all. */ i = grab_free_mail_slot(); set_mailk(recip,i); } else { mdb[prev].next = i = grab_free_mail_slot(); } mdb[i].next = NOMAIL; } mdb[i].from = from; mdb[i].date = when; mdb[i].flags = flags; SET(mdb[i].message, message); if (from != NOTHING) notify(recip,tprintf("You sense that you have new mail from %s (message number %d)",unparse_object(recip,from),msgno)); else notify(recip,"You sense that you have new mail."); } void send_mail(from,recip,message) dbref from,recip; char *message; { send_mail_as(from,recip,message,time(NULL),MF_NEW); } void do_mail(player,arg1,arg2) dbref player; char *arg1; char *arg2; { if (Typeof(player)!=TYPE_PLAYER || Guest(player)) { notify(player,"Sorry, only real players can use mail."); return; } if (!string_compare(arg1,"delete")) { /* delete a message. */ mdbref i; int num; if (*arg2) { num = atoi(arg2); if (num <= 0) { notify(player,"You have no such message."); return; } for (i=get_mailk(player); i!=NOMAIL && 0<--num; i=mdb[i].next); if (i == NOMAIL) notify(player,"You have no such message."); else { mdb[i].flags = MF_DELETED; notify(player, "Ok, deleted."); } } else { for (i=get_mailk(player); i!=NOMAIL; i=mdb[i].next) mdb[i].flags = MF_DELETED; notify(player, "All messages deleted."); } } else if (!string_compare(arg1,"undelete")) { /* delete a message. */ mdbref i; int num; if (*arg2) { num = atoi(arg2); if (num <= 0) { notify(player,"You have no such message."); return; } for (i=get_mailk(player); i!=NOMAIL && 0<--num; i=mdb[i].next); if (i == NOMAIL) notify(player,"You have no such message."); else { mdb[i].flags = MF_READ; notify(player, "Ok, undeleted."); } } else { for (i=get_mailk(player); i!=NOMAIL; i=mdb[i].next) mdb[i].flags = MF_READ; notify(player, "All messages undeleted."); } } else if (!string_compare(arg1, "purge")) { /* purge deleted messages. */ mdbref i,next; mdbref prev=NOMAIL; for (i=get_mailk(player); i!=NOMAIL; i=next) { next = mdb[i].next; if (mdb[i].flags&MF_DELETED) { if (prev != NOMAIL) mdb[prev].next = mdb[i].next; else set_mailk(player,mdb[i].next); make_free_mail_slot(i); } else prev=i; } notify(player,"deleted messages purged."); } else if (*arg1 && !*arg2) { /* must be reading a message. */ int i,k; mdbref j=NOMAIL; char buf[1024]; k=i=atoi(arg1); if (i>0) for (j=get_mailk(player); j != NOMAIL && i>1; j=mdb[j].next, i--); if (j == NOMAIL) { notify(player,"Invalid message number."); return; } notify(player,tprintf("Message %d:",k)); notify(player,tprintf("From: %s",(mdb[j].from != NOTHING)?unparse_object(player,mdb[j].from):"The MUSE server")); sprintf(buf,"Date: %s",mktm(mdb[j].date,"D",player)); notify(player,buf); strcpy(buf,"Flags:"); if (mdb[j].flags&MF_DELETED) strcat(buf," deleted"); if (mdb[j].flags&MF_READ) strcat(buf," read"); if (mdb[j].flags&MF_NEW) strcat(buf," new"); notify(player,buf); if (power(player,POW_SECURITY)) notify(player,tprintf("Mailk: %d",j)); notify(player,""); notify(player,mdb[j].message); mdb[j].flags &=~MF_NEW; mdb[j].flags |= MF_READ; } else if (!*arg1 && !*arg2) { /* list mail. */ mdbref j; int i=1; char buf[1024]; for (j=get_mailk(player); j!=NOMAIL; j=mdb[j].next, i++) { char status='u'; if (mdb[j].flags&MF_DELETED) status='d'; else if (mdb[j].flags&MF_NEW) { status='*'; mdb[j].flags &= ~MF_NEW; } else if (mdb[j].flags&MF_READ) status=' '; sprintf(buf,tprintf("%3d) %c %s %s",i,status,unparse_object(player,mdb[j].from),mktm(mdb[j].date,"D",player))); notify(player,buf); } notify(player,""); } else if (!*arg1 && *arg2) notify(player,"You want to do what?"); else if (*arg1 && *arg2) { /* send mail */ dbref recip; recip = lookup_player(arg1); if (recip == NOTHING || Typeof(recip) != TYPE_PLAYER) { notify(player,"i haven't a clue who you're talking about."); return; } send_mail(player,recip,arg2); notify(player,tprintf("You mailed %s with '%s'",unparse_object(player,recip),arg2)); } else log_error(tprintf("We shouldn't get here +mail. arg1: %s. arg2: %s.",arg1,arg2)); } void write_mail(f) FILE *f; { dbref d; mdbref i; for (d=0; d<db_top; d++) if (Typeof(d)==TYPE_PLAYER && (i=get_mailk(d))!=NOMAIL) for (; i != NOMAIL; i=mdb[i].next) if (!(mdb[i].flags&MF_DELETED)) fprintf(f,"+%d:%d:%d:%d:%s\n",mdb[i].from,d,mdb[i].date,mdb[i].flags,mdb[i].message); } void read_mail(f) FILE *f; { char buf[2048]; dbref to; dbref from; time_t date; int flags; char message[1024]; char *s; while (fgets(buf, 2048, f)) { if (*buf == '+') { from = atoi(s=buf+1); if ((s=strchr(buf,':'))) { to = atoi(++s); if ((s=strchr(s,':'))) { date = atoi(++s); if ((s=strchr(s,':'))) { flags = atoi(++s); if ((s=strchr(s,':'))) { strcpy (message, ++s); if ((s=strchr(message,'\n'))) { *s = '\0'; /* a good one. we just ignore bad ones. */ send_mail_as(from,to,message,date,flags); } } } } } } } }