# # BrandyMailer - Ported to PennMUSH by Javelin 9/7/98 # # Changes from the original file are marked with "JAVELIN". Otherwise, # just follow Brandy's instructions below. Very little required changing. # A copy of amolitor_mush_unformatter.c is also available at # ftp://ftp.pennmush.org/pub/PennMUSH/Accessories # # See also, at this directory: TBmE4P-1.0.0.txt # which is brandy-similar mailer written from scratch that uses @mail # as its transport. # ############################################################################### # code written by Brandy@CrystalMUSH # for MUSH 2.0.10 patch level 5 or later # Notes on the formating of this file: # - is used to separate attributes # # in the first column means a comment # all leading blanks should be stripped, but tailing ones should not # # This +mail code is available via anonymous FTP from # caisr2.caisr.cwru.edu (129.22.24.22) in file: # /pub/mush/mushcode/brandy_mailer.13 # # A tool that parses this format is available in the same directory in file: # amolitor_mush_unformatter.c # # Questions/Problems/Requests go to cag@empros.com # # If you have any trouble installing it, feel free to contact me and I'll # do it for you. It typically takes me 15 mins to a 1/2 hour for a first # time installation. # # Carol # a.k.a Brandy@CrystalMUSH # # CAUTION: This version is incompatible with previous versions of # this mailer. I do have a tool which may be used to convert 'old style' # mailboxes to the new format, if you want a copy of that, send me # some email (cag@empros.com). You can also request that I do the # upgrade and convert if you want. The incompatibility was # unavoidable due to the completely changed nature of how messages # are saved (which is now more DB friendly). Another option, is to # just chuck the old mailboxes. # # MAILING LIST: # # To be kept abreast of patches and upgrades, or if you just want to # make comments/suggestions whatever, subscribe to brandy-mail@lupine.org # by sending an email message to listserv@lupine.org, with # 'subscribe brandy-mail MyNameHere' in the body of the mail message. # # Or send me email at cag@empros.com # ############################################################################### # Things that still need to be done in the future: # # use %q instead of r(), 2.10.6 or later # ############################################################################### # # CHANGES SINCE THE LAST DISTRIBUTION: # # fixed bug in +set mail default separator # show 'a' for mailboxes with autoforward set in +mail status # added mail_folders and mail5 to global_commands # ############################################################################### # # Version 13 # # General: # o changed code to only store a single copy of all letters, no matter # how wide the distribution # o expanded usage of setq()/r() including removal of ALL temp variable # usage # o restructured things, one new object, three obsolete (and can be # deleted objects) # o performance should be dramatically improved # # Added code to support folders, new commands: # # o +add folder # o +remove folder # o +list folders # o +move to # o +select folder # o +add filter author|subject= folder= # o +remove filter # o +list filters # # updated all commands to work off of current_folder (default is the # inbox 'main' if not otherwise specified) # # Misc tweaks the user's may notice: # o Allow autoforward to be a list of people and/or aliases # o show total messages on +read, i.e., Message: 4/23 # o +edit cc, +edit bcc, +edit to, +edit subject, +edit personal alias # and +edit global alias now check to see if the text of what you # want to change is actually there. It also shows you the final # result of the edit upon completion (for aliases, others did that # before). # o +skim now shows a 'n' next to messages that have a note registered # o allow +add note= to add note to current letter # o options shown after a +read now include +move and +save # o +expand personal alias and +expand global alias displays are # slightly easier to read ('specially if folks have blanks in # their names) # o +set mail option separator = space or return # o +set mail option inbox = # o +set mail option vacation= # o +set mail option reject= # o +show mail options now shows value for 'separator' option # o +show mail options now shows value for 'inbox' option # o +show mail options now shows list of personal aliases # o +show mail options now shows list of folders # o +show mail options now shows count of filters # o +show mail options now shows vacation text # o +show mail options now shows reject text # o +note command added # o allow author:, subject:, text: to be # used as keywords # o allow +forward = in addition to the normal +forward cmd. # this form allows you to add additional text via '-' before # sending. # o Replaced '+review letter to ' with # '+review []' # +review w/no parameter shows one summary line per sent letter # keywords allowed: all, current, first, last, next, previous, # to:, subject:, text: # o Replaced '+retract letter to ' with # '+retract ' # keywords allowed: first, next, previous, last, current # # Misc tweaks admin's may notice: # o automatically destroy mailboxes for dest'ed players during # periodic mail timeout code # o created command to allow admin to specify when periodic letter purge # should run, default is Wednesdays at 4 AM # ( format: +set mail default purge= : ) # o created command to allow admin to enable or disable the +save # command for all users. # ( format: +set mail default save = enabled | disabled ) # o +set mail default separator = space | return # o +mail configuration changes: # shows the default for the 'separator' option # shows when the next letter/mailbox purge is scheduled # shows how many attributes are being used to hold the list of mailboxes # shows the configured text for: delivery_notification, # pickup_notification, forward_notification, text_added_notification # does some verification that things were set up right and warns if not. # o +mail status changes: # shows number of defined folders # shows number of defined filters # shows number of sent messages still stored (not deleted by recipient) # o +mail status for changes: # shows list of personal aliases defined # shows total and list of folders defined # shows current folder # shows current letter for the selected folder # shows total of sent messages still stored (not deleted) # shows inbox folder name # shows number of filters # o automatically do a +mail configuration at the end of installation # # Bug fixes: # o fixed bug - +replyall needs to include the sender as well # o made the code more accurate about overflowing letter size # o fixed semaphore not being notified in +add global alias and # +edit global alias end cases. # o fixed bug in the purge old letters code that resulted in an # infinite loop # ############################################################################### # # The following are the mapping of dbref to object in this file. # # #3478 - Mail System # #3479 - Wiz-Inherit Object # #3480 - Master Mailbox # #3481 - Help Text # #3482 - Parent Mail Object # # !!! NOTE: IMPORTANT! FOR FOLKS INSTALLING OVER AN EXISTING SYSTEM !!! # # The Parent Mail Object is NEW for this release. You need to: # # @create Parent Mail Object # @parent Mail System = Parent Mail Object # # The following objects are no longer needed with this release: # # @destroy Cleanup Module # @destroy Generic Mailbox # @destroy Generic Info Record # # Throughout this file, you'll see lots of attributes getting set to # nothing. This is done to remove attributes off the mail system that # are not commands, putting them on the (new) parent object for the mail # system since parent of objects in the master room are not searched # for commands (thanks to Amberyl for pointing this out). # # To modify this file for use on another MUSH, basically, 5 vi commands # must be used to change the dbrefs to the ones for the matching objects # on the MUSH this is being installed on. Then run it through Andrew # Molitor's MUSH code unformatter. It is then ready for quoting in via # tf or whatever. (For first time installations, see instructions below). # # (brief instructions) # create the objects needed # edit brandy_mailer.13 to reference the relevant dbrefs # compile the unformatter: cc amolitor_mush_unformatter.c # then run the mailer through it: a.out brandy_mailer.13 >mailer # and install via tf: /quote 'mailer # # (vi commands to change dbrefs through the file) # # :1,$s/#3478//g # :1,$s/#3479//g # :1,$s/#3480//g # :1,$s/#3481//g # :1,$s/#3482//g # # NOTE: # # The personal mail option commands won't work on #1, since there # are permission problems with setting attributes on 'god'. If # 'god' is so inclined to use +mail and wants personal options # set, s/he will need to set the &mail_config_options attribute # on him/herself. # ############################################################################### # # For those installing it for the first time.... # # @create Mail System (must reside in the master room) # @create Wiz-Inherit Object # (Note: must reside in the master room, this object holds the few mail # commands that need wiz powers) # @create Master Mailbox # @create Help Text # @create Parent Mail Object # # @parent Mail System = Parent Mail Object # # @set Wiz-Inherit Object=inherit # (Note: the other objects need not and indeed # should not be set inherit) # # JAVELIN: @set wiz-inherit object=!no_command # JAVELIN: @set wiz-inherit object=!inherit # JAVELIN: @set wiz-inherit object=wizard # JAVELIN: @set mail system = !no_command # # &mail_config_options me=soft # &mail_config_options me= # ^_____(just to get that attribute in the list of user attributes) # # &mail_sig me=something # &mail_sig me= # ^_____(just to get that attribute in the list of user attributes) # # @attribute/access mail_config_options=wizard (must be done by god(#1)) # @attribute/access mail_config_options=!private (must be done by god(#1)) # @attribute/access mail_sig=!private (must be done by god(#1)) # # JAVELIN: Instead of the above, add these to God's @startup: # @attribute/access mail_config_options=wizard visual # @attribute/access mail_sig=visual # # The Mail System object and the Wiz-Inherit Object must reside # in the Master Room. The remaining objects should not be in the # master room. Just stick them in a bag somewhere and forget about them. ;) # # CAUTION: In order for the +mailer to work, space compression # MUST be turned on (@admin space_compress=yes). This shouldn't # present a problem since most (all?) MUSHes run this way. # # JAVELIN: All PennMUSHes always have space compression, so no @admin # command is needed # - # # Set the MAILBOXES_NUM_OF_ATTRIBUTEs, only if not previously set by # a prior installation. # @switch words(get(#3480/mailboxes_num_of_attributes))=0, &mailboxes_num_of_attributes #3480=1 - ############################################################################### # # Data Structures: # # owner_dbref dbref of who's mailbox this is # autoforward list of players/aliases to autoforward mail to # message_timeout number of seconds (in day multiples) before # mail will be automatically timed out and deleted. # alias-list list of personal mail aliases # folder-list list of folder names # out-list list of sent letters that have not been deleted # out-list-current current letter of out list (used in +review) # current_folder current folder (default is inbox) # mail-in-progress boolean indicating if mail message in progress # author_filter dbref|folder~dbref|folder~dbref|folder # subject_filter text|folder~text|folder~text|folder # vacation if set, all incoming mail is stored, but # this text is sent to originator # reject_msg if set, all incoming mail is rejected, and # this text is sent to originator # # per personal distribution list (alias) # # alias- list of dbrefs and/or alias names # # per folder # # in-list- list of messages in folder # current_letter- current letter # # per mail sent item: # # out--time_sent date/time mail was sent # out--subject subject of letter (only for 'old' mail) # out--to TO: (prettified) # out--cc CC: (prettified) # out--bcc BCC: (prettified, used in +review) # out--bcc-expanded dbrefs (used for +read) # out--text body of mail message # out--replyall_to sender, to expanded & cc expanded # out--dist complete distribution list # : # out--held list of who still has a pointer to this letter # # per mail received item: # # in--time_read date/time mail was last read # in--flags U R RR P D M S AAEND # in--note registered via +add note # in--location where letter is stored # # Note: each player has a mailbox. On the Master Mailbox, there is an # attribute per player of the format &mailbox_ which is # set to the dbref of their mailbox. # ############################################################################### # # Several people have asked me about the capability to automatically # generate +mail during the processing of a command. This is easily # done. The key points to remember are: # # Only Players can use the +mail system, therefore, the code that actually # composes and sends the mail will need to be on a Player character. # # The object that does the trigger on the Player character, will either # need to be owned by that same player, or it will need to be wiz-owned. # It will also have to be set inherit. # # The Player that has the attribute which composes mail will need to # have a permanent mailbox. There are several ways to accomplish this, # probably the easiest way is to have that player define a personal # mail alias. Mailboxes with personal mail aliases defined do not # get automatically deleted when empty. # # Example: # # &wage_command Money System = # # $+wage *=* reason=*: # # # # @trigger v(ballybran)/wage_notification= # %#, # , # , # # # (where v(ballybran) holds the dbref of a Player Character and # attribute wage_notification holds the code that actually # composes and sends the +mail) # # &wage_notification *Ballybran = # # In this example: # # %0 - dbref of the invoker of the command # %1 - dbref of who mail is being sent to # %2 - amount of money that %1 received # %3 - reason why %0 deposited money in %1's account # # +mail [name(%1)]=Notification of deposit of wage; # -[name(%0)] has deposited %2 credits into your account.; # -%r%rReason Specified:%b%b%3; # -- # ############################################################################### # # Administrative Configurable Attributes # # Feel free to change as desired before installation, or use the provided # admin commands to change them on the fly later. # ############################################################################### # # This is the mail system-wide default for the 'delete' option. There is # a wiz-only command '+set mail default delete = hard | soft' to change this # and each user may set their own personal default by using command # '+set mail option delete = hard | soft'. Soft deleted messages are just # marked for deletion and are not actually deleted until a +flush is done. # They can be recovered by using a +undelete. Hard deleted messages are # deleted immediately. # # The current value of this is shown in +mail configuration. # # Only set if not already set from a previous release, this is to make # upgrades easier for the installer. # @switch words(get(#3480/DEFAULT_DELETE_OPTION))=0, &DEFAULT_DELETE_OPTION #3480=soft - # # This is the mail system-wide default for the 'mode' option. There is # a wiz-only command '+set mail default mode = terse | verbose' to change # this and each user may set their own personal default by using command # '+set mail option mode = terse | verbose'. Verbose mode gives you more # information on options while writing mail messages. Terse mode is for # when you are familiar with the mail system. # # The current value of this is shown in +mail configuration. # # Only set if not already set from a previous release, this is to make # upgrades easier for the installer. # @switch words(get(#3480/DEFAULT_MODE_OPTION))=0, &DEFAULT_MODE_OPTION #3480=verbose - # # This is the mail system-wide default for if mailboxes should be # automatically deleted when empty. This may be changed by wiz-only # command: '+set mail option destroy = yes | no | true | false | on | off'. # # 1 - true, mailboxes are deleted # 0 - false, mailboxes are not deleted # # The current value of this is shown in +mail configuration. # # Only set if not already set from a previous release, this is to make # upgrades easier for the installer. # @switch words(get(#3480/DELETE_WHEN_EMPTY))=0, &DELETE_WHEN_EMPTY #3480=1 - # # This is the mail system-wide default for the 'timeout' option. There is # a wiz-only command '+set mail default timeout = ' to set # this. Wizards may also set a default for an individual mailbox by using # the '+set mail option timeout = for ' command. # # Letters that haven't been read within the timeout value span, will be # automatically deleted. To further clarify this: It deletes already-read # mail that has not been read within the option-set time limit and it also # deletes mail that has not been read, but was received longer than the # option-set time limit ago. If this results in an empty mailbox, the # mailbox will also be deleted. Halfway to the timeout value, a # letter will show up with a 'T' next to it on a +skim to indicate # it is 1/2 way to the time when it would be deleted. Simply # +read'ing the mail again will remove the 'T'. # # Users may '+save' letters that they don't want to be timed out. # Hopefully, this will be used sparingly. I didn't particularly # want to add it, but the user base asked for it, I can see the # usefulness of it and Joe Average +mail user likely won't notice # the capability is there. ;) # # The value is specified in number of days on the commands, but # stored in seconds. # # Default value is 2 weeks == 1209600 seconds. # # The current value of this is shown in +mail configuration. # # Only set if not already set from a previous release, this is to make # upgrades easier for the installer. # @switch words(get(#3480/DEFAULT_TIMEOUT_OPTION))=0, &DEFAULT_TIMEOUT_OPTION #3480 = 1209600 - # # This is the default day of week and time that the periodic letter # purge will take place. This value can be changed by admins via # the '+set mail default purge= :' # It should be set for a day and time that you think the MUSH # will be the most idle. It will take effect the next time # the @startup is run on the Master Mailbox. # # : # # The current value of this is shown in +mail configuration. # # Only set if not already set from a previous release, this is to make # upgrades easier for the installer. # @switch words(get(#3480/DEFAULT_PURGE_TIME))=0, &DEFAULT_PURGE_TIME #3480 = Wednesday 04:00 - # # This is the mail system-wide default for the 'format' option. There is # a wiz-only command '+set mail default format = standard | compact' to # change this and each user may set their own personal default by using # command '+set mail option format = standard | compact'. 'compact' mode # gives you the same information that 'standard' mode gives you, but # without the formatting lines and extra white-space. # # The current value of this is shown in +mail configuration. # # Only set if not already set from a previous release, this is to make # upgrades easier for the installer. # @switch words(get(#3480/DEFAULT_FORMAT_OPTION))=0, &DEFAULT_FORMAT_OPTION #3480=standard - # # This is attribute specifies whether the +save command is enabled # or disabled for the mail system as a whole. There is a wiz-only # command '+set mail default save = enabled | disabled' to change # this. This cannot be set for individual mailboxes, although # the timeout mechanism can be disabled for a specific mailbox. # # The current value of this is shown in +mail configuration. # # Only set if not already set from a previous release, this is to make # upgrades easier for the installer. # @switch words(get(#3480/DEFAULT_SAVE_OPTION))=0, &DEFAULT_SAVE_OPTION #3480=enabled - # # This is the mail system-wide default for the 'separator' option. There is # a wiz-only command '+set mail default separator = space | return' to change # this and each user may set their own personal default by using command # '+set mail option separator = space | return'. 'space' means that there is # a space inserted between text entered with multiple '-' commands. # A 'return' means that there is a carriage return inserted. # # The current value of this is shown in +mail configuration. # # Only set if not already set from a previous release, this is to make # upgrades easier for the installer. # @switch words(get(#3480/DEFAULT_SEPARATOR_OPTION))=0, &DEFAULT_SEPARATOR_OPTION #3480=space - &DELIVERY_NOTIFICATION #3478= - &DELIVERY_NOTIFICATION #3482= # # This is the message which is pemitted to the person who is receiving a # new mail message. Feel free to customize as desired. # # Note, this is evaluated, so you can put code in there. For example: # # [switch(rand(3), 0, message0, 1, message1, 2, message2)] # # Input: # # %0 - dbref of who the mail is from # %1 - urgent flag set? (1 - yes, 0 - no) # %2 - private flag set? (1 - yes, 0 - no) # %3 - reply requested flag set? (1 - yes, 0 - no) # %4 - registered flag set? (1 - yes, 0 - no) # %5 - folder that letter was stored into # A light blinks on your wrist unit indicating that a new message has been received from [name(%0)] in folder '%5' [switch( or(%1, %2, %3, %4), 1, { %b( [switch(%1, 1, %b[v(mail_flag_u)])] [switch(%2, 1, %b[v(mail_flag_p)])] [switch(%3, 1, %b[v(mail_flag_rr)])] [switch(%4, 1, %b[v(mail_flag_r)])] %b). }, . )] - &PICKUP_NOTIFICATION #3478= - &PICKUP_NOTIFICATION #3482= # # This is the message which is pemitted to the person who is sending a # mail message. Feel free to customize as desired. Yes, it is evaluated # so code can be put in there. # The mail has been sent. - &FORWARD_NOTIFICATION #3478= - &FORWARD_NOTIFICATION #3482= # # This is the message which is pemitted to the person who is forwarding a # mail message. Feel free to customize as desired. Yes, it is evaluated # so code can be put in there. # # %0 - active folder # %1 - user request # Letter %1 in folder '%0' has been forwarded. - &TEXT_ADDED_NOTIFICATION #3478 = - &TEXT_ADDED_NOTIFICATION #3482 = # # This is used when a '-' command is successfully # completed. I know The Way It's Always Been is to not give a prompt, # but I thought it would be nice to get a response to the command; it # occasionally freaks me out when I don't. Feel free to zap this # attribute, of course, if y'all'd prefer not having the prompt. # That's why it is in its own attribute. :) # Text added. - ############################################################################### # # Miscellaneous attributes: # ############################################################################### &MAIL_VERSION #3478= - &MAIL_VERSION #3482=Fri Jun 17, 1994 - &MASTER_MAILBOX #3478= - @VM #3482 = #3480 - &MASTER_MAILBOX #3479= - @VM #3479 = #3480 - &CLEANUP_MODULE #3478= - &CLEANUP_MODULE #3482= - &CLEANUP_MODULE #3479= - &CLEANUP_MODULE #3480= - &MAIL_SYSTEM #3480=#3478 - &MAIL_SYSTEM #3478= - &MAIL_SYSTEM #3482=#3478 - &MAIL_SYSTEM #3479=#3478 - @drain #3480 - @no #3480 - &EQUAL_LINE #3478= - &EQUAL_LINE #3482=repeat(=, 78) - &DASH_LINE #3478= - &DASH_LINE #3482=repeat(-, 78) - # # Text associated with the various mail flags. You can change them here # if you wish. Putting in commas is not advised. # &MAIL_FLAG_RR #3478= - &MAIL_FLAG_RR #3482=REPLY REQUESTED - &MAIL_FLAG_P #3478= - &MAIL_FLAG_P #3482=PRIVATE - &MAIL_FLAG_U #3478= - &MAIL_FLAG_U #3482=URGENT - &MAIL_FLAG_R #3478= - &MAIL_FLAG_R #3482=REGISTERED - &MAIL_FLAG_D #3478= - &MAIL_FLAG_D #3482=MARKED FOR DELETION - &MAIL_FLAG_T #3478= - &MAIL_FLAG_T #3482=TIMEOUT WARNING - &MAIL_FLAG_S #3478= - &MAIL_FLAG_S #3482=SAVED - &MAIL_FLAG_M #3478= - &MAIL_FLAG_M #3482=MARKED - &SECONDS_IN_DAY #3478 = - &SECONDS_IN_DAY #3482 = 86400 - &SECONDS_IN_DAY #3479 = 86400 - &ENTER_MSG_VERBOSE #3478= - &ENTER_MSG_VERBOSE #3482= You may now enter the body of the message.%b This is done by doing a '-' as many times as desired.%b Once you have completed%b entering the message, simply enter a '--' (or +send).%b To see more options,%b type a '-' with no text afterwards. - &ENTER_MSG_TERSE #3478= - &ENTER_MSG_TERSE #3482= You may now enter the body of the message.%b%bFinish with a '--'. %rTo see more options, type a '-' with no text afterwards. - &FINISH_MSG_VERBOSE #3478= - &FINISH_MSG_VERBOSE #3482= Options: +proof, +send, +toss, +cc , +bcc , %r+edit =/ (where mail part=to, cc, bcc, subject or text), %r+set mail flag \[!\] (where flag=urgent (u), private (p), registered (r) or reply requested (rr)) - &FINISH_MSG_TERSE #3478= - &FINISH_MSG_TERSE #3482= Options: %b+proof, +send, +toss, +cc, +bcc, +edit =/ or +set mail flag \[!\] - &NOMAIL #3478= - &NOMAIL #3482= There is no mail in folder '[secure(%0)]'. - &NO_SENT_MAIL #3482 = There is no mail from you remaining in the mail system. - &NOFUNC #3478= - &NOFUNC #3482= I'm sorry, but function calls are not allowed within an input parameter. - &NOT_PLAYER #3482 = You must be a player to use the mail system. - &NOT_WRITING_MAIL #3482 = There is not a mail message in progress. - &NO_MATCH #3482 = %0:%b%bNo letter matches the specified criteria%1 in folder '%2'. - &NO_MAIL_FROM_YOU #3482 = There is no mail from you in %0's mailbox. - &overflow_point #3480= # # This number represent the bytesize (strlen) that a mailboxes_ # can reach before the list of mailbox dbrefs will overflow into the # next attribute, mailboxes_ # # Normally set to 3900, just to be safe. This is in an attribute # exclusively for the reason of ease of testing the overflow code. # 3900 - ############################################################################### # # READ related commands: # ############################################################################### ############################################################################### # # C H E C K M A I L # ############################################################################### &CHECK_MAIL_COMMAND #3478= # # PURPOSE: # # This command may be used to check to see if there is any unread # mail in selected folder of the user's mailbox. If there is unread # mail, the user is notified of how many unread messages there are # in addition to the total number of letters in the folder. # # Command Format: # # +check mail # # NOTE: # # A warning is also displayed if the user's 'mail-in-progress' flag # is set. # # Registers Used: # # 0 - user's mailbox dbref # 1 - list of letters in current folder # 2 - name of active folder # 3 - count of unread letters in current folder # $+check mail: @swi/first [setq(0, get(%vm/mailbox_%#))] 0 = strmatch(type(%#), PLAYER), { @pemit %# = u(not_player) }, strlen(r(0)), { # # User has no mailbox. # @pemit %# = u(nomail, u(get_inbox, %#)) }, { # # Snag the semaphore # @wait r(0) = { @pemit %# = [setq(1, u(get_folder_in_list, r(0)))] [setq(2, u(get_active_folder, r(0)))] [setq(3, switch(strlen(r(1)), 0, 0, words(filter(mail_not_read, r(1)))) )] [switch([strlen(r(1))]+[r(3)], 0+*, u(nomail, r(2)), *+0, You do not have unread mail in your '[r(2)]' mail folder., You have [r(3)] unread mail message(s) out of a total of [words(r(1))] in your '[r(2)]' mail folder. )] [switch(get(r(0)/mail-in-progress), true, %b%b(Warning:%b Your mail in progress flag is set) )]; @no r(0) } } - &MAIL_NOT_READ #3482 = # # This helper function is used while processing a filter() on a list # of letters in a mailbox. Requirements: return 1 if the letter # in question has not been read, return 0 otherwise. Mail that has # not been read has a time_read field of zero. # # %0 - internal mail number # # Assumption: # # r(0) - mailbox dbref # strmatch(get(r(0)/in-%0-time_read), 0) - ############################################################################### # # S K I M # ############################################################################### &SKIM_COMMAND #3478= # # PURPOSE: # # This command may be used to show summary information about mail # in selected folder of the user's mailbox. # # Command Format: # # +skim [keyword or letter number] # # The following keywords may be used to limit the output of +skim: # # all (default), current, deleted, first, last, marked, next, previous, # saved, unread author:, subject:, text: # # only the first character of the keyword needs to be specified # # Registers Used: # # 0 - user's mailbox dbref # 1 - list of letters in current folder # 2 - current letter in active folder # 3 - user's timeout value # 4 - list of internal letters which match the user specified criteria # 9 - user's format option # # skim_bulk reuses 4, and also uses 5-8 # $+skim*: @swi/first [setq(0, get(%vm/mailbox_%#))] 0 = strmatch(type(%#), PLAYER), { @pemit %# = u(not_player) }, not(strmatch(escape(%0), *\[*)), { # # Function calls are not allowed within an input parameter. # @pemit %# = u(nofunc) }, strlen(r(0)), { # # User has no mailbox. # @pemit %# = u(nomail, u(get_inbox, %#)) }, { # # Snag the semaphore # @wait r(0) = { @swi/first [setq(1, u(get_folder_in_list, r(0)))] [setq(2, u(get_folder_current_letter, r(0)))] [setq(3, u(grab_timeout_value, get(r(0)/message_timeout), get(%vm/default_timeout_option)) )] # # register 9 is used to hold the format option so as not to interfere # with registers used in skim_bulk. # [setq(9, u(get_format_option, get(%#/mail_config_options)))] 1 = eq(strlen(r(1)), 0), { # # There is no mail in the mailbox. Notify the user and release the semaphore. # @pemit %# = [u(nomail, u(get_active_folder, r(0)))] [switch(get(r(0)/mail-in-progress), true, %b(Warning:%b Your mail in progress flag is set))]; @no r(0) }, eq(strlen(%0), 0), { # # +skim specified with no params and there IS mail is in the mailbox. # Simulate the user specifying all letters # @pemit %# = [switch(r(9), standard, {[u(equal_line)]%r%r[space(27)]List of Mail Messages%r%r} )] [space(9)]Sender[space(12)]Subject[space(22)]Size%b%bReceived %r[space(9)]------[space(12)]-------[space(22)]----%b%b--------; @dolist r(1) = { @pemit %# = u(skim_bulk, %#, ##, r(0), r(1), r(2), r(3), u(get_src_dbref, r(0), ##), u(get_src_num, r(0), ##)) }; @swi 1 = 1, { # # Finished showing information about the letter(s) specified. # Show the user what the active folder is and release the semaphore. # @pemit %# = [setq(1, u(get_active_folder, r(0)))] [setq(2, s(remove(get(r(0)/folder-list), edit(r(1), %b, $))))] %rSelected folder:%b%b[r(1)] [switch(strlen(r(2)), 0,, %rOther folders:%b%b[u(secure_names, r(2))])] [switch(r(9), standard,%r%r[u(equal_line)])]; @no r(0) } }, { # # User specified a parameter. # # # Interpret user input and convert into a list of internal mail numbers # @swi/first [setq(4, u(expand_letter_range, %0, r(1), u(get_folder_current_letter, r(0))) )] 1 = strmatch(r(4), *ABORT*), { # # Error detected in input parameter. Notify the user and release the semaphore. # @pemit %# = after(before(r(4), ENDABORT), ABORT); @no r(0) }, eq(strlen(r(4)), 0), { # # Could not find any letters to match the specified input parameter. # Notify the user and release the semaphore. # @pemit %# = u(no_match, +skim, u(format_request, trim(%0)), u(get_active_folder, r(0))); @no r(0) }, { # # Otherwise, no error and one or more letters match the input criteria. # @pemit %# = [switch(r(9), standard, {[u(equal_line)] %r%r[space(27)]List of Mail Messages%r%r} )] [space(9)]Sender[space(12)]Subject[space(22)]Size%b%bReceived %r[space(9)]------[space(12)]-------[space(22)]----%b%b--------; @dolist # # Reorder the list of letters to 'skim' into the same order as is in # the in-list- attribute. This is needed due to setunion's distressing # habit of returning sorted lists. # [setq(4, u(filter_list, setunion(r(4), ), r(1)))] r(4) = { # # Display information to user about one letter # @pemit %# = u(skim_bulk, %#, ##, r(0), r(1), r(2), r(3), u(get_src_dbref, r(0), ##), u(get_src_num, r(0), ##)) }; @swi 1 = 1, { # # Finished showing information about the letter(s) specified. # Show the user what the active folder is and release the semaphore. # @pemit %# = [setq(1, u(get_active_folder, r(0)))] [setq(2, s(remove(get(r(0)/folder-list), edit(r(1), %b, $))))] %rSelected folder:%b%b[r(1)] [switch(strlen(r(2)), 0,, %rOther folders:%b%b[u(secure_names, r(2))])] [switch(r(9), standard,%r%r[u(equal_line)])]; @no r(0) } } } } } - &SKIM_BULK #3478= - &SKIM_BULK #3482= # # PURPOSE: # # Obtain summary information for one letter in a mailbox. # (This is a helper routine for +skim) # # INPUT # # %0 - dbref of invoker # %1 - internal mail message number of letter to obtain information about # %2 - dbref of mailbox # %3 - list of letters in folder # %4 - current letter in active folder # %5 - user's timeout value # %6 - dbref of where letter is stored # %7 - internal mail message where letter is stored # # OUTPUT # # A single line of information for the letter specified in %1 # # Don't stomp on registers 0, 1, 2, 3 or 9, they are used in skim_command # Note: registers 4, 7 and 8 are also used in skim_command but may be # stomped on. # # Registers Used: # # 4 - flags for one letter # 5 - external letter number # 6 - name of sender # 7 - subject of letter # 8 - time the letter was read # [setq(4, get(%2/in-%1-flags))] [setq(5, member(%3, %1))] [setq(6, get(%6/out-%7-sender))] [setq(6, switch(words(r(6)), 0, get(%6/owner_dbref), r(6)))] [setq(6, switch(type(r(6)), PLAYER, name(r(6)), destroyed player))] [setq(7, trim(get(%6/out-%7-subject)))] [setq(8, get(%2/in-%1-time_read))] # # a '+' is shown before the summary line that represents the current letter # [switch(%1, %4, +, %b)] # # a 'M' is shown if the letter is marked (via +mark) # a 'D' is shown if the letter is marked for deletion (via +delete), # a 'S' is shown if the letter is marked as 'saved' (via +save) # a 'T' is shown if the letter is close to being timed out # A 'U' is shown if the letter has not been read yet, # otherwise, just a blank # [switch( [gt(match(r(4), m), 0)]+ [gt(match(r(4), d), 0)]+ [gt(match(r(4), s), 0)]+ [r(8)]+ [gte(sub(secs(), convtime(r(8))), div(%5, 2))] , 1+*+*+*+*, M, *+1+*+*+*, D, *+*+1+*+*, S, 0+0+0+0+*, U, 0+0+0+*+1, T, %b )] # # Show a 'n' if there is a note associated with this letter. # [switch(words(get(%2/in-%1-note)), 0, %b, n)] # # The letter number # [rjust([r(5)]\)%b%b, 6)] # # The sender of the letter, the name is truncated to sixteen characters # [ljust(mid(r(6), 0, min(16, strlen(r(6)))), 18)] # # The subject of the letter, truncated to 27 characters # [ljust(mid(r(7), 0, min(27, strlen(r(7)))), 29)] # # Size of the body of the letter, in bytes # [ljust(strlen(u(%6/out-%7-text)), 6)] # # Date and time the letter was received # [mid(get(%6/out-%7-time_sent), 0, 16)] - ############################################################################### # # R E A D # ############################################################################### &READ_COMMAND #3478= # # PURPOSE: # # This command may be used to read one or more mail messages in the # selected folder. # # Command Format: # # +read [keyword or letter number] # # The following keywords may be used to limit the output of +read: # # all, current, deleted, first, last, marked, next, previous, saved, unread # author:, subject:, text: # # Only the first character of the keyword needs to be specified # # A +read with no parameters is equivalent to a +check mail # # Registers Used: # # 0 - user's mailbox dbref # 1 - list of letters in active folder # 2 - name of active folder # 3 - count of unread messages (if no user parameter specified) otherwise, # list of internal mail messages which match user criteria # 4 - user's timeout value # 9 - user's format option # # registers 5 - 8 are used in read_bulk # $+read*: @swi/first [setq(0, get(%vm/mailbox_%#))] 0 = strmatch(type(%#), PLAYER), { @pemit %# = u(not_player) }, not(strmatch(escape(%0), *\[*)), { # # Function calls are not allowed within an input parameter # @pemit %# = u(nofunc) }, strlen(r(0)), { # # User has no mailbox. # @pemit %# = u(nomail, u(get_inbox, %#)) }, { # # Snag the semaphore # @wait r(0) = { @swi/first [setq(1, u(get_folder_in_list, r(0)))] [setq(2, u(get_active_folder, r(0)))] # # register 9 is used to hold the format option so as not to interfere # with registers used in read_bulk. # [setq(9, u(get_format_option, get(%#/mail_config_options)))] 0 = strlen(r(1)), { # # There is no mail in the user's mailbox. Notify the user # and release the semaphore. # @pemit %# = [u(nomail, r(2))] [switch(get(r(0)/mail-in-progress), true, %b(Warning:%b Your mail in progress flag is set))]; @no r(0) }, strlen(%0), { # # +read specified with no params, do a +check mail instead # There IS mail in the user's mailbox. # @pemit %# = [setq(3, switch(strlen(r(1)), 0, 0, words(filter(mail_not_read, r(1)))))] [switch([strlen(r(1))]+[r(3)], 0+*, u(nomail, r(2)), *+0, You do not have unread mail in your '[r(2)]' mail folder., You have [r(3)] unread mail message(s) out of a total of [words(r(1))] in your '[r(2)]' mail folder. )] [switch(get(r(0)/mail-in-progress), true, %b%b(Warning:%b Your mail in progress flag is set) )]; @no r(0) }, { @swi/first # # Interpret user input and convert into a list of internal mail numbers # representing the user specified criteria. # [setq(3, u(expand_letter_range, %0, r(1), u(get_folder_current_letter, r(0)) ) )] 1 = strmatch(r(3), *ABORT*), { # # Error detected in input parameter. # # Notify the user and release the semaphore. # @pemit %# = after(before(r(3), ENDABORT), ABORT); @no r(0) }, eq(strlen(r(3)), 0), { # # Could not find any letters to match the specified input parameter. # # Notify the user and release the semaphore. # @pemit %# = u(no_match, +read, u(format_request, trim(%0)), r(2)); @no r(0) }, { @dolist # # Reorder the list of letters to 'read' into the same order as the # in-list- attribute. This is needed due to setunion's distressing # habit of returning sorted lists. # [setq(3, u(filter_list, setunion(r(3), ), r(1)))] [setq(4, u(grab_timeout_value, get(r(0)/message_timeout), get(%vm/default_timeout_option)) )] r(3) = { # # Display information to user about one letter # @pemit %# = u(read_bulk, %#, r(2), ##, r(1), r(9), r(0), r(4), u(get_src_dbref, r(0), ##), u(get_src_num, r(0), ##)); @tr me/check_if_registered = %#, r(0), ##, u(get_src_dbref, r(0), ##), u(get_src_num, r(0), ##) }; @swi 1 = 1, { # # Set current letter to be the last letter read # &[u(which_current_letter, r(0))] [r(0)] = first(revwords(r(3))); # # Finished showing information about the letter(s) specified. Release # the semaphore. Extra switch is needed to keep the queue accurate. # @swi 1 = 1, { @no r(0) } } } } } } - &READ_BULK #3478= - &READ_BULK #3482= # # PURPOSE: # # Obtain detailed information for one letter in a mailbox. # (This is a helper routine for +read) # # INPUT # # %0 - dbref of invoker # %1 - name of active folder # %2 - internal mail number of letter to obtain information for # %3 - list of letters in active folder # %4 - user's format option # %5 - dbref of mailbox # %6 - user's timeout value # %7 - dbref of where letter is stored # %8 - internal mail message where letter is stored # # OUTPUT # # Detailed display for a single letter # # NOTE: Registers 0, 1, 2, 3, 4 and 9 are set/used in read_command # and shouldn't be stomped on. # # Registers Used: # # 5 - external letter number # 6 - cc for one letter # 7 - flags for one letter # 8 - time the letter was read # [setq(5, match(%3, %2))] [setq(6, get(%7/out-%8-cc))] [setq(7, get(%5/in-%2-flags))] [setq(8, get(%5/in-%2-time_read))] [switch(%4, standard, {[u(equal_line)]%r})] # # Message number # [ljust(Message:%b%b[r(5)]/[words(%3)] in folder %1, 43)] # # Date and time received # Received:%b%b[get(%7/out-%8-time_sent)] # # Name of sender # # (games played here since normally I don't save the 'sender' information # since it is clear who the sender is by where the mail is stored. However, # if the conversion code was used to 'save' mail from older versions, # there will be a sender field, which is the only way to determine sender # at older levels. # %rFrom:[space(5)] [switch(words(get(%7/out-%8-sender)), 0, switch( type(get(%7/owner_dbref)), PLAYER, name(get(%7/owner_dbref)), destroyed player ), switch( type(get(%7/out-%8-sender)), PLAYER, name(get(%7/out-%8-sender)), destroyed player ) )] # # Who the mail was addressed to # %rTo:[space(7)][trim(get(%7/out-%8-to))] # # The CC list # [switch(words(r(6)), 0,,%rCc:[space(7)][trim(r(6))])] # # If the person reading this mail is on the BCC list, show a BCC line # with just that person's name. Other people on the BCC list are not # identified # [switch( match(get(%7/out-%8-bcc-expanded), %0), 0,, %rBcc:[space(6)][name(%0)] )] # # Subject of the letter # %rSubject:%b%b[trim(get(%7/out-%8-subject))] [switch( r(7), *A*,%b\( autoforwarded from [name(after(before(r(7), AEND), A))] \) )] # # If any flags are set, display the flags header text # [switch(words(setinter(r(7), RR P U R D T S M)), 0,, %rFlags:%b%b%b%b)] # # check for the URGENT (U) flag # [switch(match(r(7), u), 0,, [v(mail_flag_u)]%b%b)] # # check for the REQUEST REPLY (RR) flag # [switch(match(r(7), rr), 0,, [v(mail_flag_rr)]%b%b)] # # check for the REGISTERED (R) flag # [switch(match(r(7), r), 0,, [v(mail_flag_r)]%b%b)] # # check for the PRIVATE (P) flag # [switch(match(r(7), p), 0,, [v(mail_flag_p)]%b%b)] # # check for the MARKED FOR DELETION (D) flag # [switch(match(r(7), d), 0,, [v(mail_flag_d)]%b%b)] # # check for the MARKED (M) flag # [switch(match(r(7), m), 0,, [v(mail_flag_m)]%b%b)] # # check for the SAVED (S) flag # [switch(match(r(7), s), 0,, [v(mail_flag_s)]%b%b)] # # check for the TIMEOUT WARNING (T) flag # # (shown if the letter HAS been read, but not within the message # timeout/2 timeframe) and is not marked as 'saved' # [switch( and( eq(match(r(7), s), 0), not(strmatch(r(8), 0)), gte(sub(secs(), convtime(r(8))), div(%6, 2)) ), 0,, { [switch(words(r(7)), 0, %rFlags:%b%b%b%b)][v(mail_flag_t)]%b%b } )] [switch(%4, standard, {%r[u(dash_line)]%r%r},%rText:[space(5)])] # # main body of text # [u(%7/out-%8-text)] # # If there is a note registered with this mail message, show it. # [switch( gt(words(get(%5/in-%2-note)), 0), 1, {[switch(%4, standard, {%r%r[u(dash_line)]})] %rNote:[space(5)][get_eval(%5/in-%2-note)]} )] [switch(%4, standard, {%r%r[u(equal_line)]})] %rOptions:%b +add note=, +delete, +forward, +move, +reply, +replyall, +save - &CHECK_IF_REGISTERED #3482= # # PURPOSE: # # Determine if a receipt notification needs to be sent. A receipt # notification is sent to the originator of a piece of mail when it # has been sent as 'registered' and this is the first time it was # read. # # INPUT # # %0 - dbref of invoker # %1 - dbref of mailbox # %2 - internal mail number of letter just read # %3 - dbref of source mailbox # %4 - internal mail number in source mailbox # # OUTPUT # # None # # Registers used: # # NOTE: Registers 0, 1, 2, 3, 4 and 9 are set/used in read_command # and shouldn't be stomped on. # # 5 - dbref of who to send receipt to # 6 - time read # &in-%2-time_read %1 = [setq(6, get(%1/in-%2-time_read))]time(); @swi/first [setq(5, get(%3/out-%4-sender))] [setq(5, switch(words(r(5)), 0, get(%3/owner_dbref), r(5)))] 1 = and( strmatch(r(6), 0), sign(match(get(%1/in-%2-flags), r)) ), { # # The mail was REGISTERED and this is the first time it was read, send an # acknowledge back to the sender. # @tr me/store_letter = %1, Receipt Notification, name(r(5)), r(5), , , , , , {[name(%0)] has read the message which had a subject line of "[trim(get(%3/out-%4-subject))]" which was originally sent by you on [get(%3/out-%4-time_sent)].} } - ############################################################################### # # U N R E A D # ############################################################################### &UNREAD_COMMAND #3478= # # PURPOSE: # # This command may be used to mark one or more letters previously # read as unread again. # # Command Format: # # +unread # # The following keywords are available to specify the scope of +unread: # # all, current, deleted, first, last, marked, next, previous, saved # author:, subject:, text: # # only the first character of the keyword needs to be specified # # Registers Used: # # 0 - user's mailbox dbref # 1 - list of letters in active folder # 2 - list of internal message numbers reflecting the specified criteria # $+unread*: @swi/first [setq(0, get(%vm/mailbox_%#))] 0 = strmatch(type(%#), PLAYER), { @pemit %# = u(not_player) }, not(strmatch(escape(%0), *\[*)), { # # Function calls are not allowed within input parameters. # @pemit %# = u(nofunc) }, strlen(r(0)), { # # User does not have a mailbox. # @pemit %# = u(nomail, u(get_inbox, %#)) }, { # # Snag the semaphore # @wait r(0) = { @swi/first [setq(1, u(get_folder_in_list, r(0)))] # # Interpret user input and convert into a list of internal mail numbers # [setq(2, u(expand_letter_range, %0, r(1), u(get_folder_current_letter, r(0))) )] 1 = eq(strlen(r(1)), 0), { # # There is no mail in the user's mailbox. Notify the user and # release the semaphore. # @pemit %# = u(nomail, u(get_active_folder, r(0))); @no r(0) }, strmatch(r(2), *ABORT*), { # # Error detected in user input. Notify the user and release the # semaphore. # @pemit %# = after(before(r(2), ENDABORT), ABORT); @no r(0) }, eq(strlen(r(2)), 0), { # # No letters match the user specified criteria. Notify the user # and release the semaphore. # @pemit %# = u(no_match, +unread, u(format_request, trim(%0)), u(get_active_folder, r(0))); @no r(0) }, { # # Reorder the list of letters to 'unread' into the same order as is in # the in-list- attribute. This is needed due to setunion's distressing # habit of returning sorted lists. # @dolist [setq(2, u(filter_list, setunion(r(2), ), r(1)))] r(2) = { # # Zap the time_read field for the specified letter. A value of '0' # for time_read indicates that the letter has not been read yet. # &in-##-time_read [r(0)] = 0 }; @swi 1 = 1, { # # Finished showing information about the letter(s) specified. # Notify user, clean up global variables and release the semaphore. # # # Set 'current letter' to be the last letter marked as unread # &[u(which_current_letter, r(0))] [r(0)] = first(revwords(r(2))); @pemit %# = Letter(s) [u(convert_nums, r(2), r(1))] [u(format_request, trim(%0))] marked as 'unread' in folder '[u(get_active_folder, r(0))]'.; @no r(0) } } } } - ############################################################################### # # A D D N O T E # ############################################################################### &ADD_NOTE_COMMAND #3478= # # PURPOSE: # # This command may be used to store a personal note associated with # the letter specified. This note will show up on subsequent +read's # of this letter. Warning: it is also sent along if the letter it # is associated with is forwarded to another player. # # Command Format: # # +add note to = # # The following keywords are available to specify the scope of +add note: # # current (default), first, last, next, previous # # Only the first character of the keyword needs to be specified # # Registers Used: # # 0 - user's mailbox dbref # 1 - list of letters in active folder # 2 - internal message number reflecting the specified criteria # $+add note to *=*: @swi/first [setq(0, get(%vm/mailbox_%#))] 0 = strmatch(type(%#), PLAYER), { @pemit %# = u(not_player) }, not(strmatch(escape(%0), *\[*)), { # # Function calls are not allowed within input parameters # @pemit %# = u(nofunc) }, strlen(r(0)), { # # User does not have a mailbox # @pemit %# = u(nomail, u(get_inbox, %#)) }, { # # Snag the semaphore # @wait r(0) = { @swi/first [setq(1, u(get_folder_in_list, r(0)))] # # Interpret user input and convert into an internal mail number # [setq(2, u(expand_single_letter_range, trim(%0), r(1), u(get_folder_current_letter, r(0))) )] 1 = eq(strlen(r(1)), 0), { # # Mailbox is empty. Notify user, clear global variable and release # the semaphore. # @pemit %# = u(nomail, u(get_active_folder, r(0))); @no r(0) }, strmatch(r(2), *ABORT*), { # # Error detected in user input. Notify user, clear global variables # and release the semaphore. # @pemit %# = after(before(r(2), ENDABORT), ABORT); @no r(0) }, eq(strlen(r(2)), 0), { # # No letter matches the user specified criteria. Notify the user, # clear the global variables and release the semaphore. # @pemit %# = u(no_match, +add note, u(format_request, trim(%0)), u(get_active_folder, r(0))); @no r(0) }, { # # Store the note with the specified letter, update current_letter, # notify the user of the action taken and release the semaphore. # &in-[r(2)]-note [r(0)] = escape(edit(%1, \\, )); &[u(which_current_letter, r(0))] [r(0)] = r(2); @pemit %# = Note [switch(strlen(%1), 0, removed from, added to)] message [u(convert_nums, r(2), r(1))] [u(format_request, trim(%0))] in folder '[u(get_active_folder, r(0))]'.; @no r(0) } } } - ############################################################################### # # A D D N O T E # # part 2 (added for user convenience) # ############################################################################### &ADD_NOTE_2_COMMAND #3478= $+add note=*: @swi/first [setq(0, get(%vm/mailbox_%#))] 0 = strmatch(type(%#), PLAYER), { @pemit %# = u(not_player) }, strlen(r(0)), { # # User does not have a mailbox # @pemit %# = u(nomail, u(get_inbox, %#)) }, { # # Snag the semaphore # @wait r(0) = { @swi/first [setq(1, u(get_folder_in_list, r(0)))] [setq(2, u(get_folder_current_letter, r(0))))] 1 = eq(strlen(r(1)), 0), { # # Mailbox is empty. Notify user, clear global variable and release # the semaphore. # @pemit %# = u(nomail, u(get_active_folder, r(0))); @no r(0) }, { # # Store the note with the current letter, # notify the user of the action taken and release the semaphore. # &in-[r(2)]-note [r(0)] = escape(edit(%0, \\, )); @pemit %# = Note [switch(strlen(%0), 0, removed from, added to)] message [u(convert_nums, r(2), r(1))] (%bcurrent%b) in folder '[u(get_active_folder, r(0))]'.; @no r(0) } } } - &ADD_NOTE #3478 = $+add note: @pemit %# = The syntax is +add note to =. - ############################################################################### # # D E L E T E # ############################################################################### &DELETE_COMMAND #3478= # # PURPOSE: # # This command may be used to delete one or more of the messages in # a mailbox. +delete with no parameters will delete the last mail # message read. Either a keyword (listed below) or a list of # mail numbers may be specified. Example: +delete 3..5, +delete marked # # Command Format: # # +delete # # The following keywords are available to specify the scope of +delete: # # all, current (default), first, last, marked, next, previous, saved, # unread, author:, subject:, text: # # Only the first character of the keyword needs to be specified # # Registers Used: # # 0 - user's mailbox dbref # 1 - list of letters in active folder # 2 - list of internal message numbers reflecting the specified criteria # 3 - new current letter # 4 - external message numbers to delete # 5 - current folder # 6 - user's delete option # $+delete*: @swi/first [setq(0, get(%vm/mailbox_%#))] 0 = strmatch(type(%#), PLAYER), { @pemit %# = u(not_player) }, not(strmatch(escape(%0), *\[*)), { # # Function calls are not allowed within an input parameter. # @pemit %# = u(nofunc) }, strlen(r(0)), { # # User has no mailbox. # @pemit %# = u(nomail, u(get_inbox, %#)) }, { # # Snag the semaphore # @wait r(0) = { @swi/first [setq(1, u(get_folder_in_list, r(0)))] [setq(6, u(get_delete_option, %#))] # # Interpret user input and convert into a list of internal mail numbers # [setq(2, u(expand_letter_range, %0, r(1), u(get_folder_current_letter, r(0))) )] [setq(5, u(get_active_folder, r(0)))] 1 = eq(strlen(r(1)), 0), { # # Mailbox is empty. Notify user and release the semaphore. # @pemit %# = u(nomail, r(5)); @no r(0) }, strmatch(r(2), *ABORT*), { # # Error detected in input parameter. Notify user and release the semaphore. # @pemit %# = after(before(r(2), ENDABORT), ABORT); @no r(0) }, eq(strlen(r(0)), 0), { # # No letters match the specified user input criteria. Notify user # and release the semaphore. # @pemit %# = u(no_match, +delete, u(format_request, trim(%0)), r(5)); @no r(0) }, { @dolist # # Reorder the list of letters to delete into the same order as is in # the in-list- attribute. This is needed due to setunion's distressing # habit of returning sorted lists. # [setq(2, u(filter_list, setunion(r(2), ), r(1)))] # Temp variable. List of in-list after deletions. [setq(3, s(u(filter_list, setdiff(r(1), r(2)), r(1))))] # # Determine what the 'current letter' will be after all requested # deletions have occurred. If the last letter in the in-list- is # deleted, set 'current letter' to the first letter in the in-list-. # Otherwise, set 'current letter' to the letter after the last # one deleted if hard deleted, and the last letter marked for deletion, # if soft deleted. # [setq(3, switch(r(6), soft, first(revwords(r(2))), switch(first(revwords(r(2))), first(revwords(r(1))), first(r(3)), extract(r(1), add(match(r(1), first(revwords(r(2)))), 1), 1))))] # # Convert the list of internal mail numbers to external mail numbers # for use in later display to the user. # [setq(4, u(convert_nums, r(2), r(1)))] r(2) = { @swi r(6) = soft, { # # User has their mail configuration option 'delete' set to soft. Simply # mark the bugger for deletion # &in-##-flags [r(0)] = setunion(get(r(0)/in-##-flags) D, ) }, { # # Hard delete. # @tr me/remove_letter = u(get_src_dbref, r(0), ##), u(get_src_num, r(0), ##), %#, r(0), ##, edit(r(5), %b, $) } }; @swi 1 = 1, { # # Done processing the +delete command. Notify user of action taken. # ¤t_letter-[r(5)] [r(0)] = r(3); @pemit %# = Message(s) [r(4)] [u(format_request, trim(%0))] [switch(u(get_delete_option, %#), hard, deleted from, marked for deletion in)] folder '[r(5)]'.; @no r(0) } } } } - &CLEANUP_DELETE #3482= - ############################################################################### # # U N D E L E T E # ############################################################################### &UNDELETE_COMMAND #3478= # # PURPOSE: # # This command may be used to remove the 'marked for deletion' flag # previously set by a 'soft' +delete. Either a keyword (listed below) # or a list of letter numbers as shown on a +read or +skim may be # specified. Example: +undelete 3 or +undelete marked # # Command Format: # # +undelete # # The following keywords are available to specify the scope of +undelete: # # all, current (default), deleted, first, last, marked, next, previous, # saved, unread, author:, subject:, text: # # Only the first character of the keyword needs to be specified # # Registers Used: # # 0 - user's mailbox dbref # 1 - list of letters in active folder # 2 - list of internal message numbers reflecting the specified criteria # $+undelete*: @swi/first [setq(0, get(%vm/mailbox_%#))] 0 = strmatch(type(%#), PLAYER), { @pemit %# = u(not_player) }, not(strmatch(escape(%0), *\[*)), { # # Function calls are not allowed within an input parameter. # @pemit %# = u(nofunc) }, strlen(r(0)), { # # User has no mailbox. # @pemit %# = u(nomail, u(get_inbox, %#)) }, { # # Snag the semaphore # @wait r(0) = { @swi/first [setq(1, u(get_folder_in_list, r(0)))] # # Interpret user input and convert into a list of internal mail numbers # [setq(2, u(expand_letter_range, %0, r(1), u(get_folder_current_letter, r(0))) )] 1 = eq(strlen(r(1)), 0), { # # There is no mail in the user's mailbox. Notify the user # and release the semaphore. # @pemit %# = u(nomail, u(get_active_folder, r(0))); @no r(0) }, strmatch(r(2), *ABORT*), { # # Error detected in input parameter. Notify the user and release the semaphore. # @pemit %# = after(before(r(2), ENDABORT), ABORT); @no r(0) }, eq(strlen(r(2)), 0), { # # Could not find any letters to match the specified input parameter. # Notify the user and release the semaphore. # @pemit %# = u(no_match, +undelete, u(format_request, trim(%0)), u(get_active_folder, r(0))); @no r(0) }, { @dolist # # Reorder the list of letters to 'undelete' into the same order as is in # the in-list- attribute. This is needed due to setunion's distressing # habit of returning sorted lists. # [setq(2, u(filter_list, setunion(r(2), ), r(1)))] r(2) = { &in-##-flags [r(0)] = s(remove(get(r(0)/in-##-flags), D)) }; @swi 1 = 1, { # # Finished removing the 'marked for deletion' flag from the letter(s) # specified. Set 'current letter' to be the last letter that had the # marked for deletion flag removed from it. Notify the user and release # the semaphore. # &[u(which_current_letter, r(0))] [r(0)] = first(revwords(r(2))); @pemit %# = 'Marked for deletion' flag(s) removed from message(s) [u(convert_nums, r(2), r(1))] [u(format_request, trim(%0))] in folder '[u(get_active_folder, r(0))]'.; @no r(0) } } } } - ############################################################################### # # C L E A R # (alias for +delete) # ############################################################################### &CLEAR_COMMAND #3478= # # PURPOSE: # # This command may be used to clear one or more of the messages in # a mailbox. +clear with no parameters will delete the last mail # message read. Either a keyword (listed below) or a list of # mail numbers may be specified. Example: +clear 3..5, +clear marked # # Command Format: # # +clear # # The following keywords are available to specify the scope of +clear: # # all, current (default), first, last, marked, next, previous, saved, unread # # Only the first character of the keyword needs to be specified # # Registers Used: # # 0 - user's mailbox dbref # 1 - list of letters in active folder # 2 - list of internal message numbers reflecting the specified criteria # 3 - new current letter # 4 - external message numbers to delete # 5 - current folder # 6 - user's delete option # $+clear*: @swi/first [setq(0, get(%vm/mailbox_%#))] 0 = strmatch(type(%#), PLAYER), { @pemit %# = u(not_player) }, not(strmatch(escape(%0), *\[*)), { # # Function calls are not allowed within an input parameter. # @pemit %# = u(nofunc) }, strlen(r(0)), { # # User has no mailbox. # @pemit %# = u(nomail, u(get_inbox, %#)) }, { # # Snag the semaphore # @wait r(0) = { @swi/first [setq(1, u(get_folder_in_list, r(0)))] # # Interpret user input and convert into a list of internal mail numbers # [setq(2, u(expand_letter_range, %0, r(1), u(get_folder_current_letter, r(0))) )] [setq(5, u(get_active_folder, r(0)))] [setq(6, u(get_delete_option, %#))] 1 = eq(strlen(r(1)), 0), { # # Mailbox is empty. Notify user and release the semaphore. # @pemit %# = u(nomail, r(5)); @no r(0) }, strmatch(r(2), *ABORT*), { # # Error detected in input parameter. Notify user and release the semaphore. # @pemit %# = after(before(r(2), ENDABORT), ABORT); @no r(0) }, eq(strlen(r(0)), 0), { # # No letters match the specified user input criteria. Notify user # and release the semaphore. # @pemit %# = u(no_match, +clear, u(format_request, trim(%0)), r(5)); @no r(0) }, { @dolist # # Reorder the list of letters to delete into the same order as is in # the in-list- attribute. This is needed due to setunion's distressing # habit of returning sorted lists. # [setq(2, u(filter_list, setunion(r(2), ), r(1)))] # Temp variable. List of in-list after deletions. [setq(3, s(u(filter_list, setdiff(r(1), r(2)), r(1))))] # # Determine what the 'current letter' will be after all requested # deletions have occurred. If the last letter in the in-list- is # deleted, set 'current letter' to the first letter in the in-list-. # Otherwise, set 'current letter' to the letter after the last # one deleted. # [setq(3, switch(r(6), soft, first(revwords(r(2))), switch(first(revwords(r(2))), first(revwords(r(1))), first(r(3)), extract(r(1), add(match(r(1), first(revwords(r(2)))), 1), 1))))] # # Convert the list of internal mail numbers to external mail numbers # for use in later display to the user. # [setq(4, u(convert_nums, r(2), r(1)))] r(2) = { @swi r(6) = soft, { # # User has their mail configuration option 'delete' set to soft. Simply # mark the bugger for deletion # &in-##-flags [r(0)] = setunion(get(r(0)/in-##-flags) D, ) }, { # # Hard delete. # @tr me/remove_letter = u(get_src_dbref, r(0), ##), u(get_src_num, r(0), ##), %#, r(0), ##, edit(r(5), %b, $) } }; @swi 1 = 1, { # # Done processing the +clear command. Notify user of action taken. # ¤t_letter-[r(5)] [r(0)] = r(3); @pemit %# = Message(s) [r(4)] [u(format_request, trim(%0))] [switch(u(get_delete_option, %#), hard, cleared from, marked for deletion in)] folder '[r(5)]'.; @no r(0) } } } } - ############################################################################### # # F L U S H # ############################################################################### &FLUSH_COMMAND #3478= # # PURPOSE: # # This command may be used to flush (delete) all messages that have # been targeted for deletion by doing a soft delete. These messages # show up with a 'D' next to their number on a +skim. # # Command Format: # # +flush # # Registers Used: # # 0 - dbref of mailbox # 1 - list of letters in folder # 2 - count of messages before flush # 4 - count of messages after flush # 5 - internal list of letters to flush # 8 - active folder # 9 - new current_letter- # $+flush: @swi [setq(0, get(%vm/mailbox_%#))] 0 = strmatch(type(%#), PLAYER), { @pemit %# = u(not_player) }, strlen(r(0)), { @pemit %# = There is no mail marked for deletion in folder '[u(get_inbox, %#)]'. }, { # # Snag the semaphore # @wait r(0) = { @swi/first [setq(1, u(get_folder_in_list, r(0)))] [setq(5, u(find_letters_to_flush, r(0), r(1)))] [setq(8, u(get_active_folder, r(0)))] [setq(9, s(u(filter_list, setdiff(r(1), r(5)), r(1))))] [setq(9, switch( first(revwords(r(5))), first(revwords(r(1))), first(r(9)), extract( r(1), add(member(r(1), first(revwords(r(5)))), 1), 1 ) ) )] 0 = strlen(r(1)), { # # There is no mail in the user's mailbox. Notify the user # and release the semaphore. # @pemit %# = There is no mail marked for deletion in folder '[r(8)]'.; @no r(0) }, words(r(5)), { @pemit %# = There is no mail marked for deletion in folder '[r(8)]'.; @no r(0) }, { @dolist # # Temporarily save away a count of how many messages are in the mailbox. # [setq(2, words(r(1)))] r(5) = { @tr me/remove_letter = u(get_src_dbref, r(0), ##), u(get_src_num, r(0), ##), %#, r(0), ##, edit(r(8), %b, $) }; @swi 1 = 1, { # # Done purusing the mailbox, perform cleanup processing. # @pemit %# = [setq(4, words(r(5)))] All messages that were marked for deletion have been deleted from folder '[r(8)]'. (%b[r(4)] deleted, [sub(r(2), r(4))] remain%b); &[u(which_current_letter, r(0))] [r(0)] = r(9); @no r(0) } } } } - &FIND_LETTERS_TO_FLUSH #3482 = # # PURPOSE: # # This is a helper routine for +flush. Scan through the list of received # +mail messages, and return a list of internal mail numbers for any # that have the 'D' (marked for deletion) flag set. # # %0 - mailbox dbref # %1 - in-list for active folder # iter(%1, switch(member(get(%0/in-##-flags), D), 0,, ##)) - ############################################################################### # # R E P L Y # ############################################################################### &REPLY_COMMAND #3478= # # PURPOSE: # # This command may be used to reply to a received mail message. A +reply # with no parameter specified will reply to the last message read. A # +reply with a specified will reply to the specified # message. The destination will be set to where the original letter came # from, the subject will be the same as the original letter, with a 'Re: ' # prefixed to it. # # Command Format: # # +reply [keyword or letter number] # # The following keywords are available to specify which letter to reply to: # # current (default), first, last, next, previous # # Only the first character of the keyword needs to be specified. # # Registers Used: # # 0 - dbref of mailbox # 1 - list of letters in folder # 2 - internal message number reflecting the specified criteria # 3 - subject of letter to reply to # 4 - dbref of source mailbox # 5 - internal number of source mail in source mailbox # 6 - originator of mail to reply to # $+reply*: @swi/first [setq(0, get(%vm/mailbox_%#))] 1 = strmatch(%0, all*),, # # +replyall - ignore # not(strmatch(type(%#), PLAYER)), { @pemit %# = u(not_player) }, strmatch(escape(%0), *\[*), { # # Function calls are not allowed within an input parameter. # @pemit %# = u(nofunc) }, eq(strlen(r(0)), 0), { # # User has no mailbox. # @pemit %# = u(nomail, u(get_inbox, %#)) }, { # # Snag the semaphore # @wait r(0) = { @swi/first [setq(1, u(get_folder_in_list, r(0)))] # # Interpret user input and convert into an internal mail number # [setq(2, u(expand_single_letter_range, trim(%0), r(1), u(get_folder_current_letter, r(0))))] [setq(4, u(get_src_dbref, r(0), r(2)))] [setq(5, u(get_src_num, r(0), r(2)))] [setq(6, get(r(4)/out-[r(5)]-sender))] [setq(6, switch(words(r(6)), 0, get(r(4)/owner_dbref), r(6)))] 1 = strmatch(get(r(0)/mail-in-progress), true), { # # Mail message is already in progress. Notify user # and release the semaphore. # @pemit %# = You are already in the middle of sending a message. You must complete that one before you reply to this one.; @no r(0) }, eq(strlen(r(1)), 0), { # # There is no mail in the user's mailbox. Notify user and release # the semaphore. # @pemit %# = u(nomail, u(get_active_folder, r(0))); @no r(0) }, strmatch(r(2), *ABORT*), { # # Error detected in input parameter. Notify the user and release the # semaphore. # @pemit %# = after(before(r(2), ENDABORT), ABORT); @no r(0) }, eq(strlen(r(2)), 0), { # # Could not find any letter to match the specified input parameter. # Notify the user and release the semaphore. # @pemit %# = u(no_match, +reply, u(format_request, trim(%0)), u(get_active_folder, r(0))); @no r(0) }, not(strmatch(type(r(6)), PLAYER)), { # # Original sender is no longer a player. # Notify the user and release the semaphore. # @pemit %# = Originator of letter [u(convert_nums, r(2), r(1))][u(format_request, trim(%0))] in folder '[u(get_active_folder, r(0))]' is no longer a player.; @no r(0) }, { # # - Set current letter to the letter being replied to # - Set mail-in-progress to true # - Preset 'to' list and 'subject' based on letter being replied to # - Let user know what to do next # - Release the semaphore # &[u(which_current_letter, r(0))] [r(0)] = r(2); &mail-in-progress [r(0)] = true; &mail-in-progress-to [r(0)] = name(r(6)); &mail-in-progress-to-expanded [r(0)] = r(6); &mail-in-progress-subject [r(0)] = [setq(3, get(r(4)/out-[r(5)]-subject))] switch(mid(r(3), 0, 3), Re:, r(3), Re:%b%b[r(3)]); @pemit %# = switch( u(get_mode_option, %#), verbose, u(enter_msg_verbose), u(enter_msg_terse) ); @no r(0) } } } - ############################################################################### # # R E P L Y A L L # ############################################################################### &REPLYALL_COMMAND #3478= # # PURPOSE: # # This command may be used to send a reply to all recipients of a # specified mail message. A +replyall with no parameter specified # will reply to the last message read. A +replyall with a # specified will reply to the specified # message. The subject will be the same as the original letter, # with a 'Re: ' prefixed to it. # # Command Format: # # +replyall [keyword or letter number] # # The following keywords are available to specify which letter to reply to: # # current (default), first, last, next, previous # # Only the first character of the keyword needs to be specified. # # Registers Used: # # 0 - dbref of mailbox # 1 - list of letters in folder # 2 - internal message number reflecting the specified criteria # 3 - subject of letter to reply to # 4 - dbref of source mailbox # 5 - internal number of source mail in source mailbox # $+replyall*: @swi/first [setq(0, get(%vm/mailbox_%#))] 1 = not(strmatch(type(%#), PLAYER)), { @pemit %# = u(not_player) }, strmatch(escape(%0), *\[*), { # # Function calls are not allowed within an input parameter. # @pemit %# = u(nofunc) }, eq(strlen(r(0)), 0), { # # User has no mailbox. # @pemit %# = u(nomail, u(get_inbox, %#)) }, { # # Snag the semaphore # @wait r(0) = { @swi/first [setq(1, u(get_folder_in_list, r(0)))] # # Interpret user input and convert into an internal mail number # [setq(2, u(expand_single_letter_range, trim(%0), r(1), u(get_folder_current_letter, r(0))))] [setq(4, u(get_src_dbref, r(0), r(2)))] [setq(5, u(get_src_num, r(0), r(2)))] 1 = strmatch(get(r(0)/mail-in-progress), true), { # # Mail message is already in progress. Notify user and release the semaphore. # @pemit %# = You are already in the middle of sending a message. You must complete that one before you reply to this one.; @no r(0) }, eq(strlen(r(1)), 0), { # # There is no mail in the user's mailbox. Notify user and release the # semaphore. # @pemit %# = u(nomail, u(get_active_folder, r(0))); @no r(0) }, strmatch(r(2), *ABORT*), { # # Error detected in input parameter. Notify the user and release the semaphore. # @pemit %# = after(before(r(2), ENDABORT), ABORT); @no r(0) }, eq(strlen(r(2)), 0), { # Could not find any letter to match the specified input parameter. # Notify the user and release the semaphore. # @pemit %# = u(no_match, +replyall, u(format_request, trim(%0)), u(get_active_folder, r(0))); @no r(0) }, eq(words(get(r(4)/out-[r(5)]-replyall_to)), 0), { # # no 'replyall_to' attribute exists for the letter specified, # unable to perform a +replyall. # @pemit %# = +replyall:%b%bUnable to perform this function on the specified letter[u(format_request, trim(%0))] in folder '[u(get_active_folder, r(0))]'.; @no r(0) }, { # # - Set current letter to the letter being replied to # - Set mail-in-progress to true # - Preset 'to' list and 'subject' based on letter being replied to # - Let user know what to do next # - Release the semaphore # &[u(which_current_letter, r(0))] [r(0)] = r(2); &mail-in-progress [r(0)] = true; &mail-in-progress-to [r(0)] = u(format_names, get(r(4)/out-[r(5)]-replyall_to)); &mail-in-progress-to-expanded [r(0)] = get(r(4)/out-[r(5)]-replyall_to); &mail-in-progress-subject [r(0)] = [setq(3, get(r(4)/out-[r(5)]-subject))] switch(mid(r(3), 0, 3), Re:, r(3), Re:%b%b[r(3)]); @pemit %# = switch( u(get_mode_option, %#), verbose, u(enter_msg_verbose), u(enter_msg_terse) ); @no r(0) } } } - ############################################################################### # # F O R W A R D # ############################################################################### &FORWARD_MAIL #3478= # # PURPOSE: # # This command may be used to reply to forward a piece of received mail # to a list of destinations. +forward to will # forward the current letter. +forward to # will forward the letter specified. The # subject line will be the same as the original letter, with a 'Fwd: ' # prefixed to it. Text within the letter cannot be changed. # # Command Format: # # +forward [keyword or letter number] to # # The following keywords are available to specify which letter to +forward: # # current (default), first, last, next, previous # # Only the first character of the keyword needs to be specified. # # NOTE: # # If a note is registered with the letter (by having previously done # a +add note to =, this note will be carrying along with # the forwarded message. # # Registers Used: # # 0 - dbref of mailbox # 1 - list of letters in folder # 2 - holds the internal message number of the mail to forward # 3 - dbrefs of player names use specified to forward to and then later # it holds the dbref of a single player to forward the mail to # 4 - aliases specified of who to forward to, also used to hold # the subject, and another time to hold the note # 5 - player dbrefs + alias names expanded into player dbrefs # 6 - aliases specified identified as personal or global # 7 - dbref of mailbox to write into # 8 - used lots, in one case to hold the subject # in another to hold the note, in another to be the internal # mail number to write into. # # Yuck. # $+forward* to *: @swi/first [setq(0, get(%vm/mailbox_%#))] 1 = not(strmatch(type(%#), PLAYER)), { @pemit %# = u(not_player) }, or( strmatch(escape(%0), *\[*), strmatch(escape(%1), *\[*) ), { # # Function calls are not allowed within an input parameter. # @pemit %# = u(nofunc) }, eq(strlen(r(0)), 0), { # # User has no mailbox. # @pemit %# = u(nomail, u(get_inbox)) }, { # # Snag the semaphore # @wait r(0) = { @swi/first [setq(1, u(get_folder_in_list, r(0)))] # # Interpret user input and convert into an internal mail number # [setq(2, u(expand_single_letter_range, trim(%0), r(1), u(get_folder_current_letter, r(0)) ) )] # # Convert list of names specified by the user into dbrefs # [setq(3, u(identify_to_list, {%1}, r(0)))] # 4, 7, 8 are just temp/working registers and are stomped on later [setq(7, get(%vm/global-mail-aliases))] [setq(8, get(r(0)/alias-list))] [setq(4, u(get_aliases, {%1}, r(0), r(7), r(8)))] # 5 - 'real' list of destinations (dbrefs) [setq(5, setunion([r(3)] [u(expand_aliases, r(4), r(0), %b, r(7), r(8))], ) )] # 6 - 'pretty' list of destinations, for use in display to the user [setq(6, [u(pretty_dist, r(4), r(0), r(8), r(7), r(3))] )] 0 = strlen(%1), { # # No destination specified for who to forward the letter to. Notify user # and release the semaphore. # @pemit %# = You must specify a destination to forward this piece of mail to.; @no r(0) }, strlen(r(1)), { # # There is no mail in the user's mailbox. Notify user # and release the semaphore. # @pemit %# = u(nomail, u(get_active_folder, r(0))); @no r(0) }, not(strmatch(r(2), *ABORT*)), { # # Error detected in input parameter. Notify user and release the semaphore. # @pemit %# = after(before(r(2), ENDABORT), ABORT); @no r(0) }, strlen(r(2)), { # # Could not find a letter to match the specified input parameter. # Notify user and release the semaphore. # @pemit %# = u(no_match, +forward, u(format_request, trim(%0)), u(get_active_folder, r(0))); @no r(0) }, not(strmatch(r(3), *ABORT*)), { # # Error detected in input parameter. Notify user # and release the semaphore. # @pemit %# = secure(after(before(r(3), ENDABORT), ABORT)); @no r(0) }, { @trigger me/store_letter = [setq(3, u(get_src_dbref, r(0), r(2)))] [setq(4, u(get_src_num, r(0), r(2)))] [setq(7, get(r(3)/out-[r(4)]-sender))] [setq(7, switch(words(r(7)), 0, get(r(3)/owner_dbref), r(7)))] [setq(8, get(r(3)/out-[r(4)]-subject))] [setq(9, get(r(0)/in-[r(2)]-note))] r(0), switch(mid(r(8), 0, 4), Fwd:, r(8), Fwd:%b%b[r(8)]), r(6), r(5), , , , , , {Received from:%b%b [name(r(7))] %r[u(r(3)/out-[r(4)]-text)] [switch( words(r(9)), 0,, %r%r[u(dash_line)] %r%N's comment section: %r%r[r(9)] )]}; &[u(which_current_letter, r(0))] [r(0)] = r(2); @pemit %# = u(forward_notification, u(get_active_folder, r(0)), [u(convert_nums, r(2), r(1))] [u(format_request, trim(%0))]); @no r(0) } } } - &FORWARD_COMMAND #3478= $+forward: @pemit %# = u(#3481/forward_help) - ############################################################################### # # F O R W A R D # # Second version # ############################################################################### &FORWARD_MAIL2 #3478= # # PURPOSE: # # This command may be used to forward a received mail message to one # or more destinations. You will be allowed to add text via '-' # before sending it. The subject will be the same as the original # letter, with a 'Fwd: ' prefixed to it. # # This command is being provided for compatibility with Amberyl's # mailer. # # Command Format: # # +forward =[keyword or letter number] # # The following keywords are available to specify which letter to forward: # # current (default), first, last, next, previous # # Only the first character of the keyword needs to be specified. # # Registers Used: # # 0 - dbref of mailbox # 1 - list of letters in folder # 2 - internal message number reflecting the specified criteria # 3 - list of dbrefs associated with names entered for who to forward to # 4 - list of aliases to forward to # 5 - 'real' list of destinations (dbrefs) # 6 - 'pretty' list of destinations # 7 - global mail aliases # 8 - personal mail aliases # 9 - subject of letter to forward # $+forward *=*: @swi/first [setq(0, get(%vm/mailbox_%#))] 1 = not(strmatch(type(%#), PLAYER)), { @pemit %# = u(not_player) }, or( strmatch(escape(%0), *\[*), strmatch(escape(%1), *\[*) ), { # # Function calls are not allowed within an input parameter. # @pemit %# = u(nofunc) }, eq(strlen(r(0)), 0), { # # User has no mailbox. # @pemit %# = u(nomail, u(get_inbox)) }, { # # Snag the semaphore # @wait r(0) = { @swi/first # Get list of letters for the active folder [setq(1, u(get_folder_in_list, r(0)))] # Interpret user input and convert into an internal mail number [setq(2, u(expand_single_letter_range, trim(%1), r(1), u(get_folder_current_letter, r(0))))] # Convert list of names specified by the user into dbrefs [setq(3, u(identify_to_list, {%0}, r(0)))] # Global mail aliases [setq(7, get(%vm/global-mail-aliases))] # Personal mail aliases [setq(8, get(r(0)/alias-list))] # List of aliases specified by the user for who to forward to [setq(4, u(get_aliases, {%0}, r(0), r(7), r(8)))] # 'real' list of destinations (dbrefs) [setq(5, setunion([r(3)] [u(expand_aliases, r(4), r(0), %b, r(7), r(8))], ) )] # 'pretty' list of destinations, for use in display to the user [setq(6, [u(pretty_dist, r(4), r(0), r(8), r(7), r(3))] )] 1 = eq(strlen(%0), 0), { # # No destination specified for who to forward the letter to. Notify user # and release the semaphore. # @pemit %# = You must specify a destination to forward this piece of mail to.; @no r(0) }, strmatch(get(r(0)/mail-in-progress), true), { # # Mail message is already in progress. Notify user # and release the semaphore. # @pemit %# = You are already in the middle of sending a message. You must complete that one before you can forward another.; @no r(0) }, eq(strlen(r(1)), 0), { # # There is no mail in the user's mailbox. Notify user and release # the semaphore. # @pemit %# = u(nomail, u(get_active_folder, r(0))); @no r(0) }, strmatch(r(2), *ABORT*), { # # Error detected in input parameter. Notify the user and release the # semaphore. # @pemit %# = after(before(r(2), ENDABORT), ABORT); @no r(0) }, eq(strlen(r(2)), 0), { # # Could not find any letter to match the specified input parameter. # Notify the user and release the semaphore. # @pemit %# = u(no_match, +forward, u(format_request, trim(%1)), u(get_active_folder, r(0))); @no r(0) }, strmatch(r(3), *ABORT*), { # # Error detected in input parameter. Notify user # and release the semaphore. # @pemit %# = secure(after(before(r(3), ENDABORT), ABORT)); @no r(0) }, { # # - Set current letter to the letter being forwarded # - Set mail-in-progress to true # - Preset body and subject based on letter being forwarded # - Let user know what to do next # - Release the semaphore # &[u(which_current_letter, r(0))] [r(0)] = r(2); &mail-in-progress [r(0)] = true; &mail-in-progress-to [r(0)] = r(6); &mail-in-progress-to-expanded [r(0)] = r(5); &mail-in-progress-body [r(0)] = [u(u(get_src_dbref, r(0), r(2))/ out-[u(get_src_num, r(0), r(2))]-text)] %r%r---- Below this line are comments added by %N ----%r; &mail-in-progress-subject [r(0)] = [setq(9, u(u(get_src_dbref, r(0), r(2))/ out-[u(get_src_num, r(0), r(2))]-subject))] switch(mid(r(9), 0, 4), Fwd:, r(9), Fwd:%b%b[r(9)]); @pemit %# = You may now enter text to send along with the message to forward.; @no r(0) } } } - ############################################################################### # # M A R K # ############################################################################### &MARK_COMMAND #3478= # # PURPOSE: # # This command may be used to tag one or more of the messages in # a mailbox for future operations. +mark with no parameter will # mark the last mail message read. Either a keyword (listed below) # or a list of mail numbers may be specified. Example: +mark 3..5, # +mark unread # # Command Format: # # +mark [keyword or a list of letter numbers] # # The following keywords are available to specify the scope of +mark: # # all, current (default), deleted, first, last, next, previous, # saved, unread, author:, subject:, text: # # Only the first character of the keyword needs to be specified # # Registers Used: # # 0 - user's mailbox dbref # 1 - list of letters in active folder # 2 - new current letter # 3 - name of active folder # 4 - list of internal message numbers reflecting the specified criteria # $+mark*: @swi/first [setq(0, get(%vm/mailbox_%#))] 1 = not(strmatch(type(%#), PLAYER)), { @pemit %# = u(not_player) }, strmatch(escape(%0), *\[*), { # # Function calls are not allowed within an input parameter. # @pemit %# = u(nofunc) }, eq(strlen(r(0)), 0), { # # User has no mailbox. # @pemit %# = u(nomail, u(get_inbox, %#)) }, { # # Snag the semaphore # @wait r(0) = { @swi/first [setq(1, u(get_folder_in_list, r(0)))] [setq(2, u(get_folder_current_letter, r(0)))] [setq(3, u(get_active_folder, r(0)))] # # Interpret user input and convert into a list of internal mail numbers # [setq(4, u(expand_letter_range, %0, r(1), r(2)))] 0 = strlen(r(1)), { # # There is no mail in the user's mailbox. Notify the user and # release the semaphore. # @pemit %# = u(nomail, r(3)); @no r(0) }, not(strmatch(r(4), *ABORT*)), { # # Error detected in input parameter. Notify the user # and release the semaphore. # @pemit %# = after(before(r(4), ENDABORT), ABORT); @no r(0) }, strlen(r(4)), { # # Could not find any letters to match the specified input parameter. # Notify the user and release the semaphore. # @pemit %# = u(no_match, +mark, u(format_request, trim(%0)), r(3)); @no r(0) }, { @dolist # # Reorder the list of letters to mark into the same order as is in # the in-list- attribute. This is needed due to setunion's distressing # habit of returning sorted lists. # [setq(4, u(filter_list, setunion(r(4), ), r(1)))] r(4) = { &in-##-flags [r(0)] = setunion(get(r(0)/in-##-flags) M, ) }; @swi 1 = 1, { # # Finished marking the letter(s) specified. Set the 'current letter' # to be the last one marked. Notify the user and release the semaphore. # &[u(which_current_letter, r(0))] [r(0)] = first(revwords(r(4))); @pemit %# = Message(s) [u(convert_nums, r(4), r(1))] [u(format_request, trim(%0))] marked in folder '[r(3)]'.; @no r(0) } } } } - ############################################################################### # # U N M A R K # ############################################################################### &UNMARK_COMMAND #3478= # # PURPOSE: # # This command may be used to remove a tag previously set by a call to # +mark. +unmark with no parameter will unmark the last mail message read. # Either a keyword (listed below) or a list of mail numbers may be # specified. Example: +unmark 3..5, +unmark marked # # Command Format: # # +unmark [] # # The following keywords are available to specify the scope of +unmark: # # all, current (default), deleted, first, last, marked, next, previous, # saved, unread, author:, subject:, text: # # Only the first character of the keyword needs to be specified # # Registers Used: # # 0 - user's mailbox dbref # 1 - list of letters in active folder # 2 - new current letter # 3 - name of active folder # 4 - list of internal message numbers reflecting the specified criteria # $+unmark*: @swi/first [setq(0, get(%vm/mailbox_%#))] 1 = not(strmatch(type(%#), PLAYER)), { @pemit %# = u(not_player) }, strmatch(escape(%0), *\[*), { # # Function calls are not allowed within an input parameter. # @pemit %# = u(nofunc) }, eq(strlen(r(0)), 0), { # # User has no mailbox. # @pemit %# = u(nomail, u(get_inbox, %#)) }, { # # Snag the semaphore # @wait r(0) = { @swi/first [setq(1, u(get_folder_in_list, r(0)))] [setq(2, u(get_folder_current_letter, r(0)))] [setq(3, u(get_active_folder, r(0)))] # # Interpret user input and convert into a list of internal mail numbers # [setq(4, u(expand_letter_range, %0, r(1), r(2)))] 0 = strlen(r(1)), { # # Mailbox is empty. Notify user and release semaphore. # @pemit %# = u(nomail, r(3)); @no r(0) }, not(strmatch(r(4), *ABORT*)), { # # Error detected in input parameter. Notify user and release semaphore. # @pemit %# = after(before(r(4), ENDABORT), ABORT); @no r(0) }, strlen(r(4)), { # # Could not find any letters to match the specified input parameter. # Notify user and release semaphore. # @pemit %# = u(no_match, +unmark, u(format_request, trim(%0)), r(3)); @no r(0) }, { # # Reorder the list of letters to 'unmark' into the same order as is in # the in-list- attribute. This is needed due to setunion's distressing # habit of returning sorted lists. # @dolist [setq(4, u(filter_list, setunion(r(4), ), r(1)))] r(4) = { &in-##-flags [r(0)] = s(remove(get(r(0)/in-##-flags), M)) }; @swi 1 = 1, { # # Finished removing the 'M' flag from the letter(s) specified. # Notify user and release the semaphore. # # # Set the 'current letter' to be the last one unmarked # &[u(which_current_letter, r(0))] [r(0)] = first(revwords(r(4))); @pemit %# = Mark(s) removed from message(s) [u(convert_nums, r(4), r(1))] [u(format_request, trim(%0))] in folder '[r(3)]'.; @no r(0) } } } } - ############################################################################### # # S A V E # ############################################################################### &SAVE_COMMAND #3478= # # PURPOSE: # # This command may be used to exclude a message from normal mail # timeouts. +save with no parameter will tag the last mail message read. # Either a keyword (listed below) or a list of mail numbers may be # specified. Example: +save 3..5, +save current # # Command Format: # # +save [keyword or a list of letter numbers] # # The following keywords are available to specify the scope of +save: # # all, current (default), deleted, first, last, marked, next, previous, # unread, author:, subject:, text: # # Only the first character of the keyword needs to be specified # # Registers Used: # # 0 - user's mailbox dbref # 1 - list of letters in active folder # 2 - new current letter # 3 - name of active folder # 4 - list of internal message numbers reflecting the specified criteria # $+save*: @swi/first [setq(0, get(%vm/mailbox_%#))] 1 = not(strmatch(type(%#), PLAYER)), { @pemit %# = u(not_player) }, strmatch(get(%vm/default_save_option), disabled), { @pemit %# = I'm sorry, but the +save command has been disabled by the game administrators. }, strmatch(escape(%0), *\[*), { # # Function calls are not allowed within an input parameter. # @pemit %# = u(nofunc) }, eq(strlen(r(0)), 0), { # # User has no mailbox. # @pemit %# = u(nomail, u(get_inbox, %#)) }, { # # Snag the semaphore # @wait r(0) = { @swi/first [setq(1, u(get_folder_in_list, r(0)))] [setq(2, u(get_folder_current_letter, r(0)))] [setq(3, u(get_active_folder, r(0)))] # # Interpret user input and convert into a list of internal mail numbers # [setq(4, u(expand_letter_range, %0, r(1), r(2)))] 0 = strlen(r(1)), { # # There is no mail in the user's mailbox. Notify the user and # release the semaphore. # @pemit %# = u(nomail, r(3)); @no r(0) }, not(strmatch(r(4), *ABORT*)), { # # Error detected in input parameter. Notify the user # and release the semaphore. # @pemit %# = after(before(r(4), ENDABORT), ABORT); @no r(0) }, strlen(r(4)), { # # Could not find any letters to match the specified input parameter. # Notify the user and release the semaphore. # @pemit %# = u(no_match, +save, u(format_request, trim(%0)), r(3)); @no r(0) }, { # # Reorder the list of letters to 'save' into the same order as is in # the in-list- attribute. This is needed due to setunion's distressing # habit of returning sorted lists. # @dolist [setq(4, u(filter_list, setunion(r(4), ), r(1)))] r(4) = { # # Only add the 'S' (saved) flag if it is not already there. # &in-##-flags [r(0)] = setunion(get(r(0)/in-##-flags) S, ) }; @swi 1 = 1, { # # Finished saving the letter(s) specified. # Set the 'current letter' to be the last one 'saved'. # Notify user and release the semaphore. # &[u(which_current_letter, r(0))] [r(0)] = first(revwords(r(4))); @pemit %# = Message(s) [u(convert_nums, r(4), r(1))] [u(format_request, trim(%0))] marked as 'saved' in folder '[r(3)]'.; @no r(0) } } } } - ############################################################################### # # U N S A V E # ############################################################################### &UNSAVE_COMMAND #3478= # # PURPOSE: # # This command may be used to remove a tag previously set by a call to # +save. +unsave with no parameter will unsave the last mail message read. # Either a keyword (listed below) or a list of mail numbers may be # specified. Example: +unsave 3..5, +unsave saved # # Command Format: # # +unsave [keyword or a list of letter numbers] # # The following keywords are available to specify the scope of +unsave: # # all, current (default), deleted, first, last, marked, next, previous, # saved, unread, author:, subject:, text: # # Only the first character of the keyword needs to be specified # # Registers Used: # # 0 - user's mailbox dbref # 1 - list of letters in active folder # 2 - current letter # 3 - list of internal message numbers reflecting the specified criteria # 4 - name of active folder # $+unsave*: @swi/first [setq(0, get(%vm/mailbox_%#))] 1 = not(strmatch(type(%#), PLAYER)), { @pemit %# = u(not_player) }, strmatch(escape(%0), *\[*), { # # Function calls are not allowed within an input parameter. # @pemit %# = u(nofunc) }, eq(strlen(r(0)), 0), { # # User has no mailbox. # @pemit %# = u(nomail, u(get_inbox, %#)) }, { # # Snag the semaphore # @wait r(0) = { @swi/first [setq(1, u(get_folder_in_list, r(0)))] [setq(2, u(get_folder_current_letter, r(0)))] # # Interpret user input and convert into a list of internal mail numbers # [setq(3, u(expand_letter_range, %0, r(1), r(2)))] [setq(4, u(get_active_folder, r(0)))] 0 = strlen(r(1)), { # # Mailbox is empty. Notify user and release semaphore. # @pemit %# = u(nomail, r(4)); @no r(0) }, not(strmatch(r(3), *ABORT*)), { # # Error detected in input parameter. Notify user and release semaphore. # @pemit %# = after(before(r(3), ENDABORT), ABORT); @no r(0) }, strlen(r(3)), { # # Could not find any letters to match the specified input parameter. # Notify user and release the semaphore. # @pemit %# = u(no_match, +unsave, u(format_request, trim(%0)), r(4)); @no r(0) }, { # # Reorder the list of letters to 'unsave' into the same order as is in # the in-list- attribute. This is needed due to setunion's distressing # habit of returning sorted lists. # @dolist [setq(3, u(filter_list, setunion(r(3), ), r(1)))] r(3) = { &in-##-flags [r(0)] = s(remove(get(r(0)/in-##-flags), S)) }; @swi 1 = 1, { # # Finished removing the 'S' flag from the letter(s) specified. # Set the 'current letter' to be the last one unsaved. # Notify user and release the semaphore. # &[u(which_current_letter, r(0))] [r(0)] = first(revwords(r(3))); @pemit %# = The 'S' flag has been removed from message(s) [u(convert_nums, r(3), r(1))] [u(format_request, trim(%0))] in folder '[r(4)]'.; @no r(0) } } } } - ############################################################################### # # WRITE related commands: # ############################################################################### ############################################################################### # # M A I L # ############################################################################### &MAIL_COMMAND #3478= # # PURPOSE: # # This command may be used to start the letter writing process. # # Command Format: # # +mail [,] [ ...]= # # You may specify any number of players, personal mail aliases, or # global mail aliases to send the letter to, and a subject line. # Both of these may be changed any time before the letter is actually # sent, using the commands +edit to and +edit subject. Once issued, # the mail system will respond with instructions for writing your letter. # # Note: If the players' names contain spaces, each name should be # separated by a comma. Example: +mail Joe Jones, Jane Smith, wizards=FYI # # Registers Used: # # 0 - user's mailbox dbref # 1 - list of names specified by the user converted to dbrefs # 2 - list of mail aliases specified by the user # 3 - list of dbrefs for all destinations (player and expanded aliases) # 4 - mailbox dbref created for user who had no mailbox # 6 - global mail aliases # 7 - personal mail aliases # $+mail *=*: @swi/first [setq(0, get(%vm/mailbox_%#))] 1 = or(strmatch(escape(%0), *\[*), strmatch(escape(%1), *\[*)), { # # Function calls are not allowed within an input parameter. # @pemit %# = u(nofunc) }, not(strmatch(type(%#), PLAYER)), { @pemit %# = u(not_player) }, eq(strlen(r(0)), 0), { # # No mailbox exists for user # @swi/first # # Convert list of names specified by the user into dbrefs # [setq(6, get(%vm/global-mail-aliases))] [setq(1, u(identify_to_list, {%0}, %vm))] [setq(2, u(get_aliases, {%0}, #0, r(6), ))] [setq(3, setunion( [r(1)] [u(expand_aliases, r(2), #0, %b, r(6), )], ) )] 1 = strmatch(r(1), *ABORT*), { # # Error detected in input parameter. # @pemit %# = secure(after(before(r(1), ENDABORT), ABORT)) }, eq(strlen(r(3)), 0), { @pemit %# = You must specify a destination for this piece of mail. }, { # # Create a new mailbox. # @create %N's Mailbox; @set [setq(4, con(me))]r(4) = quiet; @drain [r(4)]; @tel r(4) = %vm; &mailbox_%# %vm = r(4); @trigger %vm/add_mailbox = r(4); &owner_dbref [r(4)] = %#; @startup [r(4)] = {@drain me; @no me}; @set r(4) = safe; ¤t_folder [r(4)] = u(get_inbox, %#); &folder-list [r(4)] = get(r(4)/current_folder); &mail-in-progress [r(4)] = true; &mail-in-progress-to [r(4)] = u(pretty_dist, r(2), #0, , r(6), r(1)); &mail-in-progress-to-expanded [r(4)] = r(3); &mail-in-progress-subject [r(4)] = %1; @pemit %# = switch( u(get_mode_option, %#), verbose, u(enter_msg_verbose), u(enter_msg_terse) ); @no r(4) } }, { # # User has a mailbox. Snag the semaphore # @wait r(0) = { @swi/first # # Convert list of names specified by the user into dbrefs # [setq(1, u(identify_to_list, {%0}, r(0)))] [setq(7, get(r(0)/alias-list))] [setq(6, get(%vm/global-mail-aliases))] [setq(2, u(get_aliases, {%0}, r(0), r(6), r(7)))] 1 = strmatch(get(r(0)/mail-in-progress), true), { # # User is already in the middle of writing a mail message. # @pemit %# = You are already in the middle of sending a message. %b You must complete that one before you begin another.; @no r(0) }, eq(strlen(%0), 0), { # # No destination specified for this piece of mail. # @pemit %# = You must specify a destination for this piece of mail.; @no r(0) }, strmatch(r(1), *ABORT*), { # # Error detected in input parameter. # @pemit %# = secure(after(before(r(1), ENDABORT), ABORT)); @no r(0) }, { # # Otherwise, everything looks fine so far, start storing the data # in the user's mailbox. # &mail-in-progress [r(0)] = true; &mail-in-progress-to [r(0)] = u(pretty_dist, r(2), r(0), r(7), r(6), r(1)); &mail-in-progress-to-expanded [r(0)] = [r(1)] [u(expand_aliases, r(2), r(0), %b, r(6), r(7))]; &mail-in-progress-subject [r(0)] = %1; @swi words(get(r(0)/mail-in-progress-to-expanded)) = 0, { # # Destinations specified could not be expanded into dbrefs. # @pemit %# = You must specify a destination for this piece of mail.; &mail-in-progress [r(0)] = false; &mail-in-progress-to [r(0)] ; &mail-in-progress-to-expanded [r(0)] ; &mail-in-progress-subject [r(0)] ; @no r(0) }, { # # Notify the user of the next step. # @pemit %# = switch( u(get_mode_option, %#), verbose, u(enter_msg_verbose), u(enter_msg_terse) ); @no r(0) } } } } - &MAIL_NO_PARAM #3478 = $+mail: @pemit %# = You must specify the name(s) of the individual(s) that you wish to send mail to, and an optional 'subject' line.%b (format: +mail =) - ############################################################################### # # +N O T E # ############################################################################### &NOTE_COMMAND #3478 = # # PURPOSE: # # This command may be used to send a small note to yourself. # # Command Format: # # +note # # Registers Used: # # 0 - dbref of mailbox # $+note*: @swi/first [setq(0, get(%vm/mailbox_%#))] 0 = strlen(%0), { # # No text specified. # @pemit %# = No text specified for note.%b Syntax:%b +note }, strlen(r(0)), { # # Mailbox doesn't exist, store_letter requires the 'sender' to have a # mailbox. # @create %N's Mailbox; @set [setq(0, con(me))]r(0) = quiet; @drain [r(0)]; @no r(0); @tel r(0) = %vm; &mailbox_%# %vm = r(0); @trigger %vm/add_mailbox = r(0); &owner_dbref [r(0)] = %#; @startup [r(0)] = {@drain me; @no me}; @set r(0) = safe; &mail-in-progress [r(0)] = false; ¤t_folder [r(0)] = u(get_inbox, %#); &folder-list [r(0)] = get(r(0)/current_folder); @tr me/store_letter = r(0), Personal Note, %N, %#, , , , , , escape(trim(edit(%0, \\, ))); @pemit %# = A personal note has been stored in your mailbox. }, { @tr me/store_letter = r(0), Personal Note, %N, %#, , , , , , escape(trim(edit(%0, \\, ))); @pemit %# = A personal note has been stored in your mailbox. } - ############################################################################### # # - # ############################################################################### &DASH_COMMAND #3478= # # PURPOSE: # # This command may be used to add text to a body of a letter in progress. # # Command Format: # # - # # Once a letter has begun, using the +mail, +reply or +forward command, # the '-' command is used to add text to the body of the letter. # Consecutive commands append text to the letter in process. # Whatever is configured for mail option 'separator' is used to # separate the text (either a blank or a carriage return). # # Issuing a '-' without any text following it will show the # available options. # # You may perform any other mush actions while you are entering a # message, so long as they do not start with the '-' character. # # Standard MUSH substitutions may be used, %r to insert a carriage # return, %t to insert a tab character, etc. # # Registers Used: # # 0 - user's mailbox dbref # 1 - size of mail in progress # 4 - body # # register 2 is used in helper function size_of_mail_in_progress # register 3 is used in get_separator_option # $-*: @swi/first [setq(0, get(%vm/mailbox_%#))] 1 = strmatch(%0, -),, # # Command is '--', ignore and let the $-- handler handle it. # not(strmatch(type(%#), PLAYER)), { @pemit %# = u(not_player) }, eq(strlen(r(0)), 0), { # # User does not have a mailbox and therefore cannot be writing mail. # @pemit %# = u(not_writing_mail) }, { # # Snag the semaphore # @wait r(0) = { @swi/first [setq(4, get(r(0)/mail-in-progress-body))] 1 = strmatch(get(r(0)/mail-in-progress), false), { # # User is not writing mail. # @pemit %# = u(not_writing_mail); @no r(0) }, eq(strlen(escape(%0)), 0), { # # '-' Single dash specified, show user help information # @pemit %# = u(finish_msg_verbose); @no r(0) }, { # # Add text to mail message in progress. # &mail-in-progress-body [r(0)] = switch(words(r(4)), 0, %0, escape(trim(edit([r(4)][u(get_separator_option, %#)]%0, \\\\, )))); @pemit %# = [setq(1, u(size_of_mail_in_progress, r(0)))] [u(text_added_notification)] [switch( gt(r(1), 4000), 1, %b%bWarning, message is [sub(4000, r(1))] characters too long and will be truncated. , )]; @no r(0) } } } - &SIZE_OF_MAIL_IN_PROGRESS #3482 = # # This is a helper function for dash_command. # # Purpose: Calculate as close as reasonably possible the size of # the current mail message in progress (from the perspective of # the eventual reader). This is done so the mail writer has # an idea if the message is getting too long for the reader to # see it all. The reader is limited by a 4000 byte pemit. # # %0 - dbref of mailbox # # 196 comes from: the message line, the from line, the to line, # the subject line, the options line, plus some various carriage # returns. # # Need to assume the receiver is reading in standard format since # we don't know (for sure) at this stage. # add( 196, mul(strlen(u(equal_line)), 2), strlen(u(dash_line)), strlen(u(%0/mail-in-progress-subject)), strlen(u(%0/mail-in-progress-to)), switch( strlen(get(%0/mail-in-progress-cc)), 0, 0, {[add(11, strlen(u(%0/mail-in-progress-cc)))]} ), switch( strlen(get(%0/mail-in-progress-bcc)), 0, 0, {[add(11, strlen(u(%0/mail-in-progress-bcc)))]} ), strlen(u(%0/mail-in-progress-body)), [setq(2, get(%0/mail-in-progress-flags))] switch( words(r(2)), 0, 0, {[add( 11, switch(match(r(2), RR), 0, 0, strlen(v(mail_flag_rr))), switch(match(r(2), P), 0, 0, strlen(v(mail_flag_p))), switch(match(r(2), U), 0, 0, strlen(v(mail_flag_u))), switch(match(r(2), R), 0, 0, strlen(v(mail_flag_r)) ), mul(sub(words(r(2)), 1), 2) )]} ) ) - ############################################################################### # # -- # ############################################################################### &DOUBLE_DASH_COMMAND #3478= # # PURPOSE: # # This command may be used to send a letter. # # Command Format: # # -- # # Registers Used: # # 0 - user's mailbox dbref # 1 - list of dbrefs to deliver to (to, cc, bcc) # $--: @swi/first [setq(0, get(%vm/mailbox_%#))] 0 = strmatch(type(%#), PLAYER), { @pemit %# = u(not_player) }, strlen(r(0)), { @pemit %# = u(not_writing_mail) }, { # # Snag the semaphore # @wait r(0) = { @swi/first # # Grab the complete destination list. Includes TO, CC and BCC. # Weed out duplicates. # [setq(1, u(get_final_delivery_list, r(0)))] 1 = strmatch(get(r(0)/mail-in-progress), false), { # # There is no mail in progress to send. # @pemit %# = You do not have a mail message ready to send.; @no r(0) }, eq(strlen(r(1)), 0), { @pemit %# = You do not have a destination specified.; @no r(0) }, { @trigger me/store_letter = r(0), get(r(0)/mail-in-progress-subject), get(r(0)/mail-in-progress-to), get(r(0)/mail-in-progress-to-expanded), get(r(0)/mail-in-progress-cc), get(r(0)/mail-in-progress-cc-expanded), get(r(0)/mail-in-progress-bcc), get(r(0)/mail-in-progress-bcc-expanded), get(r(0)/mail-in-progress-flags), get(r(0)/mail-in-progress-body); @tr me/cleanup_send = %#, r(0) } } } - &STORE_LETTER #3482 = # # PURPOSE: store an outgoing letter # # INPUT: # # %0 - dbref of mailbox for sender # %1 - subject of letter # %2 - TO: (prettified) # %3 - TO: (dbrefs) # %4 - CC: (prettified) # %5 - CC: (dbrefs) # %6 - BCC: (prettified) # %7 - BCC: (dbrefs) # %8 - flags # %9 - text of letter # # OUTPUT: # # None. # # For the sending mailbox: # # Update field: # # out-list # out-list-current (possibly) # # Set fields: # # out--time_sent date/time mail was sent # out--subject subject of letter # out--to TO: (prettified) # out--cc CC: (prettified) # out--bcc BCC: (prettified, used during +review) # out--bcc-expanded dbrefs (used during +read) # out--text body of mail message # out--replyall_to sender, to & cc dbrefs # out--dist total distribution list # out--held list of who still has a pointer to this letter # # For each receiving mailbox: # # Update field: # # in-list- # # Set fields: # # in--time_read date/time mail was last read # in--flags U R RR P D M S AAEND # in--note registered via +add note # in--location where letter is stored # # Registers used: # # 0 - internal number to store outgoing message in # 1 - dbref of existing destination mailbox # 2 - dbref of newly created destination mailbox # 3 - dbref of sender # 4 - mail_sig of sender # 6 - internal number to store incoming message information in # 7 - list of messages in in-list- for destination mailbox # 8 - final distribution list # 9 - inbox # # # Store information about outgoing mail in sender's mailbox. # &[setq(0, u(free_num, get(%0/out-list)))]out-[r(0)]-time_sent %0 = time(); &[setq(3, get(%0/owner_dbref))]out-[r(0)]-subject %0 = %1; &out-list %0 = [get(%0/out-list)] [r(0)]; &out-list-current %0 = switch(words(get(%0/out-list)), 1, r(0), get(%0/out-list-current)); &out-[r(0)]-to %0 = %2; &out-[r(0)]-cc %0 = %4; &out-[r(0)]-bcc %0 = %6; &out-[r(0)]-bcc-expanded %0 = %7; &out-[r(0)]-text %0 = %9 [switch( [setq(4, get(r(3)/MAIL_SIG))] strlen(r(4)), 0,, %r[r(4)] )]; &out-[r(0)]-replyall_to %0 = setunion([r(3)] %3 %5, ); &out-[r(0)]-held %0 = [setq(8, setunion(iter(setunion(%3 %5 %7, ), u(autoforward_test, ##)), ))]r(8); &out-[r(0)]-dist %0 = iter(r(8), ##:); @dolist r(8) = { @swi/first [setq(1, get(%vm/mailbox_##))] [setq(9, u(folder_to_store_into, r(1), get(%0/owner_dbref), %1, ##))] 1 = and( strmatch(type(##), PLAYER), eq(strlen(r(1)), 0) ), { # # Mailbox doesn't exist for this destination player, create one. # @create [name(##)]'s Mailbox; @set [setq(2, con(me))]r(2) = quiet; @drain [r(2)]; @tel r(2) = %vm; &mailbox_## %vm = r(2); @trigger %vm/add_mailbox = r(2); &owner_dbref [r(2)] = ##; @startup [r(2)] = {@drain me; @no me}; @set r(2) = safe; &mail-in-progress [r(2)] = false; ¤t_folder [r(2)] = r(9); &folder-list [r(2)] = r(9); # # Store information about newly received letter. # &in-list-[r(9)] [r(2)] = 0; ¤t_letter-[r(9)] [r(2)] = 0; &in-0-time_read [r(2)] = 0; &in-0-flags [r(2)] = %8; &in-0-note [r(2)] ; &in-0-location [r(2)] = %0 [r(0)]; @edit %0/out-[r(0)]-dist = ##:,##:0; # # Notify receiver that mail message has arrived ('cept if it is # a result of a '+note' command. # @pemit ## = switch(%1, Personal Note,, {u(delivery_notification, r(3), sign(match(%8, u)), sign(match(%8, p)), sign(match(%8, rr)), sign(match(%8, r)), secure(r(9)) )}); @no r(2) }, strmatch(type(##), PLAYER), { # # Mailbox exists. Store information about newly received mail. # &folder-list [r(1)] = setunion([r(9)] [get(r(1)/folder-list)], ); &in-list-[r(9)] [r(1)] = [setq(6, u(free_num, u(get_all_in_lists, r(1))))] [setq(7, get(r(1)/in-list-[r(9)]))] s([r(7)] [r(6)]); ¤t_letter-[r(9)] [r(1)] = switch(words(r(7)), 0, r(6), get(r(1)/current_letter-[r(9)])); &in-[r(6)]-time_read [r(1)] = 0; &in-[r(6)]-flags [r(1)] = %8; &in-[r(6)]-note [r(1)] ; &in-[r(6)]-location [r(1)] = %0 [r(0)]; @edit %0/out-[r(0)]-dist = ##:,##:[r(6)]; # # Notify receiver that mail message has arrived ('cept if it is # a result of a '+note' command or rejected). # @pemit ## = switch(1, strmatch(%1, Personal Note),, sign(words(get(r(1)/reject_msg))),, {u(delivery_notification, r(3), sign(match(%8, u)), sign(match(%8, p)), sign(match(%8, rr)), sign(match(%8, r)), secure(r(9)) )}); @swi 1 = strmatch(%1, On Vacation),, # # Avoid looping 'vacation' messages. # strmatch(%1, Letter Rejected),, # # Avoid looping 'reject' messages. # sign(words(get(r(1)/reject_msg))), { # # Reject set, remove the letter from the mailbox. # @tr me/remove_letter = %0, r(0), get(r(1)/owner_dbref), r(1), r(6), r(9); # # Store a letter in originator's mailbox indicating that the # mail was rejected, and why. # @tr me/store_letter = r(1), Letter Rejected, name(get(%0/owner_dbref)), get(%0/owner_dbref), , , , , , {Message with subject line "%1" has been rejected by [name(get(%0/owner_dbref))]'s mailbox. %r%r----- Reject Message ----- %r%r[get(r(1)/reject_msg)] } }, sign(words(get(r(1)/vacation))), { # # Store a letter in the originator's mailbox with the # registered vacation text from the destination mailbox. # @tr me/store_letter = r(1), On Vacation, name(get(%0/owner_dbref)), get(%0/owner_dbref), , , , , , {Message with subject line "%1" has been stored in [name(get(%0/owner_dbref))]'s mailbox. %r%r----- Vacation Message ----- %r%r[get(r(1)/vacation)] } } }, { @pemit get(%0/owner_dbref) = Unable to deliver message. } } - &REMOVE_LETTER #3482 = # # PURPOSE: Remove a letter from an incoming mailbox # # DESCRIPTION: # # Remove all references to the letter in the received (IN) mailbox. # Remove this single reference in the originator's (OUT) mailbox. # If all references to this letter have been removed, entirely # remove letter from OUT mailbox. Check to see if either the # IN or OUT mailbox may be deleted. # # %0 - dbref of mailbox (OUT) # %1 - inter