home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume6 / elm / part13 < prev    next >
Text File  |  1986-11-30  |  60KB  |  2,534 lines

  1. Subject: v06i038:  Elm mail system (elm), Part13/14
  2. Newsgroups: mod.sources
  3. Approved: rs@mirror.UUCP
  4.  
  5. Submitted by: Dave Taylor <pyramid!hplabs!hpldat!taylor>
  6. Mod.sources: Volume 6, Issue 38
  7. Archive-name: elm/Part13
  8.  
  9. # Continuation of Shell Archive, created by hpldat!taylor
  10.  
  11. # This is part 13
  12.  
  13. # To unpack the enclosed files, please use this file as input to the
  14. # Bourne (sh) shell.  This can be most easily done by the command;
  15. #     sh < thisfilename
  16.  
  17.  
  18. if [ ! -d utils ]
  19. then
  20.   echo creating directory utils
  21.   mkdir utils
  22. fi
  23.  
  24. # ---------- file utils/arepdaemon.c ----------
  25.  
  26. filename="utils/arepdaemon.c"
  27.  
  28. if [ -f $filename ]
  29. then
  30.   echo File \"$filename\" already exists\!  Skipping...
  31.   filename=/dev/null        # throw it away
  32. else
  33.   echo extracting file utils/arepdaemon.c...
  34. fi
  35.  
  36. cat << 'END-OF-FILE' > $filename
  37. /**            arepdaemon.c            **/
  38.  
  39. /** (C) Copyright 1986 Dave Taylor            **/
  40.  
  41. /** Keep track of mail as it arrives, and respond by sending a 'recording'
  42.     file to the sender as new mail is received.
  43.  
  44.     Note: the user program that interacts with this program is the
  45.     'autoreply' program and that should be consulted for further
  46.     usage information.
  47.  
  48.     This program is part of the 'autoreply' system, and is designed
  49.     to run every hour and check all mailboxes listed in the file 
  50.     "/etc/autoreply.data", where the data is in the form:
  51.  
  52.     username    replyfile    current-mailfile-size
  53.  
  54.     To avoid a flood of autoreplies, this program will NOT reply to mail 
  55.     that contains header "X-Mailer: fastmail".  Further, each time the 
  56.     program responds to mail, the 'mailfile size' entry is updated in
  57.     the file /etc/autoreply.data to allow the system to be brought 
  58.     down and rebooted without any loss of data or duplicate messages.
  59.  
  60.     This daemon also uses a lock semaphore file, /usr/spool/uucp/LCK..arep,
  61.     to ensure that more than one copy of itself is never running.  For this
  62.     reason, it is recommended that this daemon be started up each morning
  63.     from cron, since it will either start since it's needed or simply see
  64.     that the file is there and disappear.
  65.  
  66.     Since this particular program is the main daemon answering any
  67.     number of different users, it must be run with uid root.
  68.  
  69.     (C) 1985, Dave Taylor, HP Colorado Networks Operation
  70. **/
  71.  
  72. #include <stdio.h>
  73. #include <time.h>
  74. #include <sys/types.h>
  75. #include <sys/stat.h>
  76.  
  77. #include "defs.h"
  78.  
  79. static char ident[] = { WHAT_STRING };
  80.  
  81. #define arep_lock_file    "/usr/spool/uucp/LCK..arep"
  82.  
  83. #define autoreply_file    "/etc/autoreply.data"
  84. #define fastmail    "/usr/local/bin/fastmail"
  85.  
  86. #define logfile        "/etc/autoreply.log"    /* first choice   */
  87. #define logfile2    "/tmp/autoreply.log"    /* second choice  */
  88.  
  89. #define BEGINNING    0        /* see fseek(3S) for info */
  90. #define SLEEP_TIME    3600        /* run once an hour       */
  91. #define MAX_PEOPLE    20        /* max number in program  */
  92.  
  93. #define EXISTS        00        /* lock file exists??     */
  94. #define MODE        0777        /* lockfile creation mode */
  95.  
  96. #define NLEN        20
  97.  
  98. #define remove_return(s)    if (strlen(s) > 0) { \
  99.                       if (s[strlen(s)-1] == '\n') \
  100.                     s[strlen(s)-1] = '\0'; \
  101.                         }
  102.  
  103. struct replyrec {
  104.     char     username[NLEN];        /* login name of user */
  105.     char    mailfile[SLEN];        /* name of mail file  */
  106.     char    replyfile[SLEN];    /* name of reply file */
  107.     long    mailsize;        /* mail file size     */
  108.     int     in_list;        /* for new replies    */
  109.       } reply_table[MAX_PEOPLE];
  110.  
  111. FILE  *logfd;                /* logfile (log action)   */
  112. long  autoreply_size = 0L;        /* size of autoreply file */
  113. int   active = 0;            /* # of people 'enrolled' */
  114.  
  115. FILE  *open_logfile();            /* forward declaration    */
  116.  
  117. long  bytes();                /*       ditto           */
  118.  
  119. main()
  120. {
  121.     long size;
  122.     int  person, data_changed;
  123.  
  124.     if (! lock())
  125.       exit(0);    /* already running! */
  126.  
  127.     while (1) {
  128.  
  129.       logfd = open_logfile();    /* open the log */
  130.  
  131.       /* 1. check to see if autoreply table has changed.. */
  132.  
  133.       if ((size = bytes(autoreply_file)) != autoreply_size) {
  134.         read_autoreply_file(); 
  135.         autoreply_size = size;
  136.       }
  137.  
  138.       /* 2. now for each active person... */
  139.     
  140.       data_changed = 0;
  141.  
  142.       for (person = 0; person < active; person++) {
  143.         if ((size = bytes(reply_table[person].mailfile)) != 
  144.         reply_table[person].mailsize) {
  145.           if (size > reply_table[person].mailsize)
  146.             read_newmail(person);
  147.           /* else mail removed - resync */
  148.           reply_table[person].mailsize = size;
  149.           data_changed++;
  150.         }
  151.       }
  152.  
  153.       /* 3. if data changed, update autoreply file */
  154.  
  155.       if (data_changed)
  156.         update_autoreply_file();
  157.  
  158.       close_logfile();        /* close the logfile again */
  159.  
  160.       /* 4. Go to sleep...  */
  161.  
  162.       sleep(SLEEP_TIME);
  163.     }
  164. }
  165.  
  166. int
  167. read_autoreply_file()
  168. {
  169.     /** We're here because the autoreply file has changed size!!  It
  170.         could either be because someone has been added or because
  171.         someone has been removed...since the list will always be in
  172.         order (nice, eh?) we should have a pretty easy time of it...
  173.     **/
  174.  
  175.     FILE *file;
  176.     char username[SLEN],     replyfile[SLEN];
  177.     int  person;
  178.      long size;
  179.     
  180.     log("Autoreply data file has changed!  Reading...");
  181.  
  182.     if ((file = fopen(autoreply_file,"r")) == NULL) {
  183.       log("No-one is using autoreply...");
  184.       return(0);
  185.     }
  186.     
  187.     for (person = 0; person < active; person++)
  188.       reply_table[person].in_list = 0;
  189.     
  190.     while (fscanf(file, "%s %s %dl", username, replyfile, &size) != EOF) {
  191.       /* check to see if this person is already in the list */
  192.       if ((person = in_list(username)) != -1) {
  193.         reply_table[person].in_list = 1;
  194.         reply_table[person].mailsize = size;     /* sync */
  195.       }
  196.       else {     /* if not, add them */
  197.         if (active == MAX_PEOPLE) {
  198.           unlock();
  199.           exit(log("Couldn't add %s - already at max people!", 
  200.                  username));
  201.         }
  202.         log("adding %s to the active list", username);
  203.         strcpy(reply_table[active].username, username);
  204.         sprintf(reply_table[active].mailfile, "/usr/mail/%s", username);
  205.         strcpy(reply_table[active].replyfile, replyfile);
  206.         reply_table[active].mailsize = size;
  207.         reply_table[active].in_list = 1;    /* obviously! */
  208.         active++;
  209.       }
  210.     }
  211.  
  212.     /** now check to see if anyone has been removed... **/
  213.  
  214.     for (person = 0; person < active; person++)
  215.       if (reply_table[person].in_list == 0) {
  216.          log("removing %s from the active list", 
  217.           reply_table[person].username);
  218.         strcpy(reply_table[person].username, 
  219.            reply_table[active-1].username);
  220.         strcpy(reply_table[person].mailfile, 
  221.            reply_table[active-1].mailfile);
  222.         strcpy(reply_table[person].replyfile, 
  223.            reply_table[active-1].replyfile);
  224.         reply_table[person].mailsize = reply_table[active-1].mailsize;
  225.         active--;
  226.       }
  227. }
  228.  
  229. update_autoreply_file()
  230. {
  231.     /** update the entries in the autoreply file... **/
  232.  
  233.     FILE *file;
  234.     register int person;
  235.  
  236.     if ((file = fopen(autoreply_file,"w")) == NULL) {
  237.           log("Couldn't update autoreply file!");
  238.       return;
  239.     }
  240.  
  241.     for (person = 0; person < active; person++)
  242.       fprintf(file, "%s %s %ld\n",
  243.           reply_table[person].username,
  244.           reply_table[person].replyfile,
  245.           reply_table[person].mailsize);
  246.  
  247.     fclose(file);
  248.  
  249.     printf("updated autoreply file\n");
  250.     autoreply_size = bytes(autoreply_file);
  251. }
  252.  
  253. int
  254. in_list(name)
  255. char *name;
  256. {
  257.     /** search the current active reply list for the specified username.
  258.         return the index if found, or '-1' if not. **/
  259.  
  260.     register int index;
  261.  
  262.     for (index = 0; index < active; index++)
  263.       if (strcmp(name, reply_table[index].username) == 0)
  264.         return(index);
  265.     
  266.     return(-1);
  267. }
  268.  
  269. read_newmail(person)
  270. int person;
  271. {
  272.     /** Read the new mail for the specified person. **/
  273.  
  274.     
  275.     FILE *mailfile;
  276.     char from_whom[LONG_SLEN], subject[SLEN];
  277.     int  sendit;
  278.  
  279.     log("New mail for %s", reply_table[person].username);
  280.  
  281.         if ((mailfile = fopen(reply_table[person].mailfile,"r")) == NULL)
  282.            return(log("can't open mailfile for user %s", 
  283.             reply_table[person].username));
  284.  
  285.         if (fseek(mailfile, reply_table[person].mailsize, BEGINNING) == -1)
  286.            return(log("couldn't seek to %ld in mail file!", 
  287.                    reply_table[person].mailsize));
  288.  
  289.     while (get_return(mailfile, person, from_whom, subject, &sendit) != -1)
  290.       if (sendit)
  291.         reply_to_mail(person, from_whom, subject);
  292.  
  293.     return;
  294. }
  295.  
  296. int
  297. get_return(file, person, from, subject, sendit)
  298. FILE *file;
  299. int  person, *sendit;
  300. char *from, *subject;
  301. {
  302.     /** Reads the new message and return the from and subject lines.
  303.         sendit is set to true iff it isn't a machine generated msg
  304.     **/
  305.     
  306.     char name1[SLEN], name2[SLEN], lastname[SLEN];
  307.     char buffer[LONG_SLEN], hold_return[NLEN];
  308.     int done = 0, in_header = 0;
  309.  
  310.     from[0] = '\0';
  311.     *sendit = 1;
  312.  
  313.     while (! done) {
  314.  
  315.       if (fgets(buffer, LONG_SLEN, file) == NULL)
  316.     return(-1);
  317.  
  318.       if (first_word(buffer, "From ")) {
  319.     in_header++;
  320.     sscanf(buffer, "%*s %s", hold_return);
  321.       }
  322.       else if (in_header) {
  323.         if (first_word(buffer, ">From")) {
  324.       sscanf(buffer,"%*s %s %*s %*s %*s %*s %*s %*s %*s %s", name1, name2);
  325.       add_site(from, name2, lastname);
  326.         }
  327.         else if (first_word(buffer,"Subject:")) {
  328.       remove_return(buffer);
  329.       strcpy(subject, (char *) (buffer + 8));
  330.         }
  331.         else if (first_word(buffer,"X-Mailer: fastmail"))
  332.       *sendit = 0;
  333.         else if (strlen(buffer) == 1)
  334.       done = 1;
  335.       }
  336.     }
  337.  
  338.     if (from[0] == '\0')
  339.       strcpy(from, hold_return); /* default address! */
  340.     else
  341.       add_site(from, name1, lastname);    /* get the user name too! */
  342.  
  343.     return(0);
  344. }
  345.  
  346. add_site(buffer, site, lastsite)
  347. char *buffer, *site, *lastsite;
  348. {
  349.     /** add site to buffer, unless site is 'uucp', or the same as 
  350.         lastsite.   If not, set lastsite to site.
  351.     **/
  352.  
  353.     char local_buffer[LONG_SLEN], *strip_parens();
  354.  
  355.     if (strcmp(site, "uucp") != 0)
  356.       if (strcmp(site, lastsite) != 0) {
  357.           if (buffer[0] == '\0')
  358.             strcpy(buffer, strip_parens(site));         /* first in list! */
  359.           else {
  360.             sprintf(local_buffer,"%s!%s", buffer, strip_parens(site));
  361.             strcpy(buffer, local_buffer);
  362.           }
  363.           strcpy(lastsite, strip_parens(site)); /* don't want THIS twice! */
  364.        }
  365. }
  366.  
  367. remove_first_word(string)
  368. char *string;
  369. {    /** removes first word of string, ie up to first non-white space
  370.         following a white space! **/
  371.  
  372.     register int loc;
  373.  
  374.     for (loc = 0; string[loc] != ' ' && string[loc] != '\0'; loc++) 
  375.         ;
  376.  
  377.     while (string[loc] == ' ' || string[loc] == '\t')
  378.       loc++;
  379.     
  380.     move_left(string, loc);
  381. }
  382.  
  383. move_left(string, chars)
  384. char string[];
  385. int  chars;
  386. {
  387.     /** moves string chars characters to the left DESTRUCTIVELY **/
  388.  
  389.     register int i;
  390.  
  391.     chars--; /* index starting at zero! */
  392.  
  393.     for (i=chars; string[i] != '\0' && string[i] != '\n'; i++)
  394.       string[i-chars] = string[i];
  395.  
  396.     string[i-chars] = '\0';
  397. }
  398.  
  399. reply_to_mail(person, from, subject)
  400. int   person;
  401. char *from, *subject;
  402. {
  403.     /** Respond to the message from the specified person with the
  404.         specified subject... **/
  405.     
  406.     char buffer[SLEN];
  407.  
  408.     if (strlen(subject) == 0)
  409.       strcpy(subject, "Auto-reply Mail");
  410.     else if (! first_word(subject,"Auto-reply")) {
  411.       sprintf(buffer, "Auto-reply to:%s", subject);
  412.       strcpy(subject, buffer);
  413.     }
  414.  
  415.     log("auto-replying to '%s'", from);
  416.  
  417.     mail(from, subject, reply_table[person].replyfile, person);
  418. }    
  419.  
  420. reverse(string)
  421. char *string;
  422. {
  423.     /** reverse string... pretty trivial routine, actually! **/
  424.  
  425.     char buffer[SLEN];
  426.     register int i, j = 0;
  427.  
  428.     for (i = strlen(string)-1; i >= 0; i--)
  429.       buffer[j++] = string[i];
  430.  
  431.     buffer[j] = '\0';
  432.  
  433.     strcpy(string, buffer);
  434. }
  435.  
  436. long
  437. bytes(name)
  438. char *name;
  439. {
  440.     /** return the number of bytes in the specified file.  This
  441.         is to check to see if new mail has arrived....  **/
  442.  
  443.     int ok = 1;
  444.     extern int errno;    /* system error number! */
  445.     struct stat buffer;
  446.  
  447.     if (stat(name, &buffer) != 0)
  448.       if (errno != 2) {
  449.        unlock();
  450.        exit(fprintf(stderr,"Error %d attempting fstat on %s", errno, name));
  451.       }
  452.       else
  453.         ok = 0;
  454.     
  455.     return(ok ? buffer.st_size : 0);
  456. }
  457.  
  458. mail(to, subject, filename, person)
  459. char *to, *subject, *filename;
  460. int   person;
  461. {
  462.     /** Mail 'file' to the user from person... **/
  463.     
  464.     char buffer[VERY_LONG_STRING];
  465.  
  466.     sprintf(buffer, "%s -f '%s [autoreply]' -s '%s' %s %s",
  467.         fastmail, reply_table[person].username,
  468.             subject, filename, to);
  469.     
  470.     system(buffer);
  471. }
  472.  
  473. log(message, arg)
  474. char *message;
  475. char *arg;
  476. {
  477.     /** Put log entry into log file.  Use the format:
  478.           date-time: <message>
  479.     **/
  480.  
  481.     struct tm *localtime(), *thetime;
  482.     long      time(), clock;
  483.     char      buffer[SLEN];
  484.  
  485.     /** first off, get the time and date **/
  486.  
  487.     clock = time((long *) 0);       /* seconds since ???   */
  488.     thetime = localtime(&clock);    /* and NOW the time... */
  489.  
  490.     /** then put the message out! **/
  491.  
  492.     sprintf(buffer, message, arg);
  493.  
  494.     fprintf(logfd,"%d/%d-%d:%02d: %s\n", 
  495.         thetime->tm_mon+1, thetime->tm_mday,
  496.             thetime->tm_hour,  thetime->tm_min,
  497.             buffer);
  498. }
  499.  
  500. FILE *open_logfile()
  501. {
  502.     /** open the logfile.  returns a valid file descriptor **/
  503.  
  504.     FILE *fd;
  505.  
  506.     if ((fd = fopen(logfile, "a")) == 0)
  507.       if ((fd = fopen(logfile2, "a")) == 0) {
  508.         unlock();
  509.         exit(1);    /* give up! */
  510.       }
  511.  
  512.     return( (FILE *) fd);
  513. }
  514.  
  515. close_logfile()
  516. {
  517.     /** Close the logfile until needed again. **/
  518.  
  519.     fclose(logfd);
  520. }
  521.  
  522. char *strip_parens(string)
  523. char *string;
  524. {
  525.     /** Return string with all parenthesized information removed.
  526.         This is a non-destructive algorithm... **/
  527.  
  528.     static char  buffer[LONG_SLEN];
  529.     register int i, depth = 0, buffer_index = 0;
  530.  
  531.     for (i=0; i < strlen(string); i++) {
  532.       if (string[i] == '(')
  533.         depth++;
  534.       else if (string[i] == ')') 
  535.         depth--;
  536.       else if (depth == 0)
  537.         buffer[buffer_index++] = string[i];
  538.     }
  539.     
  540.     buffer[buffer_index] = '\0';
  541.  
  542.     return( (char *) buffer);
  543. }
  544.  
  545. /*** LOCK and UNLOCK - ensure only one copy of this daemon running at any
  546.      given time by using a file existance semaphore (wonderful stuff!) ***/
  547.  
  548. lock()
  549. {
  550.     /** Try to create the lock file.  If it's there, or we can't
  551.         create it for some stupid reason, return zero, otherwise,
  552.         a non-zero return code indicates success in locking this
  553.         process in. **/
  554.  
  555.     if (access(arep_lock_file, EXISTS) == 0)
  556.       return(0);     /* file already exists!! */
  557.  
  558.     if (creat(arep_lock_file, MODE) == -1)
  559.       return(0);    /* can't create file!!   */
  560.  
  561.     return(1);
  562. }
  563.  
  564. unlock()
  565. {
  566.     /** remove lock file if it's there! **/
  567.  
  568.     (void) unlink(arep_lock_file);
  569. }
  570. END-OF-FILE
  571.  
  572. if [ "$filename" != "/dev/null" ]
  573. then
  574.   size=`wc -c < $filename`
  575.  
  576.   if [ $size != 13380 ]
  577.   then
  578.     echo $filename changed - should be 13380 bytes, not $size bytes
  579.   fi
  580.  
  581.   chmod 666 $filename
  582. fi
  583.  
  584. # ---------- file utils/autoreply.c ----------
  585.  
  586. filename="utils/autoreply.c"
  587.  
  588. if [ -f $filename ]
  589. then
  590.   echo File \"$filename\" already exists\!  Skipping...
  591.   filename=/dev/null        # throw it away
  592. else
  593.   echo extracting file utils/autoreply.c...
  594. fi
  595.  
  596. cat << 'END-OF-FILE' > $filename
  597. /**            autoreply.c            **/
  598.  
  599. /** This is the front-end for the autoreply system, and performs two 
  600.     functions: it either adds the user to the list of people using the
  601.     autoreply function (starting the daemon if no-one else) or removes
  602.     a user from the list of people.
  603.  
  604.     Usage:  autoreply filename
  605.         autoreply "off"
  606.     or  autoreply        [to find current status]
  607.     
  608.     (C) 1986, Dave Taylor
  609. **/
  610.  
  611. #include <stdio.h>
  612. #include <errno.h>
  613. #include <sys/types.h>
  614. #include <sys/stat.h>
  615.  
  616. #include "defs.h"
  617.  
  618. static char ident[] = { WHAT_STRING };
  619.  
  620. #define  READ_ACCESS    04               /* is file readable?    */
  621.  
  622. #define  tempdir    "/tmp/arep"        /* file prefix          */
  623. #define  autoreply_file    "/etc/autoreply.data"   /* autoreply data file  */
  624.  
  625. extern   int errno;                /* system error code    */
  626. char     username[NLEN];            /* login name of user   */
  627.  
  628. main(argc, argv)
  629. int    argc;
  630. char *argv[];
  631. {
  632.     char filename[SLEN];
  633.  
  634.     if (argc > 2) {
  635.       printf("Usage: %s <filename>\tto start autoreply,\n", argv[0]);
  636.       printf("       %s off\t\tto turn off autoreply\n", argv[0]);
  637.       printf("   or  %s    \t\tto check current status\n", argv[0]);
  638.       exit(1);
  639.     }
  640.  
  641.     (void) cuserid(username);
  642.  
  643.     if (argc == 1 || strcmp(argv[1], "off") == 0) 
  644.       remove_user((argc == 1));
  645.     else {
  646.       strcpy(filename, argv[1]);
  647.       if (access(filename,READ_ACCESS) != 0) {
  648.         printf("Error: Can't read file '%s'\n", filename);
  649.         exit(1);
  650.       }
  651.       
  652.       if (filename[0] != '/') /* prefix home directory */
  653.         sprintf(filename,"%s/%s", getenv("HOME"), argv[1]);
  654.  
  655.       add_user(filename);
  656.     }
  657.  
  658.     exit(0);
  659. }
  660.  
  661. remove_user(stat_only)
  662. int stat_only;
  663. {
  664.     /** Remove the user from the list of currently active autoreply 
  665.         people.  If 'stat_only' is set, then just list the name of
  666.         the file being used to autoreply with, if any. **/
  667.  
  668.     FILE *temp, *repfile;
  669.     char  tempfile[SLEN], user[SLEN], filename[SLEN];
  670.     int   c, copied = 0, found = 0;
  671.     long  filesize, bytes();
  672.  
  673.     if (! stat_only) {
  674.       sprintf(tempfile, "%s.%06d", tempdir, getpid());
  675.  
  676.       if ((temp = fopen(tempfile, "w")) == NULL) {
  677.         printf("Error: couldn't open tempfile '%s'.  Not removed\n",
  678.             tempfile);
  679.         exit(1);
  680.       }
  681.     }
  682.  
  683.     if ((repfile = fopen(autoreply_file, "r")) == NULL) {
  684.       if (stat_only) {
  685.         printf("You're not currently autoreplying to mail.\n");
  686.         exit(0);
  687.       }
  688.       printf("No-one is autoreplying to their mail!\n");
  689.       exit(0);
  690.     }
  691.  
  692.     /** copy out of real replyfile... **/
  693.  
  694.     while (fscanf(repfile, "%s %s %ld", user, filename, &filesize) != EOF) 
  695.  
  696.       if (strcmp(user, username) != 0) {
  697.         if (! stat_only) {
  698.           copied++;
  699.           fprintf(tempfile, "%s %s %ld\n", user, filename, filesize);
  700.         }
  701.       }
  702.       else {
  703.         if (stat_only) {
  704.           printf("You're currently autoreplying to mail with the file %s\n",              filename); 
  705.           exit(0);
  706.         }
  707.         found++;
  708.       }
  709.  
  710.     fclose(temp);
  711.     fclose(repfile);
  712.  
  713.     if (! found) {
  714.       printf("You're not currently autoreplying to mail%s\n",
  715.           stat_only? "." : "!");
  716.       if (! stat_only)
  717.         unlink(tempfile);
  718.       exit(! stat_only);
  719.     }
  720.  
  721.     /** now copy tempfile back into replyfile **/
  722.  
  723.     if (copied == 0) {    /* removed the only person! */
  724.       unlink(autoreply_file);
  725.     }
  726.     else {            /* save everyone else   */
  727.       
  728.       if ((temp = fopen(tempfile,"r")) == NULL) {
  729.         printf("Error: couldn't reopen tempfile '%s'.  Not removed.\n",
  730.             tempfile);
  731.         unlink(tempfile);
  732.         exit(1);
  733.       }
  734.  
  735.       if ((repfile = fopen(autoreply_file, "w")) == NULL) {
  736.         printf(
  737.           "Error: couldn't reopen autoreply file for writing!  Not removed.\n");
  738.         unlink(tempfile);
  739.         exit(1);
  740.       }
  741.  
  742.       while ((c = getc(temp)) != EOF)
  743.         putc(c, repfile);
  744.  
  745.       fclose(temp);
  746.       fclose(repfile);
  747.     
  748.     }
  749.     unlink(tempfile);
  750.  
  751.     if (found > 1)
  752.       printf("Warning: your username appeared %d times!!   Removed all\n", 
  753.           found);
  754.     else
  755.       printf("You've been removed from the autoreply table.\n");
  756. }
  757.  
  758. add_user(filename)
  759. char *filename;
  760. {
  761.     /** add the user to the autoreply file... **/
  762.  
  763.     FILE *repfile;
  764.     char  mailfile[SLEN];
  765.     long  bytes();
  766.  
  767.     if ((repfile = fopen(autoreply_file, "a")) == NULL) {
  768.       printf("Error: couldn't open the autoreply file!  Not added\n");
  769.       exit(1);
  770.     }
  771.     
  772.     sprintf(mailfile,"%s/%s", mailhome, username);
  773.  
  774.     fprintf(repfile,"%s %s %ld\n", username, filename, bytes(mailfile));
  775.  
  776.     fclose(repfile);
  777.  
  778.     printf("You've been added to the autoreply system.\n");
  779. }
  780.  
  781.  
  782. long
  783. bytes(name)
  784. char *name;
  785. {
  786.     /** return the number of bytes in the specified file.  This
  787.         is to check to see if new mail has arrived....  **/
  788.  
  789.     int ok = 1;
  790.     extern int errno;    /* system error number! */
  791.     struct stat buffer;
  792.  
  793.     if (stat(name, &buffer) != 0)
  794.       if (errno != 2)
  795.        exit(fprintf(stderr,"Error %d attempting fstat on %s", errno, name));
  796.       else
  797.         ok = 0;
  798.     
  799.     return(ok ? buffer.st_size : 0L);
  800. }
  801. END-OF-FILE
  802.  
  803. if [ "$filename" != "/dev/null" ]
  804. then
  805.   size=`wc -c < $filename`
  806.  
  807.   if [ $size != 4746 ]
  808.   then
  809.     echo $filename changed - should be 4746 bytes, not $size bytes
  810.   fi
  811.  
  812.   chmod 666 $filename
  813. fi
  814.  
  815. # ---------- file utils/fastmail.c ----------
  816.  
  817. filename="utils/fastmail.c"
  818.  
  819. if [ -f $filename ]
  820. then
  821.   echo File \"$filename\" already exists\!  Skipping...
  822.   filename=/dev/null        # throw it away
  823. else
  824.   echo extracting file utils/fastmail.c...
  825. fi
  826.  
  827. cat << 'END-OF-FILE' > $filename
  828. /**            fastmail.c            **/
  829.  
  830. /** This program is specifically written for group mailing lists and
  831.     such batch type mail processing.  It does NOT use aliases at all,
  832.     it does NOT read the /etc/password file to find the From: name
  833.     of the user and does NOT expand any addresses.  It is meant 
  834.     purely as a front-end for either /bin/mail or /usr/lib/sendmail
  835.     (according to what is available on the current system).
  836.  
  837.          **** This program should be used with CAUTION *****
  838.  
  839.     (C) Copyright 1985 Dave Taylor
  840. **/
  841.  
  842. /** The calling sequence for this program is:
  843.  
  844.     fastmail {args}  filename full-email-address 
  845.  
  846.    where args could be any (or all) of;
  847.  
  848.        -b bcc-list        (Blind carbon copies to)
  849.        -c cc-list        (carbon copies to)
  850.        -d            (debug on)
  851.        -f from         (from name)
  852.        -r reply-to-address     (Reply-To:)
  853.        -s subject         (subject of message)
  854. **/
  855.  
  856. #include <stdio.h>
  857.  
  858. #ifdef BSD
  859. #  include <sys/time.h>
  860. #else
  861. #  include <time.h>
  862. #endif
  863.  
  864. #include "defs.h"
  865.  
  866. static char ident[] = { WHAT_STRING };
  867.  
  868. #define  binrmail    "/bin/rmail"
  869. #define  temphome    "/tmp/fastmail."
  870.  
  871. #define DONE        0
  872. #define ERROR        -1
  873.  
  874. char *optional_arg;            /* optional argument as we go */
  875. int   opt_index;            /* argnum + 1 when we leave   */
  876.  
  877. char *arpa_dayname[] = { "Sun", "Mon", "Tue", "Wed", "Thu",
  878.           "Fri", "Sat", "" };
  879.  
  880. char *arpa_monname[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  881.           "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ""};
  882.  
  883. char *get_arpa_date();
  884.  
  885. #ifdef BSD
  886.   char *timezone();
  887. #else
  888.   extern char *tzname[];
  889. #endif
  890.  
  891. main(argc, argv)
  892. int argc;
  893. char *argv[];
  894. {
  895.  
  896.     FILE *tempfile;
  897.     char hostname[NLEN], username[NLEN], from_string[SLEN], subject[SLEN];
  898.     char filename[SLEN], tempfilename[SLEN], command_buffer[256];
  899.     char replyto[SLEN], cc_list[SLEN], bcc_list[SLEN], to_list[SLEN];
  900.     int  c, sendmail_available, debug = 0;
  901.  
  902.     replyto[0] = '\0';
  903.     cc_list[0] = '\0';
  904.     bcc_list[0] = '\0';
  905.  
  906.     while ((c = get_options(argc, argv, "b:c:df:r:s:")) > 0) {
  907.       switch (c) {
  908.         case 'b' : strcpy(bcc_list, optional_arg);        break;
  909.         case 'c' : strcpy(cc_list, optional_arg);        break;
  910.         case 'd' : debug++;                    break;    
  911.         case 'f' : strcpy(from_string, optional_arg);    break;
  912.         case 'r' : strcpy(replyto, optional_arg);        break;
  913.         case 's' : strcpy(subject, optional_arg);        break;
  914.        }
  915.     }    
  916.  
  917.     if (c == ERROR) {
  918.       fprintf(stderr,"Usage: fastmail {args} filename address(es)\n");
  919.       fprintf(stderr, "   where {args} can be;\n");
  920.       fprintf(stderr,"\t-b bcc-list\n\t-c cc-list\n\t-d\n\t-f from-name\n");
  921.       fprintf(stderr, "\t-r reply-to\n\t-s subject\n\n");
  922.       exit(1);
  923.     }
  924.  
  925.     if (opt_index > argc) {
  926.       fprintf(stderr,"Usage: fastmail {args} filename address(es)\n");
  927.       fprintf(stderr, "   where {args} can be;\n");
  928.       fprintf(stderr,"\t-b bcc-list\n\t-c cc-list\n\t-d\n\t-f from-name\n");
  929.       fprintf(stderr, "\t-r reply-to\n\t-s subject\n\n");
  930.       exit(1);
  931.     }
  932.  
  933.     strcpy(filename, argv[opt_index++]);
  934.  
  935.     if (opt_index > argc) {
  936.       fprintf(stderr,"Usage: fastmail {args} filename address(es)\n");
  937.       fprintf(stderr, "   where {args} can be;\n");
  938.       fprintf(stderr,"\t-b bcc-list\n\t-c cc-list\n\t-d\n\t-f from-name\n");
  939.       fprintf(stderr, "\t-r reply-to\n\t-s subject\n\n");
  940.       exit(1);
  941.     }
  942.  
  943.     gethostname(hostname, sizeof(hostname));
  944.     strcpy(username, getlogin());
  945.     if (strlen(username) == 0)
  946.       cuserid(username);
  947.  
  948.     if (access(filename, READ_ACCESS) == -1)
  949.       exit(fprintf(stderr, "Error: can't find file %s!\n", filename));
  950.  
  951.     sprintf(tempfilename, "%s%d", temphome, getpid());
  952.  
  953.     if ((tempfile = fopen(tempfilename, "w")) == NULL)
  954.       exit(fprintf(stderr, "Couldn't open temp file %s\n", tempfilename));
  955.  
  956.     if (strlen(from_string) > 0)
  957.       fprintf(tempfile, "From: %s!%s (%s)\n", 
  958.           hostname, username, from_string);
  959.     else
  960.       fprintf(tempfile, "From: %s!%s\n", hostname, username);
  961.  
  962.     fprintf(tempfile, "Date: %s\n", get_arpa_date());
  963.  
  964.     if (strlen(subject) > 0)
  965.       fprintf(tempfile, "Subject: %s\n", subject);
  966.  
  967.     if (strlen(replyto) > 0)
  968.       fprintf(tempfile, "Reply-To: %s\n", replyto);
  969.  
  970.     while (opt_index < argc) 
  971.           sprintf(to_list, "%s%s%s", to_list, (strlen(to_list) > 0? ", ":""), 
  972.           argv[opt_index++]);
  973.     
  974.     fprintf(tempfile, "To: %s\n", to_list);
  975.  
  976.     if (strlen(cc_list) > 0)
  977.       fprintf(tempfile, "Cc: %s\n", cc_list);
  978.  
  979.     if (strlen(bcc_list) > 0)
  980.       fprintf(tempfile, "Bcc: %s\n", bcc_list);    /* trust xport */
  981.  
  982.     fprintf(tempfile, "X-Mailer: fastmail [version %s]\n", VERSION);
  983.     fprintf(tempfile, "\n");
  984.  
  985.     fclose(tempfile);
  986.  
  987.     /** now we'll cat both files to /bin/rmail or sendmail... **/
  988.  
  989.     sendmail_available = (access(sendmail, EXECUTE_ACCESS) != -1);
  990.  
  991.     printf("Mailing to %s%s%s%s%s [via %s]\n", to_list,
  992.         (strlen(cc_list) > 0 ? " ":""), cc_list,
  993.         (strlen(bcc_list) > 0 ? " ":""), bcc_list,
  994.         sendmail_available? "sendmail" : "rmail");
  995.  
  996.     sprintf(command_buffer, "cat %s %s | %s '%s %s %s'", 
  997.         tempfilename, filename, 
  998.             sendmail_available? sendmail : mailer,
  999.         to_list, cc_list, bcc_list);
  1000.  
  1001.     if (debug)
  1002.       printf("%s\n", command_buffer);
  1003.  
  1004.     system(command_buffer);
  1005.  
  1006.     unlink(tempfilename);
  1007. }
  1008.  
  1009.  
  1010. char *get_arpa_date()
  1011. {
  1012.     /** returns an ARPA standard date.  The format for the date
  1013.         according to DARPA document RFC-822 is exemplified by;
  1014.  
  1015.                      Mon, 12 Aug 85 6:29:08 MST
  1016.  
  1017.     **/
  1018.  
  1019.     static char buffer[SLEN];    /* static character buffer       */
  1020.     struct tm *the_time,        /* Time structure, see CTIME(3C) */
  1021.           *localtime();
  1022.     long       junk;        /* time in seconds....         */
  1023. #ifdef BSD
  1024.     struct  timeval  time_val;        
  1025.     struct  timezone time_zone;
  1026. #endif
  1027.  
  1028. #ifdef BSD
  1029.     gettimeofday(&time_val, &time_zone);
  1030.     junk = time_val.tv_sec;
  1031. #else
  1032.     junk = time(0);    /* this must be here for it to work! */
  1033. #endif
  1034.     the_time = localtime(&junk);
  1035.  
  1036.     sprintf(buffer, "%s, %d %s %d %d:%02d:%02d %s",
  1037.       arpa_dayname[the_time->tm_wday],
  1038.       the_time->tm_mday % 32,
  1039.       arpa_monname[the_time->tm_mon],
  1040.       the_time->tm_year % 100,
  1041.       the_time->tm_hour % 24,
  1042.       the_time->tm_min  % 61,
  1043.       the_time->tm_sec  % 61,
  1044. #ifdef BSD
  1045.       timezone(time_zone.tz_minuteswest, time_zone.tz_dsttime));
  1046. #else
  1047.       tzname[the_time->tm_isdst]);
  1048. #endif
  1049.     
  1050.     return( (char *) buffer);
  1051. }
  1052.  
  1053. /** Starting argument parsing routine.   
  1054.  
  1055.     Called as "get_options(argc, argv, options)" where options is a string
  1056.     of the form "abc:d" indicating that 'a' 'b' and 'd' are flags and
  1057.     'c' is a flag with a trailing argument.   Optional arguments are
  1058.     returned in the external char * variable "optional_arg", and the
  1059.     external int "opt_index" is set to the first entry in the argv list
  1060.     that wasn't processed (ie after the flags). 
  1061.  
  1062.     For example, the C compiler would have something of the form 
  1063.     getopt(argc, argv, "Oo:l:") to allow "cc -O -o output -l lib file.c"
  1064.  
  1065.     (C) Copyright 1986, Dave Taylor
  1066. **/
  1067.  
  1068. int  _indx = 1, _argnum = 1;
  1069.  
  1070. int
  1071. get_options(argc, argv, options)
  1072. int argc;
  1073. char *argv[], *options;
  1074. {
  1075.     /** Returns the character argument next, and optionally instantiates 
  1076.         "argument" to the argument associated with the particular option 
  1077.     **/
  1078.     
  1079.     char       *word, *strchr();
  1080.  
  1081.     if (_indx >= strlen(argv[_argnum])) {
  1082.       _argnum++;
  1083.       _indx = 1;        /* zeroeth char is '-' */
  1084.     }
  1085.  
  1086.     if (_argnum >= argc) {
  1087.       opt_index = argc;
  1088.       return(DONE);
  1089.     }
  1090.     
  1091.     if (argv[_argnum][0] != '-') {
  1092.       opt_index = _argnum;
  1093.       return(DONE);
  1094.     }
  1095.  
  1096.         word = strchr(options, argv[_argnum][_indx++]);
  1097.  
  1098.     if (strlen(word) == 0) 
  1099.       return(ERROR);
  1100.     
  1101.     if (word[1] == ':') {
  1102.  
  1103.       /** Two possibilities - either tailing end of this argument or the 
  1104.           next argument in the list **/
  1105.  
  1106.       if (_indx < strlen(argv[_argnum])) { /* first possibility */
  1107.         optional_arg = (char *) (argv[_argnum] + _indx);
  1108.         _argnum++;
  1109.         _indx = 1;
  1110.       }
  1111.       else {                /* second choice     */
  1112.         if (++_argnum >= argc) 
  1113.           return(ERROR);            /* no argument!!     */
  1114.  
  1115.         optional_arg = (char *) argv[_argnum++];
  1116.         _indx = 1;
  1117.       }
  1118.     }
  1119.  
  1120.     return((int) word[0]);
  1121. }
  1122. END-OF-FILE
  1123.  
  1124. if [ "$filename" != "/dev/null" ]
  1125. then
  1126.   size=`wc -c < $filename`
  1127.  
  1128.   if [ $size != 7799 ]
  1129.   then
  1130.     echo $filename changed - should be 7799 bytes, not $size bytes
  1131.   fi
  1132.  
  1133.   chmod 666 $filename
  1134. fi
  1135.  
  1136. # ---------- file utils/from.c ----------
  1137.  
  1138. filename="utils/from.c"
  1139.  
  1140. if [ -f $filename ]
  1141. then
  1142.   echo File \"$filename\" already exists\!  Skipping...
  1143.   filename=/dev/null        # throw it away
  1144. else
  1145.   echo extracting file utils/from.c...
  1146. fi
  1147.  
  1148. cat << 'END-OF-FILE' > $filename
  1149. /**        from.c        **/
  1150.  
  1151. /** print out whom each message is from in the pending mailbox
  1152.     or specified one, including a subject line if available.. 
  1153.  
  1154.     Added PREFER_UUCP knowledge 6/86
  1155.  
  1156.     (C) Copyright 1986 Dave Taylor **/
  1157.  
  1158. #include <stdio.h>
  1159. #include "defs.h"
  1160.  
  1161. static char ident[] = { WHAT_STRING };
  1162.  
  1163. #define LINEFEED    (char) 10
  1164.  
  1165. #define metachar(c)    (c == '=' || c == '+' || c == '%')
  1166.  
  1167. FILE *mailfile;
  1168.  
  1169. char *expand_define();
  1170.  
  1171. main(argc, argv)
  1172. int argc;
  1173. char *argv[];
  1174. {
  1175.     char infile[LONG_SLEN], username[SLEN];
  1176.  
  1177.     if (argc > 2)
  1178.       exit(printf("Usage: %s {filename}\n", argv[0]));
  1179.  
  1180.     if (argc == 2) 
  1181.       strcpy(infile, argv[1]);
  1182.     else {
  1183.       strcpy(username, getlogin());
  1184.       if (strlen(username) == 0)
  1185.         cuserid(username);
  1186.       sprintf(infile,"%s/%s",mailhome, username);
  1187.     }
  1188.  
  1189.     if (metachar(infile[0]))
  1190.       if (expand(infile) == 0)
  1191.          printf("%s: couldn't expand filename %s!\n", argv[0], infile);
  1192.  
  1193.     if ((mailfile = fopen(infile,"r")) == NULL) {
  1194.       if (argc == 1)
  1195.         printf("No mail!\n");
  1196.       else
  1197.         printf("%s: Couldn't open file %s\n", argv[0], infile);
  1198.     }
  1199.     else
  1200.       if (read_headers()==0)
  1201.         printf("No messages in mailbox!\n");
  1202. }
  1203.  
  1204. int
  1205. read_headers()
  1206. {
  1207.     /** read the headers, output as found **/
  1208.  
  1209.     char buffer[LONG_SLEN], from_whom[SLEN], subject[SLEN];
  1210.     register int subj = 0, in_header = 1, count = 0;
  1211.  
  1212.     while (fgets(buffer, LONG_SLEN, mailfile) != NULL) {
  1213.       if (first_word(buffer,"From ")) {
  1214.         if (real_from(buffer, from_whom)) {
  1215.           subj = 0;
  1216.           in_header = 1;
  1217.         }
  1218.       }
  1219.       else if (in_header) {
  1220.         if (first_word(buffer,">From")) 
  1221.           forwarded(buffer, from_whom); /* return address */
  1222.         else if (first_word(buffer,"Subject:") ||
  1223.              first_word(buffer,"Re:")) {
  1224.           if (! subj++) {
  1225.             remove_first_word(buffer);
  1226.         strcpy(subject, buffer);
  1227.           }
  1228.         }
  1229.         else if (first_word(buffer,"From:")) 
  1230.           parse_arpa_from(buffer, from_whom);
  1231.         else if (buffer[0] == LINEFEED) {
  1232.           in_header = 0;    /* in body of message! */
  1233.           show_header(from_whom, subject);
  1234.           from_whom[0] = 0;
  1235.           subject[0] = 0;
  1236.           count++;
  1237.         }
  1238.       }
  1239.     }
  1240.     return(count);
  1241. }
  1242.  
  1243. int
  1244. real_from(buffer, who)
  1245. char *buffer, *who;
  1246. {
  1247.     /***** returns true iff 's' has the seven 'from' fields,
  1248.            initializing the who to the sender *****/
  1249.  
  1250.     char junk[80];
  1251.  
  1252.     junk[0] = '\0';
  1253.     sscanf(buffer, "%*s %s %*s %*s %*s %*s %s",
  1254.                 who, junk);
  1255.     return(junk[0] != '\0');
  1256. }
  1257.  
  1258. forwarded(buffer, who)
  1259. char *buffer, *who;
  1260. {
  1261.     /** change 'from' and date fields to reflect the ORIGINATOR of 
  1262.         the message by iteratively parsing the >From fields... **/
  1263.  
  1264.     char machine[80], buff[80];
  1265.  
  1266.     machine[0] = '\0';
  1267.     sscanf(buffer, "%*s %s %*s %*s %*s %*s %*s %*s %*s %s",
  1268.                 who, machine);
  1269.  
  1270.     if (machine[0] == '\0') /* try for srm address */
  1271.       sscanf(buffer, "%*s %s %*s %*s %*s %*s %*s %*s %s",
  1272.                 who, machine);
  1273.  
  1274.     if (machine[0] == '\0')
  1275.       sprintf(buff,"anonymous");
  1276.     else
  1277.       sprintf(buff,"%s!%s", machine, who);
  1278.  
  1279.     strncpy(who, buff, 80);
  1280. }
  1281.  
  1282.  
  1283. remove_first_word(string)
  1284. char *string;
  1285. {    /** removes first word of string, ie up to first non-white space
  1286.         following a white space! **/
  1287.  
  1288.     register int loc;
  1289.  
  1290.     for (loc = 0; string[loc] != ' ' && string[loc] != '\0'; loc++) 
  1291.         ;
  1292.  
  1293.     while (string[loc] == ' ' || string[loc] == '\t')
  1294.       loc++;
  1295.     
  1296.     move_left(string, loc);
  1297. }
  1298.  
  1299. move_left(string, chars)
  1300. char string[];
  1301. int  chars;
  1302. {
  1303.     /** moves string chars characters to the left DESTRUCTIVELY **/
  1304.  
  1305.     register int i;
  1306.  
  1307.     chars--; /* index starting at zero! */
  1308.  
  1309.     for (i=chars; string[i] != '\0' && string[i] != '\n'; i++)
  1310.       string[i-chars] = string[i];
  1311.  
  1312.     string[i-chars] = '\0';
  1313. }
  1314.  
  1315. show_header(from, subject)
  1316. char *from, *subject;
  1317. {
  1318.     /** output header in clean format, including abbreviation
  1319.         of return address if more than one machine name is
  1320.         contained within it! **/
  1321.  
  1322.     char buffer[SLEN];
  1323.     int  loc, i=0, exc=0;
  1324.  
  1325. #ifdef PREFER_UUCP
  1326.     
  1327.     if (chloc(from,'!') != -1 && in_string(from, BOGUS_INTERNET))
  1328.       from[strlen(from) - strlen(BOGUS_INTERNET)] = '\0';
  1329.  
  1330. #endif
  1331.  
  1332.     loc = strlen(from);
  1333.  
  1334.     while (exc < 2 && loc > 0)
  1335.       if (from[--loc] == '!')
  1336.         exc++;
  1337.  
  1338.     if (exc == 2) { /* lots of machine names!  Get last one */
  1339.       loc++;
  1340.       while (loc < strlen(from) && loc < SLEN)
  1341.         buffer[i++] = from[loc++];
  1342.       buffer[i] = '\0';
  1343.       printf("%-20s  %s\n", buffer, subject);
  1344.     }
  1345.     else
  1346.       printf("%-20s  %s\n", from, subject);
  1347. }    
  1348.  
  1349. parse_arpa_from(buffer, newfrom)
  1350. char *buffer, *newfrom;
  1351. {
  1352.     /** try to parse the 'From:' line given... It can be in one of
  1353.         two formats:
  1354.         From: Dave Taylor <hpcnou!dat>
  1355.         or  From: hpcnou!dat (Dave Taylor)
  1356.         Change 'newfrom' ONLY if sucessfully parsed this entry and
  1357.         the resulting name is non-null! 
  1358.     **/
  1359.  
  1360.     char temp_buffer[SLEN], *temp;
  1361.     register int i, j = 0;
  1362.  
  1363.     temp = (char *) temp_buffer;
  1364.     temp[0] = '\0';
  1365.  
  1366.     no_ret(buffer);        /* blow away '\n' char! */
  1367.  
  1368.     if (lastch(buffer) == '>') {
  1369.       for (i=strlen("From: "); buffer[i] != '\0' && buffer[i] != '<' &&
  1370.            buffer[i] != '('; i++)
  1371.         temp[j++] = buffer[i];
  1372.       temp[j] = '\0';
  1373.     }
  1374.     else if (lastch(buffer) == ')') {
  1375.       for (i=strlen(buffer)-2; buffer[i] != '\0' && buffer[i] != '(' &&
  1376.            buffer[i] != '<'; i--)
  1377.         temp[j++] = buffer[i];
  1378.       temp[j] = '\0';
  1379.       reverse(temp);
  1380.     }
  1381.       
  1382.     if (strlen(temp) > 0) {        /* mess with buffer... */
  1383.  
  1384.       /* remove leading spaces... */
  1385.  
  1386.       while (whitespace(temp[0]))
  1387.         temp = (char *) (temp + 1);        /* increment address! */
  1388.  
  1389.       /* remove trailing spaces... */
  1390.  
  1391.       i = strlen(temp) - 1;
  1392.  
  1393.       while (whitespace(temp[i]))
  1394.        temp[i--] = '\0';
  1395.  
  1396.       /* if anything is left, let's change 'from' value! */
  1397.  
  1398.       if (strlen(temp) > 0)
  1399.         strcpy(newfrom, temp);
  1400.     }
  1401. }
  1402.  
  1403. reverse(string)
  1404. char *string;
  1405. {
  1406.     /** reverse string... pretty trivial routine, actually! **/
  1407.  
  1408.     char buffer[SLEN];
  1409.     register int i, j = 0;
  1410.  
  1411.     for (i = strlen(string)-1; i >= 0; i--)
  1412.       buffer[j++] = string[i];
  1413.  
  1414.     buffer[j] = '\0';
  1415.  
  1416.     strcpy(string, buffer);
  1417. }
  1418.  
  1419. int
  1420. expand(infile)
  1421. char *infile;
  1422. {
  1423.     /** Expand the filename since the first character is a meta-
  1424.         character that should expand to the "maildir" variable
  1425.         in the users ".elmrc" file...
  1426.  
  1427.         Note: this is a brute force way of getting the entry out 
  1428.         of the .elmrc file, and isn't recommended for the faint 
  1429.         of heart!
  1430.     **/
  1431.  
  1432.     FILE *rcfile;
  1433.     char  buffer[SLEN], *expanded_dir, *home, *getenv(), *bufptr;
  1434.     int   foundit = 0;
  1435.  
  1436.     bufptr = (char *) buffer;        /* same address */
  1437.     
  1438.     if ((home = getenv("HOME")) == NULL) {
  1439.       printf(
  1440.          "Can't expand environment variable $HOME to find .elmrc file!\n");
  1441.       exit(1);
  1442.     }
  1443.  
  1444.     sprintf(buffer, "%s/%s", home, elmrcfile);
  1445.  
  1446.     if ((rcfile = fopen(buffer, "r")) == NULL) {
  1447.       printf("Can't open your \".elmrc\" file (%s) for reading!\n",
  1448.          buffer);
  1449.       exit(1);
  1450.     }
  1451.  
  1452.     while (fgets(buffer, SLEN, rcfile) != NULL && ! foundit) {
  1453.       if (strncmp(buffer, "maildir", 7) == 0 ||
  1454.           strncmp(buffer, "folders", 7) == 0) {
  1455.         while (*bufptr != '=' && *bufptr) 
  1456.           bufptr++;
  1457.         bufptr++;            /* skip the equals sign */
  1458.         while (whitespace(*bufptr) && *bufptr)
  1459.           bufptr++; 
  1460.         home = bufptr;        /* remember this address */
  1461.  
  1462.         while (! whitespace(*bufptr) && *bufptr != '\n')
  1463.           bufptr++;
  1464.  
  1465.         *bufptr = '\0';        /* remove trailing space */
  1466.          foundit++;
  1467.       }
  1468.     }
  1469.  
  1470.     fclose(rcfile);            /* be nice... */
  1471.  
  1472.     if (! foundit) {
  1473.       printf("Couldn't find \"maildir\" in your .elmrc file!\n");
  1474.       exit(1);
  1475.     }
  1476.  
  1477.     /** Home now points to the string containing your maildir, with
  1478.         no leading or trailing white space...
  1479.     **/
  1480.  
  1481.     expanded_dir = expand_define(home);
  1482.  
  1483.     sprintf(buffer, "%s%s%s", expanded_dir, 
  1484.         (expanded_dir[strlen(expanded_dir)-1] == '/' ||
  1485.         infile[0] == '/') ? "" : "/", (char *) infile+1);
  1486.  
  1487.     strcpy(infile, buffer);
  1488. }
  1489.  
  1490. char *expand_define(maildir)
  1491. char *maildir;
  1492. {
  1493.     /** This routine expands any occurances of "~" or "$var" in
  1494.         the users definition of their maildir directory out of
  1495.         their .elmrc file.
  1496.  
  1497.         Again, another routine not for the weak of heart or staunch
  1498.         of will!
  1499.     **/
  1500.  
  1501.     static char buffer[SLEN];    /* static buffer AIEE!! */
  1502.     char   name[SLEN],        /* dynamic buffer!! (?) */
  1503.            *nameptr,           /*  pointer to name??     */
  1504.            *value;              /* char pointer for munging */
  1505.  
  1506.     if (*maildir == '~') 
  1507.       sprintf(buffer, "%s%s", getenv("HOME"), ++maildir);
  1508.     else if (*maildir == '$') {     /* shell variable */
  1509.  
  1510.       /** break it into a single word - the variable name **/
  1511.  
  1512.       strcpy(name, (char *) maildir + 1);    /* hurl the '$' */
  1513.       nameptr = (char *) name;
  1514.       while (*nameptr != '/' && *nameptr) nameptr++;
  1515.       *nameptr = '\0';    /* null terminate */
  1516.       
  1517.       /** got word "name" for expansion **/
  1518.  
  1519.       if ((value = getenv(name)) == NULL) {
  1520.         printf("Couldn't expand shell variable $%s in .elmrc!\n", name);
  1521.         exit(1);
  1522.       }
  1523.       sprintf(buffer, "%s%s", value, maildir + strlen(name) + 1);
  1524.     }
  1525.  
  1526.     return( ( char *) buffer);
  1527. }
  1528. END-OF-FILE
  1529.  
  1530. if [ "$filename" != "/dev/null" ]
  1531. then
  1532.   size=`wc -c < $filename`
  1533.  
  1534.   if [ $size != 8783 ]
  1535.   then
  1536.     echo $filename changed - should be 8783 bytes, not $size bytes
  1537.   fi
  1538.  
  1539.   chmod 666 $filename
  1540. fi
  1541.  
  1542. # ---------- file utils/newmail.c ----------
  1543.  
  1544. filename="utils/newmail.c"
  1545.  
  1546. if [ -f $filename ]
  1547. then
  1548.   echo File \"$filename\" already exists\!  Skipping...
  1549.   filename=/dev/null        # throw it away
  1550. else
  1551.   echo extracting file utils/newmail.c...
  1552. fi
  1553.  
  1554. cat << 'END-OF-FILE' > $filename
  1555. /**            newmail.c            **/
  1556.  
  1557. /** Keep track of the mail for the current user...if new mail
  1558.     arrives, output a line of the form;
  1559.  
  1560.        Mail has arrived from <name> - <subject>
  1561.  
  1562.     where <name> is either the persons full name, or machine!login.
  1563.     If there is no subject, it will say.
  1564.  
  1565.     Added: you can specify a file other than the mailbox to keep
  1566.     track of - if an argument is given, the program will try
  1567.     to use it as a filename...
  1568.  
  1569.     Also, the program will quit when you log off of the machine.
  1570.  
  1571.     (C) 1986, Dave Taylor
  1572. **/
  1573.  
  1574. #ifdef AUTO_BACKGROUND
  1575. #include <signal.h>    /* background jobs ignore some signals... */
  1576. #endif
  1577.  
  1578. #include <stdio.h>
  1579. #include <sys/types.h>
  1580. #include <sys/stat.h>
  1581.  
  1582. #include "defs.h"
  1583.  
  1584. static char ident[] = { WHAT_STRING };
  1585.  
  1586. #define LINEFEED    (char) 10
  1587. #define BEGINNING    0            /* seek fseek(3S) */
  1588. #define SLEEP_TIME    60        
  1589.  
  1590. #define NO_SUBJECT    "(No Subject Specified)"
  1591.  
  1592. FILE *mailfile;
  1593.  
  1594. long  bytes();
  1595.  
  1596. main(argc, argv)
  1597. int argc;
  1598. char *argv[];
  1599. {
  1600.     char filename[LONG_SLEN];
  1601.     long size, newsize;
  1602.  
  1603.     if (argc > 2) 
  1604.       fprintf(stderr, "Usage: %s [filename] &\n", argv[0]);
  1605.     else if (argc == 2) {
  1606.       strcpy(filename, argv[1]);
  1607.       if (access(filename, ACCESS_EXISTS) == -1) {
  1608.         fprintf(stderr,"%s: Can't open file %s to keep track of!\n",
  1609.             argv[0], filename);
  1610.         exit(1);
  1611.       }
  1612.     }
  1613.     else
  1614.       sprintf(filename,"%s/%s",mailhome, getlogin());
  1615.  
  1616. #ifdef AUTO_BACKGROUND
  1617.     if (fork())        /* automatically puts this task in background! */
  1618.       exit(0);
  1619.  
  1620.     signal(SIGINT, SIG_IGN);
  1621.     signal(SIGQUIT, SIG_IGN);
  1622.     signal(SIGHUP,  SIG_DFL);    /* so we exit when logged out */
  1623. #endif
  1624.  
  1625.     size = bytes(filename);
  1626.  
  1627.     mailfile = (FILE *) NULL;
  1628.  
  1629.     while (1) {
  1630.     
  1631. #ifndef AUTO_BACKGROUND        /* won't work if we're nested this deep! */
  1632.       if (getppid() == 1)     /* we've lost our shell! */
  1633.         exit();
  1634. #endif
  1635.     
  1636.     /** Note the lack of error checking on the fopen() (Philip Peake
  1637.         did!) - this is okay since if it fails we don't have any 
  1638.         mail and we can sleep(60) and try again later... 
  1639.     **/
  1640.  
  1641.       if (mailfile == (FILE *) NULL) 
  1642.         mailfile = fopen(filename,"r");
  1643.  
  1644.       if ((newsize = bytes(filename)) > size) {    /* new mail */
  1645.         fseek(mailfile, size, BEGINNING); /* skip all current mail */
  1646.         size = newsize;
  1647.         printf("\n\r");    /* blank lines surrounding message */
  1648.         read_headers();
  1649.         printf("\n\r");
  1650.       }
  1651.       else if (newsize != size) {
  1652.         size = newsize;         /* mail's been removed... */
  1653.         (void) fclose(mailfile);    /* close it and ...       */
  1654.         mailfile = (FILE *) NULL;    /* let's reopen the file  */
  1655.       }
  1656.  
  1657.       sleep(SLEEP_TIME);
  1658.     }
  1659. }
  1660.  
  1661. int
  1662. read_headers()
  1663. {
  1664.     /** read the headers, output as found **/
  1665.  
  1666.     char buffer[LONG_SLEN], from_whom[SLEN], subject[SLEN];
  1667.     register int subj = 0, in_header = 1, count = 0;
  1668.  
  1669.     while (fgets(buffer, LONG_SLEN, mailfile) != NULL) {
  1670.       if (first_word(buffer,"From ")) {
  1671.         if (real_from(buffer, from_whom)) {
  1672.           subj = 0;
  1673.           in_header = 1;
  1674.         }
  1675.       }
  1676.       else if (in_header) {
  1677.         if (first_word(buffer,">From")) 
  1678.           forwarded(buffer, from_whom); /* return address */
  1679.         else if (first_word(buffer,"Subject:") ||
  1680.              first_word(buffer,"Re:")) {
  1681.           if (! subj++) {
  1682.             remove_first_word(buffer);
  1683.         strcpy(subject, buffer);
  1684.           }
  1685.         }
  1686.         else if (first_word(buffer,"From:")) 
  1687.           parse_arpa_from(buffer, from_whom);
  1688.         else if (buffer[0] == LINEFEED) {
  1689.           in_header = 0;    /* in body of message! */
  1690.           show_header(from_whom, subject);
  1691.           from_whom[0] = 0;
  1692.           subject[0] = 0;
  1693.           count++;
  1694.         }
  1695.       }
  1696.     }
  1697.     return(count);
  1698. }
  1699.  
  1700. int
  1701. real_from(buffer, who)
  1702. char *buffer, *who;
  1703. {
  1704.     /***** returns true iff 's' has the seven 'from' fields,
  1705.            initializing the who to the sender *****/
  1706.  
  1707.     char junk[80];
  1708.  
  1709.     junk[0] = '\0';
  1710.     sscanf(buffer, "%*s %s %*s %*s %*s %*s %s",
  1711.                 who, junk);
  1712.     return(junk[0] != '\0');
  1713. }
  1714.  
  1715. forwarded(buffer, who)
  1716. char *buffer, *who;
  1717. {
  1718.     /** change 'from' and date fields to reflect the ORIGINATOR of 
  1719.         the message by iteratively parsing the >From fields... **/
  1720.  
  1721.     char machine[80], buff[80];
  1722.  
  1723.     machine[0] = '\0';
  1724.     sscanf(buffer, "%*s %s %*s %*s %*s %*s %*s %*s %*s %s",
  1725.                 who, machine);
  1726.  
  1727.     if (machine[0] == '\0') /* try for srm address */
  1728.       sscanf(buffer, "%*s %s %*s %*s %*s %*s %*s %*s %s",
  1729.                 who, machine);
  1730.  
  1731.     if (machine[0] == '\0')
  1732.       sprintf(buff,"anonymous");
  1733.     else
  1734.       sprintf(buff,"%s!%s", machine, who);
  1735.  
  1736.     strncpy(who, buff, 80);
  1737. }
  1738.  
  1739.  
  1740. remove_first_word(string)
  1741. char *string;
  1742. {    /** removes first word of string, ie up to first non-white space
  1743.         following a white space! **/
  1744.  
  1745.     register int loc;
  1746.  
  1747.     for (loc = 0; string[loc] != ' ' && string[loc] != '\0'; loc++) 
  1748.         ;
  1749.  
  1750.     while (string[loc] == ' ' || string[loc] == '\t')
  1751.       loc++;
  1752.     
  1753.     move_left(string, loc);
  1754. }
  1755.  
  1756. move_left(string, chars)
  1757. char string[];
  1758. int  chars;
  1759. {
  1760.     /** moves string chars characters to the left DESTRUCTIVELY **/
  1761.  
  1762.     register int i;
  1763.  
  1764.     chars--; /* index starting at zero! */
  1765.  
  1766.     for (i=chars; string[i] != '\0' && string[i] != '\n'; i++)
  1767.       string[i-chars] = string[i];
  1768.  
  1769.     string[i-chars] = '\0';
  1770. }
  1771.  
  1772. show_header(from, subject)
  1773. char *from, *subject;
  1774. {
  1775.     /** output header in clean format, including abbreviation
  1776.         of return address if more than one machine name is
  1777.         contained within it! **/
  1778.     char buffer[SLEN];
  1779.     int  loc, i=0, exc=0;
  1780.  
  1781. #ifdef PREFER_UUCP
  1782.  
  1783.     if (chloc(from, '!') != -1 && in_string(from, BOGUS_INTERNET))
  1784.       from[strlen(from) - strlen(BOGUS_INTERNET)] = '\0';
  1785.  
  1786. #endif
  1787.  
  1788.     loc = strlen(from);
  1789.  
  1790.     while (exc < 2 && loc > 0)
  1791.       if (from[--loc] == '!')
  1792.         exc++;
  1793.  
  1794.     if (exc == 2) { /* lots of machine names!  Get last one */
  1795.       loc++;
  1796.       while (loc < strlen(from) && loc < SLEN)
  1797.         buffer[i++] = from[loc++];
  1798.       buffer[i] = '\0';
  1799.       strcpy(from, buffer);
  1800.     }
  1801.  
  1802.     if (strlen(subject) < 2)
  1803.       strcpy(subject, NO_SUBJECT);
  1804.     
  1805.     printf(">> New mail from %s - %s\n\r", from, subject);
  1806. }    
  1807.  
  1808. parse_arpa_from(buffer, newfrom)
  1809. char *buffer, *newfrom;
  1810. {
  1811.     /** try to parse the 'From:' line given... It can be in one of
  1812.         two formats:
  1813.         From: Dave Taylor <hpcnou!dat>
  1814.         or  From: hpcnou!dat (Dave Taylor)
  1815.         Change 'newfrom' ONLY if sucessfully parsed this entry and
  1816.         the resulting name is non-null! 
  1817.     **/
  1818.  
  1819.     char temp_buffer[SLEN], *temp;
  1820.     register int i, j = 0;
  1821.  
  1822.     temp = (char *) temp_buffer;
  1823.     temp[0] = '\0';
  1824.  
  1825.     no_ret(buffer);        /* blow away '\n' char! */
  1826.  
  1827.     if (lastch(buffer) == '>') {
  1828.       for (i=strlen("From: "); buffer[i] != '\0' && buffer[i] != '<' &&
  1829.            buffer[i] != '('; i++)
  1830.         temp[j++] = buffer[i];
  1831.       temp[j] = '\0';
  1832.     }
  1833.     else if (lastch(buffer) == ')') {
  1834.       for (i=strlen(buffer)-2; buffer[i] != '\0' && buffer[i] != '(' &&
  1835.            buffer[i] != '<'; i--)
  1836.         temp[j++] = buffer[i];
  1837.       temp[j] = '\0';
  1838.       reverse(temp);
  1839.     }
  1840.       
  1841.     if (strlen(temp) > 0) {        /* mess with buffer... */
  1842.  
  1843.       /* remove leading spaces... */
  1844.  
  1845.       while (whitespace(temp[0]))
  1846.         temp = (char *) (temp + 1);        /* increment address! */
  1847.  
  1848.       /* remove trailing spaces... */
  1849.  
  1850.       i = strlen(temp) - 1;
  1851.  
  1852.       while (whitespace(temp[i]))
  1853.        temp[i--] = '\0';
  1854.  
  1855.       /* if anything is left, let's change 'from' value! */
  1856.  
  1857.       if (strlen(temp) > 0)
  1858.         strcpy(newfrom, temp);
  1859.     }
  1860. }
  1861.  
  1862. reverse(string)
  1863. char *string;
  1864. {
  1865.     /** reverse string... pretty trivial routine, actually! **/
  1866.  
  1867.     char buffer[SLEN];
  1868.     register int i, j = 0;
  1869.  
  1870.     for (i = strlen(string)-1; i >= 0; i--)
  1871.       buffer[j++] = string[i];
  1872.  
  1873.     buffer[j] = '\0';
  1874.  
  1875.     strcpy(string, buffer);
  1876. }
  1877.  
  1878. long
  1879. bytes(name)
  1880. char *name;
  1881. {
  1882.     /** return the number of bytes in the specified file.  This
  1883.         is to check to see if new mail has arrived....  **/
  1884.  
  1885.     int ok = 1;
  1886.     extern int errno;    /* system error number! */
  1887.     struct stat buffer;
  1888.  
  1889.     if (stat(name, &buffer) != 0)
  1890.       if (errno != 2)
  1891.        exit(fprintf(stderr,"Error %d attempting fstat on %s", errno, name));
  1892.       else
  1893.         ok = 0;
  1894.     
  1895.     return(ok ? buffer.st_size : 0);
  1896. }
  1897. END-OF-FILE
  1898.  
  1899. if [ "$filename" != "/dev/null" ]
  1900. then
  1901.   size=`wc -c < $filename`
  1902.  
  1903.   if [ $size != 7761 ]
  1904.   then
  1905.     echo $filename changed - should be 7761 bytes, not $size bytes
  1906.   fi
  1907.  
  1908.   chmod 666 $filename
  1909. fi
  1910.  
  1911. # ---------- file utils/newalias.c ----------
  1912.  
  1913. filename="utils/newalias.c"
  1914.  
  1915. if [ -f $filename ]
  1916. then
  1917.   echo File \"$filename\" already exists\!  Skipping...
  1918.   filename=/dev/null        # throw it away
  1919. else
  1920.   echo extracting file utils/newalias.c...
  1921. fi
  1922.  
  1923. cat << 'END-OF-FILE' > $filename
  1924. /**        newalias.c        **/
  1925.  
  1926. /** (C) Copyright 1986 Dave Taylor      **/
  1927.  
  1928. /** Install a new set of aliases for the 'Elm' mailer. 
  1929.  
  1930.     If invoked with a specific filename, it assumes that
  1931.   it is working with an individual users alias tables, and
  1932.   generates the .alias.hash and .alias.data files in their
  1933.   home directory.
  1934.     If, however, it is invoked with no arguments, then
  1935.   it assumes that the user is updating the system alias
  1936.   file and uses the defaults for everything.
  1937.  
  1938.   The format for the input file is;
  1939.     alias1, alias2, ... : username : address
  1940. or  alias1, alias2, ... : groupname: member, member, member, ...
  1941.                                      member, member, member, ...
  1942.  
  1943.   "-q" flag added: 6/17/86
  1944. **/
  1945.  
  1946. #ifdef BSD
  1947. #  include <sys/file.h>
  1948. #else
  1949. #  include <fcntl.h>
  1950. #endif
  1951.  
  1952. #include <stdio.h>
  1953. #include "defs.h"        /* ELM system definitions */
  1954.  
  1955. static char ident[] = { WHAT_STRING };
  1956.  
  1957. #ifndef TAB
  1958. # define TAB         '\t'    /* TAB character!         */
  1959. #endif
  1960.     
  1961. #define alias_hash    ".alias_hash"
  1962. #define alias_data    ".alias_data"
  1963. #define alias_text    ".alias_text"
  1964.  
  1965. #define group(string)        (strpbrk(string,", ") != NULL)
  1966.  
  1967. struct alias_rec
  1968. shash_table[MAX_SALIASES];    /* the actual hash table     */
  1969.  
  1970. struct alias_rec
  1971. uhash_table[MAX_UALIASES];    /* the actual hash table     */
  1972.  
  1973. int  hash_table_loaded=0;    /* is system table actually loaded? */
  1974.  
  1975. int  buff_loaded;        /* for file input overlap... */
  1976. int  error= 0;            /* if errors, don't save!    */
  1977. int  system=0;            /* system file updating?     */
  1978. int  count=0;            /* how many aliases so far?  */
  1979. long offset = 0L;        /* data file line offset!    */
  1980.  
  1981. main(argc, argv)
  1982. int argc;
  1983. char *argv[];
  1984. {
  1985.     FILE *in, *data;
  1986.     char inputname[SLEN], hashname[SLEN], dataname[SLEN];
  1987.     char home[SLEN], buffer[LONG_STRING];
  1988.     int  hash, count = 0, owner, quiet = 0;
  1989.  
  1990.     if (argc != 1)
  1991.       if (strcmp(argv[1], "-q") == 0)
  1992.         quiet++;
  1993.       else
  1994.         exit(printf("Usage: %s\n", argv[0]));
  1995.  
  1996.     owner = getuid();
  1997.  
  1998.     if (owner == 0 && ! quiet) {    /* being run by root! */
  1999.       printf("Would you like to update the system aliases? (y/n)");
  2000.       gets(buffer, 2);
  2001.       if (buffer[0] == 'y' || buffer[0] == 'Y') {
  2002.         printf("Updating the system alias file...\n");
  2003.  
  2004.         sprintf(inputname, "%s/%s", mailhome, alias_text);
  2005.         sprintf(hashname, "%s/%s", mailhome, alias_hash);
  2006.         sprintf(dataname, "%s/%s", mailhome, alias_data);
  2007.         system++;
  2008.         init_table(shash_table, MAX_SALIASES); 
  2009.       }
  2010.       else 
  2011.         printf("Updating your personal alias file...\n");
  2012.     }
  2013.     
  2014.     if (! system) {
  2015.       if (strcpy(home, getenv("HOME")) == NULL)
  2016.         exit(printf("Confused: No HOME variable in environment!\n"));
  2017.  
  2018.       sprintf(inputname, "%s/%s", home, alias_text);
  2019.       sprintf(hashname,  "%s/%s", home, alias_hash); 
  2020.       sprintf(dataname,  "%s/%s", home, alias_data); 
  2021.  
  2022.       init_table(uhash_table, MAX_UALIASES); 
  2023.  
  2024.       read_in_system(shash_table, sizeof shash_table);
  2025.     }
  2026.  
  2027.     if ((in = fopen(inputname,"r")) == NULL)
  2028.       exit(printf("Couldn't open %s for input!\n", inputname));
  2029.  
  2030.     if ((hash = open(hashname, O_WRONLY | O_CREAT, 0644)) == -1)
  2031.       exit(printf("Couldn't open %s for output!\n", hashname));
  2032.  
  2033.     if ((data = fopen(dataname,"w")) == NULL)
  2034.       exit(printf("Couldn't open %s for output!\n", dataname));
  2035.  
  2036.     buff_loaded = 0;     /* file buffer empty right now! */
  2037.  
  2038.     while (get_alias(in, buffer) != -1) {
  2039.       if (system)
  2040.         put_alias(data, buffer, shash_table, MAX_SALIASES);    
  2041.       else
  2042.         put_alias(data, buffer, uhash_table, MAX_UALIASES);    
  2043.       count++;
  2044.     }
  2045.  
  2046.     if (error) {
  2047.       printf("\n** Not saving tables!  Please fix and re-run %s!\n",
  2048.          argv[0]);
  2049.       exit(1);
  2050.     }
  2051.     else {
  2052.       if (system)
  2053.         write(hash, shash_table, sizeof shash_table);
  2054.       else
  2055.         write(hash, uhash_table, sizeof uhash_table);
  2056.  
  2057.       close(hash);
  2058.       fclose(data);
  2059.       close(in);
  2060.     
  2061.       printf("Processed %d aliases\n", count);
  2062.       exit(0);
  2063.     }
  2064. }
  2065.  
  2066. int
  2067. get_alias(file, buffer)
  2068. FILE *file;
  2069. char *buffer;
  2070. {
  2071.     /* load buffer with the next complete alias from the file.
  2072.        (this can include reading in multiple lines and appending
  2073.        them all together!)  Returns EOF after last entry in file.
  2074.     
  2075.     Lines that start with '#' are assumed to be comments and are
  2076.      ignored.  White space as the first field of a line is taken
  2077.     to indicate that this line is a continuation of the previous. */
  2078.  
  2079.     static char mybuffer[SLEN];
  2080.     int    done = 0, first_read = 1;
  2081.  
  2082.     /** get the first line of the entry... **/
  2083.  
  2084.     buffer[0] = '\0';            /* zero out line */
  2085.  
  2086.     do {
  2087.       if (get_line(file, mybuffer, first_read) == -1) 
  2088.         return(-1);
  2089.       first_read = 0;
  2090.       if (mybuffer[0] != '#')
  2091.         strcpy(buffer, mybuffer);
  2092.     } while (strlen(buffer) == 0);    
  2093.  
  2094.     /** now read in the rest (if there is any!) **/
  2095.  
  2096.     do {
  2097.       if (get_line(file, mybuffer, first_read) == -1) {
  2098.         buff_loaded = 0;    /* force a read next pass! */
  2099.         return(0);    /* okay. let's just hand 'buffer' back! */
  2100.       }
  2101.       done = (mybuffer[0] != ' ' && mybuffer[0] != TAB);
  2102.       if (mybuffer[0] != '#' && ! done)
  2103.         strcat(buffer, mybuffer);
  2104.       done = (done && mybuffer[0] != '#');
  2105.     } while (! done);
  2106.     
  2107.     return(0);    /* no sweat! */
  2108. }
  2109.  
  2110. put_alias(data, buffer, table, size)
  2111. FILE *data;
  2112. char *buffer;
  2113. struct alias_rec table[];
  2114. int  size;
  2115. {
  2116.     /** break buffer down into two pieces: aliases, and address,
  2117.         throwing away the username (comment) field. 
  2118.         Make the appropriate entries in the table (size) **/
  2119.  
  2120.     char aliases[LONG_STRING], address[LONG_STRING];
  2121.     int  i = 0, j = 0;
  2122.  
  2123.     remove_all(' ', TAB, buffer);
  2124.  
  2125.     for (i=0; buffer[i] != ':' && i < LONG_STRING; i++)
  2126.       aliases[i] = buffer[i];
  2127.     aliases[i] = '\0';
  2128.  
  2129.     for (i=strlen(buffer)-1; buffer[i] != ':' && i > 0; i--)
  2130.       address[j++] = buffer[i];
  2131.     address[j] = '\0';
  2132.  
  2133.     reverse(address);
  2134.  
  2135.     add_to_table(data, aliases, address, table, size);
  2136. }
  2137.  
  2138. int
  2139. get_line(file, buffer, first_line)
  2140. FILE *file;
  2141. char *buffer;
  2142. int  first_line;
  2143. {
  2144.     /** read line from file.  If first_line and buff_loaded, 
  2145.         then just return! **/
  2146.     int stat;
  2147.  
  2148.     if (first_line && buff_loaded) {
  2149.       buff_loaded = 1;
  2150.       return;
  2151.     }
  2152.  
  2153.     buff_loaded = 1;    /* we're going to get SOMETHING in the buffer */
  2154.  
  2155.     stat = fgets(buffer, SLEN, file) == NULL ? -1 : 0;
  2156.  
  2157.     if (stat != -1)
  2158.       no_ret(buffer);
  2159.  
  2160.     return(stat);
  2161. }
  2162.  
  2163. reverse(string)
  2164. char *string;
  2165. {
  2166.     /** reverse the order of the characters in string... 
  2167.         uses a bubble-sort type of algorithm!                 **/
  2168.     
  2169.     register int f, l;
  2170.     char     c;
  2171.     
  2172.     f = 0;
  2173.     l = strlen(string) - 1;
  2174.     
  2175.     while (f < l) {
  2176.       c = string[f];
  2177.        string[f] = string[l];
  2178.       string[l] = c;
  2179.       f++;
  2180.       l--;
  2181.     }
  2182. }
  2183.  
  2184. add_to_table(data, aliases, address, table, size)
  2185. FILE *data;
  2186. char *aliases, *address;
  2187. struct alias_rec table[];
  2188. int  size;
  2189. {
  2190.     /** add address to datafile, incrementing offset count (bytes),
  2191.         then for each alias in the aliases string, add to the
  2192.         hash table, with the associated pointer value! **/
  2193.  
  2194.     static char buf[SLEN], *word;
  2195.     long additive = 1L;
  2196.  
  2197.     word = buf;    /* use the allocated space! */
  2198.  
  2199.     if (group(address)) {
  2200.       check_group(address, aliases);
  2201.       if (error) return;    /* don't do work if we aren't to save it! */
  2202.       fprintf(data, "!%s\n", address);
  2203.       additive = 2L;
  2204.     }
  2205.     else {
  2206.       if (error) return;    /* don't do work if we aren't to save it! */
  2207.       fprintf(data, "%s\n", address);
  2208.     }
  2209.  
  2210.     while ((word = (char *) strtok(aliases,", ")) != NULL) {
  2211.       add_to_hash_table(word, offset, table, size);
  2212.       aliases = NULL;    /* let's get ALL entries via 'strtok' */
  2213.       count++;
  2214.     }
  2215.  
  2216.     if ( system ? count > MAX_SALIASES-35 : count > MAX_UALIASES-21) {
  2217.       printf("** Too many aliases in file! **\n");
  2218.       error++;
  2219.     }
  2220.  
  2221.     offset = (offset + (long) strlen(address) + additive);
  2222. }    
  2223.  
  2224. remove_all(c1, c2, string)
  2225. char c1, c2, *string;
  2226. {
  2227.     /* remove all occurances of character 'c' from string. */
  2228.     char buffer[LONG_STRING];
  2229.     register int i = 0, j = 0;
  2230.     
  2231.     for (i = 0; string[i] != '\0' && i < LONG_STRING; i++)
  2232.       if (string[i] != c1 && string[i] != c2)
  2233.         buffer[j++] = string[i];
  2234.  
  2235.     buffer[j] = '\0';
  2236.     strcpy(string, buffer);
  2237. }
  2238.  
  2239. add_to_hash_table(word, offset, table, size)
  2240. char *word;
  2241. long  offset;
  2242. struct alias_rec table[];
  2243. int   size;
  2244. {
  2245.     /** add word and offset to current hash table. **/
  2246.     register int loc;
  2247.     
  2248.     if (strlen(word) > 20)
  2249.       exit(printf("Bad alias name: %s.  Too long.\n", word));
  2250.  
  2251.     loc = hash_it(word, size);
  2252.  
  2253.     while (table[loc].name[0] != '\0' && strcmp(table[loc].name, word) != 0)
  2254.       loc = loc + 1 % size; 
  2255.  
  2256.     if (table[loc].name[0] == '\0') {
  2257.       strcpy(table[loc].name, word);
  2258.       table[loc].byte = offset;
  2259.     }
  2260.     else 
  2261.       printf("** Duplicate alias '%s' in file.  Multiples ignored.\n",
  2262.              word);
  2263. }
  2264.  
  2265. int
  2266. hash_it(string, table_size)
  2267. char *string;
  2268. {
  2269.     /** compute the hash function of the string, returning
  2270.         it (mod table_size) **/
  2271.  
  2272.     register int i, sum = 0;
  2273.     
  2274.     for (i=0; string[i] != '\0'; i++)
  2275.       sum += (int) string[i];
  2276.  
  2277.     return(sum % table_size);
  2278. }
  2279.  
  2280. init_table(table, size)
  2281. struct alias_rec table[];
  2282. int size;
  2283. {
  2284.     /** initialize hash table! **/
  2285.  
  2286.     register int i;
  2287.  
  2288.     for (i=0; i < size; i++)
  2289.       table[i].name[0] = '\0';
  2290. }
  2291.  
  2292. read_in_system(table, size)
  2293. struct alias_rec table[];
  2294. int size;
  2295. {
  2296.     /** read in the system hash table...to check for group aliases
  2297.         from the user alias file (to ensure that there are no names
  2298.         in the user group files that are not purely contained within
  2299.         either alias table) **/
  2300.     
  2301.     int  fd;
  2302.     char fname[SLEN];
  2303.  
  2304.     sprintf(fname, "%s/%s", mailhome, alias_hash);
  2305.  
  2306.     if ((fd = open(fname, O_RDONLY)) == -1)
  2307.       return;    /* no sweat: flag 'hash_table_loaded' not set! */
  2308.  
  2309.     (void) read(fd, table, size);
  2310.     close(fd);
  2311.     hash_table_loaded++;
  2312. }
  2313.     
  2314. check_group(names, groupname)
  2315. char *names, *groupname;
  2316. {
  2317.     /** one by one make sure each name in the group is defined
  2318.         in either the system alias file or the user alias file.
  2319.         This search is linearly dependent, so all group aliases
  2320.         in the source file should appear LAST, after all the user
  2321.         aliases! **/
  2322.  
  2323.     char *word, *bufptr, buffer[LONG_STRING];
  2324.  
  2325.     strcpy(buffer, names);
  2326.     bufptr = (char *) buffer;
  2327.  
  2328.     while ((word = (char *) strtok(bufptr,", ")) != NULL) {
  2329.       if (! can_find(word)) 
  2330.         if (! valid_name(word)) {
  2331.           error++;
  2332.           printf("** Alias %s in group %s is bad!\n", word, groupname);
  2333.         }
  2334.       bufptr = NULL;
  2335.     }
  2336. }
  2337.  
  2338. int
  2339. can_find(name)
  2340. char *name;
  2341. {    
  2342.     /** find name in either hash table...use 'system' variable to
  2343.         determine if we should look in both or just system....    **/
  2344.  
  2345.     register int loc;
  2346.     
  2347.     if (strlen(name) > 20) {
  2348.       error++;
  2349.       printf("** Bad alias name: %s.  Too long.\n", name);
  2350.       return(1);    /* fake out: don't want 2 error messages! */
  2351.     }
  2352.  
  2353.     /** system alias table... **/
  2354.     if (hash_table_loaded || system) {
  2355.       loc = hash_it(name, MAX_SALIASES);
  2356.  
  2357.       while (strcmp(name, shash_table[loc].name) != 0 && 
  2358.                  shash_table[loc].name[0] != '\0')
  2359.         loc = (loc + 1) % MAX_SALIASES; 
  2360.   
  2361.       if (strcmp(name, shash_table[loc].name) == 0)
  2362.         return(1);    /* found it! */
  2363.     }
  2364.  
  2365.     if (! system) {    /* okay! Let's check the user alias file! */
  2366.       loc = hash_it(name, MAX_UALIASES);
  2367.  
  2368.       while (strcmp(name, uhash_table[loc].name) != 0 && 
  2369.                  uhash_table[loc].name[0] != '\0')
  2370.         loc = (loc + 1) % MAX_UALIASES; 
  2371.  
  2372.       if (strcmp(name, uhash_table[loc].name) == 0)
  2373.         return(1);    /* found it! */
  2374.     }
  2375.  
  2376.     return(0);
  2377. }
  2378. END-OF-FILE
  2379.  
  2380. if [ "$filename" != "/dev/null" ]
  2381. then
  2382.   size=`wc -c < $filename`
  2383.  
  2384.   if [ $size != 11051 ]
  2385.   then
  2386.     echo $filename changed - should be 11051 bytes, not $size bytes
  2387.   fi
  2388.  
  2389.   chmod 666 $filename
  2390. fi
  2391.  
  2392. # ---------- file utils/printmail.c ----------
  2393.  
  2394. filename="utils/printmail.c"
  2395.  
  2396. if [ -f $filename ]
  2397. then
  2398.   echo File \"$filename\" already exists\!  Skipping...
  2399.   filename=/dev/null        # throw it away
  2400. else
  2401.   echo extracting file utils/printmail.c...
  2402. fi
  2403.  
  2404. cat << 'END-OF-FILE' > $filename
  2405. /**        printmail.c        **/
  2406.  
  2407. /** print mail, adding a formfeed between each message  **/
  2408. /** Modified to use stdin if being fed from a pipe.    **/
  2409.  
  2410. /** (C) Copyright 1985, Dave Taylor **/
  2411.  
  2412. #include <stdio.h>
  2413. #include "defs.h"
  2414.  
  2415. static char ident[] = { WHAT_STRING };
  2416.  
  2417. #define  dashes          \
  2418. "\n\n------------------------------------------------------------------------------\n\n"
  2419. #define  FF            "\014"    /* form feed! */
  2420.  
  2421. FILE *mailfile;
  2422. char  separator[80];
  2423.  
  2424. main(argc, argv)
  2425. int argc;
  2426. char *argv[];
  2427. {
  2428.     char infile[80], username[40], c;
  2429.  
  2430.     strcpy(separator, FF);
  2431.  
  2432.     *argv++;                /* get past argv[0] */
  2433.  
  2434.     if (argc > 1) 
  2435.       if (strcmp(*argv, "-d") == 0) {
  2436.         strcpy(separator, dashes);
  2437.         --argc;
  2438.         *argv++;
  2439.       }
  2440.     
  2441.     if (argc > 1 && *argv[0] == '-') 
  2442.         exit(fprintf(stderr, "Usage: printmail {-d} {filename (s)}\n"));
  2443.     
  2444.     if (argc == 1) {
  2445.       strcpy(username, getlogin());
  2446.       if (strlen(username) == 0)
  2447.         cuserid(username);
  2448.       if (isatty(fileno(stdin))) {    /* normal invokation... */
  2449.         sprintf(infile,"%s/%s",mailhome, username);
  2450.         if ((mailfile = fopen(infile,"r")) == NULL) {
  2451.           fprintf(stderr, "No mail!\n");
  2452.           exit(0);
  2453.         }
  2454.       }
  2455.       else 
  2456.         mailfile = stdin;    /* read from stdin! */
  2457.  
  2458.       if (read_headers() == 0)
  2459.         fprintf(stderr, "No messages in mailbox!\n");
  2460.     }
  2461.  
  2462.     if (argc > 1)        /* more than one file - delimit each */
  2463.       if (strcmp(separator, FF) != 0) 
  2464.         printf("\t\t\t%s\n%s", *argv, separator);
  2465.       else
  2466.         printf("\t\t\t%s\n\n", *argv);    /* Don't put a formfeed! */
  2467.  
  2468.     while (--argc) {
  2469.       if ((mailfile = fopen(*argv,"r")) == NULL) {
  2470.         fprintf(stderr, "Could not open file '%s'!", *argv);
  2471.         break;
  2472.       }
  2473.       else
  2474.         if (read_headers() == 0)
  2475.           fprintf(stderr, "No messages in mailbox '%s'!\n", *argv);
  2476.       *argv++;
  2477.       if (argc) {
  2478.         if (strcmp(separator, FF) != 0) 
  2479.           printf("%s\t\t\t%s%s", separator, *argv, separator);
  2480.         else
  2481.           printf("%s\t\t\t%s\n\n", separator, *argv);
  2482.       }
  2483.     }
  2484. }
  2485.  
  2486. int
  2487. read_headers()
  2488. {
  2489.     char buffer[100];
  2490.     register int count = 0;
  2491.  
  2492.     while (fgets(buffer, 100, mailfile) != NULL) 
  2493.       if (first_word(buffer,"From ")) {
  2494.         if (real_from(buffer)) {
  2495.           printf("%s%s", count ? separator : "", buffer);
  2496.           count++;
  2497.         }
  2498.       }
  2499.       else
  2500.         printf("%s", buffer);
  2501.  
  2502.     return(count);
  2503. }
  2504.  
  2505. int
  2506. real_from(buffer)
  2507. char *buffer;
  2508. {
  2509.     /***** returns true iff 's' has the seven 'from' fields *****/
  2510.  
  2511.     char junk[80];
  2512.  
  2513.     junk[0] = '\0';
  2514.     sscanf(buffer, "%*s %*s %*s %*s %*s %*s %s", junk);
  2515.     return(junk[0] != '\0');
  2516. }
  2517. END-OF-FILE
  2518.  
  2519. if [ "$filename" != "/dev/null" ]
  2520. then
  2521.   size=`wc -c < $filename`
  2522.  
  2523.   if [ $size != 2472 ]
  2524.   then
  2525.     echo $filename changed - should be 2472 bytes, not $size bytes
  2526.   fi
  2527.  
  2528.   chmod 666 $filename
  2529. fi
  2530.  
  2531. echo end of this archive file....
  2532. exit 0
  2533.  
  2534.