home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume35 / procmail / part07 < prev    next >
Encoding:
Text File  |  1993-02-04  |  43.4 KB  |  1,244 lines

  1. Newsgroups: comp.sources.misc
  2. From: berg@pool.informatik.rwth-aachen.de (Stephen R. van den Berg)
  3. Subject: v35i028:  procmail - mail processing package v2.80, Part07/11
  4. Message-ID: <1993Feb5.020525.16689@sparky.imd.sterling.com>
  5. X-Md4-Signature: 131eae9bcc289b0d78b907312d466809
  6. Date: Fri, 5 Feb 1993 02:05:25 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: berg@pool.informatik.rwth-aachen.de (Stephen R. van den Berg)
  10. Posting-number: Volume 35, Issue 28
  11. Archive-name: procmail/part07
  12. Environment: sendmail, smail, MMDF, mailsurr, UNIX, POSIX
  13. Supersedes: procmail: Volume 31, Issue 40-44
  14.  
  15. #! /bin/sh
  16. # This is a shell archive.  Remove anything before this line, then unpack
  17. # it by saving it into a file and typing "sh file".  To overwrite existing
  18. # files, type "sh file -c".  You can also feed this as standard input via
  19. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  20. # will see the following message at the end:
  21. #        "End of archive 7 (of 11)."
  22. # Contents:  procmail280/examples/advanced procmail280/src/lockfile.c
  23. #   procmail280/src/mailfold.c procmail280/src/misc.c
  24. # Wrapped by berg@hathi on Thu Feb  4 15:27:59 1993
  25. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  26. if test -f 'procmail280/examples/advanced' -a "${1}" != "-c" ; then 
  27.   echo shar: Will not clobber existing file \"'procmail280/examples/advanced'\"
  28. else
  29. echo shar: Extracting \"'procmail280/examples/advanced'\" \(10469 characters\)
  30. sed "s/^X//" >'procmail280/examples/advanced' <<'END_OF_FILE'
  31. X
  32. XDiscusses:
  33. X        1. One home directory, several machine architectures
  34. X        2. Procmail as an integrated local mail delivery agent
  35. X        2a.Special directions for sites with sendmail
  36. X        2b.Special directions for sites with smail
  37. X        2c.Special directions for sites with SysV /etc/mail/mailsurr
  38. X        3. Changing the mail spool directory to $HOME for all users
  39. X        4. Security considerations (when installing procmail suid root)
  40. X        5. Some exorbitant examples of rcfile formats
  41. X        6. Some advanced examples of the use of the 'A' flag
  42. X
  43. X                ---
  44. X
  45. X1. One home directory, several machine architectures
  46. X   -------------------------------------------------
  47. X
  48. XFor users that have the very same home directory on machines with differing
  49. Xarchitectures (i.e. you need different executables), and they
  50. Xhave to explicitly use (i.e. the system administrator did not arrange,
  51. Xfor example, /usr/local/bin/procmail to have exactly the right contents
  52. Xdepending on from which machine it is called) two executables of procmail,
  53. XI have the following suggestion to use as a .forward file (examples are for
  54. Xsparc and sun3 architectures):
  55. X
  56. X"|IFS=' ';if /usr/bin/sparc;then exec /home/berg/bin.sun4/procmail;else exec /home/berg/bin.sun3/procmail;fi #YOUR_LOGIN_NAME"
  57. X
  58. Xor alternatively:
  59. X
  60. X"|IFS=' ';exec /home/berg/bin.`/usr/bin/arch`/procmail #YOUR_LOGIN_NAME"
  61. X
  62. XPlease note, in the .forward file there can NOT be any newlines between
  63. Xthe doublequotes, i.e. the former example *has* to be typed in as one long
  64. Xline.
  65. X
  66. XIf, on the other hand, you have to log in to every machine to read mail
  67. Xarrived for you on that machine, a different solution might be more
  68. Xappropriate; in that case put something like the following two lines in your
  69. X.forward file:
  70. X
  71. XYOUR_LOGIN_NAME@your.favourite.machine
  72. X"|IFS=' ';if test .`/bin/uname -n` = .your.favourite.machine; then /exec /home/berg/bin/procmail; else exit 0; fi #YOUR_LOGIN_NAME"
  73. X
  74. XThe leading dots are important.     Check what `/bin/uname -n` returns on
  75. Xyour.favourite.machine, and substitute that for your.favourite.machine in the
  76. Xsample .forward file.  If your system does not have /bin/uname, check if there
  77. Xis a /bin/hostname.
  78. X
  79. X                ---
  80. X
  81. X2. Procmail as an integrated local mail delivery agent
  82. X   ---------------------------------------------------
  83. X
  84. XCompletely integrating procmail in the mail delivery means that mail is
  85. Xdelivered as normal, unless a .procmailrc file is present in the home
  86. Xdirectory of the recipient.  This will be completely independent of the
  87. Xfact if a .forward file is present.  This will not break anything, it
  88. Xjust makes the use of procmail easier because people are not required to
  89. Xstart up procmail from within their .forward files.  Creation of a .procmailrc
  90. Xfile will suffice.
  91. X
  92. XThe generic way to accomplish this (works with sendmail, smail and any other
  93. Xmail system that uses a local mail delivery program that takes the mail-
  94. Xto-be-delivered on stdin and the recipient(s) on the command line, with or
  95. Xwithout the "-d" option) is this:
  96. X
  97. XMove your current local mail delivery agent (e.g. /bin/mail, /bin/lmail,
  98. X/usr/lib/mail/mail.local, etc.) out of the way, and create a (symbolic or hard)
  99. Xlink from there to procmail, as in "ln /usr/local/bin/procmail /bin/lmail".
  100. X
  101. XBeware, however, that if you are using this method, /bin/mail can *only* be
  102. Xused to deliver mail.  On many systems /bin/mail has several uses (also to
  103. Xread mail or check for mail).  So, it would definitely be preferred if you
  104. Xcould edit the invocation of /bin/mail from within your mail transport agent
  105. Xto invoke procmail instead (with appropriate flags, if needed).     Special
  106. Xdirections detailing this process for some of the more popular MTAs are
  107. Xincluded in sections (2a) and (2b) below.
  108. X
  109. XIn addition to needing root privileges upon startup, on some systems procmail
  110. Xneeds to be sgid to daemon or mail.  One way to check is by looking at the
  111. Xcurrent mail delivery agent (usually /bin/mail) and to mimic its permissions,
  112. Xowner and group.  If you're not quite sure, just type "make recommend" and some
  113. Xsuitable recommendations will be made for your particular environment.
  114. X
  115. XThe same might apply to the "lockfile" program, in order for it to be able to
  116. Xcreate and unlink lockfiles in the mail spool directory it might need to be
  117. Xsgid to daemon or mail, not to worry however, "lockfile" will not enable users
  118. Xto abuse the sgid/suid-ness.
  119. X
  120. X                ---
  121. X
  122. X2a.Special directions for sites with sendmail
  123. X   ------------------------------------------
  124. X
  125. XThe following line should take the place of the standard
  126. XMlocal rule in your sendmail.cf (this way sendmail will start up procmail with
  127. Xroot priv, procmail will immediately setuid itself to the recipient's uid):
  128. X
  129. XMlocal, P=/usr/local/bin/procmail, F=lsSDFMhP, S=10, R=20, A=procmail -d $u
  130. X
  131. XAs for the remaining flags "S=10, R=20", if your system uses others or
  132. Xnone on the current Mlocal rule, use those instead of "S=10, R=20".
  133. X
  134. X                ---
  135. X
  136. X2b.Special directions for sites with smail
  137. X   ---------------------------------------
  138. X
  139. XFor smail 2.x users there are two options:
  140. X i. Move the current local-mail-delivery program (probably /bin/lmail) out of
  141. X    the way, make a symbolic or hard link from procmail to the name of that
  142. X    program (e.g. "ln /usr/local/bin/procmail /bin/lmail")
  143. X ii.Make sure the following macro is defined in src/defs.h:
  144. X    #define LMAIL(frm,sys) "/usr/local/bin/procmail -d"
  145. X
  146. XFor smail 3.x users there are also two options:
  147. X i. The same solution as for smail 2.x (however, method ii is preferred)
  148. X ii.Replace any existing "local"-entry in the /usr/lib/smail/transports file
  149. X    (create one, if need be) with the following two lines:
  150. X
  151. Xlocal: return_path, local, from, driver=pipe; user=root,
  152. X    cmd="/usr/local/bin/procmail -d $($user$)"
  153. X
  154. X                ---
  155. X
  156. X2c.Special directions for sites with SysV /etc/mail/mailsurr
  157. X   ---------------------------------------------------------
  158. X
  159. XSome systems use a SysV /bin/mail that supports mailsurr.  To interface
  160. Xprocmail with mailsurr the following two lines should be inserted in the
  161. X/etc/mail/mailsurr file (preferably at the bottom):
  162. X
  163. X'(.+)' '([^@!]+)' '<S=0;C=67,75;F=*;
  164. X    /usr/local/bin/procmail -f \\1 -d \\2'
  165. X
  166. X                ---
  167. X
  168. X3. Changing the mail spool directory to $HOME for all users
  169. X   --------------------------------------------------------
  170. X
  171. XThere are many different reasons why more and more sites decide not to
  172. Xstore mail in /usr/spool/mail or /usr/mail anymore.
  173. XSome of the obvious advantages when storing mail in the recipient's home
  174. Xdirectory are:
  175. X    - Mail is automatically subject to his quota limitations.
  176. X    - Often there is more room on the home partitions than on that
  177. X      one /usr/mail partition.
  178. X
  179. XThe quota limitations also apply to /usr/spool/mail or /usr/mail if procmail
  180. Xdoes the delivery.  This quota limitation often does not work with the
  181. Xregular /bin/mail since it often writes the mailbox with root permissions
  182. X(eluding the quota restrictions).
  183. X
  184. XHowever, if you are going to install procmail as the integrated local
  185. Xdelivery agent, and you want mail to be delivered to, say, $HOME/.mail
  186. Xby default, this is what you have to do:
  187. X
  188. X    Edit the procmail*/config.h file.   Uncomment and possibly change
  189. X    the SYSTEM_MBOX define.     Procmail now delivers there by default.
  190. X
  191. X    In order to make sure that normal mailtools can find the new
  192. X    system mailboxes, you should make sure that every user has the
  193. X    MAIL environment variable set to be equal to whatever you
  194. X    defined SYSTEM_MBOX to be.  Some braindamaged mail programs
  195. X    do not pick up the MAIL environment variable, these either
  196. X    have to be patched/recompiled or you have to create symbolic
  197. X    links in /usr/mail to every person's new mailbox.
  198. X
  199. X                ---
  200. X
  201. X4. Security considerations (when installing procmail suid root)
  202. X   -------------------------------------------------------------
  203. X
  204. XIf in EXPLICIT DELIVERY mode (typically when called from within sendmail)
  205. Xprocmail will ALWAYS change UID and gid to the RECIPIENT's defaults as soon as
  206. Xit starts reading the recipient's $HOME/.procmailrc file.
  207. X
  208. XIf NOT in explicit delivery mode (typically when called from within the
  209. Xrecipient's $HOME/.forward file) procmail will ALWAYS change UID and gid to
  210. Xthe real uid and gid of the INVOKER (effectively losing any suid or sgid
  211. Xprivileges).
  212. X
  213. XThese two precautions should effectively eliminate any security holes because
  214. Xprocmail will always have the uid of the person whose commands it is executing.
  215. X
  216. XTo summarise, procmail will only behave better if made suid/sgid something, in
  217. Xfact, making procmail suid/sgid something will *improve* security on systems
  218. Xwhich have dynamically linked libraries.
  219. X
  220. X                ---
  221. X
  222. X5. Some exorbitant examples of rcfile formats
  223. X   ------------------------------------------
  224. X
  225. X# Now follows an example of what you can do in a procmailrc file
  226. XHELLO=oneword
  227. XHELLO="two words"
  228. XHELLO='two words'    HELLO  =    one\
  229. Xword
  230. XHELLO=two\ words
  231. XHELLO=two\ `echo words`
  232. XHELLO=            # empty
  233. XHELLO            # This will wipe "HELLO" from the environment
  234. XHELLO     =    "three words"\ yes
  235. XHELLO    =    "$HELLO `cat somefile`    "    # Trailing blanks
  236. XHELLO = "wheeee`date`${HELLO} this works too"     HELLO = 'But so does this!'
  237. X
  238. X# As you can see, every trick in the book of /bin/sh programming can be used
  239. X# (and more).
  240. X
  241. XLOCALLOCKFILE = llf
  242. X
  243. X  ::$LOCALLOCKFILE
  244. Xgrep for this
  245. X |$HELLO        # calls up a program named "But" with 3 arguments
  246. X
  247. X:: "test ing"        # lockfilename with a space in it
  248. Xgrep for this
  249. X  |$HELLO
  250. X
  251. X:
  252. Xor for this
  253. X|"$HELLO"        # tries to call up a program named "But so does this!"
  254. X
  255. X:
  256. Xand this
  257. X|$HELLO \
  258. Xthere        # action lines can be continued
  259. X
  260. X                ---
  261. X
  262. X6. Some advanced examples of the use of the 'A' flag
  263. X   -------------------------------------------------
  264. X
  265. X:c        # Specify the 'c' otherwise we never arrive at the next recipe
  266. X^From Myfriend
  267. Xevery_message_from_my_friend        # Mailbox for everything he/she writes
  268. X
  269. X:Ac            # Note the 'c' again
  270. X! my_other_friend      # Forward everything Myfriend writes to my_other_friend
  271. X
  272. X:1Ac
  273. X^Subject:.*jokes
  274. X! my_third_friend    # Forward everything Myfriend writes about jokes
  275. X            # to my_third_friend
  276. X
  277. X:2A
  278. X^Subject:.*parties
  279. X!beach
  280. X! my_fourth_friend    # Forward everything Myfriend writes about parties,
  281. X            # except beach parties, to my_fourth_friend
  282. X
  283. X:A            # Provide a mail sink, in order to fake procmail into
  284. X/dev/null        # believing that the mail was absorbed/delivered,
  285. X            # even if the mail was about beach parties :-).
  286. X        # This is not the best solution though, better would be to
  287. X        # rearrange these last five recipes so that the current
  288. X        # number one or two is last, the current number five can be
  289. X        # omitted then.
  290. X
  291. X                ---
  292. END_OF_FILE
  293. if test 10469 -ne `wc -c <'procmail280/examples/advanced'`; then
  294.     echo shar: \"'procmail280/examples/advanced'\" unpacked with wrong size!
  295. fi
  296. # end of 'procmail280/examples/advanced'
  297. fi
  298. if test -f 'procmail280/src/lockfile.c' -a "${1}" != "-c" ; then 
  299.   echo shar: Will not clobber existing file \"'procmail280/src/lockfile.c'\"
  300. else
  301. echo shar: Extracting \"'procmail280/src/lockfile.c'\" \(9425 characters\)
  302. sed "s/^X//" >'procmail280/src/lockfile.c' <<'END_OF_FILE'
  303. X/************************************************************************
  304. X *    lockfile - The conditional semaphore-file creator        *
  305. X *                                    *
  306. X *    It has been designed to be able to be run sgid mail or        *
  307. X *    any gid you see fit (in case your mail spool area is *not*    *
  308. X *    world writeable, but group writeable), without creating        *
  309. X *    security holes.                            *
  310. X *                                    *
  311. X *    Seems to be relatively bug free.                *
  312. X *                                    *
  313. X *    Copyright (c) 1990-1992, S.R. van den Berg, The Netherlands    *
  314. X *    #include "README"                        *
  315. X ************************************************************************/
  316. X#ifdef RCS
  317. Xstatic /*const*/char rcsid[]=
  318. X "$Id: lockfile.c,v 1.13 1993/01/19 18:30:36 berg Exp $";
  319. X#endif
  320. Xstatic /*const*/char rcsdate[]="$Date: 1993/01/19 18:30:36 $";
  321. X#include "includes.h"
  322. X#include "sublib.h"
  323. X#include "exopen.h"
  324. X
  325. X#ifndef SYSTEM_MBOX
  326. X#define SYSTEM_MBOX    SYSTEM_MAILBOX
  327. X#endif
  328. X
  329. Xstatic volatile exitflag;
  330. Xpid_t thepid;
  331. Xstatic char systm_mbox[]=SYSTEM_MBOX;
  332. Xstatic const char dirsep[]=DIRSEP,lockext[]=DEFlockext,
  333. X nameprefix[]="lockfile: ",lgname[]="LOGNAME",home[]="HOME";
  334. X
  335. Xstatic void failure P((void))                      /* signal trap */
  336. X{ exitflag=2;                           /* merely sets a flag */
  337. X}
  338. X                    /* see locking.c for comment on xcreat() */
  339. Xstatic xcreat(name,tim)const char*const name;time_t*const tim;
  340. X{ char*p,*q;int j= -1,i;struct stat stbuf;
  341. X  for(q=(char*)name;p=strpbrk(q,dirsep);q=p+1);
  342. X  i=q-name;
  343. X  if(!(p=malloc(i+UNIQnamelen)))
  344. X     return exitflag=1;
  345. X  strncpy(p,name,i);
  346. X  if(unique(p,p+i,0,0))
  347. X     stat(p,&stbuf),*tim=stbuf.st_mtime,j=myrename(p,name);
  348. X  free(p);return j;
  349. X}
  350. X
  351. Xvoid elog(a)const char*const a;
  352. X{ write(STDERR,a,strlen(a));
  353. X}
  354. X
  355. Xvoid nlog(a)const char*const a;
  356. X{ elog(nameprefix);elog(a);  /* decent error messages should start with this */
  357. X}
  358. X
  359. Xstatic size_t parsecopy(dest,org,pass)char*const dest;const char*org;
  360. X const struct passwd*const pass; /* try and digest the mailbox-lockfile name */
  361. X{ size_t len;const char*chp;char*p;unsigned i;
  362. X  for(p=dest,len=STRLEN(lockext)+1;;)
  363. X   { switch(*org)
  364. X      { case '$':                        /* we substitute */
  365. X       if(!strncmp(++org,lgname,STRLEN(lgname)))
  366. X          org+=STRLEN(lgname),chp=pass->pw_name;         /* $LOGNAME and */
  367. X       else if(!strncmp(org,home,STRLEN(home)))
  368. X          org+=STRLEN(home),chp=pass->pw_dir;            /* $HOME */
  369. X       else
  370. X          goto capac;                 /* no other fancy stuff */
  371. X       if((i= *org)-'a'<='z'-'a'||i-'A'<='Z'-'A'||i-'0'<='9'-'0'||i=='_')
  372. X          goto capac;
  373. X       if(p)
  374. X          p+=strlen(strcpy(p,chp));                  /* paste it in */
  375. X       len+=strlen(chp);continue;
  376. X    default:
  377. X       if(p)
  378. X          *p++= *org;              /* simply copy everything else */
  379. X       len++;org++;continue;      /* except suspicous looking characters */
  380. X    case '\'':case '`':case '"':case '\\':case '{':goto capac;
  381. X    case '\0':;
  382. X      }
  383. X     if(p)
  384. X      { if(p==dest||!strchr(dirsep,*dest))         /* absolute path wanted */
  385. Xcapac:     { nlog("Sorry, but turning this mess into a useable mailbox \
  386. Xexceeds my humble\ncapacities");return 0;
  387. X     }
  388. X    strcpy(p,lockext);
  389. X      }
  390. X     return len;
  391. X   }
  392. X}
  393. X
  394. Xstatic PROGID;
  395. X
  396. Xmain(argc,argv)const char*const argv[];
  397. X{ const char*const*p,*const*lastf;char*cp;uid_t uid;
  398. X  int sleepsec,retries,invert,force,suspend,retval=EX_OK,virgin=1;
  399. X  static const char usage[]="Usage: lockfile -nnn | -r nnn | -l nnn | -s nnn \
  400. X| -! | -ml | -mu | file ...\n";
  401. X  if(argc<=1)                   /* sanity check, any argument at all? */
  402. X     goto usg;
  403. X  sleepsec=DEFlocksleep;force=invert=(char*)progid-(char*)progid;retries= -1;
  404. X  suspend=DEFsuspend;thepid=getpid();uid=getuid();signal(SIGPIPE,SIG_IGN);
  405. Xagain:
  406. X  signal(SIGHUP,(void(*)())failure);signal(SIGINT,(void(*)())failure);
  407. X  signal(SIGQUIT,(void(*)())failure);signal(SIGTERM,(void(*)())failure);
  408. X  for(lastf=p=argv;--argc;)
  409. X     if(*(cp=(char*)*++p)=='-')
  410. X    for(cp++;;)
  411. X     { char*cp2=cp+1;int i;
  412. X       switch(*cp++)
  413. X        { case '!':invert^=1;continue;          /* invert the exitcode */
  414. X          case 'r':case 'l':case 's':
  415. X         if(!*cp&&(cp=(char*)*++p,!--argc)) /* concatenated/seperate */
  416. X            goto eusg;
  417. X         i=strtol(cp,&cp,10);
  418. X         switch(cp2[-1])
  419. X          { case 'r':retries=i;goto checkrdec;
  420. X            case 'l':force=i;goto checkrdec;
  421. X            default:
  422. X               if(i<0)                /* suspend should be >=0 */
  423. X              goto eusg;
  424. X               suspend=i;goto checkrdec;
  425. X          }
  426. X          case HELPOPT1:case HELPOPT2:elog(usage);
  427. X         elog(
  428. X "\t-nnn\twait nnn seconds between locking attempts\
  429. X\n\t-r nnn\tmake at most nnn retries before giving up on a lock\
  430. X\n\t-l nnn\tset locktimeout to nnn seconds\
  431. X\n\t-s nnn\tsuspend nnn seconds after a locktimeout occurred\
  432. X\n\t-!\tinvert the exit code of lockfile\
  433. X\n\t-ml\tlock your system mail-spool file\
  434. X\n\t-mu\tunlock your system mail-spool file\n");goto xusg;
  435. X          default:
  436. X         if(sleepsec>=0)        /* is this still the first pass? */
  437. X          { if((sleepsec=strtol(cp,&cp,10))<0)
  438. X               goto eusg;
  439. Xcheckrdec:        if(cp2==cp)
  440. Xeusg:             { elog(usage);            /* regular usage message */
  441. Xxusg:               retval=EX_USAGE;goto nfailure;
  442. X             }
  443. X          }
  444. X         else              /* no second pass, so leave sleepsec<0 */
  445. X            strtol(cp,&cp,10);           /* and discard the number */
  446. X         continue;
  447. X          case 'm':          /* take $LOGNAME as a hint, check if valid */
  448. X           { struct passwd*pass;static char*ma;size_t alen;
  449. X         if(*cp&&cp[1]||ma&&sleepsec>=0)         /* second pass? */
  450. X            goto eusg;
  451. X         if(!ma)            /* ma initialised last time? */
  452. X          { if(!((ma=(char*)getenv(lgname))&&(pass=getpwnam(ma))&&
  453. X             pass->pw_uid==uid||(pass=getpwuid(uid))))
  454. X             { nlog("Can't determine your mailbox, who are you?\n");
  455. X               goto nfailure;     /* panic, you're not in /etc/passwd */
  456. X             }
  457. X            if(!(alen=parsecopy((char*)0,systm_mbox,pass)))
  458. X             { cp=systm_mbox;goto lfailure;      /* couldn't digest */
  459. X             }                          /* mailbox */
  460. X            if(!(ma=malloc(alen)))           /* ok, make some room */
  461. X               goto outofmem;
  462. X            parsecopy(ma,systm_mbox,pass);      /* and fill her up */
  463. X          }
  464. X         switch(*cp)
  465. X          { default:goto eusg;            /* somebody goofed again */
  466. X            case 'l':                 /* lock the mailbox */
  467. X               if(sleepsec>=0)                  /* first pass? */
  468. X            { cp=ma;goto stilv;            /* yes, lock it! */
  469. X            }
  470. X            case 'u':                   /* unlock the mailbox */
  471. X               if(unlink(ma))
  472. X            { nlog("Can't unlock \"");elog(ma);elog("\"");
  473. X              if(*cp=='l')     /* they messed up, give them a hint */
  474. X                 elog(" again,\n already dropped my privileges");
  475. X              elog("\n");
  476. X            }
  477. X               else
  478. X              virgin=0;
  479. X          }
  480. X           }
  481. X          case '\0':;
  482. X        }
  483. X       break;
  484. X     }
  485. X     else if(sleepsec<0)      /* second pass, release everything we acquired */
  486. X    unlink(cp);
  487. X     else
  488. X      { time_t t;int permanent;
  489. X    setgid(getgid());              /* just to be on the safe side */
  490. Xstilv:    virgin=0;permanent=nfsTRY;
  491. X    while(0>xcreat(cp,&t))                     /* try and lock */
  492. X     { struct stat stbuf;
  493. X       if(exitflag)                        /* time to stop? */
  494. X        { if(exitflag==1)             /* was it failure() or malloc() */
  495. Xoutofmem:     retval=EX_OSERR,nlog("Out of memory");
  496. X          else
  497. X         retval=EX_TEMPFAIL,nlog("Signal received");
  498. X          goto lfailure;
  499. X        }
  500. X       switch(errno)            /* why did the lock not succeed? */
  501. X        { case EEXIST:              /* hmmm..., by force then? */
  502. X         if(force&&!lstat(cp,&stbuf)&&force<t-stbuf.st_mtime)
  503. X          { nlog(unlink(cp)?"Forced unlock denied on \"":
  504. X             "Forcing lock on \"");
  505. X            elog(cp);elog("\"\n");sleep(suspend);    /* important */
  506. X          }
  507. X         else                       /* no forcing now */
  508. X          case ENOSPC:
  509. X#ifdef EDQUOT
  510. X          case EDQUOT:
  511. X#endif
  512. X            switch(retries)    /* await your turn like everyone else */
  513. X             { case 0:nlog("Sorry");retval=EX_CANTCREAT;
  514. X              goto lfailure;      /* patience exhausted, give up */
  515. X               default:retries--;              /* count sheep */
  516. X               case -1:sleep(sleepsec);             /* wait and see */
  517. X             }
  518. X         break;
  519. X          case ENOENT:case ENOTDIR:case EIO:case EACCES:
  520. X         if(!--permanent)     /* NFS sporadically generates these */
  521. X          { sleep(sleepsec);continue;              /* unwarranted */
  522. X          }                     /* so ignore them first */
  523. X          default:             /* but, it seems to persist, so give up */
  524. X         nlog("Try praying");retval=EX_UNAVAILABLE;
  525. X#ifdef ENAMETOOLONG
  526. X         goto lfailure;
  527. X          case ENAMETOOLONG:
  528. X         if(0<(permanent=strlen(cp)-1)&&      /* can we truncate it? */
  529. X          !strchr(dirsep,cp[permanent-1]))
  530. X          { nlog("Truncating \"");elog(cp);          /* then try it */
  531. X            elog("\" and retrying lock\n");cp[permanent]='\0';break;
  532. X          }                     /* otherwise, forget it */
  533. X         nlog("Filename too long");retval=EX_UNAVAILABLE;
  534. X#endif
  535. Xlfailure:     elog(", giving up on \"");elog(cp);elog("\"\n");
  536. Xnfailure:     sleepsec= -1;argc=lastf-argv+1;goto again; /* mark sleepsec */
  537. X        }  /* for second pass, and adjust argc to the no. of args parsed */
  538. X       permanent=nfsTRY;           /* refresh the NFS-error-ignore count */
  539. X     }
  540. X    lastf=p;                      /* last valid file */
  541. X      }
  542. X  if(retval==EX_OK&&virgin)         /* any errors?     did we do anything? */
  543. Xusg:
  544. X   { elog(usage);return EX_USAGE;
  545. X   }
  546. X  if(invert)
  547. X     switch(retval)             /* we only invert the regular cases */
  548. X      { case EX_OK:return EX_CANTCREAT;
  549. X    case EX_CANTCREAT:return EX_OK;
  550. X      }
  551. X  return retval;                   /* all other exitcodes remain */
  552. X}
  553. X
  554. Xvoid*tmalloc(len)const size_t len;                     /* stub */
  555. X{ return malloc(len);
  556. X}
  557. X
  558. Xropen(name,mode,mask)const char*const name;const int mode;const mode_t mask;
  559. X{ return open(name,mode,mask);                         /* stub */
  560. X}
  561. X
  562. Xrclose(fd)const int fd;                             /* stub */
  563. X{ return close(fd);
  564. X}
  565. X
  566. Xvoid writeerr(a)const char*const a;                     /* stub */
  567. X{
  568. X}
  569. END_OF_FILE
  570. if test 9425 -ne `wc -c <'procmail280/src/lockfile.c'`; then
  571.     echo shar: \"'procmail280/src/lockfile.c'\" unpacked with wrong size!
  572. fi
  573. # end of 'procmail280/src/lockfile.c'
  574. fi
  575. if test -f 'procmail280/src/mailfold.c' -a "${1}" != "-c" ; then 
  576.   echo shar: Will not clobber existing file \"'procmail280/src/mailfold.c'\"
  577. else
  578. echo shar: Extracting \"'procmail280/src/mailfold.c'\" \(9757 characters\)
  579. sed "s/^X//" >'procmail280/src/mailfold.c' <<'END_OF_FILE'
  580. X/************************************************************************
  581. X *    Routines that deal with the mailfolder(format)            *
  582. X *                                    *
  583. X *    Copyright (c) 1990-1992, S.R. van den Berg, The Netherlands    *
  584. X *    #include "README"                        *
  585. X ************************************************************************/
  586. X#ifdef RCS
  587. Xstatic /*const*/char rcsid[]=
  588. X "$Id: mailfold.c,v 1.19 1993/02/04 12:44:55 berg Exp $";
  589. X#endif
  590. X#include "procmail.h"
  591. X#include "sublib.h"
  592. X#include "robust.h"
  593. X#include "shell.h"
  594. X#include "misc.h"
  595. X#include "pipes.h"
  596. X#include "common.h"
  597. X#include "exopen.h"
  598. X#include "locking.h"
  599. X#include "mailfold.h"
  600. X#ifndef NO_COMSAT
  601. X#include "network.h"
  602. X
  603. Xconst char scomsat[]="COMSAT";
  604. X#endif
  605. Xint logopened,tofile;
  606. Xlong lasttell;
  607. Xstatic long lastdump;
  608. Xstatic volatile mailread;    /* if the mail is completely read in already */
  609. Xstatic struct dyna_long escFrom_,confield;      /* escapes, concatenations */
  610. X                   /* inserts escape characters on outgoing mail */
  611. Xstatic long getchunk(s,fromw,len)const int s;const char*fromw;const long len;
  612. X{ long dist,dif;int i;static char esc[]={ESCAP};
  613. X  dist=fromw-themail;            /* where are we now in transmitting? */
  614. X  for(dif=len,i=0;i<escFrom_.filled;)        /* let's see if we can find this */
  615. X     if(!(dif=escFrom_.offs[i++]-dist))             /* this exact spot? */
  616. X      { rwrite(s,esc,sizeof esc);lastdump++;            /* escape it */
  617. X    if(i>=escFrom_.filled)                      /* last block? */
  618. X       return len;                /* yes, give all what's left */
  619. X    dif=escFrom_.offs[i]-dist;break;         /* the whole next block */
  620. X      }
  621. X     else if(dif>0)                /* passed this spot already? */
  622. X    break;
  623. X  return dif<len?dif:len;
  624. X}
  625. X
  626. Xlong dump(s,source,len)const int s;const char*source;long len;
  627. X{ int i;long part;
  628. X  lasttell=i= -1;
  629. X  if(s>=0)
  630. X   { if(tofile&&(lseek(s,0L,SEEK_END),fdlock(s)))
  631. X    nlog("Kernel-lock failed\n");
  632. X     lastdump=len;part=tofile==to_FOLDER?getchunk(s,source,len):len;
  633. X     lasttell=lseek(s,0L,SEEK_END);smboxseparator(s);  /* optional separator */
  634. X#ifndef NO_NFS_ATIME_HACK
  635. X     if(part&&tofile)               /* if it is a file, trick NFS into an */
  636. X    len--,part--,rwrite(s,source++,1),sleep(1);        /* a_time<m_time */
  637. X#endif
  638. X     goto jin;
  639. X     do
  640. X      { part=getchunk(s,source,len);
  641. Xjin:    while(part&&(i=rwrite(s,source,BLKSIZ<part?BLKSIZ:(int)part)))
  642. X     { if(i<0)
  643. X        { i=0;goto writefin;
  644. X        }
  645. X       part-=i;len-=i;source+=i;
  646. X     }
  647. X      }
  648. X     while(len);
  649. X     if(!len&&(lastdump<2||!(source[-1]=='\n'&&source[-2]=='\n')))
  650. X    lastdump++,rwrite(s,newline,1);           /* message always ends with a */
  651. X     emboxseparator(s);         /* newline and an optional custom separator */
  652. Xwritefin:
  653. X     if(tofile&&fdunlock())
  654. X    nlog("Kernel-unlock failed\n");
  655. X     i=rclose(s);
  656. X   }               /* return an error even if nothing was to be sent */
  657. X  tofile=0;return i&&!len?-1:len;
  658. X}
  659. X                       /* open file or new file in directory */
  660. Xdeliver(boxname)char*const boxname;
  661. X{ struct stat stbuf;
  662. X  tofile=to_FILE;strcpy(buf,boxname);     /* boxname can be found back in buf */
  663. X  return stat(buf,&stbuf)||!S_ISDIR(stbuf.st_mode)?
  664. X   (tofile=strcmp(devnull,buf)?to_FOLDER:0,opena(buf)):dirmail();
  665. X}
  666. X
  667. Xvoid logabstract P((void))
  668. X{ if(logopened)              /* make sure that this doesn't get mailed back */
  669. X   { char*chp,*chp2;int i;static const char sfolder[]=FOLDER;
  670. X     if(mailread)              /* is the mail completely read in? */
  671. X      { *thebody='\0';               /* terminate the header, just in case */
  672. X    if(eqFrom_(chp=themail))               /* any "From " header */
  673. X     { if(chp=strchr(themail,'\n'))
  674. X          *chp++='\0';
  675. X       else
  676. X          chp=thebody;              /* preserve mailbox format */
  677. X       elog(themail);elog(newline);                 /* (any length) */
  678. X     }
  679. X    if(!(lcking&lck_ALLOCLIB)&&        /* don't reenter malloc/free */
  680. X     (chp=egrepin(NSUBJECT,chp,(long)(thebody-chp),0)))
  681. X     { for(chp2= --chp;*--chp2!='\n'&&*chp2;);
  682. X       if(chp-++chp2>MAXSUBJECTSHOW)        /* keep it within bounds */
  683. X          chp2[MAXSUBJECTSHOW]='\0';
  684. X       *chp='\0';detab(chp2);elog(" ");elog(chp2);elog(newline);
  685. X     }
  686. X      }
  687. X     elog(sfolder);
  688. X     i=strlen(strncpy(buf,lastfolder,MAXfoldlen))+STRLEN(sfolder);
  689. X     buf[MAXfoldlen]='\0';detab(buf);elog(buf);i-=i%TABWIDTH;    /* last dump */
  690. X     do elog(TABCHAR);
  691. X     while((i+=TABWIDTH)<LENoffset);
  692. X     ultstr(7,lastdump,buf);elog(buf);elog(newline);
  693. X   }
  694. X#ifndef NO_COMSAT
  695. X  ;{ int s;struct sockaddr_in addr;char*chp,*chad;         /* @ seperator? */
  696. X     if(chad=strchr(chp=(char*)tgetenv(scomsat),SERV_ADDRsep))
  697. X    *chad++='\0';              /* split it up in service and hostname */
  698. X     else if(!renvint(-1L,scomsat))        /* or is it a false boolean? */
  699. X    return;                           /* ok, no comsat then */
  700. X     if(!chad||!*chad)                          /* no host */
  701. X#ifndef IP_localhost
  702. X    chad=COMSAThost;                      /* use default */
  703. X#else /* IP_localhost */
  704. X      { static const unsigned char ip_localhost[]=IP_localhost;
  705. X    addr.sin_family=AF_INET;
  706. X    tmemmove(&addr.sin_addr,ip_localhost,sizeof ip_localhost);
  707. X      }
  708. X     else
  709. X#endif /* IP_localhost */
  710. X      { const struct hostent*host;          /* what host?  paranoid checks */
  711. X    if(!(host=gethostbyname(chad))||!host->h_0addr_list)
  712. X     { endhostent();return;             /* host can't be found, too bad */
  713. X     }
  714. X    addr.sin_family=host->h_addrtype;         /* address number found */
  715. X    tmemmove(&addr.sin_addr,host->h_0addr_list,host->h_length);
  716. X    endhostent();
  717. X      }
  718. X     if(!*chp)                               /* no service */
  719. X    chp=BIFF_serviceport;                      /* use default */
  720. X     s=strtol(chp,&chad,10);
  721. X     if(chp==chad)                   /* the service is not numeric */
  722. X      { const struct servent*serv;
  723. X    if(!(serv=getservbyname(chp,COMSATprotocol)))       /* so get its no. */
  724. X     { endservent();return;
  725. X     }
  726. X    addr.sin_port=serv->s_port;endservent();
  727. X      }
  728. X     else
  729. X    addr.sin_port=htons((short)s);                /* network order */
  730. X     cat(tgetenv(lgname),"@");             /* should always fit in buf */
  731. X     if(lasttell>=0)                       /* was it a file? */
  732. X    ultstr(0,lasttell,buf2),catlim(buf2);                  /* yep */
  733. X     catlim(COMSATxtrsep);                 /* custom seperator */
  734. X     if(lasttell>=0&&!strchr(dirsep,*lastfolder))      /* relative filename? */
  735. X    catlim(tgetenv(maildir)),catlim(_MCDIRSEP);   /* prepend current dir */
  736. X     catlim(lastfolder);s=socket(AF_INET,SOCK_DGRAM,UDP_protocolno);
  737. X     sendto(s,buf,strlen(buf),0,(const void*)&addr,sizeof(addr));rclose(s);
  738. X     yell("Notified comsat:",buf);
  739. X   }
  740. X#endif /* NO_COMSAT */
  741. X}
  742. X
  743. Xstatic concnd;                     /* last concatenation value */
  744. X
  745. Xvoid concon(ch)const int ch;   /* flip between concatenated and split fields */
  746. X{ size_t i;
  747. X  if(concnd!=ch)                   /* is this run redundant? */
  748. X   { concnd=ch;                  /* no, but note this one for next time */
  749. X     for(i=confield.filled;i;)           /* step through the saved offsets */
  750. X    themail[confield.offs[--i]]=ch;               /* and flip every one */
  751. X   }
  752. X}
  753. X
  754. Xvoid readmail(rhead,tobesent)const long tobesent;
  755. X{ char*chp,*pastend,*realstart;
  756. X  ;{ long dfilled;
  757. X     if(rhead)                    /* only read in a new header */
  758. X      { dfilled=mailread=0;chp=readdyn(malloc(1),&dfilled);filled-=tobesent;
  759. X    if(tobesent<dfilled)           /* adjust buffer size (grow only) */
  760. X       themail=realloc(themail,dfilled+filled);
  761. X    tmemmove(themail+dfilled,thebody,filled);tmemmove(themail,chp,dfilled);
  762. X    free(chp);themail=realloc(themail,1+(filled+=dfilled));
  763. X      }
  764. X     else
  765. X      { if(!mailread||!filled)
  766. X       rhead=1;     /* yup, we read in a new header as well as new mail */
  767. X    mailread=0;dfilled=thebody-themail;themail=readdyn(themail,&filled);
  768. X      }
  769. X     pastend=filled+(thebody=themail);
  770. X     while(thebody<pastend&&*thebody++=='\n');         /* skip leading garbage */
  771. X     realstart=thebody;
  772. X     if(rhead)                  /* did we read in a new header anyway? */
  773. X      { confield.filled=0;concnd='\n';
  774. X    while(thebody=
  775. X     egrepin("[^\n]\n[\n\t ]",thebody,(long)(pastend-thebody),1))
  776. X       if(thebody[-1]!='\n')          /* mark continuated fields */
  777. X          app_val(&confield,(long)(--thebody-1-themail));
  778. X       else
  779. X          goto eofheader;           /* empty line marks end of header */
  780. X    thebody=pastend;      /* provide a default, in case there is no body */
  781. Xeofheader:;
  782. X      }
  783. X     else                   /* no new header read, keep it simple */
  784. X    thebody=themail+dfilled; /* that means we know where the body starts */
  785. X   }
  786. X  ;{ int f1stchar;    /* to make sure that the first From_ line is uninjured */
  787. X     f1stchar= *realstart;*(chp=realstart)='\0';escFrom_.filled=0;
  788. X     while(chp=egrepin(FROM_EXPR,chp,(long)(pastend-chp),1))
  789. X      { while(*--chp!='\n');               /* where did this line start? */
  790. X    app_val(&escFrom_,(long)(++chp-themail));chp++;           /* bogus! */
  791. X      }
  792. X     *realstart=f1stchar;mailread=1;
  793. X   }
  794. X}
  795. X
  796. Xdirmail P((void))            /* buf should contain directory name */
  797. X{ char*chp;struct stat stbuf;
  798. X  if((chp=strchr(buf,'\0')-1)-1>=buf&&chp[-1]==*_MCDIRSEP&&*chp==chCURDIR)
  799. X     *chp='\0',strcpy(buf2,buf);               /* it ended in /. */
  800. X  else
  801. X     chp=0,strcpy(buf2,strcat(buf,_MCDIRSEP));
  802. X  if(unique(buf2,strchr(buf2,'\0'),NORMperm,verbose))
  803. X   { if(chp)
  804. X      { long i=0;             /* first let us try to prime i with the */
  805. X#ifndef NOopendir             /* highest MH folder number we can find */
  806. X    long j;DIR*dirp;struct dirent*dp;char*chp2;
  807. X    *chp='\0';yell("Opening directory",buf);
  808. X    if(dirp=opendir(buf))
  809. X     { while(dp=readdir(dirp))    /* there still are directory entries */
  810. X          if((j=strtol(dp->d_name,&chp2,10))>i&&!*chp2)
  811. X         i=j;                /* yep, we found a higher number */
  812. X       closedir(dirp);                 /* aren't we neat today */
  813. X     }
  814. X    else
  815. X       readerr(buf);
  816. X#endif /* NOopendir */
  817. X    do ultstr(0,++i,chp);               /* find first empty MH folder */
  818. X    while(link(buf2,buf)&&errno==EEXIST);
  819. X    unlink(buf2);goto opn;
  820. X      }
  821. X     stat(buf2,&stbuf);
  822. X     ultoan((unsigned long)stbuf.st_ino,      /* filename with i-node number */
  823. X      strchr(strcat(buf,tgetenv(msgprefix)),'\0'));
  824. X     if(!myrename(buf2,buf))           /* rename it, we need the same i-node */
  825. Xopn:    return opena(buf);
  826. X   }
  827. X  return -1;
  828. X}
  829. END_OF_FILE
  830. if test 9757 -ne `wc -c <'procmail280/src/mailfold.c'`; then
  831.     echo shar: \"'procmail280/src/mailfold.c'\" unpacked with wrong size!
  832. fi
  833. # end of 'procmail280/src/mailfold.c'
  834. fi
  835. if test -f 'procmail280/src/misc.c' -a "${1}" != "-c" ; then 
  836.   echo shar: Will not clobber existing file \"'procmail280/src/misc.c'\"
  837. else
  838. echo shar: Extracting \"'procmail280/src/misc.c'\" \(9939 characters\)
  839. sed "s/^X//" >'procmail280/src/misc.c' <<'END_OF_FILE'
  840. X/************************************************************************
  841. X *    Miscellaneous routines used by procmail                *
  842. X *                                    *
  843. X *    Copyright (c) 1990-1992, S.R. van den Berg, The Netherlands    *
  844. X *    #include "README"                        *
  845. X ************************************************************************/
  846. X#ifdef RCS
  847. Xstatic /*const*/char rcsid[]=
  848. X "$Id: misc.c,v 1.18 1993/02/02 15:27:13 berg Exp $";
  849. X#endif
  850. X#include "procmail.h"
  851. X#include "sublib.h"
  852. X#include "robust.h"
  853. X#include "misc.h"
  854. X#include "pipes.h"
  855. X#include "common.h"
  856. X#include "cstdio.h"
  857. X#include "exopen.h"
  858. X#include "regexp.h"
  859. X#include "goodies.h"
  860. X#include "locking.h"
  861. X#include "mailfold.h"
  862. X
  863. Xstruct varval strenvvar[]={{"LOCKSLEEP",DEFlocksleep},
  864. X {"LOCKTIMEOUT",DEFlocktimeout},{"SUSPEND",DEFsuspend},
  865. X {"NORESRETRY",DEFnoresretry},{"TIMEOUT",DEFtimeout},{"VERBOSE",DEFverbose}};
  866. Xint didchd;
  867. Xstatic fakedelivery;
  868. X               /* line buffered to keep concurrent entries untangled */
  869. Xvoid elog(newt)const char*const newt;
  870. X{ int lnew,i;static lold;static char*old;char*p;
  871. X#ifndef O_CREAT
  872. X  lseek(STDERR,0L,SEEK_END);          /* locking should be done actually */
  873. X#endif
  874. X  if(!(lnew=strlen(newt))||nextexit)                 /* force flush? */
  875. X     goto flush;
  876. X  i=lold+lnew;
  877. X  if(p=lold?realloc(old,i):malloc(i))             /* unshelled malloc */
  878. X   { memmove((old=p)+lold,newt,(size_t)lnew);               /* append */
  879. X     if(p[(lold=i)-1]=='\n')                         /* EOL? */
  880. X    rwrite(STDERR,p,i),lold=0,free(p);        /* flush the line(s) */
  881. X   }
  882. X  else                           /* no memory, force flush */
  883. Xflush:
  884. X   { if(lold)
  885. X      { rwrite(STDERR,old,lold);lold=0;
  886. X    if(!nextexit)
  887. X       free(old);            /* don't use free in signal handlers */
  888. X      }
  889. X     if(lnew)
  890. X    rwrite(STDERR,newt,lnew);
  891. X   }
  892. X}
  893. X
  894. X#include "shell.h"
  895. X
  896. Xvoid ignoreterm P((void))
  897. X{ signal(SIGTERM,SIG_IGN);signal(SIGHUP,SIG_IGN);signal(SIGINT,SIG_IGN);
  898. X  signal(SIGQUIT,SIG_IGN);
  899. X}
  900. X
  901. Xvoid writeerr(line)const char*const line;
  902. X{ nlog("Error while writing to");logqnl(line);
  903. X}
  904. X
  905. Xforkerr(pid,a)const pid_t pid;const char*const a;
  906. X{ if(pid==-1)
  907. X   { nlog("Failed forking");logqnl(a);return 1;
  908. X   }
  909. X  return 0;
  910. X}
  911. X
  912. Xvoid progerr(line)const char*const line;
  913. X{ nlog("Program failure of");logqnl(line);
  914. X}
  915. X
  916. Xvoid chderr(dir)const char*const dir;
  917. X{ nlog("Couldn't chdir to");logqnl(dir);
  918. X}
  919. X
  920. Xvoid readerr(file)const char*const file;
  921. X{ nlog("Couldn't read");logqnl(file);
  922. X}
  923. X
  924. Xvoid yell(a,b)const char*const a,*const b;        /* log if VERBOSE=on */
  925. X{ if(verbose)
  926. X     nlog(a),logqnl(b);
  927. X}
  928. X
  929. Xvoid nlog(a)const char*const a;
  930. X{ elog(procmailn);elog(": ");elog(a);
  931. X}
  932. X
  933. Xvoid logqnl(a)const char*const a;
  934. X{ elog(oquote);elog(a);elog(cquote);
  935. X}
  936. X
  937. Xvoid skipped(x)const char*const x;
  938. X{ if(*x)
  939. X     nlog("Skipped"),logqnl(x);
  940. X}
  941. X
  942. Xnextrcfile P((void))        /* next rcfile specified on the command line */
  943. X{ const char*p;
  944. X  while(p= *gargv)
  945. X   { gargv++;
  946. X     if(!strchr(p,'='))
  947. X      { rcfile=p;return 1;
  948. X      }
  949. X   }
  950. X  return 0;
  951. X}
  952. X
  953. Xvoid sterminate P((void))
  954. X{ static const char*const msg[]={"memory","fork",      /* crosscheck with */
  955. X   "a file descriptor","a kernel-lock"};      /* lck_ defs in procmail.h */
  956. X  ignoreterm();
  957. X  if(pidchild>0)        /* don't kill what is not ours, we might be root */
  958. X     kill(pidchild,SIGTERM);
  959. X  if(!nextexit)
  960. X   { nextexit=1;nlog("Terminating prematurely");
  961. X     if(!(lcking&lck_LOCKFILE))
  962. X      { register unsigned i,j;
  963. X    if(i=(lcking&~(lck_ALLOCLIB|lck_LOCKFILE))>>1)
  964. X     { elog(whilstwfor);
  965. X       for(j=0;!((i>>=1)&1);j++);
  966. X       elog(msg[j]);
  967. X     }
  968. X    elog(newline);terminate();
  969. X      }
  970. X   }
  971. X}
  972. X
  973. Xvoid terminate P((void))
  974. X{ ignoreterm();
  975. X  if(retvl2!=EX_OK)
  976. X     fakedelivery=0,retval=retvl2;
  977. X  if(getpid()==thepid)
  978. X   { if(retval!=EX_OK)
  979. X      { tofile=0;lasttell= -1;         /* make sure that logabstract knows */
  980. X    lastfolder=fakedelivery?"**Lost**":        /* don't free() here */
  981. X     retval==EX_TEMPFAIL?"**Requeued**":"**Bounced**";
  982. X      }
  983. X     logabstract();closerc();
  984. X     if(!(lcking&lck_ALLOCLIB))            /* don't reenter malloc/free */
  985. X    exectrap(tgetenv("TRAP"));
  986. X     nextexit=2;unlock(&loclock);unlock(&globlock);fdunlock();
  987. X   }
  988. X  exit(fakedelivery==2?EX_OK:retval);
  989. X}
  990. X
  991. Xvoid suspend P((void))
  992. X{ long t;
  993. X  sleep((unsigned)suspendv);
  994. X  if(alrmtime)
  995. X     if((t=alrmtime-time((time_t*)0))<=1)      /* if less than 1s timeout */
  996. X    ftimeout();                  /* activate it by hand now */
  997. X     else            /* set it manually again, to avoid problems with */
  998. X    alarm((unsigned)t);    /* badly implemented sleep library functions */
  999. X}
  1000. X
  1001. Xvoid app_val(sp,val)struct dyna_long*const sp;const long val;
  1002. X{ if(sp->filled==sp->tspace)                /* growth limit reached? */
  1003. X   { if(!sp->offs)
  1004. X    sp->offs=malloc(1);
  1005. X     sp->offs=realloc(sp->offs,(sp->tspace+=4)*sizeof sp->offs);   /* expand */
  1006. X   }
  1007. X  sp->offs[sp->filled++]=val;                     /* append to it */
  1008. X}
  1009. X
  1010. Xalphanum(c)const unsigned c;
  1011. X{ return c-'0'<='9'-'0'||c-'a'<='z'-'a'||c-'A'<='Z'-'A'||c=='_';
  1012. X}
  1013. X
  1014. Xvoid firstchd P((void))
  1015. X{ if(!didchd)                       /* have we been here already? */
  1016. X   { const char*p;
  1017. X     didchd=1;                  /* no, well, then try an initial chdir */
  1018. X     if(chdir(p=tgetenv(maildir)))
  1019. X      { chderr(p);
  1020. X    if(chdir(p=tgetenv(home)))
  1021. X       chderr(p);
  1022. X      }
  1023. X   }
  1024. X}
  1025. X
  1026. Xvoid srequeue P((void))
  1027. X{ retval=EX_TEMPFAIL;sterminate();
  1028. X}
  1029. X
  1030. Xvoid slose P((void))
  1031. X{ fakedelivery=2;sterminate();
  1032. X}
  1033. X
  1034. Xvoid sbounce P((void))
  1035. X{ retval=EX_CANTCREAT;sterminate();
  1036. X}
  1037. X
  1038. Xvoid catlim(src)register const char*src;
  1039. X{ register char*dest=buf;register size_t lim=linebuf;
  1040. X  while(lim&&*dest)
  1041. X     dest++,lim--;
  1042. X  if(lim)
  1043. X   { while(--lim&&(*dest++= *src++));
  1044. X     *dest='\0';
  1045. X   }
  1046. X}
  1047. X
  1048. Xvoid setdef(name,contents)const char*const name,*const contents;
  1049. X{ strcat(strcat(strcpy((char*)(sgetcp=buf2),name),"="),contents);
  1050. X  readparse(buf,sgetc,2);sputenv(buf);
  1051. X}
  1052. X
  1053. Xvoid metaparse(p)const char*p;                    /* result in buf */
  1054. X{ if(sh=!!strpbrk(p,tgetenv(shellmetas)))
  1055. X     strcpy(buf,p);             /* copy literally, shell will parse */
  1056. X  else
  1057. X#ifndef GOT_bin_test
  1058. X   { sgetcp=p=tstrdup(p);
  1059. X     readparse(buf,sgetc,0);                /* parse it yourself */
  1060. X     if(!strcmp(test,buf))
  1061. X    strcpy(buf,p),sh=1;                   /* oops, `test' found */
  1062. X     free((char*)p);
  1063. X   }
  1064. X#else
  1065. X     sgetcp=p,readparse(buf,sgetc,0);
  1066. X#endif
  1067. X}
  1068. X
  1069. Xvoid concatenate(p)register char*p;
  1070. X{ while(*p!=TMNATE)              /* concatenate all other arguments */
  1071. X   { while(*p++);
  1072. X     p[-1]=' ';
  1073. X   }
  1074. X  *p=p[-1]='\0';
  1075. X}
  1076. X
  1077. Xchar*lastdirsep(filename)const char*filename;     /* finds the next character */
  1078. X{ const char*p;                    /* following the last DIRSEP */
  1079. X  while(p=strpbrk(filename,dirsep))
  1080. X     filename=p+1;
  1081. X  return(char*)filename;
  1082. X}
  1083. X
  1084. Xchar*cat(a,b)const char*const a,*const b;
  1085. X{ return strcat(strcpy(buf,a),b);
  1086. X}
  1087. X
  1088. Xchar*tstrdup(a)const char*const a;
  1089. X{ int i;
  1090. X  i=strlen(a)+1;return tmemmove(malloc(i),a,i);
  1091. X}
  1092. X
  1093. Xconst char*tgetenv(a)const char*const a;
  1094. X{ const char*b;
  1095. X  return(b=getenv(a))?b:"";
  1096. X}
  1097. X
  1098. Xchar*cstr(a,b)char*const a;const char*const b;    /* dynamic buffer management */
  1099. X{ if(a)
  1100. X     free(a);
  1101. X  return tstrdup(b);
  1102. X}
  1103. X
  1104. Xchar*skpspace(chp)const char*chp;
  1105. X{ for(;;chp++)
  1106. X     switch(*chp)
  1107. X      { case ' ':case '\t':continue;
  1108. X    default:return(char*)chp;
  1109. X      }
  1110. X}
  1111. X
  1112. Xchar*gobenv(chp)char*chp;
  1113. X{ int found,i;
  1114. X  for(found=0;alphanum(i=getb());found=1,*chp++=i);
  1115. X  *chp='\0';ungetb(i);
  1116. X  switch(i)
  1117. X   { case ' ':case '\t':case '\n':case '=':return chp;
  1118. X   }
  1119. X  return 0;
  1120. X}
  1121. X
  1122. Xvoid asenvcpy(src)char*src;
  1123. X{ strcpy(buf,src);
  1124. X  if(src=strchr(buf,'='))                 /* is it an assignment? */
  1125. X   { strcpy((char*)(sgetcp=buf2),++src);readparse(src,sgetc,2);sputenv(buf);
  1126. X     src[-1]='\0';asenv(src);
  1127. X   }
  1128. X}
  1129. X
  1130. Xvoid asenv(chp)const char*const chp;
  1131. X{ static const char slinebuf[]="LINEBUF",logfile[]="LOGFILE",Log[]="LOG",
  1132. X   sdelivered[]="DELIVERED",includerc[]="INCLUDERC",eumask[]="UMASK",
  1133. X   host[]="HOST";
  1134. X  if(!strcmp(buf,slinebuf))
  1135. X   { if((linebuf=renvint(0L,chp)+XTRAlinebuf)<MINlinebuf+XTRAlinebuf)
  1136. X    linebuf=MINlinebuf+XTRAlinebuf;               /* check minimum size */
  1137. X     free(buf);free(buf2);buf=malloc(linebuf);buf2=malloc(linebuf);
  1138. X   }
  1139. X  else if(!strcmp(buf,maildir))
  1140. X     if(chdir(chp))
  1141. X    chderr(chp);
  1142. X     else
  1143. X    didchd=1;
  1144. X  else if(!strcmp(buf,logfile))
  1145. X     openlog(chp);
  1146. X  else if(!strcmp(buf,Log))
  1147. X     elog(chp);
  1148. X  else if(!strcmp(buf,sdelivered))                /* fake delivery */
  1149. X   { if(renvint(0L,chp))                    /* is it really? */
  1150. X      { lcking|=lck_LOCKFILE;            /* just to prevent interruptions */
  1151. X    if((thepid=sfork())>0)
  1152. X     { nextexit=2;lcking&=~lck_LOCKFILE;exit(retvl2);
  1153. X     }                    /* signals may cause trouble */
  1154. X    if(!forkerr(thepid,procmailn))
  1155. X       fakedelivery=1;
  1156. X    thepid=getpid();lcking&=~lck_LOCKFILE;
  1157. X    if(nextexit)                 /* signals occurred so far? */
  1158. X       elog(newline),terminate();
  1159. X      }
  1160. X   }
  1161. X  else if(!strcmp(buf,lockfile))
  1162. X     lockit((char*)chp,&globlock);
  1163. X  else if(!strcmp(buf,eumask))
  1164. X     umask((int)strtol(chp,(char**)0,8));
  1165. X  else if(!strcmp(buf,includerc))
  1166. X     pushrc(chp);
  1167. X  else if(!strcmp(buf,host))
  1168. X   { const char*name;
  1169. X     if(strncmp(chp,name=hostname(),HOSTNAMElen))
  1170. X      { yell("HOST mismatched",name);
  1171. X    if(rc<0||!nextrcfile())              /* if no rcfile opened yet */
  1172. X       retval=EX_OK,terminate();          /* exit gracefully as well */
  1173. X    closerc();rc=rc_NOFILE;
  1174. X      }
  1175. X   }
  1176. X  else
  1177. X   { int i=MAXvarvals;
  1178. X     do                          /* several numeric assignments */
  1179. X    if(!strcmp(buf,strenvvar[i].name))
  1180. X     { strenvvar[i].val=renvint(strenvvar[i].val,chp);break;
  1181. X     }
  1182. X     while(i--);
  1183. X   }
  1184. X}
  1185. X
  1186. Xlong renvint(i,env)const long i;const char*const env;
  1187. X{ const char*p;long t;
  1188. X  t=strtol(env,(char**)&p,10);              /* parse like a decimal nr */
  1189. X  if(p==env)
  1190. X   { for(;;p++)                      /* skip leading whitespace */
  1191. X      { switch(*p)
  1192. X     { case '\t':case ' ':continue;
  1193. X     }
  1194. X    break;
  1195. X      }
  1196. X     t=i;
  1197. X     if(!strnIcmp(p,"on",(size_t)2)||!strnIcmp(p,"y",(size_t)1)||
  1198. X      !strnIcmp(p,"t",(size_t)1))
  1199. X    t=1;
  1200. X     else if(!strnIcmp(p,"off",(size_t)3)||!strnIcmp(p,"n",(size_t)1)||
  1201. X      !strnIcmp(p,"f",(size_t)1))
  1202. X    t=0;
  1203. X   }
  1204. X  return t;
  1205. X}
  1206. X
  1207. Xchar*egrepin(expr,source,len,casesens)char*expr;const char*source;
  1208. X const long len;
  1209. X{ source=(const char*)bregexec((struct eps*)(expr=(char*)
  1210. X   bregcomp(expr,!casesens)),(const uchar*)source,len>0?
  1211. X   (size_t)len:(size_t)0,!casesens);
  1212. X  free(expr);return(char*)source;
  1213. X}
  1214. END_OF_FILE
  1215. if test 9939 -ne `wc -c <'procmail280/src/misc.c'`; then
  1216.     echo shar: \"'procmail280/src/misc.c'\" unpacked with wrong size!
  1217. fi
  1218. # end of 'procmail280/src/misc.c'
  1219. fi
  1220. echo shar: End of archive 7 \(of 11\).
  1221. cp /dev/null ark7isdone
  1222. MISSING=""
  1223. for I in 1 2 3 4 5 6 7 8 9 10 11 ; do
  1224.     if test ! -f ark${I}isdone ; then
  1225.     MISSING="${MISSING} ${I}"
  1226.     fi
  1227. done
  1228. if test "${MISSING}" = "" ; then
  1229.     echo You have unpacked all 11 archives.
  1230.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1231. else
  1232.     echo You still need to unpack the following archives:
  1233.     echo "        " ${MISSING}
  1234. fi
  1235. ##  End of shell archive.
  1236. exit 0
  1237. -- 
  1238. Sincerely,                                  berg@pool.informatik.rwth-aachen.de
  1239.            Stephen R. van den Berg (AKA BuGless).    berg@physik.tu-muenchen.de
  1240.  
  1241. "Be spontaneous!"
  1242.  
  1243. exit 0 # Just in case...
  1244.