/* mail.c - module for penn-based mailer system */
/* $Id: mail.c,v 1.72 2004/02/23 04:35:15 rmg Exp $ */
/*
* This code was taken from Kalkin's DarkZone code, which was
* originally taken from PennMUSH 1.50 p10, and has been heavily modified
* since being included in MUX (and then being imported wholesale into 3.0).
*
* -------------------------------------------------------------------
*/
#include "../../api.h"
#include "mail.h"
/* --------------------------------------------------------------------------
* Configuration.
*/
#define MAIL_STATS 1 /* Mail stats */
#define MAIL_DSTATS 2 /* More mail stats */
#define MAIL_FSTATS 3 /* Even more mail stats */
#define MAIL_DEBUG 4 /* Various debugging options */
#define MAIL_NUKE 5 /* Nuke the post office */
#define MAIL_FOLDER 6 /* Do folder stuff */
#define MAIL_LIST 7 /* List @mail by time */
#define MAIL_READ 8 /* Read @mail message */
#define MAIL_CLEAR 9 /* Clear @mail message */
#define MAIL_UNCLEAR 10 /* Unclear @mail message */
#define MAIL_PURGE 11 /* Purge cleared @mail messages */
#define MAIL_FILE 12 /* File @mail in folders */
#define MAIL_TAG 13 /* Tag @mail messages */
#define MAIL_UNTAG 14 /* Untag @mail messages */
#define MAIL_FORWARD 15 /* Forward @mail messages */
#define MAIL_SEND 16 /* Send @mail messages in progress */
#define MAIL_EDIT 17 /* Edit @mail messages in progress */
#define MAIL_URGENT 18 /* Sends a @mail message as URGENT */
#define MAIL_ALIAS 19 /* Creates an @mail alias */
#define MAIL_ALIST 20 /* Lists @mail aliases */
#define MAIL_PROOF 21 /* Proofs @mail messages in progress */
#define MAIL_ABORT 22 /* Aborts @mail messages in progress */
#define MAIL_QUICK 23 /* Sends a quick @mail message */
#define MAIL_REVIEW 24 /* Reviews @mail sent to a player */
#define MAIL_RETRACT 25 /* Retracts @mail sent to a player */
#define MAIL_CC 26 /* Carbon copy */
#define MAIL_SAFE 27 /* Defines a piece of mail as safe. */
#define MAIL_REPLY 28 /* Replies to a message. */
#define MAIL_REPLYALL 29 /* Replies to all recipients of msg */
#define MAIL_TO 30 /* Set recipient list */
#define MAIL_BCC 31 /* Blind Carbon copy */
#define MAIL_QUOTE 0x100 /* Quote back original in the reply? */
/* Note that we don't use all hex for mail flags, because the upper 3 bits
* of the switch word gets occupied by SW_<foo>.
*/
#define MALIAS_DESC 1 /* Describes a mail alias */
#define MALIAS_CHOWN 2 /* Changes a mail alias's owner */
#define MALIAS_ADD 3 /* Adds a player to an alias */
#define MALIAS_REMOVE 4 /* Removes a player from an alias */
#define MALIAS_DELETE 5 /* Deletes a mail alias */
#define MALIAS_RENAME 6 /* Renames a mail alias */
#define MALIAS_LIST 8 /* Lists mail aliases */
#define MALIAS_STATUS 9 /* Status of mail aliases */
NHSHTAB mod_mail_msg_htab;
MODNHASHES mod_mail_nhashtable[] = {
{ "Mail messages", &mod_mail_msg_htab, 50, 8},
{ NULL, NULL, 0, 0}};
struct mod_mail_confstorage {
int mail_expiration; /* Number of days to wait to delete mail */
int mail_freelist; /* The next free mail number */
MENT *mail_list; /* The mail database */
int mail_db_top; /* Like db_top */
int mail_db_size; /* Like db_size */
} mod_mail_config;
CONF mod_mail_conftable[] = {
{(char *)"mail_expiration", cf_int, CA_GOD, CA_PUBLIC, &mod_mail_config.mail_expiration, 0},
{ NULL, NULL, 0, 0, NULL, 0}};
extern int FDECL(do_convtime, (char *, struct tm *));
static int FDECL(sign, (int));
static void FDECL(do_mail_flags, (dbref, char *, mail_flag, int));
static void FDECL(send_mail, (dbref, dbref, const char *, const char *, \
const char *, const char *, int, mail_flag, \
int));
static int FDECL(player_folder, (dbref));
static int FDECL(parse_msglist, (char *, struct mail_selector *, dbref));
static int FDECL(mail_match, (struct mail *, struct mail_selector, int));
static int FDECL(parse_folder, (dbref, char *));
static char *FDECL(status_chars, (struct mail *));
static char *FDECL(status_string, (struct mail *));
void FDECL(add_folder_name, (dbref, int, char *));
static int FDECL(get_folder_number, (dbref, char *));
void FDECL(check_mail, (dbref, int, int));
static char *FDECL(get_folder_name, (dbref, int));
static char *FDECL(mail_list_time, (const char *));
static char *FDECL(make_numlist, (dbref, char *));
static char *FDECL(make_namelist, (dbref, char *));
static void FDECL(mail_to_list, (dbref, char *, char *, char *, char *, \
char *, int, int));
static void FDECL(do_edit_msg, (dbref, char *, char *));
static void FDECL(do_mail_proof, (dbref));
static void FDECL(do_mail_to, (dbref, char *, int));
static int FDECL(do_expmail_start, (dbref, char *, char *, char *));
static void FDECL(do_expmail_stop, (dbref, int));
static void FDECL(do_expmail_abort, (dbref));
struct mail *FDECL(mail_fetch, (dbref, int));
#define MALIAS_LEN 100
struct malias {
int owner;
char *name;
char *desc;
int numrecep;
dbref list[MALIAS_LEN];
};
int ma_size = 0;
int ma_top = 0;
struct malias **malias;
/*
* Handling functions for the database of mail messages.
*/
/*
* mail_db_grow - We keep a database of mail text, so if we send a message to
* more than one player, we won't have to duplicate the text.
*/
static void mail_db_grow(newtop)
int newtop;
{
int newsize, i;
MENT *newdb;
if (newtop <= mod_mail_config.mail_db_top) {
return;
}
if (newtop <= mod_mail_config.mail_db_size) {
for (i = mod_mail_config.mail_db_top; i < newtop; i++) {
mod_mail_config.mail_list[i].count = 0;
mod_mail_config.mail_list[i].message = NULL;
}
mod_mail_config.mail_db_top = newtop;
return;
}
if (newtop <= mod_mail_config.mail_db_size + 100) {
newsize = mod_mail_config.mail_db_size + 100;
} else {
newsize = newtop;
}
newdb = (MENT *) XMALLOC((newsize + 1) * sizeof(MENT), "mail_db_grow");
if (!newdb) {
fprintf(mainlog_fp, "ABORT! mail.c, unable to malloc new db in mail_db_grow().\n");
abort();
}
if (mod_mail_config.mail_list) {
mod_mail_config.mail_list -= 1;
memcpy((char *)newdb, (char *)mod_mail_config.mail_list,
(mod_mail_config.mail_db_top + 1) * sizeof(MENT));
XFREE(mod_mail_config.mail_list, "mail_list");
}
mod_mail_config.mail_list = newdb + 1;
newdb = NULL;
for (i = mod_mail_config.mail_db_top; i < newtop; i++) {
mod_mail_config.mail_list[i].count = 0;
mod_mail_config.mail_list[i].message = NULL;
}
mod_mail_config.mail_db_top = newtop;
mod_mail_config.mail_db_size = newsize;
}
/*
* make_mail_freelist - move the freelist to the first empty slot in the mail
* * database.
*/
static void make_mail_freelist()
{
int i;
for (i = 0; i < mod_mail_config.mail_db_top; i++) {
if (mod_mail_config.mail_list[i].message == NULL) {
mod_mail_config.mail_freelist = i;
return;
}
}
mail_db_grow(i + 1);
mod_mail_config.mail_freelist = i;
}
/*
* add_mail_message - adds a new text message to the mail database, and returns
* * a unique number for that message.
*/
static int add_mail_message(player, message)
dbref player;
char *message;
{
int number;
char *atrstr, *execstr, *bp, *str;
int aflags, alen;
dbref aowner;
if (!mod_mail_config.mail_list) {
mail_db_grow(1);
}
/*
* Add an extra bit of protection here
*/
while (mod_mail_config.mail_list[mod_mail_config.mail_freelist].message != NULL) {
make_mail_freelist();
}
number = mod_mail_config.mail_freelist;
atrstr = atr_get(player, A_SIGNATURE, &aowner, &aflags, &alen);
execstr = bp = alloc_lbuf("add_mail_message");
str = atrstr;
exec(execstr, &bp, player, player, player,
EV_STRIP | EV_FCHECK | EV_EVAL, &str, (char **)NULL, 0);
mod_mail_config.mail_list[number].message = XSTRDUP(tprintf("%s %s", message, execstr), "add_mail_message");
free_lbuf(atrstr);
free_lbuf(execstr);
make_mail_freelist();
return number;
}
/*
* add_mail_message_nosig - used for reading in old style messages from disk
*/
static int add_mail_message_nosig(message)
char *message;
{
int number;
number = mod_mail_config.mail_freelist;
if (!mod_mail_config.mail_list) {
mail_db_grow(1);
}
mod_mail_config.mail_list[number].message = XSTRDUP(message, "add_mail_message_nosig");
make_mail_freelist();
return number;
}
/*
* new_mail_message - used for reading messages in from disk which already have
* * a number assigned to them.
*/
static void new_mail_message(message, number)
char *message;
int number;
{
mod_mail_config.mail_list[number].message = XSTRDUP(message, "new_mail_message");
}
/*
* add_count - increments the reference count for any particular message
*/
static INLINE void add_count(number)
int number;
{
mod_mail_config.mail_list[number].count++;
}
/*
* delete_mail_message - decrements the reference count for a message, and
* * deletes the message if the counter reaches 0.
*/
static void delete_mail_message(number)
int number;
{
mod_mail_config.mail_list[number].count--;
if (mod_mail_config.mail_list[number].count < 1) {
XFREE(mod_mail_config.mail_list[number].message, "delete_mail");
mod_mail_config.mail_list[number].message = NULL;
mod_mail_config.mail_list[number].count = 0;
}
}
/*
* get_mail_message - returns the text for a particular number. This text
* should NOT be modified.
*/
INLINE char *get_mail_message(number)
int number;
{
static char err[] = "MAIL: This mail message does not exist in the database. Please alert your admin.";
if (mod_mail_config.mail_list[number].message != NULL) {
return mod_mail_config.mail_list[number].message;
} else {
delete_mail_message(number);
return err;
}
}
/*-------------------------------------------------------------------------*
* User mail functions (these are called from game.c)
*
* do_mail - cases
* do_mail_read - read messages
* do_mail_list - list messages
* do_mail_flags - tagging, untagging, clearing, unclearing of messages
* do_mail_file - files messages into a new folder
* do_mail_fwd - forward messages to another player(s)
* do_mail_reply - reply to a message
* do_mail_purge - purge cleared messages
* do_mail_change_folder - change current folder
*-------------------------------------------------------------------------*/
extern char *FDECL(upcasestr, (char *));
/*
* Change or rename a folder
*/
void do_mail_change_folder(player, fld, newname)
dbref player;
char *fld;
char *newname;
{
int pfld;
char *p;
if (!fld || !*fld) {
/*
* Check mail in all folders
*/
for (pfld = MAX_FOLDERS; pfld >= 0; pfld--)
check_mail(player, pfld, 1);
pfld = player_folder(player);
notify(player, tprintf("MAIL: Current folder is %d [%s].",
pfld, get_folder_name(player, pfld)));
return;
}
pfld = parse_folder(player, fld);
if (pfld < 0) {
notify(player, "MAIL: What folder is that?");
return;
}
if (newname && *newname) {
/*
* We're changing a folder name here
*/
if (strlen(newname) > FOLDER_NAME_LEN) {
notify(player, "MAIL: Folder name too long");
return;
}
for (p = newname; p && *p; p++) {
if (!isalnum(*p)) {
notify(player, "MAIL: Illegal folder name");
return;
}
}
add_folder_name(player, pfld, newname);
notify(player, tprintf("MAIL: Folder %d now named '%s'", pfld, newname));
} else {
/*
* Set a new folder
*/
set_player_folder(player, pfld);
notify(player, tprintf("MAIL: Current folder set to %d [%s].",
pfld, get_folder_name(player, pfld)));
}
}
void do_mail_tag(player, msglist)
dbref player;
char *msglist;
{
do_mail_flags(player, msglist, M_TAG, 0);
}
void do_mail_safe(player, msglist)
dbref player;
char *msglist;
{
do_mail_flags(player, msglist, M_SAFE, 0);
}
void do_mail_clear(player, msglist)
dbref player;
char *msglist;
{
do_mail_flags(player, msglist, M_CLEARED, 0);
}
void do_mail_untag(player, msglist)
dbref player;
char *msglist;
{
do_mail_flags(player, msglist, M_TAG, 1);
}
void do_mail_unclear(player, msglist)
dbref player;
char *msglist;
{
do_mail_flags(player, msglist, M_CLEARED, 1);
}
/*
* adjust the flags of a set of messages
*/
static void do_mail_flags(player, msglist, flag, negate)
dbref player;
char *msglist;
mail_flag flag;
int negate; /* if 1, clear the flag */
{
struct mail *mp;
struct mail_selector ms;
int i = 0, j = 0, folder;
if (!parse_msglist(msglist, &ms, player)) {
return;
}
folder = player_folder(player);
for (mp = (struct mail *)nhashfind((int)player, &mod_mail_msg_htab);
mp; mp = mp->next) {
if (All(ms) || (Folder(mp) == folder)) {
i++;
if (mail_match(mp, ms, i)) {
j++;
if (negate) {
mp->read &= ~flag;
} else {
mp->read |= flag;
}
switch (flag) {
case M_TAG:
notify(player, tprintf("MAIL: Msg #%d %s.", i,
negate ? "untagged" : "tagged"));
break;
case M_CLEARED:
if (Unread(mp) && !negate) {
notify(player,
tprintf("MAIL: Unread Msg #%d cleared! Use @mail/unclear %d to recover.", i, i));
} else {
notify(player, tprintf("MAIL: Msg #%d %s.", i,
negate ? "uncleared" : "cleared"));
}
break;
case M_SAFE:
notify(player, tprintf("MAIL: Msg #%d marked safe.", i));
break;
}
}
}
}
if (!j) {
/*
* ran off the end of the list without finding anything
*/
notify(player, "MAIL: You don't have any matching messages!");
}
}
/*
* Change a message's folder
*/
void do_mail_file(player, msglist, folder)
dbref player;
char *msglist;
char *folder;
{
struct mail *mp;
struct mail_selector ms;
int foldernum, origfold;
int i = 0, j = 0;
if (!parse_msglist(msglist, &ms, player)) {
return;
}
if ((foldernum = parse_folder(player, folder)) == -1) {
notify(player, "MAIL: Invalid folder specification");
return;
}
origfold = player_folder(player);
for (mp = (struct mail *)nhashfind((int)player, &mod_mail_msg_htab);
mp; mp = mp->next) {
if (All(ms) || (Folder(mp) == origfold)) {
i++;
if (mail_match(mp, ms, i)) {
j++;
mp->read &= M_FMASK; /*
* Clear the folder
*/
mp->read |= FolderBit(foldernum);
notify(player, tprintf("MAIL: Msg %d filed in folder %d", i, foldernum));
}
}
}
if (!j) {
/*
* ran off the end of the list without finding anything
*/
notify(player, "MAIL: You don't have any matching messages!");
}
}
/*
* print a mail message(s)
*/
void do_mail_read(player, msglist)
dbref player;
char *msglist;
{
struct mail *mp;
char *tbuf1, *buff, *status, *names, *ccnames;
struct mail_selector ms;
int i = 0, j = 0, folder;
tbuf1 = alloc_lbuf("do_mail_read");
if (!parse_msglist(msglist, &ms, player)) {
free_lbuf(tbuf1);
return;
}
folder = player_folder(player);
for (mp = (struct mail *)nhashfind((int)player, &mod_mail_msg_htab);
mp; mp = mp->next) {
if (Folder(mp) == folder) {
i++;
if (mail_match(mp, ms, i)) {
/*
* Read it
*/
j++;
buff = alloc_lbuf("do_mail_read");
StringCopy(buff, get_mail_message(mp->number));
notify(player, DASH_LINE);
status = status_string(mp);
names = make_namelist(player, (char *)mp->tolist);
ccnames = make_namelist(player, (char *)mp->cclist);
notify(player, tprintf("%-3d From: %-*s At: %-25s %s\r\nFldr : %-2d Status: %s\r\nTo : %-65s",
i,
PLAYER_NAME_LIMIT - 6,
Name(mp->from),
mp->time,
(Connected(mp->from) && (!Hidden(mp->from) || See_Hidden(player))) ? " (Conn)" : " ",
folder,
status,
names));
if (*ccnames)
notify(player, tprintf("Cc : %-65s", ccnames));
notify(player, tprintf("Subject: %-65s", mp->subject));
free_lbuf(names);
free_lbuf(ccnames);
free_lbuf(status);
notify(player, DASH_LINE);
StringCopy(tbuf1, buff);
notify(player, tbuf1);
notify(player, DASH_LINE);
free_lbuf(buff);
if (Unread(mp)) {
/* mark message as read */
mp->read |= M_ISREAD;
}
}
}
}
if (!j) {
/*
* ran off the end of the list without finding anything
*/
notify(player, "MAIL: You don't have that many matching messages!");
}
free_lbuf(tbuf1);
}
void do_mail_retract(player, name, msglist)
dbref player;
char *name, *msglist;
{
dbref target;
struct mail *mp, *nextp;
struct mail_selector ms;
int i = 0, j = 0;
target = lookup_player(player, name, 1);
if (target == NOTHING) {
notify(player, "MAIL: No such player.");
return;
}
if (!parse_msglist(msglist, &ms, player)) {
return;
}
for (mp = (struct mail *)nhashfind((int)target, &mod_mail_msg_htab);
mp; mp = nextp) {
if (mp->from == player) {
i++;
if (mail_match(mp, ms, i)) {
j++;
if (Unread(mp)) {
if (mp->prev == NULL)
nhashrepl((int)target,
(int *)mp->next,
&mod_mail_msg_htab);
else if (mp->next == NULL)
mp->prev->next = NULL;
if (mp->prev != NULL)
mp->prev->next = mp->next;
if (mp->next != NULL)
mp->next->prev = mp->prev;
nextp = mp->next;
XFREE(mp->subject,
"mail_retract.subject");
delete_mail_message(mp->number);
XFREE(mp->time,
"mail_retract.time");
XFREE(mp->tolist,
"mail_retract.tolist");
XFREE(mp->cclist,
"mail_retract.cclist");
XFREE(mp->bcclist,
"mail_retract.bcclist");
XFREE(mp, "mail_retract");
notify(player,
"MAIL: Mail retracted.");
} else {
notify(player, "MAIL: That message has been read.");
nextp = mp->next;
}
} else {
nextp = mp->next;
}
} else {
nextp = mp->next;
}
}
if (!j) {
/*
* ran off the end of the list without finding anything
*/
notify(player, "MAIL: No matching messages.");
}
}
void do_mail_review(player, name, msglist)
dbref player;
char *name;
char *msglist;
{
struct mail *mp;
struct mail_selector ms;
int i = 0, j = 0;
dbref target, thing;
char *status, *names, *ccnames, *bccnames;
int all = 0;
if (!*name || !strcmp(name, "all")) {
target = player;
all = 1;
} else {
target = lookup_player(player, name, 1);
if (target == NOTHING) {
notify(player, "MAIL: No such player.");
return;
}
}
if (!msglist || !*msglist) {
/* no specific list of messages to review -- either see all to
* one player, or all sent
*/
notify(player, tprintf("%.*s MAIL: %s %.*s",
(63 - strlen(Name(target))) >> 1,
"--------------------------------",
Name(target),
(64 - strlen(Name(target))) >> 1,
"--------------------------------"));
if (all) {
/* ok, review all sent messages */
MAIL_ITER_ALL(mp, thing) {
if (mp->from == player) {
i++;
/*
* list it
*/
notify(player, tprintf("[%s] %-3d (%4d) To: %-*s Sub: %.25s",
status_chars(mp),
i,
strlen(get_mail_message(mp->number)),
PLAYER_NAME_LIMIT - 6,
Name(mp->to),
mp->subject));
}
}
} else {
/* review all messages we sent to the target */
for (mp = (struct mail *)nhashfind((int)target, &mod_mail_msg_htab); mp; mp = mp->next) {
if (mp->from == player) {
i++;
/*
* list it
*/
notify(player, tprintf("[%s] %-3d (%4d) To: %-*s Sub: %.25s",
status_chars(mp),
i,
strlen(get_mail_message(mp->number)),
PLAYER_NAME_LIMIT - 6,
Name(mp->to),
mp->subject));
}
}
}
notify(player, DASH_LINE);
} else {
/* specific list of messages, either chosen from all our sent
* messages, or from messages sent to a particular player
*/
if (!parse_msglist(msglist, &ms, player)) {
return;
}
if (all) {
/* ok, choose messages from among all sent */
MAIL_ITER_ALL(mp, thing){
if (mp->from == player) {
i++;
if (mail_match(mp, ms, i)) {
/*
* Read it
*/
j++;
status = status_string(mp);
names = make_namelist(player, (char *)mp->tolist);
ccnames = make_namelist(player, (char *)mp->cclist);
bccnames = make_namelist(player, (char *)mp->bcclist);
notify(player, DASH_LINE);
notify(player, tprintf("%-3d From: %-*s At: %-25s\r\nFldr : %-2d Status: %s\r\nTo : %-65s",
i, PLAYER_NAME_LIMIT - 6, Name(mp->from), mp->time, 0, status, names));
if (*ccnames)
notify(player, tprintf("Cc : %-65s", ccnames));
if (*bccnames)
notify(player, tprintf("Bcc : %-65s", bccnames));
notify(player, tprintf("Subject: %-65s", mp->subject));
free_lbuf(status);
free_lbuf(names);
free_lbuf(ccnames);
free_lbuf(bccnames);
notify(player, DASH_LINE);
notify(player, get_mail_message(mp->number));
notify(player, DASH_LINE);
}
}
}
} else {
/* choose messages from among those sent to a
* particular player
*/
for (mp = (struct mail *)nhashfind((int)target, &mod_mail_msg_htab); mp; mp = mp->next) {
if (mp->from == player) {
i++;
if (mail_match(mp, ms, i)) {
/*
* Read it
*/
j++;
status = status_string(mp);
names = make_namelist(player, (char *)mp->tolist);
ccnames = make_namelist(player, (char *)mp->cclist);
bccnames = make_namelist(player, (char *)mp->bcclist);
notify(player, DASH_LINE);
notify(player, tprintf("%-3d From: %-*s At: %-25s\r\nFldr : %-2d Status: %s\r\nTo : %-65s",
i, PLAYER_NAME_LIMIT - 6, Name(mp->from), mp->time, 0, status, names));
if (*ccnames)
notify(player, tprintf("Cc : %-65s", ccnames));
if (*bccnames)
notify(player, tprintf("Bcc : %-65s", bccnames));
notify(player, tprintf("Subject: %-65s", mp->subject));
free_lbuf(status);
free_lbuf(names);
free_lbuf(ccnames);
free_lbuf(bccnames);
notify(player, DASH_LINE);
notify(player, get_mail_message(mp->number));
notify(player, DASH_LINE);
}
}
}
}
if (!j) {
/*
* ran off the end of the list without finding
* anything
*/
notify(player, "MAIL: You don't have that many matching messages!");
}
}
}
void do_mail_list(player, msglist, sub)
dbref player;
char *msglist;
int sub;
{
struct mail *mp;
struct mail_selector ms;
int i = 0, folder;
char *time;
if (!parse_msglist(msglist, &ms, player)) {
return;
}
folder = player_folder(player);
notify(player,
tprintf("--------------------------%s MAIL: Folder %d ----------------------------",
((folder > 9) ? "" : "-"), folder));
for (mp = (struct mail *)nhashfind((int)player, &mod_mail_msg_htab);
mp; mp = mp->next) {
if (Folder(mp) == folder) {
i++;
if (mail_match(mp, ms, i)) {
/*
* list it
*/
time = mail_list_time(mp->time);
if (sub)
notify(player, tprintf("[%s] %-3d (%4d) From: %-*s Sub: %.25s",
status_chars(mp),
i,
strlen(get_mail_message(mp->number)),
PLAYER_NAME_LIMIT - 6,
Name(mp->from),
mp->subject));
else
notify(player, tprintf("[%s] %-3d (%4d) From: %-*s At: %s %s",
status_chars(mp),
i,
strlen(get_mail_message(mp->number)),
PLAYER_NAME_LIMIT - 6,
Name(mp->from),
time,
((Connected(mp->from) && (!Hidden(mp->from) || See_Hidden(player))) ? "Conn" : " ")));
free_lbuf(time);
}
}
}
notify(player, DASH_LINE);
}
static char *mail_list_time(the_time)
const char *the_time;
{
char *new;
char *p, *q;
int i;
p = (char *)the_time;
q = new = alloc_lbuf("mail_list_time");
if (!p || !*p) {
*new = '\0';
return new;
}
/*
* Format of the_time is: day mon dd hh:mm:ss yyyy
*/
/*
* Chop out :ss
*/
for (i = 0; i < 16; i++) {
if (*p)
*q++ = *p++;
}
for (i = 0; i < 3; i++) {
if (*p)
p++;
}
for (i = 0; i < 5; i++) {
if (*p)
*q++ = *p++;
}
*q = '\0';
return new;
}
void do_mail_purge(player)
dbref player;
{
struct mail *mp, *nextp;
/*
* Go through player's mail, and remove anything marked cleared
*/
for (mp = (struct mail *)nhashfind((int)player, &mod_mail_msg_htab);
mp; mp = nextp) {
if (Cleared(mp)) {
/*
* Delete this one
*/
/*
* head and tail of the list are special
*/
if (mp->prev == NULL) {
if (mp->next == NULL)
nhashdelete((int)player, &mod_mail_msg_htab);
else
nhashrepl((int)player, (int *)mp->next, &mod_mail_msg_htab);
} else if (mp->next == NULL)
mp->prev->next = NULL;
/*
* relink the list
*/
if (mp->prev != NULL)
mp->prev->next = mp->next;
if (mp->next != NULL)
mp->next->prev = mp->prev;
/*
* save the pointer
*/
nextp = mp->next;
/*
* then wipe
*/
XFREE(mp->subject, "mail_purge.subject");
delete_mail_message(mp->number);
XFREE(mp->time, "mail_purge.time");
XFREE(mp->tolist, "mail_purge.tolist");
XFREE(mp->cclist, "mail_purge.cclist");
XFREE(mp->bcclist, "mail_purge.bcclist");
XFREE(mp, "mail_purge");
} else {
nextp = mp->next;
}
}
notify(player, "MAIL: Mailbox purged.");
}
void do_mail_fwd(player, msg, tolist)
dbref player;
char *msg;
char *tolist;
{
struct mail *mp;
int num, mail_ok;
if (Sending_Mail(player)) {
notify(player, "MAIL: Mail message already in progress.");
return;
}
if (!msg || !*msg) {
notify(player, "MAIL: No message list.");
return;
}
if (!tolist || !*tolist) {
notify(player, "MAIL: To whom should I forward?");
return;
}
num = atoi(msg);
if (!num) {
notify(player, "MAIL: I don't understand that message number.");
return;
}
mp = mail_fetch(player, num);
if (!mp) {
notify(player, "MAIL: You can't forward non-existent messages.");
return;
}
mail_ok = do_expmail_start(player, tolist, NULL, tprintf("%s (fwd from %s)", mp->subject, Name(mp->from)));
if (mail_ok) {
atr_add_raw(player, A_MAILMSG, get_mail_message(mp->number));
atr_add_raw(player, A_MAILFLAGS, tprintf("%d", atoi(atr_get_raw(player, A_MAILFLAGS)) | M_FORWARD));
}
}
void do_mail_reply(player, msg, all, key)
dbref player;
char *msg;
int all, key;
{
struct mail *mp;
int num, mail_ok;
char *tolist, *ccnames, *bp, *p, *oldlist, *tokst;
if (Sending_Mail(player)) {
notify(player, "MAIL: Mail message already in progress.");
return;
}
if (!msg || !*msg) {
notify(player, "MAIL: No message list.");
return;
}
num = atoi(msg);
if (!num) {
notify(player, "MAIL: I don't understand that message number.");
return;
}
mp = mail_fetch(player, num);
if (!mp) {
notify(player, "MAIL: You can't reply to non-existent messages.");
return;
}
ccnames = NULL;
if (all) {
bp = oldlist = alloc_lbuf("do_mail_reply.oldlist");
safe_str((char *)mp->tolist, oldlist, &bp);
if (*mp->cclist)
safe_tprintf_str(oldlist, &bp, " %s", mp->cclist);
bp = ccnames = alloc_lbuf("do_mail_reply.ccnames");
for (p = strtok_r(oldlist, " ", &tokst);
p != NULL;
p = strtok_r(NULL, " ", &tokst)) {
if (bp != ccnames) {
safe_chr(' ', ccnames, &bp);
}
if (*p == '*') {
safe_str(p, ccnames, &bp);
} else if (atoi(p) != mp->from) {
safe_chr('"', ccnames, &bp);
safe_name(atoi(p), ccnames, &bp);
safe_chr('"', ccnames, &bp);
}
}
free_lbuf(oldlist);
}
tolist = msg;
if (strncmp(mp->subject, "Re:", 3)) {
mail_ok = do_expmail_start(player, tolist, ccnames, tprintf("Re: %s", mp->subject));
} else {
mail_ok = do_expmail_start(player, tolist, ccnames, tprintf("%s", mp->subject));
}
if (mail_ok) {
if (key & MAIL_QUOTE) {
atr_add_raw(player, A_MAILMSG,
tprintf("On %s, %s wrote:\r\n\r\n%s\r\n\r\n********** End of included message from %s\r\n",
mp->time, Name(mp->from),
get_mail_message(mp->number), Name(mp->from)));
}
atr_add_raw(player, A_MAILFLAGS, tprintf("%d", (atoi(atr_get_raw(player, A_MAILFLAGS)) | M_REPLY)));
}
if (ccnames) {
free_lbuf(ccnames);
}
}
/*-------------------------------------------------------------------------*
* Admin mail functions
*
* do_mail_nuke - clear & purge mail for a player, or all mail in db.
* do_mail_debug - fix mail with a sledgehammer
* do_mail_stats - stats on mail for a player, or for all db.
*-------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------*
* Basic mail functions
*-------------------------------------------------------------------------*/
struct mail *mail_fetch(player, num)
dbref player;
int num;
{
struct mail *mp;
int i = 0;
for (mp = (struct mail *)nhashfind((int)player, &mod_mail_msg_htab);
mp; mp = mp->next) {
if (Folder(mp) == player_folder(player)) {
i++;
if (i == num)
return mp;
}
}
return NULL;
}
/*
* returns count of read, unread, & cleared messages as rcount, ucount,
* * ccount
*/
void count_mail(player, folder, rcount, ucount, ccount)
dbref player;
int folder;
int *rcount;
int *ucount;
int *ccount;
{
struct mail *mp;
int rc, uc, cc;
cc = rc = uc = 0;
for (mp = (struct mail *)nhashfind((int)player, &mod_mail_msg_htab);
mp; mp = mp->next) {
if (Folder(mp) == folder) {
if (Read(mp))
rc++;
else
uc++;
if (Cleared(mp))
cc++;
}
}
*rcount = rc;
*ucount = uc;
*ccount = cc;
}
void urgent_mail(player, folder, ucount)
dbref player;
int folder;
int *ucount;
{
struct mail *mp;
int uc;
uc = 0;
for (mp = (struct mail *)nhashfind((int)player, &mod_mail_msg_htab);
mp; mp = mp->next) {
if (Folder(mp) == folder) {
if (!(Read(mp)) && (Urgent(mp)))
uc++;
}
}
*ucount = uc;
}
static void send_mail(player, target, tolist, cclist, bcclist, subject,
number, flags, silent)
dbref player, target;
const char *tolist, *cclist, *bcclist, *subject;
int number, silent;
mail_flag flags;
{
struct mail *newp;
struct mail *mp;
time_t tt;
char tbuf1[30];
if (Typeof(target) != TYPE_PLAYER) {
notify(player, "MAIL: You cannot send mail to non-existent people.");
delete_mail_message(number);
return;
}
tt = time(NULL);
StringCopy(tbuf1, ctime(&tt));
tbuf1[strlen(tbuf1) - 1] = '\0'; /*
* whack the newline
*/
/*
* initialize the appropriate fields
*/
newp = (struct mail *) XMALLOC(sizeof(struct mail), "send_mail");
newp->to = target;
newp->from = player;
newp->tolist = XSTRDUP(tolist, "send_mail.tolist");
if (!cclist) {
newp->cclist = XSTRDUP("", "send_mail.cclist");
} else {
newp->cclist = XSTRDUP(cclist, "send_mail.cclist");
}
if (!bcclist) {
newp->bcclist = XSTRDUP("", "send_mail.bcclist");
} else {
newp->bcclist = XSTRDUP(bcclist, "send_mail.bcclist");
}
newp->number = number;
add_count(number);
newp->time = XSTRDUP(tbuf1, "send_mail.time");
newp->subject = XSTRDUP(subject, "send_mail.subj");
newp->read = flags & M_FMASK; /*
* Send to folder 0
*/
/*
* if this is the first message, it is the head and the tail
*/
if (!nhashfind((int)target, &mod_mail_msg_htab)) {
nhashadd((int)target, (int *)newp, &mod_mail_msg_htab);
newp->next = NULL;
newp->prev = NULL;
} else {
for (mp = (struct mail *)nhashfind((int)target, &mod_mail_msg_htab);
mp->next; mp = mp->next) ;
mp->next = newp;
newp->next = NULL;
newp->prev = mp;
}
/*
* notify people
*/
if (!silent)
notify(player, tprintf("MAIL: You sent your message to %s.", Name(target)));
notify(target, tprintf("MAIL: You have a new message from %s.",
Name(player)));
did_it(player, target, A_MAIL, NULL, A_NULL, NULL, A_AMAIL, 0,
(char **) NULL, 0, 0);
return;
}
void do_mail_nuke(player)
dbref player;
{
struct mail *mp, *nextp;
dbref thing;
if (!God(player)) {
notify(player, "The postal service issues a warrant for your arrest.");
return;
}
/*
* walk the list
*/
DO_WHOLE_DB(thing) {
for (mp = (struct mail *)nhashfind((int)thing,
&mod_mail_msg_htab);
mp != NULL; mp = nextp) {
nextp = mp->next;
delete_mail_message(mp->number);
XFREE(mp->subject, "mail_nuke.subject");
XFREE(mp->tolist, "mail_nuke.tolist");
XFREE(mp->cclist, "mail_nuke.cclist");
XFREE(mp->bcclist, "mail_nuke.bcclist");
XFREE(mp->time, "mail_nuke.time");
XFREE(mp, "mail_nuke");
}
nhashdelete((int)thing, &mod_mail_msg_htab);
}
STARTLOG(LOG_ALWAYS, "WIZ", "MNUKE")
log_printf("** MAIL PURGE ** done by ");
log_name(player);
ENDLOG
notify(player, "You annihilate the post office. All messages cleared.");
}
void do_mail_debug(player, action, victim)
dbref player;
char *action;
char *victim;
{
dbref target, thing;
struct mail *mp, *nextp;
if (!Wizard(player)) {
notify(player, "Go get some bugspray.");
return;
}
if (string_prefix("clear", action)) {
target = lookup_player(player, victim, 1);
if (target == NOTHING) {
init_match(player, victim, NOTYPE);
match_absolute();
target = match_result();
}
if (target == NOTHING) {
notify(player, tprintf("%s: no such player.", victim));
return;
}
do_mail_clear(target, NULL);
do_mail_purge(target);
notify(player, tprintf("Mail cleared for %s(#%d).", Name(target), target));
return;
} else if (string_prefix("sanity", action)) {
MAIL_ITER_ALL(mp, thing) {
if (!Good_obj(mp->to))
notify(player, tprintf("Bad object #%d has mail.", mp->to));
else if (Typeof(mp->to) != TYPE_PLAYER)
notify(player, tprintf("%s(#%d) has mail but is not a player.",
Name(mp->to), mp->to));
}
notify(player, "Mail sanity check completed.");
} else if (string_prefix("fix", action)) {
MAIL_ITER_SAFE(mp, thing, nextp) {
if (!Good_obj(mp->to) || (Typeof(mp->to) != TYPE_PLAYER)) {
notify(player, tprintf("Fixing mail for #%d.", mp->to));
/*
* Delete this one
*/
/*
* head and tail of the list are special
*/
if (mp->prev == NULL) {
if (mp->next == NULL)
nhashdelete((int)thing, &mod_mail_msg_htab);
else
nhashrepl((int)thing, (int *)mp->next, &mod_mail_msg_htab);
} else if (mp->next == NULL)
mp->prev->next = NULL;
/*
* relink the list
*/
if (mp->prev != NULL)
mp->prev->next = mp->next;
if (mp->next != NULL)
mp->next->prev = mp->prev;
/*
* save the pointer
*/
nextp = mp->next;
/*
* then wipe
*/
XFREE(mp->subject,
"mail_debug.subject");
delete_mail_message(mp->number);
XFREE(mp->time, "mail_debug.time");
XFREE(mp->tolist, "mail_debug.tolist");
XFREE(mp->cclist, "mail_debug.cclist");
XFREE(mp->bcclist, "mail_debug.bcclist");
XFREE(mp, "mail_debug");
} else
nextp = mp->next;
}
notify(player, "Mail sanity fix completed.");
} else {
notify(player, "That is not a debugging option.");
return;
}
}
void do_mail_stats(player, name, full)
dbref player;
char *name;
int full;
{
dbref target, thing;
int fc, fr, fu, tc, tr, tu, fchars, tchars, cchars, count;
char last[50];
struct mail *mp;
fc = fr = fu = tc = tr = tu = cchars = fchars = tchars = count = 0;
/*
* find player
*/
if ((*name == '\0') || !name) {
if Wizard
(player)
target = AMBIGUOUS;
else
target = player;
} else if (*name == NUMBER_TOKEN) {
target = atoi(&name[1]);
if (!Good_obj(target) || (Typeof(target) != TYPE_PLAYER))
target = NOTHING;
} else if (!strcasecmp(name, "me")) {
target = player;
} else {
target = lookup_player(player, name, 1);
}
if (target == NOTHING) {
init_match(player, name, NOTYPE);
match_absolute();
target = match_result();
}
if (target == NOTHING) {
notify(player, tprintf("%s: No such player.", name));
return;
}
if (!Wizard(player) && (target != player)) {
notify(player, "The post office protects privacy!");
return;
}
/*
* this command is computationally expensive
*/
if (!payfor(player, mudconf.searchcost)) {
notify(player, tprintf("Finding mail stats costs %d %s.",
mudconf.searchcost,
(mudconf.searchcost == 1) ? mudconf.one_coin : mudconf.many_coins));
return;
}
if (target == AMBIGUOUS) { /*
* stats for all
*/
if (full == 0) {
MAIL_ITER_ALL(mp, thing) {
count++;
}
notify(player,
tprintf("There are %d messages in the mail spool.", count));
return;
} else if (full == 1) {
MAIL_ITER_ALL(mp, thing) {
if (Cleared(mp))
fc++;
else if (Read(mp))
fr++;
else
fu++;
}
notify(player,
tprintf("MAIL: There are %d msgs in the mail spool, %d unread, %d cleared.",
fc + fr + fu, fu, fc));
return;
} else {
MAIL_ITER_ALL(mp, thing) {
if (Cleared(mp)) {
fc++;
cchars += strlen(get_mail_message(mp->number));
} else if (Read(mp)) {
fr++;
fchars += strlen(get_mail_message(mp->number));
} else {
fu++;
tchars += strlen(get_mail_message(mp->number));
}
}
notify(player, tprintf("MAIL: There are %d old msgs in the mail spool, totalling %d characters.", fr, fchars));
notify(player, tprintf("MAIL: There are %d new msgs in the mail spool, totalling %d characters.", fu, tchars));
notify(player, tprintf("MAIL: There are %d cleared msgs in the mail spool, totalling %d characters.", fc, cchars));
return;
}
}
/*
* individual stats
*/
if (full == 0) {
/*
* just count number of messages
*/
MAIL_ITER_ALL(mp, thing) {
if (mp->from == target)
fr++;
if (mp->to == target)
tr++;
}
notify(player, tprintf("%s sent %d messages.",
Name(target), fr));
notify(player, tprintf("%s has %d messages.", Name(target), tr));
return;
}
/*
* more detailed message count
*/
MAIL_ITER_ALL(mp, thing) {
if (mp->from == target) {
if (Cleared(mp))
fc++;
else if (Read(mp))
fr++;
else
fu++;
if (full == 2)
fchars += strlen(get_mail_message(mp->number));
}
if (mp->to == target) {
if (!tr && !tu) {
StringCopy(last, mp->time);
}
if (Cleared(mp))
tc++;
else if (Read(mp))
tr++;
else
tu++;
if (full == 2) {
tchars += strlen(get_mail_message(mp->number));
}
}
}
notify(player, tprintf("Mail statistics for %s:", Name(target)));
if (full == 1) {
notify(player, tprintf("%d messages sent, %d unread, %d cleared.",
fc + fr + fu, fu, fc));
notify(player, tprintf("%d messages received, %d unread, %d cleared.",
tc + tr + tu, tu, tc));
} else {
notify(player,
tprintf("%d messages sent, %d unread, %d cleared, totalling %d characters.",
fc + fr + fu, fu, fc, fchars));
notify(player,
tprintf("%d messages received, %d unread, %d cleared, totalling %d characters.",
tc + tr + tu, tu, tc, tchars));
}
if (tc + tr + tu > 0)
notify(player, tprintf("Last is dated %s", last));
return;
}
/*-------------------------------------------------------------------------*
* Main mail routine for @mail w/o a switch
*-------------------------------------------------------------------------*/
void do_mail_stub(player, arg1, arg2)
dbref player;
char *arg1;
char *arg2;
{
if (Typeof(player) != TYPE_PLAYER) {
notify(player, "MAIL: Only players may send and receive mail.");
return;
}
if (!arg1 || !*arg1) {
if (arg2 && *arg2) {
notify(player, "MAIL: Invalid mail command.");
return;
}
/*
* just the "@mail" command
*/
do_mail_list(player, arg1, 1);
return;
}
/*
* purge a player's mailbox
*/
if (!strcasecmp(arg1, "purge")) {
do_mail_purge(player);
return;
}
/*
* clear message
*/
if (!strcasecmp(arg1, "clear")) {
do_mail_clear(player, arg2);
return;
}
if (!strcasecmp(arg1, "unclear")) {
do_mail_unclear(player, arg2);
return;
}
if (arg2 && *arg2) {
/*
* Sending mail
*/
(void) do_expmail_start(player, arg1, NULL, arg2);
return;
} else {
/*
* Must be reading or listing mail - no arg2
*/
if (isdigit(*arg1) && !strchr(arg1, '-'))
do_mail_read(player, arg1);
else
do_mail_list(player, arg1, 1);
return;
}
}
void do_mail(player, cause, key, arg1, arg2)
dbref player, cause;
int key;
char *arg1;
char *arg2;
{
switch (key & ~MAIL_QUOTE) {
case 0:
do_mail_stub(player, arg1, arg2);
break;
case MAIL_STATS:
do_mail_stats(player, arg1, 0);
break;
case MAIL_DSTATS:
do_mail_stats(player, arg1, 1);
break;
case MAIL_FSTATS:
do_mail_stats(player, arg1, 2);
break;
case MAIL_DEBUG:
do_mail_debug(player, arg1, arg2);
break;
case MAIL_NUKE:
do_mail_nuke(player);
break;
case MAIL_FOLDER:
do_mail_change_folder(player, arg1, arg2);
break;
case MAIL_LIST:
do_mail_list(player, arg1, 0);
break;
case MAIL_READ:
do_mail_read(player, arg1);
break;
case MAIL_CLEAR:
do_mail_clear(player, arg1);
break;
case MAIL_UNCLEAR:
do_mail_unclear(player, arg1);
break;
case MAIL_PURGE:
do_mail_purge(player);
break;
case MAIL_FILE:
do_mail_file(player, arg1, arg2);
break;
case MAIL_TAG:
do_mail_tag(player, arg1);
break;
case MAIL_UNTAG:
do_mail_untag(player, arg1);
break;
case MAIL_FORWARD:
do_mail_fwd(player, arg1, arg2);
break;
case MAIL_REPLY:
do_mail_reply(player, arg1, 0, key);
break;
case MAIL_REPLYALL:
do_mail_reply(player, arg1, 1, key);
break;
case MAIL_SEND:
do_expmail_stop(player, 0);
break;
case MAIL_EDIT:
do_edit_msg(player, arg1, arg2);
break;
case MAIL_URGENT:
do_expmail_stop(player, M_URGENT);
break;
case MAIL_ALIAS:
do_malias_create(player, arg1, arg2);
break;
case MAIL_ALIST:
do_malias_list_all(player);
break;
case MAIL_PROOF:
do_mail_proof(player);
break;
case MAIL_ABORT:
do_expmail_abort(player);
break;
case MAIL_QUICK:
do_mail_quick(player, arg1, arg2);
break;
case MAIL_REVIEW:
do_mail_review(player, arg1, arg2);
break;
case MAIL_RETRACT:
do_mail_retract(player, arg1, arg2);
break;
case MAIL_TO:
do_mail_to(player, arg1, A_MAILTO);
break;
case MAIL_CC:
do_mail_to(player, arg1, A_MAILCC);
break;
case MAIL_BCC:
do_mail_to(player, arg1, A_MAILBCC);
break;
case MAIL_SAFE:
do_mail_safe(player, arg1);
break;
}
}
void mod_mail_dump_database(fp)
FILE *fp;
{
struct mail *mp, *mptr;
dbref thing;
int count = 0, i;
/* Write out version number */
fprintf(fp, "+V6\n");
putref(fp, mod_mail_config.mail_db_top);
DO_WHOLE_DB(thing) {
if (isPlayer(thing)) {
mptr = (struct mail *)nhashfind((int)thing, &mod_mail_msg_htab);
if (mptr != NULL)
for (mp = mptr; mp; mp = mp->next) {
putref(fp, mp->to);
putref(fp, mp->from);
putref(fp, mp->number);
putstring(fp, mp->tolist);
putstring(fp, mp->cclist);
putstring(fp, mp->bcclist);
putstring(fp, mp->time);
putstring(fp, mp->subject);
putref(fp, mp->read);
count++;
}
}
}
fprintf(fp, "*** END OF DUMP ***\n");
/*
* Add the db of mail messages
*/
for (i = 0; i < mod_mail_config.mail_db_top; i++) {
if (mod_mail_config.mail_list[i].count > 0) {
putref(fp, i);
putstring(fp, get_mail_message(i));
}
}
fprintf(fp, "+++ END OF DUMP +++\n");
save_malias(fp);
fflush(fp);
}
void mod_mail_load_database(fp)
FILE *fp;
{
char nbuf1[8];
int mail_top = 0;
int new = 0;
int pennsub = 0;
int read_tolist = 0;
int read_cclist = 0;
int read_newdb = 0;
int read_new_strings = 0;
int number = 0;
struct mail *mp, *mptr;
/*
* Read the version number
*/
fgets(nbuf1, sizeof(nbuf1), fp);
if (!strncmp(nbuf1, "+V1", 3)) {
new = 0;
} else if (!strncmp(nbuf1, "+V2", 3)) {
new = 1;
} else if (!strncmp(nbuf1, "+V3", 3)) {
new = 1;
read_tolist = 1;
} else if (!strncmp(nbuf1, "+V4", 3)) {
new = 1;
read_tolist = 1;
read_newdb = 1;
} else if (!strncmp(nbuf1, "+V5", 3)) {
new = 1;
read_tolist = 1;
read_newdb = 1;
read_new_strings = 1;
} else if (!strncmp(nbuf1, "+V6", 3)) {
new = 1;
read_tolist = 1;
read_cclist = 1;
read_newdb = 1;
read_new_strings = 1;
} else if (!strncmp(nbuf1, "+1", 2)) {
pennsub = 1;
} else {
/* Version number mangled */
fclose(fp);
return;
}
if (pennsub) {
/* Toss away the number of messages */
fgets(nbuf1, sizeof(nbuf1), fp);
}
if (read_newdb) {
mail_top = getref(fp);
mail_db_grow(mail_top + 1);
} else {
mail_db_grow(1);
}
fgets(nbuf1, sizeof(nbuf1), fp);
while (strncmp(nbuf1, "***", 3)) {
mp = (struct mail *) XMALLOC(sizeof(struct mail), "load_mail");
mp->to = atoi(nbuf1);
if (!nhashfind((int)mp->to, &mod_mail_msg_htab)) {
nhashadd((int)mp->to, (int *)mp, &mod_mail_msg_htab);
mp->prev = NULL;
mp->next = NULL;
} else {
for (mptr = (struct mail *)nhashfind((int)mp->to, &mod_mail_msg_htab);
mptr->next != NULL; mptr = mptr->next) ;
mptr->next = mp;
mp->prev = mptr;
mp->next = NULL;
}
mp->from = getref(fp);
if (read_newdb) {
mp->number = getref(fp);
add_count(mp->number);
}
if (read_tolist)
mp->tolist = XSTRDUP(getstring_noalloc(fp, read_new_strings), "load_mail.tolist");
else
mp->tolist = XSTRDUP(tprintf("%d", mp->to), "load_mail.tolist");
if (read_cclist){
mp->cclist = XSTRDUP(getstring_noalloc(fp, read_new_strings), "load_mail.cclist");
mp->bcclist = XSTRDUP(getstring_noalloc(fp, read_new_strings), "load_mail.bcclist");
} else {
mp->cclist = XSTRDUP("", "load_mail.cclist");
mp->bcclist = XSTRDUP("", "load_mail.bcclist");
}
mp->time = XSTRDUP(getstring_noalloc(fp, read_new_strings), "load_mail.time");
if (pennsub)
mp->subject = XSTRDUP(getstring_noalloc(fp, read_new_strings), "load_mail.subj");
else if (!new)
mp->subject = XSTRDUP("No subject", "load_mail.subj");
if (!read_newdb) {
number = add_mail_message_nosig(getstring_noalloc(fp, read_new_strings));
add_count(number);
mp->number = number;
}
if (new)
mp->subject = XSTRDUP(getstring_noalloc(fp, read_new_strings), "load_mail.subj");
else if (!pennsub)
mp->subject = XSTRDUP("No subject", "load_mail.subj");
mp->read = getref(fp);
fgets(nbuf1, sizeof(nbuf1), fp);
}
if (read_newdb) {
fgets(nbuf1, sizeof(nbuf1), fp);
while (strncmp(nbuf1, "+++", 3)) {
number = atoi(nbuf1);
new_mail_message(getstring_noalloc(fp, read_new_strings), number);
fgets(nbuf1, sizeof(nbuf1), fp);
}
}
load_malias(fp);
}
static int get_folder_number(player, name)
dbref player;
char *name;
{
int aflags, alen;
dbref aowner;
char *atrstr;
char *str, *pat, *res, *p, *bp;
/* Look up a folder name and return the appropriate number */
atrstr = atr_get(player, A_MAILFOLDERS, &aowner, &aflags, &alen);
if (!*atrstr) {
free_lbuf(atrstr);
return -1;
}
str = alloc_lbuf("get_folder_num_str");
bp = pat = alloc_lbuf("get_folder_num_pat");
strcpy(str, atrstr);
safe_tprintf_str(pat, &bp, ":%s:", upcasestr(name));
res = (char *)strstr(str, pat);
if (!res) {
free_lbuf(str);
free_lbuf(pat);
free_lbuf(atrstr);
return -1;
}
res += 2 + strlen(name);
p = res;
while (!isspace(*p))
p++;
p = '\0';
free_lbuf(atrstr);
free_lbuf(str);
free_lbuf(pat);
return atoi(res);
}
static char *get_folder_name(player, fld)
dbref player;
int fld;
{
static char str[LBUF_SIZE];
char *pat;
static char *old;
char *r, *atrstr;
int flags, len, alen;
/*
* Get the name of the folder, or "nameless"
*/
pat = alloc_lbuf("get_folder_name");
sprintf(pat, "%d:", fld);
old = NULL;
atrstr = atr_get(player, A_MAILFOLDERS, &player, &flags, &alen);
if (!*atrstr) {
StringCopy(str, "unnamed");
free_lbuf(pat);
free_lbuf(atrstr);
return str;
}
StringCopy(str, atrstr);
old = (char *)string_match(str, pat);
free_lbuf(atrstr);
if (old) {
r = old + strlen(pat);
while (*r != ':')
r++;
*r = '\0';
len = strlen(pat);
free_lbuf(pat);
return old + len;
} else {
StringCopy(str, "unnamed");
free_lbuf(pat);
return str;
}
}
void add_folder_name(player, fld, name)
dbref player;
int fld;
char *name;
{
char *old, *res, *r, *atrstr;
char *new, *pat, *str, *tbuf;
int aflags, alen;
/*
* Muck with the player's MAILFOLDERS attrib to add a string of the
* form: number:name:number to it, replacing any such string with a
* matching number.
*/
new = alloc_lbuf("add_folder_name.new");
pat = alloc_lbuf("add_folder_name.pat");
str = alloc_lbuf("add_folder_name.str");
tbuf = alloc_lbuf("add_folder_name.tbuf");
sprintf(new, "%d:%s:%d ", fld, upcasestr(name), fld);
sprintf(pat, "%d:", fld);
/* get the attrib and the old string, if any */
old = NULL;
atrstr = atr_get(player, A_MAILFOLDERS, &player, &aflags, &alen);
if (*atrstr) {
StringCopy(str, atrstr);
old = (char *)string_match(str, pat);
}
if (old && *old) {
StringCopy(tbuf, str);
r = old;
while (!isspace(*r))
r++;
*r = '\0';
res = (char *)replace_string(old, new, tbuf);
} else {
r = res = alloc_lbuf("mail_folders");
if (*atrstr)
safe_str(str, res, &r);
safe_str(new, res, &r);
*r = '\0';
}
/* put the attrib back */
atr_add(player, A_MAILFOLDERS, res, player,
AF_MDARK | AF_WIZARD | AF_NOPROG | AF_LOCK);
free_lbuf(str);
free_lbuf(pat);
free_lbuf(new);
free_lbuf(tbuf);
free_lbuf(atrstr);
free_lbuf(res);
}
static int player_folder(player)
dbref player;
{
/*
* Return the player's current folder number. If they don't have one,
* set it to 0
*/
int flags, number, alen;
char *atrstr;
atrstr = atr_pget(player, A_MAILCURF, &player, &flags, &alen);
if (!*atrstr) {
free_lbuf(atrstr);
set_player_folder(player, 0);
return 0;
}
number = atoi(atrstr);
free_lbuf(atrstr);
return number;
}
void set_player_folder(player, fnum)
dbref player;
int fnum;
{
/*
* Set a player's folder to fnum
*/
ATTR *a;
char *tbuf1;
tbuf1 = alloc_lbuf("set_player_folder");
sprintf(tbuf1, "%d", fnum);
a = (ATTR *) atr_num(A_MAILCURF);
if (a)
atr_add(player, A_MAILCURF, tbuf1, GOD, a->flags);
else { /*
* Shouldn't happen, but...
*/
atr_add(player, A_MAILCURF, tbuf1, GOD, AF_WIZARD | AF_NOPROG | AF_LOCK);
}
free_lbuf(tbuf1);
}
static int parse_folder(player, folder_string)
dbref player;
char *folder_string;
{
int fnum;
/*
* Given a string, return a folder #, or -1 The string is just a * *
* * number, * for now. Later, this will be where named folders are *
* * * handled
*/
if (!folder_string || !*folder_string)
return -1;
if (isdigit(*folder_string)) {
fnum = atoi(folder_string);
if ((fnum < 0) || (fnum > MAX_FOLDERS))
return -1;
else
return fnum;
}
/*
* Handle named folders here
*/
return get_folder_number(player, folder_string);
}
static int mail_match(mp, ms, num)
struct mail *mp;
struct mail_selector ms;
int num;
{
mail_flag mpflag;
/*
* Does a piece of mail match the mail_selector?
*/
if (ms.low && num < ms.low)
return 0;
if (ms.high && num > ms.high)
return 0;
if (ms.player && mp->from != ms.player)
return 0;
mpflag = Read(mp) ? mp->read : (mp->read | M_MSUNREAD);
if (!(ms.flags & M_ALL) && !(ms.flags & mpflag))
return 0;
if (ms.days != -1) {
time_t now, msgtime, diffdays;
char *msgtimestr;
struct tm msgtm;
/*
* Get the time now, subtract mp->time, and compare the * * *
* results with * ms.days (in manner of ms.day_comp)
*/
time(&now);
msgtimestr = alloc_lbuf("mail_match");
StringCopy(msgtimestr, mp->time);
if (do_convtime(msgtimestr, &msgtm)) {
msgtime = timelocal(&msgtm);
diffdays = (now - msgtime) / 86400;
free_lbuf(msgtimestr);
if (sign(diffdays - ms.days) != ms.day_comp) {
return 0;
}
} else {
free_lbuf(msgtimestr);
return 0;
}
}
return 1;
}
static int parse_msglist(msglist, ms, player)
char *msglist;
struct mail_selector *ms;
dbref player;
{
char *p, *q;
char tbuf1[LBUF_SIZE];
/*
* Take a message list, and return the appropriate mail_selector
* setup. For now, msglists are quite restricted. That'll change
* once all this is working. Returns 0 if couldn't parse, and
* also notifies player of why.
*/
/*
* Initialize the mail selector - this matches all messages
*/
ms->low = 0;
ms->high = 0;
ms->flags = 0x0FFF | M_MSUNREAD;
ms->player = 0;
ms->days = -1;
ms->day_comp = 0;
/*
* Now, parse the message list
*/
if (!msglist || !*msglist) {
/*
* All messages
*/
return 1;
}
/*
* Don't mess with msglist itself
*/
StringCopyTrunc(tbuf1, msglist, LBUF_SIZE - 1);
p = tbuf1;
while (p && *p && isspace(*p))
p++;
if (!p || !*p) {
return 1; /*
* all messages
*/
}
if (isdigit(*p)) {
/*
* Message or range
*/
q = strchr(p, '-');
if (q) {
/*
* We have a subrange, split it up and test to see if
* it is valid
*/
*q++ = '\0';
ms->low = atoi(p);
if (ms->low <= 0) {
notify(player, "MAIL: Invalid message range");
return 0;
}
if (!*q) {
/*
* Unbounded range
*/
ms->high = 0;
} else {
ms->high = atoi(q);
if ((ms->low > ms->high) || (ms->high <= 0)) {
notify(player, "MAIL: Invalid message range");
return 0;
}
}
} else {
/*
* A single message
*/
ms->low = ms->high = atoi(p);
}
} else {
switch (*p) {
case '-': /*
* Range with no start
*/
p++;
if (!p || !*p) {
notify(player, "MAIL: Invalid message range");
return 0;
}
ms->high = atoi(p);
if (ms->high <= 0) {
notify(player, "MAIL: Invalid message range");
return 0;
}
break;
case '~': /*
* exact # of days old
*/
p++;
if (!p || !*p) {
notify(player, "MAIL: Invalid age");
return 0;
}
ms->day_comp = 0;
ms->days = atoi(p);
if (ms->days < 0) {
notify(player, "MAIL: Invalid age");
return 0;
}
break;
case '<': /*
* less than # of days old
*/
p++;
if (!p || !*p) {
notify(player, "MAIL: Invalid age");
return 0;
}
ms->day_comp = -1;
ms->days = atoi(p);
if (ms->days < 0) {
notify(player, "MAIL: Invalid age");
return 0;
}
break;
case '>': /*
* greater than # of days old
*/
p++;
if (!p || !*p) {
notify(player, "MAIL: Invalid age");
return 0;
}
ms->day_comp = 1;
ms->days = atoi(p);
if (ms->days < 0) {
notify(player, "MAIL: Invalid age");
return 0;
}
break;
case '#': /*
* From db#
*/
p++;
if (!p || !*p) {
notify(player, "MAIL: Invalid dbref #");
return 0;
}
ms->player = atoi(p);
if (!Good_obj(ms->player) || !(ms->player)) {
notify(player, "MAIL: Invalid dbref #");
return 0;
}
break;
case '*': /*
* From player name
*/
p++;
if (!p || !*p) {
notify(player, "MAIL: Invalid player");
return 0;
}
ms->player = lookup_player(player, p, 1);
if (ms->player == NOTHING) {
notify(player, "MAIL: Invalid player");
return 0;
}
break;
case 'u': /* Urgent, Unread */
case 'U':
p++;
if (!p || !*p) {
notify(player, "MAIL: U is ambiguous (urgent or unread?)");
return 0;
}
switch (*p) {
case 'r': /*
* Urgent
*/
case 'R':
ms->flags = M_URGENT;
break;
case 'n': /*
* Unread
*/
case 'N':
ms->flags = M_MSUNREAD;
break;
default: /* bad */
notify(player, "MAIL: Invalid message specification");
return 0;
}
break;
case 'r': /* read */
case 'R':
ms->flags = M_ISREAD;
break;
case 'c': /* cleared */
case 'C':
ms->flags = M_CLEARED;
break;
case 't': /* tagged */
case 'T':
ms->flags = M_TAG;
break;
case 'm':
case 'M': /*
* Mass, me
*/
p++;
if (!p || !*p) {
notify(player, "MAIL: M is ambiguous (mass or me?)");
return 0;
}
switch (*p) {
case 'a':
case 'A':
ms->flags = M_MASS;
break;
case 'e':
case 'E':
ms->player = player;
break;
default:
notify(player, "MAIL: Invalid message specification");
return 0;
}
break;
default: /* Bad news */
notify(player, "MAIL: Invalid message specification");
return 0;
}
}
return 1;
}
void check_mail_expiration()
{
struct mail *mp, *nextp;
struct tm then_tm;
time_t then, now = time(0);
time_t expire_secs = mod_mail_config.mail_expiration * 86400;
dbref thing;
/*
* negative values for expirations never expire
*/
if (0 > mod_mail_config.mail_expiration)
return;
MAIL_ITER_SAFE(mp, thing, nextp) {
if (do_convtime((char *) mp->time, &then_tm))
{
then = timelocal(&then_tm);
if (((now - then) > expire_secs) && !(M_Safe(mp))) {
/*
* Delete this one
*/
/*
* head and tail of the list are special
*/
if (mp->prev == NULL) {
if (mp->next == NULL)
nhashdelete((int)mp->to, &mod_mail_msg_htab);
else
nhashrepl((int)mp->to, (int *)mp->next, &mod_mail_msg_htab);
} else if (mp->next == NULL)
mp->prev->next = NULL;
/*
* relink the list
*/
if (mp->prev != NULL)
mp->prev->next = mp->next;
if (mp->next != NULL)
mp->next->prev = mp->prev;
/*
* save the pointer
*/
nextp = mp->next;
/*
* then wipe
*/
XFREE(mp->subject,
"mail_expire.subject");
delete_mail_message(mp->number);
XFREE(mp->tolist,
"mail_expire.tolist");
XFREE(mp->cclist,
"mail_expire.cclist");
XFREE(mp->bcclist,
"mail_expire.bcclist");
XFREE(mp->time, "mail_expire.time");
XFREE(mp, "mail_expire");
} else
nextp = mp->next;
} else
nextp = mp->next;
}
}
static char *status_chars(mp)
struct mail *mp;
{
/*
* Return a short description of message flags
*/
static char res[10];
char *p;
StringCopy(res, "");
p = res;
*p++ = Read(mp) ? '-' : 'N';
*p++ = M_Safe(mp) ? 'S' : '-';
*p++ = Cleared(mp) ? 'C' : '-';
*p++ = Urgent(mp) ? 'U' : '-';
*p++ = Mass(mp) ? 'M' : '-';
*p++ = Forward(mp) ? 'F' : '-';
*p++ = Tagged(mp) ? '+' : '-';
*p = '\0';
return res;
}
static char *status_string(mp)
struct mail *mp;
{
/*
* Return a longer description of message flags
*/
char *tbuf1;
tbuf1 = alloc_lbuf("status_string");
StringCopy(tbuf1, "");
if (Read(mp))
strcat(tbuf1, "Read ");
else
strcat(tbuf1, "Unread ");
if (Cleared(mp))
strcat(tbuf1, "Cleared ");
if (Urgent(mp))
strcat(tbuf1, "Urgent ");
if (Mass(mp))
strcat(tbuf1, "Mass ");
if (Forward(mp))
strcat(tbuf1, "Fwd ");
if (Tagged(mp))
strcat(tbuf1, "Tagged ");
if (M_Safe(mp))
strcat(tbuf1, "Safe");
return tbuf1;
}
void check_mail(player, folder, silent)
dbref player;
int folder;
int silent;
{
/*
* Check for new @mail
*/
int rc; /*
* read messages
*/
int uc; /*
* unread messages
*/
int cc; /*
* cleared messages
*/
int gc; /*
* urgent messages
*/
/*
* just count messages
*/
count_mail(player, folder, &rc, &uc, &cc);
urgent_mail(player, folder, &gc);
#ifdef MAIL_ALL_FOLDERS
notify(player,
tprintf("MAIL: %d messages in folder %d [%s] (%d unread, %d cleared).",
rc + uc, folder, get_folder_name(player, folder), uc, cc));
#else
if (rc + uc > 0)
notify(player,
tprintf("MAIL: %d messages in folder %d [%s] (%d unread, %d cleared).",
rc + uc, folder, get_folder_name(player, folder), uc, cc));
else if (!silent)
notify(player, "MAIL: You have no mail.");
if (gc > 0)
notify(player, tprintf("URGENT MAIL: You have %d urgent messages in folder %d [%s].",
gc, folder, get_folder_name(player, folder)));
#endif
return;
}
static int sign(x)
int x;
{
if (x == 0) {
return 0;
} else if (x < 0) {
return -1;
} else {
return 1;
}
}
void do_malias_switch(player, a1, a2)
dbref player;
char *a1;
char *a2;
{
if ((!a2 || !*a2) && !(!a1 || !*a1))
do_malias_list(player, a1);
else if ((!*a1 || !a1) && (!*a2 || !a2))
do_malias_list_all(player);
else
do_malias_create(player, a1, a2);
}
void do_malias(player, cause, key, arg1, arg2)
dbref player, cause;
int key;
char *arg1;
char *arg2;
{
switch (key) {
case 0:
do_malias_switch(player, arg1, arg2);
break;
case 1:
do_malias_desc(player, arg1, arg2);
break;
case 2:
do_malias_chown(player, arg1, arg2);
break;
case 3:
do_malias_add(player, arg1, arg2);
break;
case 4:
do_malias_remove(player, arg1, arg2);
break;
case 5:
do_malias_delete(player, arg1);
break;
case 6:
do_malias_rename(player, arg1, arg2);
break;
case 7:
/*
* empty
*/
break;
case 8:
do_malias_adminlist(player);
break;
case 9:
do_malias_status(player);
}
}
struct malias *get_malias(player, alias)
dbref player;
char *alias;
{
char *mal;
struct malias *m;
int i = 0;
int x = 0;
if ((*alias == '#') && ExpMail(player)) {
x = atoi(alias + 1);
if (x < 0 || x >= ma_top)
return NULL;
else
return malias[x];
} else {
if (*alias != '*')
return NULL;
mal = alias + 1;
for (i = 0; i < ma_top; i++) {
m = malias[i];
if ((m->owner == player) || God(m->owner)) {
if (!strcmp(mal, m->name)) /*
* Found it!
*/
return m;
}
}
}
return NULL;
}
void do_malias_create(player, alias, tolist)
dbref player;
char *alias;
char *tolist;
{
char *head, *tail, spot;
struct malias *m;
struct malias **nm;
char *na, *buff;
int i = 0;
dbref target;
if (Typeof(player) != TYPE_PLAYER) {
notify(player, "MAIL: Only players may create mail aliases.");
return;
}
if (!alias || !*alias || !tolist || !*tolist) {
notify(player, "MAIL: What alias do you want to create?.");
return;
}
if (*alias != '*') {
notify(player, "MAIL: All Mail aliases must begin with '*'.");
return;
}
if (strlen(alias) > 31) {
notify(player, "MAIL: Alias name too long, truncated.");
alias[31] = '\0';
}
m = get_malias(player, alias);
if (m) {
notify(player,
tprintf("MAIL: Mail Alias '%s' already exists.", alias));
return;
}
if (!ma_size) {
ma_size = MA_INC;
malias = (struct malias **) XMALLOC(sizeof(struct malias *) *
ma_size, "malias_create");
} else if (ma_top >= ma_size) {
ma_size += MA_INC;
nm = (struct malias **) XMALLOC(sizeof(struct malias *) *
ma_size, "malias_create");
for (i = 0; i < ma_top; i++)
nm[i] = malias[i];
XFREE(malias, "malias_create.malias");
malias = nm;
}
malias[ma_top] = (struct malias *) XMALLOC(sizeof(struct malias),
"malias_create.top");
i = 0;
/* Parse the player list */
head = (char *)tolist;
while (head && *head && (i < (MALIAS_LEN - 1))) {
while (*head == ' ')
head++;
tail = head;
while (*tail && (*tail != ' ')) {
if (*tail == '"') {
head++;
tail++;
while (*tail && (*tail != '"'))
tail++;
}
if (*tail)
tail++;
}
tail--;
if (*tail != '"')
tail++;
spot = *tail;
*tail = '\0';
/*
* Now locate a target
*/
if (!strcasecmp(head, "me"))
target = player;
else if (*head == '#') {
target = atoi(head + 1);
if (!Good_obj(target))
target = NOTHING;
} else
target = lookup_player(player, head, 1);
if ((target == NOTHING) || (Typeof(target) != TYPE_PLAYER)) {
notify(player, "MAIL: No such player.");
} else {
buff = unparse_object(player, target, 0);
notify(player,
tprintf("MAIL: %s added to alias %s", buff, alias));
malias[ma_top]->list[i] = target;
i++;
free_lbuf(buff);
}
/*
* Get the next recip
*/
*tail = spot;
head = tail;
if (*head == '"')
head++;
}
malias[ma_top]->list[i] = NOTHING;
na = alias + 1;
malias[ma_top]->name = (char *) XMALLOC(sizeof(char) *
(strlen(na) + 1),
"malias_create.top.name");
malias[ma_top]->numrecep = i;
malias[ma_top]->owner = player;
StringCopy(malias[ma_top]->name, na);
malias[ma_top]->desc = (char *) XMALLOC(sizeof(char) *
(strlen(na) + 1),
"malias_create.top.desc");
StringCopy(malias[ma_top]->desc, na); /*
* For now do this.
*/
ma_top++;
notify(player, tprintf("MAIL: Alias set '%s' defined.", alias));
}
void do_malias_list(player, alias)
dbref player;
char *alias;
{
struct malias *m;
int i = 0;
char *buff, *bp;
m = get_malias(player, alias);
if (!m) {
notify(player, tprintf("MAIL: Alias '%s' not found.", alias));
return;
}
if (!ExpMail(player) && (player != m->owner) && !(God(m->owner))) {
notify(player, "MAIL: Permission denied.");
return;
}
bp = buff = alloc_lbuf("do_malias_list");
safe_tprintf_str(buff, &bp, "MAIL: Alias *%s: ", m->name);
for (i = m->numrecep - 1; i > -1; i--) {
safe_name(m->list[i], buff, &bp);
safe_chr(' ', buff, &bp);
}
*bp = '\0';
notify(player, buff);
free_lbuf(buff);
}
void do_malias_list_all(player)
dbref player;
{
struct malias *m;
int i = 0;
int notified = 0;
for (i = 0; i < ma_top; i++) {
m = malias[i];
if (God(m->owner) || (m->owner == player) || God(player)) {
if (!notified) {
notify(player,
"Name Description Owner");
notified++;
}
notify(player,
tprintf("%-12.12s %-35.35s %-15.15s", m->name, m->desc,
Name(m->owner)));
}
}
notify(player, "***** End of Mail Aliases *****");
}
void load_malias(fp)
FILE *fp;
{
char buffer[200];
(void)getref(fp);
if (fscanf(fp, "*** Begin %s ***\n", buffer) == 1 &&
!strcmp(buffer, "MALIAS")) {
malias_read(fp);
} else {
fprintf(mainlog_fp, "ERROR: Couldn't find Begin MALIAS.\n");
return;
}
}
void save_malias(fp)
FILE *fp;
{
fprintf(fp, "*** Begin MALIAS ***\n");
malias_write(fp);
}
void malias_read(fp)
FILE *fp;
{
int i, j;
char buffer[1000];
struct malias *m;
fscanf(fp, "%d\n", &ma_top);
ma_size = ma_top;
if (ma_top > 0)
malias = (struct malias **) XMALLOC(sizeof(struct malias *) *
ma_size, "malias_read");
else
malias = NULL;
for (i = 0; i < ma_top; i++) {
malias[i] = (struct malias *) XMALLOC(sizeof(struct malias),
"malias_read.element");
m = (struct malias *)malias[i];
fscanf(fp, "%d %d\n", &(m->owner), &(m->numrecep));
fscanf(fp, "%[^\n]\n", buffer);
m->name = (char *) XMALLOC(sizeof(char) * (strlen(buffer) - 1),
"malias_read.name");
StringCopy(m->name, buffer + 2);
fscanf(fp, "%[^\n]\n", buffer);
m->desc = (char *) XMALLOC(sizeof(char) * (strlen(buffer) - 1),
"malias_read.desc");
StringCopy(m->desc, buffer + 2);
if (m->numrecep > 0) {
for (j = 0; j < m->numrecep; j++) {
m->list[j] = getref(fp);
}
} else {
m->list[0] = 0;
}
}
}
void malias_write(fp)
FILE *fp;
{
int i, j;
struct malias *m;
fprintf(fp, "%d\n", ma_top);
for (i = 0; i < ma_top; i++) {
m = malias[i];
fprintf(fp, "%d %d\n", m->owner, m->numrecep);
fprintf(fp, "N:%s\n", m->name);
fprintf(fp, "D:%s\n", m->desc);
for (j = 0; j < m->numrecep; j++)
fprintf(fp, "%d\n", m->list[j]);
}
}
static int do_expmail_start(player, arg, arg2, subject)
dbref player;
char *arg, *arg2, *subject;
{
char *tolist, *cclist, *names, *ccnames;
if (!arg || !*arg) {
notify(player, "MAIL: I do not know whom you want to mail.");
return 0;
}
if (!subject || !*subject) {
notify(player, "MAIL: No subject.");
return 0;
}
if (Sending_Mail(player)) {
notify(player, "MAIL: Mail message already in progress.");
return 0;
}
if (!(tolist = make_numlist(player, arg))) {
return 0;
}
atr_add_raw(player, A_MAILTO, tolist);
names = make_namelist(player, tolist);
free_lbuf(tolist);
if (arg2) {
if (!(cclist = make_numlist(player, arg2))) {
return 0;
}
atr_add_raw(player, A_MAILCC, cclist);
ccnames = make_namelist(player, cclist);
free_lbuf(cclist);
} else {
atr_clr(player, A_MAILCC);
ccnames = NULL;
}
atr_clr(player, A_MAILBCC);
atr_add_raw(player, A_MAILSUB, subject);
atr_add_raw(player, A_MAILFLAGS, "0");
atr_clr(player, A_MAILMSG);
Flags2(player) |= PLAYER_MAILS;
if (ccnames && *ccnames) {
notify(player, tprintf("MAIL: You are sending mail to '%s', carbon-copied to '%s'.", names, ccnames));
} else {
notify(player, tprintf("MAIL: You are sending mail to '%s'.", names));
}
free_lbuf(names);
if (ccnames) {
free_lbuf(ccnames);
}
return 1;
}
static void do_mail_to(player, arg, attr)
dbref player;
char *arg;
int attr;
{
char *tolist, *names, *cclist, *ccnames, *bcclist, *bccnames;
dbref aowner;
int aflags, alen;
if (!Sending_Mail(player)) {
notify(player, "MAIL: No mail message in progress.");
return;
}
if (!arg || !*arg) {
if (attr == A_MAILTO) {
notify(player, "MAIL: I do not know whom you want to mail.");
} else {
atr_clr(player, attr);
notify_quiet(player, "Cleared.");
}
} else if ((tolist = make_numlist(player, arg))) {
atr_add_raw(player, attr, tolist);
notify_quiet(player, "Set.");
free_lbuf(tolist);
}
tolist = atr_get(player, A_MAILTO, &aowner, &aflags, &alen);
cclist = atr_get(player, A_MAILCC, &aowner, &aflags, &alen);
bcclist = atr_get(player, A_MAILBCC, &aowner, &aflags, &alen);
names = make_namelist(player, tolist);
ccnames = make_namelist(player, cclist);
bccnames = make_namelist(player, bcclist);
if (*ccnames) {
if (*bccnames) {
notify(player, tprintf("MAIL: You are sending mail to '%s', carbon-copied to '%s', blind carbon-copied to '%s'.",
names, ccnames, bccnames));
} else {
notify(player, tprintf("MAIL: You are sending mail to '%s', carbon-copied to '%s'.",
names, ccnames));
}
} else {
if (*bcclist) {
notify(player, tprintf("MAIL: You are sending mail to '%s', blind carbon-copied to '%s'.",
names, bccnames));
} else {
notify(player, tprintf("MAIL: You are sending mail to '%s'.",
names));
}
}
free_lbuf(names);
free_lbuf(ccnames);
free_lbuf(bccnames);
free_lbuf(tolist);
free_lbuf(cclist);
free_lbuf(bcclist);
}
static char *make_namelist(player, arg)
dbref player;
char *arg;
{
char *names, *oldarg;
char *bp, *p, *tokst;
oldarg = alloc_lbuf("make_namelist.oldarg");
names = alloc_lbuf("make_namelist.names");
bp = names;
StringCopy(oldarg, arg);
for (p = strtok_r(oldarg, " ", &tokst);
p != NULL;
p = strtok_r(NULL, " ", &tokst)) {
if (bp != names) {
safe_str(", ", names, &bp);
}
if (*p == '*') {
safe_str(p, names, &bp);
} else {
safe_name(atoi(p), names, &bp);
}
}
free_lbuf(oldarg);
return names;
}
static char *make_numlist(player, arg)
dbref player;
char *arg;
{
char *head, *tail, spot;
static char *numbuf;
static char buf[MBUF_SIZE];
char *numbp;
struct malias *m;
struct mail *temp;
dbref target;
int num;
numbuf = alloc_lbuf("make_numlist");
numbp = numbuf;
*numbp = '\0';
head = (char *)arg;
while (head && *head) {
while (*head == ' ')
head++;
tail = head;
while (*tail && (*tail != ' ')) {
if (*tail == '"') {
head++;
tail++;
while (*tail && (*tail != '"'))
tail++;
}
if (*tail)
tail++;
}
tail--;
if (*tail != '"')
tail++;
spot = *tail;
*tail = 0;
if (strlen(head) == 0)
continue;
num = atoi(head);
if (num) {
temp = mail_fetch(player, num);
if (!temp) {
notify(player, "MAIL: You can't reply to nonexistent mail.");
free_lbuf(numbuf);
return NULL;
}
sprintf(buf, "%d ", temp->from);
safe_str(buf, numbuf, &numbp);
} else if (*head == '*') {
m = get_malias(player, head);
if (!m) {
notify(player, tprintf("MAIL: Alias '%s' does not exist.", head));
free_lbuf(numbuf);
return NULL;
}
safe_str(head, numbuf, &numbp);
safe_chr(' ', numbuf, &numbp);
} else {
target = lookup_player(player, head, 1);
if (target != NOTHING) {
sprintf(buf, "%d ", target);
safe_str(buf, numbuf, &numbp);
} else {
notify(player, tprintf("MAIL: '%s' does not exist.", head));
free_lbuf(numbuf);
return NULL;
}
}
/*
* Get the next recip
*/
*tail = spot;
head = tail;
if (*head == '"')
head++;
}
if (!*numbuf) {
notify(player, "MAIL: No players specified.");
free_lbuf(numbuf);
return NULL;
} else {
*(numbp - 1) = '\0';
return numbuf;
}
}
void do_mail_quick(player, arg1, arg2)
dbref player;
char *arg1, *arg2;
{
char *buf, *bp, *tolist;
if (!arg1 || !*arg1) {
notify(player, "MAIL: I don't know who you want to mail.");
return;
}
if (!arg2 || !*arg2) {
notify(player, "MAIL: No message.");
return;
}
if (Sending_Mail(player)) {
notify(player, "MAIL: Mail message already in progress.");
return;
}
buf = alloc_lbuf("do_mail_quick");
bp = buf;
StringCopy(bp, arg1);
parse_to(&bp, '/', 1);
if (!bp) {
notify(player, "MAIL: No subject.");
free_lbuf(buf);
return;
}
if (!(tolist = make_numlist(player, buf))) {
free_lbuf(buf);
return;
}
mail_to_list(player, tolist, NULL, NULL, bp, arg2, 0, 0);
free_lbuf(buf);
free_lbuf(tolist);
}
void mail_to_list(player, tolist, cclist, bcclist, subject, message, flags, silent)
dbref player;
char *tolist, *cclist, *bcclist, *subject, *message;
int flags, silent;
{
char *head, *tail, spot, *list, *bp;
struct malias *m;
dbref target;
int number, i, j, n_recips, max_recips, *recip_array, *tmp;
if (!tolist || !*tolist) {
return;
}
bp = list = alloc_lbuf("mail_to_list");
safe_str(tolist, list, &bp);
if (cclist && *cclist) {
safe_chr(' ', list, &bp);
safe_str(cclist, list, &bp);
}
if (bcclist && *bcclist) {
safe_chr(' ', list, &bp);
safe_str(bcclist, list, &bp);
}
number = add_mail_message(player, message);
n_recips = 0;
max_recips = SBUF_SIZE;
recip_array = (int *) XCALLOC(max_recips, sizeof(int),
"mail_to_list.recip_array");
head = (char *)list;
while (head && *head) {
while (*head == ' ')
head++;
tail = head;
while (*tail && (*tail != ' ')) {
if (*tail == '"') {
head++;
tail++;
while (*tail && (*tail != '"'))
tail++;
}
if (*tail)
tail++;
}
tail--;
if (*tail != '"')
tail++;
spot = *tail;
*tail = '\0';
if (*head == '*') {
m = get_malias(player, head);
if (!m) {
free_lbuf(list);
XFREE(recip_array, "mail_to_list.recip_array");
return;
}
for (i = 0; i < m->numrecep; i++) {
if (isPlayer(m->list[i]) && !Going(m->list[i])) {
if (n_recips >= max_recips) {
max_recips += SBUF_SIZE;
tmp = (int *) XREALLOC(recip_array,
max_recips * sizeof(int),
"mail_to_list.recip_array");
if (!tmp) {
free_lbuf(list);
XFREE(recip_array,
"mail_to_list.recip_array");
return;
}
recip_array = tmp;
}
recip_array[n_recips] = m->list[i];
n_recips++;
} else {
send_mail(GOD, GOD, tolist, NULL, NULL, subject,
add_mail_message(player,
tprintf("Alias Error: Bad Player %d for %s",
m->list[i], head)),
flags, silent);
}
}
} else {
target = atoi(head);
if (Good_obj(target) && !Going(target)) {
if (n_recips >= max_recips) {
max_recips += SBUF_SIZE;
tmp = (int *) XREALLOC(recip_array,
max_recips * sizeof(int),
"mail_to_list.recip_array");
if (!tmp) {
free_lbuf(list);
XFREE(recip_array,
"mail_to_list.recip_array");
return;
}
recip_array = tmp;
}
recip_array[n_recips] = target;
n_recips++;
}
}
/*
* Get the next recip
*/
*tail = spot;
head = tail;
if (*head == '"')
head++;
}
/* Eliminate duplicates. */
for (i = 0; i < n_recips; i++) {
for (j = i + 1;
(recip_array[i] != NOTHING) && (j < n_recips);
j++) {
if (recip_array[i] == recip_array[j])
recip_array[i] = NOTHING;
}
if (Typeof(recip_array[i]) != TYPE_PLAYER)
recip_array[i] = NOTHING;
}
/* Send it. */
for (i = 0; i < n_recips; i++) {
if (recip_array[i] != NOTHING) {
send_mail(player, recip_array[i], tolist, cclist, bcclist, subject, number,
flags, silent);
}
}
/* Clean up. */
free_lbuf(list);
XFREE(recip_array, "mail_to_list.recip_array");
}
void do_expmail_stop(player, flags)
dbref player;
int flags;
{
char *tolist, *cclist, *bcclist, *mailsub, *mailmsg, *mailflags;
dbref aowner;
int aflags, alen;
tolist = atr_get(player, A_MAILTO, &aowner, &aflags, &alen);
cclist = atr_get(player, A_MAILCC, &aowner, &aflags, &alen);
bcclist = atr_get(player, A_MAILBCC, &aowner, &aflags, &alen);
mailmsg = atr_get(player, A_MAILMSG, &aowner, &aflags, &alen);
mailsub = atr_get(player, A_MAILSUB, &aowner, &aflags, &alen);
mailflags = atr_get(player, A_MAILFLAGS, &aowner, &aflags, &alen);
if (!*tolist || !*mailmsg || !Sending_Mail(player)) {
notify(player, "MAIL: No such message to send.");
} else {
mail_to_list(player, tolist, cclist, bcclist, mailsub, mailmsg, flags | atoi(mailflags), 0);
}
free_lbuf(tolist);
free_lbuf(cclist);
free_lbuf(bcclist);
free_lbuf(mailmsg);
free_lbuf(mailsub);
free_lbuf(mailflags);
Flags2(player) &= ~PLAYER_MAILS;
}
static void do_expmail_abort(player)
dbref player;
{
Flags2(player) &= ~PLAYER_MAILS;
notify(player, "MAIL: Message aborted.");
}
void do_prepend(player, cause, key, text)
dbref player, cause;
int key;
char *text;
{
char *oldmsg, *newmsg, *bp, *attr;
dbref aowner;
int aflags, alen;
if (Sending_Mail(player)) {
oldmsg = atr_get(player, A_MAILMSG, &aowner, &aflags, &alen);
if (*oldmsg) {
bp = newmsg = alloc_lbuf("do_prepend");
safe_str(text + 1, newmsg, &bp);
safe_chr(' ', newmsg, &bp);
safe_str(oldmsg, newmsg, &bp);
*bp = '\0';
atr_add_raw(player, A_MAILMSG, newmsg);
free_lbuf(newmsg);
} else
atr_add_raw(player, A_MAILMSG, text + 1);
free_lbuf(oldmsg);
attr = atr_get_raw(player, A_MAILMSG);
notify(player, tprintf("%d/%d characters prepended.",
attr ? strlen(attr) : 0, LBUF_SIZE));
} else {
notify(player, "MAIL: No message in progress.");
}
}
void do_postpend(player, cause, key, text)
dbref player, cause;
int key;
char *text;
{
char *oldmsg, *newmsg, *bp, *attr;
dbref aowner;
int aflags, alen;
if ((*(text + 1) == '-') && !(*(text + 2))) {
do_expmail_stop(player, 0);
return;
}
if (Sending_Mail(player)) {
oldmsg = atr_get(player, A_MAILMSG, &aowner, &aflags, &alen);
if (*oldmsg) {
bp = newmsg = alloc_lbuf("do_postpend");
safe_str(oldmsg, newmsg, &bp);
safe_chr(' ', newmsg, &bp);
safe_str(text + 1, newmsg, &bp);
*bp = '\0';
atr_add_raw(player, A_MAILMSG, newmsg);
free_lbuf(newmsg);
} else
atr_add_raw(player, A_MAILMSG, text + 1);
free_lbuf(oldmsg);
attr = atr_get_raw(player, A_MAILMSG);
notify(player, tprintf("%d/%d characters added.",
attr ? strlen(attr) : 0, LBUF_SIZE));
} else {
notify(player, "MAIL: No message in progress.");
}
}
static void do_edit_msg(player, from, to)
dbref player;
char *from;
char *to;
{
char *result, *msg;
dbref aowner;
int aflags, alen;
if (Sending_Mail(player)) {
msg = atr_get(player, A_MAILMSG, &aowner, &aflags, &alen);
result = replace_string(from, to, msg);
atr_add(player, A_MAILMSG, result, aowner, aflags);
notify(player, "Text edited.");
free_lbuf(result);
free_lbuf(msg);
} else {
notify(player, "MAIL: No message in progress.");
}
}
static void do_mail_proof(player)
dbref player;
{
char *mailto, *names, *ccnames, *bccnames, *message;
dbref aowner;
int aflags, alen;
if (Sending_Mail(player)) {
mailto = atr_get(player, A_MAILTO, &aowner, &aflags, &alen);
names = make_namelist(player, mailto);
free_lbuf(mailto);
mailto = atr_get(player, A_MAILCC, &aowner, &aflags, &alen);
ccnames = make_namelist(player, mailto);
free_lbuf(mailto);
mailto = atr_get(player, A_MAILBCC, &aowner, &aflags, &alen);
bccnames = make_namelist(player, mailto);
free_lbuf(mailto);
notify(player, DASH_LINE);
notify(player, tprintf("From: %-*s Subject: %-35s\nTo: %s",
PLAYER_NAME_LIMIT - 6, Name(player),
atr_get_raw(player, A_MAILSUB), names));
if (*ccnames)
notify(player, tprintf("Cc: %s", ccnames));
if (*bccnames)
notify(player, tprintf("Bcc: %s", bccnames));
notify(player, DASH_LINE);
if (!(message = atr_get_raw(player, A_MAILMSG))) {
notify(player, "MAIL: No text.");
} else {
notify(player, message);
notify(player, DASH_LINE);
}
free_lbuf(names);
free_lbuf(ccnames);
free_lbuf(bccnames);
} else {
notify(player, "MAIL: No message in progress.");
}
}
void do_malias_desc(player, alias, desc)
dbref player;
char *alias;
char *desc;
{
struct malias *m;
if (!(m = get_malias(player, alias))) {
notify(player, tprintf("MAIL: Alias %s not found.", alias));
return;
} else if ((m->owner != GOD) || ExpMail(player)) {
XFREE(m->desc, "malias_desc"); /* free it up */
if (strlen(desc) > 63) {
notify(player, "MAIL: Description too long, truncated.");
desc[63] = '\0';
}
m->desc = (char *) XMALLOC(sizeof(char) * (strlen(desc) + 1),
"malias_desc");
StringCopy(m->desc, desc);
notify(player, "MAIL: Description changed.");
} else
notify(player, "MAIL: Permission denied.");
return;
}
void do_malias_chown(player, alias, owner)
dbref player;
char *alias;
char *owner;
{
struct malias *m;
dbref no = NOTHING;
if (!(m = get_malias(player, alias))) {
notify(player, tprintf("MAIL: Alias %s not found.", alias));
return;
} else {
if (!ExpMail(player)) {
notify(player, "MAIL: You cannot do that!");
return;
} else {
if ((no = lookup_player(player, owner, 1)) == NOTHING) {
notify(player, "MAIL: I do not see that here.");
return;
}
m->owner = no;
notify(player, "MAIL: Owner changed for alias.");
}
}
}
void do_malias_add(player, alias, person)
dbref player;
char *alias;
char *person;
{
int i = 0;
dbref thing;
struct malias *m;
thing = NOTHING;
if (!(m = get_malias(player, alias))) {
notify(player, tprintf("MAIL: Alias %s not found.", alias));
return;
}
if (*person == '#') {
thing = parse_dbref(person + 1);
if (!isPlayer(thing)) {
notify(player, "MAIL: Only players may be added.");
return;
}
}
if (thing == NOTHING)
thing = lookup_player(player, person, 1);
if (thing == NOTHING) {
notify(player, "MAIL: I do not see that person here.");
return;
}
if (God(m->owner) && !ExpMail(player)) {
notify(player, "MAIL: Permission denied.");
return;
}
for (i = 0; i < m->numrecep; i++) {
if (m->list[i] == thing) {
notify(player, "MAIL: That person is already on the list.");
return;
}
}
if (i >= (MALIAS_LEN - 1)) {
notify(player, "MAIL: The list is full.");
return;
}
m->list[m->numrecep] = thing;
m->numrecep = m->numrecep + 1;
notify(player, tprintf("MAIL: %s added to %s", Name(thing), m->name));
}
void do_malias_remove(player, alias, person)
dbref player;
char *alias;
char *person;
{
int i, ok = 0;
dbref thing;
struct malias *m;
thing = NOTHING;
if (!(m = get_malias(player, alias))) {
notify(player, "MAIL: Alias not found.");
return;
}
if (God(m->owner) && !ExpMail(player)) {
notify(player, "MAIL: Permission denied.");
return;
}
if (*person == '#')
thing = parse_dbref(person + 1);
if (thing == NOTHING)
thing = lookup_player(player, person, 1);
if (thing == NOTHING) {
notify(player, "MAIL: I do not see that person here.");
return;
}
for (i = 0; i < m->numrecep; i++) {
if (ok)
m->list[i] = m->list[i + 1];
else if ((m->list[i] == thing) && !ok) {
m->list[i] = m->list[i + 1];
ok = 1;
}
}
if (ok)
m->numrecep--;
notify(player, tprintf("MAIL: %s removed from alias %s.",
Name(thing), alias));
}
void do_malias_rename(player, alias, newname)
dbref player;
char *alias;
char *newname;
{
struct malias *m;
if ((m = get_malias(player, alias)) == NULL) {
notify(player, "MAIL: I cannot find that alias!");
return;
}
if (!ExpMail(player) && !(m->owner == player)) {
notify(player, "MAIL: Permission denied.");
return;
}
if (*newname != '*') {
notify(player, "MAIL: Bad alias.");
return;
}
if (strlen(newname) > 31) {
notify(player, "MAIL: Alias name too long, truncated.");
newname[31] = '\0';
}
if (get_malias(player, newname) != NULL) {
notify(player, "MAIL: That name already exists!");
return;
}
XFREE(m->name, "malias_rename");
m->name = (char *) XMALLOC(sizeof(char) * strlen(newname),
"malias_rename");
StringCopy(m->name, newname + 1);
notify(player, "MAIL: Mailing Alias renamed.");
}
void do_malias_delete(player, alias)
dbref player;
char *alias;
{
int i = 0;
int done = 0;
struct malias *m;
m = get_malias(player, alias);
if (!m) {
notify(player, "MAIL: Not a valid alias. Remember to prefix the alias name with *.");
return;
}
for (i = 0; i < ma_top; i++) {
if (done)
malias[i] = malias[i + 1];
else {
if ((m->owner == player) || ExpMail(player))
if (m == malias[i]) {
done = 1;
notify(player, "MAIL: Alias Deleted.");
malias[i] = malias[i + 1];
}
}
}
if (!done)
notify(player, "MAIL: Alias not found.");
else
ma_top--;
}
void do_malias_adminlist(player)
dbref player;
{
struct malias *m;
int i;
if (!ExpMail(player)) {
do_malias_list_all(player);
return;
}
notify(player,
"Num Name Description Owner");
for (i = 0; i < ma_top; i++) {
m = malias[i];
notify(player, tprintf("%-4d %-10.10s %-40.40s %-11.11s",
i, m->name, m->desc, Name(m->owner)));
}
notify(player, "***** End of Mail Aliases *****");
}
void do_malias_status(player)
dbref player;
{
if (!ExpMail(player))
notify(player, "MAIL: Permission denied.");
else {
notify(player, tprintf("MAIL: Number of mail aliases defined: %d", ma_top));
notify(player, tprintf("MAIL: Allocated slots %d", ma_size));
}
}
/* --------------------------------------------------------------------------
* Functions.
*/
FUNCTION(fun_mail)
{
/* This function can take one of three formats: 1. mail(num) -->
* returns message <num> for privs. 2. mail(player) -->
* returns number of messages for <player>. 3.
* mail(player, num) --> returns message <num> for
* <player>.
*
* It can now take one more format: 4. mail() --> returns number of
* messages for executor
*/
struct mail *mp;
dbref playerask;
int num, rc, uc, cc;
VaChk_Range(0, 2);
if ((nfargs == 0) || !fargs[0] || !fargs[0][0]) {
count_mail(player, 0, &rc, &uc, &cc);
safe_ltos(buff, bufc, rc + uc);
return;
}
if (nfargs == 1) {
if (!is_number(fargs[0])) {
/* handle the case of wanting to count the number of
* messages
*/
if ((playerask = lookup_player(player, fargs[0], 1)) == NOTHING) {
safe_str("#-1 NO SUCH PLAYER", buff, bufc);
return;
} else if ((player != playerask) && !Wizard(player)) {
safe_noperm(buff, bufc);
return;
} else {
count_mail(playerask, 0, &rc, &uc, &cc);
safe_tprintf_str(buff, bufc, "%d %d %d", rc, uc, cc);
return;
}
} else {
playerask = player;
num = atoi(fargs[0]);
}
} else {
if ((playerask = lookup_player(player, fargs[0], 1)) == NOTHING) {
safe_str("#-1 NO SUCH PLAYER", buff, bufc);
return;
} else if ((player != playerask) && !God(player)) {
safe_noperm(buff, bufc);
return;
}
num = atoi(fargs[1]);
}
if ((num < 1) || (Typeof(playerask) != TYPE_PLAYER)) {
safe_str("#-1 NO SUCH MESSAGE", buff, bufc);
return;
}
mp = mail_fetch(playerask, num);
if (mp != NULL) {
safe_str(get_mail_message(mp->number), buff, bufc);
return;
}
/* ran off the end of the list without finding anything */
safe_str("#-1 NO SUCH MESSAGE", buff, bufc);
}
FUNCTION(fun_mailfrom)
{
/* This function can take these formats: 1) mailfrom(<num>) 2)
* mailfrom(<player>,<num>) It returns the dbref of the player the
* mail is from
*/
struct mail *mp;
dbref playerask;
int num;
VaChk_Range(1, 2);
if (nfargs == 1) {
playerask = player;
num = atoi(fargs[0]);
} else {
if ((playerask = lookup_player(player, fargs[0], 1)) == NOTHING) {
safe_str("#-1 NO SUCH PLAYER", buff, bufc);
return;
} else if ((player != playerask) && !Wizard(player)) {
safe_noperm(buff, bufc);
return;
}
num = atoi(fargs[1]);
}
if ((num < 1) || (Typeof(playerask) != TYPE_PLAYER)) {
safe_str("#-1 NO SUCH MESSAGE", buff, bufc);
return;
}
mp = mail_fetch(playerask, num);
if (mp != NULL) {
safe_dbref(buff, bufc, mp->from);
return;
}
/* ran off the end of the list without finding anything */
safe_str("#-1 NO SUCH MESSAGE", buff, bufc);
}
FUN mod_mail_functable[] = {
{"MAIL", fun_mail, 0, FN_VARARGS, CA_PUBLIC, NULL},
{"MAILFROM", fun_mailfrom, 0, FN_VARARGS, CA_PUBLIC, NULL},
{NULL, NULL, 0, 0, 0, NULL}};
/* --------------------------------------------------------------------------
* Command tables.
*/
NAMETAB mail_sw[] = {
{(char *)"abort", 1, CA_NO_SLAVE|CA_NO_GUEST, MAIL_ABORT},
{(char *)"alias", 4, CA_NO_SLAVE|CA_NO_GUEST, MAIL_ALIAS},
{(char *)"alist", 2, CA_NO_SLAVE|CA_NO_GUEST, MAIL_ALIST},
{(char *)"bcc", 2, CA_NO_SLAVE|CA_NO_GUEST, MAIL_BCC},
{(char *)"cc", 2, CA_NO_SLAVE|CA_NO_GUEST, MAIL_CC},
{(char *)"clear", 1, CA_NO_SLAVE|CA_NO_GUEST, MAIL_CLEAR},
{(char *)"debug", 1, CA_NO_SLAVE|CA_NO_GUEST, MAIL_DEBUG},
{(char *)"dstats", 2, CA_NO_SLAVE|CA_NO_GUEST, MAIL_DSTATS},
{(char *)"edit", 2, CA_NO_SLAVE|CA_NO_GUEST, MAIL_EDIT},
{(char *)"file", 2, CA_NO_SLAVE|CA_NO_GUEST, MAIL_FILE},
{(char *)"folder", 3, CA_NO_SLAVE|CA_NO_GUEST, MAIL_FOLDER},
{(char *)"forward", 2, CA_NO_SLAVE|CA_NO_GUEST, MAIL_FORWARD},
{(char *)"fstats", 2, CA_NO_SLAVE|CA_NO_GUEST, MAIL_FSTATS},
{(char *)"fwd", 2, CA_NO_SLAVE|CA_NO_GUEST, MAIL_FORWARD},
{(char *)"list", 1, CA_NO_SLAVE|CA_NO_GUEST, MAIL_LIST},
{(char *)"nuke", 1, CA_NO_SLAVE|CA_NO_GUEST, MAIL_NUKE},
{(char *)"proof", 2, CA_NO_SLAVE|CA_NO_GUEST, MAIL_PROOF},
{(char *)"purge", 1, CA_NO_SLAVE|CA_NO_GUEST, MAIL_PURGE},
{(char *)"quick", 1, CA_NO_SLAVE|CA_NO_GUEST, MAIL_QUICK},
{(char *)"quote", 3, CA_NO_SLAVE|CA_NO_GUEST, MAIL_QUOTE|SW_MULTIPLE},
{(char *)"read", 1, CA_NO_SLAVE|CA_NO_GUEST, MAIL_READ},
{(char *)"reply", 3, CA_NO_SLAVE|CA_NO_GUEST, MAIL_REPLY},
{(char *)"replyall", 6, CA_NO_SLAVE|CA_NO_GUEST, MAIL_REPLYALL},
{(char *)"retract", 3, CA_NO_SLAVE|CA_NO_GUEST, MAIL_RETRACT},
{(char *)"review", 3, CA_NO_SLAVE|CA_NO_GUEST, MAIL_REVIEW},
{(char *)"safe", 2, CA_NO_SLAVE|CA_NO_GUEST, MAIL_SAFE},
{(char *)"send", 0, CA_NO_SLAVE|CA_NO_GUEST, MAIL_SEND},
{(char *)"stats", 2, CA_NO_SLAVE|CA_NO_GUEST, MAIL_STATS},
{(char *)"tag", 1, CA_NO_SLAVE|CA_NO_GUEST, MAIL_TAG},
{(char *)"to", 2, CA_NO_SLAVE|CA_NO_GUEST, MAIL_TO},
{(char *)"unclear", 1, CA_NO_SLAVE|CA_NO_GUEST, MAIL_UNCLEAR},
{(char *)"untag", 3, CA_NO_SLAVE|CA_NO_GUEST, MAIL_UNTAG},
{(char *)"urgent", 2, CA_NO_SLAVE|CA_NO_GUEST, MAIL_URGENT},
{ NULL, 0, 0, 0}};
NAMETAB malias_sw[] = {
{(char *)"desc", 1, CA_NO_SLAVE|CA_NO_GUEST, MALIAS_DESC},
{(char *)"chown", 1, CA_NO_SLAVE|CA_NO_GUEST, MALIAS_CHOWN},
{(char *)"add", 1, CA_NO_SLAVE|CA_NO_GUEST, MALIAS_ADD},
{(char *)"remove", 1, CA_NO_SLAVE|CA_NO_GUEST, MALIAS_REMOVE},
{(char *)"delete", 1, CA_NO_SLAVE|CA_NO_GUEST, MALIAS_DELETE},
{(char *)"rename", 1, CA_NO_SLAVE|CA_NO_GUEST, MALIAS_RENAME},
{(char *)"list", 1, CA_NO_SLAVE|CA_NO_GUEST, MALIAS_LIST},
{(char *)"status", 1, CA_NO_SLAVE|CA_NO_GUEST, MALIAS_STATUS},
{ NULL, 0, 0, 0}};
CMDENT mod_mail_cmdtable[] = {
{(char *)"@mail", mail_sw, CA_NO_SLAVE|CA_NO_GUEST,
0, CS_TWO_ARG|CS_INTERP,
NULL, NULL, NULL, {do_mail}},
{(char *)"@malias", malias_sw, CA_NO_SLAVE|CA_NO_GUEST,
0, CS_TWO_ARG|CS_INTERP,
NULL, NULL, NULL, {do_malias}},
{(char *)"-", NULL,
CA_NO_GUEST|CA_NO_SLAVE|CF_DARK,
0, CS_ONE_ARG|CS_INTERP|CS_LEADIN,
NULL, NULL, NULL, {do_postpend}},
{(char *)"~", NULL,
CA_NO_GUEST|CA_NO_SLAVE|CF_DARK,
0, CS_ONE_ARG|CS_INTERP|CS_LEADIN,
NULL, NULL, NULL, {do_prepend}},
{(char *)NULL, NULL, 0,
0, 0,
NULL, NULL, NULL, {NULL}}};
/* --------------------------------------------------------------------------
* Handlers.
*/
void mod_mail_announce_connect(player, reason, num)
dbref player;
const char *reason;
int num;
{
check_mail(player, 0, 0);
if (Sending_Mail(player)) {
notify(player, "MAIL: You have a mail message in progress.");
}
}
void mod_mail_announce_disconnect(player, reason, num)
dbref player;
const char *reason;
int num;
{
do_mail_purge(player);
}
void mod_mail_destroy_player(player, victim)
dbref player, victim;
{
do_mail_clear(victim, NULL);
do_mail_purge(victim);
}
void mod_mail_cleanup_startup()
{
check_mail_expiration();
}
void mod_mail_init()
{
mod_mail_config.mail_expiration = 14;
mod_mail_config.mail_db_top = 0;
mod_mail_config.mail_db_size = 0;
mod_mail_config.mail_freelist = 0;
register_commands(mod_mail_cmdtable);
register_prefix_cmds("-~");
register_functions(mod_mail_functable);
register_hashtables(NULL, mod_mail_nhashtable);
}