home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume9 / elm2 / part14 < prev    next >
Text File  |  1987-03-10  |  46KB  |  1,503 lines

  1. Subject:  v09i014:  ELM Mail System, Part14/19
  2. Newsgroups: mod.sources
  3. Approved: rs@mirror.TMC.COM
  4.  
  5. Submitted by: Dave Taylor <hplabs!taylor>
  6. Mod.sources: Volume 9, Issue 14
  7. Archive-name: elm2/Part14
  8.  
  9. #! /bin/sh
  10. # This is a shell archive.  Remove anything before this line,
  11. # then unpack it by saving it in a file and typing "sh file".
  12. # If this archive is complete, you will see the message:
  13. #        "End of archive 14 (of 19)."
  14. # Contents:  doc/Filter.guide src/newmbox.c src/reply.c
  15. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  16. echo shar: Extracting \"doc/Filter.guide\" \(15096 characters\)
  17. if test -f doc/Filter.guide ; then 
  18.   echo shar: Will not over-write existing file \"doc/Filter.guide\"
  19. else
  20. sed "s/^X//" >doc/Filter.guide <<'END_OF_doc/Filter.guide'
  21. X.PH ""
  22. X\"
  23. X\"  A guide to the Elm Filter program
  24. X\"  format with 'tbl Filter.guide | troff -mm > Filter.format'
  25. X\"  or something similar.
  26. X\"  (C) Copyright 1986 Dave Taylor
  27. X\"
  28. X\"  Last modification: January 19th, 1987
  29. X\"
  30. X.SA 1
  31. X.nr Hy 1
  32. X.nr Pt 1
  33. X.nr Pi 8
  34. X.lg
  35. X.HM 1 1
  36. X.rs
  37. X.ds HF 3  3  
  38. X.ds HP 12 12 10 10 10
  39. X.PF ""
  40. X.ce 99
  41. X.sp 9
  42. X.ps 20
  43. X\fBElm Filter Guide\fR
  44. X.sp 7
  45. X.ps 12
  46. X\fIWhat the filter program is, what it does,
  47. Xand how to use it\fR
  48. X.sp 5
  49. XDave Taylor
  50. X.sp
  51. XHewlett-Packard Laboratories
  52. X1501 Page Mill Road
  53. XPalo Alto CA
  54. X94304
  55. X.sp 
  56. Xemail: taylor@hplabs.HP.COM or hplabs!taylor
  57. X.sp 10
  58. X.ps 18
  59. X\fB\(co\fR\s12 Copyright 1986, 1987 by Dave Taylor
  60. X.ps 10
  61. X.SK
  62. X.sp 5
  63. X.ps 14
  64. X\fBElm Filter Guide\fR
  65. X.PH "'Filter Guide''version 1.5'
  66. X.PF "''Page \\\\nP''"
  67. X.nr P 1
  68. X.sp
  69. X.ps 10
  70. X(version 1.5)
  71. X.sp 2
  72. XDave Taylor
  73. X.sp
  74. XHewlett-Packard Laboratories
  75. X1501 Page Mill Road
  76. XPalo Alto CA
  77. X94304
  78. X.sp 
  79. Xemail: taylor@hplabs.HP.COM or hplabs!taylor
  80. X.sp 2
  81. X\*(DT
  82. X.ce 0
  83. X.sp 3
  84. X.P
  85. XOne of the greatest problems with the burgeoning electronic mail
  86. Xexplosion is that we tend to get mail that we don't care about.
  87. XAmusingly, perhaps, we have the equivalent of electronic junk mail.
  88. XNot amusing, however, is the fact that this can rapidly 
  89. Xaccumulate and end up taking over your mailbox!
  90. X.P
  91. XAt the same time we often get mail that, while it is interesting
  92. Xand important, can easily be filed to be read later, without ever
  93. Xactually cluttering up the mailbox.
  94. X.sp 2
  95. XThis, then, is what \fIfilter\fR does for you!  The \fIfilter\fR program
  96. Xallows you to define a set of rules by which all incoming mail should
  97. Xbe screened, and a subsequent set of actions to perform based on whether
  98. Xthe rules were met or not.  \fIFilter\fR also has the ability to mail
  99. Xa summary of what actions it performed on the incoming mail as often as
  100. Xyou'd like.
  101. X.sp
  102. X.ps 12
  103. X\fB
  104. XWriting the Rules\fR
  105. X.ps 10
  106. X.sp
  107. XThe language for writing \fIfilter\fR rules is pretty simple, actually.
  108. XThe fundamental structure is;
  109. X.nf
  110. X
  111. X    if  (\fIcondition\fR)  then  \fIaction\fR
  112. X
  113. X.fi
  114. XWhere \fIcondition\fR is constructed by an arbitrary number of 
  115. Xindividual conditions of the form ``\fIfield\fR  \fIrelation\fR  \fIvalue\fR''.
  116. XThe \fIfield\fR value can be;
  117. X.nf
  118. X
  119. X    subject
  120. X    from
  121. X    to
  122. X    lines
  123. X    contains
  124. X
  125. X.fi
  126. Xwhere, if ``lines'' is choosen, the \fIrelation\fR can be any of the
  127. Xstandard relationships (`>', `<', `>=', `<=', `!=' and `=').  
  128. XIf another action is
  129. Xchoosen, ``contains'' can be used as the relation, ``='', or, if you'd
  130. Xlike, you can skip the relationship entirely (e.g. `subject "joe"').
  131. XThe \fIvalue\fR is any quoted string that is to be matched against
  132. Xor number if ``lines'' is the field being considered.
  133. X.sp
  134. XInvidivual conditions are joined together by using the word ``and'',
  135. Xand the logic of a condition can be flipped by using ``not'' as the
  136. Xfirst word (e.g. `not subject "joe"').  We'll see more examples of
  137. Xthis later.
  138. X.sp
  139. XNote that the ``or'' logical conjunction isn't a valid part of the
  140. X\fIfilter\fR conditional statement.  
  141. X.sp
  142. XFinally, <\fIaction\fR> can be any of;
  143. X.nf
  144. X
  145. X    delete
  146. X
  147. X    save   \fIfoldername\fR
  148. X
  149. X    savecopy  \fIfoldername\fR
  150. X
  151. X    forward  \fIaddress\fR
  152. X
  153. X    execute  \fIcommand\fR
  154. X
  155. X    leave
  156. X
  157. X.fi
  158. Xwhere they result in the actions;  \fBdelete\fR deletes the message;
  159. X\fBsave\fR saves a copy of the message in the specified foldername;
  160. X\fBsavecopy\fR does the same as save, but also puts a copy in your mailbox;
  161. X\fBforward\fR sends the message to the specified address; 
  162. X\fBexecute\fR feeds the message to the specified command (or complex
  163. Xsequence of commands) as standard input;
  164. Xand \fBleave\fR leaves the message in your mailbox.
  165. X.sp
  166. XFoldernames can contain any of a number of macros, too, as we'll see in
  167. Xthe example ruleset below.  The macros available for the string fields are;
  168. X.DS CB
  169. X.TS
  170. Xl l.
  171. X     Macro       Meaning
  172. X
  173. X      %d       day of the month
  174. X      %D       day of the week (0-6)
  175. X      %h       hour of the day (0-23)
  176. X      %m       month of the year (0-11)
  177. X      %r       return address of message
  178. X      %s       subject of original message
  179. X      %S       ``Re: \fIsubject of original message\fR''
  180. X      %t       current hour and minute in HH:MM format
  181. X      %y       year (last two digits)
  182. X.TE
  183. X.DE
  184. X.sp
  185. XThe rules file can also contain comments (any line starting with a `#')
  186. Xand blank lines.  
  187. X.sp 
  188. XThe file itself needs to reside in your home directory and be 
  189. Xcalled \fI.filter-rules\fR.  Here's an example;
  190. X.nf
  191. X
  192. X    #  $HOME/.filter-rules
  193. X    #
  194. X    #  Filter  rules  for  the  Elm  Filter  program.  Don't  change  without  some
  195. X    #  serious  thought.  (remember  -  order  counts)
  196. X    #
  197. X    #     Dave  Taylor
  198. X   
  199. X    #  rule  1
  200. X    if  (from  contains  "!uucp")  then  delete
  201. X
  202. X    #  rule  2
  203. X    to   "postmaster"   ?   save  "/tmp/postmaster-mail.%d"
  204. X
  205. X    #  rule  3
  206. X    if  (to  "culture"  and  lines  >  20)  ?   save  "/users/taylor/Mail/culture"
  207. X
  208. X    #  rule  4
  209. X    subject  =  "filter test"   ?   forward  "hpldat!taylor"
  210. X
  211. X    #  rule  5
  212. X    if  [  subject  =  "elm"  ]   savecopy  "/users/taylor/Mail/elm-incoming"
  213. X
  214. X    #  rule  6
  215. X    subject  =  "display-to-console" ?  execute "cat - > /dev/console"
  216. X
  217. X.fi
  218. X(notice the loose syntax - there are lots of valid ways to specify a
  219. Xrule in the \fIfilter\fR program!!)
  220. X.sp
  221. XTo translate these into English;
  222. X.sp
  223. X.AL
  224. X.LI
  225. XAll messages from uucp should be summarily deleted.
  226. X.LI
  227. XAll mail to postmaster should be saved in a folder (file) called 
  228. X/tmp/posmaster-mail.\fInumeric-day-of-the-week\fR
  229. X.LI
  230. XAll mail addressed to `culture' with at least 20 lines
  231. X should be automatically appended to the folder
  232. X/users/taylor/Mail/culture.
  233. X.LI
  234. XAll messages that contain the subject `filter test' should be forwarded to
  235. Xme, but via the address `hpldat!taylor' (to force a non-user forward)
  236. X.LI
  237. XAll messages with a subject that contains the word `elm' should be saved in
  238. Xthe folder ``/users/taylor/Mail/elm-incoming'' and also dropped into my
  239. Xmailbox.
  240. X.LI
  241. XAny message with the subject ``display-to-console'' will be immediately
  242. Xwritten to the console.
  243. X.LE
  244. X.sp
  245. XNotice that the \fIorder\fR of the rules is very important.  If we, for 
  246. Xexample, were to get a message from `uucp' that had the subject `filter test',
  247. Xthe \fIfilter\fR program would match rule 1 and delete the message.  It 
  248. Xwould never be forwarded to `hpldat!taylor'.  It is for this reason that
  249. Xgreat care should be taken with the ordering of the rules.
  250. X.sp
  251. X.ps 12
  252. X\fBChecking the rules out\fR
  253. X.ps 10
  254. X.sp
  255. XThe \fIfilter\fR program has a convenient way of check out the rules you 
  256. Xhave written.  Simply invoke it with the \fB-r\fR (\fBr\fRules) flag;
  257. X.nf
  258. X
  259. X    % \fBfilter -r\fR
  260. X
  261. X    Rule 1: if (from = "!uucp") then
  262. X              Delete 
  263. X
  264. X    Rule 2: if (to = "postmaster") then
  265. X              Save  /tmp/postmaster-mail.2
  266. X
  267. X    Rule 3: if (to = "culture" and lines > 20) then
  268. X              Save  /users/taylor/Mail/culture
  269. X
  270. X    Rule 4: if (subject = "filter test") then
  271. X            Forward  hpldat!taylor
  272. X
  273. X    Rule 5: if (subject="elm") then
  274. X              Copy  and  Save  /users/taylor/Mail/elm-incoming
  275. X
  276. X    Rule 6: if (subject="display-to-console") then
  277. X          Execute "cat - > /dev/console"
  278. X
  279. X.fi
  280. XThere are a few things to notice - first off, these are the parsed and
  281. Xrebuilt rules, so we can see that they are all in a 
  282. Xconsistent format.  Also, notice on the filename for rule 2 that the
  283. Xprogram has correctly expanded the ``%d'' macro to be the day of the 
  284. Xmonth.
  285. X.sp 2
  286. XIt is \fBhighly\fR recommended that you always check your ruleset before
  287. Xactually letting the program use it!
  288. X.sp
  289. X.ps 12
  290. X\fBActually Using the Program\fR
  291. X.ps 10
  292. X.sp
  293. XNow the bad news.  If you aren't running \fIsendmail\fR you cannot use
  294. Xthis program as currently written.  Why?  Because the \fIfilter\fR
  295. Xprogram expects to be put in your \fI.forward\fR file and that is something
  296. Xthat only \fIsendmail\fR looks at!
  297. X.sp
  298. XThe format for the entry in the \fI.forward\fR file (located in your
  299. Xhome directory) is simply;
  300. X.nf
  301. X
  302. X    "|filter"
  303. X
  304. X.fi
  305. XAlright, it isn't quite \fIthat\fR simple!  Since \fIfilter\fR will be invoked
  306. Xby processes that don't know where you are logged in, you need to have some
  307. Xway to trap the error messages.  For ease of use, it was decided to have all
  308. Xthe messages written to \fIstderr\fR which means that you have two main
  309. Xchoices for the actual entry.  Either;
  310. X.nf
  311. X
  312. X    "|filter  >  /dev/console  2>&1"
  313. X
  314. X.fi
  315. Xwhich will log all errors on the system console (each error is prefixed with
  316. X``filter (\fIusername\fR)'' to distinguish it), or;
  317. X.nf
  318. X
  319. X    "|filter  >>  $HOME/.filter_errors  2>&1"
  320. X
  321. X.fi
  322. XIf you want to have a copy saved to a file.  A possible strategy would be
  323. Xto have the errors written to a file and to then have a few lines in 
  324. Xyour \fI.login\fR script like;
  325. X.nf
  326. X
  327. X        if  (  -f  .filter_errors)  then
  328. X           echo  "\ \ "
  329. X           echo  "Filter  program  errors;"
  330. X           cat  .filter_errors
  331. X           echo  "\ \ "
  332. X        endif
  333. X
  334. X.fi
  335. XYou can also use the \fB-v\fR flag in combination with the above to have
  336. Xthe errors written to a file and a single line indicating messages being
  337. Xsent off or saved to folders written to the console by having 
  338. Xyour \fI.forward\fR file;
  339. X.nf
  340. X
  341. X    "|filter  -v  > /dev/console  2>>  $HOME/.filter_errors"
  342. X
  343. X.fi
  344. XSuffice to say, you can get pretty tricky with all this!!  One last point - if
  345. Xyou're interested in having it beep (for output to the screen, I would
  346. Xthink) you can use the \fB-a\fR (\fBa\fRudible) flag for any of these 
  347. Xinvocations!
  348. X.sp
  349. X.ne 5
  350. X.ps 12
  351. X\fBSummarizing the Actions Taken\fR
  352. X.ps 10
  353. X.sp
  354. XThe \fIFilter\fR program keeps a log of all actions performed, including
  355. Xwhat rules it matched against, in your home directory in a file 
  356. Xcalled \fI.filter_log\fR.  You can either directly operate on this file,
  357. Xor, much more recommended, you can one of the two summarize flags to
  358. Xthe program and let \fIit\fR do the work for you!
  359. X.sp
  360. XThe difference between the two is best demonstrated by example;
  361. X.nf
  362. X
  363. X    % \fBfilter -s\fR
  364. X
  365. X    Summary of filter activity;
  366. X
  367. X    The default rule of putting mail into your mailbox was used 18 times
  368. X
  369. X    Rule #3: (save in "/users/taylor/Mail/culture") was applied 2 times.
  370. X
  371. Xvs
  372. X
  373. X    % \fBfilter -S\fR
  374. X
  375. X    Mail from root about 
  376. X        PUT in mailbox: the default action
  377. X
  378. X    Mail from taylor about Filter Summary
  379. X        PUT in mailbox: the default action
  380. X
  381. X    Mail from hpcea!hpcesea!hpcesed!scott@hplabs.HP.COM
  382. X       about Comments and questions about elm
  383. X        PUT in mailbox: the default action
  384. X
  385. X    [etc etc]
  386. X
  387. X.fi
  388. XTo actually use either of the summarizing options, there 
  389. Xare two ways that are recommended;
  390. X.sp
  391. XThe preferred way is to have a line in either your \fIcrontab\fR
  392. X(ask your administrator for help with this) that invokes the \fIfilter\fR
  393. Xprogram as often as you desire with the \fB-s\fR flag.  For example, I
  394. Xhave a summary mailed to me every morning at 8:00 am;
  395. X.nf
  396. X
  397. X    0   8   *   *   *   "/usr/local/bin/filter  -s  |  elm  -s  'Filter  Summary'  taylor"
  398. X
  399. X.fi
  400. X.sp
  401. XAn alternative is to have your \fI.login\fR execute the command each time.
  402. X.sp 2
  403. XNote that if you want to have your log files cleared out each time the 
  404. Xsummary is generated you'll need to use the '-c' flag too.  Also,
  405. Xif you want to keep a long list of actions performed you can do this
  406. Xby saving it as you display it.  A way to do this would be, if you were to
  407. Xhave the invocation in your \fI.login\fR script, to use;
  408. X.nf
  409. X
  410. X    echo  "Filter  Log;"
  411. X    filter  -c  -s  |  tee  -a  PERM.filter.log
  412. X
  413. X.fi
  414. Xwhich would append a copy of all the output to the file `PERM.filter.log'
  415. Xand would avoid you having to read larger and larger summaries of
  416. Xwhat the program had done.
  417. X.sp
  418. X.ne 5
  419. X.ps 12
  420. X\fBFurther Testing of the Ruleset\fR
  421. X.ps 10
  422. X.sp
  423. XWith the \fIreadmsg\fR command available, it is quite easy to test the
  424. Xrules you've written to see if they'll do what you desire.  
  425. X.sp
  426. XFor example, we can use the \fB-n\fR flag to \fIfilter\fR, which means
  427. X`don't actually do this, just tell me what rule you matched, if any, and
  428. Xwhat action you would have performed' (you can see why a single letter 
  429. Xflag is easier to type in!!), and feed it each message in our mailbox 
  430. Xby using a command like;
  431. X.nf
  432. X
  433. X    % \fBset message=1\fR
  434. X    % \fBset total_messages=`messages`\fR
  435. X
  436. X    % \fBwhile  (1)\fR
  437. X    > \fBif ($message > $total_messages) exit\fR
  438. X    > \fBecho processing message $message\fR
  439. X    > \fBreadmsg -h $message | filter -n\fR
  440. X    > \fBecho " "\fR
  441. X    > \fB@ messages++\fR
  442. X    > \fBend\fR
  443. X
  444. X.fi
  445. Xwhich will then hand each of the messages in your mailbox to the \fIfilter\fR
  446. Xprogram and display what action would have been taken with that message and
  447. Xwhy.
  448. X.sp
  449. XFor example, if we do this for a few interesting messages in my mailbox,
  450. Xwe'd end up with output like;
  451. X.nf
  452. X
  453. X       Mail from taylor about filter test
  454. X         FORWARDED to hpldat!taylor by rule;
  455. X            subject="filter test"  ? forward "hpldat!taylor"
  456. X
  457. X       Mail from bradley%hplkab@hplabsc about Re:  AI-ED mailing address for HP
  458. X         PUT in mailbox: the default action
  459. X
  460. X       Mail from taylor about display-to-console
  461. X         EXECUTED "cat - > /dev/console"
  462. X
  463. X.fi
  464. X(sharp users will notice that this is exactly the same format as the longer
  465. Xsummary listing!!)
  466. X.sp 
  467. X.ps 12
  468. X\fBWhat Forwarded Messages Look Like\fR
  469. X.ps 10
  470. X.sp
  471. XWhen a message is forwarded to another user by the \fIaction\fR being specified
  472. Xas ``forward \fIaddress\fR'', then the program can generate one of two styles
  473. Xof message.  If the message is to you, then it'll simply add it to your mailbox
  474. Xin such a way as to ensure that the return address is that of the person who
  475. Xsent the message and so on.
  476. X.sp
  477. XIf not, then the message is enclosed in a message of the form;
  478. X.nf
  479. X
  480. X   From taylor Thu Oct  2 15:07:04 1986
  481. X   Date: Thu, 2 Oct 86 15:06:58 pdt
  482. X   Subject: "filter test"
  483. X   From: The filter of taylor@hpldat <taylor>
  484. X   To: hpldat!taylor
  485. X   X-Filtered-By: filter, version 1.4
  486. X
  487. X   -- Begin filtered message --
  488. X   
  489. X       From taylor Thu Oct  2 15:06:41 1986
  490. X       Date: Thu, 2 Oct 86 15:06:33 pdt
  491. X       From: Dave Taylor <taylor>
  492. X       Subject: filter test
  493. X       Just a simple test.
  494. X   -- End of filtered message --
  495. X
  496. X.fi
  497. XThe subject of the actual message is the same as the subject of the 
  498. Xmessage being forwarded, but in quotes.  The `From:'  field indicates
  499. Xhow the message was sent, and the `X-Filtered-By:' identifies what
  500. Xversion of filter is being used.
  501. X.sp
  502. X.ps 12
  503. X\fBAreas to Improve\fR
  504. X.ps 10
  505. X.sp
  506. XWhile the \fIfilter\fR program as presented herein is obviously a
  507. Xnice addition to the set of tools available for dealing with electronic
  508. Xmail, there are some key features that are missing and will be added in
  509. Xthe future based on demand.
  510. X.sp
  511. XAs I see it, the main things missing are;
  512. X.AL
  513. X.LI
  514. XThe ability to use regular expressions in the patterns.  
  515. XThis would be a \fIvery\fR nice feature!
  516. X.LI
  517. XPerhaps more \fIactions\fR available (but what?)
  518. X.LI
  519. XCertainly the ability to filter based on any field or combination of
  520. Xfields.  
  521. X.LE
  522. X.sp 2
  523. X.ps 12
  524. X\fBWarnings and Things to Look Out For\fR
  525. X.ps 10
  526. X.sp
  527. XSince this is a pretty simple program, there are a few pitfalls, some
  528. Xof which have already been mentioned;
  529. X.sp
  530. X\fBOrder\fR counts in the rules.  Beware!
  531. X.sp
  532. X\fBMatching\fR is pretty simple - make sure your patterns are sufficiently
  533. Xexclusive before having any destructive rules.
  534. X.sp 2
  535. XFinally, as with the rest of the \fBElm\fR mail system, I welcome feedback
  536. Xand suggestion on how to improve this program!!
  537. END_OF_doc/Filter.guide
  538. if test 15096 -ne `wc -c <doc/Filter.guide`; then
  539.     echo shar: \"doc/Filter.guide\" unpacked with wrong size!?
  540. fi
  541. # end of overwriting check
  542. fi
  543. echo shar: Extracting \"src/newmbox.c\" \(14549 characters\)
  544. if test -f src/newmbox.c ; then 
  545.   echo shar: Will not over-write existing file \"src/newmbox.c\"
  546. else
  547. sed "s/^X//" >src/newmbox.c <<'END_OF_src/newmbox.c'
  548. X/**            newmbox.c            **/
  549. X
  550. X/**  read new mailbox file, (C) Copyright 1986 by Dave Taylor  **/
  551. X
  552. X#include <ctype.h>
  553. X
  554. X#ifdef BSD
  555. X#undef tolower        /* we have our own "tolower" routine instead! */
  556. X#endif
  557. X
  558. X#include "headers.h"
  559. X
  560. X#include <sys/types.h>        
  561. X#include <sys/stat.h>
  562. X#include <errno.h>
  563. X
  564. X#ifdef BSD            /* Berkeley has library elsewhere... */
  565. X#  ifndef BSD4.1
  566. X#    include <sys/time.h>
  567. X#  else
  568. X#    include <time.h>
  569. X#  endif
  570. X#else
  571. X#  include <time.h>
  572. X#endif
  573. X
  574. Xextern int errno;
  575. X
  576. Xchar *error_name(), *error_description(), *strcpy(), *strncpy();
  577. Xunsigned long sleep();
  578. Xvoid rewind();
  579. Xvoid  exit();
  580. X
  581. Xstruct header_rec *realloc();
  582. X
  583. Xint
  584. Xnewmbox(stat, resync, main_screen)
  585. Xint stat, resync, main_screen;
  586. X{
  587. X    /** Read a new mailbox file or resync on current file.
  588. X
  589. X        Values of stat and what they mean;
  590. X
  591. X        stat = 0    - changing mailboxes from within program
  592. X        stat = 1    - read default mailbox or infile for the 
  593. X                      first time
  594. X            stat = 2    - read existing mailbox, new mail arrived
  595. X
  596. X        resync is TRUE iff we know the current mailbox has changed.  If
  597. X        it's set to true this means that we MUST READ SOMETHING, even 
  598. X        if it's the current mailbox again!!
  599. X
  600. X        main_screen simply tells where the counting line should be.
  601. X
  602. X    **/
  603. X
  604. X    int  switching_to_default = 0, switching_from_default = 0;
  605. X    int  iterations = 0, redraw = 0; /* for dealing with the '?' answer */
  606. X    char buff[SLEN];
  607. X
  608. X    if (mbox_specified == 0 && stat == 0)
  609. X      switching_from_default++;
  610. X
  611. X    if (stat > 0) {
  612. X      if (stat == 1 && strlen(infile) == 0) {
  613. X
  614. X        /* Subtlety - check to see if there's another instantiation
  615. X           of Elm (e.g. if the /tmp file is in use).  If so, DIE! */
  616. X
  617. X        sprintf(infile, "%s%s", temp_mbox, username);
  618. X        if (access(infile, ACCESS_EXISTS) != -1) {
  619. X          error(
  620. X        "Hey!  An instantiation of Elm is already reading this mail!\n\r");
  621. X          fprintf(stderr,
  622. X"\n\r     [if this is in error then you'll need to remove '/tmp/mbox.%s']\n\r", 
  623. X          username);
  624. X              exit(1);
  625. X            }
  626. X            sprintf(infile, "%s%s", mailhome, username);
  627. X      }
  628. X      if (strlen(infile) == 0)    /* no filename yet?? */
  629. X        sprintf(infile,"%s%s",mailhome, username);
  630. X      if ((errno = can_access(infile, READ_ACCESS))) {
  631. X        if (strncmp(infile, mailhome, strlen(mailhome)) == 0) {
  632. X          /* oh wow.  incoming mailbox with no messages... */
  633. X          return(1);
  634. X        }
  635. X        error2("Can't open mailbox '%s' for reading [%s]", infile,
  636. X            error_name(errno));
  637. X        exit(1);
  638. X      }
  639. X    }
  640. X    else {              /* get name of new mailbox! */
  641. X      MoveCursor(LINES-3, 30);
  642. X      CleartoEOS();
  643. X      PutLine0(LINES-3, 40, "(Use '?' to list your folders)");
  644. X      show_last_error();
  645. Xask_again:
  646. X      buff[0] = '\0';
  647. X      if (iterations++ == 0) {
  648. X        PutLine0(LINES-2,0,"Name of new mailbox: ");
  649. X        (void) optionally_enter(buff, LINES-2, 21, FALSE);
  650. X        ClearLine(LINES-2);
  651. X      }
  652. X      else {
  653. X        printf("\n\rName of new mailbox: ");
  654. X        (void) optionally_enter(buff, -1, -1, FALSE);
  655. X      }
  656. X      if (strlen(buff) == 0) {
  657. X        if (resync && file_changed)
  658. X          strcpy(buff, infile);
  659. X        else
  660. X          return(redraw);
  661. X      }
  662. X      if (strcmp(buff, "?") == 0) {
  663. X        redraw = 1;        /* we'll need to clean the screen */
  664. X        dprint0(1,"***  setting redraw to 1 ***\n");
  665. X        list_folders();
  666. X        goto ask_again;
  667. X      }
  668. X      if (strcmp(buff, "!") == 0 ||
  669. X           strcmp(buff, "%") == 0)     /* go to mailbox */
  670. X        sprintf(buff,"%s%s", mailhome, username);
  671. X      else if (! expand_filename(buff)) {
  672. X        error1("can't expand file %s", buff);
  673. X        if (resync && file_changed)
  674. X          strcpy(buff, infile);
  675. X        else
  676. X          return(FALSE);    
  677. X      }
  678. X
  679. X      if (strcmp(buff, infile) == 0 && ! resync) { 
  680. X        dprint0(3,"User requested change to current mailbox! (newmbox)\n");
  681. X        error("already reading that mailbox!");
  682. X        return(FALSE);
  683. X      }
  684. X
  685. X      if ((errno = can_access(buff, READ_ACCESS))) {
  686. X        dprint2(2,"Error: attempt to open %s as mailbox denied (%s)!\n",
  687. X             buff, "newmbox");
  688. X        error1("Permission to open file %s denied", buff);
  689. X        if (resync && file_changed)
  690. X          strcpy(buff, infile);
  691. X        else
  692. X          return(FALSE);    
  693. X      }
  694. X
  695. X      if (first_word(buff, mailhome)) {    /* a mail file! */
  696. X        mbox_specified = 0;       /* fake program to think that */
  697. X        stat = 1;                  /*     we're the default file */
  698. X        switching_to_default++;      /*        remember this act!  */
  699. X      }
  700. X
  701. X      if (resync && file_changed && strcmp(buff, infile) == 0)
  702. X        PutLine0(LINES-3,COLUMNS-40,"Resynchronizing file");
  703. X      else
  704. X        PutLine1(LINES-3,COLUMNS-40,"Mailbox: %s", buff);
  705. X      CleartoEOLN();
  706. X      strcpy(infile,buff);
  707. X      if (! switching_to_default) mbox_specified = 1;
  708. X    
  709. X    }
  710. X
  711. X    if (switching_from_default) {    /* we need to remove the tmp file */
  712. X        sprintf(buff, "%s%s", temp_mbox, username);
  713. X        if (unlink(buff) != 0) {
  714. X          error1(
  715. X        "Sorry, but I can't seem to unlink your temp mail file [%s]\n\r",
  716. X        error_name(errno));
  717. X              silently_exit();
  718. X        }
  719. X    }
  720. X
  721. X    clear_error();
  722. X    clear_central_message();
  723. X
  724. X    header_page = 0;
  725. X
  726. X    if (mailfile != NULL)
  727. X      (void) fclose(mailfile);  /* close it first, to avoid too many open */
  728. X
  729. X    if ((mailfile = fopen(infile,"r")) == NULL) 
  730. X      message_count = 0;
  731. X    else if (stat < 2) {          /* new mail file! */
  732. X      current = 1;
  733. X      message_count = read_headers(FALSE, main_screen);
  734. X      if (! message_count) current = 0;
  735. X    }
  736. X    else     /* resync with current mail file */
  737. X      message_count = read_headers(TRUE, main_screen);
  738. X
  739. X    if (stat < 2)
  740. X      selected = 0;    /* we don't preselect new mailboxes, boss! */
  741. X
  742. X    return(TRUE);
  743. X}
  744. X
  745. Xint
  746. Xread_headers(rereading, main_screen)
  747. Xint rereading, main_screen;
  748. X{
  749. X    /** Reads the headers into the header_table structure and leaves
  750. X        the file rewound for further I/O requests.   If the file being
  751. X        read is the default mailbox (ie incoming) then it is copied to
  752. X        a temp file and closed, to allow more mail to arrive during 
  753. X        the elm session.  If 'rereading' is set, the program will copy
  754. X        the status flags from the previous data structure to the new 
  755. X        one if possible.  This is (obviously) for re-reading a mailfile!
  756. X    **/
  757. X
  758. X    FILE *temp;
  759. X    struct header_rec *temp_struct;
  760. X    char buffer[LONG_STRING], temp_filename[SLEN];
  761. X    long bytes = 0L, line_bytes = 0L;
  762. X    register int line = 0, count = 0, subj = 0, copyit = 0, in_header = 1;
  763. X    int count_x, count_y = 17, new_messages = 0, err;
  764. X    int in_to_list = FALSE, forwarding_mail = FALSE;
  765. X
  766. X    static int first_read = 0;
  767. X
  768. X    if (! first_read++) {
  769. X      ClearLine(LINES-1);
  770. X      ClearLine(LINES);
  771. X      if (rereading)
  772. X        PutLine2(LINES, 0, "Reading in %s, message: %d", infile, 
  773. X             message_count);
  774. X      else
  775. X        PutLine1(LINES, 0, "Reading in %s, message: 0", infile);
  776. X      count_x = LINES;
  777. X          count_y = 22 + strlen(infile);
  778. X    }
  779. X    else {
  780. X      count_x = LINES-2;
  781. X      if (main_screen)
  782. X        PutLine0(LINES-2, 0, "Reading message: 0");
  783. X      else {
  784. X        PutLine0(LINES, 0, "\n");
  785. X        PutLine0(LINES, 0, "Reading message: 0");
  786. X        count_x = LINES;
  787. X      }
  788. X    }
  789. X
  790. X    if (mbox_specified == 0) {
  791. X      lock(INCOMING);    /* ensure no mail arrives while we do this! */
  792. X      sprintf(temp_filename,"%s%s",temp_mbox, username);
  793. X      if (! rereading) {
  794. X        if (access(temp_filename, ACCESS_EXISTS) != -1) {
  795. X          /* Hey!  What the hell is this?  The temp file already exists? */
  796. X          /* Looks like a potential clash of processes on the same file! */
  797. X          unlock();                     /* so remove lock file! */
  798. X          error("What's this?  The temp mailbox already exists??");
  799. X          sleep(2);
  800. X          error("Ahhhh.....I give up");
  801. X          silently_exit();    /* leave without tampering with it! */
  802. X        }
  803. X        if ((temp = fopen(temp_filename,"w")) == NULL) {
  804. X         err = errno;
  805. X         unlock();    /* remove lock file! */
  806. X         Raw(OFF);
  807. X         Write_to_screen(
  808. X             "\nCouldn't open file %s for use as temp mailbox;\n", 1,
  809. X                 temp_filename);
  810. X         Write_to_screen("** %s - %s **\n", 2,
  811. X             error_name(err), error_description(err));
  812. X         dprint3(1,
  813. X                "Error: Couldn't open file %s as temp mbox.  errno %s (%s)\n",
  814. X             temp_filename, error_name(err), "read_headers");
  815. X         leave();
  816. X        }
  817. X       get_mailtime();
  818. X       copyit++;
  819. X       chown(temp_filename, userid, groupid);
  820. X       chmod(temp_filename, 0700);    /* shut off file for other people! */
  821. X     }
  822. X     else {
  823. X       if ((temp = fopen(temp_filename,"a")) == NULL) {
  824. X         err = errno;
  825. X         unlock();    /* remove lock file! */
  826. X         Raw(OFF);
  827. X         Write_to_screen(
  828. X             "\nCouldn't reopen file %s for use as temp mailbox;\n", 1,
  829. X                 temp_filename);
  830. X         Write_to_screen("** %s - %s **\n", 2,
  831. X             error_name(err), error_description(err));
  832. X         dprint3(1,
  833. X                "Error: Couldn't reopen file %s as temp mbox.  errno %s (%s)\n",
  834. X             temp_filename, error_name(err), "read_headers");
  835. X         emergency_exit();
  836. X        }
  837. X       copyit++;
  838. X      }
  839. X    }
  840. X
  841. X    if (rereading) {
  842. X       if (fseek(mailfile, mailfile_size, 0)) {
  843. X         err = errno;
  844. X         Write_to_screen(
  845. X        "\nCouldn't seek to %ld (end of mailbox) in %s!\n", 2,
  846. X             mailfile_size, infile);    
  847. X         Write_to_screen("** %s - %s **\n", 2,
  848. X             error_name(err), error_description(err));
  849. X         dprint4(1,
  850. X     "Error: Couldn't seek to end of mailbox %s: (offset %ld) Errno %s (%s)\n",
  851. X            infile, mailfile_size, error_name(err), "read_headers");
  852. X         emergency_exit();
  853. X       }
  854. X       count = message_count;        /* next available  */
  855. X       bytes = mailfile_size;        /* start correctly */
  856. X       if (message_count > 0)
  857. X         line = header_table[message_count - 1].lines;
  858. X       else
  859. X         line = 0;
  860. X    }
  861. X
  862. X    while (fgets(buffer, LONG_STRING, mailfile) != NULL) {
  863. X
  864. X      if (bytes == 0L) {     /* first line of file... */    
  865. X        if (! mbox_specified) {
  866. X          if (first_word(buffer, "Forward to ")) {
  867. X            set_central_message("Mail being forwarded to %s", 
  868. X                   (char *) (buffer + 11));
  869. X            forwarding_mail = TRUE;
  870. X          }
  871. X        }
  872. X        if (! first_word(buffer, "From ") && !forwarding_mail) {
  873. X            PutLine0(LINES, 0, 
  874. X          "\n\rMail file is corrupt!!  I can't read it!!\n\r\n\r");
  875. X        fflush(stderr);
  876. X        dprint0(1, "\n\n**** First mail header is corrupt!! ****\n\n");
  877. X        dprint1(1, "Line is;\n\t%s\n\n", buffer);
  878. X            mail_only++;    /* to avoid leave() cursor motion */
  879. X            leave();
  880. X        }
  881. X      }
  882. X
  883. X      if (copyit) fputs(buffer, temp);
  884. X      line_bytes = (long) strlen(buffer); 
  885. X      line++;
  886. X      if (first_word(buffer,"From ")) {
  887. X    
  888. X        /** try to allocate new headers, if needed... **/
  889. X
  890. X        if (count >= max_headers) {
  891. X          max_headers += KLICK;
  892. X          dprint2(3,
  893. X          "\n\nAbout to allocate headers, count = %d, max_headers=%d\n",
  894. X          count, max_headers);
  895. X          if ((temp_struct = realloc(header_table, max_headers * 
  896. X           sizeof(struct header_rec))) == NULL) {
  897. X            error1(
  898. X      "\n\r\n\rCouldn't allocate enough memory!  Failed on message #%d\n\r\n\r",
  899. X            count);
  900. X            leave();
  901. X           }
  902. X           header_table = temp_struct;
  903. X           dprint1(7,"\tallocated %d more headers!\n\n", KLICK);
  904. X         }
  905. X          
  906. X        if (real_from(buffer, &header_table[count])) {
  907. X          header_table[count].offset = (long) bytes;
  908. X          header_table[count].index_number = count+1;
  909. X          if (! rereading || count > message_count) 
  910. X            header_table[count].status = VISIBLE;     /* default status! */
  911. X          strcpy(header_table[count].subject, "");    /* clear subj    */
  912. X          header_table[count-1].lines = line;
  913. X          if (new_msg(header_table[count])) {
  914. X            header_table[count].status |= NEW;    /* new message!  */
  915. X
  916. X            if (! new_messages++ && point_to_new && ! rereading &&
  917. X                sortby == RECEIVED_DATE) {
  918. X          current = count+1;
  919. X              get_page(current);    /* make sure we're ON that page! */
  920. X            }
  921. X
  922. X        /* Quick comment on that last conditional test...
  923. X
  924. X           We want to move the current pointer to the first new
  925. X           message IF this is the first of the new messages, the
  926. X           user requested this feature, we're not rereading the 
  927. X           mailbox (imagine how THAT could screw the user up!),
  928. X           and we're not in some funky sorting mode (received-date is
  929. X           the default).  As always, I'm open to suggestions on
  930. X           other ways to have this work intelligently.
  931. X        */
  932. X    
  933. X          }
  934. X          count++;
  935. X          subj = 0;
  936. X          line = 0;
  937. X          in_header = 1;
  938. X          PutLine1(count_x, count_y, "%d", count);
  939. X        }
  940. X      }
  941. X      else if (in_header) {
  942. X        if (first_word(buffer,">From")) 
  943. X          forwarded(buffer, &header_table[count-1]); /* return address */
  944. X        else if (first_word(buffer,"Subject:") ||
  945. X             first_word(buffer,"Subj:") ||
  946. X             first_word(buffer,"Re:")) {
  947. X          if (! subj++) {
  948. X            remove_first_word(buffer);
  949. X            strncpy(header_table[count-1].subject, buffer, STRING);
  950. X          }
  951. X        }
  952. X        else if (first_word(buffer,"From:"))
  953. X          parse_arpa_from(buffer, header_table[count-1].from);
  954. X        
  955. X        /** when it was sent... **/
  956. X
  957. X        else if (first_word(buffer, "Date:")) 
  958. X          parse_arpa_date(buffer, &header_table[count-1]);
  959. X
  960. X        /** some status things about the message... **/
  961. X
  962. X        else if (first_word(buffer, "Priority:"))
  963. X          header_table[count-1].status |= PRIORITY;
  964. X        else if (first_word(buffer, "Content-Type: mailform"))
  965. X          header_table[count-1].status |= FORM_LETTER;
  966. X        else if (first_word(buffer, "Action:"))
  967. X          header_table[count-1].status |= ACTION;
  968. X
  969. X        /** next let's see if it's to us or not... **/
  970. X
  971. X        else if (first_word(buffer, "To:")) {
  972. X          in_to_list = TRUE;
  973. X          header_table[count-1].to[0] = '\0';    /* nothing yet */
  974. X          figure_out_addressee((char *) buffer +3, 
  975. X                   header_table[count-1].to);
  976. X        }
  977. X
  978. X        else if (buffer[0] == LINE_FEED || buffer[0] == '\0') {
  979. X          if (in_header) {
  980. X            in_header = 0;    /* in body of message! */
  981. X            fix_date(&header_table[count-1]);
  982. X          }
  983. X        }
  984. X        else if (in_to_list == TRUE) {
  985. X          if (whitespace(buffer[0]))
  986. X            figure_out_addressee(buffer, header_table[count-1].to);
  987. X          else in_to_list = FALSE;
  988. X        }
  989. X      }
  990. X      bytes += (long) line_bytes;
  991. X    }
  992. X
  993. X    header_table[count > 0? count-1:count].lines = line + 1;
  994. X    
  995. X    if (mbox_specified == 0) {
  996. X      unlock();    /* remove lock file! */
  997. X      fclose(mailfile);
  998. X      fclose(temp);
  999. X      if ((mailfile = fopen(temp_filename,"r")) == NULL) {
  1000. X        err = errno;
  1001. X        MoveCursor(LINES,0);
  1002. X        Raw(OFF);
  1003. X        Write_to_screen("\nAugh! Couldn't reopen %s as temp mail file;\n",
  1004. X               1, temp_filename);
  1005. X        Write_to_screen("** %s - %s **\n", 2, error_name(err),
  1006. X           error_description(err));
  1007. X        dprint3(1,
  1008. X          "Error: Reopening %s as temp mail file failed!  errno %s (%s)\n",
  1009. X               temp_filename, error_name(errno), "read_headers");
  1010. X        leave();
  1011. X      }
  1012. X    }
  1013. X    else 
  1014. X          rewind(mailfile);
  1015. X
  1016. X    sort_mailbox(count, 1);             /* let's sort this baby now! */
  1017. X
  1018. X    return(count);
  1019. X}
  1020. END_OF_src/newmbox.c
  1021. if test 14549 -ne `wc -c <src/newmbox.c`; then
  1022.     echo shar: \"src/newmbox.c\" unpacked with wrong size!?
  1023. fi
  1024. # end of overwriting check
  1025. fi
  1026. echo shar: Extracting \"src/reply.c\" \(14009 characters\)
  1027. if test -f src/reply.c ; then 
  1028.   echo shar: Will not over-write existing file \"src/reply.c\"
  1029. else
  1030. sed "s/^X//" >src/reply.c <<'END_OF_src/reply.c'
  1031. X/**        reply.c        **/
  1032. X
  1033. X/*** routine allows replying to the sender of the current message 
  1034. X
  1035. X     (C) Copyright 1985, Dave Taylor
  1036. X***/
  1037. X
  1038. X#include "headers.h"
  1039. X#include <errno.h>
  1040. X
  1041. X#ifndef BSD
  1042. X#  include <sys/types.h>
  1043. X#  include <sys/utsname.h>
  1044. X#endif
  1045. X
  1046. X/** Note that this routine generates automatic header information
  1047. X    for the subject and (obviously) to lines, but that these can
  1048. X    be altered while in the editor composing the reply message! 
  1049. X**/
  1050. X
  1051. Xchar *strip_parens(), *get_token();
  1052. X
  1053. Xextern int errno;
  1054. X
  1055. Xchar *error_name(), *strcat(), *strcpy();
  1056. X
  1057. Xint
  1058. Xreply()
  1059. X{
  1060. X    /** Reply to the current message.  Returns non-zero iff
  1061. X        the screen has to be rewritten. **/
  1062. X
  1063. X    char return_address[LONG_SLEN], subject[SLEN];
  1064. X    int  return_value, form_letter;
  1065. X
  1066. X    form_letter = (header_table[current-1].status & FORM_LETTER);
  1067. X
  1068. X    get_return(return_address);
  1069. X
  1070. X    if (first_word(header_table[current-1].from, "To:")) {
  1071. X      strcpy(subject, header_table[current-1].subject);
  1072. X      if (form_letter)
  1073. X        return_value = mail_filled_in_form(return_address, subject);
  1074. X      else
  1075. X        return_value = send(return_address, subject, TRUE, NO);
  1076. X    }
  1077. X    else if (header_table[current-1].subject[0] != '\0') {
  1078. X      if ((strncmp("Re:", header_table[current-1].subject, 3) == 0) ||
  1079. X          (strncmp("RE:", header_table[current-1].subject, 3) == 0) ||
  1080. X          (strncmp("re:", header_table[current-1].subject, 3) == 0)) 
  1081. X        strcpy(subject, header_table[current-1].subject);
  1082. X      else {
  1083. X        strcpy(subject,"Re: ");
  1084. X        strcat(subject,header_table[current-1].subject); 
  1085. X      }
  1086. X      if (form_letter)
  1087. X        return_value = mail_filled_in_form(return_address, subject);
  1088. X      else
  1089. X        return_value = send(return_address, subject, TRUE, NO);
  1090. X    }
  1091. X    else
  1092. X      if (form_letter)
  1093. X        return_value = mail_filled_in_form(return_address, 
  1094. X                        "Filled in Form");
  1095. X      else
  1096. X        return_value = send(return_address, "Re: your mail", TRUE, NO);
  1097. X
  1098. X    return(return_value);
  1099. X}
  1100. X
  1101. Xint
  1102. Xreply_to_everyone()
  1103. X{
  1104. X    /** Reply to everyone who received the current message.  
  1105. X        This includes other people in the 'To:' line and people
  1106. X        in the 'Cc:' line too.  Returns non-zero iff the screen 
  1107. X            has to be rewritten. **/
  1108. X
  1109. X    char return_address[LONG_SLEN], subject[SLEN];
  1110. X    char full_address[VERY_LONG_STRING];
  1111. X    int  return_value;
  1112. X
  1113. X    get_return(return_address);
  1114. X
  1115. X    strcpy(full_address, return_address);    /* sender gets copy */
  1116. X    
  1117. X    get_and_expand_everyone(return_address, full_address);
  1118. X
  1119. X    if (header_table[current-1].subject[0] != '\0') {
  1120. X      if ((strncmp("Re:", header_table[current-1].subject, 3) == 0) ||
  1121. X          (strncmp("RE:", header_table[current-1].subject, 3) == 0) ||
  1122. X          (strncmp("re:", header_table[current-1].subject, 3) == 0)) 
  1123. X        strcpy(subject, header_table[current-1].subject);
  1124. X      else {
  1125. X        strcpy(subject,"Re: ");
  1126. X        strcat(subject,header_table[current-1].subject); 
  1127. X      }
  1128. X      return_value = send(full_address, subject, TRUE, NO);
  1129. X    }
  1130. X    else
  1131. X      return_value = send(full_address, "Re: your mail", TRUE, NO);
  1132. X
  1133. X    return(return_value);
  1134. X
  1135. X}
  1136. X
  1137. Xint
  1138. Xforward()
  1139. X{
  1140. X    /** Forward the current message.  What this actually does is
  1141. X        to set auto_copy to true, then call 'send' to get the 
  1142. X        address and route the mail. 
  1143. X    **/
  1144. X
  1145. X    char subject[SLEN], address[VERY_LONG_STRING];
  1146. X    int  original_cc, results, edit_msg = FALSE;
  1147. X
  1148. X    original_cc = auto_copy;
  1149. X    address[0] = '\0';
  1150. X
  1151. X    if (header_table[current-1].status & FORM_LETTER)
  1152. X      PutLine0(LINES-3,COLUMNS-40,"<no editing allowed>");
  1153. X    else {
  1154. X      edit_msg = (want_to("Edit outgoing message (y/n) ? ",'y',FALSE)!='n');
  1155. X      Write_to_screen("%s", 1, edit_msg? "Yes" : "No");
  1156. X    }
  1157. X
  1158. X    auto_cc = TRUE;            /* we want a copy */
  1159. X
  1160. X    if (strlen(header_table[current-1].subject) > 0) {
  1161. X      strcpy(subject,header_table[current-1].subject); 
  1162. X      results = send(address, subject, edit_msg,
  1163. X        header_table[current-1].status & FORM_LETTER? 
  1164. X        PREFORMATTED : allow_forms);
  1165. X    }
  1166. X    else
  1167. X      results = send(address, "Forwarded Mail...", edit_msg, 
  1168. X        header_table[current-1].status & FORM_LETTER? 
  1169. X        PREFORMATTED : allow_forms);
  1170. X    
  1171. X    auto_copy = original_cc;
  1172. X
  1173. X    return(results);
  1174. X}
  1175. X
  1176. Xget_and_expand_everyone(return_address, full_address)
  1177. Xchar *return_address, *full_address;
  1178. X{
  1179. X    /** Read the current message, extracting addresses from the 'To:'
  1180. X        and 'Cc:' lines.   As each address is taken, ensure that it
  1181. X        isn't to the author of the message NOR to us.  If neither,
  1182. X        prepend with current return address and append to the 
  1183. X        'full_address' string.
  1184. X    **/
  1185. X
  1186. X    char ret_address[LONG_SLEN], buf[LONG_SLEN], new_address[LONG_SLEN],
  1187. X     address[LONG_SLEN], comment[LONG_SLEN];
  1188. X    int  in_message = 1, first_pass = 0, index;
  1189. X
  1190. X    /** First off, get to the first line of the message desired **/
  1191. X
  1192. X    if (fseek(mailfile, header_table[current-1].offset, 0) == -1) {
  1193. X    dprint3(1,"Error: seek %ld resulted in errno %s (%s)\n", 
  1194. X         header_table[current-1].offset, error_name(errno), 
  1195. X         "get_and_expand_everyone");
  1196. X    error2("ELM [seek] couldn't read %d bytes into file (%s)",
  1197. X           header_table[current-1].offset, error_name(errno));
  1198. X    return;
  1199. X    }
  1200. X    /** okay!  Now we're there!  **/
  1201. X
  1202. X    /** let's fix the ret_address to reflect the return address of this
  1203. X    message with '%s' instead of the persons login name... **/
  1204. X
  1205. X    translate_return(return_address, ret_address);
  1206. X
  1207. X    /** now let's parse the actual message! **/
  1208. X
  1209. X    while (in_message) {
  1210. X      in_message = (int) (fgets(buf, LONG_SLEN, mailfile) != NULL);
  1211. X      if (first_word(buf, "From ") && first_pass++ != 0) 
  1212. X    in_message = FALSE;
  1213. X      else if (first_word(buf, "To:") || first_word(buf, "Cc:") ||
  1214. X           first_word(buf, "CC:") || first_word(buf, "cc:")) {
  1215. X    do {
  1216. X      no_ret(buf);
  1217. X
  1218. X      /** we have a buffer with a list of addresses, each of either the
  1219. X          form "address (name)" or "name <address>".  Our mission, should
  1220. X          we decide not to be too lazy, is to break it into the two parts.
  1221. X      **/
  1222. X          
  1223. X      if (!whitespace(buf[0]))
  1224. X        index = chloc(buf, ':')+1;        /* skip header field */
  1225. X      else
  1226. X        index = 0;                /* skip whitespace   */
  1227. X
  1228. X      while (break_down_tolist(buf, &index, address, comment)) {
  1229. X
  1230. X        if (okay_address(address, return_address)) {
  1231. X          sprintf(new_address, ret_address, address);
  1232. X          optimize_and_add(new_address, full_address);
  1233. X        }
  1234. X      }
  1235. X
  1236. X          in_message = (int) (fgets(buf, LONG_SLEN, mailfile) != NULL);
  1237. X
  1238. X      if (in_message) dprint1(1,"> %s", buf);
  1239. X    
  1240. X    } while (in_message && whitespace(buf[0]));
  1241. X
  1242. X      }
  1243. X      else if (strlen(buf) < 2)    /* done with header */
  1244. X     in_message = FALSE;
  1245. X    }
  1246. X}
  1247. X
  1248. Xint
  1249. Xokay_address(address, return_address)
  1250. Xchar *address, *return_address;
  1251. X{
  1252. X    /** This routine checks to ensure that the address we just got
  1253. X        from the "To:" or "Cc:" line isn't us AND isn't the person    
  1254. X        who sent the message.  Returns true iff neither is the case **/
  1255. X
  1256. X    char our_address[SLEN];
  1257. X    struct addr_rec  *alternatives;
  1258. X
  1259. X    if (in_string(address, return_address))
  1260. X      return(FALSE);
  1261. X
  1262. X    sprintf(our_address, "%s!%s", hostname, username);
  1263. X
  1264. X    if (in_string(address, our_address))
  1265. X      return(FALSE);
  1266. X
  1267. X    sprintf(our_address, "%s@%s", username, hostname);
  1268. X      
  1269. X    if (in_string(address, our_address))
  1270. X      return(FALSE);
  1271. X
  1272. X    alternatives = alternative_addresses;
  1273. X
  1274. X    while (alternatives != NULL) {
  1275. X      if (in_string(address, alternatives->address))
  1276. X        return(FALSE);
  1277. X      alternatives = alternatives->next;
  1278. X    }
  1279. X
  1280. X    return(TRUE);
  1281. X}
  1282. X        
  1283. Xoptimize_and_add(new_address, full_address)
  1284. Xchar *new_address, *full_address;
  1285. X{
  1286. X    /** This routine will add the new address to the list of addresses
  1287. X        in the full address buffer IFF it doesn't already occur.  It
  1288. X        will also try to fix dumb hops if possible, specifically hops
  1289. X        of the form ...a!b...!a... and hops of the form a@b@b etc 
  1290. X    **/
  1291. X
  1292. X    register int len, host_count = 0, i;
  1293. X    char     hosts[MAX_HOPS][SLEN];    /* array of machine names */
  1294. X    char     *host, *addrptr;
  1295. X
  1296. X    if (in_string(full_address, new_address))
  1297. X      return(1);    /* duplicate address */
  1298. X
  1299. X    /** optimize **/
  1300. X    /*  break down into a list of machine names, checking as we go along */
  1301. X    
  1302. X    addrptr = (char *) new_address;
  1303. X
  1304. X    while ((host = get_token(addrptr, "!", 1)) != NULL) {
  1305. X      for (i = 0; i < host_count && ! equal(hosts[i], host); i++)
  1306. X          ;
  1307. X
  1308. X      if (i == host_count) {
  1309. X        strcpy(hosts[host_count++], host);
  1310. X        if (host_count == MAX_HOPS) {
  1311. X           dprint1(2,
  1312. X              "Error: hit max_hops limit trying to build return address (%s)\n",
  1313. X              "optimize_and_add");
  1314. X           error("Can't build return address - hit MAX_HOPS limit!");
  1315. X           return(1);
  1316. X        }
  1317. X      }
  1318. X      else 
  1319. X        host_count = i + 1;
  1320. X      addrptr = NULL;
  1321. X    }
  1322. X
  1323. X    /** fix the ARPA addresses, if needed **/
  1324. X    
  1325. X    if (chloc(hosts[host_count-1], '@') > -1)
  1326. X      fix_arpa_address(hosts[host_count-1]);
  1327. X      
  1328. X    /** rebuild the address.. **/
  1329. X
  1330. X    new_address[0] = '\0';
  1331. X
  1332. X    for (i = 0; i < host_count; i++)
  1333. X      sprintf(new_address, "%s%s%s", new_address, 
  1334. X              new_address[0] == '\0'? "" : "!",
  1335. X              hosts[i]);
  1336. X
  1337. X    if (full_address[0] == '\0')
  1338. X      strcpy(full_address, new_address);
  1339. X    else {
  1340. X      len = strlen(full_address);
  1341. X      full_address[len  ] = ',';
  1342. X      full_address[len+1] = ' ';
  1343. X      full_address[len+2] = '\0';
  1344. X      strcat(full_address, new_address);
  1345. X    }
  1346. X
  1347. X    return(0);
  1348. X}
  1349. X
  1350. Xget_return_name(address, name, shift_lower)
  1351. Xchar *address, *name;
  1352. Xint   shift_lower;
  1353. X{
  1354. X    /** Given the address (either a single address or a combined list 
  1355. X        of addresses) extract the login name of the first person on
  1356. X        the list and return it as 'name'.  Modified to stop at
  1357. X        any non-alphanumeric character. **/
  1358. X
  1359. X    /** An important note to remember is that it isn't vital that this
  1360. X        always returns just the login name, but rather that it always
  1361. X        returns the SAME name.  If the persons' login happens to be,
  1362. X        for example, joe.richards, then it's arguable if the name 
  1363. X        should be joe, or the full login.  It's really immaterial, as
  1364. X        indicated before, so long as we ALWAYS return the same name! **/
  1365. X
  1366. X    /** Another note: modified to return the argument as all lowercase
  1367. X        always, unless shift_lower is FALSE... **/
  1368. X
  1369. X    char single_address[LONG_SLEN];
  1370. X    register int i, loc, index = 0;
  1371. X
  1372. X    dprint2(6,"get_return_name called with (%s, <>, shift=%s)\n", 
  1373. X           address, onoff(shift_lower));
  1374. X
  1375. X    /* First step - copy address up to a comma, space, or EOLN */
  1376. X
  1377. X    for (i=0; address[i] != ',' && ! whitespace(address[i]) && 
  1378. X         address[i] != '\0'; i++)
  1379. X      single_address[i] = address[i];
  1380. X    single_address[i] = '\0';
  1381. X
  1382. X    /* Now is it an ARPA address?? */
  1383. X
  1384. X    if ((loc = chloc(single_address, '@')) != -1) {      /* Yes */
  1385. X
  1386. X      /* At this point the algorithm is to keep shifting our copy 
  1387. X         window left until we hit a '!'.  The login name is then
  1388. X             located between the '!' and the first metacharacter to 
  1389. X         it's right (ie '%', ':' or '@'). */
  1390. X
  1391. X      for (i=loc; single_address[i] != '!' && i > -1; i--)
  1392. X          if (single_address[i] == '%' || 
  1393. X              single_address[i] == ':' ||
  1394. X              single_address[i] == '.' ||    /* no domains */
  1395. X          single_address[i] == '@') loc = i-1;
  1396. X    
  1397. X      if (i < 0 || single_address[i] == '!') i++;
  1398. X
  1399. X      for (index = 0; index < loc - i + 1; index++)
  1400. X        if (shift_lower)
  1401. X          name[index] = tolower(single_address[index+i]);
  1402. X        else
  1403. X          name[index] = single_address[index+i];
  1404. X      name[index] = '\0';
  1405. X    }
  1406. X    else {    /* easier - standard USENET address */
  1407. X
  1408. X      /* This really is easier - we just cruise left from the end of
  1409. X         the string until we hit either a '!' or the beginning of X
  1410. X    while (buf[*index] != ',' && buf[*index] != '\0')
  1411. X      buffer[loc++] = buf[(*index)++];
  1412. X
  1413. X    (*index)++;
  1414. X
  1415. X    buffer[loc] = '\0';
  1416. X    while (whitespace(buffer[loc - 1]))
  1417. X        buffer[--loc] = '\0';    /* remove trailing whitespace */
  1418. X
  1419. X    buffer[loc] = '\0';
  1420. X
  1421. X    if (strlen(buffer) == 0) return(FALSE);
  1422. X
  1423. X    dprint1(5, "\n* got \"%s\"\n", buffer);
  1424. X
  1425. X    if (buffer[loc-1] == ')') {    /*   address (name)  format */
  1426. X      for (loc = 0;buffer[loc] != '(' && loc < strlen(buffer); loc++)
  1427. X        /* get to the opening comment character... */ ;
  1428. X
  1429. X      loc--;    /* back up to just before the paren */
  1430. X      while (whitespace(buffer[loc])) loc--;    /* back up */
  1431. X
  1432. X      /** get the address field... **/
  1433. X
  1434. X      for (i=0; i <= loc; i++)
  1435. X        address[i] = buffer[i];
  1436. X      address[i] = '\0';
  1437. X
  1438. X      /** now get the comment field, en toto! **/
  1439. X
  1440. X      loc = 0;
  1441. X
  1442. X      for (i = chloc(buffer, '('); i < strlen(buffer); i++)
  1443. X        comment[loc++] = buffer[i];
  1444. X      comment[loc] = '\0';
  1445. X    }
  1446. X    else if (buffer[loc-1] == '>') {    /*   name <address>  format */
  1447. X      dprint0(7, "\tcomment <address>\n");
  1448. X      for (loc = 0;buffer[loc] != '<' && loc < strlen(buffer); loc++)
  1449. X        /* get to the opening comment character... */ ;
  1450. X      while (whitespace(buffer[loc])) loc--;    /* back up */
  1451. X
  1452. X      /** get the comment field... **/
  1453. X
  1454. X      comment[0] = '(';
  1455. X      for (i=1; i < loc; i++)
  1456. X        comment[i] = buffer[i-1];
  1457. X      comment[i++] = ')';
  1458. X      comment[i] = '\0';
  1459. X
  1460. X      /** now get the address field, en toto! **/
  1461. X
  1462. X      loc = 0;
  1463. X
  1464. X      for (i = chloc(buffer,'<') + 1; i < strlen(buffer) - 1; i++)
  1465. X        address[loc++] = buffer[i];
  1466. X    
  1467. X      address[loc] = '\0';
  1468. X    }
  1469. X    else {
  1470. X      strcpy(address, buffer);
  1471. X      comment[0] = '\0';
  1472. X    }
  1473. X
  1474. X    dprint2(5,"-- returning '%s' '%s'\n", address, comment);
  1475. X
  1476. X    return(TRUE);
  1477. X}
  1478. END_OF_src/reply.c
  1479. if test 14009 -ne `wc -c <src/reply.c`; then
  1480.     echo shar: \"src/reply.c\" unpacked with wrong size!?
  1481. fi
  1482. # end of overwriting check
  1483. fi
  1484. echo shar: End of archive 14 \(of 19\).
  1485. cp /dev/null ark14isdone
  1486. DONE=true
  1487. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ; do
  1488.     if test ! -f ark${I}isdone ; then
  1489.     echo shar: You still need to run archive ${I}.
  1490.     DONE=false
  1491.     fi
  1492. done
  1493. if test "$DONE" = "true" ; then
  1494.     echo You have unpacked all 19 archives.
  1495.     echo "See the Instructions file"
  1496.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1497. fi
  1498. ##  End of shell archive.
  1499. exit 0
  1500.