Mail Distribution Center #38

Parent #1Owner #29Flags readSource hellcore/hellcore.db

Aliases: Mail Distribution Center, Postmaster

55 verbs · 15 properties · 0 children

Verbs

VerbSpecFlagsDefinerLines
resolve_addrthis none thisrxd#3860
sends_tothis none thisrxd#3814
send_messagethis none thisrxd#3823
raw_sendthis none thisrxd#3861
mail_forward mail_notifythis none thisrxd#386
touchthis none thisrxd#3819
look_selfthis none thisrxd#384
acceptablethis none thisrxd#383
check_namesthis none thisrxd#3829
matchthis none thisrxd#3838
match_recipientthis none thisrxd#3816
match_failedthis none thisrxd#3818
make_messagethis none thisrxd#3842
namethis none thisrxd#3812
name_listthis none thisrxd#381
parse_address_fieldthis none thisrxd#3811
display_seq_fullthis none thisrxd#3822
display_seq_headersthis none thisrxd#3830
rm_message_seqthis none thisrxd#3829
undo_rmmthis none thisrxd#3828
expunge_rmm list_rmmthis none thisrxd#3844
renumberthis none thisrxd#3845
msg_summary_linethis none thisrxd#3820
parse_message_seqthis none thisrxd#38165
_parse_from _parse_tothis none thisrxd#3824
_parse_datethis none thisrxd#3829
new_message_numthis none thisrxd#3812
length_all_msgsthis none thisrxd#382
length_date_lethis none thisrxd#3821
length_date_gtthis none thisrxd#3822
length_num_lethis none thisrxd#383
exists_num_eqthis none thisrxd#383
from_msg_seqthis none thisrxd#3823
%from_msg_seqthis none thisrxd#3825
to_msg_seqthis none thisrxd#3824
%to_msg_seqthis none thisrxd#3825
subject_msg_seqthis none thisrxd#3819
body_msg_seqthis none thisrxd#3824
messages_in_seqthis none thisrxd#389
__convert_newthis none thisrxd#3846
to_textthis none thisrxd#384
is_readable_by is_writable_by is_usable_bythis none thisrxd#389
reserved_patternthis none thisrxd#3810
is_recipientthis none thisrxd#381
keep_message_seqthis none thisrxd#3823
kept_msg_seq unkept_msg_seqthis none thisrxd#3812
msg_seq_to_msg_num_stringthis none thisrxd#383
msg_seq_to_msg_num_listthis none thisrxd#383
send_log_messagethis none thisrxd#3813
parse_misc_headersthis none thisrxd#3829
resend_messagethis none thisrxd#3819
init_for_corethis none thisrx#386
display_message_improvedthis none thisrxd#3863
mail_name_forthis none thisrxd#3824
parse_new_mailspecthis none thisrxd#3845

Properties

PropertyDefinerFlagsOwnerValue
options#38rc#29
list of 11{"include", "noinclude", "all", "sender", "nosubject", "expert", "enter", "sticky", "@mail", "manymsgs", "replyto"}
reserved_patterns#38r#29{}
player_expire_time#38rc#292592000
player_default_@mail#38rc#29"last:15"
max_mail_notify#38rc#2915
aliases#1rc#29{"Mail Distribution Center", "Postmaster"}
description#1rc#29
list of 5{"This is the database of mailing-list/mail-folder objects.", "The basic procedure for creating a new list/folder is to create a child of $mail_recipient (Generic Mail Recipient) assign it a suitable name&aliases, set a suitable .mail_forward/.mail_notify (or create suitable :mail_forward() and :mail_notify() verbs) and then teleport it here.", "", "Avaliable aliases:", ""}
object_size#1r#29{55073, 1298433815}
hidden_verbs#1rc#29<clear>
phelp_msg#1rc#29<clear>
weight#1rc#29<clear>
owner_verbs#1rc#29<clear>
plural_name#1rc#29<clear>
client_image#1rc#29<clear>
listening#1rc#29<clear>

Ancestry

Ancestors (nearest first): #1 root

Children: none

Call graph

calls n38_0 #38:resolve_addr n38_0->n38_0 n45_5 #45:isa n38_0->n45_5 n107_43 #107:tell n38_0->n107_43 n20_6 #20:english_list n38_0->n20_6 n38_4 #38:mail_forward n38_0->n38_4 n47_19 #47:iassoc_suspended n38_0->n47_19 n45_2 #45:has_verb n38_4->n45_2 n38_1 #38:sends_to n38_1->n38_4 n38_1->n38_1 n48_8 #48:suspend_if_needed n38_1->n48_8 n38_2 #38:send_message n38_12 #38:make_message n38_2->n38_12 n38_3 #38:raw_send n38_2->n38_3 n38_14 #38:name_list n38_12->n38_14 n20_77 #20:escape n38_12->n20_77 n38_13 #38:name n38_12->n38_13 n20_1 #20:left n38_12->n20_1 n122_8 #122:strip n38_12->n122_8 n38_3->n38_0 n17_37 #17:random_wizard n38_3->n17_37 n38_5 #38:touch n38_3->n38_5 n6_9 #6:notify n38_3->n6_9 n47_18 #47:iassoc n38_3->n47_18 n45_3 #45:has_callable_verb n38_3->n45_3 n38_5->n38_4 n38_5->n48_8 n38_5->n38_5 n45_6 #45:ancestors n38_5->n45_6 n38_6 #38:look_self n1_11 #1:tell_lines n38_6->n1_11 n38_7 #38:acceptable n38_8 #38:check_names n38_7->n38_8 n38_8->n107_43 n38_42 #38:reserved_pattern n38_8->n38_42 n38_9 #38:match n38_8->n38_9 n38_9->n48_8 n38_9->n45_6 n38_9->n38_42 n20_16 #20:literal_object n38_9->n20_16 n38_10 #38:match_recipient n38_10->n38_9 n20_20 #20:match_player n38_10->n20_20 n38_11 #38:match_failed n38_11->n107_43 n38_11->n20_6 n30_2 #30:find_all n38_11->n30_2 n38_14->n20_6 n38_13->n45_3 n1_30 #1:name n38_13->n1_30 n38_16 #38:display_seq_full n38_16->n107_43 n6_54 #6:check_pref n38_16->n6_54 n38_52 #38:display_message_improved n38_16->n38_52 n38_52->n48_8 n38_52->n6_9 n38_52->n38_13 n38_52->n20_1 n38_52->n122_8 n20_0 #20:space n38_52->n20_0 n38_17 #38:display_seq_headers n38_17->n107_43 n38_17->n20_1 n27_18 #27:contract n38_17->n27_18 n27_2 #27:complement n38_17->n27_2 n6_12 #6:linelen n38_17->n6_12 n20_2 #20:right n38_17->n20_2 n38_17->n20_0 n38_18 #38:rm_message_seq n38_18->n107_43 n38_18->n48_8 n38_18->n45_3 n38_18->n27_18 n48_7 #48:running_out_of_time n38_18->n48_7 n27_20 #27:intersection n38_18->n27_20 n27_4 #27:tostr n38_18->n27_4

Showing 48 of 102 verbs; 54 not shown.

Source

resolve_addr

Spec this none thisFlags rxdOwner #29Definer #38

Referenced by

Source

1"resolve(name,from,seen,prevrcpts,prevnotifs) => {rcpts,notifs} or E_INVARG";
2"resolve(list,from,seen,prevrcpts,prevnotifs) => {bogus,rcpts,notifs}";
3"Given either an address (i.e., objectid) or a list of such, traces down all .mail_forward lists and .mail_notify to determine where a message should actually go and who should be told about it.  Both forms take previous lists of recipients/notifications and add only those addresses that weren't there before.  `seen' is the stack of addresses we are currently resolving (for detecting loops).  The first form returns E_INVARG if `name' is invalid.  The second form returns all invalid addresses in the `bogus' list but still does the appropriate search on the remaining addresses.";
4{recip, from, ?seen = {}, ?prevrcpts = {}, ?prevnotifs = {}} = args;
5sofar = {prevrcpts, prevnotifs};
6if (typeof(recip) == LIST)
7bogus = {};
8for r in (recip)
9result = this:resolve_addr(r, from, seen, @sofar);
10if (result)
11sofar = result;
12else
13bogus = setadd(bogus, r);
14endif
15endfor
16return {bogus, @sofar};
17else
18fwd = include_recip = 0;
19if ((recip == $nothing) || (recip in seen))
20return sofar;
21elseif ((!valid(recip)) || ((!(is_player(recip) || $object_utils:isa(recip, $mail_recipient))) || (typeof(fwd = recip:mail_forward(from)) != LIST)))
22"recip is a non-player non-mailing-list/folder or forwarding is screwed.";
23if (typeof(fwd) == STR)
24player:tell(fwd);
25endif
26return E_INVARG;
27elseif (is_player(recip) && `recip:refuses_action(from, "mail") ! E_VERBNF')
28player:tell(recip:mail_refused_msg());
29return E_INVARG;
30elseif (fwd)
31if (r = recip in fwd)
32include_recip = 1;
33fwd = listdelete(fwd, r);
34endif
35result = this:resolve_addr(fwd, recip, setadd(seen, recip), @sofar);
36if (bogus = result[1])
37player:tell(recip.name, "(", recip, ")'s .mail_forward list includes the following bogus entr", (length(bogus) > 1) ? "ies:  " | "y:  ", $string_utils:english_list(bogus));
38endif
39sofar = result[2..3];
40else
41include_recip = 1;
42endif
43if ((ticks_left() < 1000) || (seconds_left() < 2))
44suspend(0);
45endif
46biffs = sofar[2];
47for n in (this:mail_notify(recip, from))
48if (valid(n))
49if (i = $list_utils:iassoc_suspended(n, biffs))
50biffs[i] = setadd(biffs[i], recip);
51else
52biffs = {{n, recip}, @biffs};
53endif
54endif
55if ((ticks_left() < 1000) || (seconds_left() < 2))
56suspend(0);
57endif
58endfor
59return {include_recip ? setadd(sofar[1], recip) | sofar[1], biffs};
60endif

sends_to

Spec this none thisFlags rxdOwner #29Definer #38

Referenced by

Source

1"sends_to(from,addr,rcpt[,seen]) ==> true iff mail sent to addr passes through rcpt.";
2{from, addr, rcpt, ?seen = {}} = args;
3if (addr == rcpt)
4return 1;
5elseif (!(addr in seen))
6seen = {@seen, addr};
7for a in ((typeof(fwd = this:mail_forward(addr, @from ? {} | {from})) == LIST) ? fwd | {})
8if (this:sends_to(addr, a, rcpt, seen))
9return 1;
10endif
11$command_utils:suspend_if_needed(0);
12endfor
13endif
14return 0;

send_message

Spec this none thisFlags rxdOwner #29Definer #38

Referenced by

Source

1"send_message(from,rcpt-list,hdrs,msg) -- formats and sends a mail message.  hders is either the text of the subject line, or a {subject,{reply-to,...}} list.";
2"Return E_PERM if from isn't owned by the caller.";
3"Return {0, @invalid_rcpts} if rcpt-list contains any invalid addresses.  No mail is sent in this case.";
4"Return {1, @actual_rcpts} if successful.";
5{from, to, orig_hdrs, msg} = args;
6"...";
7"... remove bogus Resent-To/Resent-By headers...";
8"...";
9if ((typeof(orig_hdrs) == LIST) && (length(orig_hdrs) > 2))
10hdrs = orig_hdrs[1..2];
11orig_hdrs[1..2] = {};
12strip = {"Resent-To", "Resent-By"};
13for h in (orig_hdrs)
14(h[1] in strip) || (hdrs = {@hdrs, h});
15endfor
16else
17hdrs = orig_hdrs;
18endif
19"...";
20"... send it...";
21"...";
22text = $mail_agent:make_message(from, to, hdrs, msg);
23return this:raw_send(text, to, from);

raw_send

Spec this none thisFlags rxdOwner #361Definer #38

Referenced by

Source

1"Copied from Mail Distribution Center (#6418):raw_send by Nosredna (#2487) Mon Feb 24 10:46:26 1997 PST";
2"WIZARDLY";
3"raw_send(text,rcpts,sender) -- does the actual sending of a message.  Assumes that text has already been formatted correctly.  Decides who to send it to and who wants to be notified about it and does so.";
4"Return {E_PERM} if the caller is not entitled to use this verb.";
5"Return {0, @invalid_rcpts} if rcpts contains any invalid addresses.  No mail is sent in this case.";
6"Return {1, @actual_rcpts} if successful.";
7{text, rcpts, from} = args;
8if (typeof(rcpts) != LIST)
9rcpts = {rcpts};
10endif
11if (!(caller in {$mail_agent, $mail_editor}))
12return {E_PERM};
13elseif (bogus = (resolve = this:resolve_addr(rcpts, from))[1])
14return {0, bogus};
15else
16set_task_perms($wiz_utils:random_wizard());
17this:touch(rcpts);
18actual_rcpts = resolve[2];
19biffs = resolve[3];
20results = {};
21for recip in (actual_rcpts)
22if ((ticks_left() < 10000) || (seconds_left() < 2))
23player:notify(tostr("...", recip));
24suspend(1);
25endif
26if (typeof(e = recip:receive_message(text, from)) in {ERR, STR})
27"...receive_message bombed...";
28player:notify(tostr(recip, ":receive_message:  ", e));
29e = 0;
30elseif ((!is_player(recip)) || (!e))
31"...not a player or receive_message isn't giving out the message number";
32"...no need to force a notification...";
33elseif (i = $list_utils:iassoc(recip, biffs))
34"...player-recipient was already getting a notification...";
35"...make sure notification includes a mention of him/her/itself.";
36if (!(recip in listdelete(biffs[i], 1)))
37biffs[i][2..1] = {recip};
38endif
39else
40"...player-recipient wasn't originally being notified at all...";
41biffs = {{recip, recip}, @biffs};
42endif
43results = {@results, e};
44endfor
45"The following is because the scheduler can BITE ME. --Nosredna";
46fork (0)
47for b in (biffs)
48if ((ticks_left() < 10000) || (seconds_left() < 2))
49suspend(1);
50endif
51if ($object_utils:has_callable_verb(b[1], "notify_mail"))
52mnums = {};
53for r in (listdelete(b, 1))
54mnums = {@mnums, (rn = r in actual_rcpts) && results[rn]};
55endfor
56b[1]:notify_mail(from, listdelete(b, 1), mnums);
57endif
58endfor
59endfork
60return {1, @actual_rcpts};
61endif

mail_forward mail_notify

Spec this none thisFlags rxdOwner #29Definer #38

Referenced by

Source

1who = args[1];
2if ($object_utils:has_verb(who, verb))
3return who:(verb)(@listdelete(args, 1));
4else
5return {};
6endif

touch

Spec this none thisFlags rxdOwner #29Definer #38

Referenced by

Source

1"touch(name or list,seen) => does .last_used_time = time() if we haven't already touched this in the last hour";
2{recip, ?seen = {}} = args;
3if (typeof(recip) == LIST)
4for r in (recip)
5result = this:touch(r, seen);
6$command_utils:suspend_if_needed(0);
7endfor
8else
9if (((!valid(recip)) || (recip in seen)) || ((!is_player(recip)) && (!($mail_recipient in $object_utils:ancestors(recip)))))
10"recip is neither a player nor a mailing list/folder";
11else
12if (fwd = this:mail_forward(recip))
13this:touch(fwd, {@seen, recip});
14endif
15if (!is_player(recip))
16recip.last_used_time = time();
17endif
18endif
19endif

look_self

Spec this none thisFlags rxdOwner #29Definer #38

Referenced by

none

Source

1player:tell_lines(this.description);
2for c in (this.contents)
3c:look_self();
4endfor

acceptable

Spec this none thisFlags rxdOwner #29Definer #38

Referenced by

none

Source

1"Only allow mailing lists/folders in here and only if their names aren't already taken.";
2what = args[1];
3return is_a(what, $mail_recipient) && this:check_names(@what.aliases);

check_names

Spec this none thisFlags rxdOwner #29Definer #38

Referenced by

Source

1"...make sure the list has at least one usable name.";
2"...make sure none of the aliases are already taken.";
3ok = 0;
4for a in (args)
5sub1 = strsub(a, "_", "-");
6sub2 = strsub(a, "-", "_");
7if (sub1 == sub2)
8check = 0;
9else
10check = 1;
11endif
12if (index(a, " "))
13elseif (rp = $mail_agent:reserved_pattern(a))
14player:tell("Mailing list name \"", a, "\" uses a reserved pattern: ", rp[1]);
15return 0;
16elseif (valid(p = $mail_agent:match(a, #-1)) && (a in p.aliases))
17player:tell("Mailing list name \"", a, "\" in use on ", p.name, "(", p, ")");
18return 0;
19elseif ((check && valid(p = $mail_agent:match(sub1, #-1))) && (sub1 in p.aliases))
20player:tell("Mailing list name \"", sub1, "\" in use on ", p.name, "(", p, ")");
21return 0;
22elseif ((check && valid(p = $mail_agent:match(sub2, #-1))) && (sub2 in p.aliases))
23player:tell("Mailing list name \"", sub2, "\" in use on ", p.name, "(", p, ")");
24return 0;
25else
26ok = 1;
27endif
28endfor
29return ok;

match

Spec this none thisFlags rxdOwner #29Definer #38

Referenced by

Source

1":match(string) => mailing list object in here that matches string.";
2":match(string,player) => similar but also matches against player's private mailing lists (as kept in .mail_lists).";
3if (!(string = args[1]))
4return $nothing;
5elseif (string[1] == "*")
6string = string[2..$];
7endif
8if (valid(o = $string_utils:literal_object(string)) && ($mail_recipient in $object_utils:ancestors(o)))
9return o;
10elseif (rp = this:reserved_pattern(string))
11return rp[2]:match_mail_recipient(string);
12else
13if (valid(who = {@args, player}[2]) && (typeof(use = `who.mail_lists ! E_PROPNF, E_PERM') == LIST))
14use = {@this.contents, @use};
15else
16use = this.contents;
17endif
18partial = 1;
19string = strsub(string, "_", "-");
20for l in (use)
21if (string in l.aliases)
22return l;
23endif
24if (partial != $ambiguous_match)
25for a in (l.aliases)
26if ((index(a, string) == 1) && (!index(a, " ")))
27if (partial)
28partial = l;
29elseif (partial != l)
30partial = $ambiguous_match;
31endif
32endif
33$command_utils:suspend_if_needed(2);
34endfor
35endif
36endfor
37return partial && $failed_match;
38endif

match_recipient

Spec this none thisFlags rxdOwner #29Definer #38

Referenced by

Source

1":match_recipient(string[,meobj]) => $player or $mail_recipient object that matches string.  Optional second argument (defaults to player) is returned in the case string==\"me\" and is also used to obtain a list of private $mail_recipients to match against.";
2{string, ?me = player} = args;
3if (valid(me) && ($failed_match != (o = me:my_match_recipient(string))))
4return o;
5elseif (!string)
6return $nothing;
7elseif ((string[1] == "*") && (string != "*"))
8return this:match(@args);
9elseif (string[1] == "`")
10args[1][1..1] = "";
11return $string_utils:match_player(@args);
12elseif (valid(o = $string_utils:match_player(@args)) || (o == $ambiguous_match))
13return o;
14else
15return this:match(@args);
16endif

match_failed

Spec this none thisFlags rxdOwner #29Definer #38

Referenced by

Source

1{match_result, string, ?cmd_id = ""} = args;
2cmd_id = cmd_id || "";
3if (match_result == $nothing)
4player:tell(cmd_id, "You must specify a valid mail recipient.");
5elseif (match_result == $failed_match)
6player:tell(cmd_id, "There is no mail recipient called \"", string, "\".");
7elseif (match_result == $ambiguous_match)
8if (nostar = ((index(string, "*") != 1) && player.programmer) && (lst = $player_db:find_all(string)))
9player:tell(cmd_id, "\"", string, "\" could refer to ", (length(lst) > 20) ? tostr("any of ", length(lst), " players") | $string_utils:english_list($list_utils:map_arg(2, $string_utils, "pronoun_sub", "%n (%#)", lst), "no one", " or "), ".");
10else
11player:tell(cmd_id, "I don't know which \"", nostar ? "*" | "", string, "\" you mean.");
12endif
13elseif (!valid(match_result))
14player:tell(cmd_id, match_result, " does not exist.");
15else
16return 0;
17endif
18return 1;

make_message

Spec this none thisFlags rxdOwner #29Definer #38

Referenced by

Source

1":make_message(sender,recipients,subject/replyto/additional-headers,body)";
2" => message in the form as it will get sent.";
3{from, recips, hdrs, body} = args;
4try
5fromowner = from.owner;
6except (E_INVIND)
7raise(E_PERM);
8endtry
9fromline = this:name_list(from);
10if (typeof(recips) != LIST)
11recips = {recips};
12endif
13recips = this:name_list(@recips);
14others = {};
15replyto = 0;
16if (typeof(hdrs) != LIST)
17hdrs = {hdrs};
18endif
19subj = $su:escape(hdrs[1]);
20if (!valid(from))
21others = {"Probable-Sender:   " + this:name(fromowner)};
22"  others = {'Possible-Sender:   ' + this:name(player)}";
23"  if (caller_perms() != player)";
24"    others = {@others, 'Possible-Sender:   ' + this:name(caller_perms())}";
25"  endif";
26endif
27replyto = {@hdrs, 0}[2] && this:name_list(@hdrs[2]);
28if (length(hdrs) > 2)
29hdrs[1..2] = {};
30for h in (hdrs)
31if (match(h[1], "[a-z1-9-]+"))
32others = {@others, $su:escape($su:left(h[1] + ": ", 15) + h[2])};
33endif
34endfor
35endif
36if (typeof(body) != LIST)
37body = body ? {body} | {};
38endif
39for i in [1..length(body)]
40body[i] = $su:escape($ansi:strip(body[i]));
41endfor
42return {time(), fromline, recips, subj || " ", @replyto ? {"Reply-to: " + replyto} | {}, @others, "", @body};

name

Spec this none thisFlags rxdOwner #29Definer #38

Referenced by

Source

1if (!args)
2return pass(@args);
3endif
4what = args[1];
5if (!valid(what))
6name = "???";
7elseif ((!is_player(what)) && $object_utils:has_callable_verb(what, "mail_name"))
8name = what:mail_name();
9else
10name = what.name;
11endif
12return tostr(name, " (", what, ")");

name_list

Spec this none thisFlags rxdOwner #29Definer #38

Referenced by

Source

1return $string_utils:english_list($list_utils:map_arg(this, "name", args), "no one");

parse_address_field

Spec this none thisFlags rxdOwner #29Definer #38

Referenced by

Source

1":parse_address_field(string) => list of objects";
2"This is the standard routine for parsing address lists that appear in From:, To: and Reply-To: lines";
3objects = {};
4string = args[1];
5while (e = index(string, ")"))
6if ((s = rindex(string[1..e], "(#")) && (#0 != (o = toobj(string[s + 2..e - 1]))))
7objects = {@objects, o};
8endif
9string = string[e + 1..$];
10endwhile
11return objects;

display_seq_full

Spec this none thisFlags rxdOwner #361Definer #38

Referenced by

none

Source

1":display_seq_full(msg_seq[,preamble]) => {cur, last-read-date}";
2"This is the default message display routine.";
3"Prints entire messages on folder (caller) to player.  msg_seq is the handle returned by :parse_message_seq(...) and indicates which messages should be printed.  preamble, if given will precede the output of the message itself, in which case the message number will be substituted for \"%d\".  Returns the number of the final message in the sequence (which can be then used as the new current message number).";
4set_task_perms(caller_perms());
5{msg_seq, ?preamble = ""} = args;
6cur = date = 0;
7for x in (msgs = caller:messages_in_seq(msg_seq))
8cur = x[1];
9date = x[2][1];
10if (!player:check_pref("oldmail"))
11this:display_message_improved(cur, caller, @x[2]);
12else
13player:display_message(preamble ? strsub(preamble, "%d", tostr(cur)) | {}, caller:msg_full_text(@x[2]));
14endif
15if ((ticks_left() < 500) || (seconds_left() < 2))
16suspend(0);
17endif
18endfor
19if (cur)
20player:tell("");
21endif
22return {cur, date};

display_seq_headers

Spec this none thisFlags rxdOwner #361Definer #38

Referenced by

none

Source

1":display_seq_headers(msg_seq[,cur[,last_read_date]])";
2"This is the default header display routine.";
3"Prints a list of headers of messages on caller to player.  msg_seq is the handle returned by caller:parse_message_seq(...).  cur is the player's current message.  last_read_date is the date of the last of the already-read messages.";
4set_task_perms(caller_perms());
5{msg_seq, ?cur = 0, ?last_old = $maxint, ?show_end = 1} = args;
6keep_seq = {@$seq_utils:contract(caller:kept_msg_seq(), $seq_utils:complement(msg_seq, 1, caller:length_all_msgs())), $maxint};
7k = 1;
8mcount = 0;
9width = player:linelen() || 79;
10for x in (msgs = caller:messages_in_seq(msg_seq))
11if (keep_seq[k] <= (mcount = mcount + 1))
12k = k + 1;
13endif
14annot = ((d = x[2][1]) > last_old) ? "+" | ((k % 2) ? " " | "=");
15yield;
16summary = caller:msg_summary_line(@x[2]);
17yield;
18if (typeof(summary) != LIST)
19summary = {summary};
20endif
21prefix = tostr($string_utils:right(x[1], 4, (cur == x[1]) ? ">" | " "), ":", annot, " ");
22player:tell($su:left(prefix + summary[1], -width));
23prefix = $su:space(length(prefix));
24for l in (summary[2..$])
25player:tell($su:left(prefix + l, -width));
26yield;
27endfor
28yield;
29endfor
30show_end && player:tell("----+");

rm_message_seq

Spec this none thisFlags rxdOwner #361Definer #38

Referenced by

none

Source

1":rm_message_seq(msg_seq)  removes the given sequence of from folder (caller)";
2"...removed messages are saved in .messages_going for possible restoration.";
3set_task_perms(caller_perms());
4old = caller.messages;
5new = save = nums = {};
6next = 1;
7for i in [1..length(seq = args[1]) / 2]
8if ($command_utils:running_out_of_time())
9player:tell("... rmm ", old[next][1] - 1);
10suspend(0);
11endif
12start = seq[(2 * i) - 1];
13new = {@new, @old[next..start - 1]};
14save = {@save, {start - next, old[start..(next = seq[2 * i]) - 1]}};
15nums = {@nums, old[start][1], old[next - 1][1] + 1};
16endfor
17new = {@new, @old[next..$]};
18$command_utils:suspend_if_needed(0, "... rmm ...");
19save_kept = $seq_utils:intersection(caller.messages_kept, seq);
20$command_utils:suspend_if_needed(0, "... rmm ...");
21new_kept = $seq_utils:contract(caller.messages_kept, seq);
22$command_utils:suspend_if_needed(0, "... rmm ...");
23caller.messages_going = save_kept ? {save_kept, save} | save;
24caller.messages = new;
25caller.messages_kept = new_kept;
26if ($object_utils:has_callable_verb(caller, "_fix_last_msg_date"))
27caller:_fix_last_msg_date();
28endif
29return $seq_utils:tostr(nums);

undo_rmm

Spec this none thisFlags rxdOwner #361Definer #38

Referenced by

none

Source

1":undo_rmm()  restores previously deleted messages in .messages_going to .messages.";
2set_task_perms(caller_perms());
3old = caller.messages;
4going = caller.messages_going;
5new = seq = {};
6last = 0;
7next = 1;
8"there are two possible formats here:";
9"OLD: {{n,msgs},{n,msgs},...}";
10"NEW: {kept_seq, {{n,msgs},{n,msgs},...}}";
11if (going && ((!going[1]) || (typeof(going[1][2]) == INT)))
12kept = going[1];
13going = going[2];
14else
15kept = {};
16endif
17for s in (going)
18new = {@new, @old[last + 1..last + s[1]], @s[2]};
19last = last + s[1];
20seq = {@seq, next + s[1], next = length(new) + 1};
21endfor
22caller.messages = {@new, @old[last + 1..$]};
23caller.messages_going = {};
24caller.messages_kept = $seq_utils:union(kept, $seq_utils:expand(caller.messages_kept, seq));
25if ($object_utils:has_callable_verb(caller, "_fix_last_msg_date"))
26caller:_fix_last_msg_date();
27endif
28return seq;

expunge_rmm list_rmm

Spec this none thisFlags rxdOwner #361Definer #38

Referenced by

none

Source

1":list_rmm()    displays contents of .messages_going.";
2":expunge_rmm() destroys contents of .messages_going once and for all.";
3"... both return the number of messages in .messages_going.";
4set_task_perms(caller_perms());
5cmg = caller.messages_going;
6if (cmg && ((!cmg[1]) || (typeof(cmg[1][2]) == INT)))
7kept = cmg[1];
8cmg = cmg[2];
9else
10kept = {};
11endif
12if (verb == "expunge_rmm")
13caller.messages_going = {};
14count = 0;
15for s in (cmg)
16count = count + length(s[2]);
17endfor
18return count;
19elseif (!cmg)
20return 0;
21else
22msgs = seq = {};
23next = 1;
24for s in (cmg)
25msgs = {@msgs, @s[2]};
26seq = {@seq, next = next + s[1], next = next + length(s[2])};
27endfor
28kept = {@$seq_utils:contract(kept, $seq_utils:complement(seq, 1, $seq_utils:last(seq))), $maxint};
29k = 1;
30mcount = 0;
31for x in (msgs)
32if (kept[k] <= (mcount = mcount + 1))
33k = k + 1;
34endif
35player:tell($string_utils:right(x[1], 4), ":", (k % 2) ? "  " | "= ", caller:msg_summary_line(@x[2]));
36if ((ticks_left() < 500) || (seconds_left() < 2))
37suspend(0);
38endif
39endfor
40if (msgs)
41player:tell("----+");
42endif
43return length(msgs);
44endif

renumber

Spec this none thisFlags rxdOwner #361Definer #38

Referenced by

none

Source

1":renumber([cur]) -- assumes caller is a $mail_recipient or a $player.";
2"...renumbers caller.messages, doing a suspend() if necessary.";
3"...returns {number of messages,new cur}.";
4set_task_perms(caller_perms());
5{?cur = 0} = args;
6caller.messages_going = {};
7"... blow away @rmm'ed messages since there's no way to tell what their new numbers should be...";
8msgs = caller.messages;
9if (cur)
10cur = $list_utils:iassoc_sorted(cur, msgs);
11endif
12while (1)
13"...find first out-of-sequence message...";
14l = 0;
15r = (len = length(msgs)) + 1;
16while ((r - 1) > l)
17if (msgs[i = (r + l) / 2][1] > i)
18r = i;
19else
20l = i;
21endif
22endwhile
23"... r == first out-of-sequence, l == last in-sequence, l+1 == r ...";
24if (l >= len)
25return {l, cur};
26endif
27"...renumber as many messages as we have time for...";
28chunk = {};
29while (((r <= len) && (ticks_left() > 3000)) && (seconds_left() > 2))
30for x in (msgs[r..min(r + 9, len)])
31chunk = {@chunk, {r, x[2]}};
32r = r + 1;
33endfor
34endwhile
35caller.messages = {@msgs[1..l], @chunk, @msgs[r..len]};
36if (chunk)
37player:tell("...(renumbering ", l + 1, " -- ", r - 1, ")");
38suspend(0);
39else
40player:tell("You lose.  This message collection is just too big.");
41return;
42endif
43"... have to be careful since new mail may be received at this point...";
44msgs = caller.messages;
45endwhile

msg_summary_line

Spec this none thisFlags rxdOwner #29Definer #38

Referenced by

Source

1":msg_summary_line(@msg) => date/from/subject as a single string.";
2body = ("" in {@args, ""}) + 1;
3if ((length(args) > body) && (!args[body]))
4body = body + 1;
5endif
6if ((body > length(args)) || (!(subject = args[body])))
7subject = "(no text)";
8endif
9if (args[1] < (time() - 31536000))
10c = player:ctime(args[1]);
11date = c[5..11] + c[21..25];
12else
13date = player:ctime(args[1])[5..16];
14endif
15from = args[2];
16from_obj = from[rindex(from, " ") + 2..$ - 1];
17if (args[4] != " ")
18subject = args[4];
19endif
20return tostr(date, "   ", $string_utils:left(from, 20), "   ", subject);

parse_message_seq

Spec this none thisFlags rxdOwner #361Definer #38

Referenced by

none

Source

1"parse_message_seq(strings,cur[,last_old])";
2"This is the default <message-sequence> parsing routine for those mail commands that refer to sequences of messages (@mail, @read,...) on a folder.";
3"  caller (the folder) is assumed to be a $mail_recipient or a player.";
4"  strings is the <message-sequence> portion of the arg list.";
5"  cur is the number of the player's current message for this folder.";
6"Returns a string error message if the parse fails, otherwise";
7"returns a list {msg_seq, @unused_strings}, where";
8"   msg_seq is a handle understood by caller:display_seq_full/headers(), and ";
9"   unused_strings is the list of remaining uninterpreted strings";
10set_task_perms(caller_perms());
11{strings, ?cur = 0, ?last_old = 0} = args;
12if (!(nummsgs = caller:length_all_msgs()))
13return "%f %<has> no messages.";
14elseif (typeof(strings) != LIST)
15strings = {strings};
16endif
17seq = result = {};
18mode = #0;
19"... changes to 0 if we start seeing message numbers, to 1 if we see masks...";
20keywords = ":from:%from:to:%to:subject:body:before:after:since:until:first:last:kept:unkept";
21keyalist = {{1, "from"}, {6, "%from"}, {12, "to"}, {15, "%to"}, {19, "subject"}, {27, "body"}, {32, "before"}, {39, "after"}, {45, "since"}, {51, "until"}, {57, "first"}, {63, "last"}, {68, "kept"}, {73, "unkept"}};
22strnum = 0;
23for string in (strings)
24strnum = strnum + 1;
25$command_utils:suspend_if_needed(0);
26if (string && ((c = index(string, ":")) && ((k = index(keywords, ":" + string[1..c - 1])) && (k == rindex(keywords, ":" + string[1..c - 1])))))
27"...we have a mask to apply...";
28keywd = $list_utils:assoc(k, keyalist)[2];
29if (mode == #0)
30seq = {1, nummsgs + 1};
31endif
32mode = 1;
33if (k <= 27)
34"...from, subject, to, body...";
35pattern = string[c + 1..$];
36if (keywd in {"subject", "body"})
37elseif (keywd[1] == "%")
38pattern = $string_utils:explode(pattern, "|");
39else
40pattern = this:((keywd == "to") ? "_parse_to" | "_parse_from")(pattern);
41if (typeof(pattern) == STR)
42return pattern;
43endif
44endif
45seq = caller:(keywd + "_msg_seq")(pattern, seq);
46if (typeof(seq) == STR)
47if (strnum == 1)
48return seq;
49else
50seq = {};
51endif
52endif
53elseif (k <= 51)
54"...before, since, after, until...";
55if (typeof(date = this:_parse_date(string[c + 1..$])) != INT)
56return tostr("Bad date `", string, "':  ", date);
57endif
58s = caller:length_date_le((keywd in {"before", "since"}) ? date - 1 | (date + 86399));
59if (keywd in {"before", "until"})
60seq = $seq_utils:remove(seq, s + 1, nummsgs);
61else
62seq = $seq_utils:remove(seq, 1, s);
63endif
64elseif (k <= 63)
65"...first, last...";
66if (n = toint(string[c + 1..$]))
67seq = $seq_utils:(keywd + "n")(seq, n);
68else
69return tostr("Bad number in `", string, "'");
70endif
71else
72"...kept, unkept...";
73if (c < length(string))
74return tostr("Unexpected junk after `", keywd, ":'");
75elseif ((!(seq = caller:(keywd + "_msg_seq")(seq))) && (strnum == 1))
76return tostr("%f %<has> no ", keywd, " messages.");
77endif
78endif
79else
80"...continue building the present sequence...";
81if (mode)
82seq && (result = $seq_utils:union(result, seq));
83seq = {};
84endif
85mode = 0;
86if (!string)
87"...default case for @read: get the current message but skip to the next one if it's not there...";
88if (cur)
89i = min(caller:length_num_le(cur - 1) + 1, nummsgs);
90seq = $seq_utils:add(seq, i, i);
91else
92return "%f %<has> no current message.";
93endif
94elseif ((index(string, "next") == 1) && (!index(string, "-")))
95string[1..4] = "";
96if ((n = string ? toint(string) | 1) <= 0)
97return tostr("Bad number `", string, "'");
98elseif ((i = caller:length_num_le(cur) + 1) <= nummsgs)
99seq = $seq_utils:add(seq, i, min((i + n) - 1, nummsgs));
100else
101return "%f %<has> no next message.";
102endif
103elseif ((index(string, "prev") == 1) && (!index(string, "-")))
104string[1..4] = "";
105if ((n = string ? toint(string) | 1) <= 0)
106return tostr("Bad number `", string, "'");
107elseif (i = caller:length_num_le(cur - 1))
108seq = $seq_utils:add(seq, max(1, (i - n) + 1), i);
109else
110return "%f %<has> no previous message.";
111endif
112elseif (string == "new")
113s = last_old ? caller:length_date_le(last_old) | caller:length_num_le(cur);
114if (s < nummsgs)
115seq = $seq_utils:add(seq, s + 1, nummsgs);
116else
117return "%f %<has> no new messages.";
118endif
119elseif (string == "first")
120seq = $seq_utils:add(seq, 1, 1);
121elseif (n = toint(string) || (((string in {"last", "$"}) && -1) || ((string == "cur") && cur)))
122if (n <= 0)
123seq = $seq_utils:add(seq, max(0, nummsgs + n) + 1, nummsgs);
124elseif (i = caller:exists_num_eq(n))
125seq = $seq_utils:add(seq, i, i);
126else
127return (string == "cur") ? "%f's current message has been removed." | tostr("%f %<has> no message numbered `", string, "'.");
128endif
129elseif (((i = index(string, "..")) > 1) || ((i = index(string, "-")) > 1))
130if ((start = toint(sst = string[1..i - 1])) > 0)
131s = caller:length_num_le(start - 1);
132elseif (sst in {"next", "prev", "cur"})
133s = max(0, caller:length_num_le(cur - (sst != "next")) - (sst == "prev"));
134elseif (sst in {"last", "$"})
135s = nummsgs - 1;
136elseif (sst == "first")
137s = 0;
138else
139return {$seq_utils:union(result, seq), @strings[strnum..$]};
140endif
141j = (string[i] == ".") ? i + 2 | (i + 1);
142if ((end = toint(est = string[j..$])) > 0)
143e = caller:length_num_le(end);
144elseif (est in {"next", "prev", "cur"})
145e = min(nummsgs, caller:length_num_le(cur - (est == "prev")) + (est == "next"));
146elseif (est in {"last", "$"})
147e = nummsgs;
148elseif (est == "first")
149e = 1;
150else
151return {$seq_utils:union(result, seq), @strings[strnum..$]};
152endif
153if (s < e)
154seq = $seq_utils:add(seq, s + 1, e);
155else
156return tostr("%f %<has> no messages in range ", string, ".");
157endif
158elseif (string == "cur")
159return "%f %<has> no current message.";
160else
161return {$seq_utils:union(result, seq), @strings[strnum..$]};
162endif
163endif
164endfor
165return {$seq_utils:union(result, seq)};

_parse_from _parse_to

Spec this none thisFlags rxdOwner #29Definer #38

Referenced by

none

Source

1":_parse_from(string with |'s in it) => object list";
2":_parse_to(string with |'s in it) => object list";
3"  for from:string and to:string items in :parse_message_seq";
4if (verb == "_parse_to")
5match_obj = fail_obj = this;
6match_verb = "match_recipient";
7fail_verb = "match_failed";
8else
9match_obj = $string_utils;
10match_verb = "match_player";
11fail_obj = $command_utils;
12fail_verb = "player_match_failed";
13endif
14plist = {};
15for w in ($string_utils:explode(args[1], "|"))
16if (fail_obj:(fail_verb)(p = match_obj:(match_verb)(w), w))
17p = $string_utils:literal_object(w);
18if ((p == $failed_match) || (!$command_utils:yes_or_no("Continue? ")))
19return "Bad address list:  " + args[1];
20endif
21endif
22plist = setadd(plist, p);
23endfor
24return plist;

_parse_date

Spec this none thisFlags rxdOwner #29Definer #38

Referenced by

Source

1words = $string_utils:explode(args[1], "-");
2if (length(words) == 1)
3if (index("yesterday", words[1]) == 1)
4time = $time_utils:dst_midnight((time() - (time() % 86400)) - 86400);
5elseif (index("today", words[1]) == 1)
6time = $time_utils:dst_midnight(time() - (time() % 86400));
7elseif (index("lastweek", words[1]) == 1)
8time = $time_utils:dst_midnight((time() - (time() % 86400)) - (7 * 86400));
9elseif (index("lastmonth", words[1]) == 1)
10time = $time_utils:dst_midnight((time() - (time() % 86400)) - (30 * 86400));
11elseif (index("lastyear", words[1]) == 1)
12time = $time_utils:dst_midnight((time() - (time() % 86400)) - (365 * 86400));
13elseif (typeof(time = $time_utils:from_day(words[1], -1)) == ERR)
14time = "weekday, `Today', `Yesterday', or date expected.";
15endif
16elseif ((!words) || ((length(words) > 3) || ((!toint(words[1])) || (E_TYPE == (year = $code_utils:toint({@words, "-1"}[3]))))))
17time = "Date should be of the form `5-Jan', `5-Jan-92', `Wed',`Wednesday'";
18else
19day = toint(words[1]);
20time = $time_utils:dst_midnight($time_utils:from_month(words[2], -1, day));
21if (length(words) == 3)
22thisyear = toint(ctime(time)[21..24]);
23if (100 > year)
24year = (thisyear + 50) - (((thisyear - year) + 50) % 100);
25endif
26time = $time_utils:dst_midnight($time_utils:from_month(words[2], (year - thisyear) - (year <= thisyear), day));
27endif
28endif
29return time;

new_message_num

Spec this none thisFlags rxdOwner #361Definer #38

Referenced by

none

Source

1":new_message_num() => number that the next incoming message will receive.";
2set_task_perms(caller_perms());
3new = (msgs = caller.messages) ? msgs[$][1] + 1 | 1;
4if (rmsgs = caller.messages_going)
5if ((!rmsgs[1]) || (typeof(rmsgs[1][2]) == INT))
6rmsgs = rmsgs[2];
7endif
8lbrm = rmsgs[$][2];
9return max(new, lbrm[$][1] + 1);
10else
11return new;
12endif

length_all_msgs

Spec this none thisFlags rxdOwner #361Definer #38

Referenced by

none

Source

1set_task_perms(caller_perms());
2return length(caller.messages);

length_date_le

Spec this none thisFlags rxdOwner #361Definer #38

Referenced by

none

Source

1set_task_perms(caller_perms());
2date = args[1];
3msgs = caller.messages;
4if ((r = length(caller.messages)) < 25)
5for l in [1..r]
6if (msgs[l][2][1] > date)
7return l - 1;
8endif
9endfor
10return r;
11else
12l = 1;
13while (l <= r)
14if (date < msgs[i = (r + l) / 2][2][1])
15r = i - 1;
16else
17l = i + 1;
18endif
19endwhile
20return r;
21endif

length_date_gt

Spec this none thisFlags rxdOwner #361Definer #38

Referenced by

none

Source

1set_task_perms(caller_perms());
2date = args[1];
3msgs = caller.messages;
4if ((len = length(caller.messages)) < 25)
5for r in [0..len - 1]
6if (msgs[len - r][2][1] <= date)
7return r;
8endif
9endfor
10return len;
11else
12l = 1;
13r = len;
14while (l <= r)
15if (date < msgs[i = (r + l) / 2][2][1])
16r = i - 1;
17else
18l = i + 1;
19endif
20endwhile
21return len - r;
22endif

length_num_le

Spec this none thisFlags rxdOwner #361Definer #38

Referenced by

none

Source

1":length_num_le(num) => number of messages in folder numbered <= num";
2set_task_perms(caller_perms());
3return $list_utils:iassoc_sorted(args[1], caller.messages);

exists_num_eq

Spec this none thisFlags rxdOwner #361Definer #38

Referenced by

none

Source

1":exists_num_eq(num) => index of message in folder numbered == num";
2set_task_perms(caller_perms());
3return (i = $list_utils:iassoc_sorted(args[1], caller.messages)) && ((caller.messages[i][1] == args[1]) && i);

from_msg_seq

Spec this none thisFlags rxdOwner #361Definer #38

Referenced by

none

Source

1":from_msg_seq(object or list[,mask])";
2" => msg_seq of messages from any of these senders";
3set_task_perms(caller_perms());
4{plist, ?mask = {1}} = args;
5if (typeof(plist) != LIST)
6plist = {plist};
7endif
8i = 1;
9fseq = {};
10for msg in (caller.messages)
11if ((!mask) || (i < mask[1]))
12elseif ((length(mask) < 2) || (i < mask[2]))
13fromline = msg[2][2];
14if (toobj(fromline[rindex(fromline, "(") + 1..rindex(fromline, ")") - 1]) in plist)
15fseq = $seq_utils:add(fseq, i, i);
16endif
17else
18mask = mask[3..$];
19endif
20i = i + 1;
21$command_utils:suspend_if_needed(0);
22endfor
23return fseq || ("%f %<has> no messages from " + $string_utils:english_list($list_utils:map_arg(2, $string_utils, "pronoun_sub", "%n (%#)", plist), "no one", " or "));

%from_msg_seq

Spec this none thisFlags rxdOwner #361Definer #38

Referenced by

none

Source

1":%from_msg_seq(string or list of strings[,mask])";
2" => msg_seq of messages with one of these strings in the from line";
3set_task_perms(caller_perms());
4{nlist, ?mask = {1}} = args;
5if (typeof(nlist) != LIST)
6nlist = {nlist};
7endif
8i = 1;
9fseq = {};
10for msg in (caller.messages)
11if ((!mask) || (i < mask[1]))
12elseif ((length(mask) < 2) || (i < mask[2]))
13fromline = " " + msg[2][2];
14for n in (nlist)
15if (index(fromline, n))
16fseq = $seq_utils:add(fseq, i, i);
17endif
18endfor
19else
20mask = mask[3..$];
21endif
22i = i + 1;
23$command_utils:suspend_if_needed(0);
24endfor
25return fseq || ("%f %<has> no messages from " + $string_utils:english_list($list_utils:map_arg($string_utils, "print", nlist), "no one", " or "));

to_msg_seq

Spec this none thisFlags rxdOwner #361Definer #38

Referenced by

none

Source

1":to_msg_seq(object or list[,mask]) => msg_seq of messages to those people";
2set_task_perms(caller_perms());
3{plist, ?mask = {1}} = args;
4if (typeof(plist) != LIST)
5plist = {plist};
6endif
7i = 1;
8seq = {};
9for msg in (caller.messages)
10if ((!mask) || (i < mask[1]))
11elseif ((length(mask) < 2) || (i < mask[2]))
12toline = msg[2][3];
13for r in ($mail_agent:parse_address_field(toline))
14if (r in plist)
15seq = $seq_utils:add(seq, i, i);
16endif
17endfor
18else
19mask = mask[3..$];
20endif
21i = i + 1;
22$command_utils:suspend_if_needed(0);
23endfor
24return seq || ("%f %<has> no messages to " + $string_utils:english_list($list_utils:map_arg(2, $string_utils, "pronoun_sub", "%n (%#)", plist), "no one", " or "));

%to_msg_seq

Spec this none thisFlags rxdOwner #361Definer #38

Referenced by

none

Source

1":%to_msg_seq(string or list of strings[,mask])";
2" => msg_seq of messages containing one of strings in the to line";
3set_task_perms(caller_perms());
4{nlist, ?mask = {1}} = args;
5if (typeof(nlist) != LIST)
6nlist = {nlist};
7endif
8i = 1;
9seq = {};
10for msg in (caller.messages)
11if ((!mask) || (i < mask[1]))
12elseif ((length(mask) < 2) || (i < mask[2]))
13toline = " " + msg[2][3];
14for n in (nlist)
15if (index(toline, n))
16seq = $seq_utils:add(seq, i, i);
17endif
18endfor
19else
20mask = mask[3..$];
21endif
22i = i + 1;
23$command_utils:suspend_if_needed(0);
24endfor
25return seq || ("%f %<has> no messages to " + $string_utils:english_list($list_utils:map_arg($string_utils, "print", nlist), "no one", " or "));

subject_msg_seq

Spec this none thisFlags rxdOwner #361Definer #38

Referenced by

none

Source

1":subject_msg_seq(target) => msg_seq of messages with target in the Subject:";
2set_task_perms(caller_perms());
3{target, ?mask = {1}} = args;
4i = 1;
5seq = {};
6for msg in (caller.messages)
7if ((!mask) || (i < mask[1]))
8elseif ((length(mask) < 2) || (i < mask[2]))
9subject = msg[2][4];
10if (index(subject, target))
11seq = $seq_utils:add(seq, i, i);
12endif
13else
14mask = mask[3..$];
15endif
16i = i + 1;
17$command_utils:suspend_if_needed(0);
18endfor
19return seq || (("%f %<has> no messages with subjects containing `" + target) + "'");

body_msg_seq

Spec this none thisFlags rxdOwner #361Definer #38

Referenced by

none

Source

1":body_msg_seq(target[,mask]) => msg_seq of messages with target in the body";
2set_task_perms(caller_perms());
3{target, ?mask = {1}} = args;
4i = 1;
5seq = {};
6for msg in (caller.messages)
7if ((!mask) || (i < mask[1]))
8elseif ({@mask, $maxint}[2] <= i)
9mask = mask[3..$];
10"Old code follows. Lets save ticks and munge up the whole message body into one big string and index it. Don't need to know where target is in there, just that it is or isn't there";
11elseif (((bstart = "" in (msg = msg[2])) && (length(msg) > bstart)) && index(tostr(@msg[bstart + 1..$]), target))
12seq = $seq_utils:add(seq, i, i);
13"elseif ((bstart = \"\" in (msg = msg[2])) && (l = length(msg)) > bstart)";
14"while (!index(msg[l], target) && (l = l - 1) > bstart)";
15"$command_utils:suspend_if_needed(0);";
16"endwhile";
17"if (l > bstart)";
18"seq = $seq_utils:add(seq, i, i);";
19"endif";
20endif
21i = i + 1;
22$command_utils:suspend_if_needed(0);
23endfor
24return seq || tostr("%f %<has> no messages containing `", target, "' in the body.");

messages_in_seq

Spec this none thisFlags rxdOwner #361Definer #38

Referenced by

none

Source

1":messages_in_seq(msg_seq) => list of messages in msg_seq on folder (caller)";
2set_task_perms(caller_perms());
3if (typeof(msgs = args[1]) != LIST)
4return caller.messages[msgs];
5elseif (length(msgs) == 2)
6return caller.messages[msgs[1]..msgs[2] - 1];
7else
8return $seq_utils:extract(msgs, caller.messages);
9endif

__convert_new

Spec this none thisFlags rxdOwner #361Definer #38

Referenced by

Source

1":__convert_new(@msg) => msg in new format (if it isn't already)";
2"               ^ don't forget the @ here.";
3"If the msg is already in the new format it passes through unchanged.";
4"If the msg format is unrecognizable, warnings are printed.";
5if (typeof(date = args[1]) != INT)
6date = 0;
7start = 1;
8else
9start = 2;
10if (!((colon = index(args[2], ":")) && (args[2][1..colon] in {"From:", "To:", "Subject:"})))
11return args;
12endif
13endif
14from = to = 0;
15subject = " ";
16blank = "" in {@args, ""};
17newhdr = {};
18for line in (args[start..blank - 1])
19if (index(line, "Date:") == 1)
20if (date)
21player:notify("Warning: two dates?");
22endif
23date = $time_utils:from_ctime(line[6..$]);
24elseif (index(line, "From:") == 1)
25if (from)
26player:notify("Warning: two from-lines?");
27endif
28from = $string_utils:triml(line[6..$]);
29elseif (index(line, "To:") == 1)
30if (to)
31player:notify("Warning: two to-lines?");
32endif
33to = $string_utils:triml(line[6..$]);
34elseif (index(line, "Subject:") == 1)
35subject = $string_utils:triml(line[9..$]);
36else
37newhdr = {@newhdr, line};
38endif
39endfor
40if (!from)
41player:notify("Warning: no from-line.");
42endif
43if (!to)
44player:notify("Warning: no to-line.");
45endif
46return {date, from, to, subject, @newhdr, @args[blank..$]};

to_text

Spec this none thisFlags rxdOwner #29Definer #38

Referenced by

Source

1":to_text(@msg) => message in text form (suitable for printing)";
2msg = {"Date:     " + ctime(args[1]), "From:     " + args[2], "To:       " + args[3], @(args[4] == " ") ? {} | {"Subject:  " + args[4]}, @args[5..$]};
3msg[$] = msg[$] + $ansi.reset;
4return msg;

is_readable_by is_writable_by is_usable_by

Spec this none thisFlags rxdOwner #29Definer #38

Referenced by

none

Source

1what = args[1];
2if ($object_utils:isa(what, $mail_recipient))
3return what:(verb)(@listdelete(args, 1));
4else
5"...it's a player:";
6"...  anyone can send mail to it.";
7"...  only the player itself or a wizard can read it.";
8return (verb == "is_usable_by") || $perm_utils:controls(args[2], what);
9endif

reserved_pattern

Spec this none thisFlags rxdOwner #29Definer #38

Referenced by

Source

1":reserved_pattern(string)";
2"  if string matches one of the reserved patterns for mailing list names, ";
3"  we return that element of .reserved_patterns.";
4string = args[1];
5for p in (this.reserved_patterns)
6if (match(string, p[1]))
7return p;
8endif
9endfor
10return 0;

is_recipient

Spec this none thisFlags rxdOwner #29Definer #38

Referenced by

Source

1return valid(what = args[1]) && (($mail_recipient_class in (ances = $object_utils:ancestors(what))) || ($mail_recipient in ances));

keep_message_seq

Spec this none thisFlags rxdOwner #361Definer #38

Referenced by

none

Source

1":keep_message_seq(msg_seq)";
2"...If msg_seq nonempty {}, this marks the indicated messages on this folder (caller)";
3"...as immune from expiration.";
4"...If msg_seq == {}, this clears all such marks.";
5set_task_perms(caller_perms());
6msg_seq = args[1];
7if (!msg_seq)
8caller.messages_kept = {};
9return 1;
10endif
11prev_kept = caller.messages_kept;
12caller.messages_kept = new_kept = $seq_utils:union(prev_kept, msg_seq);
13added = $seq_utils:intersection(new_kept, $seq_utils:complement(prev_kept));
14if (!added)
15return "";
16endif
17"... urk.  now we need to get the actual numbers of the messages being kept.";
18nums = {};
19start = 0;
20for a in (added)
21nums = {@nums, (start = !start) ? caller:messages_in_seq(a)[1] | (caller:messages_in_seq(a - 1)[1] + 1)};
22endfor
23return $seq_utils:tostr(nums);

kept_msg_seq unkept_msg_seq

Spec this none thisFlags rxdOwner #361Definer #38

Referenced by

none

Source

1":kept_msg_seq([mask])";
2" => msg_seq of messages that are marked kept";
3":unkept_msg_seq([mask])";
4" => msg_seq of messages that are not marked kept";
5set_task_perms(caller_perms());
6{?mask = {1}} = args;
7if (k = verb == "kept_msg_seq")
8kseq = $seq_utils:intersection(mask, caller.messages_kept);
9else
10kseq = $seq_utils:intersection(mask, $seq_utils:range(1, caller:length_all_msgs()), $seq_utils:complement(caller.messages_kept));
11endif
12return kseq;

msg_seq_to_msg_num_string

Spec this none thisFlags rxdOwner #361Definer #38

Referenced by

none

Source

1":msg_seq_to_msg_num_string(msg_seq) => string giving the corresponding message numbers";
2set_task_perms(caller_perms());
3return $seq_utils:tostr($seq_utils:from_list($list_utils:slice(caller:messages_in_seq(args[1]))));

msg_seq_to_msg_num_list

Spec this none thisFlags rxdOwner #361Definer #38

Referenced by

none

Source

1":msg_seq_to_msg_num_list(msg_seq) => list of corresponding message numbers";
2set_task_perms(caller_perms());
3return $list_utils:slice(caller:messages_in_seq(args[1]));

send_log_message

Spec this none thisFlags rxdOwner #29Definer #38

Referenced by

none

Source

1"send_log_message(perms,from,rcpt-list,hdrs,msg) -- formats and sends a mail message. hders is either the text of the subject line, or a {subject,{reply-to,...}} list.";
2"KLUDGE.  this may go away.";
3"Send a message while supplying a different permission for use by :mail_forward to determine moderation action.";
4"Return E_PERM unless called by a wizard.";
5"Return {0, @invalid_rcpts} if rcpt-list contains any invalid addresses.  No mail is sent in this case.";
6"Return {1, @actual_rcpts} if successful.";
7{perms, from, to, hdrs, msg} = args;
8if (caller_perms().wizard)
9text = $mail_agent:make_message(from, to, hdrs, msg);
10return this:raw_send(text, to, perms);
11else
12return E_PERM;
13endif

parse_misc_headers

Spec this none thisFlags rxdOwner #29Definer #38

Referenced by

Source

1":parse_misc_headers(msg,@extract_names)";
2"Extracts the miscellaneous (i.e., not including Date: From: To: Subject:)";
3"from msg (a mail message in the usual transmission format).";
4"Extract_names is a list of header names";
5"=> {other_headers,bogus_headers,extract_texts,body}";
6"where each element of extract_texts is a string or 0";
7"  according as the corresponding header in extract_names is present.";
8"bogus_headers is a list of those headers that are undecipherable";
9"other_headers is a list of {header_name,header_text} for the remaining";
10"  miscellaneous headers.";
11"headers in msg";
12msgtxt = args[1];
13extract_names = listdelete(args, 1);
14extract_texts = $list_utils:make(length(extract_names));
15heads = bogus = {};
16for h in (msgtxt[5..(bstart = "" in {@msgtxt, ""}) - 1])
17if (m = match(h, "%([a-z1-9-]+%): +%(.*%)"))
18hname = h[m[3][1][1]..m[3][1][2]];
19htext = h[m[3][2][1]..m[3][2][2]];
20if (i = hname in extract_names)
21extract_texts[i] = htext;
22else
23heads = {@heads, {hname, htext}};
24endif
25else
26bogus = {@bogus, h};
27endif
28endfor
29return {heads, bogus, extract_texts, msgtxt[bstart + 1..$]};

resend_message

Spec this none thisFlags rxdOwner #361Definer #38

Referenced by

Source

1"resend_message(new_sender,new_rcpts,from,to,hdrs,body)";
2" -- reformats and resends a previously sent message to new recipients.";
3"msg is the previous message";
4"Return E_PERM if new_sender isn't owned by the caller.";
5"Return {0, @invalid_rcpts} if new_rcpts contains any invalid addresses.  No mail is sent in this case.";
6"Return {1, @actual_rcpts} if successful.";
7{new_sender, new_rcpts, from, to, hdrs, body} = args;
8if (typeof(hdrs) != LIST)
9hdrs = {hdrs, 0};
10elseif (length(hdrs) < 2)
11hdrs = {@hdrs || {""}, 0};
12endif
13hdrs[3..2] = {{"Resent-By", this:name_list(new_sender)}, {"Resent-To", this:name_list(@new_rcpts)}};
14if ($perm_utils:controls(caller_perms(), new_sender))
15text = $mail_agent:make_message(from, to, hdrs, body);
16return this:raw_send(text, new_rcpts, new_sender);
17else
18return E_PERM;
19endif

init_for_core

Spec this none thisFlags rxOwner #361Definer #38

Referenced by

none

Source

1if (caller_perms().wizard)
2this.reserved_patterns = {};
3`set_verb_code(this, "raw_send", verb_code(this, "raw_send(core)")) ! ANY';
4`delete_verb(this, "raw_send(core)") ! ANY';
5pass(@args);
6endif

display_message_improved

Spec this none thisFlags rxdOwner #361Definer #38

Referenced by

Source

1":display_message_improved(INT msgid, OBJ folder, INT time, STR from, STR to, STR subj, @message)";
2{msgnum, folder, time, fromtxt, totxt, subj, @rest} = args;
3datecolor = $ansi.yellow;
4foldercolor = $ansi.yellow + $ansi.bold_on;
5fromcolor = $ansi.yellow;
6whocolor = $ansi.yellow + $ansi.bold_on;
7numcolor = $ansi.yellow + $ansi.bold_on;
8oncolor = $ansi.bold_off;
9themecolor = $ansi.(folder.barcolor);
10bar = (($ansi.("bg_" + folder.barcolor) + " ") + $ansi.reset) + " ";
11msgnum = tostr(msgnum);
12foldername = $mail_agent:name(folder);
13from_obj = fromtxt[rindex(fromtxt, " ") + 2..$ - 1];
14fromtxt = `this:mail_name_for(toobj(from_obj)) ! ANY => "<unavailable>"';
15fromtxt = (((fromcolor + "From: ") + whocolor) + fromtxt) + $ansi.reset;
16rightlen = max(3 + length($ansi:strip(fromtxt)), 31);
17leftlen = ((player.linelen ? max(70, abs(player.linelen)) | 79) - rightlen) - 2;
18subj = (subj == " ") ? " " | subj;
19leftside = $su:word_wrap({tostr(msgnum, " on ", foldername)}, leftlen, foldercolor);
20leftside = {@leftside, @$su:word_wrap({subj}, leftlen, $ansi.white + $ansi.bold_on)};
21rightside = {tostr(themecolor, "// ", datecolor, ctime(time), $ansi.reset)};
22rightside = {@rightside, tostr(themecolor, "// ", fromtxt)};
23outlines = {};
24for i in [1..length(leftside)]
25if (i <= length(rightside))
26outlines = {@outlines, $su:left(leftside[i], leftlen) + rightside[i]};
27else
28outlines = {@outlines, @leftside[i..$]};
29break;
30endif
31endfor
32extra = `folder:extra_headers(bar, leftlen, themecolor + "// ", rightlen, args[3..$]) ! ANY => {}';
33extra = (typeof(extra) == LIST) ? extra | {extra};
34end_extra = `folder:extra_text(@args) ! ANY => {}';
35end_extra = (typeof(end_extra) == LIST) ? end_extra | {end_extra};
36realmsg = {};
37$cu:sin();
38for r in (rest)
39yield;
40if (typeof(r) == STR)
41realmsg = {@realmsg, r};
42endif
43endfor
44default_totxt = $su:nn(folder);
45if (index(totxt, " and "))
46realmsg = {@realmsg, "", tostr($ansi.yellow, "Message sent to ", totxt, $ansi.reset)};
47endif
48realmsg = $su:word_wrap(realmsg, (leftlen + rightlen) + 1);
49if (end_extra)
50end_extra_color = `folder.extra_text_color ! E_PROPNF => ""';
51shortname = folder.name;
52if (spc = index(shortname, " "))
53shortname = shortname[1..spc - 1];
54endif
55suspend_text = tostr($ansi.yellow, "[ Formatting long comments (", msgnum, " on *", shortname, ") ... ]", $ansi.reset);
56end_extra = $su:word_wrap(end_extra, (leftlen + rightlen) + 1, end_extra_color, suspend_text);
57endif
58for l in ({"", @outlines, @extra, @realmsg, @end_extra})
59player:notify(player.ansi ? bar + l | $ansi:strip(bar + l));
60$cu:sin();
61endfor
62endline = (((($ansi.("bg_" + folder.barcolor) + " ") + $ansi.reset) + themecolor) + $su:space((leftlen + rightlen) + 1, "_")) + $ansi.reset;
63player:notify(player.ansi ? endline | $ansi:strip(endline));

mail_name_for

Spec this none thisFlags rxdOwner #361Definer #38

Referenced by

Source

1":mail_name_for(OBJ who [, INT force_no_objnum]) => STR name with color.";
2{who, ?no_objnum = 0} = args;
3color = "";
4name = valid(who) ? who.name | "nobody";
5icon = "";
6if (is_a(who, $garbage) || is_a(who, $fossil))
7color = $ansi.white;
8name = "<deleted>";
9elseif (!is_a(who, $player))
10color = $ansi.white;
11elseif (who.wizard)
12color = $ansi.white + $ansi.bold_on;
13elseif (is_a(who, $prog))
14color = $ansi.purple + $ansi.bold_on;
15elseif (is_a(who, $immortal))
16color = $ansi.purple;
17else
18color = $ansi.yellow + $ansi.bold_on;
19endif
20if ((!no_objnum) && player.programmer)
21return tostr(color, name, " (", who, ")", $ansi.reset, icon);
22else
23return tostr(color, name, $ansi.reset, icon ? " " + icon | "");
24endif

parse_new_mailspec

Spec this none thisFlags rxdOwner #361Definer #38

Referenced by

Source

1{spec, @rest} = args;
2fname = "";
3msgspec = "";
4if (slash = index(spec, "/"))
5fname = spec[1..slash - 1];
6msgspec = spec[slash + 1..$];
7endif
8if ((!fname) || (!msgspec))
9player:tell("I don't understand '", spec, "'. (Use foldername/msg if you're using the slash message format.");
10return;
11endif
12if (fname[1] == "*")
13fname = fname[2..$];
14if (!fname)
15player:tell("There aren't any folders named \"*\", weirdo.");
16return;
17endif
18endif
19folder = $mail_agent:match(fname);
20if (!valid(folder))
21$mail_agent:match_failed(folder, "*" + fname);
22return;
23endif
24cur = player:get_current_message(folder) || {0};
25pms = folder:parse_message_seq(msgspec, @cur);
26errmsg = "";
27if (typeof(pms) == LIST)
28if (pms[1])
29return {folder, pms[1], cur, rest};
30elseif (length(pms) == 1)
31errmsg = ("%f has no '" + msgspec) + "' messages.";
32else
33player:tell("I don't understand '", msgspec, "'.");
34endif
35elseif (typeof(pms) == ERR)
36player:tell($mail_agent:name(folder), " is not readable by you.");
37elseif (typeof(pms) == STR)
38errmsg = pms;
39endif
40if (!errmsg)
41return;
42endif
43errmsg = $su:subst(errmsg, {{"%f", $mail_agent:name(folder)}, {"%<has>", "has"}});
44player:tell(errmsg);
45return 0;