home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume22 / elm2.3 / part09 < prev    next >
Text File  |  1990-06-07  |  50KB  |  1,754 lines

  1. Subject:  v22i068:  ELM mail syste, release 2.3, Part09/26
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4. X-Checksum-Snefru: 6ea2f43a 59ab3060 4770da06 e5fc5cb9
  5. Supercedes: <2580@papaya.bbn.com>
  6.  
  7. Submitted-by: Syd Weinstein <syd@dsinc.dsi.com>
  8. Posting-number: Volume 22, Issue 68
  9. Archive-name: elm2.3/part09
  10.  
  11. #!/bin/sh
  12. # this is part 9 of a multipart archive
  13. # do not concatenate these parts, unpack them in order with /bin/sh
  14. # file filter/filter.c continued
  15. #
  16. CurArch=9
  17. if test ! -r s2_seq_.tmp
  18. then echo "Please unpack part 1 first!"
  19.      exit 1; fi
  20. ( read Scheck
  21.   if test "$Scheck" != $CurArch
  22.   then echo "Please unpack part $Scheck next!"
  23.        exit 1;
  24.   else exit 0; fi
  25. ) < s2_seq_.tmp || exit 1
  26. echo "x - Continuing file filter/filter.c"
  27. sed 's/^X//' << 'SHAR_EOF' >> filter/filter.c
  28. X#include "defs.h"
  29. X#ifdef I_TIME
  30. X#  include <time.h>
  31. X#endif
  32. X#ifdef I_SYSTIME
  33. X#  include <sys/time.h>
  34. X#endif
  35. X#include <fcntl.h>
  36. X
  37. X#define  MAIN_ROUTINE            /* for the filter.h file, of course! */
  38. X#include "filter.h"
  39. X
  40. Xmain(argc, argv)
  41. Xint argc;
  42. Xchar *argv[];
  43. X{
  44. X    extern char *optarg;
  45. X    FILE   *fd;                /* for output to temp file! */
  46. X    struct passwd  *passwd_entry;
  47. X#ifndef    _POSIX_SOURCE
  48. X    struct passwd  *getpwuid();        /* for /etc/passwd          */
  49. X#endif
  50. X    char filename[SLEN],            /* name of the temp file    */
  51. X         buffer[MAX_LINE_LEN];        /* input buffer space       */
  52. X    int  in_header = TRUE,            /* for header parsing       */
  53. X         in_to     = FALSE,            /* are we on 'n' line To: ? */
  54. X         summary   = FALSE,            /* a summary is requested?  */
  55. X         c;                    /* var for getopt routine   */
  56. X
  57. X    /* first off, let's get the info from /etc/passwd */ 
  58. X    
  59. X    if ((passwd_entry = getpwuid(getuid())) == NULL) 
  60. X      leave("Cannot get password entry for this uid!");
  61. X
  62. X    strcpy(home, passwd_entry->pw_dir);
  63. X    strcpy(username, passwd_entry->pw_name);
  64. X    outfname[0] = to[0] = '\0';    /* nothing read in yet, right? */
  65. X
  66. X#ifdef HOSTCOMPILED
  67. X    strncpy(hostname, HOSTNAME, sizeof(hostname));
  68. X#else
  69. X    gethostname(hostname, sizeof(hostname));
  70. X#endif
  71. X
  72. X    /* now parse the starting arguments... */
  73. X
  74. X    while ((c = getopt(argc, argv, "clno:rSsv")) != EOF) {
  75. X      switch (c) {
  76. X        case 'c' : clear_logs = TRUE;            break;
  77. X        case 'l' : log_actions_only = TRUE;            break;
  78. X        case 'o' : strcpy(outfname, optarg);        break;
  79. X        case 'r' : printing_rules = TRUE;            break;
  80. X    
  81. X        case 's' : summary = TRUE;                break;
  82. X        case 'S' : long_summary = TRUE;            break;
  83. X
  84. X        case 'n' : show_only = TRUE;            break;
  85. X        case 'v' : verbose = TRUE;                break;
  86. X        case '?' : fprintf(stderr, 
  87. X               "Usage: | filter [-nrv]\n   or: filter [-c] -[s|S]\n");
  88. X                     exit(1);
  89. X      }
  90. X    }
  91. X
  92. X    if (c < 0) {
  93. X    }
  94. X
  95. X    /* let's open our outfd logfile as needed... */
  96. X
  97. X    if (outfname[0] == '\0')     /* default is stdout */
  98. X      outfd = stdout;
  99. X    else 
  100. X      if ((outfd = fopen(outfname, "a")) == NULL) {
  101. X        if (isatty(fileno(stderr)))
  102. X          fprintf(stderr,"filter (%s): couldn't open log file %s\n",
  103. X              username, outfname);
  104. X      }
  105. X
  106. X    if (summary || long_summary) {
  107. X          if (get_filter_rules() == -1) {
  108. X        exit(1);
  109. X        if (outfd != NULL) fclose(outfd);
  110. X      }
  111. X      show_summary();
  112. X      if (outfd != NULL) fclose(outfd);
  113. X      exit(0);
  114. X    }
  115. X
  116. X    if (printing_rules) {
  117. X          if (get_filter_rules() == -1)
  118. X        fprintf(outfd,"filter (%s): Couldn't get rules!\n", username);
  119. X          else
  120. X        print_rules();
  121. X      if (outfd != NULL) fclose(outfd);
  122. X          exit(0);
  123. X    }
  124. X
  125. X    /* next, create the tempfile and save the incoming message */
  126. X
  127. X    sprintf(filename, "%s.%d", filter_temp, getpid());
  128. X
  129. X    if ((fd = fopen(filename,"w")) == NULL)
  130. X      leave("Cannot open temporary file!");
  131. X
  132. X    while (fgets(buffer, MAX_LINE_LEN, stdin) != NULL) {
  133. X
  134. X      remove_return(buffer);
  135. X
  136. X      if (in_header) {
  137. X
  138. X        if (! whitespace(buffer[0])) 
  139. X        in_to = FALSE;
  140. X
  141. X        if (the_same(buffer, "From ")) 
  142. X          save_from(buffer);
  143. X        else if (the_same(buffer, "Subject:")) 
  144. X          save_subject(buffer);
  145. X        else if (the_same(buffer, "To:") || the_same(buffer, "Cc:")) {
  146. X          in_to++;
  147. X          save_to(buffer);
  148. X        }
  149. X        else if (the_same(buffer, "X-Filtered-By:")) 
  150. X          already_been_forwarded++;    /* could be a loop here! */
  151. X#ifdef USE_EMBEDDED_ADDRESSES
  152. X        else if (the_same(buffer, "From:"))
  153. X          save_embedded_address(buffer, "From:");
  154. X        else if (the_same(buffer, "Reply-To:"))
  155. X          save_embedded_address(buffer, "Reply-To:");
  156. X#endif
  157. X        else if (strlen(buffer) < 2) 
  158. X          in_header = 0;
  159. X        else if (whitespace(buffer[0]) && in_to)
  160. X          strcat(to, buffer);
  161. X      }
  162. X    
  163. X          fprintf(fd, "%s\n", buffer);    /* and save it regardless! */
  164. X      fflush(fd);
  165. X      lines++;
  166. X    }
  167. X
  168. X    fclose(fd);
  169. X
  170. X    /** next let's see if the user HAS a filter file, and if so what's in
  171. X            it (and so on) **/
  172. X
  173. X    if (get_filter_rules() == -1)
  174. X      mail_message(username);
  175. X    else {
  176. X      switch (action_from_ruleset()) {
  177. X
  178. X        case DELETE_MSG : if (verbose && outfd != NULL)
  179. X                fprintf(outfd, "filter (%s): Message deleted\n",
  180. X                    username);
  181. X              log(DELETE_MSG);                break;
  182. X
  183. X        case SAVE   : if (save_message(rules[rule_choosen].argument2)) {
  184. X                mail_message(username);
  185. X                log(FAILED_SAVE);
  186. X              }
  187. X              else
  188. X                 log(SAVE);                    break;
  189. X
  190. X        case SAVECC : if (save_message(rules[rule_choosen].argument2))
  191. X                log(FAILED_SAVE);
  192. X              else
  193. X                    log(SAVECC);                    
  194. X              mail_message(username);            break;
  195. X
  196. X        case FORWARD: mail_message(rules[rule_choosen].argument2);
  197. X              log(FORWARD);                    break;
  198. X
  199. X        case EXEC   : execute(rules[rule_choosen].argument2);
  200. X              log(EXEC);                    break;
  201. X
  202. X        case LEAVE  : mail_message(username);
  203. X              log(LEAVE);                    break;
  204. X      }
  205. X    }
  206. X
  207. X    (void) unlink(filename);    /* remove the temp file, please! */
  208. X    if (outfd != NULL) fclose(outfd);
  209. X    exit(0);
  210. X}
  211. X
  212. Xsave_from(buffer)
  213. Xchar *buffer;
  214. X{
  215. X    /** save the SECOND word of this string as FROM **/
  216. X
  217. X    register char *f = from;
  218. X
  219. X    while (*buffer != ' ')
  220. X      buffer++;                /* get to word     */
  221. X
  222. X    for (buffer++; *buffer != ' ' && *buffer; buffer++, f++) 
  223. X      *f = *buffer;                /* copy it and     */
  224. X
  225. X    *f = '\0';                /* Null terminate! */
  226. X}
  227. X
  228. Xsave_subject(buffer)
  229. Xchar *buffer;
  230. X{
  231. X    /** save all but the word "Subject:" for the subject **/
  232. X
  233. X    register int skip = 8;  /* skip "Subject:" initially */
  234. X
  235. X    while (buffer[skip] == ' ') skip++;
  236. X
  237. X    strcpy(subject, (char *) buffer + skip);
  238. X}
  239. X
  240. Xsave_to(buffer)
  241. Xchar *buffer;
  242. X{
  243. X    /** save all but the word "To:" or "Cc:" for the to list **/
  244. X
  245. X    register int skip = 3;    /* skip "To:" or "Cc:" initially */
  246. X
  247. X    while (buffer[skip] == ' ') skip++;
  248. X
  249. X    strcat(to, (char *) buffer + skip);
  250. X}
  251. X
  252. X#ifdef USE_EMBEDDED_ADDRESSES
  253. X
  254. Xsave_embedded_address(buffer, fieldname)
  255. Xchar *buffer, *fieldname;
  256. X{
  257. X    /** this will replace the 'from' address with the one given, 
  258. X        unless the address is from a 'reply-to' field (which overrides 
  259. X        the From: field).  The buffer given to this routine can have one 
  260. X            of three forms:
  261. X        fieldname: username <address>
  262. X        fieldname: address (username)
  263. X        fieldname: address
  264. X    **/
  265. X    
  266. X    static int processed_a_reply_to = 0;
  267. X    char address[LONG_STRING];
  268. X    register int i, j = 0;
  269. X
  270. X    /** first let's extract the address from this line.. **/
  271. X
  272. X    if (buffer[strlen(buffer)-1] == '>') {    /* case #1 */
  273. X      for (i=strlen(buffer)-1; buffer[i] != '<' && i > 0; i--)
  274. X        /* nothing - just move backwards .. */ ;
  275. X      i++;    /* skip the leading '<' symbol */
  276. X      while (buffer[i] != '>')
  277. X        address[j++] = buffer[i++];
  278. X      address[j] = '\0';
  279. X    }
  280. X    else {    /* get past "from:" and copy until white space or paren hit */
  281. X      for (i=strlen(fieldname); whitespace(buffer[i]); i++)
  282. X         /* skip past that... */ ;
  283. X      while (buffer[i] != '(' && ! whitespace(buffer[i]) && buffer[i]!='\0')
  284. X        address[j++] = buffer[i++];
  285. X      address[j] = '\0';
  286. X    }
  287. X
  288. X    /** now let's see if we should overwrite the existing from address
  289. X        with this one or not.. **/
  290. X
  291. X    if (processed_a_reply_to)
  292. X      return;    /* forget it! */
  293. X
  294. X    strcpy(from, address);            /* replaced!! */
  295. X
  296. X    if (strcmp(fieldname, "Reply-To:") == 0)
  297. X      processed_a_reply_to++;
  298. X}
  299. X#endif
  300. SHAR_EOF
  301. echo "File filter/filter.c is complete"
  302. chmod 0444 filter/filter.c || echo "restore of filter/filter.c fails"
  303. echo "x - extracting filter/lock.c (Text)"
  304. sed 's/^X//' << 'SHAR_EOF' > filter/lock.c &&
  305. X
  306. Xstatic char rcsid[] ="@(#)$Id: lock.c,v 4.1 90/04/28 22:41:57 syd Exp $";
  307. X
  308. X/*******************************************************************************
  309. X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
  310. X *
  311. X *             Copyright (c) 1986, 1987 Dave Taylor
  312. X *             Copyright (c) 1988, 1989, 1990 USENET Community Trust
  313. X *******************************************************************************
  314. X * Bug reports, patches, comments, suggestions should be sent to:
  315. X *
  316. X *    Syd Weinstein - elm@DSI.COM
  317. X *            dsinc!elm
  318. X *
  319. X *******************************************************************************
  320. X * $Log:    lock.c,v $
  321. X * Revision 4.1  90/04/28  22:41:57  syd
  322. X * checkin of Elm 2.3 as of Release PL0
  323. X * 
  324. X *
  325. X ******************************************************************************/
  326. X
  327. X
  328. X/** The lock() and unlock() routines herein duplicate exactly the
  329. X    equivalent routines in the Elm Mail System, and should also be
  330. X    compatible with sendmail, rmail, etc etc.
  331. X
  332. X  
  333. X**/
  334. X
  335. X#include <stdio.h>
  336. X#include <fcntl.h>
  337. X#include <errno.h>
  338. X#include "defs.h"
  339. X#include "filter.h"
  340. X
  341. Xstatic  int  we_locked_it;
  342. Xstatic  char lockfile[SLEN];
  343. X
  344. X#ifdef    LOCK_BY_FLOCK
  345. X#include <sys/types.h>
  346. X#include <sys/file.h>
  347. Xstatic    flock_fd = -1;
  348. Xstatic    char flock_name[SLEN];
  349. X#endif
  350. X
  351. Xextern  int  errno;
  352. X
  353. Xint
  354. Xlock()
  355. X{
  356. X    /** This routine will return 1 if we could lock the mailfile,
  357. X        zero otherwise.
  358. X    **/
  359. X
  360. X    int attempts = 0, ret;
  361. X
  362. X#ifndef    LOCK_FLOCK_ONLY            /* { !LOCK_FLOCK_ONLY    */
  363. X    sprintf(lockfile,  "%s%s.lock", mailhome, username);
  364. X#ifdef PIDCHECK
  365. X    /** first, try to read the lock file, and if possible, check the pid.
  366. X        If we can validate that the pid is no longer active, then remove
  367. X        the lock file.
  368. X    **/
  369. X    if((ret=open(lockfile,O_RDONLY)) != -1) {
  370. X      char pid_buffer[SHORT];
  371. X      if (read(ret, pid_buffer, SHORT) > 0) {
  372. X        attempts = atoi(pid_buffer);
  373. X        if (attempts) {
  374. X          if (kill(attempts, 0)) {
  375. X            close(ret);
  376. X            if (unlink(lockfile) != 0)
  377. X          return(1);
  378. X          }
  379. X        }
  380. X      }
  381. X      attempts = 0;
  382. X        }
  383. X#endif
  384. X
  385. X    while ((ret = open(lockfile, O_WRONLY | O_CREAT | O_EXCL, 0444)) < 0 
  386. X           && attempts++ < 10) {
  387. X      sleep(3);    /* wait three seconds each pass, okay?? */
  388. X    }
  389. X
  390. X    if (ret >= 0) {
  391. X      we_locked_it++;
  392. X      close(ret);            /* no need to keep it open! */
  393. X      ret = 1;
  394. X    } else {
  395. X      ret = 0;
  396. X    }
  397. X      
  398. X#endif                    /* } !LOCK_FLOCK_ONLY    */
  399. X#ifdef    LOCK_BY_FLOCK            /* { LOCK_BY_FLOCK    */
  400. X    (void)sprintf(flock_name,"%s%s",mailhome,username);
  401. X    flock_fd = open(flock_name,O_RDONLY);
  402. X    if ( flock_fd >= 0 )
  403. X      for (attempts = 0; attempts < 10; attempts++) {
  404. X        if ( (ret = flock(flock_fd,LOCK_NB|LOCK_EX)) != -1 )
  405. X            break;
  406. X        if ( errno != EWOULDBLOCK && errno != EAGAIN )
  407. X            break;
  408. X        (void)sleep((unsigned)3);
  409. X      }
  410. X    if ( flock_fd >= 0 && ret == 0 ) {
  411. X        we_locked_it++;
  412. X        ret = 1;
  413. X    } else {
  414. X        we_locked_it = 0;
  415. X        if ( lockfile[0] ) {
  416. X            (void)unlink(lockfile);
  417. X        lockfile[0] = 0;
  418. X        }
  419. X        if ( flock_fd >= 0 ) {
  420. X            (void)close(flock_fd);
  421. X            flock_fd = -1;
  422. X        }
  423. X        ret = 0;
  424. X    }
  425. X#endif
  426. X    return(ret);
  427. X}
  428. X
  429. Xunlock()
  430. X{
  431. X    /** this routine will remove the lock file, but only if we were
  432. X        the people that locked it in the first place... **/
  433. X
  434. X#ifndef    LOCK_FLOCK_ONLY
  435. X    if (we_locked_it && lockfile[0]) {
  436. X      unlink(lockfile);    /* blamo! */
  437. X      lockfile[0] = 0;
  438. X    }
  439. X#endif
  440. X#ifdef    LOCK_BY_FLOCK
  441. X    if (we_locked_it && flock_fd >= 0) {
  442. X      (void)close(flock_fd);
  443. X      flock_fd = -1;
  444. X    }
  445. X#endif
  446. X    we_locked_it = 0;
  447. X}
  448. SHAR_EOF
  449. chmod 0444 filter/lock.c || echo "restore of filter/lock.c fails"
  450. echo "x - extracting filter/parse.c (Text)"
  451. sed 's/^X//' << 'SHAR_EOF' > filter/parse.c &&
  452. X
  453. Xstatic char rcsid[] ="@(#)$Id: parse.c,v 4.1 90/04/28 22:41:58 syd Exp $";
  454. X
  455. X/*******************************************************************************
  456. X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
  457. X *
  458. X *             Copyright (c) 1986, 1987 Dave Taylor
  459. X *             Copyright (c) 1988, 1989, 1990 USENET Community Trust
  460. X *******************************************************************************
  461. X * Bug reports, patches, comments, suggestions should be sent to:
  462. X *
  463. X *    Syd Weinstein - elm@DSI.COM
  464. X *            dsinc!elm
  465. X *
  466. X *******************************************************************************
  467. X * $Log:    parse.c,v $
  468. X * Revision 4.1  90/04/28  22:41:58  syd
  469. X * checkin of Elm 2.3 as of Release PL0
  470. X * 
  471. X *
  472. X ******************************************************************************/
  473. X
  474. X
  475. X/** This is the parser for the filter program.  It accepts a wide variety of
  476. X    constructs, building the ruleset table as it goes along.  Check the 
  477. X    data structure in filter.h for more information on how the rules are
  478. X    stored.  The parser is a cunning state-table based program.
  479. X
  480. X**/
  481. X
  482. X#include <stdio.h>
  483. X#include <ctype.h>
  484. X
  485. X#include "defs.h"
  486. X#include "filter.h"
  487. X
  488. X#define NONE            0
  489. X#define AND            10
  490. X
  491. X#define NEXT_CONDITION        0
  492. X#define GETTING_OP        1
  493. X#define READING_ARGUMENT    2
  494. X#define READING_ACTION        3
  495. X#define ACTION_ARGUMENT        4
  496. X
  497. Xchar *strtok(), *whatname(), *actionname();
  498. X
  499. Xint
  500. Xget_filter_rules()
  501. X{
  502. X    /** Given the users home directory, open and parse their rules table,
  503. X        building the data structure as we go along.
  504. X        returns -1 if we hit an error of any sort...
  505. X    **/
  506. X
  507. X    FILE *fd;                /* the file descriptor     */
  508. X    char  buffer[SLEN],             /* fd reading buffer       */
  509. X          *str,                 /* ptr to read string      */
  510. X          *word,                /* ptr to 'token'          */
  511. X          filename[SLEN],             /* the name of the ruleset */
  512. X          action_argument[SLEN],         /* action arg, per rule    */
  513. X          cond_argument[SLEN];        /* cond arg, per condition */
  514. X    int   not_condition = FALSE,         /* are we in a "not" ??    */
  515. X          type=NONE,             /* what TYPE of condition? */
  516. X          lasttype,             /* and the previous TYPE?  */
  517. X          state = NEXT_CONDITION,        /* the current state       */
  518. X          in_single, in_double,         /* for handling spaces.    */
  519. X          i,                 /* misc integer for loops  */
  520. X          relop = NONE,            /* relational operator     */
  521. X          action,                 /* the current action type */
  522. X          buflen,                /* the length of buffer    */
  523. X          line = 0;                /* line number we're on    */
  524. X
  525. X    struct condition_rec    *cond, *newcond;
  526. X
  527. X    sprintf(filename,"%s/%s", home, filterfile);
  528. X
  529. X    if ((fd = fopen(filename,"r")) == NULL) {
  530. X      if (outfd != NULL)
  531. X       fprintf(outfd,"filter (%s): Couldn't read user filter rules file!\n",
  532. X          username);
  533. X      return(-1);
  534. X    }
  535. X
  536. X    cond_argument[0] = action_argument[0] = '\0';
  537. X
  538. X    /* Now, for each line... **/
  539. X
  540. X    if ((cond = (struct condition_rec *) 
  541. X             malloc(sizeof(struct condition_rec))) == NULL) {
  542. X      if (outfd != NULL)
  543. X        fprintf(outfd,"filter (%s): couldn't malloc first condition rec!\n",
  544. X            username);
  545. X      return(-1);
  546. X    }
  547. X    
  548. X    rules[total_rules].condition = cond;    /* hooked in! */
  549. X
  550. X    while (fgets(buffer, SLEN, fd) != NULL) {
  551. X      line++;
  552. X
  553. X      if (buffer[0] == '#' || (buflen = strlen(buffer)) < 2)
  554. X        continue;        /* nothing to look at! */
  555. X
  556. X      in_single = in_double = 0;
  557. X
  558. X      for (i=0; i < buflen; i++) {
  559. X        if (buffer[i] == '"') 
  560. X          in_double = ! in_double;
  561. X        else if (buffer[i] == '\'')
  562. X          in_single = ! in_single;
  563. X        if ((in_double || in_single) && buffer[i] == ' ')
  564. X          buffer[i] = '_';
  565. X      }
  566. X
  567. X      lasttype = type;
  568. X      type = NONE;
  569. X      str = (char *) buffer;
  570. X
  571. X      /** Three pieces to this loop - get the `field', the 'relop' (if
  572. X          there) then, if needed, get the argument to check against (not 
  573. X          needed for errors or the AND, of course)
  574. X      **/
  575. X
  576. X      while ((word = strtok(str, " ()[]:\t\n")) != NULL) {
  577. X
  578. X        str = (char *) NULL;        /* we can start stomping! */
  579. X      
  580. X        lowercase(word);
  581. X
  582. X        if (strcmp(word, "if") == 0) {    /* only ONE 'if' allowed */
  583. X          if ((word = strtok(str, " ()[]:\t\n")) == NULL)    /* NEXT! */
  584. X            continue;
  585. X          lowercase(word);
  586. X        }
  587. X    
  588. X        if (state == NEXT_CONDITION) {
  589. X          lasttype = type;
  590. X          type = NONE;
  591. X
  592. X          if (the_same(word, "not") || the_same(word, "!")) {
  593. X            not_condition = TRUE;
  594. X            if ((word = strtok(str, " ()[]'\"\t\n")) == NULL)
  595. X              continue;
  596. X          }
  597. X
  598. X               if (the_same(word, "from"))         type = FROM;
  599. X          else if (the_same(word, "to"))         type = TO;
  600. X          else if (the_same(word, "subject"))   type = SUBJECT;
  601. X          else if (the_same(word, "lines"))     type = LINES;
  602. X          else if (the_same(word, "contains"))  type = CONTAINS;
  603. X          else if (the_same(word, "and") || 
  604. X                   the_same(word, "&&"))         type = AND;
  605. X
  606. X          else if (the_same(word,"?") || the_same(word, "then") || 
  607. X               the_same(word, "always")) {
  608. X
  609. X        /** shove THIS puppy into the structure and let's continue! **/
  610. X
  611. X            if (lasttype == AND) {
  612. X          if (outfd != NULL)
  613. X                fprintf(outfd,
  614. X         "filter (%s): Error reading line %d of rules - badly placed \"and\"\n",
  615. X            username, line);
  616. X          return(-1);
  617. X            }
  618. X
  619. X            if (the_same(word, "always"))
  620. X          cond->matchwhat = ALWAYS;    /* so it's a hack... */
  621. X        else
  622. X          cond->matchwhat = lasttype;
  623. X
  624. X            if (relop == NONE) relop = EQ;    /* otherwise can't do -relop */
  625. X            cond->relation  = (not_condition? - (relop) : relop);
  626. X
  627. X        for (i=strlen(cond_argument); --i >= 0;)
  628. X              if (cond_argument[i] == '_') cond_argument[i] = ' ';
  629. X
  630. X        strcpy(cond->argument1, cond_argument);
  631. X            if ((newcond = (struct condition_rec *)
  632. X             malloc(sizeof(struct condition_rec))) == NULL) {
  633. X          if (outfd != NULL)
  634. X                fprintf(outfd,
  635. X                     "filter (%s): Couldn't malloc new cond rec!!\n",
  636. X                    username);
  637. X          return(-1);
  638. X            }
  639. X            cond->next = NULL;
  640. X
  641. X            relop = EQ;    /* default relational condition */
  642. X
  643. X            state = READING_ACTION;
  644. X            if ((word = strtok(str, " ()[]'\"\t\n")) == NULL)
  645. X              continue;
  646. X            goto get_outta_loop;
  647. X          }
  648. X
  649. X          if (type == NONE) {
  650. X        if (outfd != NULL)
  651. X              fprintf(outfd,
  652. X      "filter (%s): Error reading line %d of rules - field \"%s\" unknown!\n",
  653. X             username, line, word);
  654. X        return(-1);
  655. X          }
  656. X
  657. X          if (type == AND) {
  658. X
  659. X        /** shove THIS puppy into the structure and let's continue! **/
  660. X
  661. X        cond->matchwhat = lasttype;
  662. X            cond->relation  = (not_condition? - (relop) : relop);
  663. X        strcpy(cond->argument1, cond_argument);
  664. X            if ((newcond = (struct condition_rec *)
  665. X                 malloc(sizeof(struct condition_rec))) == NULL) {
  666. X          if (outfd != NULL)
  667. X                fprintf(outfd,
  668. X            "filter (%s): Couldn't malloc new cond rec!!\n",
  669. X            username);
  670. X          return(-1);
  671. X            }
  672. X            cond->next = newcond;
  673. X        cond = newcond;
  674. X        cond->next = NULL;
  675. X
  676. X            not_condition = FALSE;
  677. X            state = NEXT_CONDITION;
  678. X          }
  679. X          else {
  680. X            state = GETTING_OP;
  681. X          }
  682. X        }
  683. X
  684. Xget_outta_loop:     /* jump out when we change state, if needed */
  685. X
  686. X        if (state == GETTING_OP) {
  687. X
  688. X           if ((word = strtok(str, " ()[]'\"\t\n")) == NULL)
  689. X             continue;
  690. X
  691. X           lowercase(word);
  692. X
  693. X           relop = NONE;
  694. X
  695. X           if (the_same(word, "=") || the_same(word, "in") || 
  696. X                   the_same(word, "contains")) {
  697. X                 state = READING_ARGUMENT;
  698. X             relop = EQ;
  699. X           }
  700. X           else {
  701. X             if (the_same(word, "<="))     relop = LE;
  702. X             else if (the_same(word, ">="))    relop = GE;
  703. X             else if (the_same(word, ">"))    relop = GT;
  704. X             else if (the_same(word, "<>")||
  705. X                  the_same(word, "!="))    relop = NE;
  706. X             else if (the_same(word, "<"))    relop = LT;
  707. X
  708. X         /* maybe there isn't a relop at all!! */
  709. X
  710. X         state=READING_ARGUMENT;
  711. X
  712. X           }
  713. X        }
  714. X         
  715. X        if (state == READING_ARGUMENT) {
  716. X          if (relop != NONE) {
  717. X            if ((word = strtok(str, " ()[]'\"\t\n")) == NULL)
  718. X              continue;
  719. X          }
  720. X          for (i=strlen(word); --i>=0;)
  721. X            if (word[i] == '_') word[i] = ' ';
  722. X
  723. X          strcpy(cond_argument, word);
  724. X          state = NEXT_CONDITION;
  725. X        }
  726. X
  727. X        if (state == READING_ACTION) {
  728. X          action = NONE;
  729. X
  730. X          not_condition = FALSE;
  731. X
  732. X          if (the_same(word, "delete"))       action = DELETE_MSG;
  733. X          else if (the_same(word, "savec"))   action = SAVECC;
  734. X          else if (the_same(word, "save"))    action = SAVE;
  735. X          else if (the_same(word, "forward")) action = FORWARD;
  736. X          else if (the_same(word, "exec"))    action = EXEC;
  737. X          else if (the_same(word, "leave"))   action = LEAVE;
  738. X          else {
  739. X        if (outfd != NULL)
  740. X              fprintf(outfd,
  741. X    "filter (%s): Error on line %d of rules - action \"%s\" unknown\n",
  742. X            username, line, word);
  743. X          }
  744. X
  745. X          if (action == DELETE_MSG || action == LEAVE) {
  746. X            /** add this to the rules section and alloc next... **/
  747. X
  748. X            rules[total_rules].action = action;
  749. X        rules[total_rules].argument2[0] = '\0';    /* nothing! */
  750. X            total_rules++;
  751. X             
  752. X            if ((cond = (struct condition_rec *)
  753. X             malloc(sizeof(struct condition_rec))) == NULL) {
  754. X          if (outfd != NULL)
  755. X                fprintf(outfd,
  756. X            "filter (%s): couldn't malloc first condition rec!\n",
  757. X            username);
  758. X              return(-1);
  759. X            }
  760. X    
  761. X            rules[total_rules].condition = cond;    /* hooked in! */
  762. X            state = NEXT_CONDITION;    
  763. X          }
  764. X          else {
  765. X            state = ACTION_ARGUMENT;
  766. X          }
  767. X
  768. X          if ((word = strtok(str, " ()[]'\"\t\n")) == NULL)
  769. X            continue;
  770. X
  771. X        }
  772. X    
  773. X        if (state == ACTION_ARGUMENT) {
  774. X          strcpy(action_argument, word);
  775. X
  776. X          /** add this to the rules section and alloc next... **/
  777. X
  778. X          rules[total_rules].action = action;
  779. X          expand_macros(action_argument, rules[total_rules].argument2,line,
  780. X                printing_rules);
  781. X          total_rules++;
  782. X             
  783. X          if ((cond = (struct condition_rec *)
  784. X             malloc(sizeof(struct condition_rec))) == NULL) {
  785. X        if (outfd != NULL)
  786. X              fprintf(outfd,
  787. X              "filter (%s): couldn't malloc first condition rec!\n",
  788. X              username);
  789. X            return(-1);
  790. X          }
  791. X    
  792. X          rules[total_rules].condition = cond;    /* hooked in! */
  793. X
  794. X          state = NEXT_CONDITION;
  795. X          if ((word = strtok(str, " ()[]'\"\t\n")) == NULL)
  796. X            continue;
  797. X        }
  798. X      }
  799. X    }
  800. X
  801. X    return(0);
  802. X}
  803. SHAR_EOF
  804. chmod 0444 filter/parse.c || echo "restore of filter/parse.c fails"
  805. echo "x - extracting filter/rules.c (Text)"
  806. sed 's/^X//' << 'SHAR_EOF' > filter/rules.c &&
  807. X
  808. Xstatic char rcsid[] ="@(#)$Id: rules.c,v 4.1 90/04/28 22:42:00 syd Exp $";
  809. X
  810. X/*******************************************************************************
  811. X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
  812. X *
  813. X *             Copyright (c) 1986, 1987 Dave Taylor
  814. X *             Copyright (c) 1988, 1989, 1990 USENET Community Trust
  815. X *******************************************************************************
  816. X * Bug reports, patches, comments, suggestions should be sent to:
  817. X *
  818. X *    Syd Weinstein - elm@DSI.COM
  819. X *            dsinc!elm
  820. X *
  821. X *******************************************************************************
  822. X * $Log:    rules.c,v $
  823. X * Revision 4.1  90/04/28  22:42:00  syd
  824. X * checkin of Elm 2.3 as of Release PL0
  825. X * 
  826. X *
  827. X ******************************************************************************/
  828. X
  829. X/** This file contains all the rule routines, including those that apply the
  830. X    specified rules and the routine to print the rules out.
  831. X
  832. X**/
  833. X
  834. X#include <stdio.h>
  835. X#include <pwd.h>
  836. X#include <ctype.h>
  837. X#include "defs.h"
  838. X#ifdef I_TIME
  839. X#  include <time.h>
  840. X#endif
  841. X#ifdef I_SYSTIME
  842. X#  include <sys/time.h>
  843. X#endif
  844. X#include <fcntl.h>
  845. X
  846. X#include "filter.h"
  847. X
  848. Xchar *listrule();
  849. X
  850. Xint
  851. Xaction_from_ruleset()
  852. X{
  853. X    /** Given the set of rules we've read in and the current to, from, 
  854. X        and subject, try to match one.  Return the ACTION of the match
  855. X            or LEAVE if none found that apply.
  856. X    **/
  857. X
  858. X    register int iindex = 0, not, relation, try_next_rule, x;
  859. X    struct condition_rec *cond;
  860. X
  861. X    while (iindex < total_rules) {
  862. X      cond = rules[iindex].condition;
  863. X      try_next_rule = 0;
  864. X
  865. X      while (cond != NULL && ! try_next_rule) {
  866. X        
  867. X        not = (cond->relation < 0);
  868. X        relation = abs(cond->relation);
  869. X    
  870. X        switch (cond->matchwhat) {
  871. X
  872. X          case TO     : x = contains(to, cond->argument1);         break;
  873. X          case FROM   : x = contains(from, cond->argument1);     break;
  874. X          case SUBJECT: x = contains(subject, cond->argument1);    break;
  875. X          case LINES  : x = compare(lines, relation, cond->argument1);break;
  876. X               
  877. X          case CONTAINS: if (outfd != NULL) fprintf(outfd,
  878. X       "filter (%s): Error: rules based on 'contains' are not implemented!\n",
  879. X                username);
  880. X                if (outfd != NULL) fclose(outfd);
  881. X                exit(0);         
  882. X
  883. X          case ALWAYS: not = FALSE; x = TRUE;            break;
  884. X        }
  885. X
  886. X        if ((not && x) || ((! not) && (! x))) /* this test failed (LISP?) */
  887. X          try_next_rule++;
  888. X        else
  889. X          cond = cond->next;          /* next condition, if any?  */
  890. X      }
  891. X
  892. X      if (! try_next_rule) {
  893. X        rule_choosen = iindex;
  894. X         return(rules[rule_choosen].action);
  895. X      }
  896. X      iindex++;
  897. X    }
  898. X
  899. X    rule_choosen = -1;
  900. X    return(LEAVE);
  901. X}
  902. X
  903. X#define get_the_time()    if (!gotten_time) {           \
  904. X               thetime = time( (long *) 0);   \
  905. X               timerec = localtime(&thetime); \
  906. X               gotten_time++;           \
  907. X            }
  908. X
  909. Xexpand_macros(word, buffer, line, display)
  910. Xchar *word, *buffer;
  911. Xint  line, display;
  912. X{
  913. X    /** expand the allowable macros in the word;
  914. X        %d    = day of the month  
  915. X        %D    = day of the week  
  916. X            %h    = hour (0-23)     
  917. X        %m    = month of the year
  918. X        %r    = return address of sender
  919. X           %s    = subject of message
  920. X           %S    = "Re: subject of message"  (only add Re: if not there)
  921. X        %t    = hour:minute     
  922. X        %y    = year          
  923. X        or simply copies word into buffer. If "display" is set then
  924. X        instead it puts "<day-of-month>" etc. etc. in the output.
  925. X    **/
  926. X
  927. X#ifndef    _POSIX_SOURCE
  928. X    struct tm *localtime();
  929. X    long    time();
  930. X#endif
  931. X    struct tm *timerec;
  932. X    long    thetime;
  933. X    register int i, j=0, gotten_time = 0, reading_a_percent_sign = 0, len;
  934. X
  935. X    for (i = 0, len = strlen(word); i < len; i++) {
  936. X      if (reading_a_percent_sign) {
  937. X        reading_a_percent_sign = 0;
  938. X        switch (word[i]) {
  939. X
  940. X          case 'r' : buffer[j] = '\0';
  941. X             if (display)
  942. X                strcat(buffer, "<return-address>");
  943. X             else
  944. X               strcat(buffer, from);
  945. X                     j = strlen(buffer);
  946. X             break;
  947. X
  948. X          case 's' : buffer[j] = '\0';
  949. X             if (display)
  950. X                strcat(buffer, "<subject>");
  951. X             else {
  952. X               strcat(buffer, "\"");
  953. X               strcat(buffer, subject);
  954. X               strcat(buffer, "\"");
  955. X             }
  956. X                     j = strlen(buffer);
  957. X             break;
  958. X
  959. X          case 'S' : buffer[j] = '\0';
  960. X             if (display)
  961. X                strcat(buffer, "<Re: subject>");
  962. X             else {
  963. X               if (! the_same(subject, "Re:")) 
  964. X                 strcat(buffer, "\"Re: ");
  965. X               strcat(buffer, subject);
  966. X               strcat(buffer, "\"");
  967. X             }
  968. X                     j = strlen(buffer);
  969. X             break;
  970. X
  971. X          case 'd' : get_the_time(); buffer[j] = '\0';
  972. X             if (display)
  973. X               strcat(buffer, "<day-of-month>");
  974. X             else
  975. X               strcat(buffer, itoa(timerec->tm_mday,FALSE));
  976. X                     j = strlen(buffer);
  977. X             break;
  978. X
  979. X          case 'D' : get_the_time(); buffer[j] = '\0';
  980. X             if (display)
  981. X               strcat(buffer, "<day-of-week>");
  982. X             else
  983. X               strcat(buffer, itoa(timerec->tm_wday,FALSE));
  984. X                     j = strlen(buffer);
  985. X             break;
  986. X
  987. X          case 'm' : get_the_time(); buffer[j] = '\0';
  988. X             if (display)
  989. X               strcat(buffer, "<month>");
  990. X             else
  991. X               strcat(buffer, itoa(timerec->tm_mon+1,FALSE));
  992. X                     j = strlen(buffer);
  993. X             break;
  994. X
  995. X          case 'y' : get_the_time(); buffer[j] = '\0';
  996. X             if (display)
  997. X               strcat(buffer, "<year>");
  998. X             else
  999. X               strcat(buffer, itoa(timerec->tm_year,FALSE));
  1000. X                     j = strlen(buffer);
  1001. X             break;
  1002. X
  1003. X          case 'h' : get_the_time(); buffer[j] = '\0';
  1004. X             if (display)
  1005. X               strcat(buffer, "<hour>");
  1006. X             else
  1007. X               strcat(buffer, itoa(timerec->tm_hour,FALSE));
  1008. X                     j = strlen(buffer);
  1009. X             break;
  1010. X
  1011. X          case 't' : get_the_time(); buffer[j] = '\0';
  1012. X             if (display)
  1013. X               strcat(buffer, "<time>");
  1014. X                 else {
  1015. X               strcat(buffer, itoa(timerec->tm_hour,FALSE));
  1016. X               strcat(buffer, ":");
  1017. X               strcat(buffer, itoa(timerec->tm_min,TRUE));
  1018. X             }
  1019. X                     j = strlen(buffer);
  1020. X             break;
  1021. X
  1022. X          default  : if (outfd != NULL) fprintf(outfd,
  1023. X   "filter (%s): Error on line %d translating %%%c macro in word \"%s\"!\n",
  1024. X                     username, line, word[i], word);
  1025. X             if (outfd != NULL) fclose(outfd);
  1026. X             exit(1);
  1027. X        }
  1028. X      }
  1029. X      else if (word[i] == '%') 
  1030. X        reading_a_percent_sign++;
  1031. X      else 
  1032. X        buffer[j++] = (word[i] == '_' ? ' ' : word[i]);
  1033. X    }
  1034. X    buffer[j] = '\0';
  1035. X}
  1036. X
  1037. Xprint_rules()
  1038. X{
  1039. X    /** print the rules out.  A double check, of course! **/
  1040. X
  1041. X    register int i = -1;
  1042. X    char     *whatname(), *actionname();
  1043. X    struct   condition_rec *cond;
  1044. X
  1045. X    if (outfd == NULL) return;    /* why are we here, then? */
  1046. X
  1047. X    while (++i < total_rules) {
  1048. X      if (rules[i].condition->matchwhat == ALWAYS) {
  1049. X        fprintf(outfd, "\nRule %d:  ** always ** \n\t%s %s\n", i+1,
  1050. X         actionname(rules[i].action), listrule(rules[i].argument2));
  1051. X        continue;
  1052. X      }
  1053. X
  1054. X      fprintf(outfd, "\nRule %d:  if (", i+1);
  1055. X
  1056. X      cond = rules[i].condition;
  1057. X
  1058. X      while (cond != NULL) {
  1059. X        if (cond->relation < 0)
  1060. X          fprintf(outfd, "not %s %s %s%s%s", 
  1061. X              whatname(cond->matchwhat),
  1062. X              relationname(- (cond->relation)),
  1063. X              quoteit(cond->matchwhat),
  1064. X              cond->argument1,
  1065. X              quoteit(cond->matchwhat));
  1066. X        else
  1067. X          fprintf(outfd, "%s %s %s%s%s",
  1068. X              whatname(cond->matchwhat),
  1069. X              relationname(cond->relation),
  1070. X              quoteit(cond->matchwhat),
  1071. X              cond->argument1,
  1072. X              quoteit(cond->matchwhat));
  1073. X
  1074. X        cond = cond->next;
  1075. X
  1076. X        if (cond != NULL) fprintf(outfd, " and ");
  1077. X      }
  1078. X        
  1079. X      fprintf(outfd, ") then\n\t  %s %s\n", 
  1080. X         actionname(rules[i].action), 
  1081. X         listrule(rules[i].argument2));
  1082. X    }
  1083. X    fprintf(outfd, "\n");
  1084. X}
  1085. X
  1086. Xchar *whatname(n)
  1087. Xint n;
  1088. X{
  1089. X    static char buffer[10];
  1090. X
  1091. X    switch(n) {
  1092. X      case FROM   : return("from");
  1093. X      case TO     : return("to");
  1094. X      case SUBJECT: return("subject");
  1095. X      case LINES  : return ("lines");
  1096. X      case CONTAINS: return("contains");
  1097. X      default     : sprintf(buffer, "?%d?", n); return((char *)buffer);
  1098. X    }
  1099. X}
  1100. X
  1101. Xchar *actionname(n)
  1102. Xint n;
  1103. X{
  1104. X    switch(n) {
  1105. X      case DELETE_MSG : return("Delete");
  1106. X      case SAVE       : return("Save");
  1107. X      case SAVECC     : return("Copy and Save");
  1108. X      case FORWARD    : return("Forward");
  1109. X      case LEAVE      : return("Leave"); 
  1110. X      case EXEC       : return("Execute");
  1111. X      default         : return("?action?");
  1112. X    }
  1113. X}
  1114. X
  1115. Xint
  1116. Xcompare(line, relop, arg)
  1117. Xint line, relop;
  1118. Xchar *arg;
  1119. X{
  1120. X    /** Given the actual number of lines in the message, the relop
  1121. X        relation, and the number of lines in the rule, as a string (!),
  1122. X           return TRUE or FALSE according to which is correct.
  1123. X    **/
  1124. X
  1125. X    int rule_lines;
  1126. X
  1127. X    rule_lines = atoi(arg);
  1128. X
  1129. X    switch (relop) {
  1130. X      case LE: return(line <= rule_lines);
  1131. X      case LT: return(line <  rule_lines);
  1132. X      case GE: return(line >= rule_lines);
  1133. X      case GT: return(line >  rule_lines);
  1134. X      case NE: return(line != rule_lines);
  1135. X      case EQ: return(line == rule_lines);
  1136. X    }
  1137. X    return(-1);
  1138. X}
  1139. X
  1140. Xchar *listrule(rule)
  1141. Xchar *rule;
  1142. X{
  1143. X    /** simply translates all underscores into spaces again on the
  1144. X        way past... **/
  1145. X
  1146. X    static char buffer[SLEN];
  1147. X    register int i;
  1148. X
  1149. X    i = strlen(rule);
  1150. X    buffer[i] = '\0';
  1151. X    while (--i >= 0)
  1152. X      buffer[i] = (rule[i] == '_' ? ' ' : rule[i]);
  1153. X
  1154. X    return( (char *) buffer);
  1155. X}
  1156. SHAR_EOF
  1157. chmod 0444 filter/rules.c || echo "restore of filter/rules.c fails"
  1158. echo "x - extracting filter/summarize.c (Text)"
  1159. sed 's/^X//' << 'SHAR_EOF' > filter/summarize.c &&
  1160. X
  1161. Xstatic char rcsid[] ="@(#)$Id: summarize.c,v 4.1 90/04/28 22:42:02 syd Exp $";
  1162. X
  1163. X/*******************************************************************************
  1164. X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
  1165. X *
  1166. X *             Copyright (c) 1986, 1987 Dave Taylor
  1167. X *             Copyright (c) 1988, 1989, 1990 USENET Community Trust
  1168. X *******************************************************************************
  1169. X * Bug reports, patches, comments, suggestions should be sent to:
  1170. X *
  1171. X *    Syd Weinstein - elm@DSI.COM
  1172. X *            dsinc!elm
  1173. X *
  1174. X *******************************************************************************
  1175. X * $Log:    summarize.c,v $
  1176. X * Revision 4.1  90/04/28  22:42:02  syd
  1177. X * checkin of Elm 2.3 as of Release PL0
  1178. X * 
  1179. X *
  1180. X ******************************************************************************/
  1181. X
  1182. X/** This routine is called from the filter program (or can be called
  1183. X    directly with the correct arguments) and summarizes the users filterlog
  1184. X    file.  To be honest, there are two sorts of summaries that are
  1185. X    available - either the '.filterlog' file can be output (filter -S) 
  1186. X    or a summary by rule and times acted upon can be output (filter -s).
  1187. X    Either way, this program will delete the two associated files each
  1188. X    time ($HOME/.filterlog and $HOME/.filtersum) *if* the -c option is
  1189. X    used to the program (e.g. clear_logs is set to TRUE).
  1190. X
  1191. X**/
  1192. X
  1193. X#include <stdio.h>
  1194. X
  1195. X#include "defs.h"
  1196. X
  1197. X#include "filter.h"
  1198. X
  1199. Xshow_summary()
  1200. X{
  1201. X    /* Summarize usage of the program... */
  1202. X
  1203. X    FILE   *fd;                /* for output to temp file! */
  1204. X    char filename[SLEN],            /* name of the temp file    */
  1205. X         buffer[SLEN];            /* input buffer space       */
  1206. X    int  erroneous_rules = 0,
  1207. X         default_rules   = 0,
  1208. X         messages_filtered = 0,        /* how many have we touched? */
  1209. X         rule,
  1210. X         applied[MAXRULES];
  1211. X
  1212. X    sprintf(filename, "%s/%s", home, filtersum);
  1213. X
  1214. X    if ((fd = fopen(filename, "r")) == NULL) {
  1215. X      if (outfd != NULL)
  1216. X        fprintf(outfd,"filter (%s): Can't open filtersum file %s!\n",
  1217. X
  1218. X            username, filename);
  1219. X      if (outfd != NULL) fclose(outfd);
  1220. X      exit(1);
  1221. X    }
  1222. X
  1223. X    for (rule=0;rule < MAXRULES; rule++)
  1224. X      applied[rule] = 0;            /* initialize it all! */
  1225. X
  1226. X    /** Next we need to read it all in, incrementing by which rule
  1227. X        was used.  The format is simple - each line represents a 
  1228. X        single application of a rule, or '-1' if the default action
  1229. X        was taken.  Simple stuff, eh?  But oftentimes the best.  
  1230. X    **/
  1231. X
  1232. X    while (fgets(buffer, SLEN, fd) != NULL) {
  1233. X      if ((rule = atoi(buffer)) > total_rules || rule < -1) {
  1234. X        if (outfd != NULL)
  1235. X          fprintf(outfd,
  1236. X      "filter (%s): Warning - rule #%d is invalid data for short summary!!\n",
  1237. X                username, rule);
  1238. X        erroneous_rules++;
  1239. X      }
  1240. X      else if (rule == -1)
  1241. X        default_rules++;
  1242. X      else
  1243. X        applied[rule]++;
  1244. X      messages_filtered++;
  1245. X    }
  1246. X    
  1247. X    fclose(fd);
  1248. X
  1249. X    /** now let's summarize the data... **/
  1250. X
  1251. X    if (outfd == NULL) return;        /* no reason to go further */
  1252. X
  1253. X    fprintf(outfd, 
  1254. X        "\n\t\t\tA Summary of Filter Activity\n");
  1255. X    fprintf(outfd, 
  1256. X          "\t\t\t----------------------------\n\n");
  1257. X
  1258. X    fprintf(outfd,"A total of %d message%s %s filtered:\n\n",
  1259. X        messages_filtered, plural(messages_filtered),
  1260. X        messages_filtered > 1 ? "were" : "was");
  1261. X
  1262. X    if (erroneous_rules)
  1263. X      fprintf(outfd, 
  1264. X              "[Warning: %d erroneous rule%s logged and ignored!]\n\n",
  1265. X           erroneous_rules, erroneous_rules > 1? "s were" : " was");
  1266. X    
  1267. X    if (default_rules) {
  1268. X       fprintf(outfd,
  1269. X "The default rule of putting mail into your mailbox\n");
  1270. X       fprintf(outfd, "\tapplied %d time%s (%d%%)\n\n",
  1271. X           default_rules, plural(default_rules),
  1272. X           (default_rules*100+(messages_filtered>>1))/messages_filtered
  1273. X            );
  1274. X    }
  1275. X
  1276. X     /** and now for each rule we used... **/
  1277. X
  1278. X     for (rule = 0; rule < total_rules; rule++) {
  1279. X       if (applied[rule]) {
  1280. X          fprintf(outfd, "Rule #%d: ", rule+1);
  1281. X          switch (rules[rule].action) {
  1282. X          case LEAVE:        fprintf(outfd, "(leave mail in mailbox)");
  1283. X                    break;
  1284. X          case DELETE_MSG:  fprintf(outfd, "(delete message)");
  1285. X                    break;
  1286. X          case SAVE  :      fprintf(outfd, "(save in \"%s\")",
  1287. X                        rules[rule].argument2);        break;
  1288. X          case SAVECC:      fprintf(outfd, 
  1289. X                        "(left in mailbox and saved in \"%s\")",
  1290. X                        rules[rule].argument2);        break;
  1291. X          case FORWARD:     fprintf(outfd, "(forwarded to \"%s\")",
  1292. X                        rules[rule].argument2);        break;
  1293. X          case EXEC  :      fprintf(outfd, "(given to command \"%s\")",
  1294. X                        rules[rule].argument2);        break;
  1295. X         }
  1296. X         fprintf(outfd, "\n\tapplied %d time%s (%d%%)\n\n", 
  1297. X             applied[rule], plural(applied[rule]),
  1298. X                (applied[rule]*100+(messages_filtered>>1))/messages_filtered
  1299. X            );
  1300. X      }
  1301. X    }
  1302. X
  1303. X    if (long_summary) {
  1304. X
  1305. X      /* next, after a ^L, include the actual log file... */
  1306. X
  1307. X      sprintf(filename, "%s/%s", home, filterlog);
  1308. X
  1309. X      if ((fd = fopen(filename, "r")) == NULL) {
  1310. X        fprintf(outfd,"filter (%s): Can't open filterlog file %s!\n",
  1311. X              username, filename);
  1312. X      }
  1313. X      else {
  1314. X        fprintf(outfd, "\n\n\n%c\n\nExplicit log of each action;\n\n", 
  1315. X            (char) 12);
  1316. X        while (fgets(buffer, SLEN, fd) != NULL)
  1317. X          fprintf(outfd, "%s", buffer);
  1318. X        fprintf(outfd, "\n-----\n");
  1319. X        fclose(fd);
  1320. X      }
  1321. X    }
  1322. X
  1323. X    /* now remove the log files, please! */
  1324. X
  1325. X    if (clear_logs) {
  1326. X      sprintf(filename, "%s/%s", home, filterlog);
  1327. X      unlink(filename);
  1328. X      sprintf(filename, "%s/%s", home, filtersum);
  1329. X      unlink(filename);
  1330. X    }
  1331. X
  1332. X    return;
  1333. X}
  1334. SHAR_EOF
  1335. chmod 0444 filter/summarize.c || echo "restore of filter/summarize.c fails"
  1336. echo "x - extracting filter/utils.c (Text)"
  1337. sed 's/^X//' << 'SHAR_EOF' > filter/utils.c &&
  1338. X
  1339. Xstatic char rcsid[] ="@(#)$Id: utils.c,v 4.1 90/04/28 22:42:03 syd Exp $";
  1340. X
  1341. X/*******************************************************************************
  1342. X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
  1343. X *
  1344. X *             Copyright (c) 1986, 1987 Dave Taylor
  1345. X *             Copyright (c) 1988, 1989, 1990 USENET Community Trust
  1346. X *******************************************************************************
  1347. X * Bug reports, patches, comments, suggestions should be sent to:
  1348. X *
  1349. X *    Syd Weinstein - elm@DSI.COM
  1350. X *            dsinc!elm
  1351. X *
  1352. X *******************************************************************************
  1353. X * $Log:    utils.c,v $
  1354. X * Revision 4.1  90/04/28  22:42:03  syd
  1355. X * checkin of Elm 2.3 as of Release PL0
  1356. X * 
  1357. X *
  1358. X ******************************************************************************/
  1359. X
  1360. X/** Utility routines for the filter program...
  1361. X
  1362. X**/
  1363. X
  1364. X#include <stdio.h>
  1365. X#include <pwd.h>
  1366. X#include <ctype.h>
  1367. X#include <fcntl.h>
  1368. X
  1369. X#include "defs.h"
  1370. X#include "filter.h"
  1371. X
  1372. Xleave(reason)
  1373. Xchar *reason;
  1374. X{
  1375. X    if (outfd != NULL)
  1376. X      fprintf(outfd,"filter (%s): LEAVE %s\n", username, reason);
  1377. X    if (outfd != NULL) fclose(outfd);
  1378. X    exit(1);
  1379. X}
  1380. X
  1381. Xlog(what)
  1382. Xint what;
  1383. X{
  1384. X    /** make an entry in the log files for the specified entry **/
  1385. X
  1386. X    FILE *fd;
  1387. X    char filename[SLEN];
  1388. X
  1389. X    if (! show_only) {
  1390. X      sprintf(filename, "%s/%s", home, filtersum);    /* log action once! */
  1391. X      if ((fd = fopen(filename, "a")) == NULL) {
  1392. X        if (outfd != NULL)
  1393. X          fprintf(outfd, "filter (%s): Couldn't open log file %s\n", 
  1394. X            filename);
  1395. X        fd = stdout;
  1396. X      }
  1397. X      fprintf(fd, "%d\n", rule_choosen);
  1398. X      fclose(fd);
  1399. X    }
  1400. X
  1401. X    sprintf(filename, "%s/%s", home, filterlog);
  1402. X
  1403. X    if (show_only)
  1404. X      fd = stdout;
  1405. X    else if ((fd = fopen(filename, "a")) == NULL) {
  1406. X      if (outfd != NULL)
  1407. X        fprintf(outfd, "filter (%s): Couldn't open log file %s\n", 
  1408. X          filename);
  1409. X      fd = stdout;
  1410. X    }
  1411. X    
  1412. X#ifdef _IOFBF
  1413. X    setvbuf(fd, NULL, _IOFBF, BUFSIZ);
  1414. X#endif
  1415. X
  1416. X    if (strlen(from) + strlen(subject) > 60)
  1417. X      fprintf(fd, "\nMail from %s\n\tabout %s\n", from, subject);
  1418. X    else
  1419. X      fprintf(fd, "\nMail from %s about %s\n", from, subject);
  1420. X
  1421. X    if (rule_choosen != -1)
  1422. X      if (rules[rule_choosen].condition->matchwhat == TO)
  1423. X        fprintf(fd, "\t(addressed to %s)\n", to);
  1424. X
  1425. X    switch (what) {
  1426. X      case DELETE_MSG : fprintf(fd, "\tDELETED");            break;
  1427. X      case SAVE       : fprintf(fd, "\tSAVED in file \"%s\"", 
  1428. X                rules[rule_choosen].argument2);        break;
  1429. X      case SAVECC     : fprintf(fd,"\tSAVED in file \"%s\" AND PUT in mailbox", 
  1430. X                rules[rule_choosen].argument2);      break;
  1431. X      case FORWARD    : fprintf(fd, "\tFORWARDED to \"%s\"", 
  1432. X                rules[rule_choosen].argument2);        break;
  1433. X      case EXEC       : fprintf(fd, "\tEXECUTED \"%s\"",
  1434. X                rules[rule_choosen].argument2);        break;
  1435. X      case LEAVE      : fprintf(fd, "\tPUT in mailbox");        break;
  1436. X    }
  1437. X
  1438. X    if (rule_choosen != -1)
  1439. X      fprintf(fd, " by rule #%d\n", rule_choosen+1);
  1440. X    else
  1441. X      fprintf(fd, ": the default action\n");
  1442. X
  1443. X    fflush(fd);
  1444. X    fclose(fd);
  1445. X}
  1446. X
  1447. Xint
  1448. Xcontains(string, pattern)
  1449. Xchar *string, *pattern;
  1450. X{
  1451. X    /** Returns TRUE iff pattern occurs IN IT'S ENTIRETY in buffer. **/ 
  1452. X
  1453. X    register int i = 0, j = 0;
  1454. X
  1455. X    while (string[i] != '\0') {
  1456. X      while (tolower(string[i++]) == tolower(pattern[j++])) 
  1457. X        if (pattern[j] == '\0') 
  1458. X          return(TRUE);
  1459. X      i = i - j + 1;
  1460. X      j = 0;
  1461. X    }
  1462. X    return(FALSE);
  1463. X}
  1464. X
  1465. Xchar *itoa(i, two_digit)
  1466. Xint i, two_digit;
  1467. X{    
  1468. X    /** return 'i' as a null-terminated string.  If two-digit use that
  1469. X        size field explicitly!  **/
  1470. X
  1471. X    static char value[10];
  1472. X    
  1473. X    if (two_digit)
  1474. X      sprintf(value, "%02d", i);
  1475. X    else
  1476. X      sprintf(value, "%d", i);
  1477. X
  1478. X    return( (char *) value);
  1479. X}
  1480. X
  1481. Xlowercase(string)
  1482. Xchar *string;
  1483. X{
  1484. X    /** translate string into all lower case **/
  1485. X
  1486. X    register int i;
  1487. X
  1488. X    for (i= strlen(string); --i >= 0; )
  1489. X      if (isupper(string[i]))
  1490. X        string[i] = tolower(string[i]);
  1491. X}
  1492. SHAR_EOF
  1493. chmod 0444 filter/utils.c || echo "restore of filter/utils.c fails"
  1494. echo "x - extracting hdrs/curses.h (Text)"
  1495. sed 's/^X//' << 'SHAR_EOF' > hdrs/curses.h &&
  1496. X
  1497. X/* $Id: curses.h,v 4.1 90/04/28 22:42:05 syd Exp $ */
  1498. X
  1499. X/*******************************************************************************
  1500. X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
  1501. X *
  1502. X *             Copyright (c) 1986, 1987 Dave Taylor
  1503. X *             Copyright (c) 1988, 1989, 1990 USENET Community Trust
  1504. X *******************************************************************************
  1505. X * Bug reports, patches, comments, suggestions should be sent to:
  1506. X *
  1507. X *    Syd Weinstein, Elm Coordinator
  1508. X *    elm@DSI.COM            dsinc!elm
  1509. X *
  1510. X *******************************************************************************
  1511. X * $Log:    curses.h,v $
  1512. X * Revision 4.1  90/04/28  22:42:05  syd
  1513. X * checkin of Elm 2.3 as of Release PL0
  1514. X * 
  1515. X *
  1516. X ******************************************************************************/
  1517. X
  1518. X     /*** Include file for seperate compilation.  ***/
  1519. X
  1520. X#define OFF        0
  1521. X#define ON         1
  1522. X
  1523. Xint  InitScreen(),      /* This must be called before anything else!! */
  1524. X
  1525. X     ClearScreen(),      CleartoEOLN(),
  1526. X
  1527. X     MoveCursor(),
  1528. X
  1529. X     StartBold(),        EndBold(), 
  1530. X     StartUnderline(),   EndUnderline(), 
  1531. X     StartHalfbright(),  EndHalfbright(),
  1532. X     StartInverse(),     EndInverse(),
  1533. X    
  1534. X     transmit_functions(),
  1535. X
  1536. X     Raw(),              RawState(),
  1537. X     ReadCh();
  1538. X
  1539. Xchar *return_value_of();
  1540. SHAR_EOF
  1541. chmod 0444 hdrs/curses.h || echo "restore of hdrs/curses.h fails"
  1542. echo "x - extracting hdrs/defs.h (Text)"
  1543. sed 's/^X//' << 'SHAR_EOF' > hdrs/defs.h &&
  1544. X
  1545. X/* $Id: defs.h,v 4.1 90/04/28 22:42:06 syd Exp $ */
  1546. X
  1547. X/*******************************************************************************
  1548. X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
  1549. X *
  1550. X *             Copyright (c) 1986, 1987 Dave Taylor
  1551. X *             Copyright (c) 1988, 1989, 1990 USENET Community Trust
  1552. X *******************************************************************************
  1553. X * Bug reports, patches, comments, suggestions should be sent to:
  1554. X *
  1555. X *    Syd Weinstein, Elm Coordinator
  1556. X *    elm@DSI.COM            dsinc!elm
  1557. X *
  1558. X *******************************************************************************
  1559. X * $Log:    defs.h,v $
  1560. X * Revision 4.1  90/04/28  22:42:06  syd
  1561. X * checkin of Elm 2.3 as of Release PL0
  1562. X * 
  1563. X *
  1564. X ******************************************************************************/
  1565. X
  1566. X/**  define file for ELM mail system.  **/
  1567. X
  1568. X
  1569. X#include "../config.h"
  1570. X#include "sysdefs.h"    /* system/configurable defines */
  1571. X
  1572. X
  1573. X# define VERSION         "2.3"        /* Version number... */
  1574. X# define VERS_DATE    "May 1, 1990"        /* for elm -v option */
  1575. X# define WHAT_STRING    \
  1576. X    "@(#) Version 2.3, USENET supported version, released May 1990"
  1577. X
  1578. X#define KLICK        25
  1579. X
  1580. X#define SLEN        256        /* long for ensuring no overwrites... */
  1581. X#define SHORT        10        /* super short strings!          */
  1582. X#define NLEN        48        /* name length for aliases            */
  1583. X#define WLEN        20
  1584. X#define STRING        128    /* reasonable string length for most..      */
  1585. X#define LONG_STRING    512    /* even longer string for group expansion   */
  1586. X#define VERY_LONG_STRING 2560    /* huge string for group alias expansion    */
  1587. X#define MAX_LINE_LEN    5120    /* even bigger string for "filter" prog..   */
  1588. X
  1589. X#define BREAK        '\0'          /* default interrupt    */
  1590. X#define BACKSPACE    '\b'         /* backspace character  */
  1591. X#define TAB        '\t'            /* tab character        */
  1592. X#define RETURN        '\r'         /* carriage return char */
  1593. X#define LINE_FEED    '\n'         /* line feed character  */
  1594. X#define FORMFEED    '\f'         /* form feed (^L) char  */
  1595. X#define COMMA        ','        /* comma character      */
  1596. X#define SPACE        ' '        /* space character      */
  1597. X#define DOT        '.'        /* period/dot character */
  1598. X#define BANG        '!'        /* exclaimation mark!   */
  1599. X#define AT_SIGN        '@'        /* at-sign character    */
  1600. X#define PERCENT        '%'        /* percent sign char.   */
  1601. X#define COLON        ':'        /* the colon ..        */
  1602. X#define BACKQUOTE    '`'        /* backquote character  */
  1603. X#define TILDE_ESCAPE    '~'        /* escape character~    */
  1604. X#define ESCAPE        '\033'        /* the escape        */
  1605. X
  1606. X#define NO_OP_COMMAND    '\0'        /* no-op for timeouts   */
  1607. X
  1608. X#define STANDARD_INPUT  0        /* file number of stdin */
  1609. X
  1610. X#ifndef TRUE
  1611. X#define TRUE        1
  1612. X#define FALSE        0
  1613. X#endif
  1614. X
  1615. X#define NO        0
  1616. X#define YES        1
  1617. X#define MAYBE        2        /* a definite define, eh?  */
  1618. X#define FORM        3        /*      <nevermind>        */
  1619. X#define PREFORMATTED    4        /* forwarded form...       */
  1620. X
  1621. X#define SAME_PAGE    1        /* redraw current only     */
  1622. X#define NEW_PAGE    2        /* redraw message list     */
  1623. X#define ILLEGAL_PAGE    0        /* error in page list, punt */
  1624. X
  1625. X#define PAD        0        /* for printing name of    */
  1626. X#define FULL        1        /*   the sort we're using  */
  1627. X
  1628. X#define OUTGOING    0        /* defines for lock file   */
  1629. X#define INCOMING    1        /* creation..see lock()    */
  1630. X
  1631. X#define SH        0        /* defines for system_call */
  1632. X#define USER_SHELL    1        /* to work correctly!      */
  1633. X
  1634. X#define EXECUTE_ACCESS    01        /* These five are        */
  1635. X#define WRITE_ACCESS    02        /*    for the calls       */
  1636. X#define READ_ACCESS    04        /*       to access()       */
  1637. X#define ACCESS_EXISTS    00        /*           <etc>         */
  1638. X#define EDIT_ACCESS    06        /*  (this is r+w access)   */
  1639. X
  1640. X#define BIG_NUM        999999        /* big number!             */
  1641. X#define BIGGER_NUM    9999999     /* bigger number!          */
  1642. X
  1643. X#define START_ENCODE    "[encode]"
  1644. X#define END_ENCODE    "[clear]"
  1645. X
  1646. X#define DONT_SAVE    "[no save]"
  1647. X#define DONT_SAVE2    "[nosave]"
  1648. X
  1649. X#define alias_file    ".aliases"
  1650. X#define group_file    ".groups"
  1651. X#define system_file    ".systems"
  1652. X
  1653. X#define default_folders        "Mail"
  1654. X#define default_recvdmail    "=received"
  1655. X#define default_sentmail    "=sent"
  1656. X
  1657. X/** some defines for the 'userlevel' variable... **/
  1658. X
  1659. X#define RANK_AMATEUR    0
  1660. X#define AMATEUR        1
  1661. X#define OKAY_AT_IT    2
  1662. X#define GOOD_AT_IT    3
  1663. X#define EXPERT        4
  1664. X#define SUPER_AT_IT    5
  1665. X
  1666. X/** some defines for the "status" field of the header record **/
  1667. X
  1668. X#define ACTION        1        /* bit masks, of course */
  1669. X#define CONFIDENTIAL    2
  1670. X#define DELETED        4
  1671. X#define EXPIRED        8
  1672. X#define FORM_LETTER    16
  1673. X#define NEW        32
  1674. X#define PRIVATE        64
  1675. X#define TAGGED        128
  1676. X#define URGENT        256
  1677. X#define VISIBLE        512
  1678. X#define UNREAD        1024
  1679. X#define STATUS_CHANGED    2048
  1680. X
  1681. X#define UNDELETE    0        /* purely for ^U function... */
  1682. X
  1683. X/** values for headers exit_disposition field */
  1684. X#define UNSET    0
  1685. X#define KEEP    1
  1686. X#define    STORE    2
  1687. X#define DELETE    3
  1688. X
  1689. X/** some months... **/
  1690. X
  1691. X#define JANUARY        0            /* months of the year */
  1692. X#define FEBRUARY    1
  1693. X#define MARCH        2
  1694. X#define APRIL        3
  1695. X#define MAY        4
  1696. X#define JUNE        5
  1697. X#define JULY        6
  1698. X#define AUGUST        7
  1699. X#define SEPTEMBER    8
  1700. X#define OCTOBER        9
  1701. X#define NOVEMBER    10
  1702. X#define DECEMBER    11
  1703. X
  1704. X#define equal(s,w)    (strcmp(s,w) == 0)
  1705. X#define min(a,b)    a < b? a : b
  1706. X#define ctrl(c)            c - 'A' + 1    /* control character mapping */
  1707. X#define plural(n)    n == 1 ? "" : "s"
  1708. X#define lastch(s)    s[strlen(s)-1]
  1709. X
  1710. X/* find tab stops preceding or following a given column position 'a', where
  1711. X * the column position starts counting from 1, NOT 0!
  1712. X * The external integer "tabspacing" must be declared to use this. */
  1713. X#define prev_tab(a)    (((((a-1)/tabspacing))*tabspacing)+1)
  1714. X#define next_tab(a)    (((((a-1)/tabspacing)+1)*tabspacing)+1)
  1715. X
  1716. X#define movement_command(c)    (c == 'j' || c == 'k' || c == ' ' ||           \
  1717. X                 c == BACKSPACE || c == ESCAPE || c == '*' || \
  1718. X                 c == '-' || c == '+' || c == '=' ||          \
  1719. X                 c == '#' || c == '@' || c == 'x' ||           \
  1720. X                 c == 'a' || c == 'q')
  1721. X
  1722. X#define no_ret(s)    { register int xyz; /* varname is for lint */          \
  1723. X                  for (xyz=strlen(s)-1; xyz >= 0 &&               \
  1724. X                (s[xyz] == '\r' || s[xyz] == '\n'); )          \
  1725. X                 s[xyz--] = '\0';                                 \
  1726. X            }
  1727. X              
  1728. X#define first_word(s,w) (strncmp(s,w, strlen(w)) == 0)
  1729. X#define ClearLine(n)    MoveCursor(n,0); CleartoEOLN()
  1730. X#define whitespace(c)    (c == ' ' || c == '\t')
  1731. X#define ok_rc_char(c)    (isalnum(c) || c == '-' || c == '_')
  1732. X#define ok_alias_char(c) (isalnum(c) || c == '-' || c == '_' || c == '.')
  1733. X#define quote(c)    (c == '"' || c == '\'') 
  1734. X#define onoff(n)    (n == 0 ? "OFF" : "ON")
  1735. X
  1736. X/** The next function is so certain commands can be processed from the showmsg
  1737. X    routine without rewriting the main menu in between... **/
  1738. X
  1739. X#define special(c)    (c == 'j' || c == 'k')
  1740. X
  1741. X/** and a couple for dealing with status flags... **/
  1742. X
  1743. X#define ison(n,mask)    (n & mask)
  1744. X#define isoff(n,mask)    (!ison(n, mask))
  1745. X
  1746. X#define setit(n,mask)        n |= mask
  1747. X#define clearit(n, mask)    n &= ~mask
  1748. X
  1749. SHAR_EOF
  1750. echo "End of part 9"
  1751. echo "File hdrs/defs.h is continued in part 10"
  1752. echo "10" > s2_seq_.tmp
  1753. exit 0
  1754.