home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume12 / mush / part12 < prev    next >
Encoding:
Text File  |  1990-05-05  |  54.2 KB  |  1,466 lines

  1. Newsgroups: comp.sources.misc
  2. subject: v12i040: Mail User's Shell, Part12/19
  3. from: argv@Eng.Sun.COM (Dan Heller)
  4. Sender: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  5.  
  6. Posting-number: Volume 12, Issue 40
  7. Submitted-by: argv@Eng.Sun.COM (Dan Heller)
  8. Archive-name: mush/part12
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then feed it
  12. # into a shell via "sh file" or similar.  To overwrite existing files,
  13. # type "sh file -c".
  14. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  15. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  16. # If this archive is complete, you will see the following message at the end:
  17. #        "End of archive 12 (of 19)."
  18. # Contents:  mush/README mush/mail.c.b
  19. # Wrapped by argv@turnpike on Wed May  2 13:59:38 1990
  20. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  21. if test -f 'mush/README' -a "${1}" != "-c" ; then 
  22.   echo shar: Will not clobber existing file \"'mush/README'\"
  23. else
  24. echo shar: Extracting \"'mush/README'\" \(25704 characters\)
  25. sed "s/^X//" >'mush/README' <<'END_OF_FILE'
  26. X/* @(#)README        (c) copyright 9/15/89    (Dan Heller) */
  27. X
  28. XAuthor:
  29. X    Dan Heller
  30. X
  31. XNetwork addresses:
  32. X    argv@sun.com        argv@monet.berkeley.edu.
  33. X    argv@garp.mit.edu        dheller@ucbcory.berkeley.edu
  34. X
  35. XWhen sending mail, mail to the addresses in the order given.
  36. X
  37. XContained is the source for "Mail User's Shell" (MUSH), a "Mail User
  38. XAgent" (MUA) that is designed to manage electronic mail on most UNIX
  39. Xsystems.  That is, mush is used by users to read mail, sort it, edit
  40. Xit, delete it, or use it to act as an interface to send mail to others.
  41. XA Mail Transport Agent (MTA) is the program which mush communicates with
  42. Xthat actually -delivers- mail.
  43. X
  44. XThe Mush sources are copyright (c) 1986, 1987, 1988, 1989 by Dan Heller.
  45. XRedistribution of the unmodified source code is permitted as long as all
  46. Xcopyright notices remain intact and all other identifying notices remain
  47. Xin the code and in the binary.  This includes message headers on outgoing
  48. Xmail and the startup message.  Future releases may extract the release
  49. Xversion from the message headers of mush-originated messages to aid in
  50. Ximplementing features and providing backwards compatibility with previous
  51. Xversions.  Modification of the source for personal use is permitted.
  52. XModifications sent to the authors are humbly accepted and it is their
  53. Xperogative to make the mods official.  Only the "official" sources may be
  54. Xredistributed and no sale of the code or any part thereof is permitted
  55. Xwithout written consent from the authors.  Further, no part of the code
  56. Xmay be used in any other product, free or otherwise, without consent from
  57. Xthe authors.
  58. X
  59. XWith that out of the way...
  60. X
  61. XMush runs on various flavors of unix.  To build mush, you should identify
  62. Xwhich unix you are running:
  63. X
  64. X    Sun (all versions from 2.0 and higher).
  65. X    BSD (versions 4.2 and up)
  66. X    System-V / Version 7 / System III (Bell Labs)
  67. X    Xenix (this might be tricky)
  68. X
  69. XYou will need to copy "config.h-dist" to config.h and edit it to reflect
  70. Xthe system dependencies described there.  These consist of "compile-time
  71. Xdefinitions and macros."
  72. X
  73. XWhen it comes to "compile-time definitions", you may use one of two methods:
  74. X
  75. X    #define DEFINITION    /* in the config.h file */
  76. X    -DDEFINITION    /* in your makefile */
  77. X
  78. XIf the definition is of the form MACRO="string", then use:
  79. X
  80. X    #define MACRO string
  81. X    -DMACRO=string
  82. X
  83. XNote that if you use definitions in the makefile, you should remove the
  84. Xcorresponding definitions from config.h -- if you do not, the config.h
  85. Xdefinitions will override the -D definitions.  The compiler will usually
  86. Xprint a warning message if this happens, but the result will still be wrong.
  87. X
  88. X---------------
  89. XWhich makefile to use:
  90. X
  91. XIf you are on a Sun Workstation:
  92. X
  93. X    makefile.sun applies only to suns and creates a binary called "mush."
  94. X    If the binary ends in "tool", then the graphics (suntools) mode will be
  95. X    used by default on invocation.  Otherwise, you must specify -t for
  96. X    toolmode on sun workstations.  The SUNTOOL define is used in the
  97. X    makefile.sun in order to compile the suntools version.  You DO need
  98. X    to be running SunView; old SunWindows (2.0+) no longer works.  Be sure
  99. X    to follow the notes in the makefile.sun for SunOS-4.0 machines.
  100. X
  101. X    If you know that you're not going to use the suntools mode then you
  102. X    should use makefile.bsd so that SUNTOOL won't be defined and unnecessary
  103. X    files will not be compiled so the binary will be smaller.
  104. X
  105. X    Whether or not you define SUNTOOL, you should define one of SUN_3_5,
  106. X    SUN_4_0, or SUN_4_1 depending on your SunOS version.  If SUNTOOL is
  107. X    the only thing defined, SUN_4_0 will be used.
  108. X
  109. XIf you are on a BSD UNIX machine:
  110. X
  111. X    You should use the makefile.bsd makefile.
  112. X
  113. XIf you are using XENIX:
  114. X
  115. X    There is one makefile for xenix: makefile.xenix.  However, SCO-xenix
  116. X    runs on either 80286 or 80386 architectures.  This makefiles has been
  117. X    tuned for SCO's version of xenix.  This does not mean that it won't
  118. X    work under other xenix versions -- however, some changes may have to
  119. X    be made by hand.  If your xenix release is sco-xenix 2.2 or higher
  120. X    then you must define USG. The libraries to use may be -ltinfo instead
  121. X    of -lcurses -ltermlib.  This is because the curses package may use
  122. X    termio instead of the sgtty data structure.  If you want to use termio
  123. X    anyway, even if you're on an older xenix system (that supports termio),
  124. X    then you may define USG anyway.
  125. X
  126. X    Follow the hints in the makefile.xenix for compiling for 286 systems
  127. X    or 386 systems.  It is *very likely* that the CFLAGS will have to be
  128. X    modified -- specifically, the model size and the stack size options.
  129. X    You should be very familiar with your xenix to know how to tune this
  130. X    properly.
  131. X
  132. XIf you are on a System-V Bell labs machine:
  133. X
  134. X    makefile.sys.v is for unix machines that are not running any flavor of
  135. X    BSD and probably running a system-v flavor of unix -- this defines USG
  136. X    so that termio will be used.
  137. X
  138. X    SCO UNIX V.3.2 users will need to change the declaration of ttytype[]
  139. X    in curses.c to be "extern unsigned char" when using terminfo-based
  140. X    curses.  This may also be necessary with termcap-based curses.
  141. X
  142. X    MicroPort sys-v users should probably remove the -O compiler option
  143. X    from the makefile, and may have trouble with the msg_bit() macro
  144. X    defined in mush.h.  It should be fairly trivial to generate an
  145. X    equivalent function.
  146. X
  147. X    Silicon Graphics Iris workstations should add -DDIRECTORY to the CFLAGS
  148. X    in the makefile.  This prevents the portable directory routines from
  149. X    being compiled in.
  150. X
  151. XIf you are using Ultrix:
  152. X
  153. X    Start with makefile.bsd.
  154. X
  155. X    For Ultrix 2.2, change LIBES in makefile.bsd from
  156. X    LIBES= -lcurses -ltermlib
  157. X    to 
  158. X    LIBES= -lcurses -ltermcap
  159. X
  160. X    For Ultrix V3.0, use the standard makefile.bsd LIBES, but add
  161. X    -DSIGRET=void
  162. X    to the CFLAGS, or add
  163. X    #define SIGRET void
  164. X    to config.h (see discussion below).
  165. X
  166. XIf you are using HP-UX:
  167. X
  168. X    Use makefile.hpux.
  169. X
  170. X    Versions 6.5 and 7.0 of HP-UX (not to be confused with the same
  171. X    version numbers of Mush) have the Berkeley-style directory access
  172. X    libraries.  Those using older versions should omit -DDIRECTORY
  173. X    from the CFLAGS.  This will cause the portable directory access
  174. X    routines in that file to be compiled.
  175. X
  176. XWhen you decide on an appropriate makefile, _copy_ it to a new file called
  177. XMakefile _before_ making any of local changes.  Please read the following
  178. Xsections for addtional configuration information.  In addition to changing
  179. Xcompilation options as appropriate, you should examine the rules for the
  180. X"install:" target.  Running "make" will NOT use this target by default;
  181. Xit is provided for your convenience only.
  182. X---------------
  183. X
  184. XYour Mail Transport Agent:
  185. XSendmail:
  186. X    Mush was originally designed to use sendmail as the Mail Transport Agent.
  187. X    However, other MTA's will work.  The MTA you use should be defined in
  188. X    config.h under the MAIL_DELIVERY macro define. By default,
  189. X        /usr/lib/sendmail -i
  190. X    is used -- the option, -i, tells sendmail not to accept "." on a line
  191. X    by itself as an end-of-file marker.  This has been obsleted by "-oi",
  192. X    but "-i" still works and is backwards compatible with older sendmails.
  193. X
  194. XDelivermail:
  195. X    Some mailers such as delivermail and MMDF use special strings to separate
  196. X    messages stored in a folder.  Older delivermail versions would use "^C".
  197. X    Whatever your system uses, if it is NOT "From " (just the first 5 chars
  198. X    on a line matching "From "), then this string should be defined in
  199. X    config.h with the MSG_SEPARATOR macro.
  200. X
  201. XMMDF:
  202. X    NOTE: MMDF sites can define MMDF and not worry about MSG_SEPARATOR.  See
  203. X    config.h-dist if you run MMDF.
  204. X
  205. X    Since MMDF can deliver users' mail in their home directories, there is
  206. X    a define to specify this option: -DHOMEMAIL
  207. X
  208. X    Since MMDF uses its own libraries to do file locking, you should add the
  209. X    appropriate library to the LIBS list in your makefile.
  210. X
  211. X    MMDF sites should probably NOT define PICKY_MAILER (see below).
  212. X
  213. XAll others:
  214. X    Chances are, your MTA uses the "From " format to separate messges in
  215. X    a folder.  This includes, /bin/mail, rmail, smail, execmail, and so on.
  216. X    Unless you *know* otherwise, assume this to be the case with your MTA.
  217. X
  218. X    If no MSG_SEPARATOR is specified, what mush looks for is a pattern of
  219. X    From <string> <date format>
  220. X    The "string" is usually the return address of the sender and the date
  221. X    format is supposed to be in ctime(3) format.  Even still, some MTAs
  222. X    don't conform completely to this standard and vary slightly in
  223. X    implementation.  The function load_folder() (which reads in messages)
  224. X    contains a scanf which looks for this format to verify that this is
  225. X    indeed a new message being scanned.  If you install mush and find that
  226. X    you are entering a shell, but mush indicates there are no messages in
  227. X    the folder, it could be that you have a weird "From " line format and
  228. X    the scanf() call needs to be either modified or removed.
  229. X
  230. X    Machines that use mail transfer agents that *do not* use a colon-less
  231. X    "From " line as a message separator should #define in config.h the string
  232. X    MSG_SEPARATOR.  Since this string is usually control characters, you
  233. X    need to specify actual ascii values for those characters.  Users of MMDF,
  234. X    for example, may use "\001\001\001\001" since some mmdf versions use four
  235. X    control-A's to separate messages.  This message separator assumes that
  236. X    there is a carriage return at the end of the string.  Systems that use
  237. X    sendmail need not concern themselves with this define.  MSG_SEPARATOR
  238. X    should not contain a newline, except for MMDF.  The MSG_SEPARATOR must
  239. X    match a complete line; a prefix will not work.
  240. X
  241. X#defines specifically for your MTA:
  242. X
  243. XMSG_SEPARATOR
  244. X    See the discussion above.
  245. X
  246. XUUCP
  247. X    This should be defined if your MTA does not automatically create a
  248. X    From: header *and* your machine talks to other computers via uucp.
  249. X    If defined, the From: line created specifies the user's address in
  250. X    UUCP format (host!user).  Otherwise, arpa format is used (user@host).
  251. X    Also, return addresses generated from RFC822 route specs will be put
  252. X    in UUCP format with a complete path.
  253. X
  254. XMTA_EXIT
  255. X    The exit code of a successful delivery of a message by your MTA.
  256. X    This is typically 0, but MMDF sites should define 9 (see config.h-dist).
  257. X
  258. XNO_COMMAS
  259. X    If your mailer does *NOT* like commas between addresses (smail sites,
  260. X    xenix and sys-v machines), then you should define NO_COMMAS.  Otherwise,
  261. X    you will get mailer-daemon [type] messages back when trying to send mail
  262. X    to multiple users.  Sendmail should not define this.
  263. X
  264. XVERBOSE_ARG
  265. X    If your mailer does NOT have a verbose option, then you should not have
  266. X    VERBOSE_ARG defined.  Otherwise, define it to be whatever the verbose
  267. X    argument is for your mailer.  The default is -v.
  268. X
  269. XMETOO
  270. X    Sendmail uses the -m argument to say, "metoo" -- when sending to sendmail
  271. X    aliases (e.g. mailing lists), sendmail will expand the alias, but if your
  272. X    address appears in the expansion, you are excluded from getting your own
  273. X    mail.  However, if you have the variable metoo set with your variables,
  274. X    then the METOO argument is passed to sendmail to say, "I know I'm on this
  275. X    mailing list, but send me a copy of my message even tho I sent it."  For
  276. X    sendmail, this is -m.  If your mailer uses something else, then define
  277. X    METOO_ARG in the config.h file.  If you don't have it (sys-v), then this
  278. X    should not be defined.
  279. X
  280. XPICKY_MAILER
  281. X    Most RFC822 compliant mailers (sendmail) will add the headers From:
  282. X    and Date: on outgoing mail.  If the user or UA sends these headers,
  283. X    most MTAs will not append them automatically.  However, there are
  284. X    certain MTAs which will not allow this -- these "picky mailers" will
  285. X    precede such headers with a '>' and make the headers very ugly and
  286. X    somewhat redundant or contradictory.  It's hard to determine whether
  287. X    or not your MTA will do this without actually sending mail to yourself.
  288. X    However, it is advised to set this *unless* your mailer is not RFC822-
  289. X    compliant (used to be defined by OLD_MAILER in previous mush releases).
  290. X
  291. X    PICKY_MAILER should NOT normally be defined when MMDF is defined.
  292. X
  293. XDOT_LOCK
  294. X    Different systems use different locking mechanisms.  By default,
  295. X    mush uses one of flock(), locking(), or lockf() (depending on your
  296. X    system).  Some  systems use a file called the same name as the file
  297. X    you're locking with an appended ".lock" at the end (some Xenix's use
  298. X    /tmp/$USER.mlk).  If you define DOT_LOCK, mush will first check for the
  299. X    .lock file.  If it exists, mush loops until it goes away and then mush
  300. X    creates it mode 600.  Regardless of whether you use dot-locking, mush
  301. X    will continue to try to use flock(), or whatever.
  302. X
  303. X    Dot-locking requires mush to have write access to the directory where
  304. X    your mailbox exists.  Normally, this directory isn't writable by the
  305. X    average user, so to do this you may have to sgid mush to the group id
  306. X    of the owner of that directory.  Mush will get the effective gid at the
  307. X    beginning of the program and immediately reset it to your real gid until
  308. X    the time it needs to lock the file occurs.  It changes back to the sgid,
  309. X    locks, then returns to normal.  There shouldn't be a security problem.
  310. X
  311. X    If you don't know what any of this means, ignore DOT_LOCK.
  312. X
  313. X    Another warning is that some MTA's don't even follow their own protocol.
  314. X    System V, it has been reported, creates the .lock file without checking
  315. X    to see if it exists (therefore ruining someone else's lock).
  316. X
  317. X---------------
  318. XSignals:
  319. X
  320. XSIGRET
  321. X    When signals occur in unix, the program can identify a function to be
  322. X    called whenever a specific signal interrupts the process.  That function
  323. X    returns one of two types in unix: int and void.  Because the return value
  324. X    of this function is always ignored, many unix systems are converting
  325. X    their definition of this function from int to void.  Mush has a define:
  326. X    SIGRET which defines what the function should return.
  327. X
  328. X    By default, SIGRET is defined to be "int", except for SunOS4.0, where
  329. X    it is defined to be "void".
  330. X
  331. X    Some System-V, some Ultrix and some Xenix machines should also define
  332. X    SIGRET to be void.  If you don't know, leave it alone.  If you guess
  333. X    wrong, you will get compiler "warnings" on lines that read:
  334. X    on_intr();
  335. X    off_intr();
  336. X---------------
  337. XMemory allocation:
  338. X
  339. XINTERNAL_MALLOC
  340. X    Mush depends on the xfree() function to detect invalid pointers, so
  341. X    that they will not be incorrectly passed to free().  Some system
  342. X    organizations make this very difficult, if not impossible.  80286-based
  343. X    machines in certain memory models, AT&T 3b2s and 3b15s, and others have
  344. X    these difficulties; VAX, Sun, Sequent, Apollo, and most 680x0 and many
  345. X    80386-based machines do not.  Changes have been made to xfree() to
  346. X    handle the AT&T machines, but if you aren't sure about your machine,
  347. X    or if you get unexpected segmentation faults, define INTERNAL_MALLOC.
  348. X    SysV users may want to define this anyway, because the internal malloc
  349. X    may be faster than the default malloc(3).
  350. X
  351. X    By default, INTERNAL_MALLOC is undefined.
  352. X
  353. X---------------
  354. XMiscellaneous defines:
  355. X
  356. XTIMEZONE
  357. X    If this is defined, the string it is defined to is used as your timezone
  358. X    regardless of what the system thinks your timezone is.  This is intended
  359. X    for systems which have no functions for determining the timezone.  On
  360. X    newer Gould BSD 4.3 systems, it is safe to use
  361. X        #define TIMEZONE T->tm_zone
  362. X    On other systems, it is better to define TIMEZONE as a string, e.g.
  363. X        #define TIMEZONE "PST"    /* Or "-0800" for MH style */
  364. X
  365. XDAYLITETZ
  366. X    This should be defined to your Daylight Savings Time timezone string if
  367. X    and only if you also define TIMEZONE (above).  Do not define this if you
  368. X    use the Gould tm_zone.
  369. X
  370. XVPRINTF
  371. X    This should be defined if your system has the vprintf functions. You
  372. X    *have* these functions if you are running:
  373. X    o system V
  374. X    o xenix
  375. X    o Sun release 3.0 or higher.
  376. X    If you are still not sure, try the following command from your shell:
  377. X
  378. X    % ar t /lib/libc.a | grep vprintf
  379. X
  380. X    If you have it, you'll probably get something like
  381. X    vprintf.o
  382. X    vsprintf.o
  383. X    as output.  If you don't have it, you won't have any output.  If your
  384. X    main C-libraries are not in /lib/libc.a, then find where they are and
  385. X    try the same command using that file.  BSD machines before 4.3-tahoe
  386. X    do not have vprintf().
  387. X
  388. X---------------
  389. XThe sprintf() function:
  390. X    If you *know* your system's sprintf returns a char *, you can remove the
  391. X    #define sprintf Sprintf
  392. X    in strings.h.  Careful, not all BSD4.3 machines are alike!  If you don't
  393. X    know for sure, don't change this define.
  394. X
  395. X---------------
  396. XRegular expression defines:
  397. X    Some systems have regcmp/regex as their regular expression matching
  398. X    routines while others have re_comp/re_exec -- If you have regcmp,
  399. X    you should define REGCMP so that you will use the routines regcmp()
  400. X    and regex() as the regular expression composer/parser.  REGCMP should
  401. X    normally be defined for xenix and System-V Unix.  If you don't have
  402. X    REGCMP defined, then the routines re_comp() and re_exec() are used
  403. X    (this is the default for mush).
  404. X
  405. X    Note that some systems do not have either set of routines in the default
  406. X    libraries.  You must find the library to use and add it to the list of
  407. X    libraries to use.  If this is the case, your link will fail with the
  408. X    errors that regex and re_comp are undefined functions.  Read your man
  409. X    page for regex(3) to find where to locate those libraries.
  410. X
  411. X---------------
  412. XThe Berkeley directory(3) routines:
  413. X    If your system has directory access routines compatible with BSD Unix
  414. X    (opendir, readdir, closedir) you should define DIRECTORY in either the
  415. X    makefile or config.h.  This is already reflected in the makefile.hpux.
  416. X    See the notes above for other Sys-V-ish systems that may require this.
  417. X    If DIRECTORY is not defined, replacement routines in glob.c are used.
  418. X
  419. X---------------
  420. XThe select() function call:
  421. X    Mush uses select() to implement macros, mappings and bindings.  If your
  422. X    system is a BSD system, then this is defined for you.  However, with the
  423. X    advent of hybrid bsd/sys-v systems, you may not be able to set BSD, but
  424. X    you know you still have select() --for such systems, define SELECT in
  425. X    your makefile or in config.h.
  426. X
  427. X    Newer xenix machines have this as so some system-v machines.  If you don't
  428. X    define one of BSD or SELECT, mush will use another function although not
  429. X    as optimal as select().
  430. X
  431. X---------------
  432. XThe default Mushrc startup file:
  433. X    A default mushrc should be installed, containing local configuration
  434. X    information (aliases or variable settings).  This can also provide
  435. X    first-time users with a more friendly interface.  UCB mail's default
  436. X    Mail.rc works, but no default file works also.  The location of the
  437. X    default file should be defined in config.h.  To have no default Mushrc,
  438. X    set the default to /dev/null.
  439. X
  440. X    The Mushrc file supplied with the mush distribution is heavily commented
  441. X    and uses several of mush's features in setting up the interface.  THIS
  442. X    FILE IS NOT INTENDED TO BE USED WITHOUT LOCAL MODIFICATIONS!  If you
  443. X    use this file, you should modify it so settings of the variables MAILRC,
  444. X    ALTERNATE_RC, and ALT_DEF_RC correspond to the definitions in your
  445. X    config.h file.  You should also examine and possibly delete the help
  446. X    section for new users (creates the .mushuser/.mushexpert files), which is
  447. X    included mainly as an example.  The Mushrc is designed to source the
  448. X    ALT_DEF_RC, which is usually equivalent to the UCB mail Mail.rc.  This
  449. X    eases the transition to mush for UCB sites, and allows aliases and
  450. X    settings that should apply to both mush and mail to reside in a single
  451. X    file.  UUCP sites may also want to uncomment the line which sets the
  452. X    auto_route and known_hosts variables; be sure to modify known_hosts to be
  453. X    an accurate list of your UUCP mail neighbors.
  454. X
  455. X    Important Note to sys-v'ers who can't get their hostname from utsname(2)
  456. X    (xenix, more?), the hostname should probably be set in the default Mailrc
  457. X    defined in config.h.    set hostname=whatever
  458. X
  459. X    If your system has a LAN or UUCP name returned by gethostname(3) and
  460. X    an additional network mail (domain) name, you probably want to add the
  461. X    domain name to the value of hostname.   set hostname="domain $hostname"
  462. X    (where "domain" is your local domain name).  Sometimes, the domain name
  463. X    is listed among the alternate names for the machine, which mush is able
  464. X    to look up, but will not be the first name mush finds.  Since mush uses
  465. X    the first name listed in $hostname when constructing From: lines and
  466. X    the like, you may need to use a "set" in Mushrc to rearrange the list.
  467. X
  468. X    For sun systems, the sun Mail Mailrc (/usr/lib/Mailrc) does not work
  469. X    very well because sun's Mail is not standard /usr/ucb/Mail.  For this
  470. X    reason, sun has not changed the default Mail.rc which still resides
  471. X    in /usr/lib/Mail.rc (note this has the "." whereas the other file
  472. X    does not).  The default config.h-dist reflects this.
  473. X
  474. X    There is a supplied Mailrc file with mush, but this is only intended to
  475. X    be used as an example of how to make mush look like ucbMail.  This is a
  476. X    _reduction_ in functionality and its usage is not encouraged.  It is
  477. X    provided for those who wish to "invisibly" replace UCB mail with mush.
  478. X
  479. X    There is a Gnurc file, also supplied as an example, which can aid in
  480. X    making mush's curses mode appear similar to gnu-emacs (NOT Rmail).
  481. X
  482. X    The files sample.mushrc and advanced.mushrc are intended as samples of
  483. X    individual users' ~/.mushrc files.  There is some overlap from Mushrc
  484. X    in sample.mushrc; in particular, if you use Mushrc as the default file,
  485. X    the sample.mushrc need not source ~/.mailrc.
  486. X
  487. X---------------
  488. XHelp files:
  489. X    The help files should be placed somewhere which is readable and accessible
  490. X    by all.  Failing to do so removes virtually the entire help facility's
  491. X    ability to help anyone.  There is a help file (cmd_help) for command help
  492. X    (e.g. "command -?"), and the file tool_help is for the graphics mode (Sun
  493. X    workstations only).  You should define where you want these files in
  494. X    config.h so at runtime, they can be accessed without error.  If for some
  495. X    reason you can't define a location at run-time, you can change Mushrc
  496. X    to set the variables $cmd_help and $tool_help to the correct locations.
  497. X
  498. X---------------
  499. X
  500. XYou should now be able to run make.  You may wish to use the target "install"
  501. Xto put the mush binary and the help and init files in their proper places; be
  502. Xsure to correct the destination directories in the Makefile you have selected,
  503. Xand to doublecheck file path names in the init files.
  504. X
  505. X---------------
  506. XMaintenance:
  507. X
  508. XIf you want to use dbx or any other debugger, or to use your default tty
  509. Xdriver, -e should be used as command line argument when you run the program.
  510. XWhat this flag does is prevents your echo from being turned off and leaving
  511. Xcbreak off, thus, keeping your tty in a sane state.  This prevents the use
  512. Xof mappings and macros (map and map!).  However, curses mode will automatic-
  513. Xally disable that mode.  The -e flag is highly discouraged.
  514. X
  515. XIf you have memory allocation checking and validation (sun 3.0+ ?) then
  516. Xdefine M_DEBUG in the makefile (main.c) and add the library
  517. X/usr/lib/debug/malloc.o to the library list. Do this only if you
  518. Xfind bugs in the program and suspect memory allocation errors. main.c
  519. Xhas the code which sets the debugging level according to the value of
  520. Xan environment variable.  Because malloc-debugging is so cpu intensive,
  521. Xthe tool mode program may get a SIGXCPU (cpu time limit exceeded)
  522. Xbecause of the large amount of opening and closing large pixrects and
  523. Xdevices.  For this reason, SIGXPCPU is is caught in main.c.
  524. X
  525. XThe "warning" variable may be set (at runtime in your .mushrc or as
  526. Xa command: "set warning") to aid in finding runtime errors that aren't
  527. Xfatal.  You can also use the "debug" command:
  528. X    debug 1    --    general trace messages
  529. X    debug 3    --    verbose messages, MTA disabled
  530. X    debug 4    --    really verbose messages
  531. X    debug 5    --    free() disabled
  532. X
  533. XIf you ever get "Message N has bad date: <date string>" then note
  534. Xthe FORMAT of that date and edit dates.c.  There are a number of
  535. X"sscanf"s which you can see match known date formats.  Use them as
  536. Xexamples and insert the new date format you have.
  537. X
  538. XIf Mush ever coredumps and you are suspicious about whether or not
  539. Xyour folder (or spool directory) was removed, or if you were editing
  540. Xa letter, you should check for the files .mushXXXXXX and .edXXXXXXX.
  541. XUnless something incredibly awful has happened, Mush won't die without
  542. Xasking if you want to save the .mushXXXXX file and if you actually want
  543. Xit to dump core.  Note that if you run mush from .suntools and there is
  544. Xa core dump, it probably wants to do some IO with the console and may
  545. Xhang (not exit) because it doesn't know it can't talk to you.  If mush
  546. Xis killed by SIGHUP, it won't remove the .mushXXXXXX file, but it won't
  547. Xtell you about it either (unfortunately).
  548. X
  549. XBare-bones line-mode mush (no CURSES) and tool mode (SUNTOOL) pass lint
  550. Xwith a small number of errors, mostly about long assignments losing accuracy.
  551. XThe SysV code has not been linted as thoroughly as the rest.  Curses doesn't
  552. Xlint very well, but even when you lint mush with CURSES defined, it mainly
  553. Xcomplains about the unused curses globals in curses.h.
  554. END_OF_FILE
  555. if test 25704 -ne `wc -c <'mush/README'`; then
  556.     echo shar: \"'mush/README'\" unpacked with wrong size!
  557. fi
  558. # end of 'mush/README'
  559. fi
  560. if test -f 'mush/mail.c.b' -a "${1}" != "-c" ; then 
  561.   echo shar: Will not clobber existing file \"'mush/mail.c.b'\"
  562. else
  563. echo shar: Extracting \"'mush/mail.c.b'\" \(26265 characters\)
  564. sed "s/^X//" >'mush/mail.c.b' <<'END_OF_FILE'
  565. X        }
  566. X        if (c == 'd') {
  567. X            rm_edfile(-2);
  568. X            return 0;
  569. X        } else if (c == 'c') {
  570. X            wprint("(continue editing letter)\n");
  571. X            return -1;
  572. X        } else if (c == 's')
  573. X            break;
  574. X        }
  575. X    }
  576. X    }
  577. X
  578. X    if (send_it() == -1) {
  579. X    if (isoff(flags, SEND_NOW))
  580. X        wprint("(continue)\n");
  581. X    return -1;
  582. X    }
  583. X    return 0;
  584. X}
  585. X
  586. X/*
  587. X * actually send the letter.
  588. X * 1. reset all the signals because of fork.
  589. X * 2. determine recipients (users, address, files, programs)
  590. X * 3. determine mailer, fork and return (if not verbose).
  591. X * 4. popen mailer, $record, and other files specified in step 1.
  592. X * 5. make the headers; this includes To: line, and user set headers, etc...
  593. X * 6. copy the letter right into the array of file pointers (step 1).
  594. X * 7. close the mailer and other files (step 1) and remove the edit-file.
  595. X * return -1 if mail wasn't sent.  could be user error, could be the system.
  596. X * allow user to try again or to save message to file and abort message.
  597. X * return 0 if successful.
  598. X */
  599. Xstatic int
  600. Xsend_it()
  601. X{
  602. X    register char *p, *b, *addr_list;
  603. X#ifdef MAXFILES
  604. X    register int size = MAXFILES - 1;
  605. X    FILE *files[MAXFILES];
  606. X    char *names[MAXFILES];
  607. X#else
  608. X    register int size = getdtablesize() - 1;
  609. X    FILE *files[30];  /* 30 should be sufficiently large enough */
  610. X    char *names[30];
  611. X#endif /* MAXFILES */
  612. X#if defined(VERBOSE_ARG) && !defined(SUNTOOL)
  613. X    SIGRET (*oldchld)();
  614. X#endif /* VERBOSE_ARG && !SUNTOOL */
  615. X    int next_file = 1; /* reserve files[0] for the mail delivery program */
  616. X    int log_file = -1; /* the index into the files array for mail logging */
  617. X    char buf[3*HDRSIZ];
  618. X    char *orig_to, *orig_cc, *orig_bcc; /* save originals to restore on error */
  619. X    char expand = !do_set(set_options, "no_expand");
  620. X    int fork_err = 0;
  621. X
  622. X    names[0] = names[1] = NULL; /* for free_vec() */
  623. X    /* If edit_hdrs, make sure the correct headers exist and are intact
  624. X     * before bothering to continue.
  625. X     */
  626. X    if (ison(flags, EDIT_HDRS)) {
  627. X    /* fool header_field into thinking that the file is the folder */
  628. X    FILE *save_tmpf = tmpf;
  629. X    long old_offset = msg[msg_cnt].m_offset;
  630. X
  631. X    if (!ed_fp) {
  632. X        wprint("No file for headers!\n");
  633. X        return -1;
  634. X    }
  635. X    Debug("Getting headers from file ... ");
  636. X
  637. X    tmpf = ed_fp;
  638. X    msg[msg_cnt].m_offset = 0L;
  639. X    if (p = header_field(msg_cnt, "to")) {
  640. X        (void) strcpy(To, p);
  641. X        Cc[0] = Bcc[0] = 0;
  642. X        if (p = header_field(msg_cnt, "cc"))
  643. X        (void) strcpy(Cc, p);
  644. X        if (p = header_field(msg_cnt, "bcc"))
  645. X        (void) strcpy(Bcc, p);
  646. X        if (p = header_field(msg_cnt, "fcc"))
  647. X        next_file += find_files(p, names+next_file, size-next_file, 1);
  648. X    } else
  649. X        *To = 0; /* Error caught below */
  650. X    msg[msg_cnt].m_offset = old_offset;
  651. X    tmpf = save_tmpf;
  652. X    Debug("\n");
  653. X    }
  654. X    if (!*To) {
  655. X    wprint("You must have a To: recipient to send mail.\n");
  656. X    if (!istool) {
  657. X        (void) signal(SIGINT, oldint);
  658. X        (void) signal(SIGQUIT, oldquit);
  659. X        (void) signal(SIGTERM, oldterm);
  660. X    }
  661. X    free_vec(&names[1]);
  662. X    return -1;
  663. X    }
  664. X
  665. X    if (!(p = do_set(set_options, "sendmail")))
  666. X    p = MAIL_DELIVERY;
  667. X
  668. X#ifdef VERBOSE_ARG
  669. X    if (ison(flags, VERBOSE) || do_set(set_options, "verbose")) {
  670. X    turnon(flags, VERBOSE); /* prevent fork when "verbose" has changed */
  671. X#ifndef SUNTOOL
  672. X    oldchld = signal(SIGCHLD, SIG_DFL); /* let pclose() do the wait() */
  673. X#endif /* SUNTOOL */
  674. X#ifdef MMDF
  675. X    b = &buf[strlen(sprintf(buf, "%s%s", p, VERBOSE_ARG))];
  676. X#else /* MMDF */
  677. X    b = &buf[strlen(sprintf(buf, "%s %s", p, VERBOSE_ARG))];
  678. X#endif /* MMDF */
  679. X    } else
  680. X#endif /* VERBOSE_ARG */
  681. X    b = buf + Strcpy(buf, p);
  682. X#ifdef METOO_ARG
  683. X    if (!strcmp(p, MAIL_DELIVERY) && do_set(set_options, "metoo"))
  684. X    b += strlen(sprintf(b, " %s", METOO_ARG));
  685. X#endif /* METOO_ARG */
  686. X    *b++ = ' ', *b = 0; /* strcat(b, " "); */
  687. X    addr_list = b; /* save this position to check for addresses later */
  688. X
  689. X    /* save original list.  If alias expansion fails, replace address lists
  690. X     * with what was originally typed so user can fix it.  This isn't necessary
  691. X     * if the lists are already in the file the user is editing (edit_hdrs).
  692. X     */
  693. X    if (isoff(flags, EDIT_HDRS))
  694. X    orig_to = savestr(To);
  695. X    /*
  696. X     * Build the address lines to give to the mail transfer system.  This
  697. X     * address line cannot contain comment fields!  First, expand aliases
  698. X     * since they may contain comment fields within addresses. Copy this
  699. X     * result back into the Buffer since this will go into the header ...
  700. X     * Next, remove all comments so the buffer contains ONLY valid addresses.
  701. X     * Next, strip off any filenames/programs which might occur in the list.
  702. X     * Finally, add this information to the command line buffer (buf).
  703. X     * Remove commas if necessary (see ifdefs).  In the event of errors,
  704. X     * force a dead letter by rm_edfile(-1).
  705. X     */
  706. X    if (!(p = alias_to_address(To))) {
  707. X    print("address expansion failed for To: list.\n");
  708. X    free_vec(&names[1]);
  709. X    if (isoff(flags, EDIT_HDRS))
  710. X        strcpy(To, orig_to), xfree(orig_to);
  711. X    return -1;
  712. X    } else {
  713. X    next_file += find_files(p, names+next_file, size-next_file, 0);
  714. X    if (expand)
  715. X        (void) strcpy(To, p);
  716. X    rm_cmts_in_addr(p);
  717. X    skipspaces(0);
  718. X    b += Strcpy(b, p);
  719. X    }
  720. X    if (isoff(flags, EDIT_HDRS))
  721. X    orig_cc = savestr(Cc);
  722. X    if (*Cc) {
  723. X    if (!(p = alias_to_address(Cc))) {
  724. X        wprint("address expansion failed for Cc: list.\n");
  725. X        free_vec(&names[1]);
  726. X        if (isoff(flags, EDIT_HDRS)) {
  727. X        strcpy(To, orig_to), xfree(orig_to);
  728. X        strcpy(Cc, orig_cc), xfree(orig_cc);
  729. X        }
  730. X        return -1;
  731. X    } else {
  732. X        next_file += find_files(p, names+next_file, size-next_file, 0);
  733. X        if (expand)
  734. X        (void) strcpy(Cc, p);
  735. X        rm_cmts_in_addr(p);
  736. X        skipspaces(0);
  737. X        if (*p) {
  738. X        *b++ = ',', *b++ = ' ';
  739. X        b += Strcpy(b, p);
  740. X        }
  741. X    }
  742. X    }
  743. X
  744. X    /* expand Bcc addrs, but don't add to list yet.  sign letter first */
  745. X    if (isoff(flags, EDIT_HDRS))
  746. X    orig_bcc = savestr(Bcc);
  747. X    if (*Bcc) {
  748. X    if (p = alias_to_address(Bcc))
  749. X        p = strcpy(Bcc, p);
  750. X    else {
  751. X        wprint("address expansion failed for Bcc: list.\n");
  752. X        free_vec(&names[1]);
  753. X        /* rm_edfile(-1); */
  754. X        if (isoff(flags, EDIT_HDRS)) {
  755. X        strcpy(To, orig_to), xfree(orig_to);
  756. X        strcpy(Cc, orig_cc), xfree(orig_cc);
  757. X        strcpy(Bcc, orig_bcc), xfree(orig_bcc);
  758. X        }
  759. X        return -1;
  760. X    }
  761. X    } else
  762. X    p = NULL;
  763. X
  764. X    /* Sign the letter before adding the Bcc list since they aren't
  765. X     * considered when adding a signature.
  766. X     */
  767. X    if (*addr_list && ison(flags, SIGN|DO_FORTUNE) &&
  768. X        isoff(glob_flags, REDIRECT) && isoff(flags, FORWARD))
  769. X    sign_letter(addr_list, flags, ed_fp);
  770. X
  771. X    if (p) { /* p still points to expanded Bcc list */
  772. X    next_file += find_files(p, names+next_file, size-next_file, 0);
  773. X    rm_cmts_in_addr(p);
  774. X    skipspaces(0);
  775. X    if (*p) {
  776. X        *b++ = ',', *b++ = ' ';
  777. X        b += Strcpy(b, p);
  778. X    }
  779. X    }
  780. X    if (!*addr_list && next_file == 1) {
  781. X    wprint("There must be at least 1 legal recipient.\n");
  782. X    if (isoff(flags, EDIT_HDRS)) {
  783. X        strcpy(To, orig_to), xfree(orig_to);
  784. X        strcpy(Cc, orig_cc), xfree(orig_cc);
  785. X        strcpy(Bcc, orig_bcc), xfree(orig_bcc);
  786. X    }
  787. X    return -1;
  788. X    }
  789. X
  790. X#ifdef NO_COMMAS
  791. X    for (p = buf; p = index(p, ','); p++)
  792. X    *p = ' ';
  793. X#endif /* NO_COMMAS */
  794. X
  795. X    Debug("mail command: %s\n", buf);
  796. X
  797. X    if (isoff(flags, VERBOSE) && debug < 3)
  798. X    switch (fork()) {
  799. X        case  0:  /* the child will send the letter. ignore signals */
  800. X#ifdef SYSV
  801. X        if (setpgrp() == -1)
  802. X#else /* SYSV */
  803. X        if (setpgrp(0, getpid()) == -1)
  804. X#endif /* SYSV */
  805. X            error("setpgrp");
  806. X#ifndef SUNTOOL
  807. X        (void) signal(SIGCHLD, SIG_DFL);
  808. X        (void) signal(SIGTERM, SIG_IGN);
  809. X#endif /* SUNTOOL */
  810. X        (void) signal(SIGINT, SIG_IGN);
  811. X        (void) signal(SIGHUP, SIG_IGN);
  812. X        (void) signal(SIGQUIT, SIG_IGN);
  813. X#ifdef SIGTTIN
  814. X        (void) signal(SIGTTOU, SIG_IGN);
  815. X        (void) signal(SIGTTIN, SIG_IGN);
  816. X#endif /* SIGTTIN */
  817. X#ifdef SIGCONT
  818. X        (void) signal(SIGCONT, SIG_IGN);
  819. X        (void) signal(SIGTSTP, SIG_IGN);
  820. X#endif /* SIGCONT */
  821. X        turnon(glob_flags, IGN_SIGS);
  822. X        when -1:
  823. X        error("fork failed trying to send mail");
  824. X        fork_err++;
  825. X        if (isoff(flags, EDIT_HDRS)) {
  826. X            strcpy(To, orig_to);
  827. X            strcpy(Cc, orig_cc);
  828. X            strcpy(Bcc, orig_bcc);
  829. X        }
  830. X        /* fall thru */
  831. X        default:
  832. X        /* istool doesn't need ed_fp, so don't keep it around */
  833. X        if (istool || !fork_err && isoff(glob_flags, REDIRECT))
  834. X            (void) fclose(ed_fp), ed_fp = NULL_FILE;
  835. X        free_vec(&names[1]);
  836. X        if (isoff(flags, EDIT_HDRS))
  837. X            xfree(orig_to), xfree(orig_cc), xfree(orig_bcc);
  838. X        if (!istool) {
  839. X            (void) signal(SIGINT, oldint);
  840. X            (void) signal(SIGQUIT, oldquit);
  841. X            (void) signal(SIGTERM, oldterm);
  842. X        }
  843. X        return 0 - fork_err;
  844. X    }
  845. X
  846. X
  847. X#ifdef MMDF
  848. X    *(addr_list-1) = '\0';
  849. X#endif /* MMDF */
  850. X    if (debug > 2) {
  851. X    files[0] = stdout;
  852. X    if (!*addr_list)
  853. X        addr_list = "[no recipients]";
  854. X    } else if (*addr_list) {
  855. X    if (!(files[0] = open_file(buf, TRUE, FALSE))) {
  856. X        rm_edfile(-1); /* force saving of undeliverable mail */
  857. X        if (isoff(flags, VERBOSE) && debug < 3)
  858. X        exit(-1);
  859. X        else
  860. X        return 0;
  861. X    }
  862. X    } else
  863. X    files[0] = NULL_FILE;
  864. X
  865. X    if (ison(flags, VERBOSE))
  866. X    wprint("Sending letter ... "), (void) fflush(stdout);
  867. X#ifdef MMDF
  868. X    /* give address list to submit */
  869. X    for (p = addr_list; *p && (p = any(p, ",<")); p++)
  870. X    if (*p == ',')
  871. X        *p = '\n';
  872. X    else
  873. X        p = index(p, '>');
  874. X    if (*addr_list)
  875. X    (void) fprintf(files[0], "%s\n\n", addr_list);
  876. X#endif /* MMDF */
  877. X
  878. X    /* see if log is set.  This is just to add message headers. No msg body. */
  879. X    if (p = do_set(set_options, "logfile")) {
  880. X    if (!*p)
  881. X        p = "~/mail.log";
  882. X    if (!index("~|/+", *p))
  883. X        (void) sprintf(buf, "%s/%s", do_set(set_options, "cwd"), p);
  884. X    else
  885. X        (void) strcpy(buf, p);
  886. X    log_file = next_file;
  887. X    next_file += find_files(buf, names+next_file, size-next_file, 0);
  888. X    if (log_file == next_file)
  889. X        log_file = -1;
  890. X    }
  891. X
  892. X    /* see if record is set.  If so, open that file for appending and add
  893. X     * the letter in a format such that mail can be read from it
  894. X     */
  895. X    if (p = do_set(set_options, "record")) {
  896. X    if (!*p)
  897. X        p = "~/record";
  898. X    if (!index("~|/+", *p))
  899. X        (void) sprintf(buf, "%s/%s", do_set(set_options, "cwd"), p);
  900. X    else
  901. X        (void) strcpy(buf, p);
  902. X    next_file += find_files(buf, names+next_file, size-next_file, 0);
  903. X    }
  904. X
  905. X    /* Don't need to open names[0] as files[0], so skip those */
  906. X    next_file = 1 + open_list(names + 1, files + 1, next_file - 1);
  907. X
  908. X    /* First, put the message separator in... */
  909. X    for (size = 1; size < next_file; size++)
  910. X#ifndef MSG_SEPARATOR
  911. X    {
  912. X        time_t t;
  913. X        (void) time(&t);
  914. X        (void) fprintf(files[size], "From %s %s", login, ctime(&t));
  915. X    }
  916. X#else /* MSG_SEPARATOR */
  917. X#ifdef MMDF
  918. X    (void) fputs(MSG_SEPARATOR, files[size]);
  919. X#else /* MMDF */
  920. X    (void) fprintf(files[size], "%s\n", MSG_SEPARATOR);
  921. X#endif /* MMDF */
  922. X#endif /* MSG_SEPARATOR */
  923. X
  924. X    /* if redirection, ed_fp = stdin, else rewind the file just made */
  925. X    if (isoff(glob_flags, REDIRECT))
  926. X    rewind(ed_fp);
  927. X    else
  928. X    ed_fp = stdin;
  929. X
  930. X#ifndef MSG_SEPARATOR
  931. X    /* If forwarding or reading a draft, skip the leading From_ line.
  932. X     * This is done for drafts so that messages saved by dead_letter()
  933. X     * can be read back in as a draft; in other cases, this isn't done
  934. X     * for edit_hdrs because FORWARD wouldn't be set.
  935. X     */
  936. X    if (ison(flags, FORWARD|SEND_NOW) && fgets(buf, sizeof buf, ed_fp) &&
  937. X    strncmp(buf, "From ", 5) != 0)
  938. X    rewind(ed_fp); /* No From_ line (should never happen) */
  939. X#endif /* MSG_SEPARATOR */
  940. X    {
  941. X    long offset = add_headers(ed_fp, files, next_file, flags);
  942. X    if (offset == -1)
  943. X        offset = 0L;
  944. X    (void) fseek(ed_fp, offset, L_SET);
  945. X    }
  946. X
  947. X    /* Read from stdin or the edfile till EOF and send it all to the mailer
  948. X     * and other open files/folders/programs. Check for "From " at the
  949. X     * beginnings of these lines to prevent creating new messages in folders.
  950. X     */
  951. X    while (fgets(buf, sizeof buf, ed_fp))
  952. X    for (size = 0; size < next_file; size++) {
  953. X        if (!files[size]) /* files[0] will be NULL if not calling MTA */
  954. X        continue;
  955. X        if (size == log_file)
  956. X        continue;
  957. X#ifndef MSG_SEPARATOR
  958. X        if (!strncmp(buf, "From ", 5))
  959. X        (void) fputc('>', files[size]);
  960. X#endif /* MSG_SEPARATOR */
  961. X        if (fputs(buf, files[size]) == EOF) {
  962. X        if (size == 0) {
  963. X            error("Lost connection to MTA");
  964. X            dead_letter(-1);
  965. X            break;
  966. X        } else {
  967. X            /* Drop this file, but continue writing others */
  968. X            if (names[size]) {
  969. X            error("Write failed: %s", names[size]);
  970. X            (void) close_lock(names[size], files[size]);
  971. X            xfree(names[size]);
  972. X            } else
  973. X            error("Write failed");
  974. X            if (size < --next_file) {
  975. X            names[size] = names[next_file];
  976. X            files[size--] = files[next_file];
  977. X            }
  978. X            files[next_file] = NULL_FILE;
  979. X            names[next_file] = NULL;
  980. X        }
  981. X        }
  982. X    }
  983. X
  984. X    /* loop thru the open files (except for the first: the mail delivery agent)
  985. X     * and append a blank line so that ucb-mail can read these folders.
  986. X     * Then close the files.
  987. X     */
  988. X    for (size = 1; size < next_file; size++) {
  989. X#ifdef END_MSG_SEP
  990. X    (void) fputs(END_MSG_SEP, files[size]);
  991. X#endif /* END_MSG_SEP */
  992. X    if (names[size]) {
  993. X#ifndef END_MSG_SEP
  994. X        (void) fputc('\n', files[size]);
  995. X#endif /* !END_MSG_SEP */
  996. X        if (close_lock(names[size], files[size]) == EOF) {
  997. X        error("Warning: Close failed: %s", names[size]);
  998. X        }
  999. X        xfree(names[size]);
  1000. X    } else {
  1001. X        if (debug < 3)
  1002. X        (void) fclose(files[size]); /* Don't mess with pclose() */
  1003. X        else
  1004. X        (void) pclose(files[size]); /* unless we never forked */
  1005. X    }
  1006. X    }
  1007. X
  1008. X    if (debug < 3) {
  1009. X    int reply_code = files[0]? pclose(files[0]) : (MTA_EXIT << 8);
  1010. X    Debug("pclose reply_code = %d\n", reply_code);
  1011. X    rm_edfile((reply_code == (MTA_EXIT << 8))? 0 : -1);
  1012. X    } else
  1013. X    rm_edfile(0);
  1014. X
  1015. X#ifndef SUNTOOL
  1016. X#ifdef VERBOSE_ARG
  1017. X    if (ison(flags, VERBOSE))
  1018. X    (void) signal(SIGCHLD, oldchld);
  1019. X#endif /* VERBOSE_ARG */
  1020. X#endif /* SUNTOOL */
  1021. X
  1022. X    if (ison(flags, VERBOSE) || debug > 2) {
  1023. X    if (isoff(glob_flags, REDIRECT))
  1024. X        wprint("sent.\n");
  1025. X    if (!istool) {
  1026. X        (void) signal(SIGINT, oldint);
  1027. X        (void) signal(SIGQUIT, oldquit);
  1028. X        (void) signal(SIGTERM, oldterm);
  1029. X    }
  1030. X    } else
  1031. X    exit(0); /* not a user exit -- a child exit */
  1032. X    return 0;
  1033. X}
  1034. X
  1035. X/*
  1036. X * Add the necessary headers to make a file a legitimate mail message.
  1037. X * This could be for a file which the user will edit (via edit_hdrs) or
  1038. X * for delivery to an MTA.
  1039. X * Make folders conform to RFC-822 by adding From: and Date: headers.
  1040. X * Prefix certain header with the "Resent-" prefix when forwarding.
  1041. X * Return offset of fp if we're parsing it for headers (for delivery to MTA).
  1042. X */
  1043. Xstatic long
  1044. Xadd_headers(fp, files, size, flags)
  1045. XFILE *fp, *files[];
  1046. Xint size;
  1047. Xu_long flags;
  1048. X{
  1049. X    char buf[BUFSIZ], From_buf[256], *pF = From_buf, date_str[64];
  1050. X    char *host = NULL, *p, *subj = NULL, *own_from = NULL; /* See WARNING */
  1051. X    int i, for_editor = (fp == NULL_FILE);
  1052. X    int got_date = for_editor, got_from = for_editor;
  1053. X    struct options *opts;
  1054. X
  1055. X    if (for_editor && hfile) {
  1056. X    i = file_to_fp(hfile, files[0], "r");
  1057. X    xfree(hfile), hfile = NULL;
  1058. X    return (i < 0 ? -1 : TRUE);
  1059. X    }
  1060. X
  1061. X    buf[0] = 0;
  1062. X    if (ourname)
  1063. X    host = ourname[0];
  1064. X    if (for_editor)
  1065. X    turnoff(flags,FORWARD); /* forwarded messages must not be edited */
  1066. X
  1067. X    /* [Re]create a From: header -- check first to see if the user has
  1068. X     * created a From: header with the my_hdr command (the own_hdrs list).
  1069. X     * If his is not legitimate, warn user and use the other header.
  1070. X     */
  1071. X    if ((for_editor || isoff(glob_flags, EDIT_HDRS)) &&
  1072. X        own_hdrs && !do_set(set_options, "no_hdrs")) {
  1073. X    for (opts = own_hdrs; opts; opts = opts->next)
  1074. X        if (!strcmp(opts->option, "From:")) {
  1075. X        p = opts->value;
  1076. X        skipspaces(0);
  1077. X        sprintf(buf, "%sFrom: %s\n",
  1078. X                ison(flags, FORWARD)? "Resent-" : "", p);
  1079. X        own_from = buf;
  1080. X        /* WARNING: the above depends on the following facts:
  1081. X         * 1. If for_editor, own_from will be output immediately,
  1082. X         *    so buf will not be overwritten;
  1083. X         * 2. If !for_editor but EDIT_HDRS, the "real" from line
  1084. X         *    will be read from the file so own_from isn't needed;
  1085. X         * 3. If neither, From: is the first line output, so
  1086. X         *    buf will not be overwritten.
  1087. X         * Any change in the above means a new buffer for own_from
  1088. X         * may be needed.  Check carefully.
  1089. X         */
  1090. X        }
  1091. X    }
  1092. X    if (ison(flags, FORWARD))
  1093. X    pF += Strcpy(From_buf, "Resent-");
  1094. X    pF += Strcpy(pF, "From: ");
  1095. X#ifdef UUCP
  1096. X    if (host && *host)
  1097. X    pF += strlen(sprintf(pF, "%s!", host));
  1098. X#endif /* UUCP */
  1099. X    pF += Strcpy(pF, login);
  1100. X#ifndef UUCP
  1101. X    if (host && *host)
  1102. X    pF += strlen(sprintf(pF, "@%s", host));
  1103. X#endif /* UUCP */
  1104. X    if ((p = do_set(set_options, "realname")) ||
  1105. X    (p = do_set(set_options, "name")))
  1106. X    pF += strlen(sprintf(pF, " (%s)", p));
  1107. X    *pF++ = '\n', *pF++ = 0;
  1108. X
  1109. X    /* First print From, Date, In-Reply-To */
  1110. X    for (i = 0; i < size; i++) {
  1111. X    if (!files[i])
  1112. X        continue;
  1113. X    if (for_editor)
  1114. X        if (own_from)
  1115. X        (void) fputs(own_from, files[i]), *own_from = 0;
  1116. X        else
  1117. X        (void) fputs(From_buf, files[i]);
  1118. X    else if (isoff(flags, EDIT_HDRS)) {
  1119. X#ifdef PICKY_MAILER
  1120. X        if (i > 0)
  1121. X#endif /* PICKY_MAILER */
  1122. X        if (own_from)
  1123. X        (void) fputs(own_from, files[i]), *own_from = 0;
  1124. X        else
  1125. X        (void) fputs(From_buf, files[i]);
  1126. X        got_from = TRUE;
  1127. X    }
  1128. X    if (for_editor || isoff(flags, EDIT_HDRS)) {
  1129. X#ifdef PICKY_MAILER
  1130. X        if (i > 0 && !for_editor)
  1131. X#endif /* PICKY_MAILER */
  1132. X        (void) fprintf(files[i], "%sDate: %s\n",
  1133. X        ison(flags, FORWARD) ? "Resent-" : "", rfc_date(date_str));
  1134. X        got_date = TRUE;
  1135. X        if (*in_reply_to)
  1136. X        fprintf(files[i], "In-Reply-To: %s\n", in_reply_to);
  1137. X    }
  1138. X    }
  1139. X    /* next print user's own message headers */
  1140. X    if (for_editor || isoff(flags, EDIT_HDRS))
  1141. X    if (own_hdrs && !do_set(set_options, "no_hdrs")) {
  1142. X        for (opts = own_hdrs; opts; opts = opts->next) {
  1143. X        if (!strcmp(opts->option, "From:"))
  1144. X            continue;
  1145. X        for (i = 0; i < size; i++) {
  1146. X            if (!files[i])
  1147. X            continue;
  1148. X            p = opts->value;
  1149. X            skipspaces(0);
  1150. X            fprintf(files[i], "%s %s\n", opts->option, p);
  1151. X        }
  1152. X        }
  1153. X    }
  1154. X
  1155. X    /*
  1156. X     * Now either prepare to put the rest of the headers into the file
  1157. X     * or (when sending edited headers) copy them back out of the file
  1158. X     */
  1159. X    if (for_editor) {
  1160. X    char *orig = NULL;
  1161. X    /* for edit_hdrs, print the headers followed by a blank line */
  1162. X    if (To[0]) {
  1163. X        orig = savestr(To);
  1164. X        if (!(p = alias_to_address(To))) {
  1165. X        wprint("To: list unmodified.\n");
  1166. X        p = orig;
  1167. X        }
  1168. X        (void) strcpy(To, p);
  1169. X    }
  1170. X    if (Cc[0]) {
  1171. X        strdup(orig, Cc);
  1172. X        if (!(p = alias_to_address(Cc))) {
  1173. X        wprint("Cc: list unmodified.\n");
  1174. X        p = orig;
  1175. X        }
  1176. X        (void) strcpy(Cc, p);
  1177. X    }
  1178. X    if (Bcc[0]) {
  1179. X        strdup(orig, Bcc);
  1180. X        if (!(p = alias_to_address(Bcc))) {
  1181. X        wprint("Bcc: list unmodified.\n");
  1182. X        p = orig;
  1183. X        }
  1184. X        (void) strcpy(Bcc, p);
  1185. X    }
  1186. X    xfree(orig);
  1187. X    } else if (ison(flags, EDIT_HDRS)) {
  1188. X    /* copy the headers of the message removing special headers */
  1189. X    int print_hdr = FALSE;
  1190. X    if (isoff(flags, SEND_NOW))
  1191. X        rewind(fp); /* Drafts may have had fp positioned */
  1192. X    while (fgets(buf, sizeof(buf), fp)) {
  1193. X        (void) no_newln(buf);
  1194. X        if (!buf[0])
  1195. X        break;
  1196. X        /* if the first char is NOT a space, it MUST be a new header.
  1197. X         * Otherwise, it is considered part of the message body.
  1198. X         */
  1199. X        if (!isspace(buf[0])) {
  1200. X        print_hdr = TRUE;
  1201. X        if (!(p = any(buf, " \t:")) || isspace(*p))
  1202. X            break; /* this is not a legitimate header */
  1203. X        skipspaces(1);
  1204. X        if (!*p)
  1205. X            print_hdr = FALSE; /* blank headers are not allowed */
  1206. X        p = buf;
  1207. X        if (!lcase_strncmp(buf, "resent-", 7)) {
  1208. X            if (ison(flags, EDIT_HDRS))
  1209. X        wprint("You can't use \"Resent-\" headers in edited messages.\n");
  1210. X            p += 7;
  1211. X        }
  1212. X        if (!lcase_strncmp(p, "to:", 3) ||
  1213. X            !lcase_strncmp(p, "cc:", 3) ||
  1214. X            !lcase_strncmp(p, "bcc:", 4) ||
  1215. X            !lcase_strncmp(p, "fcc:", 4) ||
  1216. X            !lcase_strncmp(p, "x-mailer:", 9) ||
  1217. X            !lcase_strncmp(p, "status:", 7))
  1218. X            print_hdr = FALSE;
  1219. X        else if (!lcase_strncmp(p, "date:", 5))
  1220. X            if (got_date)
  1221. X            wprint("You can't change or add date headers.\n");
  1222. X            else {
  1223. X            got_date = TRUE;
  1224. X            (void) sprintf(buf, "Date: %s", rfc_date(date_str));
  1225. X            p = buf;
  1226. X            }
  1227. X        else if (!lcase_strncmp(p, "subject:", 8))
  1228. X            (print_hdr = FALSE), strdup(subj, p);
  1229. X        else if (!lcase_strncmp(p, "from:", 5)) {
  1230. X            char not_me[BUFSIZ];
  1231. X            (void) strcpy(not_me, buf + 5);
  1232. X            take_me_off(not_me);
  1233. X            if (*not_me) {
  1234. X            /* Ignore bogus From: if we have a good one */
  1235. X            if (got_from)
  1236. X                print_hdr = FALSE;
  1237. X            /* otherwise, output a good one */
  1238. X            else {
  1239. X                (void) strcpy(buf, From_buf);
  1240. X                (void) no_newln(buf);
  1241. X            }
  1242. X            }
  1243. X            got_from = TRUE;
  1244. X#ifdef PICKY_MAILER
  1245. X            /* don't send From: to mta -- fool "for loop" below
  1246. X             * by initializing the loop at files[1], not files[0]
  1247. X             */
  1248. X            if (!for_editor)
  1249. X            print_hdr = 2;
  1250. X#endif /* PICKY_MAILER */
  1251. X        }
  1252. X        }
  1253. X        if (print_hdr)
  1254. X        /* print_hdr may be 2 for From: header */
  1255. X        for (i = print_hdr-1; i < size; i++)
  1256. X            if (files[i]) {
  1257. X            (void) fputs(buf, files[i]);
  1258. X            (void) fputc('\n', files[i]);
  1259. X            }
  1260. X    }
  1261. X    }
  1262. X    /* Finally, do the required (or changed) headers (Date, To, Cc) */
  1263. X    (void) wrap_addrs(To, 80);
  1264. X    (void) wrap_addrs(Cc, 80);
  1265. X    (void) wrap_addrs(Bcc, 80);
  1266. X    for (i = 0; i < size; i++) {
  1267. X    if (!files[i])
  1268. X        continue;
  1269. X#ifdef PICKY_MAILER
  1270. X    if (i > 0) {
  1271. X#endif /* PICKY_MAILER */
  1272. X    if (!got_from)
  1273. X        if (own_from)
  1274. X        (void) fputs(own_from, files[i]);
  1275. X        else
  1276. X        (void) fputs(From_buf, files[i]);
  1277. X    if (!got_date)
  1278. X        (void) fprintf(files[i], "%sDate: %s\n",
  1279. X        ison(flags, FORWARD) ? "Resent-" : "", rfc_date(date_str));
  1280. X#ifdef PICKY_MAILER
  1281. X    }
  1282. X#endif /* PICKY_MAILER */
  1283. X    (void) fprintf(files[i], "X-Mailer: %s\n", check_internal("version"));
  1284. X    (void) fprintf(files[i], "%sTo: %s\n",
  1285. X        ison(flags, FORWARD) ? "Resent-" : "", To);
  1286. X    if (for_editor || isoff(flags, EDIT_HDRS)) {
  1287. X        if (isoff(flags, FORWARD) &&
  1288. X            (*Subject || for_editor && (do_set(set_options, "ask") ||
  1289. X                        do_set(set_options, "asksub"))))
  1290. X        (void) fprintf(files[i], "Subject: %s\n", Subject);
  1291. X    } else if (subj && *subj && strlen(subj) > 9)
  1292. X        (void) (fputs(subj, files[i]), fputc('\n', files[i]));
  1293. X    if (*Cc || for_editor && do_set(set_options, "askcc"))
  1294. X        (void) fprintf(files[i], "%sCc: %s\n",
  1295. X        ison(flags, FORWARD) ? "Resent-" : "", Cc);
  1296. X    if (i > 0 || for_editor)
  1297. X        /* Do not send these to mail transfer agent */
  1298. X        if (*Bcc)
  1299. X        (void) fprintf(files[i], "%sBcc: %s\n",
  1300. X            ison(flags, FORWARD) ? "Resent-" : "", Bcc);
  1301. X    if (i > 0)
  1302. X        (void) fprintf(files[i], "Status: OR\n");
  1303. X    }
  1304. X    for (i = 0; i < size; i++)
  1305. X    if (files[i])
  1306. X        (void) fflush(files[i]);
  1307. X    if (buf[0]) /* last attempted header read was a line of msg text */
  1308. X    for (i = 0; i < size; i++) {
  1309. X        if (files[i]) {
  1310. X        (void) fputs(buf, files[i]);
  1311. X        (void) fputc('\n', files[i]);
  1312. X        (void) fflush(files[i]);
  1313. X        }
  1314. X    }
  1315. X    else
  1316. X    if (isoff(flags, FORWARD))
  1317. X        for (i = 0; i < size; i++)
  1318. X        if (files[i]) {
  1319. X            (void) fputc('\n', files[i]);
  1320. X            (void) fflush(files[i]);
  1321. X        }
  1322. X    return fp? ftell(fp) : (long)TRUE;
  1323. X}
  1324. X
  1325. X/* ARGSUSED */
  1326. XSIGRET
  1327. Xrm_edfile(sig)
  1328. X{
  1329. X    if (sig > 0) {
  1330. X    char *fix;
  1331. X    if (ison(glob_flags, IGN_SIGS))
  1332. X        return;
  1333. X    /* wrapcolumn may have been trashed -- restore it */
  1334. X    if ((fix = do_set(set_options, "wrapcolumn")) && *fix)
  1335. X        wrapcolumn = atoi(fix);
  1336. X    mac_flush(); /* abort pending macros */
  1337. X    }
  1338. X    /* now check whether we should abort the letter */
  1339. X    if (sig > 0 && !killme && ison(glob_flags, IS_GETTING)) {
  1340. X    if (!istool)
  1341. X        (void) signal(sig, rm_edfile);
  1342. X    killme = 1;
  1343. X    print("\n** interrupt -- one more to kill letter **\n");
  1344. X    longjmp(cntrl_c_buf, 1);
  1345. X    }
  1346. X    killme = 0;
  1347. X    /* if sig == -1, force a save into dead.letter.
  1348. X     * else, check for nosave not being set and save anyway if it's not set
  1349. X     * sig == 0 indicates normal exit (or ~x), so don't save a dead letter.
  1350. X     */
  1351. X    if (sig == -1 || sig != 0 && !do_set(set_options, "nosave"))
  1352. X    dead_letter(sig);
  1353. X    if (isoff(glob_flags, REDIRECT) && ed_fp) /* ed_fp may be null in toolmode*/
  1354. X    (void) fclose(ed_fp), ed_fp = NULL_FILE;
  1355. X    (void) unlink(edfile);
  1356. X
  1357. X    turnoff(glob_flags, IS_GETTING);
  1358. X    if (sig == -1)
  1359. X    return;
  1360. X
  1361. X    if (sig == SIGHUP)
  1362. X    cleanup(0);
  1363. X    if (!istool) {
  1364. X    (void) signal(SIGINT, oldint);
  1365. X    (void) signal(SIGQUIT, oldquit);
  1366. X    (void) signal(SIGTERM, oldterm);
  1367. X    }
  1368. X
  1369. X    if (sig == 0 || sig == -2 || istool) /* make sure sigchld is reset first */
  1370. X    return;
  1371. X
  1372. X    if (isoff(glob_flags, DO_SHELL)) {  /* If we're not in a shell, exit */
  1373. X    puts("exiting");
  1374. X    echo_on();
  1375. X    exit(1);
  1376. X    }
  1377. X    longjmp(jmpbuf, 1);
  1378. X}
  1379. X
  1380. X/* save letter into dead letter */
  1381. Xdead_letter(sig)
  1382. Xint sig;    /* signal passed to rm_edfile() or 0 */
  1383. X{
  1384. X    char     *p, buf[BUFSIZ];
  1385. X    long     t;
  1386. X    FILE     *dead;
  1387. X
  1388. X    if (ison(glob_flags, REDIRECT)) {
  1389. X    print("input redirected -- can't save dead letter.\n");
  1390. X    return;
  1391. X    }
  1392. X    /* If the file doesn't exist, get outta here. File may not exist if
  1393. X     * user generated a ^C from a promptable header and catch sent us here.
  1394. X     */
  1395. X    if (!ed_fp && Access(edfile, R_OK) != 0)
  1396. X    return;
  1397. X    /* User may have killed mush via a signal while he was in an editor.
  1398. X     * ed_fp will be NULL in this case.  Since the file does exist (above),
  1399. X     * open it so we can copy it to dead letter.
  1400. X     */
  1401. X    if (!ed_fp && !(ed_fp = fopen(edfile, "r"))) {
  1402. X    error("can't save dead letter from %s", edfile);
  1403. X    return;
  1404. X    }
  1405. X    /* don't save a dead letter if there's nothing to save. */
  1406. X    if (fseek(ed_fp, 0L, 2) || ftell(ed_fp) <= 1L)
  1407. X    return;
  1408. X    if (!(p = do_set(set_options, "dead")))
  1409. X    p = "~/dead.letter";
  1410. X    if (!(dead = open_file(p + (*p == '|'), (*p == '|'), TRUE)))
  1411. X    return;
  1412. X    (void) time (&t);
  1413. X    (void) fflush(ed_fp);
  1414. X    rewind(ed_fp);
  1415. X#ifdef MSG_SEPARATOR
  1416. X    (void) fputs(MSG_SEPARATOR, dead);
  1417. X#ifndef MMDF
  1418. X    (void) fputc('\n', dead);
  1419. X#endif /* MMDF */
  1420. X#else /* MSG_SEPARATOR */
  1421. X    (void) fprintf(dead, "From %s %s", login, ctime(&t));
  1422. X#endif /* MSG_SEPARATOR */
  1423. X    (void) fprintf(dead, "From: %s\nTo: %s\nSubject: %s\n", login, To, Subject);
  1424. X    (void) fprintf(dead, "Date: %s\n", rfc_date(buf));
  1425. X    if (*Cc)
  1426. X    (void) fprintf(dead, "Cc: %s\n", Cc);
  1427. X    if (*Bcc)
  1428. X    (void) fprintf(dead, "Bcc: %s\n", Bcc);
  1429. X    (void) fputc('\n', dead);
  1430. X    while (fgets(buf, sizeof(buf), ed_fp))
  1431. X    (void) fputs(buf, dead);
  1432. X    (void) fputc('\n', dead);
  1433. X#ifdef END_MSG_SEP
  1434. X    (void) fputs(END_MSG_SEP, dead);
  1435. X#endif /* END_MSG_SEP */
  1436. X    if (*p != '|')
  1437. X    (void) close_lock(p, dead);
  1438. X    else
  1439. X    (void) pclose(dead);
  1440. X    wprint("Saved%s letter in %s.\n", sig > 0? " unfinished" : "", p);
  1441. X}
  1442. END_OF_FILE
  1443. if test 26265 -ne `wc -c <'mush/mail.c.b'`; then
  1444.     echo shar: \"'mush/mail.c.b'\" unpacked with wrong size!
  1445. fi
  1446. # end of 'mush/mail.c.b'
  1447. fi
  1448. echo shar: End of archive 12 \(of 19\).
  1449. cp /dev/null ark12isdone
  1450. MISSING=""
  1451. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ; do
  1452.     if test ! -f ark${I}isdone ; then
  1453.     MISSING="${MISSING} ${I}"
  1454.     fi
  1455. done
  1456. if test "${MISSING}" = "" ; then
  1457.     echo You have unpacked all 19 archives.
  1458.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1459. else
  1460.     echo You still need to unpack the following archives:
  1461.     echo "        " ${MISSING}
  1462. fi
  1463. ##  End of shell archive.
  1464. exit 0
  1465.  
  1466.