home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume33 / mailagnt / part10 < prev    next >
Encoding:
Text File  |  1992-11-20  |  54.6 KB  |  1,832 lines

  1. Newsgroups: comp.sources.misc
  2. From: ram@eiffel.com (Raphael Manfredi)
  3. Subject:  v33i102:  mailagent - Rule Based Mail Filtering, Part10/17
  4. Message-ID: <1992Nov20.230408.26327@sparky.imd.sterling.com>
  5. X-Md4-Signature: b826138ad1dd7510dfb9c4ab4c3a8e03
  6. Date: Fri, 20 Nov 1992 23:04:08 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: ram@eiffel.com (Raphael Manfredi)
  10. Posting-number: Volume 33, Issue 102
  11. Archive-name: mailagent/part10
  12. Environment: Perl, Sendmail, UNIX
  13.  
  14. #! /bin/sh
  15. # This is a shell archive.  Remove anything before this line, then feed it
  16. # into a shell via "sh file" or similar.  To overwrite existing files,
  17. # type "sh file -c".
  18. # Contents:  agent/filter/hash.c agent/maildist.SH agent/mailpatch.SH
  19. #   agent/pl/lexical.pl agent/pl/queue_mail.pl agent/pl/sendfile.pl
  20. # Wrapped by kent@sparky on Wed Nov 18 22:42:25 1992
  21. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
  22. echo If this archive is complete, you will see the following message:
  23. echo '          "shar: End of archive 10 (of 17)."'
  24. if test -f 'agent/filter/hash.c' -a "${1}" != "-c" ; then 
  25.   echo shar: Will not clobber existing file \"'agent/filter/hash.c'\"
  26. else
  27.   echo shar: Extracting \"'agent/filter/hash.c'\" \(10157 characters\)
  28.   sed "s/^X//" >'agent/filter/hash.c' <<'END_OF_FILE'
  29. X/*
  30. X
  31. X #    #    ##     ####   #    #           ####
  32. X #    #   #  #   #       #    #          #    #
  33. X ######  #    #   ####   ######          #
  34. X #    #  ######       #  #    #   ###    #
  35. X #    #  #    #  #    #  #    #   ###    #    #
  36. X #    #  #    #   ####   #    #   ###     ####
  37. X
  38. X    Hash table handling (no item ever deleted).
  39. X*/
  40. X
  41. X/*
  42. X * $Id: hash.c,v 2.9 92/07/14 16:48:08 ram Exp $
  43. X *
  44. X *  Copyright (c) 1992, Raphael Manfredi
  45. X *
  46. X *  You may redistribute only under the terms of the GNU General Public
  47. X *  Licence as specified in the README file that comes with dist.
  48. X *
  49. X * $Log:    hash.c,v $
  50. X * Revision 2.9  92/07/14  16:48:08  ram
  51. X * 3.0 beta baseline.
  52. X * 
  53. X */
  54. X
  55. X#include "config.h"
  56. X#include "portable.h"
  57. X#include "hash.h"
  58. X
  59. X#ifndef lint
  60. Xprivate char *rcsid =
  61. X    "$Id: hash.c,v 2.9 92/07/14 16:48:08 ram Exp $";
  62. X#endif
  63. X
  64. Xprivate uint32 hashcode();            /* The hahsing function */
  65. Xprivate int prime();                /* Is a number a prime one? */
  66. Xprivate uint32 nprime();            /* Find next prime number */
  67. X
  68. Xextern char *malloc();                /* Memory allocation */
  69. Xextern char *calloc();                /* Character allocation */
  70. Xextern char *strsave();                /* Save string in memory */
  71. X
  72. Xpublic int ht_create(ht, n)
  73. Xstruct htable *ht;
  74. Xint n;
  75. X{
  76. X    /* Creates an H table to hold 'n' items with descriptor held in 'ht'. The
  77. X     * size of the table is optimized to avoid conflicts and is of course a
  78. X     * prime number. We take the first prime after (5 * n / 4).
  79. X     * The function returns 0 if everything was ok, -1 otherwise.
  80. X     */
  81. X
  82. X    int hsize;            /* Size of created table */
  83. X    char **array;        /* For array creation (keys/values) */
  84. X    
  85. X    hsize = nprime((5 * n) / 4);    /* Table's size */
  86. X
  87. X    array = (char **) calloc(hsize, sizeof(char *));    /* Array of keys */
  88. X    if (array == (char **) 0)
  89. X        return -1;                    /* Malloc failed */
  90. X    ht->h_keys = array;                /* Where array of keys is stored */
  91. X
  92. X    array = (char **) malloc(hsize * sizeof(char *));    /* Array of values */
  93. X    if (array == (char **) 0) {
  94. X        free(ht->h_keys);            /* Free keys array */
  95. X        return -1;                    /* Malloc failed */
  96. X    }
  97. X    ht->h_values = array;            /* Where array of keys is stored */
  98. X
  99. X    ht->h_size = hsize;                /* Size of hash table */
  100. X    ht->h_items = 0;                /* Table is empty */
  101. X
  102. X    return 0;            /* Creation was ok */
  103. X}
  104. X
  105. Xpublic char *ht_value(ht, skey)
  106. Xstruct htable *ht;
  107. Xchar *skey;
  108. X{
  109. X    /* Look for item associated with given key and returns its value.
  110. X     * Return a null pointer if item is not found.
  111. X     */
  112. X    
  113. X    register1 int32 key;        /* Hash code associated with string key */
  114. X    register2 int32 pos;        /* Position in H table */
  115. X    register3 int32 hsize;        /* Size of H table */
  116. X    register4 char **hkeys;        /* Array of keys */
  117. X    register5 int32 try = 0;    /* Count number of attempts */
  118. X    register6 int32 inc;        /* Loop increment */
  119. X
  120. X    /* Initializations */
  121. X    hsize = ht->h_size;
  122. X    hkeys = ht->h_keys;
  123. X    key = hashcode(skey);
  124. X
  125. X    /* Jump from one hashed position to another until we find the value or
  126. X     * go to an empty entry or reached the end of the table.
  127. X     */
  128. X    inc = 1 + (key % (hsize - 1));
  129. X    for (pos = key % hsize; try < hsize; try++, pos = (pos + inc) % hsize) {
  130. X        if (hkeys[pos] == (char *) 0)
  131. X            break;
  132. X        else if (0 == strcmp(hkeys[pos], skey))
  133. X            return ht->h_values[pos];
  134. X    }
  135. X
  136. X    return (char *) 0;            /* Item was not found */
  137. X}
  138. X
  139. Xpublic char *ht_put(ht, skey, val)
  140. Xstruct htable *ht;
  141. Xchar *skey;
  142. Xchar *val;
  143. X{
  144. X    /* Puts string held at 'val' tagged with key 'key' in H table 'ht'. If
  145. X     * insertion was successful, the address of the value is returned and the
  146. X     * value is copied in the array. Otherwise, return a null pointer.
  147. X     */
  148. X
  149. X    register1 int32 key;        /* Hash code associated with string key */
  150. X    register2 int32 pos;        /* Position in H table */
  151. X    register3 int32 hsize;        /* Size of H table */
  152. X    register4 char **hkeys;        /* Array of keys */
  153. X    register5 int32 try = 0;    /* Records number of attempts */
  154. X    register6 int32 inc;        /* Loop increment */
  155. X
  156. X    /* If the table is full at 75%, resize it to avoid performance degradations.
  157. X     * The extension updates the htable structure in place.
  158. X     */
  159. X    hsize = ht->h_size;
  160. X    if ((ht->h_items * 4) / 3 > hsize) {
  161. X        ht_xtend(ht);
  162. X        hsize = ht->h_size;
  163. X    }
  164. X    hkeys = ht->h_keys;
  165. X    key = hashcode(skey);
  166. X
  167. X    /* Jump from one hashed position to another until we find a free entry or
  168. X     * we reached the end of the table.
  169. X     */
  170. X    inc = 1 + (key % (hsize - 1));
  171. X    for (pos = key % hsize; try < hsize; try++, pos = (pos + inc) % hsize) {
  172. X        if (hkeys[pos] == (char *) 0) {            /* Found a free location */
  173. X            hkeys[pos] = strsave(skey);            /* Record item */
  174. X            ht->h_values[pos] = strsave(val);    /* Save string */
  175. X            ht->h_items++;                /* One more item */
  176. X            return ht->h_values[pos];
  177. X        } else if (0 == strcmp(hkeys[pos], skey))
  178. X            fatal("H table key conflict: %s", skey);
  179. X    }
  180. X
  181. X    return (char *) 0;        /* We were unable to insert item */
  182. X}
  183. X
  184. Xpublic char *ht_force(ht, skey, val)
  185. Xstruct htable *ht;
  186. Xchar *skey;
  187. Xchar *val;
  188. X{
  189. X    /* Replace value tagged with key 'key' in H table 'ht' with 'val'. If
  190. X     * insertion was successful, the address of the value is returned and the
  191. X     * value is copied in the array. Otherwise, return a null pointer (if table
  192. X     * is full and item was not found). The previous value is freed if any.
  193. X     * Otherwise, simply add the item in the table.
  194. X     */
  195. X
  196. X    register1 int32 key;        /* Hash code associated with string key */
  197. X    register2 int32 pos;        /* Position in H table */
  198. X    register3 int32 hsize;        /* Size of H table */
  199. X    register4 char **hkeys;        /* Array of keys */
  200. X    register5 int32 try = 0;    /* Records number of attempts */
  201. X    register6 int32 inc;        /* Loop increment */
  202. X
  203. X    /* If the table is full at 75%, resize it to avoid performance degradations.
  204. X     * The extension updates the htable structure in place.
  205. X     */
  206. X    hsize = ht->h_size;
  207. X    if ((ht->h_items * 4) / 3 > hsize) {
  208. X        ht_xtend(ht);
  209. X        hsize = ht->h_size;
  210. X    }
  211. X    hkeys = ht->h_keys;
  212. X    key = hashcode(skey);
  213. X
  214. X    /* Jump from one hashed position to another until we find a free entry or
  215. X     * we reached the end of the table.
  216. X     */
  217. X    inc = 1 + (key % (hsize - 1));
  218. X    for (pos = key % hsize; try < hsize; try++, pos = (pos + inc) % hsize) {
  219. X        if (hkeys[pos] == (char *) 0) {            /* Found a free location */
  220. X            hkeys[pos] = strsave(skey);            /* Record item */
  221. X            ht->h_values[pos] = strsave(val);    /* Save string */
  222. X            ht->h_items++;                        /* One more item */
  223. X            return ht->h_values[pos];
  224. X        } else if (0 == strcmp(hkeys[pos], skey)) {
  225. X            if (ht->h_values[pos])                /* If old value */
  226. X                free(ht->h_values[pos]);        /* Free it */
  227. X            ht->h_values[pos] = strsave(val);    /* Save string */
  228. X            return ht->h_values[pos];
  229. X        }
  230. X    }
  231. X
  232. X    return (char *) 0;        /* We were unable to insert item */
  233. X}
  234. X
  235. Xpublic int ht_xtend(ht)
  236. Xstruct htable *ht;
  237. X{
  238. X    /* The H table 'ht' is full and needs resizing. We add 50% of old size and
  239. X     * copy the old table in the new one, before freeing the old one. Note that
  240. X     * h_create multiplies the number we give by 5/4, so 5/4*3/2 yields ~2, i.e.
  241. X     * the final size will be the double of the previous one (modulo next prime
  242. X     * number).
  243. X     * Return 0 if extension was ok, -1 otherwise.
  244. X     */
  245. X
  246. X    register1 int32 size;            /* Size of old H table */
  247. X    register2 char **key;            /* To loop over keys */
  248. X    register3 char **val;            /* To loop over values */
  249. X    struct htable new_ht;
  250. X
  251. X    size = ht->h_size;
  252. X    if (-1 == ht_create(&new_ht, size + (size / 2)))
  253. X        return -1;        /* Extension of H table failed */
  254. X
  255. X    key = ht->h_keys;                /* Start of array of keys */
  256. X    val = ht->h_values;                /* Start of array of values */
  257. X
  258. X    /* Now loop over the whole table, inserting each item in the new one */
  259. X
  260. X    for (; size > 0; size--, key++, val++)
  261. X        if ((char *) 0 == ht_put(&new_ht, *key, *val)) {    /* Failed */
  262. X            free(new_ht.h_values);    /* Free new H table */
  263. X            free(new_ht.h_keys);
  264. X            fatal("BUG in ht_xtend");
  265. X        }
  266. X
  267. X    /* Free old H table and set H table descriptor */
  268. X    free(ht->h_values);                /* Free in allocation order */
  269. X    free(ht->h_keys);                /* To make free happy (coalescing) */
  270. X    bcopy(&new_ht, ht, sizeof(struct htable));
  271. X
  272. X    return 0;        /* Extension was ok */
  273. X}
  274. X
  275. Xpublic int ht_start(ht)
  276. Xstruct htable *ht;
  277. X{
  278. X    /* Start iteration over H table. Return 0 if ok, -1 if the table is empty */
  279. X
  280. X    register1 int32 hpos;        /* Index in H table */
  281. X    register2 char **hkeys;        /* Array of keys */
  282. X    register3 int32 hsize;        /* Size of H table */
  283. X
  284. X    /* Initializations */
  285. X    hpos = 0;
  286. X    hkeys = ht->h_keys;
  287. X    hsize = ht->h_size;
  288. X
  289. X    /* Stop at first non-null key */
  290. X    for (; hpos < hsize; hpos++, hkeys++)
  291. X        if (*hkeys != (char *) 0)
  292. X            break;
  293. X    ht->h_pos = hpos;            /* First non-null postion */
  294. X
  295. X    return (hpos < hsize) ? 0 : -1;
  296. X}
  297. X
  298. Xpublic int ht_next(ht)
  299. Xstruct htable *ht;
  300. X{
  301. X    /* Advance to next item in H table, if possible. Return 0 if there is a
  302. X     * next item, -1 otherwise.
  303. X     */
  304. X
  305. X    register1 int32 hpos;        /* Index in H table */
  306. X    register2 char **hkeys;        /* Array of keys */
  307. X    register3 int32 hsize;        /* Size of H table */
  308. X
  309. X    /* Initializations */
  310. X    hpos = ht->h_pos + 1;
  311. X    hkeys = ht->h_keys + hpos;
  312. X    hsize = ht->h_size;
  313. X
  314. X    /* Stop at first non-null key */
  315. X    for (; hpos < hsize; hpos++, hkeys++)
  316. X        if (*hkeys != (char *) 0)
  317. X            break;
  318. X    ht->h_pos = hpos;            /* Next non-null postion */
  319. X
  320. X    return (hpos < hsize) ? 0 : -1;
  321. X}
  322. X
  323. Xpublic char *ht_ckey(ht)
  324. Xstruct htable *ht;
  325. X{
  326. X    /* Return pointer on current item's key */
  327. X
  328. X    return ht->h_keys[ht->h_pos];
  329. X}
  330. X
  331. Xpublic char *ht_cvalue(ht)
  332. Xstruct htable *ht;
  333. X{
  334. X    /* Return pointer on current item's value */
  335. X
  336. X    return ht->h_values[ht->h_pos];
  337. X}
  338. X
  339. Xpublic int ht_count(ht)
  340. Xstruct htable *ht;
  341. X{
  342. X    /* Return the number of items in the H table */
  343. X
  344. X    return ht->h_items;
  345. X}
  346. X
  347. Xprivate uint32 hashcode(s)
  348. Xregister3 char *s;
  349. X{
  350. X    /* Compute the hash code associated with given string s. The magic number
  351. X     * below is the greatest prime lower than 2^23.
  352. X     */
  353. X
  354. X    register1 uint32 hashval = 0;
  355. X    register2 uint32 magic = 8388593;
  356. X
  357. X    while (*s)
  358. X        hashval = ((hashval % magic) << 8) + (unsigned int) *s++;
  359. X
  360. X    return hashval;
  361. X}
  362. X
  363. Xprivate uint32 nprime(n)
  364. Xregister1 uint32 n;
  365. X{
  366. X    /* Return the closest prime number greater than `n' */
  367. X
  368. X    while (!prime(n))
  369. X        n++;
  370. X
  371. X    return n;
  372. X}
  373. X
  374. Xprivate int prime(n)
  375. Xregister2 uint32 n;
  376. X{
  377. X    /* Return 1 if `n' is a prime number */
  378. X
  379. X    register1 uint32 divisor;
  380. X
  381. X    if (n == 1)
  382. X        return 0;
  383. X    else if (n == 2)
  384. X        return 1;
  385. X    else if (n % 2) {
  386. X        for (
  387. X            divisor = 3; 
  388. X            divisor * divisor <= n;
  389. X            divisor += 2
  390. X        )
  391. X            if (0 == (n % divisor))
  392. X                return 0;
  393. X        return 1;
  394. X    }
  395. X    return 0;
  396. X}
  397. X
  398. END_OF_FILE
  399.   if test 10157 -ne `wc -c <'agent/filter/hash.c'`; then
  400.     echo shar: \"'agent/filter/hash.c'\" unpacked with wrong size!
  401.   fi
  402.   # end of 'agent/filter/hash.c'
  403. fi
  404. if test -f 'agent/maildist.SH' -a "${1}" != "-c" ; then 
  405.   echo shar: Will not clobber existing file \"'agent/maildist.SH'\"
  406. else
  407.   echo shar: Extracting \"'agent/maildist.SH'\" \(9200 characters\)
  408.   sed "s/^X//" >'agent/maildist.SH' <<'END_OF_FILE'
  409. Xcase $CONFIG in
  410. X'')
  411. X    if test ! -f config.sh; then
  412. X        ln ../config.sh . || \
  413. X        ln ../../config.sh . || \
  414. X        ln ../../../config.sh . || \
  415. X        (echo "Can't find config.sh."; exit 1)
  416. X    fi 2>/dev/null
  417. X    . config.sh
  418. X    ;;
  419. Xesac
  420. Xcase "$0" in
  421. X*/*) cd `expr X$0 : 'X\(.*\)/'` ;;
  422. Xesac
  423. Xecho "Extracting agent/maildist (with variable substitutions)"
  424. X$spitshell >maildist <<!GROK!THIS!
  425. X# feed this into perl
  426. X    eval "exec perl -S \$0 \$*"
  427. X        if \$running_under_some_shell;
  428. X
  429. X# $Id: maildist.SH,v 2.9 92/07/14 16:48:51 ram Exp $
  430. X#
  431. X#  Copyright (c) 1991, 1992, Raphael Manfredi
  432. X#
  433. X#  You may redistribute only under the terms of the GNU General Public
  434. X#  Licence as specified in the README file that comes with dist.
  435. X#
  436. X# $Log:    maildist.SH,v $
  437. X# Revision 2.9  92/07/14  16:48:51  ram
  438. X# 3.0 beta baseline.
  439. X# 
  440. X
  441. X\$mversion = '$VERSION';
  442. X\$patchlevel = '$PATCHLEVEL';
  443. X!GROK!THIS!
  444. X
  445. X$spitshell >>maildist <<'!NO!SUBS!'
  446. X
  447. X$prog_name = $0;                # Who I am
  448. X$prog_name =~ s|^.*/(.*)|$1|;    # Keep only base name
  449. X
  450. Xdo read_config();    # First, read configuration file (in ~/.mailagent)
  451. X
  452. X# take job number and command from environment
  453. X# (passed by mailagent)
  454. X$jobnum = $ENV{'jobnum'};
  455. X$fullcmd = $ENV{'fullcmd'};
  456. X$pack = $ENV{'pack'};
  457. X$path = $ENV{'path'};
  458. X
  459. Xdo read_dist();        # Read distributions
  460. X
  461. X$dest = shift;        # Who should the system be sent to
  462. X$system = shift;    # Which system
  463. X$version = shift;    # Which version it is
  464. X
  465. X# A single '-' as first argument stands for return path
  466. X$dest = $path if $dest eq '-';
  467. X
  468. X# A single '-' for version means "highest available" version
  469. X$version = $Version{$system} if $version eq '-' || $version eq '';
  470. X
  471. X# Full program's name for H table access
  472. X$pname = $system . "|" . $version;
  473. X
  474. X$maillist = "To obtain a list of what is available, send me the following mail:
  475. X
  476. X    Subject: Command
  477. X    @SH maillist $path
  478. X        ^ note the l";
  479. X
  480. Xif (!$System{$system}) {
  481. X    open(MAILER, "|/usr/lib/sendmail -odq -t");
  482. X    print MAILER
  483. X"To: $path
  484. XBcc: $cf'user
  485. XSubject: No program called $system
  486. XX-Mailer: mailagent [version $mversion PL$patchlevel]
  487. X
  488. XI don't know how to send a program called \"$system\".  Sorry.
  489. X
  490. X$maillist
  491. X
  492. XIf $cf'name can figure out what you meant, you'll get the program anyway.
  493. X
  494. X-- $prog_name speaking for $cf'user
  495. X";
  496. X    close MAILER;
  497. X    do add_log("FAILED (UNKNOWN SYSTEM)") if ($loglvl > 1);
  498. X    exit 0;
  499. X}
  500. X
  501. Xif (!$Program{$pname}) {
  502. X    open(MAILER, "|/usr/lib/sendmail -odq -t");
  503. X    print MAILER
  504. X"To: $path
  505. XBcc: $cf'user
  506. XSubject: No version $version for $system
  507. XX-Mailer: mailagent [version $mversion PL$patchlevel]
  508. X
  509. XI don't know how to send version $version of $system.  Sorry.
  510. X
  511. X$maillist
  512. X
  513. XIf $cf'name can figure out what you meant, you'll get the program anyway.
  514. X
  515. X-- $prog_name speaking for $cf'user
  516. X";
  517. X    close MAILER;
  518. X    do add_log("FAILED (BAD VERSION NUMBER)") if ($loglvl > 1);
  519. X    exit 0;
  520. X}
  521. X
  522. X# Has the user made a request for an old version (patch only) ?
  523. Xif ($Patch_only{$pname}) {
  524. X    # It is required that patch only systems have a version number
  525. X    do abort("old system has no version number") if $version eq '';
  526. X    open(MAILER, "|/usr/lib/sendmail -odq -t");
  527. X    print MAILER
  528. X"To: $path
  529. XBcc: $cf'user
  530. XSubject: System $system $version is obsolete
  531. XX-Mailer: mailagent [version $mversion PL$patchlevel]
  532. X
  533. XI can't send you version $version of $system. Sorry.
  534. X
  535. XThis version appears to be an old one, and only patches are available.
  536. XThe up-to-date version for $system is $Version{$system}.
  537. X
  538. X$maillist
  539. X
  540. XIf $cf'name can figure out what you meant, he may send you the latest version.
  541. X
  542. X-- $prog_name speaking for $cf'user
  543. X";
  544. X    close MAILER;
  545. X    do add_log("FAILED (PATCH ONLY VERSION)") if ($loglvl > 1);
  546. X    exit 0;
  547. X}
  548. X
  549. X# If the request is not the most recent version, warn the user.
  550. Xif ($version < $Version{$system}) {
  551. X    open(MAILER, "|/usr/lib/sendmail -odq -t");
  552. X    print MAILER
  553. X"To: $path
  554. XBcc: $cf'user
  555. XSubject: Version $version of $system is an old one
  556. XX-Mailer: mailagent [version $mversion PL$patchlevel]
  557. X
  558. XYou asked for version $version of $system.
  559. X
  560. XThis version appears to be an old one, but it is sill available, and
  561. XI am currently processing your request. However, I wanted to let you
  562. Xknow that the up-to-date version for $system is $Version{$system}.
  563. X
  564. X$maillist
  565. X
  566. XUnless you receive an error message telling you otherwise, I am sending
  567. Xyou version $version of $system. You may also request for the new version
  568. Xright now if you wish.
  569. X
  570. X-- $prog_name speaking for $cf'user
  571. X";
  572. X    close MAILER;
  573. X    do add_log("MSG old version still available") if ($loglvl > 8);
  574. X}
  575. X
  576. X# Create a temporary directory
  577. X$tmp = "$cf'tmpdir/dmd$$";
  578. Xmkdir($tmp, 0700);
  579. X
  580. X# Need to unarchive the distribution
  581. Xif ($Archived{$pname}) {
  582. X    # Create a temporary directory for distribution
  583. X    $tmp_loc = "$cf'tmpdir/dmdl$$";
  584. X    mkdir($tmp_loc, 0700);
  585. X    $location =
  586. X        do unpack($Location{$pname}, $tmp_loc, $Compressed{$pname});
  587. X} else {
  588. X    $location = $Location{$pname};
  589. X}
  590. X
  591. X# Go to top-level directory
  592. Xchdir "$location" ||
  593. X    do abort("cannot go to $location");
  594. X
  595. X# We are now in the place. Look for a MANIFEST file. If none, we will
  596. X# send *everything* held, RCS sub-directories and executable/object files
  597. X# excepted.
  598. X
  599. X$manifest = '';
  600. X$tmp_list = '';
  601. X
  602. Xif (-f 'MANIFEST') {
  603. X    $manifest = "$location/MANIFEST";
  604. X} else {
  605. X    $tmp_list = "$cf'tmpdir/mdlist$$";
  606. X    open(FIND, "find . -type f -print | sort |") ||
  607. X        do abort("cannot run find");
  608. X    open(LIST, ">$tmp_list") ||
  609. X        do abort("cannot create $tmp_list");
  610. X    while (<FIND>) {
  611. X        chop;
  612. X        s|\./||;
  613. X        next if (m|^U/| && -f '.package');    # Skip units if meta-configured
  614. X        next if m|^RCS/|;            # Skip RCS files
  615. X        next if m|/RCS/|;
  616. X        next if m|,v$|;
  617. X        next if m|bugs/|;            # Skip bugs files (patches and al.)
  618. X        next if m|^\.#|;            # Skip [marked for deletion] files
  619. X        next if m|/\.#|;
  620. X        next if m|\.o$|;            # Skip object files
  621. X        next if m|core$|;            # Skip core files
  622. X        next if (-x $_ && -B $_);    # Skip binaries
  623. X        print LIST $_,"\n";            # Keep that file
  624. X    }
  625. X    close FIND;
  626. X    close LIST;
  627. X    $manifest = $tmp_list;
  628. X}
  629. X
  630. Xdo add_log("manifest is in $manifest") if ($loglvl > 19);
  631. Xchdir $tmp || do abort("cannot chdir to $tmp");
  632. X
  633. X# Now for each file in manifest, look if there is an
  634. X# RCS file associated with it. If so, check out either
  635. X# the 'lastpat' version or the highest version on the
  636. X# default branch, provided that the file does not exists
  637. X# in checked-out form. Otherwise, only run co if 'lastpat'
  638. X# is defined.
  639. Xopen(MANI, $manifest) || do abort("cannot open $manifest");
  640. Xwhile (<MANI>) {
  641. X    next if /^--/;
  642. X    s|^\s*||;                        # Remove leading spaces
  643. X    ($file,$foo) = split;            # Save filename, discard comments
  644. X    next if (-d "$location/$file");    # Skip directories
  645. X    next if ($file =~ /^\s*$/);        # Skip blank lines
  646. X    # Extract dirname and basename
  647. X    ($dir, $base) = ('', $file) unless ($dir, $base) = ($file =~ m|(.*/)(.*)|);
  648. X    $logmsg = '';                # String to add to log message
  649. X    $rcsfile = 'blurfl';
  650. X    $rcsfile = "$location/$file,v" if (-f "$location/$file,v");
  651. X    $rcsfile = "$location/${dir}RCS/$base,v"
  652. X        if (-f "$location/${dir}RCS/$base,v");
  653. X    next unless -f "$location/$file" || -f "$rcsfile";    # Skip unexisting files
  654. X    do makedir($dir) unless $dir eq '';
  655. X    open(COPY, ">$file") || do abort("cannot create $file");
  656. X    if ($rcsfile ne '') {
  657. X        $rlog = `rlog $rcsfile 2>&1`;
  658. X        ($revs) = ($rlog =~ /lastpat: (\d+)/);
  659. X        if (!$revs) {
  660. X            # Symbol 'lastpat' is not defined
  661. X            # If file exists, open it. Otherwise, run co
  662. X            if (-f "$location/$file") {
  663. X                $logmsg = " (lastpat undefined)";
  664. X                $origfile = "$location/$file";
  665. X                open(FILE, $origfile) ||
  666. X                    do abort("cannot open $origfile");
  667. X            } else {
  668. X                $logmsg = " (co but no lastpat)";
  669. X                $origfile = $rcsfile;
  670. X                open(FILE, "co -q -p $rcsfile |") ||
  671. X                    do abort("cannot run co on $rcsfile");
  672. X            }
  673. X        } else {
  674. X            # Symbol 'lastpat' is defined
  675. X            $logmsg = " (co lastpat)";
  676. X            $origfile = $rcsfile;
  677. X            open(FILE, "co -q -p -rlastpat $rcsfile |") ||
  678. X                do abort("cannot run co on $rcsfile");
  679. X        }
  680. X    } else {
  681. X        $origfile = "$location/$file";
  682. X        open(FILE, "$location/$file") ||
  683. X            do abort("cannot open $location/$file");
  684. X    }
  685. X    while (<FILE>) {
  686. X        s|$|;      # Remove locker mark
  687. X        (print COPY) || do abort("ran out of disk space");
  688. X    }
  689. X    close FILE;
  690. X    close COPY;
  691. X    do add_log("copied $file$logmsg") if ($loglvl > 19);
  692. X
  693. X    # If file is executable, change its permissions
  694. X    if (-x $origfile) {
  695. X        chmod 0755, $file;
  696. X    } else {
  697. X        chmod 0644, $file;
  698. X    }
  699. X}
  700. X
  701. X$subject = "$system";
  702. X$subject .= " $version" if $version ne '0';
  703. X$subject .= " package";
  704. Xdo sendfile($dest, $tmp, $pack, $subject);
  705. Xdo clean_tmp();
  706. X
  707. Xexit 0;        # Ok
  708. X
  709. Xsub clean_tmp {
  710. X    # Do not stay in the directories we are removing...
  711. X    chdir $cf'home;
  712. X    if ($tmp ne '') {
  713. X        system '/bin/rm', '-rf', $tmp;
  714. X        do add_log("removed dir $tmp") if ($loglvl > 19);
  715. X    }
  716. X    if ($Archived{$pname}) {
  717. X        system '/bin/rm', '-rf', $tmp_loc;
  718. X        do add_log("removed dir $tmp_loc") if ($loglvl > 19);
  719. X    }
  720. X    unlink $tmp_list if $tmp_list ne '';
  721. X}
  722. X
  723. X# Emergency exit with clean-up
  724. Xsub abort {
  725. X    local($reason) = shift(@_);        # Why we are exiting
  726. X    do clean_tmp();
  727. X    do fatal($reason);
  728. X}
  729. X
  730. X!NO!SUBS!
  731. X$grep -v '^;#' pl/makedir.pl >>maildist
  732. X$grep -v '^;#' pl/fatal.pl >>maildist
  733. X$grep -v '^;#' pl/add_log.pl >>maildist
  734. X$grep -v '^;#' pl/read_conf.pl >>maildist
  735. X$grep -v '^;#' pl/unpack.pl >>maildist
  736. X$grep -v '^;#' pl/sendfile.pl >>maildist
  737. X$grep -v '^;#' pl/distribs.pl >>maildist
  738. Xchmod 755 maildist
  739. X$eunicefix maildist
  740. END_OF_FILE
  741.   if test 9200 -ne `wc -c <'agent/maildist.SH'`; then
  742.     echo shar: \"'agent/maildist.SH'\" unpacked with wrong size!
  743.   fi
  744.   chmod +x 'agent/maildist.SH'
  745.   # end of 'agent/maildist.SH'
  746. fi
  747. if test -f 'agent/mailpatch.SH' -a "${1}" != "-c" ; then 
  748.   echo shar: Will not clobber existing file \"'agent/mailpatch.SH'\"
  749. else
  750.   echo shar: Extracting \"'agent/mailpatch.SH'\" \(8849 characters\)
  751.   sed "s/^X//" >'agent/mailpatch.SH' <<'END_OF_FILE'
  752. Xcase $CONFIG in
  753. X'')
  754. X    if test ! -f config.sh; then
  755. X        ln ../config.sh . || \
  756. X        ln ../../config.sh . || \
  757. X        ln ../../../config.sh . || \
  758. X        (echo "Can't find config.sh."; exit 1)
  759. X    fi 2>/dev/null
  760. X    . config.sh
  761. X    ;;
  762. Xesac
  763. Xcase "$0" in
  764. X*/*) cd `expr X$0 : 'X\(.*\)/'` ;;
  765. Xesac
  766. Xecho "Extracting agent/mailpatch (with variable substitutions)"
  767. X$spitshell >mailpatch <<!GROK!THIS!
  768. X# feed this into perl
  769. X    eval "exec perl -S \$0 \$*"
  770. X        if \$running_under_some_shell;
  771. X
  772. X# $Id: mailpatch.SH,v 2.9 92/07/14 16:49:00 ram Exp $
  773. X#
  774. X#  Copyright (c) 1991, 1992, Raphael Manfredi
  775. X#
  776. X#  You may redistribute only under the terms of the GNU General Public
  777. X#  Licence as specified in the README file that comes with dist.
  778. X#
  779. X# $Log:    mailpatch.SH,v $
  780. X# Revision 2.9  92/07/14  16:49:00  ram
  781. X# 3.0 beta baseline.
  782. X# 
  783. X
  784. X\$cat = '$cat';
  785. X\$zcat = '$zcat';
  786. X\$mversion = '$VERSION';
  787. X\$patchlevel = '$PATCHLEVEL';
  788. X!GROK!THIS!
  789. X$spitshell >>mailpatch <<'!NO!SUBS!'
  790. X
  791. X$prog_name = $0;                # Who I am
  792. X$prog_name =~ s|^.*/(.*)|$1|;    # Keep only base name
  793. X
  794. Xdo read_config();    # First, read configuration file (in ~/.mailagent)
  795. X
  796. X# take job number and command from environment
  797. X# (passed by mailagent)
  798. X$jobnum = $ENV{'jobnum'};
  799. X$fullcmd = $ENV{'fullcmd'};
  800. X$pack = $ENV{'pack'};
  801. X$path = $ENV{'path'};
  802. X
  803. Xdo read_dist();            # Read distributions
  804. X
  805. X$dest = shift;            # Who should the patches be sent to
  806. X$system = shift;        # Which system do patches belong
  807. X$version = shift;        # Which version it is
  808. X
  809. X# A single '-' as first argument stands for return path
  810. X$dest = $path if $dest eq '-';
  811. X
  812. X# A single '-' for version means "highest available" version.
  813. X$version = $Version{$system} if $version eq '-';
  814. X
  815. X# Full name of system for H table access
  816. X$pname = $system . "|" . $version;
  817. X
  818. X$maillist = "To obtain a list of what is available, send me the following mail:
  819. X
  820. X    Subject: Command
  821. X    @SH maillist $path
  822. X        ^ note the l";
  823. X
  824. Xif (!$System{$system}) {
  825. X    open(MAILER, "|/usr/lib/sendmail -odq -t");
  826. X    print MAILER
  827. X"To: $path
  828. XBcc: $cf'user
  829. XSubject: No program called $system
  830. XX-Mailer: mailagent [version $mversion PL$patchlevel]
  831. X
  832. XI don't know how to send patches for a program called $system.  Sorry.
  833. X
  834. X$maillist
  835. X
  836. XIf $cf'name can figure out what you meant, you'll get the patches anyway.
  837. X
  838. X-- mailpatch speaking for $cf'user
  839. X";
  840. X    close MAILER;
  841. X    do add_log("FAILED (UNKNOWN SYSTEM)") if ($loglvl > 1);
  842. X    exit 0;
  843. X}
  844. X
  845. Xif (!$Program{$pname}) {
  846. X    open(MAILER, "|/usr/lib/sendmail -odq -t");
  847. X    print MAILER
  848. X"To: $path
  849. XBcc: $cf'user
  850. XSubject: No patches for $system version $version
  851. XX-Mailer: mailagent [version $mversion PL$patchlevel]
  852. X
  853. XI don't know how to send patches for version $version of $system.  Sorry.";
  854. X    if ($Version{$system} ne '') {
  855. X        print MAILER "
  856. X
  857. X[The highest version for $system is $Version{$system}.]";
  858. X        do add_log("MSG highest version is $Version{$system}")
  859. X            if ($loglvl > 11);
  860. X    } else {
  861. X        print MAILER "
  862. X
  863. X[There is no version number for $system.]";
  864. X        do add_log("MSG no version number") if ($loglvl > 11);
  865. X    }
  866. X    print MAILER "
  867. X
  868. X$maillist
  869. X
  870. XIf $cf'name can figure out what you meant, you'll get the patches anyway.
  871. X
  872. X-- mailpatch speaking for $cf'user
  873. X";
  874. X    close MAILER;
  875. X    do add_log("FAILED (BAD SYSTEM NUMBER)") if ($loglvl > 1);
  876. X    exit 0;
  877. X}
  878. X
  879. Xif (!($Maintained{$pname} || $Patches{$pname})) {
  880. X    open(MAILER, "|/usr/lib/sendmail -odq -t");
  881. X    print MAILER
  882. X"To: $path
  883. XBcc: $cf'user
  884. XSubject: $system version $version is not maintained
  885. XX-Mailer: mailagent [version $mversion PL$patchlevel]
  886. X
  887. XI can't send you patches for version $version of $system, because this code
  888. Xis not maintained by $cf'name. There are no official patches available either...
  889. X
  890. X$maillist
  891. X
  892. XAnyway, if you discover a bug or have remarks about \"$system\", please
  893. Xlet me know. Better, if you know where patches for $system can be found,
  894. Xwell... you have my e-mail address ! :->
  895. X
  896. X-- mailpatch speaking for $cf'user
  897. X";
  898. X    close MAILER;
  899. X    do add_log("FAILED (NOT MAINTAINED)") if ($loglvl > 1);
  900. X    exit 0;
  901. X}
  902. X
  903. X# Create a temporary directory
  904. X$tmp = "$cf'tmpdir/dmp$$";
  905. Xmkdir($tmp, 0700) || do fatal("cannot create $tmp");
  906. X
  907. X# Need to unarchive the distribution
  908. Xif ($Archived{$pname}) {
  909. X    # Create a temporary directory for distribution
  910. X    $tmp_loc = "$cf'tmpdir/dmpl$$";
  911. X    mkdir($tmp_loc, 0700) || do fatal("cannot create $tmp_loc");
  912. X    $Location{$pname} =
  913. X        do unpack($Location{$pname}, $tmp_loc, $Compressed{$pname});
  914. X}
  915. X
  916. X# Go to bugs sub-directory. It is possible to ask for patches for
  917. X# old systems. Such systems are identified by having the `patches'
  918. X# field from the distrib file set to "old". In that case, patches
  919. X# are taken from a bugs-version directory. Version has to be non null.
  920. X
  921. Xif ($Patch_only{$pname}) {
  922. X    do abort("old system has no version number") if $version eq '';
  923. X    chdir "$Location{$pname}/bugs-$version" ||
  924. X        do abort("cannot go to $Location{$pname}/bugs-$version");
  925. X    # There is no patchlevel to look at -- compute by hand.
  926. X    for ($maxnum = 1; ; $maxnum++) {
  927. X        last unless -f "patch$maxnum" || -f "patch$maxnum.Z";
  928. X    }
  929. X    $maxnum--;        # We've gone too far
  930. X} else {
  931. X    chdir "$Location{$pname}/bugs" ||
  932. X        do abort("cannot go to $Location{$pname}/bugs");
  933. X    open(PATCHLEVEL, "../patchlevel.h") ||
  934. X        do abort("cannot open patchlevel.h");
  935. X    $maxnum = 0;
  936. X    while (<PATCHLEVEL>) {
  937. X        if (/.*PATCHLEVEL[ \t]*(\d+)/) {
  938. X            $maxnum = $1;
  939. X            last;
  940. X        }
  941. X    }
  942. X    close PATCHLEVEL;
  943. X}
  944. X
  945. Xif (!$maxnum) {
  946. X    # If we get here, it must be for one of our systems. Indeed,
  947. X    # if we do not have any patches for a third party program, there
  948. X    # should be a "no" in the patches field of distribution file, and
  949. X    # in that case an error would have been reported before.
  950. X    open(MAILER, "|/usr/lib/sendmail -odq -t");
  951. X    print MAILER
  952. X"To: $path
  953. XBcc: $cf'user
  954. XSubject: No patches yet for $system version $version
  955. XX-Mailer: mailagent [version $mversion PL$patchlevel]
  956. X
  957. XThere are no patches (yet) for $system version $version. Sorry.
  958. X
  959. X-- mailpatch speaking for $cf'user
  960. X";
  961. X    close MAILER;
  962. X    do add_log("FAILED (NO PATCHES YET)") if ($loglvl > 1);
  963. X    do clean_tmp();
  964. X    exit 0;
  965. X}
  966. X
  967. X$patchlist = do rangeargs($maxnum, @ARGV);    # Generate patch list
  968. X
  969. Xif (! ($patchlist =~ /\d/)) {
  970. X    open(MAILER, "|/usr/lib/sendmail -odq -t");
  971. X    print MAILER
  972. X"To: $path
  973. XBcc: $cf'user
  974. XSubject: Invalid patch request for $system $version
  975. XX-Mailer: mailagent [version $mversion PL$patchlevel]
  976. X";
  977. X    if ($Patches{$pname}) {
  978. X        print MAILER "
  979. XThe highest patch I have for $system version $version is #$maxnum.";
  980. X    } else {
  981. X        print MAILER "
  982. XThe latest patch for $system version $version is #$maxnum.";
  983. X    }
  984. X    print MAILER "
  985. X(Your command was: $fullcmd)";
  986. X    if ($Version{$system} > $version) {
  987. X        print MAILER "
  988. X
  989. XPlease note that the latest version for $system is $Version{$system}.
  990. X
  991. X$maillist";
  992. X    }
  993. X    print MAILER "
  994. X
  995. X-- mailpatch speaking for $cf'user
  996. X";
  997. X    close MAILER;
  998. X    do add_log("FAILED (INVALID PATCH LIST)") if ($loglvl > 1);
  999. X    do clean_tmp();
  1000. X    exit 0;
  1001. X}
  1002. X
  1003. X@numbers = split(/ /,$patchlist);
  1004. X
  1005. Xforeach $num (@numbers) {
  1006. X    $patchfile = "patch" . $num;    # Base name of the patch
  1007. X    if (-f $patchfile) {            # Normal patch
  1008. X        $append = $cat;
  1009. X        $extent = '';
  1010. X    } elsif (-f "$patchfile.Z") {    # Compressed patch
  1011. X        if ($zcat ne 'zcat') {        # Zcat found by Configure
  1012. X            $append = $zcat;
  1013. X            $extent = '.Z';
  1014. X        } else {
  1015. X            do add_log("ERROR no zcat to uncompress patch #$num ($system)")
  1016. X                if ($loglvl > 5);
  1017. X            next;
  1018. X        }
  1019. X    } else {
  1020. X        do add_log("ERROR no patch #$num ($system)") if ($loglvl > 5);
  1021. X        next;
  1022. X    }
  1023. X    open (TMP, ">$tmp/$patchfile");
  1024. X    if ($Patches{$pname}) {
  1025. X        print TMP "
  1026. XThis is an official patch for $system version $version, please apply it.
  1027. XThe highest patch I have for that version of $system is #$maxnum.";
  1028. X    } else {
  1029. X        print TMP "
  1030. XThe latest patch for $system version $version is #$maxnum.";
  1031. X    }
  1032. X    print TMP "
  1033. X
  1034. X-- mailpatch speaking for $cf'user
  1035. X
  1036. X";
  1037. X    close TMP;
  1038. X    system "$append <$patchfile$extent >>$tmp/$patchfile";
  1039. X    do add_log("copied file $patchfile into $tmp") if ($loglvl > 17);
  1040. X}
  1041. X
  1042. Xif ($#numbers > 0) {
  1043. X    $subject = $#numbers + 1;        # Array count starts at 0
  1044. X    $subject = "$system $version, $subject patches";
  1045. X} else {
  1046. X    $subject = "$system $version patch #$numbers[0]";
  1047. X}
  1048. Xdo sendfile($dest, $tmp, $pack, $subject);
  1049. Xdo clean_tmp();
  1050. X
  1051. Xexit 0;        # Ok
  1052. X
  1053. Xsub clean_tmp {
  1054. X    # Do not stay in the directories we are removing...
  1055. X    chdir $cf'home;
  1056. X    if ($tmp ne '') {
  1057. X        system '/bin/rm', '-rf', $tmp;
  1058. X        do add_log("removed dir $tmp") if ($loglvl > 19);
  1059. X    }
  1060. X    if ($Archived{$pname}) {
  1061. X        system '/bin/rm', '-rf', $tmp_loc;
  1062. X        do add_log("removed dir $tmp_loc") if ($loglvl > 19);
  1063. X    }
  1064. X}
  1065. X
  1066. X# Emergency exit with clean-up
  1067. Xsub abort {
  1068. X    local($reason) = shift(@_);        # Why we are exiting
  1069. X    do clean_tmp();
  1070. X    do fatal($reason);
  1071. X}
  1072. X
  1073. X!NO!SUBS!
  1074. X$grep -v '^;#' pl/fatal.pl >>mailpatch
  1075. X$grep -v '^;#' pl/add_log.pl >>mailpatch
  1076. X$grep -v '^;#' pl/read_conf.pl >>mailpatch
  1077. X$grep -v '^;#' pl/unpack.pl >>mailpatch
  1078. X$grep -v '^;#' pl/rangeargs.pl >>mailpatch
  1079. X$grep -v '^;#' pl/sendfile.pl >>mailpatch
  1080. X$grep -v '^;#' pl/distribs.pl >>mailpatch
  1081. Xchmod 755 mailpatch
  1082. X$eunicefix mailpatch
  1083. END_OF_FILE
  1084.   if test 8849 -ne `wc -c <'agent/mailpatch.SH'`; then
  1085.     echo shar: \"'agent/mailpatch.SH'\" unpacked with wrong size!
  1086.   fi
  1087.   chmod +x 'agent/mailpatch.SH'
  1088.   # end of 'agent/mailpatch.SH'
  1089. fi
  1090. if test -f 'agent/pl/lexical.pl' -a "${1}" != "-c" ; then 
  1091.   echo shar: Will not clobber existing file \"'agent/pl/lexical.pl'\"
  1092. else
  1093.   echo shar: Extracting \"'agent/pl/lexical.pl'\" \(4343 characters\)
  1094.   sed "s/^X//" >'agent/pl/lexical.pl' <<'END_OF_FILE'
  1095. X;# $Id: lexical.pl,v 2.9.1.2 92/11/01 15:50:52 ram Exp $
  1096. X;#
  1097. X;#  Copyright (c) 1992, Raphael Manfredi
  1098. X;#
  1099. X;#  You may redistribute only under the terms of the GNU General Public
  1100. X;#  Licence as specified in the README file that comes with dist.
  1101. X;#
  1102. X;# $Log:    lexical.pl,v $
  1103. X;# Revision 2.9.1.2  92/11/01  15:50:52  ram
  1104. X;# patch11: fixed English typo
  1105. X;# 
  1106. X;# Revision 2.9.1.1  92/08/02  16:11:18  ram
  1107. X;# patch2: added support for negated selectors
  1108. X;# 
  1109. X;# Revision 2.9  92/07/14  16:50:10  ram
  1110. X;# 3.0 beta baseline.
  1111. X;# 
  1112. X;#
  1113. X#
  1114. X# Lexical parsing of the rules
  1115. X#
  1116. X
  1117. X# The following subroutine is called whenever a new rule input is needed.
  1118. X# It returns that new line or a null string if end of file has been reached.
  1119. Xsub read_filerule {
  1120. X    <RULES>;                    # Read a new line from file
  1121. X}
  1122. X
  1123. X# The following subroutine is called in place of read_rule when rules are
  1124. X# coming from the command line via @Linerules.
  1125. Xsub read_linerule {
  1126. X    shift(@Linerules);            # Read a new line from array
  1127. X}
  1128. X
  1129. X# Assemble a whole rule in one line and return it. The end of a line is
  1130. X# marked by a ';' at the end of an input line.
  1131. Xsub get_line {
  1132. X    local($result) = "";        # what will be returned
  1133. X    local($in_braces) = 0;        # are we inside braces ?
  1134. X    for (;;) {
  1135. X        $_ = &read_rule;        # new rule line (pseudo from compile_rules)
  1136. X        last if $_ eq '';        # end of file reached
  1137. X        s/\n$//;                # don't use chop in case we read from array
  1138. X        next if /^\s*#/;        # skip comments
  1139. X        s/\s\s+/ /;                # reduce white spaces
  1140. X        $result .= $_;
  1141. X        # Very simple braces handling
  1142. X        /.*{/ && ($in_braces = 1);
  1143. X        if ($in_braces) {
  1144. X            /.*}/ && ($in_braces = 0);
  1145. X        }
  1146. X        last if !$in_braces && /;\s*$/;
  1147. X    }
  1148. X    $result;
  1149. X}
  1150. X
  1151. X# Get optional mode (e.g. <TEST>) at the beginning of the line and return
  1152. X# it, or ALL if none was present.
  1153. Xsub get_mode {
  1154. X    local(*line) = shift(@_);    # edited in place
  1155. X    local($_) = $line;            # make a copy of original
  1156. X    local($mode) = "ALL";        # default mode
  1157. X    s/^<([\s\w,]+)>// && ($mode = $1);
  1158. X    $mode =~ s/\s//g;            # no spaces in returned mode
  1159. X    $line = $_;                    # eventually updates the line
  1160. X    $mode;
  1161. X}
  1162. X
  1163. X# A selector is either a script or a list of header fields ending with a ':'.
  1164. Xsub get_selector {
  1165. X    local(*line) = shift(@_);    # edited in place
  1166. X    local($_) = $line;            # make a copy of original
  1167. X    local($selector) = "";
  1168. X    s/^\s*,//;                    # remove rule separator
  1169. X    if (/^\s*\[\[/) {            # detected a script form
  1170. X        $selector = 'script:';
  1171. X    } else {
  1172. X        s/^\s*([^\/,{\n]*:)// && ($selector = $1);
  1173. X    }
  1174. X    $line = $_;                    # eventually updates the line
  1175. X    $selector;
  1176. X}
  1177. X
  1178. X# A pattern if either a single word (with no white space) or something
  1179. X# starting with a / and ending with an un-escaped / followed by some optional
  1180. X# modifiers.
  1181. X# Patterns may be preceded by a single '!' to negate the matching value.
  1182. Xsub get_pattern {
  1183. X    local(*line) = shift(@_);        # edited in place
  1184. X    local($_) = $line;                # make a copy of original
  1185. X    local($pattern) = "";            # the recognized pattern
  1186. X    local($buffer) = "";            # the buffer used for parsing
  1187. X    local($not) = '';                # shall boolean value be negated?
  1188. X    s|^\s*||;                        # remove leading spaces
  1189. X    s/^!// && ($not = '!');            # A leading '!' inverts matching status
  1190. X    if (s|^\[\[([^{]*)\]\]||) {        # pattern is a script
  1191. X        $pattern = $1;                # get the whole script
  1192. X    } elsif (s|^/||) {                # pattern starts with a /
  1193. X        $pattern = "/";                # record the /
  1194. X        while (s|([^/]*/)||) {        # while there is something before a /
  1195. X            $buffer = $1;            # save what we've been reading
  1196. X            $pattern .= $1;
  1197. X            last unless $buffer =~ m|\\/$|;    # finished unless / is escaped
  1198. X        }
  1199. X        s/^(\w+)// && ($pattern .= $1);        # add optional modifiers
  1200. X    } else {                                # pattern does not start with a /
  1201. X        s/([^\s,;{]*)// && ($pattern = $1);    # grab all until next delimiter
  1202. X    }
  1203. X    $line = $_;                    # eventually updates the line
  1204. X    $pattern =~ s/\s+$//;        # remove trailing spaces
  1205. X    if ($not && !$pattern) {
  1206. X        &add_log("ERROR discarding '!' not followed by pattern") if $loglvl;
  1207. X    } else {
  1208. X        $pattern = $not . $pattern;
  1209. X    }
  1210. X    $pattern;
  1211. X}
  1212. X
  1213. Xsub get_action {
  1214. X    local(*line) = shift(@_);    # edited in place
  1215. X    local($_) = $line;            # make a copy of original
  1216. X    local($action) = "";
  1217. X    if (s/^\s*{([^}]*)}//) {
  1218. X        $action = $1;
  1219. X    } else {
  1220. X        unless (/\{.*\}/) {        # trash line if no { action } is present
  1221. X            &add_log("ERROR expected action, discarded '$_'") if $loglvl;
  1222. X            $_ = '';
  1223. X        }
  1224. X    }
  1225. X    $line = $_;                    # eventually updates the line
  1226. X    $action =~ s/\s+$//;        # remove trailing spaces
  1227. X    $action;
  1228. X}
  1229. X
  1230. END_OF_FILE
  1231.   if test 4343 -ne `wc -c <'agent/pl/lexical.pl'`; then
  1232.     echo shar: \"'agent/pl/lexical.pl'\" unpacked with wrong size!
  1233.   fi
  1234.   # end of 'agent/pl/lexical.pl'
  1235. fi
  1236. if test -f 'agent/pl/queue_mail.pl' -a "${1}" != "-c" ; then 
  1237.   echo shar: Will not clobber existing file \"'agent/pl/queue_mail.pl'\"
  1238. else
  1239.   echo shar: Extracting \"'agent/pl/queue_mail.pl'\" \(8543 characters\)
  1240.   sed "s/^X//" >'agent/pl/queue_mail.pl' <<'END_OF_FILE'
  1241. X;# $Id: queue_mail.pl,v 2.9 92/07/14 16:50:34 ram Exp $
  1242. X;#
  1243. X;#  Copyright (c) 1992, Raphael Manfredi
  1244. X;#
  1245. X;#  You may redistribute only under the terms of the GNU General Public
  1246. X;#  Licence as specified in the README file that comes with dist.
  1247. X;#
  1248. X;# $Log:    queue_mail.pl,v $
  1249. X;# Revision 2.9  92/07/14  16:50:34  ram
  1250. X;# 3.0 beta baseline.
  1251. X;# 
  1252. X;#
  1253. X;# Queue a mail file. Needs add_log(). Calls fatal() in emergency situations.
  1254. X;# Requires a parsed config file.
  1255. X;# 
  1256. X# Queue mail in a 'fm' file. The mail is held in memory. It returns 0 if the
  1257. X# mail was queued, 1 otherwise.
  1258. Xsub qmail {
  1259. X    local(*array) = @_;            # In which array mail is located.
  1260. X    local($queue_file);            # Where we attempt to save the mail
  1261. X    local($failed) = 0;            # Be positive and look forward :-)
  1262. X    $queue_file = "$cf'queue/Tqm$$";
  1263. X    $queue_file = "$cf'queue/Tqmb$$" if -f "$queue_file";    # Paranoid
  1264. X    unless (open(QUEUE, ">$queue_file")) {
  1265. X        &add_log("ERROR unable to create $queue_file: $!") if $loglvl > 1;
  1266. X        return 1;        # Failed
  1267. X    }
  1268. X    # Write mail on disk, making sure there is a first From line
  1269. X    local($first_line) = 1;
  1270. X    local($in_header) = 1;        # True while in mail header
  1271. X    foreach $line (@array) {
  1272. X        if ($first_line) {
  1273. X            $first_line = 0;
  1274. X            print QUEUE "$FAKE_FROM\n" unless $line =~ /^From\s+\S+/;
  1275. X        }
  1276. X        next if (print QUEUE $line, "\n");
  1277. X        $failed = 1;
  1278. X        &add_log("SYSERR write: $!") if $loglvl;
  1279. X        last;
  1280. X    }
  1281. X    close QUEUE;
  1282. X    unlink "$queue_file" if $failed;
  1283. X    $failed = &queue_mail($queue_file) unless $failed;
  1284. X    $failed;            # 0 means success
  1285. X}
  1286. X
  1287. X# Queue mail in a 'fm' file. The mail is supposed to be either on disk or
  1288. X# is expected from standard input. Returns 0 for success, 1 if failed.
  1289. X# In case mail comes from stdin, may not return at all but raise a fatal error.
  1290. Xsub queue_mail {
  1291. X    local($file_name) = shift(@_);        # Where mail to-be-queued is
  1292. X    local($deferred) = shift(@_);        # True when 'qm' mail wanted instead
  1293. X    local($dirname);                    # Directory name of processed file
  1294. X    local($tmp_queue);                    # Tempoorary storing of queued file
  1295. X    local($queue_file);                    # Final name of queue file
  1296. X    local($ok) = 1;                        # Print status
  1297. X    local($_);
  1298. X    &add_log("queuing mail for delayed processing") if $loglvl > 18;
  1299. X    chdir $cf'queue || do fatal("cannot chdir to $cf'queue");
  1300. X
  1301. X    # The following ensures unique queue mails. As the mailagent itself may
  1302. X    # queue intensively throughout the SPLIT command, a queue counter is kept
  1303. X    # and is incremented each time a mail is successfully queued.
  1304. X    local($base) = $deferred ? 'qm' : 'fm';
  1305. X    $queue_file = "$base$$";        # 'fm' stands for Full Mail
  1306. X    $queue_file = "$base$$x" . $queue_count if -f "$queue_file";
  1307. X    $queue_file = "${queue_file}x" if -f "$queue_file";    # Paranoid
  1308. X    ++$queue_count;                    # Counts amount of queued mails
  1309. X    &add_log("queue file is $queue_file") if $loglvl > 19;
  1310. X
  1311. X    # Do not write directly in the fm file, otherwise the main
  1312. X    # mailagent process could start its processing on it...
  1313. X    $tmp_queue = "Tfm$$";
  1314. X    local($sender) = "<someone>";    # Attempt to report the sender of message
  1315. X    if ($file_name) {                # Mail is already on file system
  1316. X        # Mail already in a file
  1317. X        $ok = 0 if &mv($file_name, $tmp_queue);
  1318. X        if ($ok && open(QUEUE, $tmp_queue)) {
  1319. X            while (<QUEUE>) {
  1320. X                $Header{'All'} .= $_ unless defined $Header{'All'};
  1321. X                if (1 .. /^$/) {        # While in header of message
  1322. X                    /^From:[ \t]*(.*)/ && ($sender = $1 );
  1323. X                }
  1324. X            }
  1325. X            close QUEUE;
  1326. X        }
  1327. X    } else {
  1328. X        # Mail comes from stdin or has already been stored in %Header
  1329. X        unless (defined $Header{'All'}) {    # Only if mail was not already read
  1330. X            $Header{'All'} = '';            # Needed in case of emergency
  1331. X            if (open(QUEUE, ">$tmp_queue")) {
  1332. X                while (<STDIN>) {
  1333. X                    $Header{'All'} .= $_;
  1334. X                    if (1 .. /^$/) {        # While in header of message
  1335. X                        /^From:[ \t]*(.*)/ && ($sender = $1);
  1336. X                    }
  1337. X                    (print QUEUE) || ($ok = 0);
  1338. X                }
  1339. X                close QUEUE;
  1340. X            } else {
  1341. X                $ok = 0;        # Signals: was not able to queue mail
  1342. X            }
  1343. X        } else {                            # Mail already in %Header
  1344. X            if (open(QUEUE, ">$tmp_queue")) {
  1345. X                local($in_header) = 1;
  1346. X                foreach (split(/\n/, $Header{'All'})) {
  1347. X                    if ($in_header) {        # While in header of message
  1348. X                        $in_header = 0 if /^$/;
  1349. X                        /^From:[ \t]*(.*)/ && ($sender = $1);
  1350. X                    }
  1351. X                    (print QUEUE $_, "\n") || ($ok = 0);
  1352. X                }
  1353. X                close QUEUE;
  1354. X            } else {
  1355. X                $ok = 0;        # Signals: was not able to queue mail
  1356. X            }
  1357. X        }
  1358. X    }
  1359. X
  1360. X    # If there has been some problem (like we ran out of disk space), then
  1361. X    # attempt to record the temporary file name into the waiting file. If
  1362. X    # mail came from stdin, there is not much we can do, so we panic.
  1363. X    if (!$ok) {
  1364. X        do add_log("ERROR could not queue message") if $loglvl > 0;
  1365. X        unlink "$tmp_queue";
  1366. X        if ($file_name) {
  1367. X            # The file processed is already on the disk
  1368. X            $dirname = $file_name;
  1369. X            $dirname =~ s|^(.*)/.*|$1|;    # Keep only basename
  1370. X            $cf'user = (getpwuid($<))[0] || "uid$<" if $cf'user eq '';
  1371. X            $tmp_queue = $dirname/$cf'user.$$;
  1372. X            $tmp_queue = $file_name if &mv($file_name, $tmp_queue);
  1373. X            do add_log("NOTICE mail held in $tmp_queue") if $loglvl > 4;
  1374. X        } else {
  1375. X            do fatal("mail may be lost");    # Mail came from filter via stdin
  1376. X        }
  1377. X        # If the mail is on the disk, add its name to the file $agent_wait
  1378. X        # in the queue directory. This file contains the names of the mails
  1379. X        # stored outside of the mailagent's queue and waiting to be processed.
  1380. X        $ok = &waiting_mail($tmp_queue);
  1381. X        return 1 unless $ok;    # Queuing failed if not ok
  1382. X        return 0;
  1383. X    }
  1384. X
  1385. X    # We succeeded in writing the temporary queue mail. Now rename it so that
  1386. X    # the mailagent may see it and process it.
  1387. X    if (rename($tmp_queue, $queue_file)) {
  1388. X        local($bytes) = (stat($queue_file))[7];    # Size of file
  1389. X        local($s) = $bytes == 1 ? '' : 's';
  1390. X        &add_log("QUEUED [$queue_file] ($bytes byte$s) from $sender")
  1391. X            if $loglvl > 3;
  1392. X    } else {
  1393. X        &add_log("ERROR cannot rename $tmp_queue to $queue_file") if $loglvl;
  1394. X        $ok = &waiting_mail($tmp_queue);
  1395. X    }
  1396. X    return 1 unless $ok;        # Queuing failed if not ok
  1397. X    0;
  1398. X}
  1399. X
  1400. X# Adds mail into the agent.wait file, if possible. This file records all the
  1401. X# mails queued with a non-standard name or which are stored outside of the
  1402. X# queue. Returns 1 if mail was successfully added to this list.
  1403. Xsub waiting_mail {
  1404. X    local($tmp_queue) = @_;
  1405. X    local($status) = 0;
  1406. X    if (open(WAITING, ">>$agent_wait")) {
  1407. X        if (print WAITING "$tmp_queue\n") {
  1408. X            $status = 1;            # Mail more or less safely queued
  1409. X            do add_log("NOTICE processing deferred for $tmp_queue")
  1410. X                if $loglvl > 3;
  1411. X        } else {
  1412. X            do add_log("ERROR could not record $tmp_queue in $agent_wait")
  1413. X                if $loglvl > 1;
  1414. X        }
  1415. X        close WAITING;
  1416. X    } else {
  1417. X        do add_log("ERROR unable to open $agent_wait") if $loglvl > 0;
  1418. X        do add_log("WARNING left mail in $tmp_queue") if $loglvl > 1;
  1419. X    }
  1420. X    $status;        # 1 means success
  1421. X}
  1422. X
  1423. X# Performs a '/bin/mv' operation, but without the burden of an extra process.
  1424. Xsub mv {
  1425. X    local($from, $to) = @_;        # Original path and destination path
  1426. X    # If the two files are on the same file system, then we may use the rename()
  1427. X    # system call.
  1428. X    if (&same_device($from, $to)) {
  1429. X        &add_log("using rename system call") if $loglvl > 19;
  1430. X        unless (rename($from, $to)) {
  1431. X            &add_log("SYSERR rename: $!") if $loglvl;
  1432. X            &add_log("ERROR could not rename $from into $to") if $loglvl;
  1433. X            return 1;
  1434. X        }
  1435. X        return 0;
  1436. X    }
  1437. X    # Have to emulate a 'cp'
  1438. X    &add_log("copying file $from to $to") if $loglvl > 19;
  1439. X    unless (open(FROM, $from)) {
  1440. X        &add_log("SYSERR open: $!") if $loglvl;
  1441. X        &add_log("ERROR cannot open source $from") if $loglvl;
  1442. X        return 1;
  1443. X    }
  1444. X    unless (open(TO, ">$to")) {
  1445. X        &add_log("SYSERR open: $!") if $loglvl;
  1446. X        &add_log("ERROR cannot open target $to") if $loglvl;
  1447. X        close FROM;
  1448. X        return 1;
  1449. X    }
  1450. X    local($ok) = 1;        # Assume all I/O went all right
  1451. X    local($_);
  1452. X    while (<FROM>) {
  1453. X        next if print TO;
  1454. X        $ok = 0;
  1455. X        &add_log("SYSERR write: $!") if $loglvl;
  1456. X        last;
  1457. X    }
  1458. X    close FROM;
  1459. X    close TO;
  1460. X    unless ($ok) {
  1461. X        &add_log("ERROR could not copy $from to $to") if $loglvl;
  1462. X        unlink "$to";
  1463. X        return 1;
  1464. X    }
  1465. X    # Copy succeeded, remove original file
  1466. X    unlink "$from";
  1467. X    0;                    # Denotes success
  1468. X}
  1469. X
  1470. X# Look whether two paths refer to the same device.
  1471. X# Compute basename and directory name for both files, as the file may
  1472. X# not exist. However, if both directories are on the same file system,
  1473. X# then so is it for the two files beneath each of them.
  1474. Xsub same_device {
  1475. X    local($from, $to) = @_;        # Original path and destination path
  1476. X    local($fromdir, $fromfile) = $from =~ m|^(.*)/(.*)|;
  1477. X    ($fromdir, $fromfile) = ('.', $fromdir) if $fromfile eq '';
  1478. X    local($todir, $tofile) = $to =~ m|^(.*)/(.*)|;
  1479. X    ($todir, $tofile) = ('.', $todir) if $tofile eq '';
  1480. X    local($dev1) = stat($fromdir);
  1481. X    local($dev2) = stat($todir);
  1482. X    $dev1 == $dev2;
  1483. X}
  1484. X
  1485. END_OF_FILE
  1486.   if test 8543 -ne `wc -c <'agent/pl/queue_mail.pl'`; then
  1487.     echo shar: \"'agent/pl/queue_mail.pl'\" unpacked with wrong size!
  1488.   fi
  1489.   # end of 'agent/pl/queue_mail.pl'
  1490. fi
  1491. if test -f 'agent/pl/sendfile.pl' -a "${1}" != "-c" ; then 
  1492.   echo shar: Will not clobber existing file \"'agent/pl/sendfile.pl'\"
  1493. else
  1494.   echo shar: Extracting \"'agent/pl/sendfile.pl'\" \(8942 characters\)
  1495.   sed "s/^X//" >'agent/pl/sendfile.pl' <<'END_OF_FILE'
  1496. X;# $Id: sendfile.pl,v 2.9 92/07/14 16:50:49 ram Exp $
  1497. X;#
  1498. X;#  Copyright (c) 1991, Raphael Manfredi
  1499. X;#
  1500. X;#  You may redistribute only under the terms of the GNU General Public
  1501. X;#  Licence as specified in the README file that comes with dist.
  1502. X;#
  1503. X;# $Log:    sendfile.pl,v $
  1504. X;# Revision 2.9  92/07/14  16:50:49  ram
  1505. X;# 3.0 beta baseline.
  1506. X;# 
  1507. X;#
  1508. X;# This file contains two subroutines:
  1509. X;#   - sendfile, sends a set of files
  1510. X;#   - abort, called when something got wrong
  1511. X;#
  1512. X;# A routine clean_tmp must be defined in the program, for removing
  1513. X;# possible temporary files in case abort is called.
  1514. X;#
  1515. X# Send a set of files
  1516. Xsub sendfile {
  1517. X    local($dest, $cf'tmpdir, $pack, $subject) = @_;
  1518. X    do add_log("sending dir $cf'tmpdir to $dest, mode $pack")
  1519. X        if ($loglvl > 9);
  1520. X
  1521. X    # A little help message
  1522. X    local($mail_help) = "Detailed intructions can be obtained by:
  1523. X
  1524. X    Subject: Command
  1525. X    @SH mailhelp $dest";
  1526. X
  1527. X    # Go to tmpdir where files are stored
  1528. X    chdir $cf'tmpdir || do abort("NO TMP DIRECTORY");
  1529. X
  1530. X    # Build a list of files to send
  1531. X    local($list) = "";        # List of plain files
  1532. X    local($dlist) = "";        # List with directories (for makekit)
  1533. X    local($nbyte) = 0;
  1534. X    local($nsend) = 0;
  1535. X    open(FIND, "find . -print |") || do abort("CANNOT RUN FIND");
  1536. X    while (<FIND>) {
  1537. X        chop;
  1538. X        next if $_ eq '.';        # Skip current directory `.'
  1539. X        s|^\./||;
  1540. X        $dlist .= $_ . " ";        # Save file/dir name
  1541. X        if (-f $_) {            # If plain file
  1542. X            $list .= $_ . " ";    # Save plain file
  1543. X            $nsend++;            # One more file to send
  1544. X            ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,
  1545. X                $blksize,$blocks) = stat($_);
  1546. X            $nbyte += $size;    # Update total size
  1547. X        }
  1548. X    }
  1549. X    close FIND;
  1550. X
  1551. X    do abort("NO FILE TO SEND") unless $nsend;
  1552. X    if ($nsend > 1) {
  1553. X        do add_log("$nsend files to pack ($nbyte bytes)") if ($loglvl > 9);
  1554. X    } else {
  1555. X        do add_log("1 file to pack ($nbyte bytes)") if ($loglvl > 9);
  1556. X    }
  1557. X
  1558. X    # Pack files
  1559. X    if ($pack =~ /kit/) {
  1560. X        system "kit -n Part $list" || do abort("CANNOT KIT FILES");
  1561. X        $packed = "kit";
  1562. X    } elsif ($pack =~ /shar/) {
  1563. X        # Create a manifest, so that we can easily run maniscan
  1564. X        # Leave a PACKNOTES file with non-zero length if problems.
  1565. X        local($mani) = $dlist;
  1566. X        $mani =~ s/ /\n/g;
  1567. X        local($packlist) = "pack.$$";    # Pack list used as manifest
  1568. X        if (open(PACKLIST, ">$packlist")) {
  1569. X            print PACKLIST $mani;
  1570. X            close PACKLIST;
  1571. X            system 'maniscan', "-i$packlist",
  1572. X                "-o$packlist", '-w0', '-n', '-lPACKNOTES';
  1573. X            do add_log("ERROR maniscan returned non-zero status")
  1574. X                if ($loglvl > 5 && $?);
  1575. X            if (-s 'PACKNOTES') {        # Files split or uu-encoded
  1576. X                system 'makekit', "-i$packlist", '-t',
  1577. X                    "Now run 'sh PACKNOTES'." || do abort("CANNOT SHAR FILES");
  1578. X            } else {
  1579. X                system 'makekit', "-i$packlist" || do abort("CANNOT SHAR FILES");
  1580. X            }
  1581. X        } else {
  1582. X            do add_log("ERROR cannot create packlist") if ($loglvl > 5);
  1583. X            system "makekit $dlist" || do abort("CANNOT SHAR FILES");
  1584. X        }
  1585. X        $packed = "shar";
  1586. X    } else {
  1587. X        if ($nbyte > $cf'maxsize) {        # Defined in ~/.mailagent
  1588. X            system "kit -M -n Part $list" || do abort("CANNOT KIT FILES");
  1589. X            $packed = "minikit";        # The minikit is included
  1590. X        } else {
  1591. X            # Try with makekit first
  1592. X            if (system "makekit $dlist") {    # If failed
  1593. X                system "kit -M -n Part $list" || do abort("CANNOT KIT FILES");
  1594. X                $packed = "minikit";    # The minikit is included
  1595. X            } else {
  1596. X                $packed = "shar";
  1597. X            }
  1598. X        }
  1599. X    }
  1600. X
  1601. X    # How many parts are there ?
  1602. X    @parts = <Part*>;
  1603. X    $npart = $#parts + 1;        # Number of parts made
  1604. X    do abort("NO PART TO SEND -- $packed failed") unless $npart;
  1605. X    if ($npart > 1) {
  1606. X        do add_log("$npart $packed parts to send") if ($loglvl > 19);
  1607. X    } else {
  1608. X    do add_log("$npart $packed part to send") if ($loglvl > 19);
  1609. X    }
  1610. X
  1611. X    # Now send the parts
  1612. X    $nbyte = 0;                # How many bytes do we send ?
  1613. X    $part_num = 0;
  1614. X    $signal="";                # To signal parts number if more than 1
  1615. X    local($partsent) = 0;    # Number of parts actually sent
  1616. X    local($bytesent) = 0;    # Amount of bytes actually sent
  1617. X    foreach $part (@parts) {
  1618. X        ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,
  1619. X            $blksize,$blocks) = stat($part);
  1620. X        $nbyte += $size;    # Update total size
  1621. X
  1622. X        do add_log("dealing with $part ($size bytes)") if ($loglvl > 19);
  1623. X
  1624. X        # See if we need to signal other parts
  1625. X        $part_num++;            # Update part number
  1626. X        if ($npart > 1) {
  1627. X            $signal=" (Part $part_num/$npart)";
  1628. X        }
  1629. X
  1630. X        # Send part
  1631. X        open(MAILER, "|/usr/lib/sendmail -odq -t");
  1632. X        print MAILER
  1633. X"To: $dest
  1634. XSubject: $subject$signal
  1635. XPrecedence: bulk
  1636. XX-Mailer: mailagent [version $mversion PL$patchlevel]
  1637. X
  1638. XHere is the answer to your request:
  1639. X
  1640. X    $fullcmd
  1641. X
  1642. X
  1643. X";
  1644. X        if ($packed eq 'minikit') {        # Kit with minikit included
  1645. X            print MAILER
  1646. X"This is a kit file. It will be simpler to unkit it if you own the kit
  1647. Xpackage (latest patchlevel), but you can use the minikit provided with
  1648. Xthis set of file (please see instructions provided by kit itself at the
  1649. Xhead of each part). If you wish to get kit, send me the following mail:
  1650. X
  1651. X";
  1652. X        } elsif ($packed eq 'kit') {    # Plain kit files
  1653. X            print MAILER
  1654. X"This is a kit file. You need the kit package (latest patchlevel) to
  1655. Xunkit it. If you do not have kit, send me the following mail:
  1656. X
  1657. X";
  1658. X        }
  1659. X        if ($packed =~ /kit/) {        # Kit parts
  1660. X            print MAILER
  1661. X"    Subject: Command
  1662. X    @PACK shar
  1663. X    @SH maildist $dest kit -
  1664. X
  1665. Xand you will get the latest release of kit as shell archives.
  1666. X
  1667. X$mail_help
  1668. X
  1669. X";
  1670. X            # Repeat instructions which should be provided by kit anyway
  1671. X            if ($npart > 1) {
  1672. X                print MAILER
  1673. X"Unkit:    Save this mail into a file, e.g. \"foo$part_num\" and wait until
  1674. X    you have received the $npart parts. Then, do \"unkit foo*\". To see
  1675. X    what will be extracted, you may wish to do \"unkit -l foo*\" before.
  1676. X";
  1677. X            } else {
  1678. X                print MAILER
  1679. X"Unkit:    Save this mail into a file, e.g. \"foo\". Then do \"unkit foo\". To see
  1680. X    what will be extracted, you may wish to do \"unkit -l foo\" before.
  1681. X";
  1682. X            }
  1683. X            # If we used the minikit, signal where instruction may be found
  1684. X            if ($packed eq 'minikit') {
  1685. X                print MAILER
  1686. X"    This kit archive also contains a minikit which will enable you to
  1687. X    extract the files even if you do not have kit. Please follow the
  1688. X    instructions kit has provided for you at the head of each part. Should
  1689. X    the minikit prove itself useless, you may wish to get kit.
  1690. X";
  1691. X            }
  1692. X        } else {            # Shar parts
  1693. X            print MAILER
  1694. X"This is a shar file. It will be simpler to unshar it if you own the Rich Salz's
  1695. Xcshar package. If you do not have it, send me the following mail:
  1696. X
  1697. X    Subject: Command
  1698. X    @PACK shar
  1699. X    @SH maildist $dest cshar 3.0
  1700. X
  1701. Xand you will get cshar as shell archives.
  1702. X
  1703. X$mail_help
  1704. X
  1705. X";
  1706. X            if (-s 'PACKNOTES') {        # Problems detected by maniscan
  1707. X                print MAILER
  1708. X"
  1709. XWarning:
  1710. X    Some minor problems were encountered during the building of the
  1711. X    shell archives. Perhaps a big file has been split, a binary has been
  1712. X    uu-encoded, or some lines were too long. Once you have unpacked the
  1713. X    whole distribution, see file PACKNOTES for more information. You can
  1714. X    run it through sh by typing 'sh PACKNOTES' to restore possible splited
  1715. X    or encoded files.
  1716. X
  1717. X";
  1718. X            }
  1719. X            if ($npart > 1) {
  1720. X                print MAILER
  1721. X"Unshar: Save this mail into a file, e.g. \"foo$part_num\" and wait until
  1722. X    you have received the $npart parts. Then, do \"unshar -n foo*\". If you
  1723. X    do not own \"unshar\", edit the $npart files and remove the mail header
  1724. X    by hand before feeding into sh.
  1725. X";
  1726. X            } else {
  1727. X                print MAILER
  1728. X"Unshar: Save this mail into a file, e.g. \"foo\". Then do \"unshar -n foo\". If
  1729. X    you do not own \"unshar\", edit the file and remove the mail header by
  1730. X    hand before feeding into sh.
  1731. X";
  1732. X            }
  1733. X        }
  1734. X        print MAILER
  1735. X"
  1736. X-- $prog_name speaking for $cf'user
  1737. X
  1738. X
  1739. X";
  1740. X        open(PART, $part) || do abort("CANNOT OPEN $part");
  1741. X        while (<PART>) {
  1742. X            print MAILER;
  1743. X        }
  1744. X        close PART;
  1745. X        close MAILER;
  1746. X        if ($?) {
  1747. X            do add_log("ERROR couldn't send $size bytes to $dest")
  1748. X                if $loglvl > 1;
  1749. X        } else {
  1750. X            do add_log("SENT $size bytes to $dest") if $loglvl > 2;
  1751. X            $partsent++;
  1752. X            $bytesent += $size;
  1753. X        }
  1754. X    }
  1755. X
  1756. X    # Prepare log message
  1757. X    local($partof) = "";
  1758. X    local($byteof) = "";
  1759. X    local($part);
  1760. X    local($byte);
  1761. X    if ($partsent > 1) {
  1762. X        $part = "parts";
  1763. X    } else {
  1764. X        $part = "part";
  1765. X    }
  1766. X    if ($bytesent > 1) {
  1767. X        $byte = "bytes";
  1768. X    } else {
  1769. X        $byte = "byte";
  1770. X    }
  1771. X    if ($partsent != $npart) {
  1772. X        $partof = " (of $npart)";
  1773. X        $byteof = "/$nbyte";
  1774. X    }
  1775. X    &add_log(
  1776. X        "SENT $partsent$partof $packed $part ($bytesent$byteof $byte) to $dest"
  1777. X    ) if $loglvl > 4;
  1778. X}
  1779. X
  1780. X# In case something got wrong
  1781. X# We call the clean_tmp routine, which must be defined in the
  1782. X# main program that will use abort.
  1783. Xsub abort {
  1784. X    local($reason) = shift;        # Why do we abort ?
  1785. X    open(MAILER,"|/usr/lib/sendmail -odq -t");
  1786. X    print MAILER
  1787. X"To: $path
  1788. XBcc: $cf'user
  1789. XSubject: $subject failed
  1790. XX-Mailer: mailagent [version $mversion PL$patchlevel]
  1791. X
  1792. XSorry, the $prog_name command failed while sending files.
  1793. X
  1794. XYour command was: $fullcmd
  1795. XError message I got:
  1796. X
  1797. X    >>>> $reason <<<<
  1798. X
  1799. XIf $cf'name can figure out what you meant, he may answer anyway.
  1800. X
  1801. X-- $prog_name speaking for $cf'user
  1802. X";
  1803. X    close MAILER;
  1804. X    do add_log("FAILED ($reason)") if ($loglvl > 1);
  1805. X    do clean_tmp();
  1806. X    exit 0;            # Scheduled error
  1807. X}
  1808. X
  1809. END_OF_FILE
  1810.   if test 8942 -ne `wc -c <'agent/pl/sendfile.pl'`; then
  1811.     echo shar: \"'agent/pl/sendfile.pl'\" unpacked with wrong size!
  1812.   fi
  1813.   # end of 'agent/pl/sendfile.pl'
  1814. fi
  1815. echo shar: End of archive 10 \(of 17\).
  1816. cp /dev/null ark10isdone
  1817. MISSING=""
  1818. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ; do
  1819.     if test ! -f ark${I}isdone ; then
  1820.     MISSING="${MISSING} ${I}"
  1821.     fi
  1822. done
  1823. if test "${MISSING}" = "" ; then
  1824.     echo You have unpacked all 17 archives.
  1825.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1826. else
  1827.     echo You still must unpack the following archives:
  1828.     echo "        " ${MISSING}
  1829. fi
  1830. exit 0
  1831. exit 0 # Just in case...
  1832.