# # Patch name: CoolMail # Patch version: 1 # Author's name: Leonid Korogodsky # Author's email: leokor@math.ias.edu (only till September 1997) # Version of PennMUSH: 1.6.10-patch06 # Date patch made: July 16, 1007 # Author is willing to support (yes/no): yes # Patch format: diff -c # # # This is a contributed PennMUSH patch. Its use is subject to the # same restrictions found in PennMUSH's hdrs/copyrite.h file. # # No warranty is given for this patch. It is not necessarily going # to work on your system, with any version of PennMUSH other than # the one above, etc. # # If the author given above was willing to support the patch, you # should write to the author if you have any questions or problems. Do # *NOT* send email messages to Javelin or any PennMUSH mailing list about # this patch! # # Below this line is the author's description of the patch, # followed by the patch itself. If the patch is in context diff # format, you'll probably apply it by typing: patch < patchfile # in your top-level MUSH directory, unless instructed otherwise # below. # This patch introduces a new kind of @mail messages, those marked with the "Draft" mail flag. They can be created with the @mail/draft command, edited with @mail/edit and @mail/subject (if you have MAIL_SUBJECTS option on), and sent with @mail/fwd. They are stored in the folder 1, while their already sent copies in the folder 2. Also, two maildb extensions are in here, providing the complete field of addressees per each @mail message and the original author of the message (helpful if it was forwarded). They come with the mailto() and mailauthor() functions. The format of the change is through three options into dune.h. The change in the maildb format is flexible enough, as it is protected against the switch in the options by some MDBF flags. The following is a brief synopsis of the changes in the CHANGE-* style (although, I do not include that in the patch, as is asked of all contributors). However, I do patch pennmail.hlp, so you can have a better look. :) If Penn 1.7.0 is released before the middle of August, I will update the patch to 1.7.0. Cannot say for sure about the time after that. ========================================================================== Special @mail Features (by Leonid Korogodsky) (leokor@math.ias.edu till Sept, 1997) Major Changes: * MAIL_DRAFTS option enables drafting and editing @mail messages. * @mail/draft, @mail/edit, and @mail/subject commands. * MAIL_CC option remembers the complete list of addressees in the @mail messages. The reply messages recieve a separate addressee field. * MAIL_AUTHOR option remembers the original author of the forwarded @mail messages. * Both MAIL_CC and MAIL_AUTHOR options have the maildb protected with respective MDBF flags. Minor Changes: * mailto() and mailauthor() functions. * The M_REPLY flag is now reflected in the @mail status string, together with M_DRAFT and M_SENT. * The player is now notified of the number of messages sent by do_mail_send(). * The layout of the @mail headings is slightly changed, "(no subject)" is replaced with "(No Subject)", and other minor embellishments. :) Fixes: * Cleaned some minor conflicts between signed and unsigned in extmail.c. ========================================================================== *** dune.h.dist.orig Tue Jul 15 10:01:23 1997 --- dune.h.dist Wed Jul 16 15:59:52 1997 *************** *** 422,426 **** --- 422,444 ---- /* If defined, DARK wizards don't trigger AENTER/ALEAVE as they move around */ /* #define WIZ_NOAENTER /* */ + /* If defined, the complete addressee fields adds to the @mail messages. + * This option increases the size of the maildb, so do not define it if + * you worry about the memory space. + */ + /* #define MAIL_CC /* */ + /* If defined, @mail remembers the original author of the forwarded + * messages. This option also takes extra memory for the maildb, although + * not as much as CC_FIELD can take. + */ + /* #define MAIL_AUTHOR /* */ + + /* If defined, the @mail/draft command is enabled, which creates draft + * messages in the DRAFTS (1) folder. The @mail/edit allows to edit + * draft messages (those marked with the M_DRAFT flag). + */ + /* #define MAIL_DRAFTS /* */ + + #endif /* __DUNE_H */ *** hdrs/dbdefs.h.orig Tue Jul 15 13:30:09 1997 --- hdrs/dbdefs.h Wed Jul 16 16:04:14 1997 *************** *** 278,288 **** --- 278,295 ---- ((db[(thing)].next = (locative)), (locative) = (thing)) #ifdef USE_MAILER + struct mail { struct mail *next; struct mail *prev; dbref to; dbref from; + #ifdef MAIL_CC + struct dblist *cc; + #endif + #ifdef MAIL_AUTHOR + dbref author; + #endif unsigned char *message; /* compressed */ unsigned char *time; /* compressed */ #ifdef MAIL_SUBJECTS *** hdrs/extmail.h.orig Tue Jul 15 13:30:36 1997 --- hdrs/extmail.h Wed Jul 16 02:36:04 1997 *************** *** 13,18 **** --- 13,22 ---- #define M_RECEIPT 0x0020 #define M_TAG 0x0040 #define M_FORWARD 0x0080 + #ifdef MAIL_DRAFTS + #define M_DRAFT 0x0100 + #define M_SENT 0x0200 + #endif /* 0x0100 - 0x0F00 reserved for folder numbers */ #define M_FMASK 0xF0FF #define M_ALL 0x1000 /* In mail_selector, all msgs in all folders */ *************** *** 38,43 **** --- 42,51 ---- #define All(ms) (ms.flags & M_ALL) #define AllInFolder(ms) (ms.flags & M_FOLDER) #define MSFolder(ms) ((ms.flags & ~M_FMASK) >> 8) + #ifdef MAIL_DRAFTS + #define Draft(m) (m->read & M_DRAFT) + #define Sent(m) (m->read & M_SENT) + #endif typedef unsigned int mail_flag; *************** *** 60,64 **** --- 68,74 ---- #define MDBF_SUBJECT 0x1 #define MDBF_ALIASES 0x2 + #define MDBF_CC 0x4 + #define MDBF_AUTHOR 0x8 #endif /* _EXTMAIL_H */ *** hdrs/function.h.orig Tue Jul 15 13:30:28 1997 --- hdrs/function.h Wed Jul 16 16:05:58 1997 *************** *** 164,169 **** --- 164,175 ---- FUNCTION_PROTO(fun_mail); /* extmail.c */ FUNCTION_PROTO(fun_mailfrom); /* extmail.c */ FUNCTION_PROTO(fun_mailtime); /* extmail.c */ + #ifdef MAIL_CC + FUNCTION_PROTO(fun_mailto); /* extmail.c */ + #endif + #ifdef MAIL_AUTHOR + FUNCTION_PROTO(fun_mailauthor); /* extmail.c */ + #endif FUNCTION_PROTO(fun_mailstatus); /* extmail.c */ #ifdef MAIL_SUBJECTS FUNCTION_PROTO(fun_mailsubject); /* extmail.c */ *** src/extmail.c.orig Tue Jul 15 13:38:58 1997 --- src/extmail.c Wed Jul 16 20:56:12 1997 *************** *** 77,82 **** --- 77,83 ---- #include "match.h" #include "extmail.h" #include "parse.h" + #include "ansi.h" #include "confmagic.h" #define notify(p,m) notify_check(p,m,0) *************** *** 100,111 **** static struct mail *mail_fetch _((dbref player, int num)); static struct mail *real_mail_fetch _((dbref player, int num, int folder)); static struct mail *mailfun_fetch _((dbref player, int nargs, char *arg1, char *arg2)); ! static void count_mail _((dbref player, int folder, int *rcount, int *ucount, int *ccount)); ! #ifdef MAIL_SUBJECTS ! static void send_mail _((dbref player, dbref target, unsigned char *subject, char *message, mail_flag flags, int silent)); #else ! static void send_mail _((dbref player, dbref target, char *message, mail_flag flags, int silent)); #endif void do_mail_nuke _((dbref player)); void do_mail_debug _((dbref player, char *action, char *victim)); void do_mail_stats _((dbref player, char *name, int full)); --- 101,113 ---- static struct mail *mail_fetch _((dbref player, int num)); static struct mail *real_mail_fetch _((dbref player, int num, int folder)); static struct mail *mailfun_fetch _((dbref player, int nargs, char *arg1, char *arg2)); ! #ifdef MAIL_DRAFTS ! static void count_mail _((dbref player, int folder, int *rcount, int *ucount, int *ccount, int *dcount, int *scount)); #else ! static void count_mail _((dbref player, int folder, int *rcount, int *ucount, int *ccount)); #endif + void do_mail_heading _((dbref player, struct mail *mp)); + static void send_mail _((dbref player, dbref target, unsigned char *subject, char *message, mail_flag flags, int silent, struct dblist *address, dbref author)); void do_mail_nuke _((dbref player)); void do_mail_debug _((dbref player, char *action, char *victim)); void do_mail_stats _((dbref player, char *name, int full)); *************** *** 128,136 **** --- 130,144 ---- static char *status_string _((struct mail * mp)); void check_mail _((dbref player, int folder, int silent)); static int sign _((int x)); + #ifdef MAIL_DRAFTS + void do_mail_edit _((dbref player, char *msglist, char **argv)); + #endif #ifdef MAIL_SUBJECTS static char *get_subject _((struct mail * mp)); + #ifdef MAIL_DRAFTS + void do_mail_subject _((dbref player, char *msglist, char *subj)); #endif + #endif struct mail *maildb; struct mail *tail_ptr; *************** *** 181,187 **** } } } else ! strcpy(sbuf, "(no subject)"); return sbuf; } #endif --- 189,195 ---- } } } else ! strcpy(sbuf, "(No Subject)"); return sbuf; } #endif *************** *** 386,391 **** --- 394,486 ---- return; } + void + do_mail_heading(player, mp) + dbref player; + struct mail *mp; + { + char tbuf1[BUFFER_LEN]; + char tbuf2[BUFFER_LEN]; + char conn1[BUFFER_LEN]; + char conn2[BUFFER_LEN]; + char conn3[BUFFER_LEN]; + char conn4[BUFFER_LEN]; + char *bp; + struct dblist *list = mp->cc; + + strcpy(conn1, + (Connected(mp->from) && (!hidden(mp->from) || + Hasprivs(player))) ? "(Connected)" : " "); + strcpy(conn2, + (Connected(mp->author) && (!hidden(mp->author) || + Hasprivs(player))) ? "(Connected)" : " "); + strcpy(conn3, + (Connected(Owner(mp->from)) && + (!hidden(Owner(mp->from)) || + Hasprivs(player))) ? "(Connected)" : " "); + strcpy(conn4, + (Connected(Owner(mp->author)) && + (!hidden(Owner(mp->author)) || + Hasprivs(player))) ? "(Connected)" : " "); + #ifdef MAIL_AUTHOR + if (Typeof(mp->from) == TYPE_PLAYER) { + if (Forward(mp) && (Typeof(mp->author) == TYPE_PLAYER)) + sprintf(tbuf1, "From: %-52s %s\nOriginally by: %-43s %s", + Name(mp->from), conn1, Name(mp->author), conn2); + else if (Forward(mp)) + sprintf(tbuf1, + "From: %-52s %s\nOriginally by: %-16s Owner: %-17s %s", + Name(mp->from), conn1, Name(mp->author), + Name(Owner(mp->author)), conn4); + else + sprintf(tbuf1, "From: %-52s %s", Name(mp->from), conn1); + } else { + if (Forward(mp) && (Typeof(mp->author) == TYPE_PLAYER)) + sprintf(tbuf1, + "From: %-16s Owner: %-17s %s\nOriginally by: %-43s %s", + Name(mp->from), Name(Owner(mp->from)), conn3, + Name(mp->author), conn2); + else if (Forward(mp)) + sprintf(tbuf1, + "From: %-22s Owner: %-22s %s\nOriginally by: %-17s Owner: %-18s %s", + Name(mp->from), Name(Owner(mp->from)), conn3, + Name(mp->author), Name(Owner(mp->author)), conn4); + else + sprintf(tbuf1, "From: %-22s Owner: %-22s %s", + Name(mp->from), Name(Owner(mp->from)), conn3); + } + #else + if (Typeof(mp->from) == TYPE_PLAYER) + sprintf(tbuf1, "%s", Name(mp->from)); + else + sprintf(tbuf1, "%-22s Owner: %s", + Name(mp->from), Name(Owner(mp->from))); + #endif /* MAIL_AUTHOR */ + #ifdef MAIL_CC + strcpy(tbuf2, " "); + bp = tbuf2; + while (list) { + if (Connected(list->obj)) + safe_chr('*', tbuf2, &bp); + safe_str(Name(list->obj), tbuf2, &bp); + safe_chr(' ', tbuf2, &bp); + list = list->next; + } + *bp = '\0'; + #ifdef MAIL_AUTHOR + notify(player, tprintf("%s\nTo: %s", tbuf1, tbuf2)); + #else + notify(player, tprintf("From: %-55s\nTo: %s", tbuf1, tbuf2)); + #endif + #else /* MAIL_CC */ + #ifdef MAIL_AUTHOR + notify(player, tbuf1); + #else + notify(player, tprintf("From: %-55s", tbuf1)); + #endif + #endif /* MAIL_CC */ + } + void do_mail_read(player, msglist) dbref player; *************** *** 414,431 **** /* Read it */ j++; notify(player, DASH_LINE); ! if (Typeof(mp->from) == TYPE_PLAYER) ! sprintf(tbuf1, "%s", Name(mp->from)); ! else ! sprintf(tbuf1, "%s (owner: %s)", Name(mp->from), Name(Owner(mp->from))); ! notify(player, tprintf("From: %-55s %s\nDate: %-25s Folder: %2d Message: %d\nStatus: %s", ! tbuf1, ! ((Typeof(mp->from) == TYPE_PLAYER) && Connected(mp->from) && ! (!hidden(mp->from) || Hasprivs(player))) ? ! " (Conn)" : " ", ! uncompress(mp->time), ! Folder(mp), i[Folder(mp)], ! status_string(mp))); #ifdef MAIL_SUBJECTS notify(player, tprintf("Subject: %s", get_subject(mp))); #endif --- 509,520 ---- /* Read it */ j++; notify(player, DASH_LINE); ! do_mail_heading(player, mp); ! notify(player, ! tprintf("Date: %-25s Folder: %2d Message: %d\nStatus: %s", ! uncompress(mp->time), ! Folder(mp), i[Folder(mp)], ! status_string(mp))); #ifdef MAIL_SUBJECTS notify(player, tprintf("Subject: %s", get_subject(mp))); #endif *************** *** 477,483 **** /* list it */ #ifdef MAIL_SUBJECTS strcpy(subj, chopstr(get_subject(mp), 28)); ! notify(player, tprintf("[%s] %2d:%-3d %c%-12s %-*s %s", status_chars(mp), Folder(mp), i[Folder(mp)], ((Connected(mp->from) && (!hidden(mp->from) || Hasprivs(player))) --- 566,572 ---- /* list it */ #ifdef MAIL_SUBJECTS strcpy(subj, chopstr(get_subject(mp), 28)); ! notify(player, tprintf("[%s] %d:%-3d %c%-12s %-*s %s", status_chars(mp), Folder(mp), i[Folder(mp)], ((Connected(mp->from) && (!hidden(mp->from) || Hasprivs(player))) *************** *** 486,492 **** 30, subj, mail_list_time(uncompress(mp->time), 1))); #else ! notify(player, tprintf("[%s] %2d:%-3d (%4d) From: %-*s At: %s %s", status_chars(mp), Folder(mp), i[Folder(mp)], strlen(uncompress(mp->message)), PLAYER_NAME_LIMIT + 1, Name(mp->from), --- 575,581 ---- 30, subj, mail_list_time(uncompress(mp->time), 1))); #else ! notify(player, tprintf("[%s] %d:%-3d (%4d) From: %-*s At: %s %s", status_chars(mp), Folder(mp), i[Folder(mp)], strlen(uncompress(mp->message)), PLAYER_NAME_LIMIT + 1, Name(mp->from), *************** *** 581,587 **** --- 670,845 ---- return; } + #ifdef MAIL_DRAFTS + #ifdef MAIL_SUBJECTS void + do_mail_subject(player, msglist, subj) + dbref player; + char *msglist; + char *subj; + { + struct mail *mp; + struct mail_selector ms; + int j, folder; + folder_array i; + int counter = 0; + + if (!parse_msglist(msglist, &ms, player)) { + return; + } + #ifndef ALLOW_NOSUBJECT + if (!subj || !*subj) { + notify(player, "MAIL: What subject do you want to set?"); + return; + } + #endif + FA_Init(i, j); + j = 0; + folder = MSFolder(ms) ? MSFolder(ms) : player_folder(player); + for (mp = find_exact_starting_point(player); + mp && (mp->to == player); + mp = mp->next) { + if ((mp->to == player) && (All(ms) || (Folder(mp) == folder))) { + i[Folder(mp)]++; + if (mail_match(player, mp, ms, i[Folder(mp)])) { + j++; + if (Draft(mp)) { + counter++; + if (!subj || !*subj) + mp->subject = u_strdup(compress("(No Subject)")); + else + mp->subject = u_strdup(compress(chopstr(tprintf("%s", subj), SUBJECT_LEN))); + } else + notify(player, "MAIL: You can edit only draft messages."); + } + } + } + if (!j) + notify(player, "MAIL: You don't have any matching messages!"); + else if (counter == 1) { + if (!subj || !*subj) + notify(player, "MAIL: The subject is changed to: '(No Subject)'."); + else + notify(player, tprintf("MAIL: The subject is changed to: '%s'.", subj)); + } else if (counter > 1) { + if (!subj || !*subj) + notify(player, tprintf("MAIL: The subject is changed to: '(No Subject)' for %d draft messages.", counter)); + else + notify(player, tprintf("MAIL: The subject is changed to: '%s' for %d draft messages.", subj, counter)); + } + } + #endif /* MAIL_SUBJECTS */ + + void + do_mail_edit(player, msglist, argv) + dbref player; + char *msglist; + char **argv; + { + struct mail *mp; + struct mail_selector ms; + int j, folder; + folder_array i; + int counter = 0; + int k, d, len, res, ansi_d, ansi_long_flag = 0; + char *r, *s, *val, *bp1; + char tbuf1[BUFFER_LEN]; + char tbuf_ansi[BUFFER_LEN]; + + if (!parse_msglist(msglist, &ms, player)) { + return; + } + + FA_Init(i, j); + j = 0; + folder = MSFolder(ms) ? MSFolder(ms) : player_folder(player); + for (mp = find_exact_starting_point(player); + mp && (mp->to == player); + mp = mp->next) { + if ((mp->to == player) && (All(ms) || (Folder(mp) == folder))) { + i[Folder(mp)]++; + if (mail_match(player, mp, ms, i[Folder(mp)])) { + j++; + if (!Draft(mp)) + notify(player, "MAIL: You can edit only draft messages."); + else { + bp1 = tbuf1; + val = argv[1]; + r = (argv[2]) ? argv[2] : (char *) ""; + s = (char *) uncompress(mp->message); /* warning: pointer to static buffer */ + if (!strcmp(val, "$")) { + /* append */ + strcpy(tbuf1, s); + if (strlen(s) + strlen(r) < BUFFER_LEN) + strcat(tbuf1, r); + if (strlen(tbuf1) + strlen(ANSI_HILITE) + strlen(ANSI_NORMAL) < BUFFER_LEN) + sprintf(tbuf_ansi, "%s%s%s%s", s, ANSI_HILITE, r, ANSI_NORMAL); + else + strcpy(tbuf_ansi, tbuf1); + } else if (!strcmp(val, "^")) { + /* prepend */ + strcpy(tbuf1, r); + strncat(tbuf1, s, BUFFER_LEN - strlen(r) - 1); + if (strlen(tbuf1) + strlen(ANSI_HILITE) + strlen(ANSI_NORMAL) < BUFFER_LEN) + sprintf(tbuf_ansi, "%s%s%s%s", ANSI_HILITE, r, ANSI_NORMAL, s); + else + strcpy(tbuf_ansi, tbuf1); + } else { + /* find and replace */ + len = strlen(val); + for (d = 0, ansi_d = 0; (d < BUFFER_LEN) && *s;) { + if (strncmp(val, s, len) == 0) { + if ((d + strlen(r)) < BUFFER_LEN) { + strcpy(tbuf1 + d, r); + d += strlen(r); + if ((ansi_d + strlen(r) + strlen(ANSI_HILITE) + strlen(ANSI_NORMAL)) < BUFFER_LEN) { + sprintf(tbuf_ansi + ansi_d, "%s%s%s", ANSI_HILITE, r, ANSI_NORMAL); + ansi_d += strlen(r) + strlen(ANSI_HILITE) + strlen(ANSI_NORMAL); + } else { + /* Hmm. What here? We can't assume that r will still fit. */ + /* For now, let's just give up. After all, how often is this + * going to arise, anyway? */ + if (!ansi_long_flag) { + ansi_long_flag = 1; + strcpy(tbuf_ansi, "MAIL: Sorry, that message became too long to display. Read it to see its new value."); + /* Not informative, but at least not a lie. */ + } + } + s += len; + } else + break; + } else + tbuf1[d++] = tbuf_ansi[ansi_d++] = *s++; + } + tbuf1[d++] = 0; + tbuf_ansi[ansi_d++] = '\0'; + } + mp->message = u_strdup(compress(bp1)); + if (!ansi_long_flag) { + notify(player, DASH_LINE); + do_mail_heading(player, mp); + notify(player, + tprintf("Date: %-25s Folder: %2d Message: %d\nStatus: %s", + uncompress(mp->time), + Folder(mp), i[Folder(mp)], + status_string(mp))); + #ifdef MAIL_SUBJECTS + notify(player, tprintf("Subject: %s", get_subject(mp))); + #endif + notify(player, DASH_LINE); + notify(player, tbuf_ansi); + notify(player, DASH_LINE); + } + } + } + } + } + if (!j) + notify(player, "MAIL: You don't have any matching messages!"); + } + #endif /* MAIL_DRAFTS */ + + void do_mail_fwd(player, msglist, tolist) dbref player; char *msglist; *************** *** 596,609 **** --- 854,882 ---- struct mail *temp; dbref target; int num_recpts = 0; + struct dblist *list; + struct dblist *list1 = NULL; + struct dblist *list2 = NULL; + struct dblist *aux1, *aux2; + dbref author; + unsigned char *subject; + mail_flag flags; if (!parse_msglist(msglist, &ms, player)) { return; } + #ifndef MAIL_DRAFTS if (!tolist || !*tolist) { notify(player, "MAIL: To whom should I forward?"); return; } + #endif + #ifndef MAIL_CC + if (!tolist || !*tolist) { + notify(player, "MAIL: To whom should I forward?"); + return; + } + #endif folder = MSFolder(ms) ? MSFolder(ms) : player_folder(player); /* Mark the player's last message. This prevents a loop if * the forwarding command happens to forward a message back *************** *** 622,689 **** if ((mp->to == player) && (All(ms) || (Folder(mp) == folder))) { i[Folder(mp)]++; if (mail_match(player, mp, ms, i[Folder(mp)])) { ! /* forward it to all players listed */ ! head = (char *) tolist; ! 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; ! /* Now locate a target */ ! num = atoi(head); ! if (num) { ! /* reply to a mail message */ ! temp = mail_fetch(player, num); ! if (!temp) { ! notify(player, "MAIL: You can't reply to nonexistant mail."); } else { ! #ifdef MAIL_SUBJECTS ! send_mail(player, temp->from, mp->subject, mp->message, M_FORWARD | M_REPLY, 1); #else ! send_mail(player, temp->from, mp->message, M_FORWARD | M_REPLY, 1); #endif - num_recpts++; - } - } else { - /* forwarding to a player */ - if (!strcasecmp(head, "me")) - target = player; - else if (*head == '#') { - target = atoi(head + 1); - if (!GoodObject(target)) - target = NOTHING; - } else - target = lookup_player(head); - if ((target == NOTHING) || (Typeof(target) != TYPE_PLAYER)) { - notify(player, "No such player."); - } else { #ifdef MAIL_SUBJECTS ! send_mail(player, target, mp->subject, mp->message, M_FORWARD, 1); #else ! send_mail(player, target, mp->message, M_FORWARD, 1); #endif ! num_recpts++; } } ! /* Get the next recip */ ! *tail = spot; ! head = tail; ! if (*head == '"') ! head++; } } } --- 895,1036 ---- if ((mp->to == player) && (All(ms) || (Folder(mp) == folder))) { i[Folder(mp)]++; if (mail_match(player, mp, ms, i[Folder(mp)])) { ! #ifdef MAIL_DRAFTS ! #ifdef MAIL_CC ! if (!tolist || !*tolist) { ! /* If there is no new list of addressees, ! * send to the old one from the draft. ! */ ! if (!Draft(mp)) ! notify(player, "MAIL: To whom should I forward?"); ! else { ! #ifdef MAIL_AUTHOR ! author = mp->author; ! #else ! author = NOTHING; ! #endif ! #ifdef MAIL_SUBJECTS ! subject = mp->subject; ! #else ! subject = NULL; ! #endif ! list = mp->cc; ! while (list) { ! if (GoodObject(list->obj)) { ! send_mail(player, list->obj, subject, (char *) mp->message, NULL, 1, mp->cc, author); ! num_recpts++; ! } ! list = list->next; ! } ! #ifdef MAIL_DRAFTS ! if (Draft(mp)) { ! mp->read = flags & M_SENT; ! mp->read &= M_FMASK; /* Clear the folder */ ! mp->read |= FolderBit(2); /* Send to folder 2 */ ! } ! #endif ! } ! } else { ! #endif /* MAIL_CC */ ! #endif /* MAIL_DRAFTS */ ! /* forward it to all players listed */ ! head = (char *) tolist; ! 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; ! /* Now locate a target */ ! num = atoi(head); ! if (num) { ! /* reply to a mail message */ ! temp = mail_fetch(player, num); ! if (!temp) { ! notify(player, "MAIL: You can't reply to nonexistant mail."); ! } else { ! if (list1) ! listadd(list1, temp->from); ! else ! list1 = listcreate(temp->from); ! num_recpts++; ! } } else { ! /* forwarding to a player */ ! if (!strcasecmp(head, "me")) ! target = player; ! else if (*head == '#') { ! target = atoi(head + 1); ! if (!GoodObject(target)) ! target = NOTHING; ! } else ! target = lookup_player(head); ! if ((target == NOTHING) || (Typeof(target) != TYPE_PLAYER)) { ! notify(player, "No such player."); ! } else { ! if (list2) ! listadd(list2, target); ! else ! list2 = listcreate(target); ! num_recpts++; ! } ! } ! /* Get the next recip */ ! *tail = spot; ! head = tail; ! if (*head == '"') ! head++; ! } ! #ifdef MAIL_AUTHOR ! author = mp->author; #else ! author = player; #endif #ifdef MAIL_SUBJECTS ! subject = mp->subject; #else ! subject = NULL; #endif ! #ifdef MAIL_DRAFTS ! if (Draft(mp)) { ! flags = NULL; ! mp->read = flags & M_SENT; ! mp->read &= M_FMASK; /* Clear the folder */ ! mp->read |= FolderBit(2); /* Send to folder 2 */ ! } else ! flags = M_FORWARD; ! #else ! flags = M_FORWARD; ! #endif ! if (list1) { ! aux1 = list1; ! while (aux1) { ! send_mail(player, aux1->obj, subject, (char *) mp->message, flags | M_REPLY, 1, list1, author); ! aux1 = aux1->next; } + listfree(list1); } ! if (list2) { ! aux2 = list2; ! while (aux2) { ! send_mail(player, aux2->obj, subject, (char *) mp->message, flags, 1, list2, author); ! aux2 = aux2->next; ! } ! listfree(list2); ! } } } } *************** *** 692,697 **** --- 1039,1049 ---- notify(player, tprintf("MAIL: %d messages forwarded.", num_recpts)); } + struct subj_list { + unsigned char *str; + struct subj_list *next; + }; + void do_mail_send(player, tolist, message, flags, silent) dbref player; *************** *** 708,713 **** --- 1060,1072 ---- char sbuf[SUBJECT_LEN + 1], *sb, *mb; int i = 0, subject_given = 0; #endif + struct dblist *list1 = NULL; + struct dblist *list2 = NULL; + struct dblist *aux1, *aux2; + int num_recpts = 0; + unsigned char *subject; + struct subj_list *subj = NULL; + struct subj_list *ptr, *ptra, *ptrb; if (!tolist || !*tolist) { notify(player, "MAIL: I can't figure out who you want to mail to."); *************** *** 732,738 **** message = mb; /* Rewind the pointer to the beginning */ #ifdef ALLOW_NOSUBJECT if (!subject_given) ! strcpy(sbuf, "(no subject)"); #endif #endif /* Parse the player list */ --- 1091,1097 ---- message = mb; /* Rewind the pointer to the beginning */ #ifdef ALLOW_NOSUBJECT if (!subject_given) ! strcpy(sbuf, "(No Subject)"); #endif #endif /* Parse the player list */ *************** *** 768,782 **** notify(player, "MAIL: You can't reply to nonexistant mail."); return; } ! #ifdef MAIL_SUBJECTS ! if (subject_given) ! send_mail(player, temp->from, compress(sbuf), message, mail_flags, silent); else ! send_mail(player, temp->from, temp->subject, message, ! mail_flags | M_REPLY, silent); ! #else ! send_mail(player, temp->from, message, mail_flags, silent); ! #endif } else { /* send a new mail message */ if (!strcasecmp(head, "me")) --- 1127,1153 ---- notify(player, "MAIL: You can't reply to nonexistant mail."); return; } ! if (list1) ! listadd(list1, temp->from); else ! list1 = listcreate(temp->from); ! if (subj) { ! ptr = subj; ! while (ptr->next) ! ptr = ptr->next; ! ptr->next = (struct subj_list *) mush_malloc((unsigned) sizeof(struct subj_list), "subj_list"); ! if (!ptr->next) ! panic("Out of memory."); ! ptr->next->str = temp->subject; ! ptr->next->next = NULL; ! } else { ! subj = (struct subj_list *) mush_malloc((unsigned) sizeof(struct subj_list), "subj_list"); ! if (!subj) ! panic("Out of memory."); ! subj->str = temp->subject; ! subj->next = NULL; ! } ! num_recpts++; } else { /* send a new mail message */ if (!strcasecmp(head, "me")) *************** *** 789,800 **** target = lookup_player(head); if (!GoodObject(target) || (Typeof(target) != TYPE_PLAYER)) notify(player, "No such player."); ! else ! #ifdef MAIL_SUBJECTS ! send_mail(player, target, compress(sbuf), message, mail_flags, silent); ! #else ! send_mail(player, target, message, mail_flags, silent); ! #endif } /* Get the next recip */ *tail = spot; --- 1160,1172 ---- target = lookup_player(head); if (!GoodObject(target) || (Typeof(target) != TYPE_PLAYER)) notify(player, "No such player."); ! else { ! if (list2) ! listadd(list2, target); ! else ! list2 = listcreate(target); ! num_recpts++; ! } } /* Get the next recip */ *tail = spot; *************** *** 802,807 **** --- 1174,1218 ---- if (*head == '"') head++; } + if (list1) { + aux1 = list1; + while (aux1) { + #ifdef MAIL_SUBJECTS + if (subject_given) + subject = compress(sbuf); + else + subject = subj->str; + #else + subject = NULL; + #endif + send_mail(player, aux1->obj, subject, message, mail_flags | M_REPLY, silent, list1, player); + aux1 = aux1->next; + subj = subj->next; + } + listfree(list1); + if (subj) { + ptra = subj; + while (ptra->next) { + ptrb = ptra->next; + mush_free((Malloc_t) ptra, "subj_list"); + ptra = ptrb; + } + } + } + if (list2) { + aux2 = list2; + while (aux2) { + #ifdef MAIL_SUBJECTS + subject = compress(sbuf); + #else + subject = NULL; + #endif + send_mail(player, aux2->obj, subject, message, mail_flags, silent, list2, player); + aux2 = aux2->next; + } + listfree(list2); + } + notify(player, tprintf("MAIL: %d messages sent.", num_recpts)); } /*-------------------------------------------------------------------------* *************** *** 844,851 **** return NULL; } ! static void count_mail(player, folder, rcount, ucount, ccount) dbref player; int folder; --- 1255,1272 ---- return NULL; } ! #ifdef MAIL_DRAFTS static void + count_mail(player, folder, rcount, ucount, ccount, dcount, scount) + dbref player; + int folder; + int *rcount; + int *ucount; + int *ccount; + int *dcount; + int *scount; + #else + static void count_mail(player, folder, rcount, ucount, ccount) dbref player; int folder; *************** *** 852,865 **** int *rcount; int *ucount; int *ccount; { /* returns count of read, unread, & cleared messages as rcount, ucount, * ccount. folder=-1 returns for all folders */ struct mail *mp; ! int rc, uc, cc; ! cc = rc = uc = 0; for (mp = find_exact_starting_point(player); mp && (mp->to == player); mp = mp->next) { --- 1273,1287 ---- int *rcount; int *ucount; int *ccount; + #endif { /* returns count of read, unread, & cleared messages as rcount, ucount, * ccount. folder=-1 returns for all folders */ struct mail *mp; ! int rc, uc, cc, dc, sc; ! cc = rc = uc = dc = sc = 0; for (mp = find_exact_starting_point(player); mp && (mp->to == player); mp = mp->next) { *************** *** 866,871 **** --- 1288,1299 ---- if ((mp->to == player) && ((folder == -1) || (Folder(mp) == folder))) { if (Cleared(mp)) cc++; + #ifdef MAIL_DRAFTS + else if (Sent(mp)) + sc++; + else if (Draft(mp)) + dc++; + #endif else if (Read(mp)) rc++; else *************** *** 875,898 **** *rcount = rc; *ucount = uc; *ccount = cc; } - - #ifdef MAIL_SUBJECTS static void ! send_mail(player, target, subject, message, flags, silent) ! #else ! static void ! send_mail(player, target, message, flags, silent) ! #endif dbref player; dbref target; - #ifdef MAIL_SUBJECTS unsigned char *subject; - #endif char *message; mail_flag flags; int silent; { /* send a mail message */ --- 1303,1324 ---- *rcount = rc; *ucount = uc; *ccount = cc; + #ifdef MAIL_DRAFTS + *dcount = dc; + *scount = sc; + #endif } static void ! send_mail(player, target, subject, message, flags, silent, address, author) dbref player; dbref target; unsigned char *subject; char *message; mail_flag flags; int silent; + struct dblist *address; + dbref author; { /* send a mail message */ *************** *** 904,910 **** ATTR *a; #endif ! if (Typeof(target) != TYPE_PLAYER) { notify(player, "MAIL: You cannot send mail to non-existent people."); return; } --- 1330,1337 ---- ATTR *a; #endif ! if ((Typeof(target) != TYPE_PLAYER) && ! !((flags & M_FORWARD) && (flags & M_REPLY))) { notify(player, "MAIL: You cannot send mail to non-existent people."); return; } *************** *** 926,937 **** newp = (struct mail *) mush_malloc(sizeof(struct mail), "mail"); newp->to = target; newp->from = player; #ifdef MAIL_SUBJECTS /* Deal with the subject */ if (subject) strcpy(sbuf, uncompress(subject)); else ! strcpy(sbuf, "(no subject)"); if ((flags & M_FORWARD) && !string_prefix(sbuf, "Fwd:")) newp->subject = u_strdup(compress(chopstr(tprintf("Fwd: %s", sbuf), SUBJECT_LEN))); else if ((flags & M_REPLY) && !string_prefix(sbuf, "Re:")) --- 1353,1370 ---- newp = (struct mail *) mush_malloc(sizeof(struct mail), "mail"); newp->to = target; newp->from = player; + #ifdef MAIL_CC + newp->cc = address; + #endif + #ifdef MAIL_AUTHOR + newp->author = author; + #endif #ifdef MAIL_SUBJECTS /* Deal with the subject */ if (subject) strcpy(sbuf, uncompress(subject)); else ! strcpy(sbuf, "(No Subject)"); if ((flags & M_FORWARD) && !string_prefix(sbuf, "Fwd:")) newp->subject = u_strdup(compress(chopstr(tprintf("Fwd: %s", sbuf), SUBJECT_LEN))); else if ((flags & M_REPLY) && !string_prefix(sbuf, "Re:")) *************** *** 949,954 **** --- 1382,1393 ---- newp->message = u_strdup(compress(message)); newp->time = u_strdup(compress(tbuf1)); newp->read = flags & M_FMASK; /* Send to folder 0 */ + #ifdef MAIL_DRAFTS + if (flags & M_DRAFT) { + newp->read &= M_FMASK; /* Clear the folder */ + newp->read |= FolderBit(1); /* Send to folder 1 */ + } + #endif /* Where do we insert it? After mp, wherever that is. * This can return NULL if there are no messages or *************** *** 989,998 **** --- 1428,1448 ---- mdb_top++; /* notify people */ + #ifdef MAIL_DRAFTS + if (silent == 2) + notify(player, "MAIL: You start writing a draft message."); + else { + 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))); + } + #else 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))); + #endif #ifdef AMAIL if ((atr_get_noparent(target, "AMAIL")) && (player != target) && *************** *** 1129,1135 **** --- 1579,1589 ---- int fc, fr, fu, tc, tr, tu, fchars, tchars, cchars; char last[50]; struct mail *mp; + #ifdef MAIL_DRAFTS + int fd, fs, dr, dc, du, dchars, schars; + fd = fs = dr = dc = du = dchars = schars = 0; + #endif fc = fr = fu = tc = tr = tu = cchars = fchars = tchars = 0; /* find player */ *************** *** 1181,1194 **** --- 1635,1660 ---- for (mp = HEAD; mp != NULL; mp = mp->next) { if (Cleared(mp)) fc++; + #ifdef MAIL_DRAFTS + else if (Sent(mp)) + fs++; + else if (Draft(mp)) + fd++; + #endif else if (Read(mp)) fr++; else fu++; } + #ifdef MAIL_DRAFTS notify(player, + tprintf("MAIL: There are %d msgs in the mail spool, %d drafts, %d sent, %d unread, %d cleared.", + fc + fd + fs + fr + fu, fd, fs, fu, fc)); + #else + notify(player, tprintf("MAIL: There are %d msgs in the mail spool, %d unread, %d cleared.", fc + fr + fu, fu, fc)); + #endif return; } else { for (mp = HEAD; mp != NULL; mp = mp->next) { *************** *** 1195,1200 **** --- 1661,1674 ---- if (Cleared(mp)) { fc++; cchars += strlen((char *) uncompress(mp->message)); + #ifdef MAIL_DRAFTS + } else if (Sent(mp)) { + fs++; + schars += strlen((char *) uncompress(mp->message)); + } else if (Draft(mp)) { + fd++; + dchars += strlen((char *) uncompress(mp->message)); + #endif } else if (Read(mp)) { fr++; fchars += strlen((char *) uncompress(mp->message)); *************** *** 1203,1210 **** --- 1677,1694 ---- tchars += strlen((char *) uncompress(mp->message)); } } + #ifdef MAIL_DRAFTS notify(player, tprintf( + "MAIL: There are %d unsent draft msgs in the mail spool, totalling %d characters.", + fd, dchars)); + notify(player, + tprintf( + "MAIL: There are %d sent draft msgs in the mail spool, totalling %d characters.", + fs, schars)); + #endif + notify(player, + tprintf( "MAIL: There are %d old msgs in the mail spool, totalling %d characters.", fr, fchars)); notify(player, *************** *** 1223,1240 **** --- 1707,1757 ---- if (full == 0) { /* just count number of messages */ for (mp = HEAD; mp != NULL; mp = mp->next) { + #ifdef MAIL_DRAFTS + if ((mp->from == target) && !Draft(mp)) + fr++; + if ((mp->from == target) && Draft(mp)) + dr++; + #else if (mp->from == target) fr++; + #endif if (mp->to == target) tr++; } notify(player, tprintf("%s sent %d messages.", Name(target), fr)); + #ifdef MAIL_DRAFTS + notify(player, tprintf("%s is drafting %d messages.", + Name(target), dr)); + #endif notify(player, tprintf("%s has %d messages.", Name(target), tr)); return; } /* more detailed message count */ for (mp = HEAD; mp != NULL; mp = mp->next) { + #ifdef MAIL_DRAFTS + if ((mp->from == target) && (!Draft(mp))) { + if (Cleared(mp)) + fc++; + else if (Read(mp)) + fr++; + else + fu++; + if (full == 2) + fchars += strlen((char *) uncompress(mp->message)); + } + if ((mp->from == target) && Draft(mp)) { + if (Cleared(mp)) + dc++; + else if (Read(mp)) + dr++; + else + du++; + if (full == 2) + dchars += strlen((char *) uncompress(mp->message)); + } + #else if (mp->from == target) { if (Cleared(mp)) fc++; *************** *** 1245,1250 **** --- 1762,1768 ---- if (full == 2) fchars += strlen((char *) uncompress(mp->message)); } + #endif if (mp->to == target) { if (!tr && !tu) strcpy(last, (char *) uncompress(mp->time)); *************** *** 1264,1269 **** --- 1782,1791 ---- if (full == 1) { notify(player, tprintf("%d messages sent, %d unread, %d cleared.", fc + fr + fu, fu, fc)); + #ifdef MAIL_DRAFTS + notify(player, tprintf("%d messages drafted, %d unread, %d cleared.", + dc + dr + du, du, dc)); + #endif notify(player, tprintf("%d messages received, %d unread, %d cleared.", tc + tr + tu, tu, tc)); } else { *************** *** 1270,1275 **** --- 1792,1801 ---- notify(player, tprintf("%d messages sent, %d unread, %d cleared, totalling %d characters.", fc + fr + fu, fu, fc, fchars)); + #ifdef MAIL_DRAFTS + notify(player, tprintf("%d messages drafted, %d unread, %d cleared, totalling %d characters.", + dc + dr + du, du, dc, dchars)); + #endif notify(player, tprintf("%d messages received, %d unread, %d cleared, totalling %d characters.", tc + tr + tu, tu, tc, tchars)); *************** *** 1346,1356 **** * folderstats(player,folder#) -> returns stats for player's folder folder# */ dbref player; ! int rc, uc, cc; if (nargs == 0) { count_mail(executor, player_folder(executor), &rc, &uc, &cc); safe_str(unparse_integer(rc + uc), buff, bp); return; } if (nargs == 1) { --- 1872,1887 ---- * folderstats(player,folder#) -> returns stats for player's folder folder# */ dbref player; ! int rc, uc, cc, dc, sc; if (nargs == 0) { + #ifdef MAIL_DRAFTS + count_mail(executor, player_folder(executor), &rc, &uc, &cc, &dc, &sc); + safe_str(unparse_integer(rc + uc +dc +sc), buff, bp); + #else count_mail(executor, player_folder(executor), &rc, &uc, &cc); safe_str(unparse_integer(rc + uc), buff, bp); + #endif return; } if (nargs == 1) { *************** *** 1363,1369 **** --- 1894,1908 ---- safe_str("#-1 PERMISSION DENIED", buff, bp); return; } else { + #ifdef MAIL_DRAFTS + count_mail(player, player_folder(player), &rc, &uc, &cc, &dc, &sc); + safe_str(unparse_integer(dc), buff, bp); + safe_chr(' ', buff, bp); + safe_str(unparse_integer(sc), buff, bp); + safe_chr(' ', buff, bp); + #else count_mail(player, player_folder(player), &rc, &uc, &cc); + #endif safe_str(unparse_integer(rc), buff, bp); safe_chr(' ', buff, bp); safe_str(unparse_integer(uc), buff, bp); *************** *** 1372,1379 **** --- 1911,1923 ---- return; } } else { + #ifdef MAIL_DRAFTS + count_mail(executor, parse_integer(args[0]), &rc, &uc, &cc, &dc, &sc); + safe_str(unparse_integer(rc + uc + dc + sc), buff, bp); + #else count_mail(executor, parse_integer(args[0]), &rc, &uc, &cc); safe_str(unparse_integer(rc + uc), buff, bp); + #endif return; } } else { *************** *** 1388,1394 **** --- 1932,1946 ---- safe_str("#-1 FOLDER MUST BE INTEGER", buff, bp); return; } + #ifdef MAIL_DRAFTS + count_mail(player, parse_integer(args[1]), &rc, &uc, &cc, &dc, &sc); + safe_str(unparse_integer(dc), buff, bp); + safe_chr(' ', buff, bp); + safe_str(unparse_integer(sc), buff, bp); + safe_chr(' ', buff, bp); + #else count_mail(player, parse_integer(args[1]), &rc, &uc, &cc); + #endif safe_str(unparse_integer(rc), buff, bp); safe_chr(' ', buff, bp); safe_str(unparse_integer(uc), buff, bp); *************** *** 1408,1418 **** struct mail *mp; dbref player; ! int rc, uc, cc; if (nargs == 0) { count_mail(executor, -1, &rc, &uc, &cc); safe_str(unparse_integer(rc + uc + cc), buff, bp); return; } /* Try mail() */ --- 1960,1975 ---- struct mail *mp; dbref player; ! int rc, uc, cc, dc, sc; if (nargs == 0) { + #ifdef MAIL_DRAFTS + count_mail(executor, -1, &rc, &uc, &cc, &dc, &sc); + safe_str(unparse_integer(rc + uc + cc + dc + sc), buff, bp); + #else count_mail(executor, -1, &rc, &uc, &cc); safe_str(unparse_integer(rc + uc + cc), buff, bp); + #endif return; } /* Try mail() */ *************** *** 1422,1428 **** --- 1979,1993 ---- if ((executor != player) && !Wizard(executor)) { safe_str("#-1 PERMISSION DENIED", buff, bp); } else { + #ifdef MAIL_DRAFTS + count_mail(player, -1, &rc, &uc, &cc, &dc, &sc); + safe_str(unparse_integer(dc), buff, bp); + safe_chr(' ', buff, bp); + safe_str(unparse_integer(sc), buff, bp); + safe_chr(' ', buff, bp); + #else count_mail(player, -1, &rc, &uc, &cc); + #endif safe_str(unparse_integer(rc), buff, bp); safe_chr(' ', buff, bp); safe_str(unparse_integer(uc), buff, bp); *************** *** 1432,1438 **** return; } } ! /* That didn't work. Ok, try mailfun_fetch */ mp = mailfun_fetch(executor, nargs, args[0], args[1]); if (mp) { safe_str(uncompress(mp->message), buff, bp); --- 1997,2003 ---- return; } } ! /* That didn't work. Ok, try mailfun_fetch */ mp = mailfun_fetch(executor, nargs, args[0], args[1]); if (mp) { safe_str(uncompress(mp->message), buff, bp); *************** *** 1469,1474 **** --- 2034,2040 ---- /* Both a target and a message */ if ((target = noisy_match_result(player, arg1, TYPE_PLAYER, MAT_OBJECTS)) == NOTHING) { return NULL; + } else if ((player != target) && !Wizard(player)) { notify(player, "Permission denied"); return NULL; *************** *** 1488,1493 **** --- 2054,2060 ---- /* ARGSUSED */ FUNCTION(fun_mailfrom) { + struct mail *mp; mp = mailfun_fetch(executor, nargs, args[0], args[1]); *************** *** 1498,1505 **** --- 2065,2109 ---- return; } + #ifdef MAIL_CC + /* ARGSUSED */ + FUNCTION(fun_mailto) + { + struct mail *mp; + struct dblist *list; + mp = mailfun_fetch(executor, nargs, args[0], args[1]); + if (!mp) + + safe_str("#-1", buff, bp); + else { + list = mp->cc; + while (list) { + safe_str(unparse_dbref(list->obj), buff, bp); + safe_chr(' ', buff, bp); + list = list->next; + } + } + return; + } + #endif + + #ifdef MAIL_AUTHOR /* ARGSUSED */ + FUNCTION(fun_mailauthor) + { + struct mail *mp; + + mp = mailfun_fetch(executor, nargs, args[0], args[1]); + if (!mp) + safe_str("#-1", buff, bp); + else + safe_str(unparse_dbref(mp->author), buff, bp); + return; + } + #endif + + /* ARGSUSED */ FUNCTION(fun_mailtime) { struct mail *mp; *************** *** 1548,1557 **** --- 2152,2168 ---- struct mail *mp; int count = 0; int mail_flags = 0; + struct dblist *list; #ifdef MAIL_SUBJECTS mail_flags += MDBF_SUBJECT; #endif + #ifdef MAIL_CC + mail_flags += MDBF_CC; + #endif + #ifdef MAIL_AUTHOR + mail_flags += MDBF_AUTHOR; + #endif if (mail_flags) fprintf(fp, "+%d\n", mail_flags); *************** *** 1561,1566 **** --- 2172,2188 ---- for (mp = HEAD; mp != NULL; mp = mp->next) { putref(fp, mp->to); putref(fp, mp->from); + #ifdef MAIL_AUTHOR + putref(fp, mp->author); + #endif + #ifdef MAIL_CC + list = mp->cc; + while (list) { + putref(fp, list->obj); + list = list->next; + } + putref(fp, NOTHING); + #endif putstring(fp, uncompress(mp->time)); #ifdef MAIL_SUBJECTS if (mp->subject) *************** *** 1674,1679 **** --- 2296,2303 ---- #ifdef MAIL_SUBJECTS char sbuf[BUFFER_LEN]; #endif + struct dblist *list; + dbref author, member; mail_init(); *************** *** 1693,1698 **** --- 2317,2340 ---- mp = (struct mail *) mush_malloc(sizeof(struct mail), "mail"); mp->to = getref(fp); mp->from = getref(fp); + if (mail_flags & MDBF_AUTHOR) + author = getref(fp); + else + author = NOTHING; + #ifdef MAIL_AUTHOR + mp->author = author; + #endif + if (mail_flags & MDBF_CC) { + list = listcreate(getref(fp)); + while ((member = getref(fp) != NOTHING)) + listadd(list, member); + } else + list = listcreate(NOTHING); + #ifdef MAIL_CC + mp->cc = list; + #endif + if (list) + listfree(list); mp->time = u_strdup(compress((char *) getstring_noalloc(fp))); if (mail_flags & MDBF_SUBJECT) { tbuf = u_strdup(compress((char *) getstring_noalloc(fp))); *************** *** 1718,1723 **** --- 2360,2383 ---- mp = (struct mail *) mush_malloc(sizeof(struct mail), "mail"); mp->to = getref(fp); mp->from = getref(fp); + if (mail_flags & MDBF_AUTHOR) + author = getref(fp); + else + author = NOTHING; + #ifdef MAIL_AUTHOR + mp->author = author; + #endif + if (mail_flags & MDBF_CC) { + list = listcreate(getref(fp)); + while ((member = getref(fp) != NOTHING)) + listadd(list, member); + } else + list = listcreate(NOTHING); + #ifdef MAIL_CC + mp->cc = list; + #endif + if (list) + listfree(list); mp->time = u_strdup(compress((char *) getstring_noalloc(fp))); if (mail_flags & MDBF_SUBJECT) tbuf = u_strdup(compress((char *) getstring_noalloc(fp))); *************** *** 2109,2114 **** --- 2769,2780 ---- ms->flags = M_MSUNREAD; } else if (!strcasecmp(p, "read")) { ms->flags = M_READ; + #ifdef MAIL_DRAFTS + } else if (!strcasecmp(p, "draft") || !strcasecmp(p, "drafts")) { + ms->flags = M_DRAFT; + } else if (!strcasecmp(p, "sent")) { + ms->flags = M_SENT; + #endif } else if (!strcasecmp(p, "clear") || !strcasecmp(p, "cleared")) { ms->flags = M_CLEARED; } else if (!strcasecmp(p, "tag") || !strcasecmp(p, "tagged")) { *************** *** 2134,2144 **** --- 2800,2814 ---- strcpy(res, ""); p = res; + #ifdef MAIL_DRAFTS + *p++ = Sent(mp) ? 'S' : (Draft(mp) ? 'D' : '-'); + #endif *p++ = Read(mp) ? '-' : 'N'; *p++ = Cleared(mp) ? 'C' : '-'; *p++ = Urgent(mp) ? 'U' : '-'; /* *p++ = Mass(mp) ? 'M' : '-'; */ *p++ = Forward(mp) ? 'F' : '-'; + *p++ = Reply(mp) ? 'R' : '-'; *p++ = Tagged(mp) ? '+' : '-'; *p = '\0'; return res; *************** *** 2152,2157 **** --- 2822,2833 ---- static char tbuf1[BUFFER_LEN]; strcpy(tbuf1, ""); + #ifdef MAIL_DRAFTS + if (Draft(mp)) + strcat(tbuf1, "Draft "); + if (Sent(mp)) + strcat(tbuf1, "Sent "); + #endif if (Read(mp)) strcat(tbuf1, "Read "); else *************** *** 2180,2187 **** --- 2856,2875 ---- int rc; /* read messages */ int uc; /* unread messages */ int cc; /* cleared messages */ + #ifdef MAIL_DRAFTS + int dc; /* unsent draft messages */ + int sc; /* sent draft messages */ /* just count messages */ + count_mail(player, folder, &rc, &uc, &cc, &dc, &sc); + if (rc + uc + cc + dc + sc > 0) + notify(player, + tprintf("MAIL: %d messages in folder %d [%s] (%d drafts, %d sent, %d unread, %d cleared).", dc + sc + rc + uc + cc, folder, get_folder_name(player, folder), dc, sc, uc, cc)); + else if (!silent) + notify(player, tprintf("\nMAIL: You have no mail.\n")); + return; + #else + /* just count messages */ count_mail(player, folder, &rc, &uc, &cc); if (rc + uc + cc > 0) notify(player, *************** *** 2190,2195 **** --- 2878,2884 ---- else if (!silent) notify(player, tprintf("\nMAIL: You have no mail.\n")); return; + #endif } static int *** src/function.c.orig Tue Jul 15 13:39:06 1997 --- src/function.c Wed Jul 16 16:06:32 1997 *************** *** 235,241 **** --- 235,247 ---- {"MAILSUBJECT", fun_mailsubject, 1, 2, FN_REG}, #endif {"MAILTIME", fun_mailtime, 1, 2, FN_REG}, + #ifdef MAIL_CC + {"MAILTO", fun_mailto, 1, 2, FN_REG}, #endif + #ifdef MAIL_AUTHOR + {"MAILAUTHOR", fun_mailauthor, 1, 2, FN_REG}, + #endif + #endif {"MAP", fun_map, 2, 3, FN_REG}, {"MATCH", fun_match, 2, 3, FN_REG}, {"MATCHALL", fun_matchall, 2, 3, FN_REG}, *** src/game.c.orig Tue Jul 15 13:41:04 1997 --- src/game.c Wed Jul 16 16:06:58 1997 *************** *** 2026,2031 **** --- 2026,2041 ---- do_mail_send(player, arg1, arg2, 0, 1); else if (Switch("urgent")) do_mail_send(player, arg1, arg2, M_URGENT, 0); + #ifdef MAIL_DRAFTS + else if (Switch("draft")) + do_mail_send(player, arg1, arg2, M_DRAFT, 2); + else if (Switch("edit")) + do_mail_edit(player, arg1, vargs); + #ifdef MAIL_SUBJECTS + else if (Switch("subject")) + do_mail_subject(player, arg1, arg2); + #endif + #endif else goto bad; break; *************** *** 3780,3785 **** --- 3790,3801 ---- #else notify(player, "@mail messages do not have subject lines."); #endif + #ifdef MAIL_DRAFTS + notify(player, "The draft @mail messages can be edited."); + #endif + #ifdef MAIL_CC + notify(player, "The @mail messages have the full addressee field."); + #endif #else notify(player, "The built-in MUSH mailing system is not being used."); #endif *** src/player.c.orig Tue Jul 15 13:41:10 1997 --- src/player.c Wed Jul 16 00:56:45 1997 *************** *** 301,308 **** #endif #ifdef USE_MAILER (void) atr_add(player, "MAILCURF", "0", GOD, AF_LOCKED | AF_NOPROG | AF_WIZARD | AF_ODARK); ! add_folder_name(player, 0, "inbox"); #endif /* link him to PLAYER_START */ PUSH(player, db[PLAYER_START].contents); --- 301,312 ---- #endif #ifdef USE_MAILER (void) atr_add(player, "MAILCURF", "0", GOD, AF_LOCKED | AF_NOPROG | AF_WIZARD | AF_ODARK); ! add_folder_name(player, 0, "INBOX"); ! #ifdef MAIL_DRAFTS ! add_folder_name(player, 1, "DRAFTS"); ! add_folder_name(player, 2, "COPIES"); #endif + #endif /* link him to PLAYER_START */ PUSH(player, db[PLAYER_START].contents); *** game/txt/hlp/pennmail.hlp.orig Wed Jul 16 21:17:51 1997 --- game/txt/hlp/pennmail.hlp Wed Jul 16 16:15:32 1997 *************** *** 7,110 **** any messages you may try to send. A is one of the following: ! A single msg # (ex: 3) ! A message range (ex: 2-5, -7, 3-) A folder number and message number/range (ex: 0:3, 1:2-5, 2:-7) ! A sender (ex: *paul) ! An age of mail in days (ex: ~3 (exactly 3), <2, >1) ! "days" here means 24-hour periods from the current time. ! One of the following: "read", "unread", "cleared", "tagged", "urgent", "all" (all messages in all folders), "folder" (all messages in current folder) A is a space-separated list of recipients, which may be: ! Player names ! Player dbref #'s ! Message #'s, in which case you send to the sender of that message. ! See the following topics: ! mail-sending mail-reading mail-folders mail-other mail-admin & mail-reading @mail @mail/read ! This displays messages which match the msg# or msg-list from ! your current folder. @mail @mail @mail/list ! This gives a brief list of all mail in the current folder, ! with sender name, time sent, and message status. ! The status field is a set of characters (ex: NC-UF+) which mean: ! N = New (unread) message ! C = Cleared message ! U = Urgent message ! F = Forwarded message ! + = Tagged message ! The opposites of these (read messages, etc.) are indicated with a ! '-' in the status field in that position. ! & mail-sending ! @mail[/switch] = []/ This sends the message to all players in . ! If no subject is given, the message subject is the beginning ! of the message itself. ! All function subsitutes are valid in including mail(#) which ! will allow you to forward mail you have recieved to other users. ! The following switches are available: ! /send - same as no switch ! /urgent - mail is marked as "Urgent" ! /silent - no notification to sender that mail was sent ! Useful with large mailing lists ! ! @mail/fwd = ! This sends a copy of all the messages in to ! all the players in . The copy will appear to have ! been sent by you (not the original sender), and its status will ! be "Forwarded". & mail-other @mail/clear [] @mail/unclear [ | all>] ! These commands mark mail in the current folder as cleared or uncleared. ! Mail marked for clearing is deleted when you disconnect, or ! if you use @mail/purge. If no msg-list is specified, all ! mail in your current folder is cleared. If "all" is given instead ! of a msg-list, all mail in *all* folders is cleared/uncleared. @mail/purge ! Actually deletes all messages marked for clearing with @mail/clear. ! This is done automatically when you log out. @mail/tag [] @mail/untag [ | all>] ! These commands tag or untag mail in the current folder. ! Tagged mail can be later acted on en masse by using "tagged" as ! the msg-list for other commands (which does *not* untag them ! afterward). If no msg-list is specified, all messages in the ! current folder are tagged/untagged. If "all" is given as the ! msg-list, all mail in *all* folders is tagged/untagged. ! (Ex: To clear all mail from Paul and Chani, @mail/tag *paul, ! @mail/tag *chani, @mail/clear tagged, @mail/untag all). & mail-folders The MUSH mail system allows each player 16 folders, numbered from 0 to 15. Mail can only be in 1 folder at a time. Folder 0 is ! the "inbox" where new mail is received. Most @mail commands ! operate on only the current folder. @mail/folder ! This commands lists all folders which contain mail, telling ! how many messages are in each, and what the current folder is. @mail/folder ! This command sets your current folder to . @mail/folder = ! This command gives a name. @mail/file = ! This command moves all messages in msg-list from the current ! folder to a new folder, . & mail-admin The @mail command can also take the following switches: --- 7,141 ---- any messages you may try to send. A is one of the following: ! A single msg # (ex: 3) ! A message range (ex: 2-5, -7, 3-) A folder number and message number/range (ex: 0:3, 1:2-5, 2:-7) ! A sender (ex: *paul) ! An age of mail in days (ex: ~3 (exactly 3), <2, >1) ! "days" here means 24-hour periods from the current time. ! One of the following: "read", "unread", "cleared", "tagged", "urgent", "all" (all messages in all folders), "folder" (all messages in current folder) A is a space-separated list of recipients, which may be: ! Player names ! Player dbref #'s ! Message #'s, in which case you send to the sender of that message. ! See the following topics: MAIL-SENDING MAIL-EDITING MAIL-READING ! MAIL-FOLDERS MAIL-OTHER MAIL-ADMIN & mail-reading @mail @mail/read ! This displays messages which match the msg# or msg-list from ! your current folder. @mail @mail @mail/list ! This gives a brief list of all mail in the current folder, ! with sender name, time sent, and message status. ! The status field is a set of 7 characters (ex: DNCUFR+) which mean: ! D = Draft (unsent) message ! S = Sent (draft) message ! N = New (unread) message ! C = Cleared message ! U = Urgent message ! F = Forwarded message ! R = Reply message ! + = Tagged message ! The opposites of these (read messages, etc.) are indicated with a ! '-' in the status field in that position. The order of the ! characters' positions in the string is as follows: D/S N C U F R + ! & mail-sending ! @mail[/switch] [] = []/ This sends the message to all players in . ! If the message numbers are used instead of the players, the ! message will be sent in reply to those. ! If no subject is given, the message subject is the beginning ! of the message itself. ! All function subsitutes are valid in including mail(#) which ! will allow you to forward mail you have recieved to other users. ! The following switches are available: ! /send - same as no switch ! /draft - creates a draft message (one which can be edited) ! /urgent - mail is marked as "Urgent" ! /silent - no notification to sender that mail was sent ! Useful with large mailing lists ! @mail/fwd = [] ! This sends a copy of all the messages in to ! all the players in . The copy will appear to have ! been sent by you (not the original sender), and its status will ! be "Forwarded". If the message numbers are given in the right ! hand side, the forwarded messages are formatted as replies. ! If a draft message is forwarded, it is NOT marked as "Forwarded". ! Once sent, it ceases to be a draft, is marked as "Sent", and ! its copy stays with the sender. If the addressee field is ! defined, the may be omitted. ! & mail-editing ! @mail/draft = [/] ! This creates a message in your 1st (DRAFT) folder, marked as ! "Draft". The draft messages can be edited before forwarding. ! @mail/edit = , ! This replaces the string with the string in the body ! of the indicated messages. Only draft messages can be edited. ! The message is no longer marked as "Sent" after editing. ! @mail/subject = ! This replaces the subject of the indicated messages. Only draft ! messages can be edited. The message is no longer marked as "Sent" ! after editing. ! @mail/fwd [ = ] ! If you forward a draft message, it is sent to the original adresses ! if you don't specify the , or to the players in the list ! if you want to change the addressees this way. In both cases, the ! message remains in your folder, but is now marked as "Sent", and its ! list of addresses changes to the if that was specified. & mail-other @mail/clear [] @mail/unclear [ | all>] ! These commands mark mail in the current folder as cleared or uncleared. ! Mail marked for clearing is deleted when you disconnect, or ! if you use @mail/purge. If no msg-list is specified, all ! mail in your current folder is cleared. If "all" is given instead ! of a msg-list, all mail in *all* folders is cleared/uncleared. @mail/purge ! Actually deletes all messages marked for clearing with @mail/clear. ! This is done automatically when you log out. @mail/tag [] @mail/untag [ | all>] ! These commands tag or untag mail in the current folder. ! Tagged mail can be later acted on en masse by using "tagged" as ! the msg-list for other commands (which does *not* untag them ! afterward). If no msg-list is specified, all messages in the ! current folder are tagged/untagged. If "all" is given as the ! msg-list, all mail in *all* folders is tagged/untagged. ! (Ex: To clear all mail from Paul and Chani, @mail/tag *paul, ! @mail/tag *chani, @mail/clear tagged, @mail/untag all). & mail-folders The MUSH mail system allows each player 16 folders, numbered from 0 to 15. Mail can only be in 1 folder at a time. Folder 0 is ! the "INBOX" where new mail is received. Folder 1 is the "DRAFTS" ! folder where the draft messages are edited. Folder 2 is the "COPIES" ! folder where the copies of the sent draft messages are stored. ! Most @mail commands operate on only the current folder. @mail/folder ! This commands lists all folders which contain mail, telling ! how many messages are in each, and what the current folder is. @mail/folder ! This command sets your current folder to . @mail/folder = ! This command gives a name. @mail/file = ! This command moves all messages in msg-list from the current ! folder to a new folder, . & mail-admin The @mail command can also take the following switches: *** game/txt/hlp/pennfunc.hlp.orig Fri Jul 18 16:29:32 1997 --- game/txt/hlp/pennfunc.hlp Fri Jul 18 17:03:09 1997 *************** *** 86,95 **** cwho() doing() elock() findable() flags() folderstats() fullname() hasattr() hasattrp() hasflag() haspower() hastype() hidden() idle() lock() ! lstats() lwho() mail() mailfrom() mailstatus() ! mailtime() money() mtime() mwho() name() ! nearby() objmem() orflags() playermem() poll() ! ports() powers() quota() type() visible() & Floating point functions Floating point functions operate on floating point numbers. Most of --- 86,96 ---- cwho() doing() elock() findable() flags() folderstats() fullname() hasattr() hasattrp() hasflag() haspower() hastype() hidden() idle() lock() ! lstats() lwho() mail() mailauthor() mailfrom() ! mailstatus() mailtime() mailto() money() mtime() ! mwho() name() nearby() objmem() orflags() ! playermem() poll() ports() powers() quota() ! type() visible() & Floating point functions Floating point functions operate on floating point numbers. Most of *************** *** 1640,1653 **** & MAILFROM() & MAILTIME() & MAILSTATUS() mailfrom([,] [:]) mailtime([,] [:]) mailstatus([,] [:]) mailfrom() returns the dbref number of the sender of a mail message. mailtime() is similar, but returns the time the mail was sent. ! mailstatus() returns the mail's status characters (as per ! @mail/list) & FOLDERSTATS() folderstats() --- 1641,1662 ---- & MAILFROM() & MAILTIME() & MAILSTATUS() + & MAILTO() + & MAILAUTHOR() mailfrom([,] [:]) mailtime([,] [:]) mailstatus([,] [:]) + mailto([,] [:]) + mailauthor([,] [:]) mailfrom() returns the dbref number of the sender of a mail message. mailtime() is similar, but returns the time the mail was sent. ! mailstatus() returns the mail's status characters (as per @mail/list). ! mailto() returns the list of everyone to whom the message was sent ! (although, if you get a reply message, the list is only of those ! who got it as a reply; and if you got a non-reply messages, the list ! is only of those who got it as a non-reply). ! mailauthor() returns the original author of the message. & FOLDERSTATS() folderstats()