Amiga-Request@cs.odu.edu (Amiga Sources/Binaries Moderator) (02/04/90)
Submitted-by: overload!dillon (Matt Dillon) Posting-number: Volume 90, Issue 054 Archive-name: unix/uucp-1.03d/part10 #!/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 10 (of 16)." # Contents: src/dmail/dmail.help src/sendmail/sendmail.c # Wrapped by tadguy@xanth on Sat Feb 3 20:51:17 1990 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'src/dmail/dmail.help' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'src/dmail/dmail.help'\" else echo shar: Extracting \"'src/dmail/dmail.help'\" \(23627 characters\) sed "s/^X//" >'src/dmail/dmail.help' <<'END_OF_FILE' X X'help TOPIC' for more information on a command. Many commands take Xmessage numbers or message lists: X [msg] is an optionaly specified message number (usually the X operation is on the current message if no number is X specified) X <list> is an optionaly specified message list. Message lists X consists of number ranges of the form N -N N- or N-N, and X keywords (help keywords) X X XOTHER HELP AVAILABLE (in addition to the commands): X pager sendmail tilde header newmail keywords enviroment X XDMAIL written by Matthew Dillon, U.C. Berkeley -UCF X X(C)Copyright 1985-1989 by Matthew Dillon X X.pager Xset page [rows/command] X X 'page' is a SET variable which determines the type of paging list and Xdisplay commands will use. If not defined, no filter is used. If a numerical Xvalue (i.e. 24) is specified, the page length will be set to that value and Xa rather stupid, simple internal paging routine will be used. If the Xvariable is set to an alpha-numeric string, output will be piped through Xthat filter. For instance: X X unset page -no paging X set page more -use more filter X set page page -use 'page' filter X set page > x -redirect to a file (be careful) X set page 24 -use internal paging, page length 24 rows. X X For internal paging, use <return> to continue, or your INTR Xcharacter to break out. Note that if you have paging set to a program, Xresponse time may be slower because dmail must execute that program. X X.sendmail Xset sendmail sendmail-path X X Inform DMAIL as to where the sendmail program is. The default X(variable unset) is /usr/lib/sendmail. This variable is useful only for Xthose of us who like to hack-up our own sendmail. X X.tilde X~ ~user directory expansion X X In all expressions except those within double quotes, the tilde X`~` will be expanded to either your home directory, or the directory of Xa specified user, depending. Note that '*' and '?' are not expanded by XDMAIL, though they will be by any shell commands you execute. X X It is probably a good idea to use ~ in any aliases, etc... in case Xyou change directories using the 'cd' command. X X alias resource source ~/.dmailrc -example using ~ X X.header Xset header filepath X X Set the location of your header file, which will appended to the Xscratch mail file before you are placed in the editor (usually vi). X X set header ~/.header -set header file to ~/.header X unset header -no header file X X.newmail XWhen new mail comes in: X X Whenever newmail arrives, it will be automatically incorporated into Xa running DMAIL. However, to see it, you must 'select all' (or select on Xanything that would include it). X X.keywords X.range X.message XKEYWORDS, MESSAGE LISTS X X Many commands in DMAIL require a range of messages be given. A Range Xconsists of message numbers (3 4 5), message ranges (1-45 -9 9-), and Xkeywords. Keywords select certain messages from the entire SELECTED list: X X all -All messages X tag -All TAGGED messages X mark -All MARKED (read) messages X deleted -All DELETED messages X written -All WRITTEN messages X untag -All messages NOT TAGGED X unmark -All messages NOT MARKED (i.e. read) X undeleted -All messages NOT DELETED X unwritten -All messages NOT WRITTEN X X Only the first three letters need be specified. For instance, the X'all' keyword selects all the messages currently selected. You could select Xon some subject, say, and then 'delete all'. X X The message number 0 refers to the last message. the 'undeleted' Xkeyword exists only for completeness; you will probably never use it. X X.ver X.version XVER X X returns the version number. X X.if X.else X.endif XIF [!]variable XELSE XENDIF X X Conditionals. Example: X X if verbose X .... do stuff if the variable exists X else X ... do stuff if the variable does not exist X endif X if !page; echo no page variable; endif X X.nobreak X.breakok XNOBREAK XBREAKOK X X Disable or Enable your INTR key. This command is stackable, thus Xthere is no problem with recursive aliases which use it. Be careful that Xyou match any NOBREAK to a BREAKOK, or you may accidently put yourself into XNOBREAK mode (and a single BREAKOK may not fix it because it's stackable). X X A good example would be a command which needs the page variable set Xfor the duration... say an alias to TYPE to a file: X Xalias file "%_a nobreak; set _b $page; set page cat > $_a; type; set page $_b; unset _b; breakok" X X You can see that if the user were to hit his INTR character at the Xwrong time, the page variable would be incorrectly set. The nobreak/breakok Xcommands fix this problem. For simplicity, most people don't bother with Xbreak/nobreak, as it clutter's aliases up. X X.delete XDELETE <message list> X X Mark the specified messages for deletion. They will no longer show up Xon LISTings, (gaps will appear in message numbering). However, you can Xstill TYPE them, if you remember the message number, and you can always XUNDELETE them. Remember that the particular message # you've deleted Xmay be different if you change the SELECT parameters. For example, Xmessage #3 selecting 'To' & 'foo' may actually be message #45 when you Xare selecting ALL (see SELECT). Upon a QUIT, messages marked for Xdeletion are actually deleted from the mail file. X X.undelete XUNDELETE <message list> X X UNDELETES messages. Without arguments, UNDELETE will Xrestore the last message you deleted. Specifying 'all' (undelete all), will Xundelete any deleted messages in the currently selected message list. X X.header XHEADER [message] X X Display the entire header of a message. This does not cause the Xmessage to be marked 'read'. TYPE, on the other hand, only displays Xheader information specified by SETLIST. X X.type XTYPE [message] X X Type the text of a message. Only header fields defined by SETLIST Xare displayed. Otherwise, only the text is displayed. This marks Xthe particular message as 'read', and also makes that message the Xcurrent message. X X.echo XECHO [string] X X Echo the given string onto the screen. X X.go XGO # X go to a message, don't type it out or anything. Remember that you Xcan go to the last message by using the message # 0. By placing a keyword X(help range), you can go to the first TAGGED message, etc... X X.reply X.Reply XREPLY X X Reply to the current letter. There are two forms of 'reply'. The Xfirst does not include the senders original letter, the second does. XIn both cases, Dmail will place you in VI, with the To:, Cc:, and Xsubject lines filled out. The second form is 'Reply', with an Xupper case 'R'. This form includes the sender's message shifted to Xthe right with '>'s on the left hand side. See FORWARD for another Xmethod of replying to mail. X X In any case, you may get the sender's letter by reading the file '#' Xfrom VI. That sequence would be ':r\\#' X X See MAIL for more information on VI X X.forward XFORWARD [user user user....] X X Forward the current message to a list of users. The sender's Xentire message is placed in the text portion. The To: field will Xcontain the user's named above, and the Subject: field will contain Xa 'Fo:' (you append your own subject) X X See MAIL for more information on VI X X.mail XMAIL [user user user user...] X X Mail to [users]. You are given a VI to work from, and may modify Xany of the header fields. the From: field is inserted automatically Xby SENDMAIL, but you can overide it if you wish. X X Quitting out of VI without writing the output file will cause an Xabort, and no mail will be sent. Additionaly, you may use the 'vibreak' Xvariable to enable your INTR character (usually CTL-C) to break you out of XVI. X X When modifying the users list in To and Cc fields, remember that Xthey should be all comma delimited, or none comma delimited. X X.select XSELECT ALL XSELECT Field match match match match... XSELECT Field !match XSELECT Field match match match , Field match , ..... X X Select what you want to look at. Select will take the field header Xyou supply and attempt to match arguments with that field in the mail Xfile. You can then work on the selected material as if the rest of Xyour mail didn't exist. For instance, 'select To dillon', will select Xall messages addressed to you. Note that case is checked for the XFIELD-HEADER, but not for arguments, so the latter will also find Xanything addressed to Dillon or DILLON. You only have to give a Xpartial match, so 'select To di' would work just as well. X X Select then, allows you to quickly find what you want even though Xyou may have 12000 messages (though it may take a while with that many) XYou may also specify what you DON'T want to select on: X X select To !foo X Xwill select all letters not addressed to 'foo'. You may select on any Xfield you wish. At any time, you may say 'select ALL' to select the Xentire message list. Use RESELECT to select on the current message Xlist. SELECT always selects from the entire message-list X X select Cc hack , To hack X Xwill select any mail with Cc or To fields containing hack. You may Xhave as many comma operators as you wish. The comma must be a field Xof its own (spaces on either side... will be fixed in a later version) X X.reselect XRESELECT ALL XRESELECT Field match match match match... XRESELECT Field !match X X SEE SELECT. Reselect allows you to CONTINUE to narrow down a topic Xor whatever. It will select on the current message list (which you have Xalready narrowed down with SELECT or RESELECT). X X.defer XDEFER X X Deselects any marked messages .. messages marked as 'read'. This is Xas if you did a RESELECT on all unread messages in the current select field. XThus, the messages will be renumbered. To see these messages again, you must Xuse SELECT. X X.rlist <num> XRLIST <num> -<num> > 0 (next N), < 0 (prev N). XRLIST -Lists next 20 (or previous 20 if near the end) X X Relative list. See LIST for details of the list command. This Xcommand will display the next <num> messages beginning at the current Xmessage. If <num> is negative, it displays the previous 20 ending at Xthe current message. If there are not enough messages remaining in the Xforward or reverse direction, it lists in the opposite direction to try Xto bring the total messages listed to <num> X X.list XLIST <message list> XLIST -Lists all selected messages X X Display header information on a message as specified by SETLIST, Xin a one line per message format. The default lists ALL messages. X XLeftword flags: r -indicates message has been read. Message will be X moved to the destination file on QUIT X > -indicates message is the current message X w -indicates message has been written to a file. X Message will be deleted from source file on QUIT X T -indicates message has been taged by the user X X.next XNEXT X X Execute TYPE or HEADER for the next message, depending on which of XTYPE or HEADER was last executed by you X X._next X_NEXT X X Go to next message, do not print it out. X X.back XBACK X X Execute TYPE or HEADER for the previous message, depending on which Xof TYPE or HEADER was last executed by you X X._back X_BACK X X Go to previous message, do not print it out. X X.db XDB X Delete the current message, type (or header) the previous message. XThis command could not be implemented with "del;prev" due to a special case Xwhen one is on the last message. X X.dt XDT X Delete current message, type (or header) next message. This command Xwill warn you when you reach the end of the message list. X X References: DELETE and NEXT X X.enviroment XENVIROMENT VARIABLE ACCESS X X Access may be gained to enviroment variables by using $$ instead of X a single $. For example: echo $$USER X X 'help dmail' for command line options, X 'help set' for description of special variables X X.set XSET [variable [string]] X X see 'enviroment' for enviroment variables X X With no arguments, SET prints out all currently active variables. XNote that this variable list is a different list than the ALIAS list. With Xone argument, the specified variable is displayed if it exists, or created Xif it doesn't. With more than one argument, the specified variable is set Xto the specified string. Variables may be references on the command line by X$variable . The variable's contents will replace the reference. Unlike Xaliases, however, variable substitutions may take place anywhere on the Xcommand line rather than substitute just the command name. Note also that Xif you use a $ substitution for an argument of a command, the entire Xvariable's contents is ONE argument (i.e. if a = "b c d", and you say Xsomething like: 'unset $a', it would attempt to unset a single variable Xwhos name is "b c d". X X There are several reserved SET variables, which define options in XDMAIL. Changing these will modify the option: X X page set paging on or to a specific command (i.e. more) X sendmail set the path to the sendmail program X vibreak enable your INTR character even when in VI. X verbose reflects verbose option to sendmail X comlinemail set when dmail executed w/ command line mailing list X header header file to append to any messages you send. X ask ask what to do after vi'ing mail X archive file to archive any mail you send out in. X _headchar string used to precede included text, default ">" X replyfields fields to search to find the reply path X X page X X This variable determines what kind of paging is used for LIST, X TYPE, and HEADER commands. If the variable does not exist, paging X is turned off. If set to null (no string), an internal paging X routine is used. If set to a value, an internal paging routine is X used using the value as the page length. the 'page' variable can X also be set to a command, such as 'more' or 'page', in which case, X the output is piped through those commands: X X set page Turn paging on (internal page routine) X set page 25 Internal page routine... 25 rows/screen X set page more Use 'more' command to pipe output through X set page page Use 'page' command to pipe output through X X you could also conceviably say: 'set page cat > x', or X 'set page cat | lpr', but be very careful. X X sendmail X X This variable will redirect DMAIL as to where the mailer program X is. The mailer program must be compatible with /usr/lib/sendmail X which is the default used if the 'sendmail' variable isn't set X to anything: X X set sendmail bin/mysendmail X X vibreak X X This variable, when set, allows the INTR character to abort a X reply, mail, or forward command. Otherwise, if this variable is X not present, INTR will not abort the above commands. X X verbose X X This variable, when set, causes the -v flag to be sent to X sendmail. In addition, DMAIL will wait for sendmail to complete X before returning your prompt. X X comlinemail X X This variable is set when dmail is invoked with a command line X user list (e.g. dmail charlie mary mark). Usually, one uses X this variable in an IF construct. A good example would be that X you may usually CD to a mail directory, but you don't want to X CD when dmail is run with a command line user-list: X X if !comlinemail X cd ... X X alternate definition: The comlinemail variable will NOT be set X if dmail is in interactive mode. X X header X X The file specified by this variable will be appended onto the temp X vi files in reply and mail. The file is appended before you go into X vi, so when you do, what you see is still what you get. X X ask X X If set, dmail will ask you what to to (quit, send, re-edit) after you X leave the editor when sending mail. If not set, the mail is sent as X soon as you leave the editor (unless you didn't write anything). X X archive X X If set (to a file name), any mail you send out (mail/reply/etc...) X will be archived to this file. Usually, you provide a fully X specified path so cd's won't effect the file location. X X _headchar X X This string is prepend to any included text when you do an upper-case X reply (R) command. X X replyfields X X This string holds a list of fields which are searched for to X determine which one to use in the To: field of your reply. If X this variable does not exist or none of the specified fields could X be found, the 'From ' (not From:) mail header will be used. The X search ends at the first field found. Example: X X set replyfields "Reply-To: From:" X X.replyfields XSET replyfields "field1 field2 ..." X X This string holds a list of fields which are searched for to X determine which one to use in the To: field of your reply. If X this variable does not exist or none of the specified fields could X be found, the 'From ' (not From:) mail header will be used. The X search ends at the first field found. Example: X X set replyfields "Reply-To: From:" X X.> XSET _HEADCHAR "string" X X see SET. The _headchar variable determines the string prepending all X included text when you do an upper-case reply (R) command. X X.archive XSET ARCHIVE file X X if the archive variable is set to a file path, any mail you send out X will automatically be appended to that file. Dmail pre-pends a X "From ", so it is compatible with /bin/mail and so that you can X dmail -f your archive file. Additionaly, a "Date: " field is X pre-pended so you know when you sent the message. example: X X set archive ~/Dmail/arch X X since your .dmailrc is sourced even when you "dmail user .." from X your csh, putting the above line in your .dmailrc will turn on X archiving whenever you use dmail to send mail, command line or X dmail prompt. X X if unset or set to nothing, no archive is made. X X.ask XSET ASK X X if the 'ask' variable is set (set ask), dmail will ask you what to do X when you are finished editing mail rather than send it immediately. X (see 'help set') X X.alias XALIAS [variable [string]] X X Create an alias for a command. With no arguments, ALIAS will display Xall active aliases. With one argument, a particular alias is displayed (if Xit exists), or defined (if it did not previously exist). With more than one Xargument, the particular alias is set to the string list specified. X Xalias Xalias hack "select From hacker , To hacker , Cc hacker" Xalias bye quit Xalias stuff "setlist 60 To ; list" X X Usually, any arguments following the alias are appended to the Xexpansion. However, you can place such arguments inside the alias somewhere Xby using the following construction: X Xalias myecho "%var echo $var ; list" X Xmyecho hello there ---> echo hello there ; list X X to unalias an alias, use the UNALIAS command. X X.unset X.unalias XUNSET var var var... XUNALIAS var var var... X X Eradicate variables or aliases from memory. X X.setlist XSETLIST [-s] [columns] Field [columns] Field ... X X -s prevents display of the list. XSet the list format used for LIST and TYPE. The optional [columns] Xindicates how many columns to allocate for the Field specified. The XField can be a partial match. However, case is observed: X Xsetlist 18 Fro 38 Sub 10 To 0 Dat X X18 columns for the From: field, etc... when TYPEing messages, the X[columns] is ignored, and each field is printed in its entirety. XNote that 0 columns have been allocated for the Date: field. XTherefore, the Date: field will not show up on the LIST command, Xbut will show up in the TYPE command. X X.cd XCD PATH X X cd, as in csh. Changes your base directory. You can use X the shell escape '! pwd' to get your current working directory. X X.source XSOURCE file X X Source a file. The file is read in an executed in sequence. X X.preserve XPRE <message list> X X PRESERVE messages. A message is MARKED if it has been read (has an 'r' Xflag from the LIST command). Marked messages are moved from your readfile Xinto your outfile upon a QUIT. If you are reading and writing to the same Xfile (i.e. from your mbox to your mbox), the 'r' flag has no effect. X X However, if you are reading from your spool file, and want to keep Xread messages in your spool (that is, not move them to your mbox), you want Xto PRESERVE them. This command simply unmarks them, so they appear not to Xhave been read. X X.mark XMARK <message list> X X Mark messages specified as being already 'read'. Remember that if Xyou executed DMAIL without a -f option, any message 'read' at the time Xyou quit will be moved to MBOX (or file specified by -o) X X.tag X.untag XTAG <list> XUNTAG <list> X X The TAG command allow you to flag any message. You can tag a set of Xmessages, then reference them all at once. For instance, if you tag Xinteresting messages as you glance at them, you may then write them all Xto a file by 'write filename tag', or list them with 'list tag'. XAlternately, you could delete all your taged messages with a single delete Xcommand 'delete tag'. The 'tag' operand works in the same way as the 'all' Xoperand, except it works only on taged messages. X X UNTAG will untag a particular message in your message list. For Xinstance, to untag any taged messages in the entire message list, you would: X X select all X untag all OR untag tag X X Note that 'untag all' and 'untag tag' have the same effect. X X.write XWRITE file <message list> X X Write the given messages or the current message to a file. The file Xfile is appended to. Remember that you may specify 'all' to write Xall messages in the current select field to the file. Messages will be Xmarked as having been writen, and will be deleted from the mail file Xwhen you 'quit'. However, you may cause them to be kept in the mail Xfile by UNdeleting the messages (i.e. undelete all) X X You can also TAG the messages you want to write, and say X'write file tag' to write to the file all taged messages. X X.! X! [shell command] X X Give yourself a shell or execute a shell command. The shell forked Xis that specified by your SHELL enviroment variable, or /bin/sh if there is Xno SHELL enviroment variable. X X.x X.exit XX (EXIT) X X EXIT out of DMAIL without changing any files. Usually, one exits Xwith QUIT, which would cause deleted messages to disappear, and TYPEd Xmessages to go to MBOX (if you did not use the -f option with DMAIL). X X If your outfile is the same as your infile, reading a message does Xnot effect anything. X X.quit XQUIT X X Quit out of DMAIL. Delete any messages that were marked for deletion Xand if you executed DMAIL on /usr/spool/mail/ (default), any mail Xmarked 'read' will be placed in MBOX in your home directory X X.xswitch X.qswitch XXSWITCH fromfile [tofile] XQSWITCH fromfile [tofile] X X Switch to a different set of files. XSWITCH doesn't modify your Xold from and to files before switching, QSWITCH works as if you had QUIT Xstuff before switching to another set of files. X X If no [tofile] is specified, the new tofile will be the same as the Xfromfile you specify. X X.help X.? XHELP [topic] X X Give me help on a topic X X.dmail XCOMMAND LINE OPTIONS FOR DMAIL X X dmail -O [-l rcfile] -f [file] -o [file] -F field -F field -F field ... X X Default conditions: X Home directory gotten from password entry X User gotten from password entry X Visual editor set to /usr/ucb/vi X X VI BREAKOUT enabled X READ file is /usr/spool/mail/$USER X WRITE file is $HOME/mbox X From:, To:, and Subject: fields will be loaded into memory. X X HOME enviroment variable becomes home directory X USER enviroment variable becomes user name X VISUAL enviroment variable becomes editor used X X -O Go into interactive mode, even if there is no X mail to read. X X -f [from file] Specify spool file to get mail from. If no file X Argument is given, $HOME/MBOX is used. X X -o [to file] Specify file to write to, If no Argument X is given, $HOME/.MBOX is used. Note that X the default without -o is $HOME/MBOX X X -f -o With no file arguments causes both READ and X WRITE files to be $HOME/.MBOX X X -F field Append this field to those which will be X used on initial load. If, During usage of the X program you specify a field which is not in X memory, DMAIL will be forced to re-load the X entire spool file, which can take a long time X if you have more than 64K in the file X X -l rcfile Use this as the rc file rather than .dmailrc X X -L Do not source the rc file on boot X X END_OF_FILE if test 23627 -ne `wc -c <'src/dmail/dmail.help'`; then echo shar: \"'src/dmail/dmail.help'\" unpacked with wrong size! fi # end of 'src/dmail/dmail.help' fi if test -f 'src/sendmail/sendmail.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'src/sendmail/sendmail.c'\" else echo shar: Extracting \"'src/sendmail/sendmail.c'\" \(22055 characters\) sed "s/^X//" >'src/sendmail/sendmail.c' <<'END_OF_FILE' X X/* X * SENDMAIL / RMAIL X * X * (C) Copyright 1989-1990 by Matthew Dillon, All Rights Reserved. X * X * SENDMAIL <file -f from -t to -s subject -c cc -b bcc -r X * RMAIL user X * X * Example: Sendmail <datafile -froot X * X * From: line is automatically added but can be overriden by a From: X * header in the file. stdin is made up of a list of headers, a blank X * line, and then data until EOF. X * X * the -r option tells sendmail that this is incomming mail. X * If av[0] begins with an 'r' for RMail instead of an 's' for X * Sendmail, then the rmail argument format is used (rmail user), X * as well as forcing -r. X */ X X#include <exec/types.h> X#include <exec/lists.h> X#include <proto/all.h> X#include <stdio.h> X#include <stdlib.h> X#include <string.h> X#include <log.h> X#include <config.h> X#include <time.h> X#include <pwd.h> X#include <string.h> X#include "/version.h" X X#define RCVR_UUCP 1 X#define RCVR_SENDMAIL 2 X XIDENT(".03"); X Xtypedef struct List LIST; Xtypedef struct Node NODE; X Xchar *UserName; Xchar *NodeName; Xchar *DomainName; Xchar *TimeZoneName; /* All caps, ex: PST */ Xchar *DefaultNode; /* for addr formats we don't understand */ XLIST RecvList; /* Received: */ XLIST FromList; /* last one rules */ XLIST ToList; /* To: */ XLIST CcList; /* Cc: */ XLIST BccList; /* Bcc: */ XLIST XccList; /* list of actual mail to be sent */ XLIST SubjList; /* Subject: */ XLIST HdrList; /* other headers not specifically parsed */ Xchar ScrBuf[1024]; Xchar ScrBuf2[1024]; Xchar TempFileBuf[256]; Xint Seq; /* UUCP sequence no */ Xchar ROpt; /* Receive-Mail flag */ Xstatic char OrigFromLine[512]; Xstatic char FromLine[512]; /* 'From ' line, if ROpt */ X Xchar *TmpFileName(); Xchar *atime(); Xvoid PostPend(); Xvoid MakeToFixNode(); Xvoid MakeToAddrNode(); Xvoid ToFixup(); Xvoid FromFixup(); Xvoid DumpHeaderInfo(); Xvoid DumpHeader(); Xvoid DumpCombineHeader(); Xvoid IntegrateHeader(); Xvoid Usage(); XFILE *SendMailTo(); XFILE *OneMailTo(); XFILE *OneMailToUUCP(); XFILE *OneMailToUser(); XFILE *OneMailToFile(); XFILE *OneMailToPipe(); XNODE *FindHeader(); XNODE *MakeNode(); X XCXBRK() X{ X return(0); X} X Xvoid XUsage() X{ X printf( X "Sendmail -f user [-t address -c address -b address -s subject -r]\n" X "RMail user\n" X ); X} X Xvoid Xmain(ac, av) Xchar *av[]; X{ X short isRMail = 0; X short isSendMail = 1; X FILE *fi; X X NewList(&RecvList); X NewList(&FromList); X NewList(&ToList); X NewList(&CcList); X NewList(&BccList); X NewList(&XccList); X NewList(&SubjList); X NewList(&HdrList); X X UserName = FindConfig("UserName"); X if (UserName == NULL) { X puts("Sendmail: UserName not in UULIB:Config!"); X exit(1); X } X NodeName = FindConfig("NodeName"); X if (NodeName == NULL) { X puts("Sendmail: NodeName not in UULIB:Config!"); X exit(1); X } X DomainName = FindConfig("DomainName"); X if (DomainName == NULL) { X puts("Sendmail: DomainName not in UULIB:Config! using .UUCP"); X DomainName = ".UUCP"; X } X DefaultNode = FindConfig("DefaultNode"); X TimeZoneName = FindConfig("TimeZone"); X X LoadAliases(); X X { X char *ptr = av[0] + strlen(av[0]); X X /* X * Skip path X */ X X while (ptr >= av[0] && *ptr != ':' && *ptr != '/') X --ptr; X ++ptr; X X if (*ptr == 'r' || *ptr == 'R') { X isRMail = 1; X isSendMail = 0; X } X } X X if (isRMail) { X char *addr = (ac == 2) ? av[1] : "Mailer-Daemon"; X X MakeNode(&BccList, addr); X UserName = "postmaster"; /* XXX */ X ROpt = 1; /* no header processing */ X } X if (isSendMail) { X short i; X char *arg; X for (i = 1; i < ac; ++i) { X arg = av[i]; X if (*arg != '-') X Usage(); X switch(arg[1]) { X case 'f': X UserName = av[i+1]; X sprintf(ScrBuf, "%s@%s%s", av[i+1], NodeName, DomainName); X MakeNode(&FromList, ScrBuf); X ++i; X break; X case 't': X MakeNode(&ToList, av[++i]); X break; X case 'c': X MakeNode(&CcList, av[++i]); X break; X case 'b': X MakeNode(&BccList, av[++i]); X break; X case 's': X MakeNode(&SubjList, av[++i]); X break; X case 'r': X ++ROpt; X break; X default: X Usage(); X } X } X } X X /* X * Read headers from input file. Headers are not necessarily X * contained on a single line. Maximum 4096 chars per header. X */ X X if (ROpt) { X fgets(ScrBuf, sizeof(ScrBuf), stdin); X strcpy(OrigFromLine, ScrBuf); X if (strncmp(ScrBuf, "From ", 5) != 0) { X ulog(-1, "Receive mail, expected 'From ', got %s", ScrBuf); X } X strcpy(FromLine, "From "); X PostPend(ScrBuf + 5, 1); X X while (fgets(ScrBuf, sizeof(ScrBuf), stdin) && strncmp(ScrBuf, ">From ", 6) == 0) { X strcpy(OrigFromLine, ScrBuf + 1); X PostPend(ScrBuf + 6, 1); X } X strcpy(ScrBuf2, OrigFromLine + 5); X PostPend(ScrBuf2, 0); X } else { X ScrBuf[0] = '\n'; X fgets(ScrBuf, sizeof(ScrBuf), stdin); X } X { X static char Hdr[4096]; X short i = 0; /* index into Hdr */ X X while (ScrBuf[0] != '\n') { X char *ptr = ScrBuf; X while (*ptr && *ptr != ' ' && *ptr != 9 && *ptr != ':') X ++ptr; X if (*ptr == ':') { /* found new header */ X if (i) /* Dump old header */ X IntegrateHeader(Hdr, i); X strcpy(Hdr, ScrBuf); X i = strlen(Hdr); X } else { /* append to existing header */ X if (i == 0) X puts("Expected a Header!"); X strcpy(Hdr + i, ScrBuf); X i = i + strlen(Hdr + i); X } X X if (fgets(ScrBuf, sizeof(ScrBuf), stdin) == NULL) X ScrBuf[0] = '\n'; X } X if (i) X IntegrateHeader(Hdr, i); X X if (ScrBuf[0] != '\n') { X puts("sendmail: no mail"); X exit(1); X } X } X X /* X * Parse & fixup each To:, Cc:, and Bcc: field. X * X * From: we add the personal info arg from the password file X * To: we expand any aliases X */ X X if (ROpt == 0) X FromFixup(&FromList); X if (ROpt) { X ToFixup(&BccList); X } else { X ToFixup(&ToList); X ToFixup(&CcList); X ToFixup(&BccList); X } X X /* X * If no Subject: field add a dummy one X */ X X if (EmptyList(&SubjList)) X MakeNode(&SubjList, ""); X X if (EmptyList(&FromList)) { X sprintf(ScrBuf, "%s@%s%s", UserName, NodeName, DomainName); X MakeNode(&FromList, ScrBuf); X } X X fi = SendMailTo(&XccList, stdin); X if (fi && fi != stdin) X fclose(fi); X if (TempFileBuf[0]) X remove(TempFileBuf); X UnLockFiles(); X} X X/* X * Strips string and creates named node which is appended to the X * given list. X */ X XNODE * XMakeNode(list, str) XLIST *list; Xchar *str; X{ X NODE *node; X char *ptr; X X while (*str == ' ' || *str == 9) X ++str; X for (ptr = str + strlen(str); ptr >= str && (*ptr == ' ' || *ptr == 9); --ptr); X ++ptr; X *ptr = 0; X node = malloc(sizeof(NODE) + strlen(str) + 1); X node->ln_Name = (char *)(node + 1); X strcpy(node->ln_Name, str); X AddTail(list, node); X return(node); X} X X/* X * X */ X Xvoid XMakeToFixNode(list, str, send) XLIST *list; Xchar *str; Xchar *send; X{ X char *ptr; X short len; X short c; X void fixCallBack(); X X while (str < send && (*str == ' ' || *str == 9)) X ++str; X for (ptr = send - 1; ptr >= str && (*ptr == ' ' || *ptr == 9); --ptr); X ++ptr; X X len = ptr - str; X if (len < 0) X return; X X /* X * str[0..len-1] X */ X X c = str[len]; X str[len] = 0; X X if (ROpt) { /* disallow remote asking for special options */ X ulog(-1, "Received mail for %s", str); X if (str[0] == '>' || str[0] == '<' || str[0] == '|' || str[0] == ':' || str[0] == '/') { X ulog(-1, "SendMail, bad user %s", str); X return; X } X } X X { X NODE *node = malloc(sizeof(NODE) + strlen(str) + 1); X X node->ln_Name = (char *)(node + 1); X strcpy(node->ln_Name, str); X AddTail(list, node); X } X X UserAliasList(str, fixCallBack); /* from lib/alias.c */ X str[len] = c; X} X Xvoid XfixCallBack(user) Xchar *user; X{ X NODE *node; X X if (user[0] == '<') { X FILE *fi = fopen(user + 1, "r"); X char *buf = malloc(256); X X if (fi == NULL) { X ulog(-1, "Unable to open < file %s", user + 1); X return; X } X while (fgets(buf, 256, fi)) { X short i = 0; X short j; X while (buf[i] == ' ' || buf[i] == 9) X ++i; X if (buf[i] == 0 || buf[i] == '\n') X continue; X for (j = i; buf[j] && buf[j] != '\n' && buf[j] != ' ' && buf[j] != 9; ++j); X buf[j] = 0; X UserAliasList(buf, fixCallBack); X } X fclose(fi); X free(buf); X return; X } X X ulog(-1, "Sendmail, Sending mail to %s", user); X X if (user[0] == '\\') X ++user; X X node = malloc(sizeof(NODE) + strlen(user) + 1); X node->ln_Name = (char *)(node + 1); X strcpy(node->ln_Name, user); X AddTail(&XccList, node); X} X X X/* X * Integrates a header X */ X Xvoid XIntegrateHeader(hdr, len) Xchar *hdr; Xshort len; X{ X if (hdr[len-1] == '\n') /* strip trailing newline */ X hdr[len-1] = 0; X X if (strncmp(hdr, "From:", 5) == 0) { X MakeNode(&FromList, hdr + 5); X return; X } X if (strncmp(hdr, "To:", 3) == 0) { X MakeNode(&ToList, hdr + 3); X return; X } X if (strncmp(hdr, "Cc:", 3) == 0) { X MakeNode(&CcList, hdr + 3); X return; X } X if (strncmp(hdr, "Bcc:", 4) == 0) { X MakeNode(&BccList, hdr + 4); X return; X } X if (strncmp(hdr, "Subject:", 8) == 0) { X MakeNode(&SubjList, hdr + 8); X return; X } X if (strncmp(hdr, "Received:", 9) == 0) { X MakeNode(&RecvList, hdr + 9); X return; X } X MakeNode(&HdrList, hdr); X} X X/* X * Adds (personal info) to FromList based on passwd entry or, if X * that is not available, from the Config entry 'RealName'. X */ X Xvoid XFromFixup(list) XLIST *list; X{ X char *wholeName = GetConfig("RealName", "Who Knows"); X NODE *node; X NODE *nn; X LIST tmpList; X X NewList(&tmpList); X X while (node = RemHead(list)) { X /* X * FIXME. Fix getpwnam() and use pw_gecos entry. X */ X nn = malloc(sizeof(NODE) + strlen(node->ln_Name) + strlen(wholeName) + 16); X nn->ln_Name = (char *)(nn + 1); X sprintf(nn->ln_Name, "%s (%s)", node->ln_Name, wholeName); X free(node); X AddTail(&tmpList, nn); X } X while (node = RemHead(&tmpList)) X AddTail(list, node); X} X X/* X * Converts an unparsed list of names into a list of single address X * fields, removing any personal idents from the entries. These will X * be recombined after processing when the data file is written out. X * X * Also expands sendmail aliases (UULIB:Aliases) (HACK) X */ X Xvoid XToFixup(list) XLIST *list; X{ X NODE *node; X LIST tmpList; X X NewList(&tmpList); X X while (node = RemHead(list)) { X char *str = node->ln_Name; X char *ptr; X X while (*str) { /* breakup fields by newline or comma */ X for (ptr = str; *ptr && *ptr != '\n' && *ptr != ','; ++ptr); X MakeToAddrNode(&tmpList, str); X str = ptr; X while (*str == '\n' || *str == ',' || *str == ' ' || *str == 9) X ++str; X } X free(node); X } X while (node = RemHead(&tmpList)) X AddTail(list, node); X} X X/* X * Extracts a single name / address (comma or newline delimited) X * field and creates a new node. X */ X Xvoid XMakeToAddrNode(list, str) XLIST *list; Xchar *str; X{ X char *p1, *p2; X short ns = 0; /* non-whitespace encountered */ X X for (p1 = str; *p1 && *p1 != ',' && *p1 != '\n'; ++p1) { X if (*p1 == '(') { /* addr (name) OR (name) addr */ X if (ns) { /* addr (name) */ X MakeToFixNode(list, str, p1); X } else { X while (*p1 && *p1 != ',' && *p1 != '\n' && *p1 != ')') X ++p1; X if (*p1 == ')') { X for (p2 = p1 + 1; *p2 && *p2 != ',' && *p2 != '\n'; ++p2); X MakeToFixNode(list, p1 + 1, p2); X } X } X return; X } X X if (*p1 == '<') { /* <addr> */ X for (p2 = p1 + 1; *p2 && *p2 != ',' && *p2 != '\n' && *p2 != '>'; ++p2); X if (*p2 == '>') X MakeToFixNode(list, p1 + 1, p2); X return; X } X if (*p1 != ' ' && *p1 != 9) X ns = 1; X } X MakeToFixNode(list, str, p1); X} X X X/* X * Send mail to <recipeant> X * X * -Local mail X * -Machine path (UUCP) X */ X XFILE * XSendMailTo(list, fi) XLIST *list; XFILE *fi; X{ X NODE *node; X X for (node = list->lh_Head; node != (NODE *)&list->lh_Tail; node = node->ln_Succ) X fi = OneMailTo(node->ln_Name, fi); X return(fi); X} X XFILE * XOneMailTo(toaddr, rfi) Xchar *toaddr; XFILE *rfi; X{ X short i; X char c; X static char Buf[256]; X static char typeBuf[16]; X static char classBuf[16]; X static char addrBuf[128]; X X if (toaddr[0] == '|') /* pipe through command */ X return(OneMailToPipe(toaddr + 1, rfi)); X if (toaddr[0] == '>') /* copy to file */ X return(OneMailToFile(toaddr + 1, rfi)); X X for (i = 0; c = toaddr[i]; ++i) { X if (c == '!' || c == '%' || c == '@' || c == ':') X break; X } X if (c == 0) /* local name */ X return(OneMailToUser(toaddr, rfi)); X X /* X * Non-Local mail X */ X X i = ParseAddress(toaddr, Buf, strlen(toaddr)); X if (DomainLookup(Buf, strlen(Buf), typeBuf, classBuf, addrBuf)) { X printf("type %s class %s addr %s\n", typeBuf, classBuf, addrBuf); X printf("buf %s\n", Buf); X X /* X * Note distinction between mail destination and mail forwarder. X * mail destination removes the first machine from the rmail line X * mail forwarder does NOT X */ X X if (strcmpi(classBuf, "UU") == 0) { X if (strcmpi(typeBuf, "MD") == 0) X return(OneMailToUUCP(addrBuf, Buf + i + 1, rfi)); X else X return(OneMailToUUCP(addrBuf, Buf, rfi)); X } else { X ulog(-1, "Unsupported domain class: %s", classBuf); X printf("Unsupported domain class: %s\n", classBuf); X } X return(rfi); X } else { X ulog(-1, "Could not find domain for %s, no mail sent", Buf); X printf("Unable to send mail to %s\n", Buf); X return(rfi); X } X} X X XFILE * XOneMailToPipe(toaddr, rfi) Xchar *toaddr; XFILE *rfi; X{ X FILE *fi; X char *ptr; X static long pos; X X if (TempFileBuf[0] == 0) { X strcpy(TempFileBuf, TmpFileName("T:pipe")); X fi = fopen(TempFileBuf, "w"); X if (fi == NULL) { X ulog(-1, "Unable to open temp file %s for command: %s", TempFileBuf, toaddr); X return(rfi); X } X DumpHeaderInfo(fi, RCVR_SENDMAIL, 0, 1); X pos = ftell(fi); X while (fgets(ScrBuf, sizeof(ScrBuf), rfi)) X fputs(ScrBuf, fi); X fclose(fi); X } X strcpy(ScrBuf, toaddr); X X ptr = toaddr; X if (strncmpi(toaddr, "run", 3) == 0) { X ptr += 3; X while (*ptr == ' ' || *ptr == 9) X ++ptr; X } X while (*ptr && *ptr != ' ' && *ptr != 9) X ++ptr; X X if (*ptr == 0) X strcat(ScrBuf, " "); X sprintf(ScrBuf + (ptr - toaddr + 1), "<%s %s", TempFileBuf, ptr); X if (Execute(ScrBuf, NULL, NULL) == 0) X ulog(-1, "Couldn't execute %s", ScrBuf); X X fi = fopen(TempFileBuf, "r"); X if (fi) { X if (rfi != stdin) X fclose(rfi); X rfi = fi; X fseek(rfi, pos, 0); X } else { X ulog(-1, "Couldn't reopen temp '%s', mail failed!", TempFileBuf); X rfi = stdin; X } X return(rfi); X} X XFILE * XOneMailToUser(toaddr, rfi) Xchar *toaddr; XFILE *rfi; X{ X sprintf(ScrBuf, "UUMAIL:%s", toaddr); X return(OneMailToFile(ScrBuf, rfi)); X} X XFILE * XOneMailToFile(tofile, rfi) Xchar *tofile; XFILE *rfi; X{ X FILE *fo; X static char DataFile[128]; X long pos; X X strcpy(DataFile, tofile); X X LockFile(DataFile); X fo = fopen(DataFile, "a"); X if (fo == NULL) { X strcpy(DataFile, "T:MailOverflow"); X fo = fopen(DataFile, "a"); X if (fo) X ulog(-1, "Could not append to %s, appending to %s", tofile, DataFile); X else X ulog(-1, "Can't append to anywhere! (%s)", tofile); X } X if (fo) { X DumpHeaderInfo(fo, RCVR_SENDMAIL, 0, 1); X pos = ftell(fo); X if (ROpt) { X if (fgets(ScrBuf, sizeof(ScrBuf), rfi)) X fputs(ScrBuf, fo); X } X while (fgets(ScrBuf, sizeof(ScrBuf), rfi)) { X if (ScrBuf[0] == 'F' && strncmp(ScrBuf, "From ", 5) == 0) X strins(ScrBuf, " "); X fputs(ScrBuf, fo); X } X fclose(fo); X if (rfi != stdin) X fclose(rfi); X rfi = fopen(DataFile, "r"); X fseek(rfi, pos, 0); X } X return(rfi); X} X XFILE * XOneMailToUUCP(toaddr, skipaddr, rfi) Xchar *toaddr; Xchar *skipaddr; XFILE *rfi; X{ X static char ExecFile[128]; X static char XExecFile[128]; X static char CommandFile[128]; X static char DataFile[128]; X static char DestNode[256]; X /*static char ToAddr[256];*/ X FILE *fi; X int seq; X long pos; X short i; X short ai; X X /* X * If the destination node X */ X X strcpy(DestNode, toaddr); X X ai = -1; X for (i = 0; DestNode[i]; ++i) { X /* X * Remember index for additional paths X */ X X if (DestNode[i] == '!') { X DestNode[i] = 0; X ai = i + 1; X break; X } X X /* X * Cut off machine name at 7 chars and ignore any domain X * info. X */ X X if (i == 7 || DestNode[i] == '.') X DestNode[i] = 0; X } X X Seq = seq = GetSequence(4); X X#define FOFF 8 X X sprintf(ExecFile, "UUSPOOL:D.%sX%04d", DestNode, seq++); X sprintf(XExecFile, "UUSPOOL:X.%sX%04d", DestNode, seq++); X sprintf(CommandFile,"UUSPOOL:C.%sA%04d", DestNode, seq++); X sprintf(DataFile, "UUSPOOL:D.%sB%04d", DestNode, seq); X X LockFile(ExecFile); X LockFile(XExecFile); X LockFile(CommandFile); X LockFile(DataFile); X X /* X * Note, cannot run uuxqt from sendmail as uuxqt may call X * sendmail! X */ X X if (strncmp(DestNode, NodeName, 7) == 0) X fi = fopen(XExecFile, "w"); X else X fi = fopen(ExecFile, "w"); X X if (fi == NULL) X goto fail; X X fprintf(fi, "U %s\n", UserName); X fprintf(fi, "F %s\n", DataFile + FOFF); X fprintf(fi, "I %s\n", DataFile + FOFF); X if (ai >= 0) X fprintf(fi, "C rmail %s!%s\n", DestNode + ai, skipaddr); X else X fprintf(fi, "C rmail %s\n", skipaddr); X fclose(fi); X X if (strncmp(DestNode, NodeName, 7)) { X fi = fopen(CommandFile, "w"); X if (fi == NULL) X goto fail; X X fprintf(fi, "S %s %s %s - %s 0666\n", DataFile + FOFF, DataFile + FOFF, UserName, DataFile + FOFF); X fprintf(fi, "S %s %s %s - %s 0666\n", ExecFile + FOFF, XExecFile + FOFF, UserName, ExecFile + FOFF); X fclose(fi); X } X X fi = fopen(DataFile, "w"); X if (fi == NULL) X goto fail; X X DumpHeaderInfo(fi, RCVR_UUCP, 1, 0); X pos = ftell(fi); X X if (ROpt) { X if (fgets(ScrBuf, sizeof(ScrBuf), rfi)) X fputs(ScrBuf, fi); X } X while (fgets(ScrBuf, sizeof(ScrBuf), rfi)) { X if (ScrBuf[0] == 'F' && strncmp(ScrBuf, "From ", 5) == 0) X strins(ScrBuf, " "); X fputs(ScrBuf, fi); X } X fclose(fi); X if (rfi != stdin) X fclose(rfi); X fi = fopen(DataFile, "r"); X fseek(fi, pos, 0); X return(fi); Xfail: X puts("Fail"); X return(rfi); X} X Xvoid XDumpHeaderInfo(fi, rcvr, resend, local) XFILE *fi; X{ X char *source; X time_t t; X X time(&t); X X /* X * Write header info X */ X X if (rcvr == RCVR_UUCP) X source = "AmigaUUCP"; X else X source = "Sendmail"; X X if (ROpt) { X if (resend) X fprintf(fi, "%s %s remote from %s\n", FromLine, atime(&t), NodeName); X else X fprintf(fi, "%s %s\n", FromLine, atime(&t)); X } else { X if (local) X fprintf(fi, "From %s %s\n", UserName, atime(&t)); X else X fprintf(fi, "From %s %s remote from %s\n", UserName, atime(&t), NodeName); X } X fprintf(fi, "Received: by %s%s (0.44/0.44)\n\tid AA%05d; %s\n", X NodeName, DomainName, Seq, atime(&t) X ); X DumpHeader(fi, "Received:", &RecvList); X if (ROpt == 0) { X time_t t2 = t + 3600 * GetHourOffset(TimeZoneName); X struct tm *ut; X X if (FindHeader("Date:") == NULL) X fprintf(fi, "Date: %s\n", atime(&t)); X ut = localtime(&t2); X fprintf(fi, "Message-Id: <%02d%02d%02d%02d%02d.AA%05d@%s%s>\n", X ut->tm_year % 100, ut->tm_mon + 1, ut->tm_mday, ut->tm_hour, ut->tm_min, X Seq, NodeName, DomainName X ); X } X X /* X * From:, To:, Cc:, Subject: (Bcc: never written to header), X * and any other header fields X */ X X DumpHeader(fi, NULL, &HdrList); X DumpHeader(fi, "From:", &FromList); X DumpCombineHeader(fi, "To:", &ToList); X if (!EmptyList(&CcList)) X DumpCombineHeader(fi, "Cc:", &CcList); X DumpHeader(fi, "Subject:", &SubjList); X X fprintf(fi, "\n"); X} X Xvoid XDumpHeader(fi, field, list) XFILE *fi; Xchar *field; XLIST *list; X{ X NODE *node; X X for (node = list->lh_Head; node != (NODE *)&list->lh_Tail; node = node->ln_Succ) { X if (field) X fprintf(fi, "%s %s\n", field, node->ln_Name); X else X fprintf(fi, "%s\n", node->ln_Name); X } X} X XNODE * XFindHeader(field) Xchar *field; X{ X NODE *node; X short len = strlen(field); X X for (node = HdrList.lh_Head; node != (NODE *)&HdrList.lh_Tail; node = node->ln_Succ) { X if (strncmp(node->ln_Name, field, len) == 0) X return(node); X } X return(NULL); X} X Xvoid XDumpCombineHeader(fi, field, list) XFILE *fi; Xchar *field; XLIST *list; X{ X NODE *node; X short ci = 0; X X fprintf(fi, "%s ", field); X for (node = list->lh_Head; node != (NODE *)&list->lh_Tail; node = node->ln_Succ) { X if (ci && ci + strlen(node->ln_Name) > 70) { X fprintf(fi, ",\n\t"); X ci = 0; X } X if (ci) X fprintf(fi, ", "); X fprintf(fi, "%s", node->ln_Name); X ci += strlen(node->ln_Name) + 2; X } X fprintf(fi, "\n"); X} X Xchar * Xatime(pt) Xtime_t *pt; X{ X static char buf[40]; X static char *mo[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", X "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" X }; X static char *dow[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; X struct tm *ut = localtime(pt); X X sprintf(buf, "%s, %d %s %02d %02d:%02d:%02d %s", X dow[ut->tm_wday], ut->tm_mday, mo[ut->tm_mon], X ut->tm_year % 100, ut->tm_hour, ut->tm_min, ut->tm_sec, X TimeZoneName X ); X return(buf); X} X XGetHourOffset(tz) Xchar *tz; X{ X short i; X X static struct { X char *Name; X short Hours; X } TZAry[] = { X "GMT", 0, X "UT", 0, X "PST", 8, X "MST", 7, X "CST", 6, X "EST", 5, X "AST", 4, X "PDT", 7, X "MDT", 6, X "CDT", 5, X "EDT", 4, X "ADT", 3, X NULL, 0 X }; X for (i = 0; TZAry[i].Name; ++i) { X if (strncmp(tz, TZAry[i].Name, 3) == 0) X return((int)TZAry[i].Hours); X } X ulog(-1, "Unknown Timezone: %s", tz); X printf("Unknown Timezone: %s", tz); X return(6); X} X Xvoid XPostPend(str, frend) Xchar *str; X{ X char *ptr; X if (frend) { X ptr = str + strlen(str); X while (ptr > str && *ptr != ' ' && *ptr != 9) { X if (*ptr == '\n') X *ptr = 0; X --ptr; X } X str = ptr + 1; X } X for (ptr = str; *ptr && *ptr != ' ' && *ptr != 9 && *ptr != '\n'; ++ptr); X if (frend) X strcpy(ptr, "!"); X else X strcpy(ptr, ""); X for (ptr = FromLine + 5; *ptr && *ptr != ' ' && *ptr != 9; ++ptr); X strins(ptr, str); X} X XEmptyList(list) XLIST *list; X{ X if (list->lh_Head == (NODE *)&list->lh_Tail) X return(1); X return(0); X} X END_OF_FILE if test 22055 -ne `wc -c <'src/sendmail/sendmail.c'`; then echo shar: \"'src/sendmail/sendmail.c'\" unpacked with wrong size! fi # end of 'src/sendmail/sendmail.c' fi echo shar: End of archive 10 \(of 16\). cp /dev/null ark10isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 16 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 -- Submissions to comp.sources.amiga and comp.binaries.amiga should be sent to: amiga@cs.odu.edu or amiga@xanth.cs.odu.edu ( obsolescent mailers may need this address ) or ...!uunet!xanth!amiga ( very obsolescent mailers need this address ) Comments, questions, and suggestions should be addressed to ``amiga-request'' (please only use ``amiga'' for actual submissions) at the above addresses.