#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);
}
}
}
}
}
}
}
}