#include <stdlib.h>
#include "sflags.h"
#include "edit.h"
#include "kernel.h"
#include "mudmacros.h"
#include "mud.h"
#include "mail.h"
#include "log.h"
#include <sys/ioctl.h>
#include <errno.h>
void mailcom(void) {
if (aliased(real_mynum)) {
bprintf ("&#You cannot use the mailer while you are aliased.\n");
return;
}
sclrflg(mynum, SFL_MAIL);
bprintf("&+BCDirt&+w Mailer v.3\n");
cur_player->old_inp_handler = phandler(mynum);
if(!EMPTY (getreinput(wordbuf))) { /* mail <player> */
new(wordbuf);
return;
}
loadmail();
if (ststflg(mynum, SFL_AUTOMAIL))
listmail();
strcpy(cur_player->cprompt, MAILPROMPT);
cur_player->inmailer = True;
push_input_handler(list);
return;
}
void exit_mail() {
pop_input_handler();
replace_input_handler ((void *)cur_player->old_inp_handler);
cur_player->inmailer = False;
strcpy(cur_player->cprompt, build_prompt(mynum));
}
void new(char *input){
time_t t;
struct tm *tm;
cur_player->work_msg = NEW(Message, 1);
cur_player->work_msg->next = NULL;
cur_player->work_msg->prev = NULL;
strcpy(cur_player->work_msg->mailfrom, pname(mynum));
cur_player->work_msg->status = MAIL_STATUS_NEW;
time (&t);
tm = localtime (&t);
strftime(cur_player->work_msg->date, LINE_LEN, "%a %b %d, %I:%M%P", tm);
get_mailto(input);
}
#ifdef INTERNET_EMAIL
Boolean is_internet_email( char *input ) {
if( plev(mynum) >= LVL_ARCHWIZARD ) {
while( *input != '\0' && *input != '\n' ) {
if( *input == '@' )
return True;
++input;
}
}
return False;
}
#endif /* INTERNET_EMAIL */
void get_mailto(char *input) {
PERSONA p;
if (input == NULL) {
strcpy(cur_player->cprompt, "To: ");
replace_input_handler(get_mailto);
}
else if (*input == 0) {
if(cur_player->inmailer) {
strcpy(cur_player->cprompt, MAILPROMPT);
replace_input_handler(list);
return;
}
else {
exit_mail();
return;
}
}
else if (!getuaf(input, &p)) {
bprintf("No such persona on system.\n");
#ifdef INTERNET_EMAIL
if(is_internet_email(input)) {
bprintf( "Assuming it's Internet E-Mail.\n" );
strcpy(cur_player->work_msg->mailto, input );
get_subject(NULL);
return;
}
#endif /* INTERNET_EMAIL */
if (cur_player->inmailer) {
replace_input_handler(get_mailto);
return;
}
else {
exit_mail();
return;
}
}
else {
strcpy(cur_player->work_msg->mailto, p.ublock.pname);
get_subject(NULL);
}
}
void write_msg(Boolean is_reply, char *reply_path) {
char tmppath[256];
sprintf(tmppath, "%s/SENDMSG.%s", TEMP_DIR, pname(mynum));
if (cur_player->inmailer)
replace_input_handler(list); /* nxt input handler, restored after edit1 */
else
replace_input_handler(cur_player->old_inp_handler);
start_editor("Please type in your message:\n",
"&+W[&+BC-Mail %.3d&+W]&N ",
reply_path, tmppath, is_reply, TYPE_MAIL);
}
void get_subject(char *input) {
if (input == NULL) {
bprintf("To: &+G%s\n", cur_player->work_msg->mailto);
strcpy(cur_player->cprompt, "Subject: " );
replace_input_handler(get_subject);
}
else {
if (*input == 0)
strcpy(cur_player->work_msg->subject, "None");
else
strcpy(cur_player->work_msg->subject, input);
write_msg(False, NULL);
}
}
void savemail(void) {
char mailpath[256], tmppath[256];
int tmpfd, saved, deleted;
Messageptr message;
sprintf(mailpath, "%s/%s", MAIL_DIR, pname(mynum));
sprintf(tmppath, "%s/MAIL.%s", TEMP_DIR, pname(mynum));
if ((tmpfd = OPEN(tmppath, O_WRONLY | O_CREAT | O_TRUNC, 0644)) == -1) {
progerror("open");
return;
}
else {
saved = deleted = 0;
for (message = cur_player->first_msg ;
message != NULL ; message = message->next) {
if (message->status == MAIL_STATUS_NEW)
message->status = MAIL_STATUS_OLD;
if (message->status != MAIL_STATUS_DELETED) {
save(message, tmpfd);
saved++;
}
else
deleted++;
FREE(message->prev);
}
CLOSE(tmpfd);
if (saved == 0)
unlink(mailpath);
else
rename(tmppath, mailpath);
if (saved && !deleted)
bprintf("[Keeping &+Call&N messages]\n");
else if (deleted && !saved)
bprintf("[Deleting &+Yall&N messages]\n");
else if (deleted || saved)
bprintf( "[&+Y%d&N %s &+Ydeleted&N, &+C%d&N %s &+Csaved&N]\n",
deleted, (deleted == 1) ? "message" : "messages",
saved, (saved == 1) ? "message" : "messages" );
}
}
void help_msg (void) {
bprintf("\nHelp for the &+BCDirt&+w mailer:\n\n"
"&+WS&+gend [message]&+w........ Send a message\n"
"&+WR&+Geply [message]&+w....... Reply to a message\n"
"&+WN&+cext&+w.................. Go to next unread message.\n"
"&+WP&+crevious&+w.............. Go to previous unread msg.\n"
"&+WD&+Belete [message]&+w...... Delete a message\n"
"&+WU&+Bndelete[messsage]&+w.... Undelete a message\n"
"&+WV&+yiew [message]&+w........ View a message\n"
"&+WQ&+ruit&+w.................. Quit the mailer\n"
"&+WT&+moggle&+w................ Toggle auto-list of mail\n"
"&+C<number keys>&+w......... View message #\n"
"&+C<return>&+w.............. Show index of mail\n\n"
"&+YNote:&+w arguments in square brackets are optional,"
"those in <>'s are required.\n"
"Your current message is marked with a '>'. Many commands "
"work by default\n on the current message.\n"
"Upon exiting the mailer, all messages marked with a D will be "
"deleted\n\n");
}
void listmail (void) {
int i;
Messageptr message;
if (cur_player->first_msg != NULL) {
bprintf("\n &+G From &+R Subject &+CDate\n");
bprintf(" &+W ----------- --------------------------------------- -----------------\n");
for (i = 1, message = cur_player->first_msg ;
message != NULL ; i++, message = message->next)
bprintf("%-2s%c %-2d) %-11s %-41.40s%-17s\n",
(message == cur_player->cur_msg) ? ">" : "",
(message->status == MAIL_STATUS_READ) ? ' ' : message->status,
i, message->mailfrom, message->subject, message->date);
bprintf("\n");
}
}
/* main routine */
void list(char *inp){
int i;
Messageptr message;
strcpy(cur_player->cprompt, MAILPROMPT);
if(inp[0] == '*') {
gamecom(inp+1, True);
return;
}
else if (isdigit(*inp)) {
i = atoi(inp);
if ((cur_player->cur_msg = queue_msg(cur_player->first_msg, i)) != NULL)
viewmsg();
return;
}
switch (toupper(inp[0])) {
case 'S':
if (strchr(inp, ' ') != NULL && strlen(inp) > 1)
new(strchr(inp, ' ') + sizeof(char));
else
new(NULL);
return;
case 'U':
if (strchr(inp, ' ') == NULL) {
if(cur_player->cur_msg &&
cur_player->cur_msg->status == MAIL_STATUS_DELETED) {
bprintf("Current message no longer marked for deletion.\n");
cur_player->cur_msg->status = MAIL_STATUS_READ;
return;
}
bprintf("Usage: Undelete <message> or U <message>\n");
break;
}
i = atoi(strchr(inp, ' '));
if ((message = queue_msg(cur_player->first_msg, i)) != NULL)
message->status = MAIL_STATUS_READ;
break;
case 'D':
if (strchr(inp, ' ') == NULL) {
if (cur_player->cur_msg &&
cur_player->cur_msg->status != MAIL_STATUS_DELETED) {
bprintf( "Current message marked for deletion.\n");
cur_player->cur_msg->status = MAIL_STATUS_DELETED;
break;
}
bprintf("Usage: Delete <message> or D <message>\n");
break;
}
i = atoi(strchr(inp, ' '));
if ((message = queue_msg(cur_player->first_msg, i)) != NULL) {
message->status = MAIL_STATUS_DELETED;
}
break;
case 'V':
if (strchr(inp, ' ') == NULL) {
if( cur_player->cur_msg ) {
viewmsg();
return;
}
else
bprintf("Usage: View <message> or V <message>\n");
}
else {
i = atoi(strchr(inp, ' '));
if((cur_player->cur_msg = queue_msg(cur_player->first_msg, i)) != NULL) {
viewmsg();
return;
}
}
break;
case 'N':
if ((message = cur_player->cur_msg) != NULL) {
do {
message = message->next;
} while (message != NULL && message->status == MAIL_STATUS_DELETED);
if (message == NULL)
bprintf( "No more un-deleted messages after this one.\n" );
else
cur_player->cur_msg = message;
}
break;
case 'T':
if (ststflg(mynum, SFL_AUTOMAIL)) {
sclrflg(mynum, SFL_AUTOMAIL);
bprintf("Auto mail listing on startup disabled.\n");
}
else {
ssetflg(mynum, SFL_AUTOMAIL);
bprintf("Auto mail listing on startup enabled.\n");
}
break;
case 'P':
if ((message = cur_player->cur_msg) != NULL ) {
do {
message = message->prev;
} while (message != NULL && message->status == MAIL_STATUS_DELETED);
}
if (message == NULL)
bprintf( "No more un-deleted messages before this one.\n" );
else
cur_player->cur_msg = message;
break;
case 'R':
if (strchr(inp, ' ' ) == NULL) {
if (cur_player->cur_msg != NULL) {
replymsg(NULL);
return;
}
else
bprintf("Usage: Reply <message>\n");
}
else {
i = atoi(strchr(inp, ' '));
if ((cur_player->cur_msg = queue_msg(cur_player->first_msg, i)) != NULL){
replymsg(NULL);
return;
}
}
break;
case '?': case 'H':
help_msg();
break;
case '\0':
listmail();
break;
case 'Q': case 'X':
savemail();
exit_mail();
return;
default:
bprintf("Invalid command, type \"?\" for help with the mailer\n");
break;
}
}
/* copy mail text from the current message to an opened fd */
void write_text(int outfd) {
char buff[M_BUFLEN];
char path[256];
int n_read;
int mailfd;
sprintf(path, "%s/%s", MAIL_DIR, pname(mynum));
if ((mailfd = OPEN(path, O_RDONLY, 0644)) == -1) {
bprintf("Unable to open player's mail file.\n");
return;
}
lseek(mailfd, cur_player->cur_msg->text, SEEK_SET);
do {
n_read = getline(mailfd, buff);
if (!strstr(buff, DELIM)) {
write(outfd, buff, n_read);
write(outfd, "\n", 1);
}
else
break;
} while(n_read != -1);
CLOSE(mailfd);
}
/* save headers to player's mail file */
void store_header(int fd) {
char c[2];
c[0] = cur_player->work_msg->status;
c[1] = '\0';
write(fd, "From: ", 6);
write(fd, cur_player->work_msg->mailfrom,
strlen(cur_player->work_msg->mailfrom));
write(fd, "\nSubject: ", 10);
write(fd, cur_player->work_msg->subject,
strlen(cur_player->work_msg->subject));
write(fd, "\nDate: ", 7);
write(fd, cur_player->work_msg->date,
strlen(cur_player->work_msg->date));
write(fd, "\nStatus: ", 9);
write(fd, c, 1);
write(fd, "\n", 1);
}
/* save headers for viewing */
void write_header(int fd) {
write(fd, "\n&+BFrom&+W : &+w", 19);
write(fd, cur_player->cur_msg->mailfrom,
strlen(cur_player->cur_msg->mailfrom));
write(fd, "\n&+BTo&+W : &+w", 19);
write(fd, cur_player->cur_msg->mailto,strlen(cur_player->cur_msg->mailto));
write(fd, "\n&+BDate&+W : &+w", 19);
write(fd, cur_player->cur_msg->date, strlen(cur_player->cur_msg->date));
write(fd, "\n&+BSubject&+W: &+w", 19);
write(fd, cur_player->cur_msg->subject,
strlen(cur_player->cur_msg->subject));
write(fd, "\n\n", 2);
}
void viewmsg() {
int tmp;
char path[256];
sprintf(path, "%s/MESSAGE.%s", TEMP_DIR, pname(mynum));
if ((tmp = OPEN(path, O_WRONLY | O_TRUNC | O_CREAT, 0660)) == -1) {
bprintf("Unable to open temporary mail file. Sorry.\n");
return;
}
write_header(tmp); /* save header to temp file */
write_text(tmp); /* save text to temp file */
if (cur_player->cur_msg->status == MAIL_STATUS_NEW ||
cur_player->cur_msg->status == MAIL_STATUS_OLD)
cur_player->cur_msg->status = MAIL_STATUS_READ;
CLOSE(tmp);
strcpy(cur_player->cprompt, MAILPROMPT);
bprintf("\001f%s\003", path);
}
void replymsg(char *input) {
time_t t;
struct tm *tm;
char path[256];
int tmp;
Messageptr newmessage;
if (input == NULL) {
strcpy(cur_player->cprompt, "Quote text from original message? ");
replace_input_handler(replymsg);
return;
}
else if (tolower(*input) != 'y' && tolower(*input) != 'n') {
bprintf("Please answer with Yes or No.\n");
return;
}
time (&t);
tm = localtime (&t);
/* Initialize the message */
newmessage = NEW(Message, 1);
newmessage->next = NULL;
newmessage->prev = NULL;
/* Fill in the data. */
strcpy(newmessage->mailfrom, pname(mynum));
newmessage->status = MAIL_STATUS_NEW;
strftime(newmessage->date, LINE_LEN, "%a %b %d, %I:%M%P", tm);
strcpy(newmessage->mailto, cur_player->cur_msg->mailfrom);
if(!strncmp(cur_player->cur_msg->subject, "Re:", 3 ))
strcpy(newmessage->subject, cur_player->cur_msg->subject);
else
sprintf(newmessage->subject, "Re: %s", cur_player->cur_msg->subject);
/* Make it our work message */
cur_player->work_msg = newmessage;
/* Tell them the info and get the text */
bprintf("\n&+BTo&+W : &+w%s\n", newmessage->mailto);
bprintf("&+BDate&+W : &+w%s\n", newmessage->date);
bprintf("&+BSubject&+W: &+w%s\n\n", newmessage->subject);
if (tolower(*input) == 'y') {
/* save the msg to a temp file, loaded by the editor */
sprintf(path, "%s/REPLY.%s", TEMP_DIR, pname(mynum));
if ((tmp = OPEN(path, O_WRONLY | O_CREAT | O_TRUNC, 0644)) != -1) {
write_text(tmp);
write_msg(True, path);
}
else {
bprintf("Error opening temporary save file for reply.\n");
progerror("open");
}
}
else
write_msg(False, NULL);
return;
}
Messageptr queue_msg(Messageptr first, int i) {
Messageptr message = NEW(Message, 1);
if (first == NULL) {
bprintf("You don't have any mail, so try sending some!\n");
return NULL;
}
else if (i <= 0) {
bprintf("No such message.\n");
return NULL;
}
for (message = first; i > 1 && message != NULL;
message = message->next, i--);
if (message == NULL) {
bprintf("No such message.\n");
return(NULL);
}
return(message);
}
/* getline : reads from FD, returns number of characters read, w/o newline */
int getline(int fd, char *str) {
char *ptr;
for (ptr = str ; read(fd, ptr, 1) > 0 ; ptr++)
if (*ptr == '\n') {
*ptr = '\0';
return ptr - str;
}
return -1;
}
void loadmail(void) {
Messageptr message;
char path[LINE_LEN];
int j, fd, newmsgs = 0, unreadmsgs = 0;
char line[MAX_COM_LEN];
cur_player->first_msg = NEW(Message, 1);
cur_player->first_msg = NULL;
sprintf(path, "%s/%s", MAIL_DIR, pname(mynum));
if ((fd = OPEN(path, O_RDONLY, 0644)) == -1) {
cur_player->cur_msg = NULL;
bprintf("You have no mail.\n\n");
return;
}
else {
for (message = cur_player->first_msg, j = 0 ;; j++) {
Messageptr newmessage = NULL;
newmessage = NEW(Message, 1);
if (getline(fd, line) != -1)
strcpy(newmessage->mailfrom, &line[6]);
else {
if (!newmsgs && !unreadmsgs)
bprintf("You have no unread mail.\n");
else if (!newmsgs && unreadmsgs)
bprintf("You have %d unread %s waiting, %s.\n", unreadmsgs,
(unreadmsgs == 1) ? "message" : "messages", pname(mynum));
else if (newmsgs && unreadmsgs)
bprintf("You have %d unread %s and %d &+Ynew&N, %s.\n", unreadmsgs,
(unreadmsgs == 1) ? "message" : "messages", newmsgs, pname(mynum));
else if (newmsgs && !unreadmsgs)
bprintf("You have %d &+Ynew &N%s, %s.\n", newmsgs,
(newmsgs == 1) ? "message" : "messages", pname(mynum));
CLOSE(fd);
return;
}
getline(fd, line);
strcpy(newmessage->subject, &line[9]);
getline(fd, line);
strcpy(newmessage->date, &line[6]);
getline(fd, line);
newmessage->status = line[8];
newmessage->text = lseek(fd, 0L, SEEK_CUR);
if (newmessage->status == 'N')
newmsgs++;
else if (newmessage->status == 'O')
unreadmsgs++;
strcpy(newmessage->mailto, pname(mynum));
do { /* skip to next entry */
getline(fd, line);
} while(!strstr(line, DELIM));
newmessage->next = NULL;
if (j == 0) { /* first message */
newmessage->prev = NULL;
cur_player->cur_msg = newmessage;
cur_player->first_msg = newmessage;
message = newmessage;
}
else {
newmessage->prev = message;
message->next = newmessage;
message = message->next;
}
}
}
}
/* extracts/saves a message from the players mailbox, should only be used
when the player exits the mailer, since it changes the current msg */
void save(Messageptr message, int fd) {
cur_player->cur_msg = message;
cur_player->work_msg = message;
store_header(fd);
write_text(fd);
write(fd, DELIM, strlen(DELIM));
write(fd, "\n", 1);
}
void check_for_internet_mail() {
FILE *fptr;
char path[80];
/* Messageptr message = (Messageptr) malloc(sizeof(Message)); */
return; /* for now. :) */
sprintf(path, "%s/%s", MAIL_DIR, cur_player->work_msg->mailto);
if ((fptr = FOPEN(path, "a")) != NULL) {
}
}