00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "copyright.h"
00011 #include "autoconf.h"
00012 #include "config.h"
00013 #include "externs.h"
00014
00015 #include <sys/types.h>
00016
00017 #include "attrs.h"
00018 #include "command.h"
00019 #include "powers.h"
00020 #include "mail.h"
00021
00022 #define SIZEOF_MALIAS 13
00023 #define WIDTHOF_MALIASDESC 40
00024 #define SIZEOF_MALIASDESC (WIDTHOF_MALIASDESC*2)
00025
00026 #define MAX_MALIAS_MEMBERSHIP 100
00027 struct malias
00028 {
00029 int owner;
00030 char *name;
00031 char *desc;
00032 int desc_width;
00033 int numrecep;
00034 dbref list[MAX_MALIAS_MEMBERSHIP];
00035 };
00036
00037 static int ma_size = 0;
00038 static int ma_top = 0;
00039
00040 static struct malias **malias = NULL;
00041 static MAILBODY *mail_list = NULL;
00042
00043
00044
00045
00046
00047
00048
00049
00050 #define MAIL_FUDGE 1
00051 static void mail_db_grow(int newtop)
00052 {
00053 if (newtop <= mudstate.mail_db_top)
00054 {
00055 return;
00056 }
00057 if (mudstate.mail_db_size <= newtop)
00058 {
00059
00060
00061 int newsize = mudstate.mail_db_size + 100;
00062 if (newtop > newsize)
00063 {
00064 newsize = newtop;
00065 }
00066
00067 MAILBODY *newdb = (MAILBODY *)MEMALLOC((newsize + MAIL_FUDGE) * sizeof(MAILBODY));
00068 ISOUTOFMEMORY(newdb);
00069 if (mail_list)
00070 {
00071 mail_list -= MAIL_FUDGE;
00072 memcpy( newdb,
00073 mail_list,
00074 (mudstate.mail_db_top + MAIL_FUDGE) * sizeof(MAILBODY));
00075 MEMFREE(mail_list);
00076 mail_list = NULL;
00077 }
00078 mail_list = newdb + MAIL_FUDGE;
00079 newdb = NULL;
00080 mudstate.mail_db_size = newsize;
00081 }
00082
00083
00084
00085 for (int i = mudstate.mail_db_top; i < newtop; i++)
00086 {
00087 mail_list[i].m_nRefs = 0;
00088 mail_list[i].m_pMessage = NULL;
00089 }
00090 mudstate.mail_db_top = newtop;
00091 }
00092
00093
00094
00095
00096 static DCL_INLINE void MessageReferenceInc(int number)
00097 {
00098 mail_list[number].m_nRefs++;
00099 }
00100
00101
00102
00103
00104
00105
00106 static void MessageReferenceCheck(int number)
00107 {
00108 MAILBODY &m = mail_list[number];
00109 if (m.m_nRefs <= 0)
00110 {
00111 if (m.m_pMessage)
00112 {
00113 MEMFREE(m.m_pMessage);
00114 m.m_pMessage = NULL;
00115 }
00116 }
00117 if (m.m_pMessage == NULL)
00118 {
00119 m.m_nRefs = 0;
00120 }
00121 }
00122
00123
00124
00125
00126 static void MessageReferenceDec(int number)
00127 {
00128 mail_list[number].m_nRefs--;
00129 MessageReferenceCheck(number);
00130 }
00131
00132
00133
00134
00135 static const char *MessageFetch(int number)
00136 {
00137 MessageReferenceCheck(number);
00138 if (mail_list[number].m_pMessage)
00139 {
00140 return mail_list[number].m_pMessage;
00141 }
00142 else
00143 {
00144 return "MAIL: This mail message does not exist in the database. Please alert your admin.";
00145 }
00146 }
00147
00148
00149
00150
00151 static int MessageAdd(char *pMessage)
00152 {
00153 if (!mail_list)
00154 {
00155 mail_db_grow(1);
00156 }
00157
00158 int i;
00159 MAILBODY *pm;
00160 bool bFound = false;
00161 for (i = 0; i < mudstate.mail_db_top; i++)
00162 {
00163 pm = &mail_list[i];
00164 if (pm->m_pMessage == NULL)
00165 {
00166 pm->m_nRefs = 0;
00167 bFound = true;
00168 break;
00169 }
00170 }
00171 if (!bFound)
00172 {
00173 mail_db_grow(i + 1);
00174 }
00175
00176 pm = &mail_list[i];
00177 pm->m_pMessage = StringClone(pMessage);
00178 MessageReferenceInc(i);
00179 return i;
00180 }
00181
00182
00183
00184
00185
00186
00187
00188 static int add_mail_message(dbref player, char *message)
00189 {
00190 if (!mux_stricmp(message, "clear"))
00191 {
00192 notify(player, "MAIL: You probably did not intend to send a @mail saying 'clear'.");
00193 return NOTHING;
00194 }
00195
00196
00197
00198 int aflags;
00199 dbref aowner;
00200 char *bp = alloc_lbuf("add_mail_message");
00201 char *atrstr = atr_get(player, A_SIGNATURE, &aowner, &aflags);
00202 char *execstr = bp;
00203 char *str = atrstr;
00204 mux_exec(execstr, &bp, player, player, player,
00205 EV_STRIP_CURLY | EV_FCHECK | EV_EVAL, &str, (char **)NULL, 0);
00206 *bp = '\0';
00207
00208
00209
00210 int number = MessageAdd(tprintf("%s %s", message, execstr));
00211 free_lbuf(atrstr);
00212 free_lbuf(execstr);
00213 return number;
00214 }
00215
00216
00217
00218
00219 static bool MessageAddWithNumber(int i, char *pMessage)
00220 {
00221 mail_db_grow(i+1);
00222
00223 MAILBODY *pm = &mail_list[i];
00224 pm->m_pMessage = StringClone(pMessage);
00225 return true;
00226 }
00227
00228
00229
00230
00231
00232
00233
00234 static void new_mail_message(char *message, int number)
00235 {
00236 bool bTruncated = false;
00237 if (strlen(message) > LBUF_SIZE-1)
00238 {
00239 bTruncated = true;
00240 message[LBUF_SIZE-1] = '\0';
00241 }
00242 MessageAddWithNumber(number, message);
00243 if (bTruncated)
00244 {
00245 STARTLOG(LOG_BUGS, "BUG", "MAIL");
00246 log_text(tprintf("new_mail_message: Mail message %d truncated.", number));
00247 ENDLOG;
00248 }
00249 }
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266 static void set_player_folder(dbref player, int fnum)
00267 {
00268
00269
00270 char *tbuf1 = alloc_lbuf("set_player_folder");
00271 mux_ltoa(fnum, tbuf1);
00272 ATTR *a = atr_num(A_MAILCURF);
00273 if (a)
00274 {
00275 atr_add(player, A_MAILCURF, tbuf1, GOD, a->flags);
00276 }
00277 else
00278 {
00279
00280
00281 atr_add(player, A_MAILCURF, tbuf1, GOD, AF_ODARK | AF_WIZARD | AF_NOPROG | AF_LOCK);
00282 }
00283 free_lbuf(tbuf1);
00284 }
00285
00286 static void add_folder_name(dbref player, int fld, char *name)
00287 {
00288
00289
00290 int aflags;
00291 size_t nFolders;
00292 dbref aowner;
00293 char *aFolders = alloc_lbuf("add_folder_name.str");
00294 atr_get_str_LEN(aFolders, player, A_MAILFOLDERS, &aowner, &aflags,
00295 &nFolders);
00296
00297
00298
00299 char *aNew = alloc_lbuf("add_folder_name.new");
00300 char *q = aNew;
00301 q += mux_ltoa(fld, q);
00302 *q++ = ':';
00303 char *p = name;
00304 while (*p)
00305 {
00306 *q++ = mux_toupper(*p);
00307 p++;
00308 }
00309 *q++ = ':';
00310 q += mux_ltoa(fld, q);
00311 *q = '\0';
00312 size_t nNew = q - aNew;
00313
00314 if (nFolders != 0)
00315 {
00316
00317
00318 char *aPattern = alloc_lbuf("add_folder_name.pat");
00319 q = aPattern;
00320 q += mux_ltoa(fld, q);
00321 *q++ = ':';
00322 *q = '\0';
00323 size_t nPattern = q - aPattern;
00324
00325 BMH_State bmhs;
00326 BMH_Prepare(&bmhs, nPattern, aPattern);
00327 for (;;)
00328 {
00329 int i = BMH_Execute(&bmhs, nPattern, aPattern, nFolders, aFolders);
00330 if (i < 0)
00331 {
00332 break;
00333 }
00334
00335
00336
00337 q = aFolders + i;
00338 p = q + nPattern;
00339
00340
00341
00342 while ( aFolders < q
00343 && mux_isspace(q[-1]))
00344 {
00345 q--;
00346 }
00347
00348
00349
00350 while ( *p
00351 && *p != ':')
00352 {
00353 p++;
00354 }
00355 while ( *p
00356 && !mux_isspace(*p))
00357 {
00358 p++;
00359 }
00360 while (mux_isspace(*p))
00361 {
00362 p++;
00363 }
00364
00365 if (q != aFolders)
00366 {
00367 *q++ = ' ';
00368 }
00369 while (*p)
00370 {
00371 *q++ = *p++;
00372 }
00373 *q = '\0';
00374 nFolders = q - aFolders;
00375 }
00376 free_lbuf(aPattern);
00377 }
00378 if (nFolders + 1 + nNew < LBUF_SIZE)
00379 {
00380
00381
00382 q = aFolders + nFolders;
00383 if (nFolders)
00384 {
00385 *q++ = ' ';
00386 }
00387 memcpy(q, aNew, nNew);
00388 q += nNew;
00389 *q = '\0';
00390
00391 atr_add(player, A_MAILFOLDERS, aFolders, player,
00392 AF_MDARK | AF_WIZARD | AF_NOPROG | AF_LOCK);
00393 }
00394 free_lbuf(aFolders);
00395 free_lbuf(aNew);
00396 }
00397
00398 static char *get_folder_name(dbref player, int fld)
00399 {
00400
00401
00402 int aflags;
00403 size_t nFolders;
00404 dbref aowner;
00405 static char aFolders[LBUF_SIZE];
00406 atr_get_str_LEN(aFolders, player, A_MAILFOLDERS, &aowner, &aflags,
00407 &nFolders);
00408 char *p;
00409 if (nFolders != 0)
00410 {
00411 char *aPattern = alloc_lbuf("get_folder_name");
00412 p = aPattern;
00413 p += mux_ltoa(fld, p);
00414 *p++ = ':';
00415 *p = '\0';
00416 size_t nPattern = p - aPattern;
00417
00418 int i = BMH_StringSearch(nPattern, aPattern, nFolders, aFolders);
00419 free_lbuf(aPattern);
00420
00421 if (0 <= i)
00422 {
00423 p = aFolders + i + nPattern;
00424 char *q = p;
00425 while ( *q
00426 && *q != ':')
00427 {
00428 q++;
00429 }
00430 *q = '\0';
00431 return p;
00432 }
00433 }
00434 p = "unnamed";
00435 return p;
00436 }
00437
00438 static int get_folder_number(dbref player, char *name)
00439 {
00440
00441
00442 int aflags;
00443 size_t nFolders;
00444 dbref aowner;
00445 char *aFolders = alloc_lbuf("get_folder_num_str");
00446 atr_get_str_LEN(aFolders, player, A_MAILFOLDERS, &aowner, &aflags,
00447 &nFolders);
00448 if (nFolders != 0)
00449 {
00450 char *aPattern = alloc_lbuf("get_folder_num_pat");
00451 char *q = aPattern;
00452 *q++ = ':';
00453 char *p = name;
00454 while (*p)
00455 {
00456 *q++ = mux_toupper(*p);
00457 p++;
00458 }
00459 *q++ = ':';
00460 *q = '\0';
00461 size_t nPattern = q - aPattern;
00462
00463 int i = BMH_StringSearch(nPattern, aPattern, nFolders, aFolders);
00464 free_lbuf(aPattern);
00465 if (0 <= i)
00466 {
00467 p = aFolders + i + nPattern;
00468 q = p;
00469 while ( *q
00470 && !mux_isspace(*q))
00471 {
00472 q++;
00473 }
00474 *q = '\0';
00475 i = mux_atol(p);
00476 free_lbuf(aFolders);
00477 return i;
00478 }
00479 }
00480 free_lbuf(aFolders);
00481 return -1;
00482 }
00483
00484 static int parse_folder(dbref player, char *folder_string)
00485 {
00486
00487
00488 if ( !folder_string
00489 || !*folder_string)
00490 {
00491 return -1;
00492 }
00493 if (mux_isdigit(*folder_string))
00494 {
00495 int fnum = mux_atol(folder_string);
00496 if ( fnum < 0
00497 || fnum > MAX_FOLDERS)
00498 {
00499 return -1;
00500 }
00501 else
00502 {
00503 return fnum;
00504 }
00505 }
00506
00507
00508
00509 return get_folder_number(player, folder_string);
00510 }
00511
00512 #define MAIL_INVALID_RANGE 0
00513 #define MAIL_INVALID_NUMBER 1
00514 #define MAIL_INVALID_AGE 2
00515 #define MAIL_INVALID_DBREF 3
00516 #define MAIL_INVALID_PLAYER 4
00517 #define MAIL_INVALID_SPEC 5
00518 #define MAIL_INVALID_PLAYER_OR_USING_MALIAS 6
00519
00520 static char *mailmsg[] =
00521 {
00522 "MAIL: Invalid message range",
00523 "MAIL: Invalid message number",
00524 "MAIL: Invalid age",
00525 "MAIL: Invalid dbref #",
00526 "MAIL: Invalid player",
00527 "MAIL: Invalid message specification",
00528 "MAIL: Invalid player or trying to send @mail to a @malias without a subject",
00529 };
00530
00531 static bool parse_msglist(char *msglist, struct mail_selector *ms, dbref player)
00532 {
00533
00534
00535
00536
00537
00538
00539
00540 ms->low = 0;
00541 ms->high = 0;
00542 ms->flags = 0x0FFF | M_MSUNREAD;
00543 ms->player = 0;
00544 ms->days = -1;
00545 ms->day_comp = 0;
00546
00547
00548
00549 if (!msglist || !*msglist)
00550 {
00551
00552
00553 return true;
00554 }
00555
00556 char *p = msglist;
00557 while (mux_isspace(*p))
00558 {
00559 p++;
00560 }
00561
00562 if (*p == '\0')
00563 {
00564 return true;
00565 }
00566
00567 if (mux_isdigit(*p))
00568 {
00569
00570
00571 char *q = strchr(p, '-');
00572 if (q)
00573 {
00574
00575
00576 q++;
00577 ms->low = mux_atol(p);
00578 if (ms->low <= 0)
00579 {
00580 notify(player, mailmsg[MAIL_INVALID_RANGE]);
00581 return false;
00582 }
00583 if (*q == '\0')
00584 {
00585
00586
00587 ms->high = 0;
00588 }
00589 else
00590 {
00591 ms->high = mux_atol(q);
00592 if (ms->low > ms->high)
00593 {
00594 notify(player, mailmsg[MAIL_INVALID_RANGE]);
00595 return false;
00596 }
00597 }
00598 }
00599 else
00600 {
00601
00602
00603 ms->low = ms->high = mux_atol(p);
00604 if (ms->low <= 0)
00605 {
00606 notify(player, mailmsg[MAIL_INVALID_NUMBER]);
00607 return false;
00608 }
00609 }
00610 }
00611 else
00612 {
00613 switch (mux_toupper(*p))
00614 {
00615 case '-':
00616
00617
00618
00619 p++;
00620 if (*p == '\0')
00621 {
00622 notify(player, mailmsg[MAIL_INVALID_RANGE]);
00623 return false;
00624 }
00625 ms->high = mux_atol(p);
00626 if (ms->high <= 0)
00627 {
00628 notify(player, mailmsg[MAIL_INVALID_RANGE]);
00629 return false;
00630 }
00631 break;
00632
00633 case '~':
00634
00635
00636
00637 p++;
00638 if (*p == '\0')
00639 {
00640 notify(player, mailmsg[MAIL_INVALID_AGE]);
00641 return false;
00642 }
00643 ms->day_comp = 0;
00644 ms->days = mux_atol(p);
00645 if (ms->days < 0)
00646 {
00647 notify(player, mailmsg[MAIL_INVALID_AGE]);
00648 return false;
00649 }
00650 break;
00651
00652 case '<':
00653
00654
00655
00656 p++;
00657 if (*p == '\0')
00658 {
00659 notify(player, mailmsg[MAIL_INVALID_AGE]);
00660 return false;
00661 }
00662 ms->day_comp = -1;
00663 ms->days = mux_atol(p);
00664 if (ms->days < 0)
00665 {
00666 notify(player, mailmsg[MAIL_INVALID_AGE]);
00667 return false;
00668 }
00669 break;
00670
00671 case '>':
00672
00673
00674
00675 p++;
00676 if (*p == '\0')
00677 {
00678 notify(player, mailmsg[MAIL_INVALID_AGE]);
00679 return false;
00680 }
00681 ms->day_comp = 1;
00682 ms->days = mux_atol(p);
00683 if (ms->days < 0)
00684 {
00685 notify(player, mailmsg[MAIL_INVALID_AGE]);
00686 return false;
00687 }
00688 break;
00689
00690 case '#':
00691
00692
00693
00694 p++;
00695 if (*p == '\0')
00696 {
00697 notify(player, mailmsg[MAIL_INVALID_DBREF]);
00698 return false;
00699 }
00700 ms->player = mux_atol(p);
00701 if (!Good_obj(ms->player) || !(ms->player))
00702 {
00703 notify(player, mailmsg[MAIL_INVALID_DBREF]);
00704 return false;
00705 }
00706 break;
00707
00708 case '*':
00709
00710
00711
00712 p++;
00713 if (*p == '\0')
00714 {
00715 notify(player, mailmsg[MAIL_INVALID_PLAYER]);
00716 return false;
00717 }
00718 ms->player = lookup_player(player, p, true);
00719 if (ms->player == NOTHING)
00720 {
00721 notify(player, mailmsg[MAIL_INVALID_PLAYER_OR_USING_MALIAS]);
00722 return false;
00723 }
00724 break;
00725
00726 case 'A':
00727
00728
00729
00730 p++;
00731 switch (mux_toupper(*p))
00732 {
00733 case '\0':
00734 notify(player, "MAIL: A isn't enough (all?)");
00735 return false;
00736
00737 case 'L':
00738
00739
00740
00741 p++;
00742 switch (mux_toupper(*p))
00743 {
00744 case '\0':
00745 notify(player, "MAIL: AL isn't enough (all?)");
00746 return false;
00747
00748 case 'L':
00749
00750
00751
00752 p++;
00753 if (*p == '\0')
00754 {
00755 ms->flags = M_ALL;
00756 }
00757 else
00758 {
00759 notify(player, mailmsg[MAIL_INVALID_SPEC]);
00760 return false;
00761 }
00762 break;
00763
00764 default:
00765
00766
00767
00768 notify(player, mailmsg[MAIL_INVALID_SPEC]);
00769 return false;
00770 }
00771 break;
00772
00773 default:
00774
00775
00776
00777 notify(player, mailmsg[MAIL_INVALID_SPEC]);
00778 return false;
00779 }
00780 break;
00781
00782 case 'U':
00783
00784
00785
00786 p++;
00787 if (*p == '\0')
00788 {
00789 notify(player, "MAIL: U is ambiguous (urgent or unread?)");
00790 return false;
00791 }
00792 switch (mux_toupper(*p))
00793 {
00794 case 'R':
00795
00796
00797
00798 ms->flags = M_URGENT;
00799 break;
00800
00801 case 'N':
00802
00803
00804
00805 ms->flags = M_MSUNREAD;
00806 break;
00807
00808 default:
00809
00810
00811
00812 notify(player, mailmsg[MAIL_INVALID_SPEC]);
00813 return false;
00814 }
00815 break;
00816
00817 case 'R':
00818
00819
00820
00821 ms->flags = M_ISREAD;
00822 break;
00823
00824 case 'C':
00825
00826
00827
00828 ms->flags = M_CLEARED;
00829 break;
00830
00831 case 'T':
00832
00833
00834
00835 ms->flags = M_TAG;
00836 break;
00837
00838 case 'M':
00839
00840
00841
00842 p++;
00843 if (*p == '\0')
00844 {
00845 notify(player, "MAIL: M is ambiguous (mass or me?)");
00846 return false;
00847 }
00848 switch (mux_toupper(*p))
00849 {
00850 case 'A':
00851
00852 ms->flags = M_MASS;
00853 break;
00854
00855 case 'E':
00856
00857 ms->player = player;
00858 break;
00859
00860 default:
00861
00862 notify(player, mailmsg[MAIL_INVALID_SPEC]);
00863 return false;
00864 }
00865 break;
00866
00867 default:
00868
00869
00870
00871 notify(player, mailmsg[MAIL_INVALID_SPEC]);
00872 return false;
00873 }
00874 }
00875 return true;
00876 }
00877
00878 static int player_folder(dbref player)
00879 {
00880
00881
00882
00883 int flags;
00884 char *atrstr = atr_pget(player, A_MAILCURF, &player, &flags);
00885 if (!*atrstr)
00886 {
00887 free_lbuf(atrstr);
00888 set_player_folder(player, 0);
00889 return 0;
00890 }
00891 int number = mux_atol(atrstr);
00892 free_lbuf(atrstr);
00893 return number;
00894 }
00895
00896
00897
00898 static void do_mail_change_folder(dbref player, char *fld, char *newname)
00899 {
00900 int pfld;
00901
00902 if (!fld || !*fld)
00903 {
00904
00905
00906 for (pfld = 0; pfld <= MAX_FOLDERS; pfld++)
00907 {
00908 check_mail(player, pfld, true);
00909 }
00910 pfld = player_folder(player);
00911 notify(player, tprintf("MAIL: Current folder is %d [%s].",
00912 pfld, get_folder_name(player, pfld)));
00913 return;
00914 }
00915 pfld = parse_folder(player, fld);
00916 if (pfld < 0)
00917 {
00918 notify(player, "MAIL: What folder is that?");
00919 return;
00920 }
00921 if (newname && *newname)
00922 {
00923
00924
00925 if (strlen(newname) > FOLDER_NAME_LEN)
00926 {
00927 notify(player, "MAIL: Folder name too long");
00928 return;
00929 }
00930 char *p;
00931 for (p = newname; mux_isalnum(*p); p++) ;
00932 if (*p != '\0')
00933 {
00934 notify(player, "MAIL: Illegal folder name");
00935 return;
00936 }
00937
00938 add_folder_name(player, pfld, newname);
00939 notify(player, tprintf("MAIL: Folder %d now named '%s'", pfld, newname));
00940 }
00941 else
00942 {
00943
00944
00945 set_player_folder(player, pfld);
00946 notify(player, tprintf("MAIL: Current folder set to %d [%s].",
00947 pfld, get_folder_name(player, pfld)));
00948 }
00949 }
00950
00951 static int sign(int x)
00952 {
00953 if (x == 0)
00954 {
00955 return 0;
00956 }
00957 else if (x < 0)
00958 {
00959 return -1;
00960 }
00961 else
00962 {
00963 return 1;
00964 }
00965 }
00966
00967 static bool mail_match(struct mail *mp, struct mail_selector ms, int num)
00968 {
00969
00970
00971 if (ms.low && num < ms.low)
00972 {
00973 return false;
00974 }
00975 if (ms.high && ms.high < num)
00976 {
00977 return false;
00978 }
00979 if (ms.player && mp->from != ms.player)
00980 {
00981 return false;
00982 }
00983
00984 mail_flag mpflag = Read(mp)
00985 ? (mp->read | M_ALL)
00986 : (mp->read | M_ALL | M_MSUNREAD);
00987
00988 if ((ms.flags & mpflag) == 0)
00989 {
00990 return false;
00991 }
00992
00993 if (ms.days == -1)
00994 {
00995 return true;
00996 }
00997
00998
00999
01000
01001 CLinearTimeAbsolute ltaNow;
01002 ltaNow.GetLocal();
01003
01004 const char *pMailTimeStr = mp->time;
01005
01006 CLinearTimeAbsolute ltaMail;
01007 if (ltaMail.SetString(pMailTimeStr))
01008 {
01009 CLinearTimeDelta ltd(ltaMail, ltaNow);
01010 int iDiffDays = ltd.ReturnDays();
01011 if (sign(iDiffDays - ms.days) == ms.day_comp)
01012 {
01013 return true;
01014 }
01015 }
01016 return false;
01017 }
01018
01019
01020
01021 static void do_mail_flags(dbref player, char *msglist, mail_flag flag, bool negate)
01022 {
01023 struct mail_selector ms;
01024
01025 if (!parse_msglist(msglist, &ms, player))
01026 {
01027 return;
01028 }
01029 int i = 0, j = 0;
01030 int folder = player_folder(player);
01031
01032 MailList ml(player);
01033 struct mail *mp;
01034 for (mp = ml.FirstItem(); !ml.IsEnd(); mp = ml.NextItem())
01035 {
01036 if ( All(ms)
01037 || Folder(mp) == folder)
01038 {
01039 i++;
01040 if (mail_match(mp, ms, i))
01041 {
01042 j++;
01043 if (negate)
01044 {
01045 mp->read &= ~flag;
01046 }
01047 else
01048 {
01049 mp->read |= flag;
01050 }
01051
01052 switch (flag)
01053 {
01054 case M_TAG:
01055 notify(player, tprintf("MAIL: Msg #%d %s.", i, negate ? "untagged" : "tagged"));
01056 break;
01057
01058 case M_CLEARED:
01059 if (Unread(mp) && !negate)
01060 {
01061 notify(player, tprintf("MAIL: Unread Msg #%d cleared! Use @mail/unclear %d to recover.", i, i));
01062 }
01063 else
01064 {
01065 notify(player, tprintf("MAIL: Msg #%d %s.", i, negate ? "uncleared" : "cleared"));
01066 }
01067 break;
01068
01069 case M_SAFE:
01070 notify(player, tprintf("MAIL: Msg #%d marked safe.", i));
01071 break;
01072 }
01073 }
01074 }
01075 }
01076
01077 if (!j)
01078 {
01079
01080
01081 notify(player, "MAIL: You don't have any matching messages!");
01082 }
01083 }
01084
01085 static void do_mail_tag(dbref player, char *msglist)
01086 {
01087 do_mail_flags(player, msglist, M_TAG, false);
01088 }
01089
01090 static void do_mail_safe(dbref player, char *msglist)
01091 {
01092 do_mail_flags(player, msglist, M_SAFE, false);
01093 }
01094
01095 void do_mail_clear(dbref player, char *msglist)
01096 {
01097 do_mail_flags(player, msglist, M_CLEARED, false);
01098 }
01099
01100 static void do_mail_untag(dbref player, char *msglist)
01101 {
01102 do_mail_flags(player, msglist, M_TAG, true);
01103 }
01104
01105 static void do_mail_unclear(dbref player, char *msglist)
01106 {
01107 do_mail_flags(player, msglist, M_CLEARED, true);
01108 }
01109
01110
01111
01112 static void do_mail_file(dbref player, char *msglist, char *folder)
01113 {
01114 struct mail_selector ms;
01115 if (!parse_msglist(msglist, &ms, player))
01116 {
01117 return;
01118 }
01119 int foldernum;
01120 if ((foldernum = parse_folder(player, folder)) == -1)
01121 {
01122 notify(player, "MAIL: Invalid folder specification");
01123 return;
01124 }
01125 int i = 0, j = 0;
01126 int origfold = player_folder(player);
01127
01128 MailList ml(player);
01129 struct mail *mp;
01130 for (mp = ml.FirstItem(); !ml.IsEnd(); mp = ml.NextItem())
01131 {
01132 if ( All(ms)
01133 || (Folder(mp) == origfold))
01134 {
01135 i++;
01136 if (mail_match(mp, ms, i))
01137 {
01138 j++;
01139
01140
01141
01142 mp->read &= M_FMASK;
01143 mp->read |= FolderBit(foldernum);
01144 notify(player, tprintf("MAIL: Msg %d filed in folder %d", i, foldernum));
01145 }
01146 }
01147 }
01148
01149 if (!j)
01150 {
01151
01152
01153 notify(player, "MAIL: You don't have any matching messages!");
01154 }
01155 }
01156
01157
01158
01159
01160
01161 static char *MakeCanonicalMailAlias
01162 (
01163 char *pMailAlias,
01164 int *pnValidMailAlias,
01165 bool *pbValidMailAlias
01166 )
01167 {
01168 static char Buffer[SIZEOF_MALIAS];
01169 size_t nLeft = sizeof(Buffer)-1;
01170 char *q = Buffer;
01171 char *p = pMailAlias;
01172
01173 if ( !p
01174 || !mux_isalpha(*p))
01175 {
01176 *pnValidMailAlias = 0;
01177 *pbValidMailAlias = false;
01178 return NULL;
01179 }
01180 *q++ = *p++;
01181 nLeft--;
01182
01183 while ( *p
01184 && nLeft)
01185 {
01186 if ( !mux_isalpha(*p)
01187 && !mux_isdigit(*p)
01188 && *p != '_')
01189 {
01190 break;
01191 }
01192 *q++ = *p++;
01193 nLeft--;
01194 }
01195 *q = '\0';
01196
01197 *pnValidMailAlias = q - Buffer;
01198 *pbValidMailAlias = true;
01199 return Buffer;
01200 }
01201
01202 #define GMA_NOTFOUND 1
01203 #define GMA_FOUND 2
01204 #define GMA_INVALIDFORM 3
01205
01206 static struct malias *get_malias(dbref player, char *alias, int *pnResult)
01207 {
01208 *pnResult = GMA_INVALIDFORM;
01209 if (!alias)
01210 {
01211 return NULL;
01212 }
01213 if (alias[0] == '#')
01214 {
01215 if (ExpMail(player))
01216 {
01217 int x = mux_atol(alias + 1);
01218 if (x < 0 || x >= ma_top)
01219 {
01220 *pnResult = GMA_NOTFOUND;
01221 return NULL;
01222 }
01223 *pnResult = GMA_FOUND;
01224 return malias[x];
01225 }
01226 }
01227 else if (alias[0] == '*')
01228 {
01229 int nValidMailAlias;
01230 bool bValidMailAlias;
01231 char *pValidMailAlias = MakeCanonicalMailAlias
01232 ( alias+1,
01233 &nValidMailAlias,
01234 &bValidMailAlias
01235 );
01236
01237 if (bValidMailAlias)
01238 {
01239 for (int i = 0; i < ma_top; i++)
01240 {
01241 struct malias *m = malias[i];
01242 if ( m->owner == player
01243 || m->owner == GOD
01244 || ExpMail(player))
01245 {
01246 if (!strcmp(pValidMailAlias, m->name))
01247 {
01248
01249
01250 *pnResult = GMA_FOUND;
01251 return m;
01252 }
01253 }
01254 }
01255 *pnResult = GMA_NOTFOUND;
01256 }
01257 }
01258 if (*pnResult == GMA_INVALIDFORM)
01259 {
01260 if (ExpMail(player))
01261 {
01262 notify(player, "MAIL: Mail aliases must be of the form *<name> or #<num>.");
01263 }
01264 else
01265 {
01266 notify(player, "MAIL: Mail aliases must be of the form *<name>.");
01267 }
01268 }
01269 return NULL;
01270 }
01271
01272 static char *make_namelist(dbref player, char *arg)
01273 {
01274 UNUSED_PARAMETER(player);
01275
01276 char *p;
01277 char *oldarg = alloc_lbuf("make_namelist.oldarg");
01278 char *names = alloc_lbuf("make_namelist.names");
01279 char *bp = names;
01280
01281 strcpy(oldarg, arg);
01282
01283 MUX_STRTOK_STATE tts;
01284 mux_strtok_src(&tts, oldarg);
01285 mux_strtok_ctl(&tts, " ");
01286 bool bFirst = true;
01287 for (p = mux_strtok_parse(&tts); p; p = mux_strtok_parse(&tts))
01288 {
01289 if (!bFirst)
01290 {
01291 safe_str(", ", names, &bp);
01292 }
01293 bFirst = false;
01294
01295 if ( mux_isdigit(p[0])
01296 || ( p[0] == '!'
01297 && mux_isdigit(p[1])))
01298 {
01299 char ch = p[0];
01300 if (ch == '!')
01301 {
01302 p++;
01303 }
01304 dbref target = mux_atol(p);
01305 if ( Good_obj(target)
01306 && isPlayer(target))
01307 {
01308 if (ch == '!')
01309 {
01310 safe_chr('!', names, &bp);
01311 }
01312 safe_str(Name(target), names, &bp);
01313 }
01314 }
01315 else
01316 {
01317 safe_str(p, names, &bp);
01318 }
01319 }
01320 *bp = '\0';
01321 free_lbuf(oldarg);
01322 return names;
01323 }
01324
01325 #define NUM_MAILSTATUSTABLE 7
01326 static struct tag_mailstatusentry
01327 {
01328 int nMask;
01329 char *pYes;
01330 int nYes;
01331 char *pNo;
01332 int nNo;
01333 }
01334 aMailStatusTable[NUM_MAILSTATUSTABLE] =
01335 {
01336 { M_ISREAD, "Read", 4, "Unread", 6 },
01337 { M_CLEARED, "Cleared", 7, 0, 0 },
01338 { M_URGENT, "Urgent", 6, 0, 0 },
01339 { M_MASS, "Mass", 4, 0, 0 },
01340 { M_FORWARD, "Fwd", 3, 0, 0 },
01341 { M_TAG, "Tagged", 6, 0, 0 },
01342 { M_SAFE, "Safe", 4, 0, 0 }
01343 };
01344
01345 static char *status_string(struct mail *mp)
01346 {
01347
01348
01349 char *tbuf1 = alloc_lbuf("status_string");
01350 char *p = tbuf1;
01351 struct tag_mailstatusentry *mse = aMailStatusTable;
01352 for (int i = 0; i < NUM_MAILSTATUSTABLE; i++, mse++)
01353 {
01354 if (mp->read & mse->nMask)
01355 {
01356 if (p != tbuf1) *p++ = ' ';
01357 memcpy(p, mse->pYes, mse->nYes);
01358 p += mse->nYes;
01359 }
01360 else if (mse->pNo)
01361 {
01362 if (p != tbuf1) *p++ = ' ';
01363 memcpy(p, mse->pNo, mse->nNo);
01364 p += mse->nNo;
01365 }
01366 }
01367 *p++ = '\0';
01368 return tbuf1;
01369 }
01370
01371 static void do_mail_read(dbref player, char *msglist)
01372 {
01373 struct mail_selector ms;
01374 if (!parse_msglist(msglist, &ms, player))
01375 {
01376 return;
01377 }
01378
01379 char *status, *names;
01380 int i = 0, j = 0;
01381 char *buff = alloc_lbuf("do_mail_read.1");
01382 int folder = player_folder(player);
01383
01384 MailList ml(player);
01385 struct mail *mp;
01386 for (mp = ml.FirstItem(); !ml.IsEnd(); mp = ml.NextItem())
01387 {
01388 if (Folder(mp) == folder)
01389 {
01390 i++;
01391 if (mail_match(mp, ms, i))
01392 {
01393
01394
01395 j++;
01396 buff[LBUF_SIZE-1] = '\0';
01397 strncpy(buff, MessageFetch(mp->number), LBUF_SIZE);
01398 if (buff[LBUF_SIZE-1] != '\0')
01399 {
01400 STARTLOG(LOG_BUGS, "BUG", "MAIL");
01401 log_text(tprintf("do_mail_read: %s: Mail message %d truncated.", Name(player), mp->number));
01402 ENDLOG;
01403 buff[LBUF_SIZE-1] = '\0';
01404 }
01405 notify(player, DASH_LINE);
01406 status = status_string(mp);
01407 names = make_namelist(player, mp->tolist);
01408 char szSubjectBuffer[MBUF_SIZE];
01409 int iRealVisibleWidth;
01410 ANSI_TruncateToField(mp->subject, sizeof(szSubjectBuffer),
01411 szSubjectBuffer, 65, &iRealVisibleWidth, ANSI_ENDGOAL_NORMAL);
01412 notify(player, tprintf("%-3d From: %-*s At: %-25s %s\r\nFldr : %-2d Status: %s\r\nTo : %-65s\r\nSubject: %s",
01413 i, PLAYER_NAME_LIMIT - 6, Name(mp->from),
01414 mp->time,
01415 (Connected(mp->from) &&
01416 (!Hidden(mp->from) || See_Hidden(player))) ?
01417 " (Conn)" : " ", folder,
01418 status,
01419 names,
01420 szSubjectBuffer));
01421 free_lbuf(names);
01422 free_lbuf(status);
01423 notify(player, DASH_LINE);
01424 notify(player, buff);
01425 notify(player, DASH_LINE);
01426 if (Unread(mp))
01427 {
01428
01429
01430 mp->read |= M_ISREAD;
01431 }
01432 }
01433 }
01434 }
01435 free_lbuf(buff);
01436
01437 if (!j)
01438 {
01439
01440
01441 notify(player, "MAIL: You don't have that many matching messages!");
01442 }
01443 }
01444
01445 static char *status_chars(struct mail *mp)
01446 {
01447
01448
01449 static char res[10];
01450
01451 char *p = res;
01452 *p++ = Read(mp) ? '-' : 'N';
01453 *p++ = M_Safe(mp) ? 'S' : '-';
01454 *p++ = Cleared(mp) ? 'C' : '-';
01455 *p++ = Urgent(mp) ? 'U' : '-';
01456 *p++ = Mass(mp) ? 'M' : '-';
01457 *p++ = Forward(mp) ? 'F' : '-';
01458 *p++ = Tagged(mp) ? '+' : '-';
01459 *p = '\0';
01460 return res;
01461 }
01462
01463 static void do_mail_review(dbref player, char *name, char *msglist)
01464 {
01465 dbref target = lookup_player(player, name, true);
01466 if (target == NOTHING)
01467 {
01468 notify(player, "MAIL: No such player.");
01469 return;
01470 }
01471
01472 struct mail *mp;
01473 struct mail_selector ms;
01474 int i = 0, j = 0;
01475 int iRealVisibleWidth;
01476 char szSubjectBuffer[MBUF_SIZE];
01477
01478 if ( !msglist
01479 || !*msglist)
01480 {
01481 notify(player, tprintf("-------------------- MAIL: %-25s ------------------", Name(target)));
01482 MailList ml(target);
01483 for (mp = ml.FirstItem(); !ml.IsEnd(); mp = ml.NextItem())
01484 {
01485 if (mp->from == player)
01486 {
01487 i++;
01488 ANSI_TruncateToField(mp->subject, sizeof(szSubjectBuffer),
01489 szSubjectBuffer, 25, &iRealVisibleWidth, ANSI_ENDGOAL_NORMAL);
01490 size_t nSize = strlen(MessageFetch(mp->number));
01491 const char *pFromName = Name(mp->from);
01492 notify(player, tprintf("[%s] %-3d (%4d) From: %-*s Sub: %s",
01493 status_chars(mp),
01494 i, nSize,
01495 PLAYER_NAME_LIMIT - 6, pFromName,
01496 szSubjectBuffer));
01497 }
01498 }
01499 notify(player, DASH_LINE);
01500 }
01501 else
01502 {
01503 if (!parse_msglist(msglist, &ms, target))
01504 {
01505 return;
01506 }
01507 MailList ml(target);
01508 for (mp = ml.FirstItem(); !ml.IsEnd() && !MuxAlarm.bAlarmed; mp = ml.NextItem())
01509 {
01510 if (mp->from == player)
01511 {
01512 i++;
01513 if (mail_match(mp, ms, i))
01514 {
01515 j++;
01516 char *status = status_string(mp);
01517 const char *str = MessageFetch(mp->number);
01518 ANSI_TruncateToField(mp->subject, sizeof(szSubjectBuffer),
01519 szSubjectBuffer, 65, &iRealVisibleWidth, ANSI_ENDGOAL_NORMAL);
01520 notify(player, DASH_LINE);
01521 notify(player, tprintf("%-3d From: %-*s At: %-25s %s\r\nFldr : %-2d Status: %s\r\nSubject: %s",
01522 i, PLAYER_NAME_LIMIT - 6, Name(mp->from),
01523 mp->time,
01524 (Connected(mp->from) &&
01525 (!Hidden(mp->from) || See_Hidden(player))) ?
01526 " (Conn)" : " ", 0,
01527 status, szSubjectBuffer));
01528 free_lbuf(status);
01529 notify(player, DASH_LINE);
01530 notify(player, str);
01531 notify(player, DASH_LINE);
01532 }
01533 }
01534 }
01535
01536 if (!j)
01537 {
01538
01539
01540 notify(player, "MAIL: You don't have that many matching messages!");
01541 }
01542 }
01543 }
01544
01545 static char *mail_list_time(const char *the_time)
01546 {
01547 char *p = (char *)the_time;
01548 char *new0 = alloc_lbuf("mail_list_time");
01549 char *q = new0;
01550 if (!p || !*p)
01551 {
01552 *new0 = '\0';
01553 return new0;
01554 }
01555
01556
01557
01558
01559 int i;
01560 for (i = 0; i < 16; i++)
01561 {
01562 if (*p)
01563 {
01564 *q++ = *p++;
01565 }
01566 }
01567
01568 for (i = 0; i < 3; i++)
01569 {
01570 if (*p)
01571 {
01572 p++;
01573 }
01574 }
01575
01576 for (i = 0; i < 5; i++)
01577 {
01578 if (*p)
01579 {
01580 *q++ = *p++;
01581 }
01582 }
01583
01584 *q = '\0';
01585 return new0;
01586 }
01587
01588 static void do_mail_list(dbref player, char *msglist, bool sub)
01589 {
01590 struct mail_selector ms;
01591
01592 if (!parse_msglist(msglist, &ms, player))
01593 {
01594 return;
01595 }
01596 int i = 0;
01597 char *time;
01598 int iRealVisibleWidth;
01599 char szSubjectBuffer[MBUF_SIZE];
01600 int folder = player_folder(player);
01601
01602 notify(player,
01603 tprintf("--------------------------- MAIL: Folder %d ----------------------------", folder));
01604
01605 MailList ml(player);
01606 struct mail *mp;
01607 for (mp = ml.FirstItem(); !ml.IsEnd(); mp = ml.NextItem())
01608 {
01609 if (Folder(mp) == folder)
01610 {
01611 i++;
01612 if (mail_match(mp, ms, i))
01613 {
01614 time = mail_list_time(mp->time);
01615 size_t nSize = strlen(MessageFetch(mp->number));
01616 const char *pFromName = Name(mp->from);
01617 if (sub)
01618 {
01619 ANSI_TruncateToField(mp->subject, sizeof(szSubjectBuffer),
01620 szSubjectBuffer, 25, &iRealVisibleWidth, ANSI_ENDGOAL_NORMAL);
01621
01622 notify(player, tprintf("[%s] %-3d (%4d) From: %-*s Sub: %s",
01623 status_chars(mp), i, nSize, PLAYER_NAME_LIMIT - 6, pFromName, szSubjectBuffer));
01624 }
01625 else
01626 {
01627 notify(player, tprintf("[%s] %-3d (%4d) From: %-*s At: %s %s",
01628 status_chars(mp), i, nSize, PLAYER_NAME_LIMIT - 6, pFromName, time,
01629 ((Connected(mp->from) && (!Hidden(mp->from) || See_Hidden(player))) ? "Conn" : " ")));
01630 }
01631 free_lbuf(time);
01632 }
01633 }
01634 }
01635 notify(player, DASH_LINE);
01636 }
01637
01638 void do_mail_purge(dbref player)
01639 {
01640
01641
01642 MailList ml(player);
01643 struct mail *mp;
01644 for (mp = ml.FirstItem(); !ml.IsEnd(); mp = ml.NextItem())
01645 {
01646 if (Cleared(mp))
01647 {
01648 ml.RemoveItem();
01649 }
01650 }
01651 notify(player, "MAIL: Mailbox purged.");
01652 }
01653
01654 static char *make_numlist(dbref player, char *arg, bool bBlind)
01655 {
01656 char *tail, spot;
01657 struct malias *m;
01658 dbref target;
01659 int nRecip = 0;
01660 dbref aRecip[(LBUF_SIZE+1)/2];
01661
01662 char *head = arg;
01663
01664 while ( head
01665 && *head)
01666 {
01667 while (*head == ' ')
01668 {
01669 head++;
01670 }
01671
01672 tail = head;
01673 while ( *tail
01674 && *tail != ' ')
01675 {
01676 if (*tail == '"')
01677 {
01678 head++;
01679 tail++;
01680 while ( *tail
01681 && *tail != '"')
01682 {
01683 tail++;
01684 }
01685 }
01686 if (*tail)
01687 {
01688 tail++;
01689 }
01690 }
01691 tail--;
01692 if (*tail != '"')
01693 {
01694 tail++;
01695 }
01696 spot = *tail;
01697 *tail = '\0';
01698
01699 if (*head == '*')
01700 {
01701 int nResult;
01702 m = get_malias(player, head, &nResult);
01703 if (nResult == GMA_NOTFOUND)
01704 {
01705 notify(player, tprintf("MAIL: Alias '%s' does not exist.", head));
01706 return NULL;
01707 }
01708 else if (nResult == GMA_INVALIDFORM)
01709 {
01710 notify(player, tprintf("MAIL: '%s' is a badly-formed alias.", head));
01711 return NULL;
01712 }
01713 for (int i = 0; i < m->numrecep; i++)
01714 {
01715 aRecip[nRecip++] = m->list[i];
01716 }
01717 }
01718 else
01719 {
01720 target = lookup_player(player, head, true);
01721 if (Good_obj(target))
01722 {
01723 aRecip[nRecip++] = target;
01724 }
01725 else
01726 {
01727 notify(player, tprintf("MAIL: '%s' does not exist.", head));
01728 return NULL;
01729 }
01730 }
01731
01732
01733
01734 *tail = spot;
01735 head = tail;
01736 if (*head == '"')
01737 {
01738 head++;
01739 }
01740 }
01741
01742 if (nRecip <= 0)
01743 {
01744 notify(player, "MAIL: No players specified.");
01745 return NULL;
01746 }
01747 else
01748 {
01749 ITL itl;
01750 char *numbuf, *numbp;
01751 numbp = numbuf = alloc_lbuf("mail.make_numlist");
01752 ItemToList_Init(&itl, numbuf, &numbp, bBlind ? '!' : '\0');
01753 int i;
01754 for (i = 0; i < nRecip; i++)
01755 {
01756 if (aRecip[i] != NOTHING)
01757 {
01758 for (int j = i + 1; j < nRecip; j++)
01759 {
01760 if (aRecip[i] == aRecip[j])
01761 {
01762 aRecip[j] = NOTHING;
01763 }
01764 }
01765 if (Good_obj(aRecip[i]))
01766 {
01767 ItemToList_AddInteger(&itl, aRecip[i]);
01768 }
01769 }
01770 }
01771 ItemToList_Final(&itl);
01772 return numbuf;
01773 }
01774 }
01775
01776 static void do_expmail_start(dbref player, char *arg, char *subject)
01777 {
01778 if (!arg || !*arg)
01779 {
01780 notify(player, "MAIL: I do not know whom you want to mail.");
01781 return;
01782 }
01783 if (!subject || !*subject)
01784 {
01785 notify(player, "MAIL: No subject.");
01786 return;
01787 }
01788 if (Flags2(player) & PLAYER_MAILS)
01789 {
01790 notify(player, "MAIL: Mail message already in progress.");
01791 return;
01792 }
01793 if ( !Wizard(player)
01794 && ThrottleMail(player))
01795 {
01796 notify(player, "MAIL: Too much @mail sent recently.");
01797 return;
01798 }
01799 char *tolist = make_numlist(player, arg, false);
01800 if (!tolist)
01801 {
01802 return;
01803 }
01804
01805 atr_add_raw(player, A_MAILTO, tolist);
01806 atr_add_raw(player, A_MAILSUB, subject);
01807 atr_add_raw(player, A_MAILFLAGS, "0");
01808 atr_clr(player, A_MAILMSG);
01809 Flags2(player) |= PLAYER_MAILS;
01810 char *names = make_namelist(player, tolist);
01811 notify(player, tprintf("MAIL: You are sending mail to '%s'.", names));
01812 free_lbuf(names);
01813 free_lbuf(tolist);
01814 }
01815
01816 static void do_mail_fwd(dbref player, char *msg, char *tolist)
01817 {
01818 if (Flags2(player) & PLAYER_MAILS)
01819 {
01820 notify(player, "MAIL: Mail message already in progress.");
01821 return;
01822 }
01823 if (!msg || !*msg)
01824 {
01825 notify(player, "MAIL: No message list.");
01826 return;
01827 }
01828 if (!tolist || !*tolist)
01829 {
01830 notify(player, "MAIL: To whom should I forward?");
01831 return;
01832 }
01833 if ( !Wizard(player)
01834 && ThrottleMail(player))
01835 {
01836 notify(player, "MAIL: Too much @mail sent recently.");
01837 return;
01838 }
01839 int num = mux_atol(msg);
01840 if (!num)
01841 {
01842 notify(player, "MAIL: I don't understand that message number.");
01843 return;
01844 }
01845 struct mail *mp = mail_fetch(player, num);
01846 if (!mp)
01847 {
01848 notify(player, "MAIL: You can't forward non-existent messages.");
01849 return;
01850 }
01851 do_expmail_start(player, tolist, tprintf("%s (fwd from %s)", mp->subject, Name(mp->from)));
01852 atr_add_raw(player, A_MAILMSG, MessageFetch(mp->number));
01853 const char *pValue = atr_get_raw(player, A_MAILFLAGS);
01854 int iFlag = M_FORWARD;
01855 if (pValue)
01856 {
01857 iFlag |= mux_atol(pValue);
01858 }
01859 atr_add_raw(player, A_MAILFLAGS, mux_ltoa_t(iFlag));
01860 }
01861
01862 static void do_mail_reply(dbref player, char *msg, bool all, int key)
01863 {
01864 if (Flags2(player) & PLAYER_MAILS)
01865 {
01866 notify(player, "MAIL: Mail message already in progress.");
01867 return;
01868 }
01869 if (!msg || !*msg)
01870 {
01871 notify(player, "MAIL: No message list.");
01872 return;
01873 }
01874 if ( !Wizard(player)
01875 && ThrottleMail(player))
01876 {
01877 notify(player, "MAIL: Too much @mail sent recently.");
01878 return;
01879 }
01880 int num = mux_atol(msg);
01881 if (!num)
01882 {
01883 notify(player, "MAIL: I don't understand that message number.");
01884 return;
01885 }
01886 struct mail *mp = mail_fetch(player, num);
01887 if (!mp)
01888 {
01889 notify(player, "MAIL: You can't reply to non-existent messages.");
01890 return;
01891 }
01892 char *tolist = alloc_lbuf("do_mail_reply.tolist");
01893 char *bp = tolist;
01894 if (all)
01895 {
01896 char *names = alloc_lbuf("do_mail_reply.names");
01897 char *oldlist = alloc_lbuf("do_mail_reply.oldlist");
01898 bp = names;
01899 *bp = '\0';
01900
01901 strcpy(oldlist, mp->tolist);
01902
01903 MUX_STRTOK_STATE tts;
01904 mux_strtok_src(&tts, oldlist);
01905 mux_strtok_ctl(&tts, " ");
01906 char *p;
01907 for (p = mux_strtok_parse(&tts); p; p = mux_strtok_parse(&tts))
01908 {
01909 if (mux_atol(p) != mp->from)
01910 {
01911 safe_chr('#', names, &bp);
01912 safe_str(p, names, &bp);
01913 safe_chr(' ', names, &bp);
01914 }
01915 }
01916 free_lbuf(oldlist);
01917 safe_chr('#', names, &bp);
01918 safe_ltoa(mp->from, names, &bp);
01919 *bp = '\0';
01920 strcpy(tolist, names);
01921 free_lbuf(names);
01922 }
01923 else
01924 {
01925 safe_chr('#', tolist, &bp);
01926 safe_ltoa(mp->from, tolist, &bp);
01927 *bp = '\0';
01928 }
01929
01930 const char *pSubject = mp->subject;
01931 const char *pMessage = MessageFetch(mp->number);
01932 const char *pTime = mp->time;
01933 if (strncmp(pSubject, "Re:", 3))
01934 {
01935 do_expmail_start(player, tolist, tprintf("Re: %s", pSubject));
01936 }
01937 else
01938 {
01939 do_expmail_start(player, tolist, tprintf("%s", pSubject));
01940 }
01941 if (key & MAIL_QUOTE)
01942 {
01943 const char *pFromName = Name(mp->from);
01944 char *pMessageBody =
01945 tprintf("On %s, %s wrote:\r\n\r\n%s\r\n\r\n********** End of included message from %s\r\n",
01946 pTime, pFromName, pMessage, pFromName);
01947 atr_add_raw(player, A_MAILMSG, pMessageBody);
01948 }
01949
01950
01951
01952
01953
01954 const char *pValue = atr_get_raw(player, A_MAILFLAGS);
01955 int iFlag = M_REPLY;
01956 if (pValue)
01957 {
01958 iFlag |= mux_atol(pValue);
01959 }
01960 atr_add_raw(player, A_MAILFLAGS, mux_ltoa_t(iFlag));
01961
01962 free_lbuf(tolist);
01963 }
01964
01965
01966
01967
01968
01969
01970
01971
01972
01973
01974
01975
01976 struct mail *mail_fetch(dbref player, int num)
01977 {
01978 int i = 0;
01979 MailList ml(player);
01980 struct mail *mp;
01981 for (mp = ml.FirstItem(); !ml.IsEnd(); mp = ml.NextItem())
01982 {
01983 if (Folder(mp) == player_folder(player))
01984 {
01985 i++;
01986 if (i == num)
01987 {
01988 return mp;
01989 }
01990 }
01991 }
01992 return NULL;
01993 }
01994
01995 const char *mail_fetch_message(dbref player, int num)
01996 {
01997 struct mail *mp = mail_fetch(player, num);
01998 if (mp)
01999 {
02000 return MessageFetch(mp->number);
02001 }
02002 return NULL;
02003 }
02004
02005 int mail_fetch_from(dbref player, int num)
02006 {
02007 struct mail *mp = mail_fetch(player, num);
02008 if (mp)
02009 {
02010 return mp->from;
02011 }
02012 return NOTHING;
02013 }
02014
02015
02016
02017 void count_mail(dbref player, int folder, int *rcount, int *ucount, int *ccount)
02018 {
02019 int rc = 0;
02020 int uc = 0;
02021 int cc = 0;
02022
02023 MailList ml(player);
02024 struct mail *mp;
02025 for (mp = ml.FirstItem(); !ml.IsEnd(); mp = ml.NextItem())
02026 {
02027 if (Folder(mp) == folder)
02028 {
02029 if (Read(mp))
02030 {
02031 rc++;
02032 }
02033 else
02034 {
02035 uc++;
02036 }
02037
02038 if (Cleared(mp))
02039 {
02040 cc++;
02041 }
02042 }
02043 }
02044 *rcount = rc;
02045 *ucount = uc;
02046 *ccount = cc;
02047 }
02048
02049 static void urgent_mail(dbref player, int folder, int *ucount)
02050 {
02051 int uc = 0;
02052
02053 MailList ml(player);
02054 struct mail *mp;
02055 for (mp = ml.FirstItem(); !ml.IsEnd(); mp = ml.NextItem())
02056 {
02057 if (Folder(mp) == folder)
02058 {
02059 if (Unread(mp) && Urgent(mp))
02060 {
02061 uc++;
02062 }
02063 }
02064 }
02065 *ucount = uc;
02066 }
02067
02068 static void mail_return(dbref player, dbref target)
02069 {
02070 dbref aowner;
02071 int aflags;
02072
02073 char *str = atr_pget(target, A_MFAIL, &aowner, &aflags);
02074 if (*str)
02075 {
02076 char *str2, *buf, *bp;
02077 str2 = bp = alloc_lbuf("mail_return");
02078 buf = str;
02079 mux_exec(str2, &bp, target, player, player,
02080 EV_FCHECK | EV_EVAL | EV_TOP | EV_NO_LOCATION, &buf,
02081 (char **)NULL, 0);
02082 *bp = '\0';
02083 if (*str2)
02084 {
02085 CLinearTimeAbsolute ltaNow;
02086 ltaNow.GetLocal();
02087 FIELDEDTIME ft;
02088 ltaNow.ReturnFields(&ft);
02089
02090 notify_with_cause_ooc(player, target, tprintf("MAIL: Reject message from %s: %s",
02091 Moniker(target), str2));
02092 notify_with_cause_ooc(target, player, tprintf("[%d:%02d] MAIL: Reject message sent to %s.",
02093 ft.iHour, ft.iMinute, Moniker(player)));
02094 }
02095 free_lbuf(str2);
02096 }
02097 else
02098 {
02099 notify_with_cause_ooc(player, target, tprintf("Sorry, %s is not accepting mail.", Moniker(target)));
02100 }
02101 free_lbuf(str);
02102 }
02103
02104 static bool mail_check(dbref player, dbref target)
02105 {
02106 if (!could_doit(player, target, A_LMAIL))
02107 {
02108 mail_return(player, target);
02109 }
02110 else if (!could_doit(target, player, A_LMAIL))
02111 {
02112 if (Wizard(player))
02113 {
02114 notify(player, tprintf("Warning: %s can't return your mail.", Moniker(target)));
02115 return true;
02116 }
02117 else
02118 {
02119 notify(player, tprintf("Sorry, %s can't return your mail.", Moniker(target)));
02120 return false;
02121 }
02122 }
02123 else
02124 {
02125 return true;
02126 }
02127 return false;
02128 }
02129
02130 static void send_mail
02131 (
02132 dbref player,
02133 dbref target,
02134 const char *tolist,
02135 const char *subject,
02136 int number,
02137 mail_flag flags,
02138 bool silent
02139 )
02140 {
02141 if (!isPlayer(target))
02142 {
02143 notify(player, "MAIL: You cannot send mail to non-existent people.");
02144 return;
02145 }
02146 if (!mail_check(player, target))
02147 {
02148 return;
02149 }
02150 CLinearTimeAbsolute ltaNow;
02151 ltaNow.GetLocal();
02152
02153 char *pTimeStr = ltaNow.ReturnDateString(0);
02154
02155
02156
02157 struct mail *newp = (struct mail *)MEMALLOC(sizeof(struct mail));
02158 ISOUTOFMEMORY(newp);
02159 newp->to = target;
02160
02161
02162
02163
02164
02165 if (isPlayer(player))
02166 {
02167 newp->from = player;
02168 }
02169 else
02170 {
02171 dbref mailbag = Owner(player);
02172 if (Wizard(mailbag))
02173 {
02174 newp->from = player;
02175 }
02176 else
02177 {
02178 newp->from = mailbag;
02179 }
02180 }
02181 if ( !tolist
02182 || tolist[0] == '\0')
02183 {
02184 newp->tolist = StringClone("*HIDDEN*");
02185 }
02186 else
02187 {
02188 newp->tolist = StringClone(tolist);
02189 }
02190
02191 newp->number = number;
02192 MessageReferenceInc(number);
02193 newp->time = StringClone(pTimeStr);
02194 newp->subject = StringClone(subject);
02195
02196
02197
02198 newp->read = flags & M_FMASK;
02199
02200
02201
02202 MailList ml(target);
02203 ml.AppendItem(newp);
02204
02205
02206
02207 if (!silent)
02208 {
02209 notify(player, tprintf("MAIL: You sent your message to %s.", Name(target)));
02210 }
02211
02212 notify(target, tprintf("MAIL: You have a new message from %s.", Name(player)));
02213 did_it(player, target, A_MAIL, NULL, 0, NULL, A_AMAIL, NULL, NOTHING);
02214 }
02215
02216 static void do_mail_nuke(dbref player)
02217 {
02218 if (!God(player))
02219 {
02220 notify(player, "The postal service issues a warrant for your arrest.");
02221 return;
02222 }
02223
02224
02225
02226 dbref thing;
02227 DO_WHOLE_DB(thing)
02228 {
02229 MailList ml(thing);
02230 ml.RemoveAll();
02231 }
02232 log_text(tprintf("** MAIL PURGE ** done by %s(#%d)." ENDLINE, Name(player), player));
02233 notify(player, "You annihilate the post office. All messages cleared.");
02234 }
02235
02236 static void do_mail_debug(dbref player, char *action, char *victim)
02237 {
02238 if (!ExpMail(player))
02239 {
02240 notify(player, "Go get some bugspray.");
02241 return;
02242 }
02243
02244 dbref thing;
02245 if (string_prefix("clear", action))
02246 {
02247 dbref target = lookup_player(player, victim, true);
02248 if (target == NOTHING)
02249 {
02250 init_match(player, victim, NOTYPE);
02251 match_absolute();
02252 target = match_result();
02253 }
02254 if (target == NOTHING)
02255 {
02256 notify(player, tprintf("%s: no such player.", victim));
02257 return;
02258 }
02259 if (Wizard(target))
02260 {
02261 notify(player, tprintf("Let %s clear their own @mail.", Name(target)));
02262 return;
02263 }
02264 do_mail_clear(target, NULL);
02265 do_mail_purge(target);
02266 notify(player, tprintf("Mail cleared for %s(#%d).", Name(target), target));
02267 return;
02268 }
02269 else if (string_prefix("sanity", action))
02270 {
02271 int *ai = (int *)MEMALLOC(mudstate.mail_db_top * sizeof(int));
02272 ISOUTOFMEMORY(ai);
02273 memset(ai, 0, mudstate.mail_db_top * sizeof(int));
02274
02275 DO_WHOLE_DB(thing)
02276 {
02277 MailList ml(thing);
02278 struct mail *mp;
02279 for (mp = ml.FirstItem(); !ml.IsEnd(); mp = ml.NextItem())
02280 {
02281 bool bGoodReference;
02282 if (0 <= mp->number && mp->number < mudstate.mail_db_top)
02283 {
02284 ai[mp->number]++;
02285 bGoodReference = true;
02286 }
02287 else
02288 {
02289 bGoodReference = false;
02290 }
02291 if (!Good_obj(mp->to))
02292 {
02293 if (bGoodReference)
02294 {
02295 notify(player, tprintf("Bad object #%d has mail.", mp->to));
02296 }
02297 else
02298 {
02299 notify(player, tprintf("Bad object #%d has mail which refers to a non-existent mailbag item.", mp->to));
02300 }
02301 }
02302 else if (!isPlayer(mp->to))
02303 {
02304 if (bGoodReference)
02305 {
02306 notify(player, tprintf("%s(#%d) has mail, but is not a player.",
02307 Name(mp->to), mp->to));
02308 }
02309 else
02310 {
02311 notify(player, tprintf("%s(#%d) is not a player, but has mail which refers to a non-existent mailbag item.",
02312 Name(mp->to), mp->to));
02313 }
02314 }
02315 else if (!bGoodReference)
02316 {
02317 notify(player, tprintf("%s(#%d) has mail which refers to a non-existent mailbag item.", Name(mp->to), mp->to));
02318 }
02319 }
02320 }
02321
02322
02323
02324 if (mail_list)
02325 {
02326 int i;
02327 int nCountHigher = 0;
02328 int nCountLower = 0;
02329 for (i = 0; i < mudstate.mail_db_top; i++)
02330 {
02331 if (mail_list[i].m_nRefs < ai[i])
02332 {
02333 nCountLower++;
02334 }
02335 else if (mail_list[i].m_nRefs > ai[i])
02336 {
02337 nCountHigher++;
02338 }
02339 }
02340 if (nCountLower)
02341 {
02342 notify(player, "Some mailbag items are referred to more often than the mailbag item indicates.");
02343 }
02344 if (nCountHigher)
02345 {
02346 notify(player, "Some mailbag items are referred to less often than the mailbag item indicates.");
02347 }
02348 }
02349 MEMFREE(ai);
02350 ai = NULL;
02351 notify(player, "Mail sanity check completed.");
02352 }
02353 else if (string_prefix("fix", action))
02354 {
02355
02356
02357 if (mail_list)
02358 {
02359 notify(player, tprintf("Re-counting mailbag reference counts."));
02360 int *ai = (int *)MEMALLOC(mudstate.mail_db_top * sizeof(int));
02361 ISOUTOFMEMORY(ai);
02362 memset(ai, 0, mudstate.mail_db_top * sizeof(int));
02363
02364 DO_WHOLE_DB(thing)
02365 {
02366 MailList ml(thing);
02367 struct mail *mp;
02368 for (mp = ml.FirstItem(); !ml.IsEnd(); mp = ml.NextItem())
02369 {
02370 if ( 0 <= mp->number
02371 && mp->number < mudstate.mail_db_top)
02372 {
02373 ai[mp->number]++;
02374 }
02375 else
02376 {
02377 mp->number = NOTHING;
02378 }
02379 }
02380 }
02381 int i;
02382 int nCountWrong = 0;
02383 for (i = 0; i < mudstate.mail_db_top; i++)
02384 {
02385 if (mail_list[i].m_nRefs != ai[i])
02386 {
02387 mail_list[i].m_nRefs = ai[i];
02388 nCountWrong++;
02389 }
02390 }
02391 if (nCountWrong)
02392 {
02393 notify(player, "Some reference counts were wrong [FIXED].");
02394 }
02395 MEMFREE(ai);
02396 ai = NULL;
02397 }
02398
02399 notify(player, tprintf("Removing @mail that is associated with non-players."));
02400
02401
02402
02403
02404 DO_WHOLE_DB(thing)
02405 {
02406 MailList ml(thing);
02407 struct mail *mp;
02408 for (mp = ml.FirstItem(); !ml.IsEnd(); mp = ml.NextItem())
02409 {
02410 if ( !Good_obj(mp->to)
02411 || !isPlayer(mp->to)
02412 || NOTHING == mp->number)
02413 {
02414
02415
02416 notify(player, tprintf("Fixing mail for #%d.", mp->to));
02417 ml.RemoveItem();
02418 }
02419 }
02420 }
02421 notify(player, "Mail sanity fix completed.");
02422 }
02423 else
02424 {
02425 notify(player, "That is not a debugging option.");
02426 return;
02427 }
02428 }
02429
02430 static void do_mail_stats(dbref player, char *name, int full)
02431 {
02432 dbref target, thing;
02433 int fc, fr, fu, tc, tr, tu, fchars, tchars, cchars, count;
02434 fc = fr = fu = tc = tr = tu = fchars = tchars = cchars = count = 0;
02435
02436
02437
02438 if ( !name
02439 || *name == '\0')
02440 {
02441 if (Wizard(player))
02442 {
02443 target = AMBIGUOUS;
02444 }
02445 else
02446 {
02447 target = player;
02448 }
02449 }
02450 else if (*name == NUMBER_TOKEN)
02451 {
02452 target = mux_atol(&name[1]);
02453 if (!Good_obj(target) || !isPlayer(target))
02454 {
02455 target = NOTHING;
02456 }
02457 }
02458 else if (!mux_stricmp(name, "me"))
02459 {
02460 target = player;
02461 }
02462 else
02463 {
02464 target = lookup_player(player, name, true);
02465 }
02466
02467 if (target == NOTHING)
02468 {
02469 init_match(player, name, NOTYPE);
02470 match_absolute();
02471 target = match_result();
02472 }
02473 if (target == NOTHING)
02474 {
02475 notify(player, tprintf("%s: No such player.", name));
02476 return;
02477 }
02478 if (!ExpMail(player) && (target != player))
02479 {
02480 notify(player, "The post office protects privacy!");
02481 return;
02482 }
02483
02484
02485
02486 if (!payfor(player, mudconf.searchcost))
02487 {
02488 notify(player, tprintf("Finding mail stats costs %d %s.",
02489 mudconf.searchcost,
02490 (mudconf.searchcost == 1) ? mudconf.one_coin : mudconf.many_coins));
02491 return;
02492 }
02493 if (AMBIGUOUS == target)
02494 {
02495
02496
02497 if (full == 0)
02498 {
02499 DO_WHOLE_DB(thing)
02500 {
02501 MailList ml(thing);
02502 for ((void)ml.FirstItem(); !ml.IsEnd(); (void)ml.NextItem())
02503 {
02504 count++;
02505 }
02506 }
02507 notify(player, tprintf("There are %d messages in the mail spool.", count));
02508 return;
02509 }
02510 else if (full == 1)
02511 {
02512 DO_WHOLE_DB(thing)
02513 {
02514 MailList ml(thing);
02515 struct mail *mp;
02516 for (mp = ml.FirstItem(); !ml.IsEnd(); mp = ml.NextItem())
02517 {
02518 if (Cleared(mp))
02519 {
02520 fc++;
02521 }
02522 else if (Read(mp))
02523 {
02524 fr++;
02525 }
02526 else
02527 {
02528 fu++;
02529 }
02530 }
02531 }
02532 notify(player,
02533 tprintf("MAIL: There are %d msgs in the mail spool, %d unread, %d cleared.",
02534 fc + fr + fu, fu, fc));
02535 return;
02536 }
02537 else
02538 {
02539 DO_WHOLE_DB(thing)
02540 {
02541 MailList ml(thing);
02542 struct mail *mp;
02543 for (mp = ml.FirstItem(); !ml.IsEnd(); mp = ml.NextItem())
02544 {
02545 if (Cleared(mp))
02546 {
02547 fc++;
02548 cchars += strlen(MessageFetch(mp->number));
02549 }
02550 else if (Read(mp))
02551 {
02552 fr++;
02553 fchars += strlen(MessageFetch(mp->number));
02554 }
02555 else
02556 {
02557 fu++;
02558 tchars += strlen(MessageFetch(mp->number));
02559 }
02560 }
02561 }
02562 notify(player, tprintf("MAIL: There are %d old msgs in the mail spool, totalling %d characters.", fr, fchars));
02563 notify(player, tprintf("MAIL: There are %d new msgs in the mail spool, totalling %d characters.", fu, tchars));
02564 notify(player, tprintf("MAIL: There are %d cleared msgs in the mail spool, totalling %d characters.", fc, cchars));
02565 return;
02566 }
02567 }
02568
02569
02570
02571 if (full == 0)
02572 {
02573
02574
02575 DO_WHOLE_DB(thing)
02576 {
02577 MailList ml(thing);
02578 struct mail *mp;
02579 for (mp = ml.FirstItem(); !ml.IsEnd(); mp = ml.NextItem())
02580 {
02581 if (mp->from == target)
02582 {
02583 fr++;
02584 }
02585 if (mp->to == target)
02586 {
02587 tr++;
02588 }
02589 }
02590 }
02591 notify(player, tprintf("%s sent %d messages.", Name(target), fr));
02592 notify(player, tprintf("%s has %d messages.", Name(target), tr));
02593 return;
02594 }
02595
02596
02597
02598 char last[50];
02599 DO_WHOLE_DB(thing)
02600 {
02601 MailList ml(thing);
02602 struct mail *mp;
02603 for (mp = ml.FirstItem(); !ml.IsEnd(); mp = ml.NextItem())
02604 {
02605 if (mp->from == target)
02606 {
02607 if (Cleared(mp))
02608 {
02609 fc++;
02610 }
02611 else if (Read(mp))
02612 {
02613 fr++;
02614 }
02615 else
02616 {
02617 fu++;
02618 }
02619 if (full == 2)
02620 {
02621 fchars += strlen(MessageFetch(mp->number));
02622 }
02623 }
02624 if (mp->to == target)
02625 {
02626 if (!tr && !tu)
02627 {
02628 strcpy(last, mp->time);
02629 }
02630 if (Cleared(mp))
02631 {
02632 tc++;
02633 }
02634 else if (Read(mp))
02635 {
02636 tr++;
02637 }
02638 else
02639 {
02640 tu++;
02641 }
02642 if (full == 2)
02643 {
02644 tchars += strlen(MessageFetch(mp->number));
02645 }
02646 }
02647 }
02648 }
02649
02650 notify(player, tprintf("Mail statistics for %s:", Name(target)));
02651
02652 if (full == 1)
02653 {
02654 notify(player, tprintf("%d messages sent, %d unread, %d cleared.",
02655 fc + fr + fu, fu, fc));
02656 notify(player, tprintf("%d messages received, %d unread, %d cleared.",
02657 tc + tr + tu, tu, tc));
02658 }
02659 else
02660 {
02661 notify(player,
02662 tprintf("%d messages sent, %d unread, %d cleared, totalling %d characters.",
02663 fc + fr + fu, fu, fc, fchars));
02664 notify(player,
02665 tprintf("%d messages received, %d unread, %d cleared, totalling %d characters.",
02666 tc + tr + tu, tu, tc, tchars));
02667 }
02668
02669 if (tc + tr + tu > 0)
02670 {
02671 notify(player, tprintf("Last is dated %s", last));
02672 }
02673 }
02674
02675
02676
02677
02678
02679 static void do_mail_stub(dbref player, char *arg1, char *arg2)
02680 {
02681 if (!arg1 || !*arg1)
02682 {
02683 if (arg2 && *arg2)
02684 {
02685 notify(player, "MAIL: Invalid mail command.");
02686 return;
02687 }
02688
02689
02690
02691 do_mail_list(player, arg1, true);
02692 return;
02693 }
02694
02695
02696
02697 if (!mux_stricmp(arg1, "purge"))
02698 {
02699 do_mail_purge(player);
02700 return;
02701 }
02702
02703
02704
02705 if (!mux_stricmp(arg1, "clear"))
02706 {
02707 do_mail_clear(player, arg2);
02708 return;
02709 }
02710 if (!mux_stricmp(arg1, "unclear"))
02711 {
02712 do_mail_unclear(player, arg2);
02713 return;
02714 }
02715 if (arg2 && *arg2)
02716 {
02717
02718
02719 do_expmail_start(player, arg1, arg2);
02720 return;
02721 }
02722 else
02723 {
02724
02725
02726 if ( mux_isdigit(*arg1)
02727 && !strchr(arg1, '-'))
02728 {
02729 do_mail_read(player, arg1);
02730 }
02731 else
02732 {
02733 do_mail_list(player, arg1, true);
02734 }
02735 return;
02736 }
02737 }
02738
02739 static void malias_write(FILE *fp)
02740 {
02741 int i, j;
02742 struct malias *m;
02743
02744 putref(fp, ma_top);
02745 for (i = 0; i < ma_top; i++)
02746 {
02747 m = malias[i];
02748 fprintf(fp, "%d %d\n", m->owner, m->numrecep);
02749 fprintf(fp, "N:%s\n", m->name);
02750 fprintf(fp, "D:%s\n", m->desc);
02751 for (j = 0; j < m->numrecep; j++)
02752 {
02753 putref(fp, m->list[j]);
02754 }
02755 }
02756 }
02757
02758 static void save_malias(FILE *fp)
02759 {
02760 fprintf(fp, "*** Begin MALIAS ***\n");
02761 malias_write(fp);
02762 }
02763
02764 int dump_mail(FILE *fp)
02765 {
02766 dbref thing;
02767 int count = 0, i;
02768
02769
02770
02771 fprintf(fp, "+V5\n");
02772 putref(fp, mudstate.mail_db_top);
02773 DO_WHOLE_DB(thing)
02774 {
02775 if (isPlayer(thing))
02776 {
02777 MailList ml(thing);
02778 struct mail *mp;
02779 for (mp = ml.FirstItem(); !ml.IsEnd(); mp = ml.NextItem())
02780 {
02781 putref(fp, mp->to);
02782 putref(fp, mp->from);
02783 putref(fp, mp->number);
02784 putstring(fp, mp->tolist);
02785 putstring(fp, mp->time);
02786 putstring(fp, mp->subject);
02787 putref(fp, mp->read);
02788 count++;
02789 }
02790 }
02791 }
02792
02793 fprintf(fp, "*** END OF DUMP ***\n");
02794
02795
02796
02797 for (i = 0; i < mudstate.mail_db_top; i++)
02798 {
02799 if (0 < mail_list[i].m_nRefs)
02800 {
02801 putref(fp, i);
02802 putstring(fp, MessageFetch(i));
02803 }
02804 }
02805 fprintf(fp, "+++ END OF DUMP +++\n");
02806 save_malias(fp);
02807
02808 return count;
02809 }
02810
02811 static void load_mail_V5(FILE *fp)
02812 {
02813 int mail_top = getref(fp);
02814 mail_db_grow(mail_top + 1);
02815
02816 char nbuf1[8];
02817 char *p = fgets(nbuf1, sizeof(nbuf1), fp);
02818 while (p && strncmp(nbuf1, "***", 3) != 0)
02819 {
02820 struct mail *mp = (struct mail *)MEMALLOC(sizeof(struct mail));
02821 ISOUTOFMEMORY(mp);
02822
02823 mp->to = mux_atol(nbuf1);
02824 mp->from = getref(fp);
02825
02826 mp->number = getref(fp);
02827 MessageReferenceInc(mp->number);
02828 mp->tolist = StringClone(getstring_noalloc(fp, true));
02829
02830 mp->time = StringClone(getstring_noalloc(fp, true));
02831 mp->subject = StringClone(getstring_noalloc(fp, true));
02832 mp->read = getref(fp);
02833
02834 MailList ml(mp->to);
02835 ml.AppendItem(mp);
02836
02837 p = fgets(nbuf1, sizeof(nbuf1), fp);
02838 }
02839
02840 p = fgets(nbuf1, sizeof(nbuf1), fp);
02841 while (p && strncmp(nbuf1, "+++", 3))
02842 {
02843 int number = mux_atol(nbuf1);
02844 new_mail_message(getstring_noalloc(fp, true), number);
02845 p = fgets(nbuf1, sizeof(nbuf1), fp);
02846 }
02847 }
02848
02849
02850
02851
02852
02853
02854 static char *MakeCanonicalMailAliasDesc
02855 (
02856 char *pMailAliasDesc,
02857 int *pnValidMailAliasDesc,
02858 bool *pbValidMailAliasDesc,
02859 int *pnVisualWidth
02860 )
02861 {
02862 if (!pMailAliasDesc)
02863 {
02864 return NULL;
02865 }
02866
02867
02868
02869 char *Buffer = RemoveSetOfCharacters(pMailAliasDesc, "\r\n\t");
02870
02871
02872
02873 *pnVisualWidth = 0;
02874 static char szFittedMailAliasDesc[SIZEOF_MALIASDESC];
02875 *pnValidMailAliasDesc = ANSI_TruncateToField
02876 ( Buffer,
02877 SIZEOF_MALIASDESC,
02878 szFittedMailAliasDesc,
02879 WIDTHOF_MALIASDESC,
02880 pnVisualWidth,
02881 ANSI_ENDGOAL_NORMAL
02882 );
02883 *pbValidMailAliasDesc = true;
02884 return szFittedMailAliasDesc;
02885 }
02886
02887 static void malias_read(FILE *fp)
02888 {
02889 int i, j;
02890
02891 i = getref(fp);
02892 if (i <= 0)
02893 {
02894 return;
02895 }
02896 char buffer[LBUF_SIZE];
02897 struct malias *m;
02898
02899 ma_size = ma_top = i;
02900
02901 malias = (struct malias **)MEMALLOC(sizeof(struct malias *) * ma_size);
02902 ISOUTOFMEMORY(malias);
02903
02904 for (i = 0; i < ma_top; i++)
02905 {
02906
02907
02908 if (!fgets(buffer, sizeof(buffer), fp))
02909 {
02910
02911
02912
02913 ma_top = i;
02914 return;
02915 }
02916
02917 m = (struct malias *)MEMALLOC(sizeof(struct malias));
02918 ISOUTOFMEMORY(m);
02919 malias[i] = m;
02920
02921 char *p = strchr(buffer, ' ');
02922 m->owner = m->numrecep = 0;
02923 if (p)
02924 {
02925 m->owner = mux_atol(buffer);
02926 m->numrecep = mux_atol(p+1);
02927 }
02928
02929
02930
02931 int nLen = GetLineTrunc(buffer, sizeof(buffer), fp);
02932 buffer[nLen-1] = '\0';
02933 int nMailAlias;
02934 bool bMailAlias;
02935 char *pMailAlias = MakeCanonicalMailAlias( buffer+2,
02936 &nMailAlias,
02937 &bMailAlias);
02938 if (bMailAlias)
02939 {
02940 m->name = StringCloneLen(pMailAlias, nMailAlias);
02941 }
02942 else
02943 {
02944 m->name = StringCloneLen("Invalid", 7);
02945 }
02946
02947
02948
02949 nLen = GetLineTrunc(buffer, sizeof(buffer), fp);
02950 int nMailAliasDesc;
02951 bool bMailAliasDesc;
02952 int nVisualWidth;
02953 char *pMailAliasDesc = MakeCanonicalMailAliasDesc( buffer+2,
02954 &nMailAliasDesc,
02955 &bMailAliasDesc,
02956 &nVisualWidth);
02957 if (bMailAliasDesc)
02958 {
02959 m->desc = StringCloneLen(pMailAliasDesc, nMailAliasDesc);
02960 m->desc_width = nVisualWidth;
02961 }
02962 else
02963 {
02964 m->desc = StringCloneLen("Invalid Desc", 12);
02965 m->desc_width = 12;
02966 }
02967
02968 if (m->numrecep > 0)
02969 {
02970 for (j = 0; j < m->numrecep; j++)
02971 {
02972 int k = getref(fp);
02973 if (j < MAX_MALIAS_MEMBERSHIP)
02974 {
02975 m->list[j] = k;
02976 }
02977 }
02978 }
02979 else
02980 {
02981 m->list[0] = 0;
02982 }
02983 }
02984 }
02985
02986 static void load_malias(FILE *fp)
02987 {
02988 char buffer[200];
02989
02990 getref(fp);
02991 if ( fscanf(fp, "*** Begin %s ***\n", buffer) == 1
02992 && !strcmp(buffer, "MALIAS"))
02993 {
02994 malias_read(fp);
02995 }
02996 else
02997 {
02998 Log.WriteString("ERROR: Couldn't find Begin MALIAS." ENDLINE);
02999 return;
03000 }
03001 }
03002
03003 void load_mail(FILE *fp)
03004 {
03005 char nbuf1[8];
03006
03007
03008
03009 if (!fgets(nbuf1, sizeof(nbuf1), fp))
03010 {
03011 return;
03012 }
03013 if (strncmp(nbuf1, "+V5", 3) == 0)
03014 {
03015 load_mail_V5(fp);
03016 }
03017 else
03018 {
03019 return;
03020 }
03021 load_malias(fp);
03022 }
03023
03024 void check_mail_expiration(void)
03025 {
03026
03027
03028 if (0 > mudconf.mail_expiration)
03029 {
03030 return;
03031 }
03032
03033 dbref thing;
03034 int expire_secs = mudconf.mail_expiration * 86400;
03035
03036 CLinearTimeAbsolute ltaNow;
03037 ltaNow.GetLocal();
03038
03039 CLinearTimeAbsolute ltaMail;
03040 DO_WHOLE_DB(thing)
03041 {
03042 MailList ml(thing);
03043 struct mail *mp;
03044 for (mp = ml.FirstItem(); !ml.IsEnd(); mp = ml.NextItem())
03045 {
03046 if (M_Safe(mp))
03047 {
03048 continue;
03049 }
03050
03051 const char *pMailTimeStr = mp->time;
03052 if (!ltaMail.SetString(pMailTimeStr))
03053 {
03054 continue;
03055 }
03056
03057 CLinearTimeDelta ltd(ltaMail, ltaNow);
03058 if (ltd.ReturnSeconds() <= expire_secs)
03059 {
03060 continue;
03061 }
03062
03063
03064
03065 ml.RemoveItem();
03066 }
03067 }
03068 }
03069
03070 void check_mail(dbref player, int folder, bool silent)
03071 {
03072
03073
03074 int rc;
03075 int uc;
03076 int cc;
03077 int gc;
03078
03079
03080
03081 count_mail(player, folder, &rc, &uc, &cc);
03082 urgent_mail(player, folder, &gc);
03083 #ifdef MAIL_ALL_FOLDERS
03084 notify(player,
03085 tprintf("MAIL: %d messages in folder %d [%s] (%d unread, %d cleared).\r\n",
03086 rc + uc, folder, get_folder_name(player, folder), uc, cc));
03087 #else // MAIL_ALL_FOLDERS
03088 if (rc + uc > 0)
03089 {
03090 notify(player, tprintf("MAIL: %d messages in folder %d [%s] (%d unread, %d cleared).", rc + uc, folder, get_folder_name(player, folder), uc, cc));
03091 }
03092 else if (!silent)
03093 {
03094 notify(player, tprintf("\r\nMAIL: You have no mail.\r\n"));
03095 }
03096 if (gc > 0)
03097 {
03098 notify(player, tprintf("URGENT MAIL: You have %d urgent messages in folder %d [%s].", gc, folder, get_folder_name(player, folder)));
03099 }
03100 #endif // MAIL_ALL_FOLDERS
03101 }
03102
03103 static void do_malias_send
03104 (
03105 dbref player,
03106 char *tolist,
03107 char *listto,
03108 char *subject,
03109 int number,
03110 mail_flag flags,
03111 bool silent
03112 )
03113 {
03114 int nResult;
03115 struct malias *m = get_malias(player, tolist, &nResult);
03116 if (nResult == GMA_INVALIDFORM)
03117 {
03118 notify(player, tprintf("MAIL: I can't figure out from '%s' who you want to mail to.", tolist));
03119 return;
03120 }
03121 else if (nResult == GMA_NOTFOUND)
03122 {
03123 notify(player, tprintf("MAIL: Alias '%s' not found.", tolist));
03124 return;
03125 }
03126
03127
03128
03129 dbref vic;
03130 int k;
03131 for (k = 0; k < m->numrecep; k++)
03132 {
03133 vic = m->list[k];
03134
03135 if (isPlayer(vic))
03136 {
03137 send_mail(player, m->list[k], listto, subject, number, flags, silent);
03138 }
03139 else
03140 {
03141
03142
03143 char *pMail = tprintf("Alias Error: Bad Player %d for %s", vic, tolist);
03144 int iMail = add_mail_message(player, pMail);
03145 if (iMail != NOTHING)
03146 {
03147 send_mail(GOD, GOD, listto, subject, iMail, 0, silent);
03148 MessageReferenceDec(iMail);
03149 }
03150 }
03151 }
03152 }
03153
03154 static void do_malias_create(dbref player, char *alias, char *tolist)
03155 {
03156 struct malias **nm;
03157 int nResult;
03158 get_malias(player, alias, &nResult);
03159
03160 if (nResult == GMA_INVALIDFORM)
03161 {
03162 notify(player, "MAIL: What alias do you want to create?.");
03163 return;
03164 }
03165 else if (nResult == GMA_FOUND)
03166 {
03167 notify(player, tprintf("MAIL: Mail Alias '%s' already exists.", alias));
03168 return;
03169 }
03170
03171 int i = 0;
03172 if (!ma_size)
03173 {
03174 ma_size = MA_INC;
03175 malias = (struct malias **)MEMALLOC(sizeof(struct malias *) * ma_size);
03176 ISOUTOFMEMORY(malias);
03177 }
03178 else if (ma_top >= ma_size)
03179 {
03180 ma_size += MA_INC;
03181 nm = (struct malias **)MEMALLOC(sizeof(struct malias *) * (ma_size));
03182 ISOUTOFMEMORY(nm);
03183
03184 for (i = 0; i < ma_top; i++)
03185 {
03186 nm[i] = malias[i];
03187 }
03188 MEMFREE(malias);
03189 malias = nm;
03190 }
03191 malias[ma_top] = (struct malias *)MEMALLOC(sizeof(struct malias));
03192 ISOUTOFMEMORY(malias[ma_top]);
03193
03194
03195
03196
03197 char *head = tolist;
03198 char *tail, spot;
03199 char *buff;
03200 dbref target;
03201 i = 0;
03202 while ( head
03203 && *head
03204 && i < (MAX_MALIAS_MEMBERSHIP - 1))
03205 {
03206 while (*head == ' ')
03207 {
03208 head++;
03209 }
03210 tail = head;
03211 while ( *tail
03212 && *tail != ' ')
03213 {
03214 if (*tail == '"')
03215 {
03216 head++;
03217 tail++;
03218 while ( *tail
03219 && *tail != '"')
03220 {
03221 tail++;
03222 }
03223 }
03224 if (*tail)
03225 {
03226 tail++;
03227 }
03228 }
03229 tail--;
03230 if (*tail != '"')
03231 {
03232 tail++;
03233 }
03234 spot = *tail;
03235 *tail = '\0';
03236
03237
03238
03239 if (!mux_stricmp(head, "me"))
03240 {
03241 target = player;
03242 }
03243 else if (*head == '#')
03244 {
03245 target = mux_atol(head + 1);
03246 }
03247 else
03248 {
03249 target = lookup_player(player, head, true);
03250 }
03251
03252 if ( !Good_obj(target)
03253 || !isPlayer(target))
03254 {
03255 notify(player, "MAIL: No such player.");
03256 }
03257 else
03258 {
03259 buff = unparse_object(player, target, false);
03260 notify(player, tprintf("MAIL: %s added to alias %s", buff, alias));
03261 malias[ma_top]->list[i] = target;
03262 i++;
03263 free_lbuf(buff);
03264 }
03265
03266
03267
03268 *tail = spot;
03269 head = tail;
03270 if (*head == '"')
03271 {
03272 head++;
03273 }
03274 }
03275 int nValidMailAlias;
03276 bool bValidMailAlias;
03277 char *pValidMailAlias = MakeCanonicalMailAlias
03278 ( alias+1,
03279 &nValidMailAlias,
03280 &bValidMailAlias
03281 );
03282
03283 if (!bValidMailAlias)
03284 {
03285 notify(player, "MAIL: Invalid mail alias.");
03286 return;
03287 }
03288
03289
03290
03291
03292
03293
03294 #if 0
03295 int nValidMailAliasDesc;
03296 bool bValidMailAliasDesc;
03297 char *pValidMailAliasDesc = MakeCanonicalMailAliasDesc
03298 ( alias+1,
03299 &nValidMailAliasDesc,
03300 &bValidMailAliasDesc
03301 );
03302
03303 if (!bValidMailAliasDesc)
03304 {
03305 notify(player, "MAIL: Invalid mail alias description.");
03306 break;
03307 }
03308 #else
03309 char *pValidMailAliasDesc = pValidMailAlias;
03310 int nValidMailAliasDesc = nValidMailAlias;
03311 #endif
03312
03313 malias[ma_top]->list[i] = NOTHING;
03314 malias[ma_top]->name = StringCloneLen(pValidMailAlias, nValidMailAlias);
03315 malias[ma_top]->numrecep = i;
03316 malias[ma_top]->owner = player;
03317 malias[ma_top]->desc = StringCloneLen(pValidMailAliasDesc, nValidMailAliasDesc);
03318 malias[ma_top]->desc_width = nValidMailAliasDesc;
03319 ma_top++;
03320
03321 notify(player, tprintf("MAIL: Alias set '%s' defined.", alias));
03322 }
03323
03324 static void do_malias_list(dbref player, char *alias)
03325 {
03326 int nResult;
03327 struct malias *m = get_malias(player, alias, &nResult);
03328 if (nResult == GMA_NOTFOUND)
03329 {
03330 notify(player, tprintf("MAIL: Alias '%s' not found.", alias));
03331 return;
03332 }
03333 if (nResult != GMA_FOUND)
03334 {
03335 return;
03336 }
03337 if (!ExpMail(player) && (player != m->owner) && !(God(m->owner)))
03338 {
03339 notify(player, "MAIL: Permission denied.");
03340 return;
03341 }
03342 char *buff = alloc_lbuf("do_malias_list");
03343 char *bp = buff;
03344
03345 safe_tprintf_str(buff, &bp, "MAIL: Alias *%s: ", m->name);
03346 for (int i = m->numrecep - 1; i > -1; i--)
03347 {
03348 const char *p = Name(m->list[i]);
03349 if (strchr(p, ' '))
03350 {
03351 safe_chr('"', buff, &bp);
03352 safe_str(p, buff, &bp);
03353 safe_chr('"', buff, &bp);
03354 }
03355 else
03356 {
03357 safe_str(p, buff, &bp);
03358 }
03359 safe_chr(' ', buff, &bp);
03360 }
03361 *bp = '\0';
03362
03363 notify(player, buff);
03364 free_lbuf(buff);
03365 }
03366
03367 static char *Spaces(unsigned int n)
03368 {
03369 static char buffer[42] = " ";
03370 static unsigned int nLast = 0;
03371 buffer[nLast] = ' ';
03372 if (n < sizeof(buffer)-1)
03373 {
03374 buffer[n] = '\0';
03375 nLast = n;
03376 }
03377 return buffer;
03378 }
03379
03380 static void do_malias_list_all(dbref player)
03381 {
03382 bool notified = false;
03383 for (int i = 0; i < ma_top; i++)
03384 {
03385 struct malias *m = malias[i];
03386 if ( m->owner == GOD
03387 || m->owner == player
03388 || God(player))
03389 {
03390 if (!notified)
03391 {
03392 notify(player, "Name Description Owner");
03393 notified = true;
03394 }
03395 char *pSpaces = Spaces(40 - m->desc_width);
03396 char *p = tprintf( "%-12s %s%s %-15.15s",
03397 m->name,
03398 m->desc,
03399 pSpaces,
03400 Name(m->owner));
03401 notify(player, p);
03402 }
03403 }
03404 notify(player, "***** End of Mail Aliases *****");
03405 }
03406
03407 static void do_malias_switch(dbref player, char *a1, char *a2)
03408 {
03409 if (a1 && *a1)
03410 {
03411 if (a2 && *a2)
03412 {
03413 do_malias_create(player, a1, a2);
03414 }
03415 else
03416 {
03417 do_malias_list(player, a1);
03418 }
03419 }
03420 else
03421 {
03422 do_malias_list_all(player);
03423 }
03424 }
03425
03426 static void do_mail_cc(dbref player, char *arg, bool bBlind)
03427 {
03428 if (!(Flags2(player) & PLAYER_MAILS))
03429 {
03430 notify(player, "MAIL: No mail message in progress.");
03431 return;
03432 }
03433 if (!arg || !*arg)
03434 {
03435 notify(player, "MAIL: I do not know whom you want to mail.");
03436 return;
03437 }
03438
03439 char *tolist = make_numlist(player, arg, bBlind);
03440 if (!tolist)
03441 {
03442 return;
03443 }
03444 char *fulllist = alloc_lbuf("do_mail_cc");
03445 char *bp = fulllist;
03446
03447 safe_str(tolist, fulllist, &bp);
03448 const char *pPlayerMailTo = atr_get_raw(player, A_MAILTO);
03449 if (pPlayerMailTo)
03450 {
03451 safe_chr(' ', fulllist, &bp);
03452 safe_str(pPlayerMailTo, fulllist, &bp);
03453 }
03454 *bp = '\0';
03455
03456 atr_add_raw(player, A_MAILTO, fulllist);
03457 char *names = make_namelist(player, fulllist);
03458 notify(player, tprintf("MAIL: You are sending mail to '%s'.", names));
03459 free_lbuf(names);
03460 free_lbuf(tolist);
03461 free_lbuf(fulllist);
03462 }
03463
03464 static void mail_to_list(dbref player, char *list, char *subject, char *message, int flags, bool silent)
03465 {
03466 if (!list)
03467 {
03468 return;
03469 }
03470 if (!*list)
03471 {
03472 free_lbuf(list);
03473 return;
03474 }
03475
03476
03477
03478
03479 char *tolist = alloc_lbuf("mail_to_list");
03480 char *p = tolist;
03481 char *tail;
03482 char *head = list;
03483 while (*head)
03484 {
03485 while (*head == ' ')
03486 {
03487 head++;
03488 }
03489
03490 tail = head;
03491 while ( *tail
03492 && *tail != ' ')
03493 {
03494 if (*tail == '"')
03495 {
03496 head++;
03497 tail++;
03498 while ( *tail
03499 && *tail != '"')
03500 {
03501 tail++;
03502 }
03503 }
03504 if (*tail)
03505 {
03506 tail++;
03507 }
03508 }
03509 tail--;
03510 if (*tail != '"')
03511 {
03512 tail++;
03513 }
03514
03515 if (*head != '!')
03516 {
03517 if (p != tolist)
03518 {
03519 *p++ = ' ';
03520 }
03521 memcpy(p, head, tail-head);
03522 p += tail-head;
03523 }
03524
03525
03526
03527 head = tail;
03528 if (*head == '"')
03529 {
03530 head++;
03531 }
03532 }
03533 *p = '\0';
03534
03535 int number = add_mail_message(player, message);
03536 if (number != NOTHING)
03537 {
03538 char spot;
03539 head = list;
03540 while (*head)
03541 {
03542 while (*head == ' ')
03543 {
03544 head++;
03545 }
03546
03547 tail = head;
03548 while ( *tail
03549 && *tail != ' ')
03550 {
03551 if (*tail == '"')
03552 {
03553 head++;
03554 tail++;
03555 while ( *tail
03556 && *tail != '"')
03557 {
03558 tail++;
03559 }
03560 }
03561 if (*tail)
03562 {
03563 tail++;
03564 }
03565 }
03566 tail--;
03567 if (*tail != '"')
03568 {
03569 tail++;
03570 }
03571 spot = *tail;
03572 *tail = '\0';
03573
03574 if (*head == '!')
03575 {
03576 head++;
03577 }
03578
03579 if (*head == '*')
03580 {
03581 do_malias_send(player, head, tolist, subject, number, flags, silent);
03582 }
03583 else
03584 {
03585 dbref target = mux_atol(head);
03586 if ( Good_obj(target)
03587 && isPlayer(target))
03588 {
03589 send_mail(player, target, tolist, subject, number, flags, silent);
03590 }
03591 }
03592
03593
03594
03595 *tail = spot;
03596 head = tail;
03597 if (*head == '"')
03598 {
03599 head++;
03600 }
03601 }
03602 MessageReferenceDec(number);
03603 }
03604 free_lbuf(tolist);
03605 free_lbuf(list);
03606 }
03607
03608 static void do_mail_quick(dbref player, char *arg1, char *arg2)
03609 {
03610 if (!arg1 || !*arg1)
03611 {
03612 notify(player, "MAIL: I don't know who you want to mail.");
03613 return;
03614 }
03615 if (!arg2 || !*arg2)
03616 {
03617 notify(player, "MAIL: No message.");
03618 return;
03619 }
03620 if (Flags2(player) & PLAYER_MAILS)
03621 {
03622 notify(player, "MAIL: Mail message already in progress.");
03623 return;
03624 }
03625 if ( !Wizard(player)
03626 && ThrottleMail(player))
03627 {
03628 notify(player, "MAIL: Too much @mail sent recently.");
03629 return;
03630 }
03631 char *bufDest = alloc_lbuf("do_mail_quick");
03632 char *bpSubject = bufDest;
03633
03634 strcpy(bpSubject, arg1);
03635 parse_to(&bpSubject, '/', 1);
03636
03637 if (!bpSubject)
03638 {
03639 notify(player, "MAIL: No subject.");
03640 free_lbuf(bufDest);
03641 return;
03642 }
03643
03644 mail_to_list(player, make_numlist(player, bufDest, false), bpSubject, arg2, 0, false);
03645 free_lbuf(bufDest);
03646 }
03647
03648 static void do_expmail_stop(dbref player, int flags)
03649 {
03650 if ((Flags2(player) & PLAYER_MAILS) != PLAYER_MAILS)
03651 {
03652 notify(player, "MAIL: No message started.");
03653 return;
03654 }
03655
03656 dbref aowner;
03657 dbref aflags;
03658 char *tolist = atr_get(player, A_MAILTO, & aowner, &aflags);
03659 if (*tolist == '\0')
03660 {
03661 notify(player, "MAIL: No recipients.");
03662 free_lbuf(tolist);
03663 }
03664 else
03665 {
03666 char *mailmsg = atr_get(player, A_MAILMSG, &aowner, &aflags);
03667 if (*mailmsg == '\0')
03668 {
03669 notify(player, "MAIL: The body of this message is empty. Use - to add to the message.");
03670 free_lbuf(tolist);
03671 }
03672 else
03673 {
03674 char *mailsub = atr_get(player, A_MAILSUB, &aowner, &aflags);
03675 char *mailflags = atr_get(player, A_MAILFLAGS, &aowner, &aflags);
03676 mail_to_list(player, tolist, mailsub, mailmsg, flags | mux_atol(mailflags), false);
03677 free_lbuf(mailflags);
03678 free_lbuf(mailsub);
03679
03680 Flags2(player) &= ~PLAYER_MAILS;
03681 }
03682 free_lbuf(mailmsg);
03683 }
03684 }
03685
03686 static void do_expmail_abort(dbref player)
03687 {
03688 Flags2(player) &= ~PLAYER_MAILS;
03689 notify(player, "MAIL: Message aborted.");
03690 }
03691
03692 void do_prepend(dbref executor, dbref caller, dbref enactor, int key, char *text)
03693 {
03694 UNUSED_PARAMETER(key);
03695
03696 if (!mudconf.have_mailer)
03697 {
03698 return;
03699 }
03700
03701 if (Flags2(executor) & PLAYER_MAILS)
03702 {
03703 if ( !text
03704 || !*text)
03705 {
03706 notify(executor, "No text prepended.");
03707 return;
03708 }
03709
03710 char *bufText = alloc_lbuf("do_prepend");
03711 char *bpText = bufText;
03712 char *strText = text+1;
03713 mux_exec(bufText, &bpText, executor, caller, enactor,
03714 EV_STRIP_CURLY | EV_FCHECK | EV_EVAL, &strText, (char **)NULL, 0);
03715 *bpText = '\0';
03716
03717 dbref aowner;
03718 int aflags;
03719
03720 char *oldmsg = atr_get(executor, A_MAILMSG, &aowner, &aflags);
03721 if (*oldmsg)
03722 {
03723 char *newmsg = alloc_lbuf("do_prepend");
03724 char *bp = newmsg;
03725 safe_str(bufText, newmsg, &bp);
03726 safe_chr(' ', newmsg, &bp);
03727 safe_str(oldmsg, newmsg, &bp);
03728 *bp = '\0';
03729 atr_add_raw(executor, A_MAILMSG, newmsg);
03730 free_lbuf(newmsg);
03731 }
03732 else
03733 {
03734 atr_add_raw(executor, A_MAILMSG, bufText);
03735 }
03736
03737 free_lbuf(bufText);
03738 free_lbuf(oldmsg);
03739 size_t nLen;
03740
03741 atr_get_raw_LEN(executor, A_MAILMSG, &nLen);
03742 notify(executor, tprintf("%d/%d characters prepended.", nLen, LBUF_SIZE-1));
03743 }
03744 else
03745 {
03746 notify(executor, "MAIL: No message in progress.");
03747 }
03748 }
03749
03750 void do_postpend(dbref executor, dbref caller, dbref enactor, int key, char *text)
03751 {
03752 UNUSED_PARAMETER(key);
03753
03754 if (!mudconf.have_mailer)
03755 {
03756 return;
03757 }
03758 if ( text[1] == '-'
03759 && text[2] == '\0')
03760 {
03761 do_expmail_stop(executor, 0);
03762 return;
03763 }
03764
03765 if (Flags2(executor) & PLAYER_MAILS)
03766 {
03767 if ( !text
03768 || !*text)
03769 {
03770 notify(executor, "No text added.");
03771 return;
03772 }
03773
03774 char *bufText = alloc_lbuf("do_prepend");
03775 char *bpText = bufText;
03776 char *strText = text+1;
03777 mux_exec(bufText, &bpText, executor, caller, enactor,
03778 EV_STRIP_CURLY | EV_FCHECK | EV_EVAL, &strText, (char **)NULL, 0);
03779 *bpText = '\0';
03780
03781 dbref aowner;
03782 int aflags;
03783
03784 char *oldmsg = atr_get(executor, A_MAILMSG, &aowner, &aflags);
03785 if (*oldmsg)
03786 {
03787 char *newmsg = alloc_lbuf("do_postpend");
03788 char *bp = newmsg;
03789 safe_str(oldmsg, newmsg, &bp);
03790 safe_chr(' ', newmsg, &bp);
03791 safe_str(bufText, newmsg, &bp);
03792 *bp = '\0';
03793 atr_add_raw(executor, A_MAILMSG, newmsg);
03794 free_lbuf(newmsg);
03795 }
03796 else
03797 {
03798 atr_add_raw(executor, A_MAILMSG, bufText);
03799 }
03800
03801 free_lbuf(bufText);
03802 free_lbuf(oldmsg);
03803 size_t nLen;
03804
03805 atr_get_raw_LEN(executor, A_MAILMSG, &nLen);
03806 notify(executor, tprintf("%d/%d characters added.", nLen, LBUF_SIZE-1));
03807 }
03808 else
03809 {
03810 notify(executor, "MAIL: No message in progress.");
03811 }
03812 }
03813
03814 static void do_edit_msg(dbref player, char *from, char *to)
03815 {
03816 if (Flags2(player) & PLAYER_MAILS)
03817 {
03818 dbref aowner;
03819 int aflags;
03820 char *msg = atr_get(player, A_MAILMSG, &aowner, &aflags);
03821 char *result = replace_string(from, to, msg);
03822 atr_add(player, A_MAILMSG, result, aowner, aflags);
03823 notify(player, "Text edited.");
03824 free_lbuf(result);
03825 free_lbuf(msg);
03826 }
03827 else
03828 {
03829 notify(player, "MAIL: No message in progress.");
03830 }
03831 }
03832
03833 static void do_mail_proof(dbref player)
03834 {
03835 if (!(Flags2(player) & PLAYER_MAILS))
03836 {
03837 notify(player, "MAIL: No message in progress.");
03838 return;
03839 }
03840
03841 dbref aowner;
03842 int aflags;
03843
03844 char *mailto = atr_get(player, A_MAILTO, &aowner, &aflags);
03845 char *mailmsg = atr_get(player, A_MAILMSG, &aowner, &aflags);
03846 char *names = make_namelist(player, mailto);
03847
03848 int iRealVisibleWidth;
03849 char szSubjectBuffer[MBUF_SIZE];
03850 ANSI_TruncateToField(atr_get_raw(player, A_MAILSUB),
03851 sizeof(szSubjectBuffer), szSubjectBuffer, 35,
03852 &iRealVisibleWidth, ANSI_ENDGOAL_NORMAL);
03853
03854 notify(player, DASH_LINE);
03855 notify(player, tprintf("From: %-*s Subject: %s\nTo: %s",
03856 PLAYER_NAME_LIMIT - 6, Name(player), szSubjectBuffer, names));
03857 notify(player, DASH_LINE);
03858 notify(player, mailmsg);
03859 notify(player, DASH_LINE);
03860 free_lbuf(mailmsg);
03861 free_lbuf(names);
03862 free_lbuf(mailto);
03863 }
03864
03865 static void do_malias_desc(dbref player, char *alias, char *desc)
03866 {
03867 int nResult;
03868 struct malias *m = get_malias(player, alias, &nResult);
03869 if (nResult == GMA_NOTFOUND)
03870 {
03871 notify(player, tprintf("MAIL: Alias '%s' not found.", alias));
03872 return;
03873 }
03874 if (nResult != GMA_FOUND)
03875 {
03876 return;
03877 }
03878 if ( m->owner != GOD
03879 || ExpMail(player))
03880 {
03881 int nValidMailAliasDesc;
03882 bool bValidMailAliasDesc;
03883 int nVisualWidth;
03884 char *pValidMailAliasDesc = MakeCanonicalMailAliasDesc
03885 ( desc,
03886 &nValidMailAliasDesc,
03887 &bValidMailAliasDesc,
03888 &nVisualWidth
03889 );
03890
03891 if (bValidMailAliasDesc)
03892 {
03893 MEMFREE(m->desc);
03894 m->desc = StringCloneLen(pValidMailAliasDesc, nValidMailAliasDesc);
03895 m->desc_width = nVisualWidth;
03896 notify(player, "MAIL: Description changed.");
03897 }
03898 else
03899 {
03900 notify(player, "MAIL: Description is not valid.");
03901 }
03902 }
03903 else
03904 {
03905 notify(player, "MAIL: Permission denied.");
03906 }
03907 }
03908
03909 static void do_malias_chown(dbref player, char *alias, char *owner)
03910 {
03911 if (!ExpMail(player))
03912 {
03913 notify(player, "MAIL: You cannot do that!");
03914 return;
03915 }
03916
03917 int nResult;
03918 struct malias *m = get_malias(player, alias, &nResult);
03919 if (nResult == GMA_NOTFOUND)
03920 {
03921 notify(player, tprintf("MAIL: Alias '%s' not found.", alias));
03922 return;
03923 }
03924 if (nResult != GMA_FOUND)
03925 {
03926 return;
03927 }
03928 dbref no = lookup_player(player, owner, true);
03929 if (no == NOTHING)
03930 {
03931 notify(player, "MAIL: I do not see that here.");
03932 return;
03933 }
03934 m->owner = no;
03935 notify(player, "MAIL: Owner changed for alias.");
03936 }
03937
03938 static void do_malias_add(dbref player, char *alias, char *person)
03939 {
03940 int nResult;
03941 struct malias *m = get_malias(player, alias, &nResult);
03942 if (nResult == GMA_NOTFOUND)
03943 {
03944 notify(player, tprintf("MAIL: Alias '%s' not found.", alias));
03945 return;
03946 }
03947 else if (nResult != GMA_FOUND)
03948 {
03949 return;
03950 }
03951 dbref thing = NOTHING;
03952 if (*person == '#')
03953 {
03954 thing = parse_dbref(person + 1);
03955 if (!isPlayer(thing))
03956 {
03957 notify(player, "MAIL: Only players may be added.");
03958 return;
03959 }
03960 }
03961
03962 if (thing == NOTHING)
03963 {
03964 thing = lookup_player(player, person, true);
03965 }
03966
03967 if (thing == NOTHING)
03968 {
03969 notify(player, "MAIL: I do not see that person here.");
03970 return;
03971 }
03972
03973 if ((m->owner == GOD) && !ExpMail(player))
03974 {
03975 notify(player, "MAIL: Permission denied.");
03976 return;
03977 }
03978 int i;
03979 for (i = 0; i < m->numrecep; i++)
03980 {
03981 if (m->list[i] == thing)
03982 {
03983 notify(player, "MAIL: That person is already on the list.");
03984 return;
03985 }
03986 }
03987
03988 if (i >= (MAX_MALIAS_MEMBERSHIP - 1))
03989 {
03990 notify(player, "MAIL: The list is full.");
03991 return;
03992 }
03993
03994 m->list[m->numrecep] = thing;
03995 m->numrecep = m->numrecep + 1;
03996 notify(player, tprintf("MAIL: %s added to %s", Name(thing), m->name));
03997 }
03998
03999 static void do_malias_remove(dbref player, char *alias, char *person)
04000 {
04001 int nResult;
04002 struct malias *m = get_malias(player, alias, &nResult);
04003 if (nResult == GMA_NOTFOUND)
04004 {
04005 notify(player, tprintf("MAIL: Alias '%s' not found.", alias));
04006 return;
04007 }
04008 if (nResult != GMA_FOUND)
04009 {
04010 return;
04011 }
04012 if ((m->owner == GOD) && !ExpMail(player))
04013 {
04014 notify(player, "MAIL: Permission denied.");
04015 return;
04016 }
04017
04018 dbref thing = NOTHING;
04019 if (*person == '#')
04020 {
04021 thing = parse_dbref(person + 1);
04022 }
04023 if (thing == NOTHING)
04024 {
04025 thing = lookup_player(player, person, true);
04026 }
04027 if (thing == NOTHING)
04028 {
04029 notify(player, "MAIL: I do not see that person here.");
04030 return;
04031 }
04032
04033 bool ok = false;
04034 for (int i = 0; i < m->numrecep; i++)
04035 {
04036 if (ok)
04037 {
04038 m->list[i] = m->list[i + 1];
04039 }
04040 else if (m->list[i] == thing)
04041 {
04042 m->list[i] = m->list[i + 1];
04043 ok = true;
04044 }
04045 }
04046
04047 if (ok)
04048 {
04049 m->numrecep--;
04050 notify(player, tprintf("MAIL: %s removed from alias %s.",
04051 Name(thing), alias));
04052 }
04053 else
04054 {
04055 notify(player, tprintf("MAIL: %s is not a member of alias %s.",
04056 Name(thing), alias));
04057 }
04058 }
04059
04060 static void do_malias_rename(dbref player, char *alias, char *newname)
04061 {
04062 int nResult;
04063 struct malias *m = get_malias(player, newname, &nResult);
04064 if (nResult == GMA_FOUND)
04065 {
04066 notify(player, "MAIL: That name already exists!");
04067 return;
04068 }
04069 if (nResult != GMA_NOTFOUND)
04070 {
04071 return;
04072 }
04073 m = get_malias(player, alias, &nResult);
04074 if (nResult == GMA_NOTFOUND)
04075 {
04076 notify(player, "MAIL: I cannot find that alias!");
04077 return;
04078 }
04079 if (nResult != GMA_FOUND)
04080 {
04081 return;
04082 }
04083 if (!ExpMail(player) && !(m->owner == player))
04084 {
04085 notify(player, "MAIL: Permission denied.");
04086 return;
04087 }
04088
04089 int nValidMailAlias;
04090 bool bValidMailAlias;
04091 char *pValidMailAlias = MakeCanonicalMailAlias
04092 ( newname+1,
04093 &nValidMailAlias,
04094 &bValidMailAlias
04095 );
04096 if (bValidMailAlias)
04097 {
04098 MEMFREE(m->name);
04099 m->name = StringCloneLen(pValidMailAlias, nValidMailAlias);
04100 notify(player, "MAIL: Mailing Alias renamed.");
04101 }
04102 else
04103 {
04104 notify(player, "MAIL: Alias is not valid.");
04105 }
04106 }
04107
04108 static void do_malias_delete(dbref player, char *alias)
04109 {
04110 int nResult;
04111 struct malias *m = get_malias(player, alias, &nResult);
04112 if (nResult == GMA_NOTFOUND)
04113 {
04114 notify(player, tprintf("MAIL: Alias '%s' not found.", alias));
04115 return;
04116 }
04117 if (nResult != GMA_FOUND)
04118 {
04119 return;
04120 }
04121 bool done = false;
04122 for (int i = 0; i < ma_top; i++)
04123 {
04124 if (done)
04125 {
04126 malias[i] = malias[i + 1];
04127 }
04128 else
04129 {
04130 if ((m->owner == player) || ExpMail(player))
04131 {
04132 if (m == malias[i])
04133 {
04134 done = true;
04135 notify(player, "MAIL: Alias Deleted.");
04136 malias[i] = malias[i + 1];
04137 }
04138 }
04139 }
04140 }
04141
04142 if (!done)
04143 {
04144 notify(player, tprintf("MAIL: Alias '%s' not found.", alias));
04145 }
04146 else
04147 {
04148 ma_top--;
04149 }
04150 }
04151
04152 static void do_malias_adminlist(dbref player)
04153 {
04154 if (!ExpMail(player))
04155 {
04156 do_malias_list_all(player);
04157 return;
04158 }
04159 notify(player,
04160 "Num Name Description Owner");
04161
04162 struct malias *m;
04163 int i;
04164
04165 for (i = 0; i < ma_top; i++)
04166 {
04167 m = malias[i];
04168 char *pSpaces = Spaces(40 - m->desc_width);
04169 notify(player, tprintf("%-4d %-12s %s%s %-15.15s",
04170 i, m->name, m->desc, pSpaces,
04171 Name(m->owner)));
04172 }
04173
04174 notify(player, "***** End of Mail Aliases *****");
04175 }
04176
04177 static void do_malias_status(dbref player)
04178 {
04179 if (!ExpMail(player))
04180 {
04181 notify(player, "MAIL: Permission denied.");
04182 }
04183 else
04184 {
04185 notify(player, tprintf("MAIL: Number of mail aliases defined: %d", ma_top));
04186 notify(player, tprintf("MAIL: Allocated slots %d", ma_size));
04187 }
04188 }
04189
04190 static void malias_cleanup1(struct malias *m, dbref target)
04191 {
04192 int count = 0;
04193 dbref j;
04194 for (int i = 0; i < m->numrecep; i++)
04195 {
04196 j = m->list[i];
04197 if ( !Good_obj(j)
04198 || j == target)
04199 {
04200 count++;
04201 }
04202 if (count)
04203 {
04204 m->list[i] = m->list[i + count];
04205 }
04206 }
04207 m->numrecep -= count;
04208 }
04209
04210 void malias_cleanup(dbref player)
04211 {
04212 for (int i = 0; i < ma_top; i++)
04213 {
04214 malias_cleanup1(malias[i], player);
04215 }
04216 }
04217
04218 static void do_mail_retract1(dbref player, char *name, char *msglist)
04219 {
04220 dbref target = lookup_player(player, name, true);
04221 if (target == NOTHING)
04222 {
04223 notify(player, "MAIL: No such player.");
04224 return;
04225 }
04226 struct mail_selector ms;
04227 if (!parse_msglist(msglist, &ms, target))
04228 {
04229 return;
04230 }
04231
04232 int i = 0, j = 0;
04233 MailList ml(target);
04234 struct mail *mp;
04235 for (mp = ml.FirstItem(); !ml.IsEnd(); mp = ml.NextItem())
04236 {
04237 if (mp->from == player)
04238 {
04239 i++;
04240 if (mail_match(mp, ms, i))
04241 {
04242 j++;
04243 if (Unread(mp))
04244 {
04245 ml.RemoveItem();
04246 notify(player, "MAIL: Mail retracted.");
04247 }
04248 else
04249 {
04250 notify(player, "MAIL: That message has been read.");
04251 }
04252 }
04253 }
04254 }
04255
04256 if (!j)
04257 {
04258
04259
04260 notify(player, "MAIL: No matching messages.");
04261 }
04262 }
04263
04264 static void do_mail_retract(dbref player, char *name, char *msglist)
04265 {
04266 if (*name == '*')
04267 {
04268 int pnResult;
04269 struct malias *m = get_malias(player, name, &pnResult);
04270 if (pnResult == GMA_NOTFOUND)
04271 {
04272 notify(player, tprintf("MAIL: Mail alias %s not found.", name));
04273 return;
04274 }
04275 if (pnResult == GMA_FOUND)
04276 {
04277 for (int i = 0; i < m->numrecep; i++)
04278 {
04279 do_mail_retract1(player, tprintf("#%d", m->list[i]), msglist);
04280 }
04281 }
04282 }
04283 else
04284 {
04285 do_mail_retract1(player, name, msglist);
04286 }
04287 }
04288
04289 void do_malias
04290 (
04291 dbref executor,
04292 dbref caller,
04293 dbref enactor,
04294 int key,
04295 int nargs,
04296 char *arg1,
04297 char *arg2
04298 )
04299 {
04300 UNUSED_PARAMETER(caller);
04301 UNUSED_PARAMETER(enactor);
04302 UNUSED_PARAMETER(nargs);
04303
04304 if (!mudconf.have_mailer)
04305 {
04306 notify(executor, "Mailer is disabled.");
04307 return;
04308 }
04309 switch (key)
04310 {
04311 case 0:
04312 do_malias_switch(executor, arg1, arg2);
04313 break;
04314 case MALIAS_DESC:
04315 do_malias_desc(executor, arg1, arg2);
04316 break;
04317 case MALIAS_CHOWN:
04318 do_malias_chown(executor, arg1, arg2);
04319 break;
04320 case MALIAS_ADD:
04321 do_malias_add(executor, arg1, arg2);
04322 break;
04323 case MALIAS_REMOVE:
04324 do_malias_remove(executor, arg1, arg2);
04325 break;
04326 case MALIAS_DELETE:
04327 do_malias_delete(executor, arg1);
04328 break;
04329 case MALIAS_RENAME:
04330 do_malias_rename(executor, arg1, arg2);
04331 break;
04332 case 7:
04333
04334 break;
04335 case MALIAS_LIST:
04336 do_malias_adminlist(executor);
04337 break;
04338 case MALIAS_STATUS:
04339 do_malias_status(executor);
04340 }
04341 }
04342
04343 void do_mail
04344 (
04345 dbref executor,
04346 dbref caller,
04347 dbref enactor,
04348 int key,
04349 int nargs,
04350 char *arg1,
04351 char *arg2
04352 )
04353 {
04354 UNUSED_PARAMETER(caller);
04355 UNUSED_PARAMETER(enactor);
04356 UNUSED_PARAMETER(nargs);
04357
04358 if (!mudconf.have_mailer)
04359 {
04360 notify(executor, "Mailer is disabled.");
04361 return;
04362 }
04363
04364
04365
04366 if ( (key & ~MAIL_QUOTE) != MAIL_QUICK
04367 && !isPlayer(executor))
04368 {
04369 return;
04370 }
04371
04372 switch (key & ~MAIL_QUOTE)
04373 {
04374 case 0:
04375 do_mail_stub(executor, arg1, arg2);
04376 break;
04377 case MAIL_STATS:
04378 do_mail_stats(executor, arg1, 0);
04379 break;
04380 case MAIL_DSTATS:
04381 do_mail_stats(executor, arg1, 1);
04382 break;
04383 case MAIL_FSTATS:
04384 do_mail_stats(executor, arg1, 2);
04385 break;
04386 case MAIL_DEBUG:
04387 do_mail_debug(executor, arg1, arg2);
04388 break;
04389 case MAIL_NUKE:
04390 do_mail_nuke(executor);
04391 break;
04392 case MAIL_FOLDER:
04393 do_mail_change_folder(executor, arg1, arg2);
04394 break;
04395 case MAIL_LIST:
04396 do_mail_list(executor, arg1, false);
04397 break;
04398 case MAIL_READ:
04399 do_mail_read(executor, arg1);
04400 break;
04401 case MAIL_CLEAR:
04402 do_mail_clear(executor, arg1);
04403 break;
04404 case MAIL_UNCLEAR:
04405 do_mail_unclear(executor, arg1);
04406 break;
04407 case MAIL_PURGE:
04408 do_mail_purge(executor);
04409 break;
04410 case MAIL_FILE:
04411 do_mail_file(executor, arg1, arg2);
04412 break;
04413 case MAIL_TAG:
04414 do_mail_tag(executor, arg1);
04415 break;
04416 case MAIL_UNTAG:
04417 do_mail_untag(executor, arg1);
04418 break;
04419 case MAIL_FORWARD:
04420 do_mail_fwd(executor, arg1, arg2);
04421 break;
04422 case MAIL_REPLY:
04423 do_mail_reply(executor, arg1, false, key);
04424 break;
04425 case MAIL_REPLYALL:
04426 do_mail_reply(executor, arg1, true, key);
04427 break;
04428 case MAIL_SEND:
04429 do_expmail_stop(executor, 0);
04430 break;
04431 case MAIL_EDIT:
04432 do_edit_msg(executor, arg1, arg2);
04433 break;
04434 case MAIL_URGENT:
04435 do_expmail_stop(executor, M_URGENT);
04436 break;
04437 case MAIL_ALIAS:
04438 do_malias_create(executor, arg1, arg2);
04439 break;
04440 case MAIL_ALIST:
04441 do_malias_list_all(executor);
04442 break;
04443 case MAIL_PROOF:
04444 do_mail_proof(executor);
04445 break;
04446 case MAIL_ABORT:
04447 do_expmail_abort(executor);
04448 break;
04449 case MAIL_QUICK:
04450 do_mail_quick(executor, arg1, arg2);
04451 break;
04452 case MAIL_REVIEW:
04453 do_mail_review(executor, arg1, arg2);
04454 break;
04455 case MAIL_RETRACT:
04456 do_mail_retract(executor, arg1, arg2);
04457 break;
04458 case MAIL_CC:
04459 do_mail_cc(executor, arg1, false);
04460 break;
04461 case MAIL_SAFE:
04462 do_mail_safe(executor, arg1);
04463 break;
04464 case MAIL_BCC:
04465 do_mail_cc(executor, arg1, true);
04466 break;
04467 }
04468 }
04469
04470 struct mail *MailList::FirstItem(void)
04471 {
04472 m_miHead = (struct mail *)hashfindLEN(&m_player, sizeof(m_player), &mudstate.mail_htab);
04473 m_mi = m_miHead;
04474 m_bRemoved = false;
04475 return m_mi;
04476 }
04477
04478 struct mail *MailList::NextItem(void)
04479 {
04480 if (!m_bRemoved)
04481 {
04482 if (NULL != m_mi)
04483 {
04484 m_mi = m_mi->next;
04485 if (m_mi == m_miHead)
04486 {
04487 m_mi = NULL;
04488 }
04489 }
04490 }
04491 m_bRemoved = false;
04492 return m_mi;
04493 }
04494
04495 bool MailList::IsEnd(void)
04496 {
04497 return (NULL == m_mi);
04498 }
04499
04500 MailList::MailList(dbref player)
04501 {
04502 m_mi = NULL;
04503 m_miHead = NULL;
04504 m_player = player;
04505 m_bRemoved = false;
04506 }
04507
04508 void MailList::RemoveItem(void)
04509 {
04510 if ( NULL == m_mi
04511 || NOTHING == m_player)
04512 {
04513 return;
04514 }
04515
04516 struct mail *miNext = m_mi->next;
04517
04518 if (m_mi == m_miHead)
04519 {
04520 if (miNext == m_miHead)
04521 {
04522 hashdeleteLEN(&m_player, sizeof(m_player), &mudstate.mail_htab);
04523 miNext = NULL;
04524 }
04525 else
04526 {
04527 hashreplLEN(&m_player, sizeof(m_player), miNext, &mudstate.mail_htab);
04528 }
04529 m_miHead = miNext;
04530 }
04531
04532
04533
04534 m_mi->prev->next = m_mi->next;
04535 m_mi->next->prev = m_mi->prev;
04536
04537 m_mi->next = NULL;
04538 m_mi->prev = NULL;
04539 MessageReferenceDec(m_mi->number);
04540 MEMFREE(m_mi->subject);
04541 m_mi->subject = NULL;
04542 MEMFREE(m_mi->time);
04543 m_mi->time = NULL;
04544 MEMFREE(m_mi->tolist);
04545 m_mi->tolist = NULL;
04546 MEMFREE(m_mi);
04547
04548 m_mi = miNext;
04549 m_bRemoved = true;
04550 }
04551
04552 void MailList::AppendItem(struct mail *miNew)
04553 {
04554 struct mail *miHead = (struct mail *)
04555 hashfindLEN(&m_player, sizeof(m_player), &mudstate.mail_htab);
04556
04557 if (miHead)
04558 {
04559
04560
04561 struct mail *miEnd = miHead->prev;
04562
04563 miNew->next = miHead;
04564 miNew->prev = miEnd;
04565
04566 miHead->prev = miNew;
04567 miEnd->next = miNew;
04568 }
04569 else
04570 {
04571 hashaddLEN(&m_player, sizeof(m_player), miNew, &mudstate.mail_htab);
04572 miNew->next = miNew;
04573 miNew->prev = miNew;
04574 }
04575 }
04576
04577 void MailList::RemoveAll(void)
04578 {
04579 struct mail *miHead = (struct mail *)
04580 hashfindLEN(&m_player, sizeof(m_player), &mudstate.mail_htab);
04581
04582 if (NULL != miHead)
04583 {
04584 hashdeleteLEN(&m_player, sizeof(m_player), &mudstate.mail_htab);
04585 }
04586
04587 struct mail *mi;
04588 struct mail *miNext;
04589 for (mi = miHead; NULL != mi; mi = miNext)
04590 {
04591 if (mi == miHead)
04592 {
04593 miNext = NULL;
04594 }
04595 else
04596 {
04597 miNext = mi->next;
04598 }
04599 MessageReferenceDec(mi->number);
04600 MEMFREE(mi->subject);
04601 mi->subject = NULL;
04602 MEMFREE(mi->tolist);
04603 mi->tolist = NULL;
04604 MEMFREE(mi->time);
04605 mi->time = NULL;
04606 MEMFREE(mi);
04607 }
04608 m_mi = NULL;
04609 }