home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #27 / NN_1992_27.iso / spool / comp / sources / misc / 4107 < prev    next >
Encoding:
Text File  |  1992-11-20  |  54.8 KB  |  1,838 lines

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