!* -*-TECO-*-! !~Filename~:! !RMAIL mail-reading program.! RMAIL !& RMAIL Execute Options:! !S RMAIL command loop.! !* Q-Register usage in RMAILX: qRMAIL Reply Buffer holds the buffer for constructing mail and replies. It is either an actual TECO buffer to use, or a string which is the name of an EMACS buffer to use, or 0 meaning create a TECO buffer on first use. qRMAIL S Filename is 0 in perusal mode; otherwise, it holds the rmail file name. qRMAIL F Default has a string containing the last "F" command argument. qRMAIL Deletions is a buffer holding all messages that were deleted, for "U"s sake. It must be set up before invoking this macro. qRMAIL O Filename holds the default filenames for the "O" option. qRMAIL ^O Filenames holds the buffer which holds the remembered filenames for ^O. It is not created until it is needed. qRMAIL Buffer should hold what ..O holds (a buffer containing the mail). This Q-Register is MM Kill Var'd by the X command, telling a future MM RMAIL that it should start from scratch. q3 (local) holds string to be executed, accumulated by ; command. fq3 is < 1 if there is none. q5 (local) holds the argument to most commands. q6 holds a copy of qRMAIL Display. q0 - q9, q.1, q.2, q.3 are all temporaries. They are saved and restored. q..j is saved and restored. ! !* EXITS: If & RMAIL Execute Options is called with "1," as arg, Q kills the job, and ^X returns to DDT. This is for TRMAIL^K. If called with "2," as arg, Q kills the job but ^X exits to EMACS. This is for RMAIL^K (running inside EMACS). Otherwise, Q and ^X both simply exit, the difference being that Q has killed all the text in RMAIL's buffers first.! [0 [1 [2 0[3 [5 [.1 [.2 [.3 0FO..Q RMAIL_DISPLAY[6 !* Get user's display macro.! [..J :I*RMAIL[Editor_Type QEMACS_Version-140"L -1F[NOQUIT !* Quits should pop to the errset,! @:I*| [..J :I..J [..J_^R] 0F[NOQUIT| F[^R ENTER' !* but inside recursive edits, quits should be allowed.! !* In version 140, :@< exists so we don't need this.! !BACKFROMC-X! F< !RMAIL-CATCH! !* Q and ^X options throw out of this.! :@< !CANON! :I5 !DISPLAY! FQ3-1"L !* Unless within a ;-accumulated line, ! FS RGETTY"N FS ECHO ACT"L :I*CFSECHO DIS 0FS ECHO ACT'' Q6"NM6'"# @V ' FS RGETTY"E 0FO..Q RMAIL_Auto_Type"N !* Maybe should display even on TTY.! 0FO..Q RMAIL_Old_FSVZ-(FS VZ)( !* if have moved to new message! 0FO..Q RMAIL_Old_B-B)"N !* (either B or FS VZ changed),! :I3 T !* Type it now,! B M.V RMAIL_Old_B !* but remember we are at it so we don't type it again.! FS VZ M.V RMAIL_Old_FSVZ'''' !INPUT! 0F[HELP MAC FQ3"G G3 FK+1FX3 0AU0 -D ' !* If have stuff read in by ";", get a char of it! "# FS RGETTY"E FS TYO HPOS"E FT:'' !* On printing tty, maybe prompt.! ^FIU0 Q0FSECHOOUT !* else read one from terminal.! 0FS ECHO ACT' !* Don't erase echo area if only echoed commands are in it! F]HELP MAC Q0-4110."E ?U0' !* Respond properly to the Help character.! Q0:I1 !* Convert character to 1-character string.! Q0&400."N Q0&177.U1 Q1-33"L :I1 $^1'"# :I1 $1'' !* Represent meta chars as $-foo or Meta-Control as $^-foo! Q0&200."N Q0&177.U1 :I1 ^1' !* Represent control chars as ^-foo! Q0-33"L Q0+100.U1 :I1 ^1' !* And of course, under 41. like control! Q0-127"E :I1 ^?' !* Rubout is # RMAIL ^?.! 1,M.M #_RMAIL_1U1 !* Get character's definition, or 0.! Q1"E Q0M(M.M&_Charprint) FT :__no_such_option.__Type_?_for_help. !' FQ5"G 5'@M1 F"N O INPUT' !* MACRO RETURNS VAL => DON'T FLSH ARGUMENT.! >U0 !* End of the error catch, which is also a loop, so only exit if error.! >U0 !* End RMAIL-CATCH. Loop around for error, drop out for throw.! !* The pre-comma argument is 0 normally, 1 in bare-teco RMAIL^K, 2 in Emacs RMAIL^K ! "E ' !* Not RMAIL^K. Just return from RMAIL.! -1"E Q0-1"E 40000.'+100000. FSEXIT !* RMAIL^K: Q kills the RMAIL, ^X just returns to DDT.! O BACKFROMC-X ' q0-1"E 140000. FSEXIT'  !* Emacs RMAIL^K: Q kills, ^X exits! !# RMAIL 0:! !# RMAIL 1:! !# RMAIL 2:! !# RMAIL 3:! !# RMAIL 4:! !# RMAIL 5:! !# RMAIL 6:! !# RMAIL 7:! !# RMAIL 8:! !# RMAIL 9:! !# RMAIL +:! !# RMAIL -:! !# RMAIL *:! !# RMAIL /:! !# RMAIL ):! !# RMAIL (:! !# RMAIL ,:! !S Part of a numeric argument.! :I550 0 !# RMAIL Z:! !S Largest possible argument for whatever command follows.! :I5599999 0 !# RMAIL ^@:! !S ^@ is a no-op.! 0 !# RMAIL ^G:! !S After ^G causes a quit, it shouldn't be an error too.!  !# RMAIL ^?:! !S Rubout - just flush argument.!  !# RMAIL ;:! !S Accumulate a line, then execute it with no display.! [..J :I..J RMAIL-Shhh M(M.M &_Read_Line);U3  !# RMAIL T:! !S Type some or all of this message.! FF"N M(M.M#_RMAIL_J) ' !* IF NONZERO ARG, SELECT THAT MESSAGE FIRST.! FSZ-Z"E FT End_of_buffer  ' [0 [.2 [.3 [1 [7 0F[VB -:S: .U1 !* Q1 gets addr of start of current message.! 1U7 J <.-Q1; :S; %7> !* Compute abs. number of this message in Q7.! F]VB FT #_ Q7= 140.M(M.M&_RMAIL_Parse_Header) !* PARSE MACRO, BE CAREFUL, SMASHES .2,.3! 4L .-B-200"G B+200J .U1 :@L FSHPOS-120"G Q1J '"# L '' !* PRINT MIN(4 LINES,200 CHARS+TILL END OF LINE)! .-B-Q.3"L B+Q.3J ' !* BUT PRINT AT LEAST ALL RELEVANT HEADER LINES! Z-.-150"L ZJ ' !* IF LESS THAN 150 CHARS LEFT, PRINT ALL! B,.T -2F= "N FT ' !* THEN TYPE CR UNLESS STUFF TYPED ENDED WITH ONE! :M(M.M&_RMAIL_--MORE--) !& RMAIL --MORE--:! !S Maybe print --MORE-- and the number of lines remaining in this message.! .-Z"N [1[2 .( 0U2 <%2WL.-Z;>W )J !* Type # lines, plus stars if avg linel > tty linel! FT( Q2:= Z-./(FSWIDTH*Q2) FT_lines)--MORE-- ]2]1 '  !# RMAIL ^M:! !S No-op, flushes argument.! @FT   !# RMAIL ^`:! !# RMAIL ^V:! !S Print more of this message.! FSRGETTY"E FT  !* ON PRINTING TTY, PRINT! FF"N .,(L).T !* AS MANY LINES AS SPECIFIED (MAYBE THEN --MORE--)! M(M.M &_RMAIL_--MORE--)' "# .,ZT !* OR ALL THE REST OF THE LINES! ZJ -2F= !* (SUPPLYING A CRLF AT END IF NOT ALREADY ONE)! "N FT '' ' !* ON A DISPLAY,! .-Z"E J ' !* IF AT END, CYCLE TO BEGINNING.! F @M(M.M ^R_NEXT_SCREEN) !* ELSE MOVE TO NEXT SCREENFULL.!  !* DON'T USE :M SINCE ^R NEXT SCREEN RETURNS VALUES.! !# RMAIL ^H:! !# RMAIL $V:! !S Move to previous screenfull.! F @M(M.M ^R_Previous_Screen)  !# RMAIL ^R:! !S Call ^R to edit this message.! 0F[^R MORE   !# RMAIL ^[:! !S Altmode Command.! FI400.FSREREADW 0 !# RMAIL $^[:! !S Mini Buffer Command.! M(M.M ^R_Execute_Mini) W !* Don't use :M - The W must make sure we return no value.! !# RMAIL A:! !S Move to next message and summarize it.! < 1M(M.M #_RMAIL_N) @M(M.M #_RMAIL_B) > !# RMAIL N:! !# RMAIL ^J:! !S Move to next message.! "L -:M(M.M #_RMAIL_P)' !* With negative arg, turn into P option.! [0 0,FSZ FS BOUND 0U0 <:S; .+2-Z"L .U0'> !* LOOK FOR OTHER ^_S WITH STUFF AFTER THEM! Q0"N Q0J !* FOUND AT LEAST 1 => LAST ONE IS START OF DESIRED MSG! :M(M.M &_RMAIL_Select_Message)' .,Z FS BOUND :I*No_next_message,_now_at_eof FS ERR !# RMAIL J:! !S Jump to message with given number.! 0F[VB 0F[VZ !* SAVE OLD BOUNDS AND POINT SO THAT IF THERE IS! .[1 FN Q1J !* AN ERROR NOTHING IS CLOBBERED.! BJ -2"L J M(M.M &_RMAIL_Select_Message)' !* DEFAULT TO FIRST MESSAGE! "# -99998"G !* ARG OF Z SPECIFIES LAST MESSAGE.! ZJ .< R 1AF :;> !* So go to end, back over blank lines and the last ^_.! M(M.M &_RMAIL_Select_Message)' "# J 0U0 !* Explicit arg is # of desired msg, rel. to beginning.! -1<:S; .+2-Z"L .U0'> !* LOOK FOR OTHER ^_S WITH STUFF AFTER THEM! Q0"E :I*NSM No_Such_Message FS ERR' Q0J M(M.M &_RMAIL_Select_Message)'' !* FOUND AT LEAST 1 => LAST ONE IS START OF DESIRED MSG! ]..N ]1 ]*W ]*W !* WE WON => DISCARD SAVED OLD POINT, BOUNDS.!  !# RMAIL P:! !# RMAIL ^:! !S Move to previous message.! .[1 FN Q1J !* SAVE OLD BOUNDS AND POINT SO THAT IF THERE IS! 0F[VB 0F[VZ !* AN ERROR NOTHING IS CLOBBERED.! :-SW Q1-."E !* TRY TO FIND DESIRED MESSAGE. IF NONE BEFORE THIS,! Q1J 0F]VZ 0F]VB :I* NPM No_Previous_Message FS ERR' ]*W ]*W ]..N ]1 !* WE WON => DISCARD SAVED OLD POINT, BOUNDS.! :M(M.M&_RMAIL_Select_Message) !# RMAIL .:! !& RMAIL Select Message:! !S Set bounds around message that point is in. Sets point at the beginning of the message.! :-S : !* FIND BEGINNING OF MESSAGE! ."E 10F~*APPEND* "E 10C'' !* *APPEND* AT FRONT OF FILE ISN'T PART OF ANY MESSAGE.! @:F"G 15.I12.I2R' @L !* Must be careful not to spuriously ! 0,1AF_ !* modify buffer ! "L'"# @F_ !* Clean up excess whitespace, there ! K ' !* should be only a CRLF after the ^_ ! !* Note this means there will ALWAYS be a CRLF before the virtual ! !* buffer bounds. ! .[0 :S: !* FIND END OF NEXT MESSAGE! Q0,.FSBOUNDW J !* SET THE BOUNDS AROUND IT.!  !# RMAIL D:! !S Delete this message, select next.! 0,fszfsboundw m(m.m&_rmail_select_message) !* ReSelect msg in case bounds bad.! B-2,Z+1FSBOUNDW !* INCLUDE THE TERMINATING ^_ AND ! !* STARTING CRLF IN BUFFER BOUNDARIES! G(Q..O( !* SELECT THE BUFFER OF DELETED MSGS, ! QRMAIL_Deletions[..O)) !* AND INSERT THE NEW ONE ! ]..O HK !* DELETE IT FROM THE MAIN BUFFER! 0,FSZFSBOUNDW !* POINTER NOW AT START OF NEXT MSG! "L !* -D MEANS DELETE AND MOVE BACKWARD.! 1:< 1M(M.M #_RMAIL_P)>"L !* ALSO DON'T COMPLAIN ABOUT LAST MSG - BUT DO, FOR 1ST.! :I*DFM Deleted_First_Message :FG M(M.M &_RMAIL_Select_Message)' ' .[1 @F R !* Skip over any blank lines.! .-Z"E !* DELETED LAST MESSAGE IN FILE?! Q1,ZFSBOUND !* YES => SET UP BOUNDS AT EMPTINESS AT END.! :I*DFM Deleted_Final_Message :FG ' :M(M.M &_RMAIL_Select_Message) !# RMAIL ^D:! !S Delete message and move backward.! -1M(M.M #_RMAIL_D) !# RMAIL U:! !S Undelete last deleted message.! QRMAIL_Deletions[9 FQ9"E :I* NDM No_Deleted_Messages_to_Undelete FS ERR' -:S: !* MAKE SURE AT BEGINNING OF A MESSAGE! ."E 10F~*APPEND* "E 10C'' !* BUT AFTER ANY *APPEND* AT THE BEGINNING.! Q9[..O !* SELECT THE BUFFER HOLDING THE DELETED MESSAGES! 0A-"N I' R !* GO BACK OVER THE ^_ (INSERTING IT IF NECESSARY)! -:S: !* GO BACK TO BEGINNING OF THE MESSAGE THAT ENDS! .,Z( ]..O )G9 FKC !* YANK THE MESSAGE INTO THE MAIN BUFFER! Q9[..O .,ZK !* AND DELETE IT FROM THE LIST OF DELETED MSGS! ]..O m(m.m&_RMAIL_Select_Message) !* Get the bounds set properly !  !# RMAIL Y:! !S Yank last deleted message into this message.! QRMAIL_Deletions[9 FQ9"E :I* NDM No_Deleted_Messages_to_Yank FS ERR' :S: !* MAKE SURE AT END OF A MESSAGE! 15.I 12.I 15.I 12.I !* Make sure at least one blank line! Q9[..O !* SELECT THE BUFFER HOLDING THE DELETED MESSAGES! 0A-"N I' R !* GO BACK OVER THE ^_ (INSERTING IT IF NECESSARY)! -:S: !* GO BACK TO BEGINNING OF THE MESSAGE THAT ENDS! .,Z-1( ]..O )G9 FKC !* YANK THE MESSAGE INTO THE MAIN BUFFER! Q9[..O .,ZK !* AND DELETE IT FROM THE LIST OF DELETED MSGS! ]..O -L m(m.m^R_Delete_Blank_Lines) !* Make just 1 blank line!  !# RMAIL F:! !S Find and select message containing specific string.! 1,M(M.M &_Read_Line)Find:_[0 FQ0"L 0' !* Give up if rubbed out.! FQ0"N Q0URMAIL_F_Default' !* Null string => use default; else it is new default.! .[1 FN Q1J 0F[VB 0F[VZ !* SAVE CURRENT STATE OF THINGS IN CASE SEARCH FAILS.! QRMAIL_F_Default[2 !* PUT STRING IN Q2 SO ^] CAN BE USED.! :S2"E fg ' ]2 !* SEARCH FOR THE USERS STRING (forward or backward)! ]*W ]*W !* Found it, discard saved old Bounds.! .U1 !* But keep the FN to restore point after the Select! :M(M.M &_RMAIL_Select_Message) !* SET BOUNDS AROUND FOUND MESSAGE.! !# RMAIL Q:! !S File out RMAIL file and exit RMAIL.! QBuffer_FilenamesF"N[1 !* In update mode, file out changes,! FSZ"N M(M.M ^R_Save_File)' !* If file is nonempty, save it if changed.! FSZ"E 1:'' !* If file is empty, kill it if it exists.! 0FSVZW 0FSVB !* Kill all of buffer RMAIL so that ! HK 1F? !* next MM RMAIL knows it must start from scratch.! 0FS MODIFIED !* MM Save All Files shouldn't save this empty buffer.! 0UBuffer_Filenames !* Unvisit the file so C-X C-F isn't confused.! 0U:.B(QBuffer_Index+2) QRMAIL_Deletions [..O HK 1F? ]..O 1F;RMAIL-CATCH !# RMAIL ^X:! !# RMAIL ^]:! !S Temporarily exit MM RMAIL. Doesn't file out. Repeating the MM RMAIL will resume with state unchanged.! 2F;RMAIL-CATCH !# RMAIL X:! !# RMAIL $X:! !S Execute an MM command using the completing reader.! Fm(m.m^R_Extended_Command)  !# RMAIL S:! !S Write out the RMAIL file.! QBuffer_Filenames[1 FSZ"N M(M.M ^R_Save_File)' !* If file is nonempty, save it if changed.! FSZ"E 1:'' !* If file is empty, kill it if it exists.!  !# RMAIL W:! !S Access whole file.! 0,FSZFSBOUNDW  !# RMAIL ^A:! !S Redisplay screen with cursor on top! F+ 0@:F  !# RMAIL ^L:! !S Clear screen.! F+  !# RMAIL ^O:! !S Write buffer to one of several files.! !*** The filenames are associated with their numbers through text in a buffer. It contains one line per filename, with this format: #nnn filename where nnn is the number (as many digits as needed) and a tab follows it. ***! :\[0 [1 F[D FILE [..O !* ..O must be last pushed. It will be popped.! 0FO..Q RMAIL_^O_FilenamesF"N U..O' "# FS B CREATE !* Get the buffer of filenams and numbers, or make it.! Q..O M.V RMAIL_^O_Filenames' FF"E FT^O_numbers_and_filenames   HT ' !* No arg => print the contents of that buffer.! J :S#0 "L :X1 ET1' !* If number was already used, find its filename! "# QRMAIL_O_FilenameU1 ET1 !* Else set defaults to last O or ^O file,! 1,M(M.M &_Read_Line)Append_message_to_file_#0_(1):_U1 FQ1"L ' ET1 !* Read name from user and run through defaults! FS D FILEU1 !* to canonicalize it.! ZJ I#0 1 !* Remember this name with the specified number.!   C \ L' !* Sort the filenames by the numbers.! Q1 URMAIL_O_Filename !* Remember last ^O file as O default.! ]..O 1,:m(m.m #_RMAIL_O) !# RMAIL O:! !S Write buffer to specified file.! B-2F[VBW B,B+2F= !* Reveal the CRLF before the selected ! "N WF]VBW ' !* message if indeed ther is one ! "E !* Unless "1," indicates use default filenames, read some.! QRMAIL_O_Filename[1 Q1F[D FILE !* Temporarily set up the O default filenames.! 1,M(M.M &_Read_Line)Add_message_to_(1):_U1 FQ1"L ' ET1 !* Did he chicken out? ! FS D FILEURMAIL_O_Filename !* remember altered filenames ! ' !* and write the buffer into that file,! Q..O[1 F[B BIND E?"E ER @A ' "# @FT (New_File) 0fsecho act' !* commenting if the file is being created, ! J 1F=*APPEND* !* usually at front, ! "E ZJ' !* but at end if file starts with *APPEND* ! G1 I .-Z"N .-(./5*5),32I' EIHPEF !* Write out new contents of file.!  !& Mail Message:! !S Enter from outside RMAIL to mail one message.! 0[Comment_Start F[WINDOW :I*To_resume,_invoke_the_Mail_command_again_with_a_numeric_argument.[Abort_Resumption_Message 0fo..QRMAIL_Reply_Buffer"E 0 m.vRMAIL_Reply_Buffer' :i* *Mail*[RMAIL_Reply_Buffer FF&1"E 1+'1, :M(M.A RMAIL#_RMAIL_R) !# RMAIL C:! !S Continue editing a reply message.! 1,:M(M.M #_RMAIL_R) !# RMAIL M:! !S Edit and then send a message.! 2,:M(M.M #_RMAIL_R) !# RMAIL R:! !S Edit and then send a reply to current message.! !* With 1st arg of 1, continues editing an outgoing message.! !* With 1st arg of 2, sends a (non-reply) message - different initialization.! [2 [3 .[0 [.4 FN Q0J [0 Q..O[5 [..O 1[8 QAbort_Resumption_Message"E :i*Use_the_C_command_to_resume_editing_this_message[Abort_Resumption_Message' 0FO..Q RMAIL_Reply_BufferU2 Q2FP"G FQ2"E 0U2'' !* Null string is equivalent to 0 - make TECO buf.! Q2"E FS B CONS M.V RMAIL_Reply_Buffer' !* Nothing said about reply buffer => make one.! -1"E QRMAIL_Reply_BufferM(M.M&_Push_Buffer) !* select the old reply buffer! O Continue' !* For C, don't clobber what reply-buffer already has.! :I1 Q1U2 Q1U3 Q1U0 Q1U.4 !* In case it's M, init all fields to null.! !* For R, parse the message.! "E FF&1"N 12.+'605.M(M.M &_RMAIL_Parse_Header)' FQ.4"G Q.4U0 ' !* If REPLY-TO: it replaces sender! QRMAIL_Reply_BufferM(M.M &_Push_Buffer) HK "E F~0COMSAT"E !* If R command and message is from COMSAT! Q5[..O .( JS----- L .-BU0)J ]..O !* Extract that text and insert in reply buffer.! Q0,FQ5G5 J Q8"N K !* Kill the old header, leaving just the old text.! < 3F~To:"N 3F~Cc:"N 0;'' K>' "# S   B,.K' J FQ2"G iSubject:2 ' !* Insert the subject, if any.! I To: --Text_follows_this_line--  !* Then set up to mail failed text to someone.! :-L !* Position cursor after the "To:"! O Continue'' !* Skip rest of reply setup.! FF&1"N !* Explicit numeric arg means reply to recipients.! G1 G3 !* Get recipients and CCs ! J < :ST; Cc:> !* Pick up To: and Cc: names ! J < :SC; Cc:> !* Turn everyone being replied to, except ! J < :S_at_; @> !* the sender (see below) into a Cc: ! J < :S_@_; @> ' FQ0"G J iTo: G0 i  !* get senders name ! :< :S0; R FK+2D @f,_ k> !* Flush any second occurrence.! !* Use errset in case too long to search for.! ' -2"N J <:S INFO-; FKAF:,_+1"G !* Only with arg of 2 reply to ! FKD .,(S, !* info mailing lists. !  FKC .)K'> ' J <:LW -@F_,K 10,-3A-10"E0LK' !* Flush any blank To: lines ! L .-Z;> ZJ I--Text_follows_this_line--  J -2"N L' FQ2"G iSubject:2 ' !* INSERT THE SUBJECT, IF ANY! FF&1"N Q8"E iHeader-Force:RFC733  '' !* If 1R and not ITS header, return in kind.! ZJ -L I  2R !* Create blank line in case user wants to add to header.! -2"E I To:' !* For M, make an empty To.! !CONTINUE! !* Set up the ^R environment for editing the reply.! F~ModeFundamental"E M(M.M Text_Mode)' 0[..F !* prevent auto-filing of our reply.! M.M ^R_RMAIL_YANK U2 !* Macro to yank message being replied to.! FS ^R INIT-Q.Y"E !* If ^Y has its built-in definition, redefine it.! Q2[.Y' 600.+@FS ^R INIT-Q...Y"E !* If C-M-Y undefined, redefine it.! Q2[...Y' 201.@FS ^R INIT-Q...Y"E !* If C-M-Y is an error, redefine it.! Q2[...Y' 3FS ^R INIT # Q.C"E !* If ^C unredefined, define it to send the message.! 33.FS ^R INIT [.C' 35.FS^RINIT # Q.]"E !* If ^] unredefined, define it to abort.! M.MAbort_Recursive_Edit[.] ' QParagraph_DelimiterU2 FQ2"G :I2 2-' "# :I2-' !* Make a line starting with "-" a separate paragraph.! Q2[Paragraph_Delimiter 0FO..Q RMAIL_Reply_Hook !* Does user say what other commands to redefine? ! F"NU2 M2' 0F[WINDOW !Re edit! 0U..H !* MAKE DISPLAY OCCUR?! [..J :I..JRMAIL-Mail FSRGETTY"E FT  B,.T FT..A .,ZT' !* give printing lusers some hope!  ]..J !* LET USER TYPE HIS REPLY IN! Q..0&337.-307."E ' Z"E ' !* IF HE DIDNT EXIT WITH ^G, AND DIDNT CLEAR THE BUFFER,! 1:< M(M.M &_Mail_Buffer)>F"E W' !* Mail the contents. Error => go back to editing. ! @:FG O Re edit !& Mail Buffer:! !S Mail message as specified by buffer contents. Buffer should contain header information followed by a line containing "...Text follows this line...", followed by the text. Header info is as described in .MAIL.;MAILRQ INFO except that To: allows several recipients separated by commas, and Cc: is allowed. Also, use From: to say who you are.! Q..O[1 F[B BIND G1 !* Make copy of buffer to do munging in, so "C" after! J 1F[Bothcase:S !* sending finds the message as user set it up.! --Text_follows_this_line--"L @F_ L 1A-15."E O Win'' :I*No_text,_just_header FS ERR !Win! [2 [3 0[4 [5 0[6 !* Q4 counts number of recipients.! !* Q6 will be SEND flag! 0L FSZ-.F[VZ !* Narrow bounds to just the header info.! J < .-Z; !* look at each line of header! 1af_ +1"g l !' !* line ok if it begins with whitespace! :fb:"l r -@f_ k !* remove whitespace before colon if any! 0@fc l !' !* convert item name to upper case! 1A-15."E L !' !* If no colon on line, but not empty, it's garbage.! :I*Garbage_in_message_header FS ERR > !* (Maybe user typed the text above the ....)! !* the mailer won't accept lower.! BJ :SSEND:"L !* Set Q6 if its a QSEND! @f_ k 1@fc 1afNSA+1f"g-2(d)\0l5c' 1a-13"e i-12r ' :x6 0lk :I6_(R-MODE-SEND_6) ' J I  J < .-Z; :S CC: TO:; !* Find the next CC or TO line.! -D :I2 0FF~TO"N 0X2 !* Q2 gets null string for To,! :I2_(R-OPTION_2)' !* or (R-OPTION CC) for CC.! 0K <:FB@_; -D> 0L !* Flush any spaces after @'s.! < @f_ k !* Flush whitespace before name.! 1a-42."e c fb"!'!W ' !* We can have comma or even CR in quotes! < :S(, +1"n 0;' s)> !* Else search for comma or CR not within parens.! FKD FKU3 !* Q3 has -1 for comma, -2 for CRLF.! 0,1af_ +1"g -1u3' !* unless next line is continuation! 0F"E -2-Q3; !' !* If null name, ignore, or exit if ended by CR.! !* Put RCPT: before name. If doesn't start with "("! .-ZU5 0L IRCPT: 1A-("E FLL .,Q5+Z:FB_at_"L@' Q5+ZJ' "# I( 1a-42."e c fb"!'!w' !* skip the quoted string again! 1AF["L !* don't even look inside if its in []s! .,Q5+Z:FB<"L .(:FB>"L-D0L6C')-.D' !* Process 733 style <>! .,Q5+Z:FB("L R.,(:FB)W).K -@F_K ' !* Delete RFC733 comments! 0l .,Q5+Z:FB_at_"L @ ' !* Convert Foo at Bar to Foo@Bar ! 0l .,Q5+Z:FB_"L !* whitespace inside.! 0l 6c 0,1a-42."n0L6CI" Q5+ZJ .,(0l.):FB@W I" !''!''' Q5+ZJ I)' !* Then put a pair of parens around it.! %4 !* Indicate that we have seen at least one recipient.! I  !* Move any @Site inside the trailing closeparen.! :0L 0A-)"N I_) -2S) F_' L !* If it's a CC, stick (R-OPTION CC) before final ")".! FQ2"N -S) G2 L' Q6"N -S) G6 L' !* Insert (R-Mode-Send #) if send: was on! -2-Q3; > :0L > Q4"E :I*No_Recipients FS ERR' !* Message is illegal if not mailed to anybody.! J :S BCC:"L :I*BCC_option_not_supported FS ERR' J :S FROM:"E I AUTHOR: FS XUNAMEF6 I !* If no FROM, stick our UNAME in! ' "#  AUTHOR:' J :S H:"L  HEADER-FORCE: @ FC' !* Convert line following H: to U.C.! J :S RE: S:"L  SUBJECT:' J :S R:"L  REGISTERED: @FC' j 2f= "e 2d' J IFROM-PROGRAM: FS XJNAMEF6 I FROM-XUNAME: FS XUNAMEF6I FROM-UNAME: FS UNAMEF6 I  ZJ ITEXT;-1  F] VZ K F[D FILE ET DSK:.MAIL.;MAIL_> FS MACHINE-(F6DM)"E ET MC:' E\ FN E^ EIHPEF  !& Push Buffer:! !S Push-select buffer. Prefix arg is either TECO buffer, or string naming EMACE buffer. When caller returns, the original buffer will be re-selected.! FP"E [..O :' F[MODECH [..J [Previous_Buffer !* save modeline and previous buffer! qBuffer_Name[0 !* 0: Original buffer name.! @:i*|m(m.mSelect_Buffer)0|(]0)[..n !* Make cleanup handler that will! !* select back to the original buffer.! !* Pop Q0 since not needed any more.! m(m.mSelect_Buffer) !* Select the buffer that caller wants! : !* Exit without popping ..N etc. so! !* that when caller returns, we! !* select back.! !^R RMAIL Yank:! !^R While editing a reply, yank message being replied to. Normally indents by four spaces and weeds out uninteresting lines from header, but numeric arg inhibits that.! :S--Text_Follows_This_Line--  .:W .F[VB G5 FSZ-.F[VZ !* Yank the message and set bounds around it.! FF"N ZJ H ' !* Numeric arg, insertion is literal.! J @F L < .-Z; !* Look at each line.! :SCC:TO:SUBJECT:MESSAGE-ID:+5"N !* If it's uninteresting header,! 0@L @FK !' !* flush it.! @:F@; !* Blank line means end of header.! @L > ZJ 0@F"G I ' !* If yanked stuff doesn't end with CRLF, add a CRLF.! J <:@F"N 4,32I' @L .-Z;> ZJ H !# RMAIL I:! !S File out RMAIL file, read in another.! M(M.M ^R_Save_File) @M(M.M ^R_Visit_File) :M(M.M &_RMAIL_Select_Message) !* Select 1st message of new file.! !# RMAIL G:! !S Gobble any new mail received since RMAIL was started.! M(M.M ^R_Save_File) 0FSVBW 0FSVZW HK FSHSNAMEF6 I  FSXUNAMEF6 I  M(M.M &_RMAIL_INITIALIZE) M(M.M &_RMAIL_Select_Message) !# RMAIL L:! !S Use ^R to move around in list of all messages.! [1[2[3[4[5 FSQPPTR 0F[VB 0F[VZ !* SAVE STATE, LOOK AT WHOLE BUFFER.! Z-.-1U4 !* IDENTIFY THIS MSG BY HOW FAR FROM END! Q..OU2 !* KEEP CURRENT BUFFER HANDY! F[B BIND Q..OU1 [..O !* MAKE A TEMP. BUFFER TO MAKE LIST IN! G2 !* COPY THE FILE INTO THE AUX BFR! !* NOW TURN EACH MSG INTO A 1-LINE ENTRY! !* REMEMBER PLACE ENTRY STARTS! !* MOVE TO END OF MESSAGE, DELETE ^_! !* TRUNCATE ENTRY TO 100 CHARS AT MOST! !* USE Q4 TO TELL WHEN THE CURRENT MESSAGE IS REACHED! !* Q5 HAS ADDR OF L-ENTRY FOR THAT MESSAGE, OR -1! !* THIS LOOP HAS COMMENTS MOVED OUTSIDE TO SPEED IT UP! J 0S -1U5 :I3__  <.U0 :S; -D .-Q0-100"G Q0+100,.K' G3 Z-.-Q4"G>0<' Q0U5 -1U4> !* AND END IT WITH ^_! .-Z"N ZJ .-Q0-100"G Q0+100,.K' G3' !* TAKE CARE OF TRUNCATION OF LAST MESSAGE.! Q5"L Q0U5' Q5J !* SELECT ENTRY FOR EITHER MESSAGE HOLDING POINT,! !* OR THE LAST MESSAGE.! 0[..F !* TURN OFF AUTO-SAVING.! [..J :I..JRMAIL-"L"  !''!  !* LET USER POINT AT SOME OTHER ONE! Q..0&337.-307."E ' !* IF USER QUIT WITH ^G, JUST RETURN TO OPTION LEVEL! 0U0 <-:S; %0> !* FIND WHICH ONE BY COUNTING ENTRIES ABOVE IT! QP FS QP UNWIND !* POP TO ORIGINAL BUFFER AND BOUNDS.! 0FSVBW 0FSVZW J Q0"N :Q0S"EZJ'' !* AND FIND THE ENTRY THE USER CHOSE.! :M(M.M&_RMAIL_Select_Message) !* GO SELECT IT.! !# RMAIL =:! !S Type value of numeric argument.! =  !# RMAIL B:! !S Summarize one or more messages. A pre-comma argument is macroed after typing each line (# RMAIL K uses it), and must return -1 (exit), 0 (do next message), 1 (do current message). In that case, doesn't return to original spot! FSRGETTY"E FT ' M.M&_MAYBE_FLUSH_OUTPUT [0[3[6 [.1 [.2 .[1 "E fn Q1J  f[vb f[vz [1 ' !* Return to this msg on exit! 0fsVBw 0fsVZ !* Open up buffer bounds to whole buffer! [5 !* Put argument in Q5 so can override it.! 1[7 J <:S; Q1-.:; %7> !* Compute abs. number of this message in Q7.! Q1J Q5"L Q7U1 Q5-1:S"E1U7'"#C Q7+Q5U7' !* -5B briefs the previous 5 messages.! Q1-Q7U5' M(M.M &_RMAIL_Select_Message) !* SET BOUNDS AROUND 1ST MESSAGE TO BE HACKED.! Q..O[4 !* KEEP CURRENT BUFFER HANDY! F[B BIND Q..O[3 [..O !* MAKE A TEMP. BUFFER TO pretty up output in.! -F[TRUNCATE M.M&_RMAIL_Parse_Header FF&1"N !* Unless just hacking current msg, give a header line.! !*22: 32 10/02/76 2008 [FOO@AI] About toys and ships and! FT_#_Lines_____Date________From______________Subject ' Q4U..O Q5< MA0; !* Give up if output is flushed.! 67.MP !* PARSE SENDER, SUBJECT, DATE AND LINE COUNT! :I6 FQ2"E 1:< J FWL !* IF NO SUBJECT, USE FIRST CHARS OF MESSAGE! 1A-@"E L FWL ' !* I.T.S. FORMAT, DIFFERENT FIRST LINE! < 1A--"E FWL !' !* FIND FIRST LINE NOT STARTING "Field:"! 1A-:"N 0L0;' L 1A-13"'N; FWL> @f_ l :X6 > BJ' !* WE WORRY ABOUT TRUNCATING TO FIT LATER! FQ6+FQ.1+FQ0"E !* BASICALLY NO STANDARD FIELDS! J@F R :X6 ' Q3U..O HK !* GO TO OUTPUT BUFFER! Q7\ I: !* MESSAGE NUMBER AND COLON.! 7-FSHPOS,Q.2\ 32I !* LINE COUNT, RIGHT-JUSTIFIED AT COLUMN 7.! 9-FSHPOSF"G w1',32I !* PAD TO COLUMN 9.! FQ.1+FQ0"G 0,23-FSHPOSG.1 !* DATE, TRUNCATE TO COLUMN 23.! 23-FSHPOSF"G,32I'' !* OR PAD OUT TO THERE.! HTHK !* TYPE IT OUT.! FQ0"G FT_[ !* THEN THE SENDER, IF ANY.! G0 !* GET IT IN BUFFER FOR PRETTIFICATION.! FS XUNAME @F6 U.2 !* BUT IF SENDER IS ME, USE RECIPIENTS INSTEAD.! F=0.2@-2-FQ.2"E FQ1"G HK ITo: 2,FQ1G1 !* LEAVE OUT THE $T WHICH IS IN Q1.! J:L .,ZK'' !* SHOW ONLY 1 LINE OF RECIPIENTS.! J <:S_AT_; @> J <:S@MIT-; -4D> ZJ 18:J -:S_:RW .,ZK !* TRUNCATE SENDER TO 18 CHARS, AND FLUSH TRAILING SPACE.! HT FT]_ !* PRINT IT, AND CLOSE THE [.! 6-FSHPOS !* IF SENDER VERY SHORT, PAD TO ALIGN SUBJECTS.! '' FQ6+FQ3"G !* NOW HACK SUBJECT OR 1ST TEXT LINE.! FQ2"E FT T:_6 '"# FT2' ' FT  Q4U..O  F"N M()'U6 !* Maybe call pre-comma hook, Q6 gets what to do! Q6:; Z-FSZ+3; !* Give up after hacking last message in buffer.! !* Note, at end is ^_ optionally followed by crlf! Q6"E 1M(M.M#_RMAIL_N) !* Advance to next and hack it.! BJ %7 ' !* Including updating message number in Q7! >  !# RMAIL K:! !S Summarize and kill messages D deletes, P previous, N or space next, ? help Anything else (e.g. period, R) exits and is then executed. K doesn't delete in case you accidentally hit it twice.! 1f[^R More !* This ^R More seems not to work?! :i* RMAIL_Summarize/Kill[..J !* Arrange mode line! :^i*{ [0 !* Called by Summarize macro after each line! !type-in! FI:FC u0 !* Get input character in Q0! Q0-_"E 0  ' !* Space advances to next message! Q0-D"E !* D calls delete on this msg, proceeds! ft Delete  m(m.m #_RMAIL_D) 1  ' Q0-P"E q7-1u7 !* P goes to previous message! 1m(m.m #_RMAIL_P) 1  ' Q0-N"E 0  ' !* N is like space! Q0-?"E ft Type_D_to_delete_message,_space_to_see_next, or_N_for_next,_P_for_previous.__Anything_else_exits_and_is_executed.  Otype-in ' !* ? Gives help and looks for more input! Q0-K"E FG Otype-in ' !* K is ignored! q0fsReReadw 0u..H -1  ' !* Anything else exits and is executed! {,999999:m(m.m #_RMAIL_B) !* Call Summarize command! !# RMAIL ^C:! !# RMAIL ^Z:! !S Return to DDT temporarily.! 100000.FSEXIT  !# RMAIL ?:! !S Here is a list of RMAIL options: OPTION ACTION T Types specified message (for printing terminal). N Goes to next message. D Deletes message, moves to next. Deleted messages go in QRMAIL Deletions. U Undeletes last message deleted. Y Yanks last deleted message into this one. P Moves back to previous message. B Briefs you. Prints summary of message. Arg is repeat count. A is equivalent to ;NB K Like ZB but after each line you may hit space, D (delete), etc. J Jumps to message N. Defaults to first message. M Sends a message. C-C C-C sends, C-] aborts. R Replies to sender of message. Use C-M-Y to yank text of message. Use 1R to include all the recipients. Exit same way as M command. C Resumes editing a reply, after aborting or sending it. O Adds message to file - reads file name. ^O Adds message to file. Remembers files by numbers. n^O adds to file n. Just ^O lists files and numbers. Space Looks at next screen of a long message. ^H Backs up to previous screen. . Goes to the beginning of the message. Q Exits, rewriting file. ^X,^] Exits to EMACS temporarily. Entering RMAIL again finds state unchanged. ^C,^Z Return to DDT temporarily. X eXecute a named EMACS command, with completion. S Rewrites file but does not exit. I Rewrites file, and reads a new RMAIL file. G Rewrites file, and gobbles any new mail. ; Reads rest of line and executes without redisplay. Altmode Meta-prefix as in EMACS. Altmode Altmode gets minibuffer. ^R Enters ^R mode recursively on the message text. ^L Redisplays screen. F Searches for a string. W Looks at entire file. "." reselects message pointed at. L Lists 1st 100 chars of all messages, Lets user move to a different message using ^R mode. Digits Are prefix repeat-count for N and P and B, msg # for J. Z Sets arg to largest possible value for that command. ?,Help Prints this text. For more help, run INFO.! M.M~DOC~_#_RMAIL_?[1 2,FQ1:G1U1 !* Delete the macro class "S".! :FT1   !& RMAIL Parse Header:! !S Extract contents of some fields of message header. Takes MASK as arg saying which fields to scan. The Q-register for a field will remain intact if field is not scanned. Q0 (mask bit 1) collects sender's name. Q1 (mask bit 2) collects recipients. Q2 (mask bit 4) collects subject of message. Q3 (mask bit 10) collects carbon copy names. Q.1 (mask bit 20) collects time of message. Q.2 (mask bit 40) has count of lines. Q.3 (mask bit 100) char offset of last useful line of header. Q.4 (mask bit 200) collects REPLY-TO name. Q8 (mask bit 400) is 1 iff header is ITS header. ! F[S STRING [6 .[7 FN Q7J 1F[BOTHCASEW Z[9 !* Q9 will be # of lines in hdr! FSVB-2F[VBW !* Reveal the CRLF hidden before every msg ! 0[4 !* Q4 nonzero if COMSAT complaint.! 0[8 !* Q8 non-zero if ITS header! !* be damned careful that Q8 is last thing pushed! !* SET INITIAL AND/OR DEFAULT VALUES! &1."N :I0 ' &2."N :I1 ' &4."N :I2 ' &10."N :I3 ' &20."N :I.1 ' &40."N 0U.2 ' &100."N 0U.3 ' &200."N :I.4 ' J 1:"N ]8 &400."N 1U8 ' !* presume header as ITS if malformed.!  ' !* QUIT IF THERE ISNT EVEN A WORD IN THE BUFFER.! J :FWL 4F=MSG:"E L !* REPLY PROPERLY TO .MSGS. MESSAGES.! FW+1F=DISTRIB:"E 2L'' 7F=COMSAT@"E !* IF COMSAT COMPLAINT, SET FLAG, SKIP TO RETURNED MSG.! 1U4 :S -----"L L'' 7F=FAILED:"E 8C' !* REPLY PROPERLY TO OLD COMSAT COMPLAINTS.! .U6 FWL 0,1A--"E FWL ' !* Parse past any Mail-From: ! 0,1A-:"E !* SEE IF MAIL HAS TENEX HEADER,! :S  "L .U9 ' !* Find the end of the header! &120."N !* PICK UP DATE/TIME! B,Q9:FB DATE:"L @F_ R !* SKIP LEADING SPACES,TABS! &20."N :X.1' !* GET DATE! &100."N .,Q.3FU.3W' '' !* MAX(.,Q.3)! &104."N !* IF WE ARE PARSING FOR SUBJECT! B,Q9:FB SUBJECT: !* PUT SUBJECT, IF ANY, IN Q2! RE:"L &4"N @F_ R :X2 ' L &100."N .,Q.3FU.3W' '' !* MAX(.,Q.3)! &1"N B,Q9:FB FROM:"L F[MODIFIEDW X0 L G0 -L !* duplicate for munging ! :FB<"L 0K :FB>W-D ' !* sender between <>, rfc733 style ! "# :FB("L .-1,(:FB)"L).K !* comments parse as precisely 1 space! -@F_ K @F_ K I_ '"#)W''' 0L @F_ K !* squeeze out leading space ! :FB_At_"L -4D I@R ' !* AT -> @ ! :FB@"L !* take out space around @ ! @F_ K R -@F_ K ' :L -@F_ K !* squeeze out trailing space ! 0L :X0 K F]MODIFIEDW '' &200."N B,Q9:FB REPLY-TO:"L F[MODIFIEDW X.4 L G.4 -L !* duplicate for munging ! :FB<"L 0K :FB>W-D ' !* sender between <>, rfc733 style ! "# :FB("L .-1,(:FB)"L).K !* comments parse as precisely 1 space! -@F_ K @F_ K I_ '"#)W''' 0L @F_ K !* squeeze out leading space ! :FB_At_"L -4D I@R ' !* AT -> @ ! :FB@"L !* take out space around @ ! @F_ K R -@F_ K ' :L -@F_ K !* squeeze out trailing space ! 0L :X.4 K F]MODIFIEDW '' '"# 1U8 !* If ITS format ! &1"N Q6J !* Get sender? ! .,(:FB@"L :FWL :S_W R).X0 '' &20."N :FB/"N .-3,.+14X.1'' !* snarf up time! &4"N :FB_Re:_"N:FB_WR:X2'' !* put subject in q2! ' &2"N !* COLLECT "TO:" LINES IN Q1.! BJ <:S TO:; .-Q9; < @F_ L !* Skip leading spaces, tabs! :I11T @X1 :L !* Add another line starting with alt T to Q1! Q8:@; !* Don't look for continuation line if ITS header! (0,3A-32)*(0,3A-9):@; L > !* Stop if we don't have a continuation line! >' &10."N !* COLLECT "CC:" LINES IN Q3.! BJ <:S CC:; .-Q9; < @F_ R !* Skip leading spaces, tabs! :I33C @X3 :L !* Add another line starting with alt C to Q3! Q8:@; !* Don't look for continuation line if ITS header! (0,3A-32)*(0,3A-9):@; L > !* Stop if we don't have a continuation line! >' &100."N Q.3-2-BU.3 Q.3"L0U.3'' !* CORRECT Q.3 FOR VIRTUAL BUFFER BOUNDRIES! &40."N BJ 0U.2 <%.2WL.-Z;>' !* COUNT LINES IN MESSAGE! &400."N Q8(]8W)U8 ' Q4"N BJ L :I0COMSAT ' !* If COMSAT-returned failed msg, move point back to B.!  !& Find Dash Separator:! !S Find a line of numarg1 to numarg2 dashes. Blanks before end of line are ignored. We move past the found line if any. Returns 0 for failure, -1 for success.! [1 !* temp qreg! ,-:I1 !* 1: minimal separator string! 0S 1 !* search default-line starting with it! fu1 !* 1:number of extra dashes allowed! < :S"e !* find line starting with separator! 0' !* if none, report failure! q1,z-.f:u1w !* 1:min(q1,#chars left)! q1@f-L !* move past extra separator chars! @F_ L !* Move to first non-blank! .-(:L .)@; !* exit if at end of line! > !* else not it, loop! 1L -1 !* Move to next line and report success! !Undigestify Message:! !C break up a digest into individual messages. The digest is assumed to be the currently selected message. Adds a "To: List-name" field to each sub-message header, for identification and Replying. If a variable Undigestify Keep Digest exists and is non-zero, a copy of the original digest will be kept. If the value is negative, the digest will follow the individual messages, if positive it will precede them. If a numarg is given it is used instead of the value of the variable. This command is UNDOable as long as no NON-digest messages have changed. Type "." after undoing, to reselect current message.! [0[1[3[.3 [L [T [B [D b,zm(m.m&_Save_for_Undo)undigestify !* Make us undoable! !* Undo will work as long as no non-digest messages are messed with! FF&1"e 0FO..QUndigestify_Keep_Digest' "# 'u1 !* 1: Keep copy?! q1"n !* non-0 means yes.! HX0 BJ G0 I  !* Make a copy of entire message! q1"l 3R FSZ-.FSVZ' "# .FSVB'' !* Narrow around the appropriate copy! !* Get the name of the list from first word of digest into QL! 100.m(m.m&_RMAIL_Parse_Header) !* offset of last header line into Q.3! j q.3c l !* Move past header! @F _ L !* Move to first non-blank! .,(sî_ @r).XL !* L:first word (List name)! !* Get what the To: field should be, for proper replies into QT! !* At DUFFEYs request, to avoid overexercising the mailer, we try to! !* use the local machine when possible. This will lose with some! !* half-baked digests which forget to define themselves everywhere.! !* Tough.! fsmachine:f6u0 !* get machine! f=0MC*(f=0AI)*(f=0ML)"e !* one of the good guys?! :iT' !* no need for a site! "#:iT_at_MIT-AI' !* else default to MIT-AI! :iTTo:_LT  !* and make the To field! m.m&_Find_Dash_SeparatoruD !* D:Dash finder, for efficiency! 65,75mD"e !* Find end of topics list! :i*BDF Bad_Digest_FormatFS ERR' !* not found - err out! -k -@F _ k !* Kill separator & preceeding whitespace! !* now undigestify the messages ! f[vb !* save away top of digest! fsbconsuB !* B: temp buffer! F !* Make sure really separator - line! !* before it should be blank! -k -@f _ k !* Kill separator & preceeding whitespace! > !* else have another message - do it to it! qbfsbkill !* all done with temp buffer! f]vbw bj !* go back to start of digest! :m(m.m &_RMAIL_Select_Message) !* and select the top message! !Reformat Tenex Mail:! !C Reformats the buffer from Tenex/Twenex mail file format to ITS mail file format. Works from within Rmail if you have selected a single message which contains a Tenex style mail file.! bj :< :fb,; \(1a-;:@;0lk)c i  > bj  !* Local Modes: Compile Command:MMGenerateEMACS;[RMAI] >EMACS1;RMAILXEMACS1;RMAILZ End: !