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