rsalz@bbn.com (Rich Salz) (03/17/89)
Submitted-by: Dan Heller <island!argv@sun.com> Posting-number: Volume 18, Issue 33 Archive-name: mush6.4/part11 #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 11 (of 19)." # Contents: cmd_help msgs.c # Wrapped by rsalz@papaya.bbn.com on Mon Mar 13 19:25:17 1989 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'cmd_help' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'cmd_help'\" else echo shar: Extracting \"'cmd_help'\" \(27197 characters\) sed "s/^X//" >'cmd_help' <<'END_OF_FILE' X/* @(#)cmd_help 1.4 10/24/88 (Dan heller) */ X X%?% XThe `?' command will give you a list of legal commands. Most Xcommands accept -? as an option. This will give you specialized Xhelp with that particular command. X%% X X%ignore% X ignore/unignore [headers] X XUse this command to set the message headers you would like not Xto be printed when you read a message. If no header specified, Xthen a list of all headers currently being ignored is printed. XYou must specify a header for unignore. X XYou can set the variable "alwaysignore" to force normally Xignored headers to be ignored while saving messages, forwarding Xmessages or including messages into message buffers. X%% X X%set% X set/unset [variable [= value]] X XWith no parameters, set lists all variables and their values. XTo set a boolean variable (on or off), use: X set variable XTo set a variable's value to a string, use: X set variable = value X XIf you want double-quotes or white-space embedded in a string, Xencase the string in single quotes. If you want single quotes Xin a string, encase the string in double quotes. X XFor a list of all variables with special meanings, use: X set ?all XFor help on a particular one of these variables, use: X set ?variable_name X%% X X%readmsg% XYou can read messages in different ways. "type" and "print" Xwill print the current message. "top" will only print the first XN lines of the current message where N is the value of the Xvariable "crt". "next" will go to the next unread message and Xprint that. "previous" will go back and read the first unread Xmessage previous to the current. "^" will print the first Xmessage, "$" will print the last. X XAny of these commands can be followed by a message list, and Xeach message in that list will be printed (or piped to other Xcommands). X%% X X%alts% X alts [hostnames] X XThe alts command sets a list of hostnames on which you have an Xaccount. Normally, when you respond to all recipients of mail, Xyour account name will be listed as if you wished to send Xyourself mail. If you don't have metoo set, then your name will Xbe removed from the mailing list if your login name is on the Xlist and the host specified is in the alternates list. The Xspecial parameter `*' instructs alts to match all hostnames; in Xthat case, only the login name is tested. X%% X X%source% X source/saveopts [file] X XThe source/saveopts commands will load/save all variable Xsettings, options, aliases, cmd's, ignored headers ... Xeverything you can set, it loads or saves. The file read or Xwritten follows these rules: X X1) If a filename is given, that file is used X2) The file described by the environment variable MAILRC X3) In the user's home directory: .mushrc (if it exists) X4) In the user's home directory: .mailrc (if it exists) X XIf saveopts is used and the file exists, confirmation will be Xrequested before the file is overwritten. X%% X X%general% XThis is the general help message. To get help on a specific Xcommand, try "command -?". Extended help is given by typing X"help item" where item is one of: X path, msg_list, prompt, hdr_format XHelp with msg_list is highly advisable! X XType "?" to get a list of available commands. Try "? command" Xto get help on the particular command that you specify. X%% X X%path% XWhenever "path" is specified, the following syntax is legal Xbesides the normal path addressing scheme used by unix: X ~[user] -- the home directory of specified user (yours by default) X %[user] --/usr/spool/mail/login_name [user_name] (yours by default) X +file --the directory described by `set folder'; file is `file' X%% X X%msg_list% XA "msg_list" references one or more messages. The user Xspecifies a group of messages according to a special syntax. X X * All messages. X ^ The first message. X $ The last message. X . The current message. X N-M A range of messages between N and M, inclusive. X XIn the last case, N and M may be * ^ $ . or digits referencing Xexplicit message numbers. The range must be in ascending order. X XYou can also negate messages by placing the message list inside Xbraces, `{' `}' -- thus, the expression "2-19 {11-14}" Xreferences messages 2 through 19 except for those from 11 Xthrough 14. X XCommands can be "piped" to one another, because the return value Xof a command is a msg_list, not text. For example, X pick -f fred | lpr Xwill find all messages "from fred" and send them to the printer. X XCommands dealing with more than one message process them in Xnumeric order -- not necessarily the order specified. Thus, the Xcommand "save 1-5 9 7 6 file" will save the messages in Xascending order, not in the order given. X%% X X%preserve% X preserve [msg_list] X XThe "preserve" command saves deleted or read messages in your Xmailbox. Without explicitely setting preserve, all mail that Xyou read will be saved in ~/mbox (or set mbox). Setting the Xboolean variable "hold" is equivalent to preserving each message Xas you read it. X%% X X%save% X save/write/copy [-s|-S|-a|-A] [!] [msg_list] [filename] X XIf no filename is specified, ~/mbox (or the value of the Xvariable "mbox") is used. Save and write will append msg if X`file' already exists. Specifying the `!' will overwrite the Xfile (e.g., erasing it first). X XTo save messages to a filename beginning with a digit, escape Xthe filename with a backslash (\). X XThe "write" command will write message without the headers (msg Xbody only). Save and write both mark messages for deletion Xunless "keepsave" is set. The "copy" command is identical to X"save" except that messages are not marked for deletion X(identical to having the variable "keepsave" set). X XThe -s and -S options save messages to files named by the Xsubject of the message. If more than one message is specified, Xthen the message subject of each message is used. If -S is Xspecified, then the subject of the first message is used for all Xmessages. Spaces and forward slashes (/) are converted to Xunderscores (_). X XThe -a and -A options save messages by author's login name. X%% X X%lpr% X lpr [-n] [-h] [msg_list] X -n print body of message only (not headers) X -h print all headers with message body (default true) X -Pxx print on printer xx X%% X X%respond% X replysender/replyall [msg_list] [-r path] [mail_flags] [users] X XThe "replysender" command replies only to the sender of a Xmessage, whereas "replyall" responds to everyone on the To: and XCc: lines of the message. X XThe commands "reply" is identical to "replysender". X XIf a message list is indicated, then each message on the list is Xreplied to in the same manner. If -r is specified with a host or Xpath (uucp-style), then each address in the list is routed via Xthis path. This overrides the value of auto_route (see man page). X XThe address of the author is obtained from certain headers in Xhis message to you. Unless you specify otherwise, mush will Xsearch for the headers Reply-To: Return-Path: and From:. You Xcan override these values by setting the variable reply_to_hdr. X X set reply_to_hdr = "sender reply-to return-path from_" X XThis example shows that mush will search for (in order), the Xheaders listed in the reply_to_hdr variable. If one header isn't Xfound, then mush looks for the next in the list. If none of the Xheaders in the list are found, the default headers (mentioned Xabove) are searched. The last header listed in the example is Xthe special "From " header. See the man page for more details. X XType "mail -?" for information on legal mail flags. X%% X X%sort% X sort [-] [a|d|R|s|S] X a by author (alphabetical) X d according to date X R by subject including Re: (alphabetical) X s by subject ignoring Re: (alphabetical) X S by status X XThe optional `-' flag will reverse the order of sorting. By Xdefault (no parameters), sort sorts messages by status: New, Xunread messages are first, followed by preserved messages and Xfinally the deleted messages are placed at the end. X XIf the "date_received" variable is set, sorting by date is Xdone using the date you received the message. Otherwise, Xmessages are sorted by date sent by the original author. X%% X X%pick% X pick [-x] [-f|s|t] [-h hdr] [-i] [-r msg_list] [<pat>] X [-d [-][date]] [-ago [n days] [n weeks] [n months]] X XSearch for patterns within messages. Entire messages are Xsearched for <pattern> unless -f, -h, -s, or -t is specified. XOnly one of -d, -f, -h, -s, -t and -ago can be specified; no Xpattern is used with -d and -ago. X X -x return those messages which do NOT match X -f match pattern in the "From:" field (author) only X -s match pattern in the "Subject:" header only X -t match pattern in the "To:" field only X -h hdr match pattern in specified header field only X -i ignore case of letters in when matching X -r msg_list restrict the range of messages search to msg_list X -d select messages sent on [+ after] [- before] date X A "date" is of the form: [+-][month]/[date[/year]] X Omitted fields default to today's values. Examples: X pick -d 4/20 messages on Apr 20, this year X pick -d -/2/85 on or before the 2nd, this month, 1985 X pick -d +5/4 on or after May 4, this year X pick -d / finds today's messages only X At least one `/' char must be used in a date. There is X no strong date checking; 2/30 would be considered valid. X -ago select messages relative to the current date X Date formats for "ago" are more verbose than for -d; see X the manual page for details. X%% X X%alias% XOptions for alias: X alias print all namelists X alias name print namelist associated with name X alias name namelist set "name" to the value of namelist X unalias namelist unalias names in namelist X XA "namelist" consists of one or more addresses. An address may Xbe a name already set to another list, a valid user, a file or Xa program. Filenames must be full pathnames, i.e., they must Xbegin with a '/' (or with a ~, which expands to some home dir). XA "program" must start with a pipe symbol and be encased in Xquotes: X X "|program_name" X XThe command "expand" will print addresses (including sublists) Xassociated with the given alias. X%% X X%from% XWith no parameters, "from" will print the current message's Xheader line. If given a message list, "from" will print the Xheaders of the listed messages. X XThe special parameters `-' and `+' can be given to move the Xcurrent message pointer to the previous or next message Xrespectively, while also printing that message's header. X XIf a message list was given in addition to `-' or `+', then Xthe current message pointer will be set to the first or last Xmessage, respectively, in the message list given. X XExamples: X X from - 10-30 {16} Xwill print the headers of messages 10 through 30 except for Xmessage 16 and set the current message pointer to 10. X X pick -f Dan | from + Xwill print the headers of all messages that contain "Dan" in the Xauthor's name and set the current message pointer to the last Xone of that kind in the list. X X from + Xwill print the header of the message after the current message Xand increment the current message pointer to that message. X%% X X%own_hdrs% XThis command is used to set, unset or view your personalized Xmessage headers. These headers are included in all your Xoutgoing mail. X XOptions for my_hdr: X my_hdr show all headers X my_hdr header show value of header X my_hdr header: string set header to string X un_hdr header unset header X%% X X%fkey% XThis command is used to make function key settings in Suntools X(graphics) mode. When run as a tool (-t on command line), Xchoose the Options item, and the "function key" menu option. X%% X X%cmd% XThis function is used to establish command aliases; cmd's are Xjust like aliases in the C-shell. Options are: X cmd view all commands X cmd command show value of command X cmd command "value" set command to value X uncmd command unset command X XIf you want to reference history commands within a cmd, Xescape the ! with a backslash. For example: X X cmd r 'replysender \!* ; delete -t' X Xwill cmd "r" to reply using whatever parameters you have given on Xthe command line and then delete that message and print the next Xmessage (-t parameter to "delete"). X%% X X%headers% X headers [+|-|N] [[-H]:c] X + print the next screenful (or use the 'z' command). X - print the previous screenful (or use 'z-' ). X N print a screenful starting at message number N. X -H:c where `c' is one of X a all messages (mostly for the command line parameter -H:c) X d deleted messages X n new messages X o old messages X p preserved messages X r replied-to messages X s saved messages X u unread messages X XThe "headers" command prints out a screenful of headers. XDeleted messages are not normally shown; set "show_deleted" to Xinclude deleted messages. X XThe command ":c" is equivalent to "headers -H:c". The -H can be Xomitted, i.e., "headers :c" will also work. X%% X X%hdr_format% XThis variable controls the display of message headers. Use: X set hdr_format="string" Xto change the header display. The string uses printf style Xformatting and follows these conventions: X %a address of the author X %c number of characters (bytes) in the message X %d entire date of the message (see "date_received" variable) X %f "From" field (author name and address) X %i the message-id (may or may not be present) X %l number of lines in the message X %M month name of the message X %N day of the month (number) X %n name of the author X %s subject of the message X %t "To" field (recipients) X %T time of the message (see "mil_time" variable) X %W day of the week (Sun, Mon, etc.) X %Y year of the message X %y year (last 2 digits only) X \n a newline X \t a tab X XA field specifier may be used in any % expansion. Thus, "%20s" Xwill print the first 20 characters of the Subject. No matter Xwhat the formatting string, the message number, the status of Xthe message and a '>' (if this is the "current" message) is Xbefore any user defined format is printed. X%% X X%folder% X folder/update [-N] [-r] [!] [%[user]|#|&|file] X -N Do not display the list of headers X -r read only mode (cannot write changes to this folder) X %[user] change to /usr/spool/mail/[user] (you by default) X # change to folder accessed previous to current folder X & change to "mbox" -- default is $mbox or ~/mbox X XThe "folder" command changes the current folder; with no parameters, Xit prints the name of the current folder. If `!' is specified, the Xcurrent folder is not updated before changing. X XThe "update" command updates the current folder. In this case, only Xthe -N and -r options are observed. X%% X X%prompt% XThis variable controls the prompt that mush will display. X set prompt = "string" XThe "string" follows printf style formatting conventions: X %F full path of the current working folder X %f name (path tail) of the current folder X %m current message number X %n number of new messages X %u number of unread messages X %d number of deleted messages X %t total number of messages X %T current time X %N day of the month (number) (today) X %W weekday name (today) X %M month name (this month) X %Y year (this year) X %y year (last 2 digits only) X \n newline X \t tab X%% X X%quit% X quit/exit X XThese commands end a mush session. "quit" will update your Xmailbox; if new mail has come in, you will be told so and given Xan option whether to really quit or not. "exit" will leave mush Xneither updating your mailbox nor checking for new mail. X%% X X%ls% XThe "ls" command is exactly like the UNIX command "ls". All Xparameters are the same. The variable "lister" can be set to Xa list of default parameters, thus avoiding having to specify Xthem all the time. The "folders" command is equivalent to Xdoing "ls $folder" from the Mush prompt. X%% X X%shell% X sh [command] X XIf a "command" is given, that UNIX command will be executed Xunder the Bourne shell. If no command is specified, then an Xinteractive shell will be started. The environment variable XSHELL or the local mail shell variable shell describes the Xshell to invoke. If none is set, then the default shell is Xdefined by the system administrator (currently set to csh). X XUsers on systems with job control will probably have little Xuse for the sh command. X%% X X%stop% XThe stop command sends a stop signal to the mail shell. It is Xequivalent to ^Z as it will stop the process. Since the shell Xnever needs to be exited, the command 'q' may be aliased to X"stop" and the shell may have X alias mail %mush X(assumes csh) which will bring mush into the foreground rather Xthan having to invoke a new shell. New mail will be read into Xthe shell automatically and much time and energy is saved. X%% X X%curses% XThe curses-based interface for Mush does not require a graphics Xdisplay, but does requires a terminal which can handle upline Xcursor movement capabilities. All commands are one or two Xkeystroke commands and are executed as soon as the key is typed. X XFor a list of current key-to-command bindings, use the "bind" Xcommand (defaults to 'b' in curses mode). X%% X X%bind% X bind <sequence> <curses-command> [ <parameters> ] X XBinding is done for the curses interface only. It allows the Xuser to bind keystrokes or key sequences to curses-interface Xcommands. You cannot bind keystrokes to regular mush commands Xusing bind. X XA bound key-sequence (input by the user) will be converted into Xthe curses command it is bound to. For a list of all curses Xcommands, issue the "bind" command and follow the instructions Xto get a list. Currently, parameters are ignored for all curses Xcommands except the special command "macro". X XWhen specifying sequences, you may enter almost anything at the Xkeyboard that you want to type. This includes most control Xcharacters. A special syntax is provided to specify control Xcharacters if you wish to set up default key bindings in your Xinitialization file without using real control characters. X XTo bind keystrokes that are control characters in the Xinitialization file, you must use the notation "\CX" where "X" Xis an upper-case letter representing the control key you want to Xuse. "\CN" would be control-N; "\n" is carriage return. You may Xnot bind keyboard generated signals; for most users, those key Xsequences are control-C and control-\. For users with job Xcontrol, the suspend characters (usually control-Z and Xcontrol-Y) are also ignored. X XTo specify the escape key, use "\E"; "\C[" will not work. X XTrying to bind a key sequence which prefixes another sequence is Xan error and the user is warned that the longer binding will not Xwork. The binding will take place, however, because it is Xpossible to unbind the shorter sequence, thus validating the Xlonger sequence. X XThe special curses command "macro" allows a string to be Xexecuted just as if the user typed it directly. Issue the X"bind-macro" command for more details. X%% X X%msg_flags% X flags [msg_list] [[+|-] [D N O P R S r U]] X XThis command displays the status of messages by default. XIf a list is specified, it will tell which bits of the Xmessage are set: Delete, New, Old, Preserved, Read, Saved Xreplied-to, and Unread. If any (one or more) of the bits Xare given and no + or - modifier is specified, then the Xstatus of each message in the list will be set to that Xstatus absolutely (other status flags are lost). However, Xif a + or - is specified, then the status is modified for Xthat bit to on (+) or off (-). X XIf no list is given, then the list of messages is taken Xfrom a pipe (if piped) or the current message is used. X%% X X%setenv% X setenv VARIABLE [value] X XVariable names may be any string, but traditionally environment Xvariables are all upper case. If no "value" is specified, then Xthe variable name will be set to an empty string. If the value Xcontains spaces, you should enclose the string in quotation Xmarks. Use printenv to print a list of all your environment Xvariables. X%% X X%unsetenv% X unsetenv VARIABLE X XYou must specify one and only one variable to unset in your Xenvironment variable settings. Use printenv to print a list of Xall your environment variables. X%% X X%edit_msg% X edit_msg [msg_list] X XThe "edit_msg" command lets you edit messages in your folder. XWhen editing messages, be careful not to remove certain message Xheaders such as Date:, From:, or any others that look important. XIf you remove or change something you shouldn't have, you will Xbe notified and the temporary file used to edit the message will Xnot be removed. X%% X X%bind-macro% X bind-macro [<sequence> [<expansion>]] X XThe "bind-macro" command allows you to set macros in curses Xmode, so that one keystroke (or a few) will act as though you Xhad typed a longer sequence. Using "bind-macro" is equivalent Xto specifying the "macro" special command as a parameter to Xthe "bind" command. X XGiven no parameters, "bind-macro" will list all current curses Xmode macros. Given only a <sequence>, it will show the current Xbinding for that sequence. Given both a <sequence> and an X<expansion>, it will create a macro such that, when the X<sequence> is typed in curses mode, the effect will be the same Xas if the <expansion> had been typed instead. X XThe same format for control characters that is used for the X"bind" command may be used in both the <sequence> and the X<expansion>, i.e., X \Cx control-x (where x is a capital letter) X \E the escape character (\C[ does NOT work!) X \n a newline (other C-style escapes also work) X XExample: X bind-macro F [folder]+record\n X XIf you are in curses mode and hit the F key, then the curses Xmode command "folder" will execute and +record (followed by Xa carriage return) will be entered as if you typed it. X XAlso see the "map" and "map!" commands. X%% X X%map% X map [<sequence> [<expansion>]] X XThe "map" command allows you to use one keystroke (or a few) and Xhave it act as though you had typed a longer sequence. X XGiven no parameters, "map" will list all current line mode Xmacros. Given only a <sequence>, it will show the current Xbinding for that sequence. Given both a <sequence> and an X<expansion>, it will create a macro such that, when the X<sequence> is typed in line mode, the effect will be the same Xas if the <expansion> had been typed instead. X XThe same format for control characters that is used for the X"bind" command may be used in both the <sequence> and the X<expansion>, i.e., X \Cx control-x (where x is a capital letter) X \E the escape character (\C[ does NOT work!) X \n a newline (other C-style escapes also work) X XExample: X map & print\n X XIf you are not in curses mode and hit the & key, then it will Xbe as if you typed the word "print" and hit carriage return. X XTo type a character without having the mapping expanded, precede Xthe character with a backslash (\). X XAlso see the "map!" and "bind" commands. X%% X X%map!% X map! [<sequence> [<expansion>]] X XThe "map!" command allows you to set macros in message Xcomposition mode, so that one keystroke (or a few) will act Xas though you had typed a longer sequence. map!'s take Xeffect regardless of whether you started the letter from Xcurses mode or line mode. X XGiven no parameters, "map!" will list all composition mode Xmacros. Given only a <sequence>, it will show the current Xbinding for that sequence. Given both a <sequence> and an X<expansion>, it will create a macro such that, when the X<sequence> is typed in message composition mode, the effect will Xbe the same as if the <expansion> had been typed instead. X XThe same format for control characters that is used for the X"bind" command may be used in both the <sequence> and the X<expansion>, i.e., X \Cx control-x (where x is a capital letter) X \E the escape character (\C[ does NOT work!) X \n a newline (other C-style escapes also work) X XExample: X map! ! <BANG> X XIf you are typing in a letter regardless of which interface you Xuse and you hit the ! key, then it would be as if you typed the Xkeys "<BANG>". X XTo type a character without having the mapping expanded, precede Xthe character with a backslash (\). X XAlso see the "bind" and "map" commands. X%% X X%eval% X eval args ... X XThis command causes its arguments to be re-parsed and then Xexecuted as a mush command. Example: X set initprompt='"$hostname:$cwd "' X eval set prompt=$initprompt X%% X X%pipe_msg% X pipe [msg-list] unix-command X XThe specified unix-command is executed. The standard input of Xthe command is the texts of listed messages, including headers Xthat are not ignored (see "ignore -?" and "set ?show_hdrs"). If Xthis command is part of a mush pipeline (|) then any list of Xmessages given is added to those taken from the pipeline. If no Xmsg-list is given and there is no pipeline, the current message Xis used. The unix-command is executed via "sh", so csh aliases Xmay not be used. X XIf invoked with a capital letter (Pipe), only the bodies of the Xmessages will be fed to the unix-command -- all headers will be Xomitted. X XExamples: X pipe 2 7 more -- send messages 2 and 7 through "more" X pipe patch -- send the current message to "patch" X 1 | Pipe nroff -- send the body of message 1 to "nroff" X%% X X%merge% X merge [-N] folder-name X XThe contents of the specified folder are read into the current Xfolder. If -N is not specified, a header summary is printed Xfor each message read (see "headers -?"). X XA list of all the merged messages is returned for use in pipes. X%% X X%echo% X echo [-n] [-h | -p] args X XEcho simply echoes the parameters to the command back to the user. X XIf the -n flag is given, then no newline is appended. XIf the -h flag is given, then echo looks for formatting parameters Xas if the "from" command were given on the "current" message. XIf the -p flag is given, then echo looks for formatting parameters Xas if your prompt were changed temporarily. X XExamples: X echo -h This message is from %a and is dated %d Xmight produce: X This message is from island!argv and is dated Dec 14, 1988. X X echo -p There are %n new messages to read in %f. Xmight produce: X There are 5 new messages to read in /usr/spool/mail/argv. X XNote that -h and -p cannot be specified together. X%% X X%undigest% X undigest [-m] [msg_list] [filename] X XA "digest" is a mail message which is a collection of other mail messages Xmailed to a "moderator" by other users. The moderator compiles all the Xmessages into a folder and sends the result to all the subscribers of the Xmailing list. The undigest command disassembles the entries into the set Xof messages which comprises the digest. X XThe -m option will merge these messages into the current folder. Otherwise, Xif a filename is specified, a new folder is created and the user can change Xfolders to read the messages separately. X XIf a message list is specified, each digest is disassembled to the same Xfilename (if given). If no filename is given and the user did not request Xa merge, then a folder is created based on the subject of the digest. X%% END_OF_FILE if test 27197 -ne `wc -c <'cmd_help'`; then echo shar: \"'cmd_help'\" unpacked with wrong size! fi # end of 'cmd_help' fi if test -f 'msgs.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'msgs.c'\" else echo shar: Extracting \"'msgs.c'\" \(24063 characters\) sed "s/^X//" >'msgs.c' <<'END_OF_FILE' X/* @(#)msgs.c (c) copyright 10/18/86 (Dan Heller) */ X X#include "mush.h" X Xvoid Xdisplay_msg(n, flg) Xregister int n; Xlong flg; X{ X if (ison(msg[n].m_flags, DELETE) && !do_set(set_options, "show_deleted")) { X print("Message %d deleted; ", n+1); X#ifdef SUNTOOL X if (istool) X print_more("Select UNDELETE to read."), do_clear(); X else X#endif /* SUNTOOL */ X if (iscurses) X print_more("Type 'u' to undelete."); X else X print("Type 'undelete %d' to undelete\n", n+1); X return; X } X set_isread(n); X if (ison(flg, M_TOP)) { X turnon(flg, NO_HEADER); X print("Top of "), turnon(glob_flags, CONT_PRNT); X } X X#ifdef MMDF X turnon(flg, NO_SEPARATOR); X#endif /* MMDF */ X if (!istool && isoff(flg, NO_PAGE) && X crt < msg[n].m_lines && isoff(flg, M_TOP)) { X char buf[32], *pager = do_set(set_options, "pager"); X if (!pager) X pager = DEF_PAGER; X if (!*pager || !strcmp(pager, "internal")) X pager = NULL; /* default to internal pager if pager set to "" */ X (void) do_pager(pager, TRUE); /* start pager */ X (void) do_pager(sprintf(buf, "Message #%d (%d lines)\n", X n+1, msg[n].m_lines), FALSE); X (void) copy_msg(n, NULL_FILE, flg); X (void) do_pager(NULL, FALSE); /* end pager */ X } else { X print("Message #%d (%d lines)\n", n+1, msg[n].m_lines); X (void) copy_msg(n, stdout, flg); X } X} X X/* X * copy message 'n' to file "fp" according to various flag arguments X * return number of lines copied or -1 if system error on fputs. X * If "fp" is null, send to internal pager. This can only happen from X * display_msg above. X */ Xcopy_msg(n, fp, flags) Xregister int n; Xregister FILE *fp; Xu_long flags; X{ X register int ignoring = 0, lines = 0; X register char *indent_str; X int on_hdr = 1, top, squeeze = 0; X char line[BUFSIZ], *show_hdrs = NULL; X X still_more = 0; X if (ison(flags, M_TOP)) { X register char *p = do_set(set_options, "toplines"); X top = (p)? atoi(p) : crt; X } X /* When updating to a folder, always write all headers! */ X if (ison(flags, UPDATE_STATUS)) X turnon(flags, NO_IGNORE); X else if (do_set(set_options, "alwaysignore")) X turnoff(flags, NO_IGNORE); X if (isoff(flags, NO_IGNORE)) { X if (do_set(set_options, "squeeze")) X squeeze = 1; X show_hdrs = do_set(set_options, "show_hdrs"); X } X X#ifdef SUNTOOL X if (istool && (!fp || fp == stdout)) { X register int x = (msg[n].m_lines + 2) * l_height(curfont); X X if (x > 32765) { /* to overcome a bug in pixrects that sun won't fix */ X print("message too big to display using this font"); X return 0; X } X if (x < msg_rect.r_height) /* make it at least as big as the window */ X x = msg_rect.r_height; X /* If the window isn't big enough, an infinite loop occurs in Addstr */ X if (x < 2 * l_height(curfont) || msg_rect.r_width < 3*l_width(curfont)) X return 0; X do_clear(); X lock_cursors(); X /* msg_pix is for Addstr() */ X if (!(msg_pix = mem_create(msg_rect.r_width, x, 1))) { X error("mem_create"); X return 0; X } X pr_rop(msg_pix, 0,0, msg_rect.r_width-1, x-1, PIX_CLR, 0,0,0); X on_hdr = 1; X } X#endif /* SUNTOOL */ X if (ison(flags, INDENT)) { X if ((indent_str = do_set(set_options, "pre_indent_str"))) { X char *old_fmt = hdr_format; X hdr_format = indent_str; X fprintf(fp, "%s\n", compose_hdr(n) + 9); /* magic number 9 !! */ X hdr_format = old_fmt; X } X if (!(indent_str = do_set(set_options, "indent_str"))) X indent_str = DEF_INDENT_STR; X } X /* "line" used as dummy here, since 0 bytes read */ X if (!msg_get(n, line, 0)) { X error("Unable to find msg %d", n+1); X return -1; X } X while (still_more < msg[n].m_size && fgets(line, sizeof (line), tmpf)) { X still_more += strlen(line); X#ifdef MMDF X if (ison(flags, NO_SEPARATOR)) { X if (!strncmp(line, MSG_SEPARATOR, 4)) X continue; X } X#endif /* MMDF */ X /* X * If squeeze is one, all blanks lines squeeze down to one blank line. X * If squeeze is two, squeezing is in progress so wait for the next \n. X */ X if (*line == '\n') { X if (on_hdr) /* blank line -- end of header */ X turnoff(flags, NO_HEADER), on_hdr = 0; X if (squeeze > 1) X continue; X else if (squeeze) X squeeze = 2; X } else if (squeeze > 1) X squeeze = 1; X X if (ison(flags, UPDATE_STATUS)) X if (!strncmp(line, "Status:", 7)) X continue; /* ignore this and other "Status" lines */ X else if (!on_hdr) { X /* preserve NEW/UNREAD status on preserved messages */ X register char *p = line; X p += Strcpy(p, "Status: O"); X if (isoff(msg[n].m_flags, UNREAD) && X isoff(msg[n].m_flags, PRESERVE)) X *p++ = 'R'; X if (ison(msg[n].m_flags, SAVED)) X *p++ = 'S'; X if (ison(msg[n].m_flags, REPLIED)) X *p++ = 'r'; X *p++ = '\n', *p = 0; X fputs(line, fp); X (void) strcpy(line, "\n"); X turnoff(flags, UPDATE_STATUS); X } X if (on_hdr && (isoff(flags, NO_IGNORE) || ison(flags, FORWARD))) { X register char *p = any(line, " \t:"); X if (!p) X ignoring = 0, on_hdr = 0; X else if (ignoring) X if (*p != ':') { X Debug("Ignoring: %s", line); X continue; X } else X ignoring = 0; X if (p && *p == ':') { X *p = 0; X ignoring = 0; X if (show_hdrs) { X if (!chk_two_lists(line, show_hdrs, ":, \t")) X ignoring = 1; X } else if (ison(flags, FORWARD)) { X if (chk_two_lists(line, IGNORE_ON_FWD, ":, \t")) X ignoring = 1; X } else { X register struct options *opts; X for (opts = ignore_hdr; opts; opts = opts->next) X if (!lcase_strncmp(opts->option, line, -1)) { X ignoring = 1; X break; X } X } X *p = ':'; X if (ignoring) { X Debug("Ignoring: %s", line); X continue; X } X } X } X if (!on_hdr && ison(flags, M_TOP) && !--top) X break; X if (isoff(flags, NO_HEADER)) { X /* note that function returns the number of lines */ X lines++; X#ifdef SUNTOOL X if (istool && (!fp || fp == stdout)) { X Addstr(line); X continue; X } X#endif /* SUNTOOL */ X if (ison(flags, INDENT)) X fputs(indent_str, fp); X if (!fp) { X if (do_pager(line, FALSE) == EOF) X return -1; X } else if (fputs(line, fp) == EOF) X /* Pipe broken, out of file space, etc */ X return -1; X } X } X if (ison(flags, INDENT) && X (indent_str = do_set(set_options, "post_indent_str")) && *indent_str) { X char *old_fmt = hdr_format; X hdr_format = indent_str; X fprintf(fp, "%s\n", compose_hdr(n)+9); /* magic number 9 !! */ X hdr_format = old_fmt; X } X#ifdef SUNTOOL X if (istool && (!fp || fp == stdout)) { X unlock_cursors(); X txt.y = still_more = msg_rect.r_height; X scroll_win(0); /* causes a display */ X } X#endif /* SUNTOOL */ X return lines; X} X X/* X * copy tempfile back to folder. X * Return 1 on success, 0 on failure. X */ Xcopyback(prompt) Xchar *prompt; X{ X register int i=0, j=0, k=0; X register long flg = 0; X register FILE *mbox = NULL_FILE, *mail_fp = NULL_FILE; X#ifndef DOT_LOCK X#ifdef SYSV X FILE *save_mail_fp = NULL_FILE; X#endif /* SYSV */ X#endif /* !DOT_LOCK */ X char *mbox_file, action = 0; X int hold = 0, delete_it = 0, dont_unlink = FALSE; X int isspool, keepsave; X static int first = 1; X X /* X * if there is new mail in this folder, the user is notified and X * prompted if he really wants to update the folder. He's either X * quitting or changing folders, so let him read the new mail first. X */ X if (!first && check_new_mail() > 0) { X if (!istool) { X char buf[16]; X if (iscurses) X putchar('\n'), turnon(glob_flags, CNTD_CMD); X print("%s [n] ", prompt); X buf[0] = 0; X if (!Getstr(buf, sizeof (buf), 0) || lower(*buf) != 'y') X return 0; X } X } X first = 0; X X /* If the user hasn't changed anything, just return true */ X if (isoff(glob_flags, DO_UPDATE)) X return 1; X if (ison(glob_flags, READ_ONLY)) { X print("Unable to update %s: read only\n", mailfile); X return 0; /* user should use "exit" instead of "quit". */ X } X if (!msg_cnt) /* prevent unnecessary overwrite */ X return 1; X X#ifdef SUNTOOL X if (istool) { X timerclear(&(mail_timer.it_interval)); X timerclear(&(mail_timer.it_value)); X } X#endif /* SUNTOOL */ X X /* open mbox if: "autodelete" AND "hold" are NOT set. */ X if (!strcmp(mailfile, spoolfile) X && !(delete_it = !!do_set(set_options, "autodelete")) X && !(hold = !!do_set(set_options, "hold"))) { X register char *p; X int x = 1; /* tell getpath to ignore "ENOENT" if file not found */ X X if (!(p = do_set(set_options, "mbox"))) X p = DEF_MBOX; X mbox_file = getpath(p, &x); X if (x) { X if (x > 0) X print("%s is a directory.\n", mbox_file); X else X print("Unable to open %s: %s\n", p, mbox_file); X mbox = NULL_FILE; X } else { X if (Access(mbox_file, F_OK) == -1) /* does it exist? */ X mbox = mask_fopen(mbox_file, "w"); X else X mbox = mask_fopen(mbox_file, "a"); X if (!mbox) X error("Unable to write to %s", mbox_file); X } X } X#ifdef DOT_LOCK X if ((i = dot_lock(mailfile)) == 0) X#endif /* DOT_LOCK */ X#ifdef DOT_LOCK X mail_fp = mask_fopen(mailfile, "w+"); X#else /* !DOT_LOCK */ X /* We can't lock a file unless we have an fd, but "w+" will zero X * the file. If the lock later failed for any reason (possible X * race condition with an MTA), we would lose all current mail. X * So, open read/write (if possible) and truncate later. X */ X mail_fp = mask_fopen(mailfile, "r+"); X#endif /* DOT_LOCK */ X if (!mail_fp) { X error("Unable to rewrite %s", mailfile); X if (mbox) X fclose(mbox); X return 0; X } X if (i != 0 || lock_file(mailfile, mail_fp) == -1) { X#ifndef DOT_LOCK X error("WARNING: unable to lock %s", mailfile); X#endif /* DOT_LOCK */ X if (mail_fp) X close_lock(mailfile, mail_fp); X if (mbox) X fclose(mbox); X return 0; X } X#if !defined(DOT_LOCK) && defined(SYSV) X /* SysV can't truncate a file in the middle, so we can't just X * write to mail_fp and close. Instead, we save the mail_fp X * and reopen for writing, ignoring our own lock. After updating, X * we can safely fclose both file pointers. X */ X save_mail_fp = mail_fp; X /* This could fail if we run out of file descriptors */ X if (!(mail_fp = fopen(mailfile, "w"))) { X error("WARNING: unable to reopen %s for update", mailfile); X if (save_mail_fp) X close_lock(mailfile, save_mail_fp); X if (mbox) X fclose(mbox); X return 0; X } X#endif /* SYSV && !DOT_LOCK */ X X print("Updating \"%s\"", mailfile); X X turnon(flg, UPDATE_STATUS); X turnon(glob_flags, IGN_SIGS); X X keepsave = !!do_set(set_options, "keepsave"); X isspool = !strcmp(mailfile, spoolfile); X X for (i = 0; i < msg_cnt; i++) X /* check to see if message is marked for deletion or, if read and not X * preserved, delete it if autodelete is set. Otherwise, save the X * message in the spool file if hold is set. If all fails, save in mbox. X */ X if (ison(msg[i].m_flags, DELETE) X || ison(msg[i].m_flags, SAVED) && !keepsave && X isoff(msg[i].m_flags, PRESERVE) && isspool X || isoff(msg[i].m_flags, UNREAD) && isoff(msg[i].m_flags, PRESERVE) X && delete_it) { X Debug("%s %d", X (action!='d')? "\ndeleting message:" : "", i+1), action = 'd'; X continue; X } else if (ison(msg[i].m_flags, UNREAD) || X ison(msg[i].m_flags, PRESERVE) || hold || !mbox) { X j++; X Debug("%s %d", X (action!='s')? "\nsaving in spool:" : "", i+1), action = 's'; X if (copy_msg(i, mail_fp, flg) == -1) { X error("WARNING: unable to write back to spool"); X print("ALL mail left in %s\n", tempfile); X print("Spool mailbox may be corrupted.\n"); X dont_unlink = TRUE; X break; X } X } else if (isspool) { /* copy back to mbox */ X k++; X if (copy_msg(i, mbox, flg) == -1) { X error("WARNING: unable to write to mbox"); X print("Unresolved mail left in %s\n", tempfile); X dont_unlink = TRUE; X break; X } X Debug("%s %d", X (action!='m')? "\nsaving in mbox:" : "", i+1), action = 'm'; X } X Debug("\n%s", mailfile); X X#ifndef DOT_LOCK X#ifdef SYSV X /* Close the write file pointer first */ X fclose(mail_fp); X mail_fp = save_mail_fp; X#else /* !SYSV */ X /* Truncate the file at the end of what we just wrote. X * If you aren't SYSV and you still can't ftruncate(), X * you're out of luck? X */ X (void) ftruncate(fileno(mail_fp), ftell(mail_fp)); X#endif /* SYSV */ X#endif /* !DOT_LOCK */ X X close_lock(mailfile, mail_fp); X X#ifdef SUNTOOL X if (istool) { X mail_timer.it_value.tv_sec = time_out; X setitimer(ITIMER_REAL, &mail_timer, NULL); X } X#endif /* SUNTOOL */ X X /* some users like to have zero length folders for frequent usage */ X if (mbox) X fclose(mbox); X if (j) { X long times[2]; X times[1] = time(×[0]) - (long)2; X if (!strcmp(mailfile, spoolfile) && utime(mailfile, times)) X error("utime"); X print_more(": saved %d message%s\n", j, (j==1)? NO_STRING: "s"); X } else X#ifdef HOMEMAIL X if (!dont_unlink && !do_set(set_options, "save_empty")) X#else /* HOMEMAIL */ X if (strcmp(mailfile, spoolfile) && !dont_unlink && X !do_set(set_options, "save_empty")) X#endif /* HOMEMAIL */ X if (unlink(mailfile)) X turnon(glob_flags, CONT_PRNT), error(": cannot remove"); X else X print_more(": removed\n"); X else X print_more(": empty\n"); X if (k) X print("saved %d message%s in %s\n",k,(k==1)? NO_STRING:"s", mbox_file); X X turnoff(glob_flags, IGN_SIGS); X X return 1; X} X X/* X * check the sizes of the current folder (file) and the spool file. X * spool_size is the size in bytes of the user's main mailbox. X * last_size is the size of the _current_ folder the last time we checked. X * return true if the current folder has new mail. check_new_mail() checks X * for new mail in the system mailbox since it checks against last_spool_size. X */ Xmail_size() X{ X struct stat buf; X if (strcmp(mailfile, spoolfile) && !stat(spoolfile, &buf)) X spool_size = buf.st_size; X if (!*mailfile) X return 0; X if (stat(mailfile, &buf)) { X if (errno != ENOENT) X error("Unable to stat %s", mailfile); X return 0; X } X if (!strcmp(mailfile, spoolfile)) X spool_size = buf.st_size; X if (buf.st_size != last_size) { X last_size = buf.st_size; X return 1; X } X return 0; X} X Xvoid Xmail_status(as_prompt) X{ X static char buf[256]; X register int cnt = 0, new = 0, unread = 0, deleted = 0; X X for ( ; cnt < msg_cnt; cnt++) { X if (ison(msg[cnt].m_flags, UNREAD)) X unread++; X if (ison(msg[cnt].m_flags, DELETE)) X deleted++; X if (isoff(msg[cnt].m_flags, OLD)) X new++; X } X if (as_prompt) { X register char *p, *b = buf; X for (p = prompt; *p; p++) X if (*p == '\\') X switch (*++p) { X case 'n': case 'r': *b++ = '\n'; X when 't': *b++ = '\t'; X otherwise: *b++ = *p; X } X else if (*p == '%') X switch (*++p) { X case 'm': X b += strlen(sprintf(b,"%d",(msg_cnt)? current_msg+1:0)); X when 't': X b += strlen(sprintf(b, "%d", msg_cnt)); X when 'd': X b += strlen(sprintf(b, "%d", deleted)); X when 'u': X b += strlen(sprintf(b, "%d", unread)); X when 'n': X b += strlen(sprintf(b, "%d", new)); X when 'f': X { X char *tail = rindex(mailfile, '/'); X if (tail && tail[1]) X b += Strcpy(b, tail+1); X else X /* Fall through */ X case 'F': X b += Strcpy(b, mailfile); X if (ison(glob_flags, READ_ONLY)) X b += Strcpy(b, " [read-only]"); X } X when 'T': case 'D': case 'Y': case 'y': X case 'M': case 'N': case 'W': X b += Strcpy(b, Time(p, (long)0)); X otherwise: *b++ = *p; X } X else if (*p == '!') X b += strlen(sprintf(b, "%d", hist_no+1)); X else X *b++ = *p; X *b = 0; X print("%s", buf); /* use %s in case "buf" has any %'s in it */ X return; X } X (void) sprintf(buf,"\"%s\"%s: %d message%s, %d new, %d unread", X mailfile, ison(glob_flags, READ_ONLY)? " [read only]" : "", X msg_cnt, (msg_cnt != 1)? "s": NO_STRING, new, unread); X if (istool || iscurses) X (void) sprintf(buf+strlen(buf), ", %d deleted", deleted); X#ifdef SUNTOOL X if (istool) { X static char ic_text[4]; X extern struct pixrect mail_icon_image1, mail_icon_image2; X (void) sprintf(ic_text, "%3d", msg_cnt); X tool_set_attributes(tool, X WIN_LABEL, buf, X WIN_ICON_LABEL, ic_text, X WIN_ICON_IMAGE, ison(glob_flags, NEW_MAIL)? X &mail_icon_image2 : &mail_icon_image1, X 0); X } else X#endif /* SUNTOOL */ X#ifdef CURSES X if (iscurses) { X move (0, 0); X printw("%-3d %-.*s", X ((msg_cnt)? current_msg+1 : 0), COLS-5, buf), clrtoeol(); X } else X#endif /* CURSES */ X puts(buf); X return; X} X X/* X * For uucp mailers that use >From lines with "remote from <path>": X * (where "path" is a hostname or pathnames) X * X * a. Set the return_path to the empty string. X * b. For each From_ or >From_ line: X * c. Save the username (second token). X * d. Save the date (3-7 tokens). X * e. If it has a "remote from" then append the remote host X * (last token) followed by a "!" to the return_path. X * f. If the saved username has a '@' but no '!' then convert it X * to UUCP path form. X * g. Append the saved username to return_path. X */ Xparse_from(fp, path) XFILE *fp; Xchar path[]; X{ X char user[256], buf[256]; /* max size for each line in a mail file */ X register char *p; X long save_offset = ftell(fp); X X path[0] = '\0'; X while (fgets(buf, sizeof buf, fp)) { X if (strncmp(buf, ">From ", 6)) X break; X p = buf + 6; X X (void) sscanf(p, "%s", user); X X while (p = index(p+1, 'r')) { X if (!strncmp(p, "remote from ", 12)) { X char *p2 = path+strlen(path); X skipspaces(12); X sscanf(p, "%s", p2); /* add the new machine to current path */ X (void) strcat(p2, "!"); X break; X } X } X X if (p) X (void) bang_form(path + strlen(path), user); X save_offset = ftell(fp); X } X fseek(fp, save_offset, L_SET); X} X X/* X * Scan a file and select messages from it and append them to the current folder X * X * If "append" is 1, start where we left off (held in msg[cnt].m_offset) X * and scan for messages. Append all messages found until EOF. X * X * If "append" is 2, we're merging in a new file, so start at the end of X * the present folder and append all messages found until EOF. X * X * If "append" is 0, then the message separator must exist once and X * only once. All extra occurrences of the separator is preceded by a '>'. X * The list argument will be the message number to replace in the current X * folder with the message read in from other filename. X */ Xload_folder(file, append, list) Xchar *file, *list; Xint append; X{ X char buf[BUFSIZ]; X int lines = 0, msg_found = 0, had_error = 1; X int get_status = 1, cnt; X long bytes, ftell(); X struct msg old; X char wkday[4], month[4]; X int day, year, mins, hour; X FILE *fp; X#ifdef MMDF X int begin_sep = 0; /* track beginning vs ending separators */ X#endif /* MMDF */ X X if (!(fp = fopen(file, "r"))) { X error("Unable to open %s", file); X return -1; X } X X if (append) { X cnt = msg_cnt; X (void) fseek(fp, append == 1 ? msg[cnt].m_offset : 0L, L_SET); X } else { X cnt = (int)list; X old = msg[cnt]; X } X X if (isoff(glob_flags, READ_ONLY)) { X if (tmpf) X (void) fclose(tmpf); X if (!(tmpf = mask_fopen(tempfile, "a"))) { X error("Unable to open %s for appending", tempfile); X (void) fclose(fp); X return -1; X } X (void) fseek(tmpf, 0L, 2); /* assure we're at the end of the file */ X } else if (append == 2) { X /* you can't merge in a folder to a read-only folder */ X (void) fclose(fp); X return -1; X } X X#ifdef MMDF X if (!append) { X strcpy(buf, MSG_SEPARATOR); X goto do_headers; X } X#endif /* MMDF */ X while (fgets(buf, sizeof (buf), fp)) { X#ifndef MSG_SEPARATOR X if (!strncmp(buf, "From ", 5) && X /* From uucp Wed Jan 11 20:40:00 1989 */ X (sscanf(buf+5, "%*s %3s %3s %d %d:%d:%*d %d", X wkday, month, &day, &hour, &mins, &year) == 6 || X /* From uucp Wed Jan 11 20:40:00 PST 1989 */ X sscanf(buf+5, "%*s %3s %3s %d %d:%d:%*d %*s %d", X wkday, month, &day, &hour, &mins, &year) == 6 || X /* From uucp Wed Jan 11 20:40 PST 1989 */ X sscanf(buf+5, "%*s %3s %3s %d %d:%d %*s %d", X wkday, month, &day, &hour, &mins, &year) == 6)) X#else /* MSG_SEPARATOR */ X if (!strncmp(buf, MSG_SEPARATOR, strlen(MSG_SEPARATOR))) X#endif /* MSG_SEPARATOR */ X { X#ifdef MMDF X if (!append) X fputc('>', tmpf); X else if (begin_sep = !begin_sep) Xdo_headers: X#else /* MMDF */ X if (!append && msg_found) X fputc('>', tmpf); X else X#endif /* MMDF */ X { X msg_found++; X had_error = 0; X if (append && cnt == MAXMSGS-2) { X wprint("WARNING: exceeded %d messages.\n", MAXMSGS); X wprint("Not all messages have been loaded.\n"); X had_error++; X break; X } X if (ison(glob_flags, READ_ONLY)) X bytes = ftell(fp) - strlen(buf); X else { X char path[256]; X parse_from(fp, path); X if (path[0]) X (void) sprintf(buf, "From %s %s %s %d %d:%d:00 %d\n", X path, wkday, month, day, hour, mins, year); X bytes = ftell(tmpf); X } X /* finish up message structure from previous message. X * if this is incorporating new mail, check "lines" to X * see if previous message has already been set! X */ X if (cnt && lines) { X msg[cnt-1].m_size = bytes - msg[cnt-1].m_offset; X msg[cnt-1].m_lines = lines; X } X if (isoff(glob_flags, READ_ONLY) && fputs(buf, tmpf) == -1) { X error(tempfile); X had_error++; X break; X } X msg[cnt].m_offset = bytes; X msg[cnt].m_flags = 0L; X lines = 0; X#ifndef MSG_SEPARATOR X if (year > 1900) X year -= 1900; X (void) sprintf(buf, "%02d%02d%02d%02d%02d%.3s", X year, month_to_n(month), day, hour, mins, wkday); X strdup(msg[cnt].m_date_recv, buf); X#endif /* MSG_SEPARATOR */ X turnon(msg[cnt].m_flags, UNREAD); /* initialize */ X X /* we've read the "From " line(s), now read the rest of X * the message headers till we get to a blank line. X */ X while (fgets(buf, sizeof (buf), fp) && (*buf != '\n')) { X register char *p = buf; X if (!strncmp(buf, "Date:", 5)) X strdup(msg[cnt].m_date_sent, parse_date(p+5)); X if (get_status && X !(get_status = strncmp(p, "Status:", 7))) { X /* new mail should not have a Status: field! */ X turnon(msg[cnt].m_flags, OLD); X for (p += 8 ; *p != '\n'; p++) X switch(*p) { X case 'R': turnoff(msg[cnt].m_flags, UNREAD); X when 'P': turnon(msg[cnt].m_flags, UNREAD); X when 'S': turnon(msg[cnt].m_flags, SAVED); X when 'r': turnon(msg[cnt].m_flags, REPLIED); X when 'O': ; /* do nothing */ X otherwise : X if (ison(glob_flags, WARNING)) X print("unknown msg status flag: %c",*p); X } X } X if (isoff(glob_flags,READ_ONLY) && fputs(buf, tmpf) == -1) { X error(tempfile); X had_error++; X break; X } X lines++; X } X if (!msg[cnt].m_date_sent || !*msg[cnt].m_date_sent) X if (!msg[cnt].m_date_recv || !*msg[cnt].m_date_recv) { X wprint("Message %d has *no* date!?\n", cnt+1); X msg[cnt].m_date_sent = msg[cnt].m_date_recv = X "0000000000XXX"; X } else X strdup(msg[cnt].m_date_sent, msg[cnt].m_date_recv); X else if (!msg[cnt].m_date_recv || !*msg[cnt].m_date_recv) X strdup(msg[cnt].m_date_recv, msg[cnt].m_date_sent); X if (had_error) X break; X if (append && list) X set_msg_bit(list, cnt); X if (append) X cnt = ++msg_cnt; X get_status = 1; X } X } X if (msg_found) { X lines++; X if (isoff(glob_flags, READ_ONLY) && fputs(buf, tmpf) == -1) { X error(tempfile); X had_error++; X break; X } X } X } X if (msg_found && append != 1) X turnon(glob_flags, DO_UPDATE); X#ifdef MMDF X if (!append) X fputs(END_MSG_SEP, tmpf); X#endif /* MMDF */ X if (had_error) { X if (!append) X msg[cnt] = old; X if (!msg_found && !append) X print("File not left in correct message format.\n"); X } else { X if (append) X cnt--; X if (isoff(glob_flags, READ_ONLY)) X msg[cnt].m_size = ftell(tmpf) - msg[cnt].m_offset; X else X msg[cnt].m_size = ftell(fp) - msg[cnt].m_offset; X msg[cnt].m_lines = lines; X /* remember where we were to seek to for when we append new mail */ X if (append) X cnt++; X } X if (append) X msg[cnt].m_offset = ftell(fp); X fclose(fp); X if (isoff(glob_flags, READ_ONLY)) { X fclose(tmpf); X if (!(tmpf = fopen(tempfile, "r"))) { X error("Unable to open %s for reading", tempfile); X return -1; X } X } X return !had_error; X} END_OF_FILE if test 24063 -ne `wc -c <'msgs.c'`; then echo shar: \"'msgs.c'\" unpacked with wrong size! fi # end of 'msgs.c' fi echo shar: End of archive 11 \(of 19\). cp /dev/null ark11isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 19 archives. rm -f ark[1-9]isdone ark[1-9][0-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0 -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.