home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume4 / msg / part6 < prev    next >
Encoding:
Internet Message Format  |  1986-11-30  |  57.6 KB

  1. From: decvax!hplabs!hpcnou!dat (Dave Taylor)
  2. Subject: Msg Shar.part.6
  3. Newsgroups: mod.sources
  4. Approved: jpn@panda.UUCP
  5.  
  6. Mod.sources:  Volume 4, Issue 10
  7. Submitted by: decvax!hplabs!hpcnou!dat (Dave Taylor)
  8.  
  9. # Msg Shar part 6 of 7
  10.  
  11. # Shell Archive created by hpcnou!dat at Wed Feb 26 15:56:49 1986
  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. # This archive contains;
  18. #  src/newmbox.c    src/strings.c       src/syscall.c       src/utils.c
  19. #  src/validname.c  src/Makefile        utils/answer.c      utils/arepdaemon.c
  20. #  utils/autoreply.c
  21.  
  22.  
  23. if [ ! -d src ]
  24. then
  25.   echo creating directory src
  26.   mkdir src
  27. fi
  28.  
  29. # ---------- file src/newmbox.c ----------
  30.  
  31.  
  32. if [ -f src/newmbox.c ]
  33. then
  34.   echo File 'src/newmbox.c' already exists\!
  35.   exit 1
  36. fi
  37.  
  38. echo extracting file src/newmbox.c...
  39. cat << 'END-OF-FILE' > src/newmbox.c
  40. /**            newmbox.c            **/
  41.  
  42. /**  read new mbox file 
  43.  
  44.      (C) Copyright 1986 Dave Taylor
  45. **/
  46.  
  47. #include <ctype.h>
  48.  
  49. #ifdef BSD
  50. #undef tolower
  51. #endif
  52.  
  53. #include "headers.h"
  54.  
  55. #include <sys/types.h>
  56. #include <sys/stat.h>
  57. #ifdef BSD
  58. #  include <sys/time.h>
  59. #else
  60. #  include <time.h>
  61. #endif
  62.  
  63. int
  64. newmbox(stat, resync)
  65. int stat, resync;
  66. {
  67.     /** Read a new mailbox file or resync on current file.
  68.  
  69.         Values of stat and what they mean;
  70.  
  71.         stat = 0    - changing mailboxes from within program
  72.         stat = 1    - read default mailbox for the first time
  73.             stat = 2    - read existing mailbox, new mail arrived
  74.  
  75.         resync is TRUE iff we know the current mailbox has changed.  If
  76.         it's set to true this means that we MUST READ SOMETHING, even 
  77.         if it's the current mailbox again!!
  78.     **/
  79.  
  80.     int  switching_to_default = 0;
  81.     char buff[SLEN];
  82.  
  83.     dprint2("newmbox(stat=%d, resync=%d)\n", stat, resync);
  84.  
  85.     dprint1("\tfile-changed = %s\n\n", onoff(file_changed));
  86.  
  87.     if (stat > 0) {
  88.       if (strlen(infile) == 0)    /* no filename yet?? */
  89.         sprintf(infile,"%s%s",mailhome, username);
  90.     }
  91.     else {              /* get name of new mailbox! */
  92.       MoveCursor(LINES-3, 30);
  93.       CleartoEOS();
  94.       show_last_error();
  95.       if (mbox_specified != 2) {
  96.         PutLine(LINES-2,0,"Name of new mailbox: ");
  97.         buff[0] = '\0';
  98.         (void) optionally_enter(buff, LINES-2, 21, FALSE);
  99.         ClearLine(LINES-2);
  100.         if (strlen(buff) == 0) {
  101.           if (resync && file_changed)
  102.             strcpy(buff, infile);
  103.           else
  104.             return(FALSE);
  105.         }
  106.         if (strcmp(buff, infile) == 0 && ! resync) {
  107.           error("already reading that mailbox!");
  108.           return(FALSE);
  109.         }
  110.         if (first_word(buff, mailhome) && ! resync) {
  111.           mbox_specified = 0;       /* fake program to think that */
  112.           stat = 1;                  /*     we're the default file */
  113.           switching_to_default++;      /*        remember this act!  */
  114.         }
  115.         else if (strcmp(buff, "!") == 0) {    /* go to mailbox */
  116.           sprintf(buff,"%s%s", mailhome, username);
  117.           if (! resync || (resync && ! file_changed)) {
  118.             if (strcmp(buff, infile) == 0) {    /* are we reading it? */
  119.               error("already reading your incoming mailbox!");
  120.           return(FALSE);
  121.             }
  122.           }
  123.           if (! resync || (resync && ! file_changed)) {
  124.             mbox_specified = 0;     /* fake program to think that */
  125.             stat = 1;          /*     we're the default file */
  126.             switching_to_default++;    /*        remember this act!  */
  127.           }
  128.         }
  129.  
  130.         if (! expand_filename(buff)) {
  131.           error1("cannot expand file %s", buff);
  132.           if (resync && file_changed)
  133.             strcpy(buff, infile);
  134.           else
  135.             return(FALSE);    
  136.         }
  137.  
  138.         if (! can_access(buff,"r")) {
  139.           error1("cannot open file %s", buff);
  140.           if (resync && file_changed)
  141.             strcpy(buff, infile);
  142.           else
  143.             return(FALSE);    
  144.         }
  145.  
  146.         if (resync && file_changed && strcmp(buff, infile) == 0)
  147.           PutLine(20,40,"Resynchronizing file");
  148.         else
  149.           PutLine(20,40,"Mailbox: %s", buff);
  150.         CleartoEOLN();
  151.         strcpy(infile,buff);
  152.         if (! switching_to_default) mbox_specified = 1;
  153.       }
  154.       else { /* starting filename given to routine */
  155.         if (! can_access(infile,"r")) 
  156.           exit(PutLine(LINES, 0, "Could not open file %s!\n", infile));
  157.         mbox_specified = 1;
  158.       }
  159.     }
  160.  
  161.     clear_error();
  162.     clear_central_message();
  163.  
  164.     if ((mailfile = fopen(infile,"r")) == NULL) 
  165.       message_count = 0;
  166.     else if (stat < 2) {          /* new mail file! */
  167.       if (notesfile)
  168.         message_count = read_notesfile();    /* can't get new notes! */
  169.       else
  170.         message_count = read_headers(FALSE);
  171.     }
  172.     else     /* resync with current mail file */
  173.       message_count = read_headers(TRUE);
  174.  
  175.     if (message_count && stat < 2) current = 1;
  176.  
  177.     header_page = 0;
  178.  
  179.     return(TRUE);
  180. }
  181.  
  182. int
  183. read_headers(stat)
  184. int stat;
  185. {
  186.     /** Reads the headers into the header_table structure and leaves
  187.         the file rewound for further I/O requests.   If the file being
  188.         read is the default mailbox (ie incoming) then it is copied to
  189.         a temp file and closed, to allow more mail to arrive during 
  190.         the msg session.  If stat is set, the program will then copy
  191.         the delete flag from the previous data structure value to the
  192.         new one if possible.  This is for re-reading the mailfile!
  193.         Added: reads and formats the date from the first 'From' line
  194.     **/
  195.  
  196.     FILE *temp;
  197.     char buffer[LONG_STRING], temp_filename[SLEN];
  198.     register int line = 0, count = 0, subj = 0, copyit = 0, in_header = 1;
  199.     long bytes = 0L, line_bytes = 0L;
  200.     static int first_read = 0; 
  201.     int count_x, count_y = 17;
  202.  
  203.     dprint1("read_headers(stat=%d)\n", stat);
  204.  
  205.     if (! first_read++) {
  206.       MoveCursor(LINES-2, 0);
  207.       CleartoEOS();
  208.       PutLine(LINES-1, 0, "Reading in %s, message: 0", infile);
  209.       count_x = LINES-1;
  210.           count_y = 22 + strlen(infile);
  211.     }
  212.     else {
  213.       PutLine(LINES-2, 0, "Reading message: 0");
  214.       count_x = LINES-2;
  215.     }
  216.  
  217.     if (mbox_specified == 0) {
  218.       lock(INCOMING);    /* ensure no mail arrives while we do this! */
  219.       sprintf(temp_filename,"%s%s",temp_mbox, username);
  220.       if ((temp = fopen(temp_filename,"w")) == NULL) {
  221.         unlock();    /* remove lock file! */
  222.         Raw(OFF);
  223.         printf("Could not open file %s for writing (uid=%d)...\n",
  224.                temp_filename, getuid());
  225.         system_call("/bin/ls -l /tmp/*", SH);
  226.         leave(error1("could not open file %s for writing!",
  227.               temp_filename));
  228.       }
  229.       get_mailtime();
  230.       copyit++;
  231.       chown(temp_filename, userid, getgid());
  232.     }
  233.  
  234.     while (fgets(buffer, LONG_STRING, mailfile) != NULL) {
  235.       if (line == 0) {     /* first line of file... */    
  236.  
  237.         if (! mbox_specified) {
  238.           if (first_word(buffer, "Forward to ")) 
  239.             set_central_message("Mail being forwarded to %s", 
  240.                    (char *) (buffer + 11));
  241.         }
  242.  
  243.         /* Are we reading in a notesfile file without the flag
  244.            turned on??? */
  245.     
  246.         if (first_word(buffer, NOTES_HEADER)) {    /* if so...  */
  247.           rewind(mailfile);
  248.           notesfile++;            /* set da flag, boss-man */
  249.           return(read_notesfile());     /* hop over to notes */
  250.         }
  251.       }
  252.  
  253.       if (copyit) fputs(buffer, temp);
  254.       line_bytes = (long) strlen(buffer); 
  255.       line++;
  256.       if (first_word(buffer,"From ")) {
  257.         if (real_from(buffer, &header_table[count])) {
  258.           header_table[count].offset = (long) bytes;
  259.           if (! stat || count > message_count) 
  260.             header_table[count].delete = 0;        /* clear flag! */
  261.           strcpy(header_table[count].subject, "");    /* clear subj  */
  262.           header_table[count++].lines = line;
  263.           header_table[count].priority = 0;
  264.           subj = 0;
  265.           in_header = 1;
  266.           PutLine(count_x, count_y, "%d", count);
  267.           if (count > 1)
  268.             header_table[count-2].lines = header_table[count-1].lines - 
  269.                           header_table[count-2].lines;
  270.         }
  271.       }
  272.       else if (in_header) {
  273.         if (first_word(buffer,">From")) 
  274.           forwarded(buffer, &header_table[count-1]); /* return address */
  275.         else if (first_word(buffer,"Subject:") ||
  276.              first_word(buffer,"Subj:") ||
  277.              first_word(buffer,"Re:")) {
  278.           if (! subj++) {
  279.             remove_first_word(buffer);
  280.             strncpy(header_table[count-1].subject, buffer, SLEN);
  281.           }
  282.         }
  283.         else if (first_word(buffer,"From:"))
  284.           parse_arpa_from(buffer, header_table[count-1].from);
  285.         else if (first_word(buffer, "Date:")) 
  286.           parse_arpa_date(buffer, &header_table[count-1]);
  287.         else if (first_word(buffer, "Priority:"))
  288.           header_table[count-1].priority++;
  289.         else if (buffer[0] == LINE_FEED || buffer[0] == '\0') {
  290.           if (in_header) {
  291.             in_header = 0;    /* in body of message! */
  292.             fix_date(&header_table[count-1]);
  293.           }
  294.         }
  295.       }
  296.       bytes += (long) line_bytes;
  297.     }
  298.  
  299.     total_lines_in_file = line;
  300.     header_table[count-1].lines = line - header_table[count-1].lines + 1;
  301.  
  302.     if (mbox_specified == 0) {
  303.       unlock();    /* remove lock file! */
  304.       fclose(mailfile);
  305.       fclose(temp);
  306.       if ((mailfile = fopen(temp_filename,"r")) == NULL) {
  307.         MoveCursor(LINES,0);
  308.         Raw(OFF);
  309.         printf("Fatal error: could not reopen %s as temp mail file!\n",
  310.                temp_filename);
  311.         leave();
  312.       }
  313.     }
  314.     else 
  315.           rewind(mailfile);
  316.  
  317.     return(count);
  318. }
  319. END-OF-FILE
  320.  
  321. size=`wc -c < src/newmbox.c`
  322.  
  323. if [ $size != 8124 ]
  324. then
  325.   echo Warning: src/newmbox.c changed - should be 8124 bytes, not $size bytes
  326. fi
  327.  
  328. chmod 644 src/newmbox.c
  329.  
  330. # ---------- file src/strings.c ----------
  331.  
  332.  
  333. if [ -f src/strings.c ]
  334. then
  335.   echo File 'src/strings.c' already exists\!
  336.   exit 1
  337. fi
  338.  
  339. echo extracting file src/strings.c...
  340. cat << 'END-OF-FILE' > src/strings.c
  341. /**            strings.c        **/
  342.  
  343. /** This file contains all the string oriented functions for the
  344.     MSG Mailer, and lots of other generally useful string functions! 
  345.  
  346.     For BSD systems, this file also includes the function "tolower"
  347.     to translate the given character from upper case to lower case.
  348.  
  349.     (C) Copyright 1985, Dave Taylor
  350. **/
  351.  
  352. #include <stdio.h>
  353. #include "headers.h"
  354. #include <ctype.h>
  355.  
  356. #ifdef BSD
  357. #undef tolower
  358. #undef toupper
  359. #endif
  360.  
  361. /** forward declarations **/
  362.  
  363. char *format_long(), *strip_commas(), *tail_of_string(), *shift_lower(),
  364.      *get_token(), *strip_parens(), *argv_zero();
  365.  
  366. #ifdef BSD
  367.  
  368. int
  369. tolower(ch)
  370. char ch;
  371. {
  372.     /** This should be a macro call, but if you use this as a macro
  373.         calls to 'tolower' where the argument is a function call will
  374.         cause the function to be called TWICE which is obviously the
  375.         wrong behaviour.  On the other hand, to just blindly translate
  376.         assuming the character is always uppercase can cause BIG
  377.         problems, so...
  378.     **/
  379.  
  380.     return ( isupper(ch) ? ch - 'A' + 'a' : ch );
  381. }
  382.  
  383. int
  384. toupper(ch)
  385. char ch;
  386. {
  387.     /** see comment for above routine - tolower() **/
  388.  
  389.     return ( islower(ch) ? ch - 'a' + 'A' : ch );
  390. }
  391.  
  392. #endif
  393.  
  394. int 
  395. in_string(buffer, pattern)
  396. char *buffer, *pattern;
  397. {
  398.     /** Returns TRUE iff pattern occurs IN IT'S ENTIRETY in buffer. **/ 
  399.  
  400.     register int i = 0, j = 0;
  401.     
  402.     while (buffer[i] != '\0') {
  403.       while (buffer[i++] == pattern[j++]) 
  404.         if (pattern[j] == '\0') 
  405.           return(TRUE);
  406.       i = i - j + 1;
  407.       j = 0;
  408.     }
  409.     return(FALSE);
  410. }
  411.  
  412. tail_of(from, buffer, header_line)
  413. char *from, *buffer;
  414. int   header_line;
  415. {
  416.     /** Return last two words of 'from'.  This is to allow
  417.         painless display of long return addresses as simply the
  418.         machine!username.  Alternatively, if the first three
  419.         characters of the 'from' address are 'To:' and 'header_line'
  420.         is TRUE, then return the buffer value prepended with 'To '. 
  421.     **/
  422.  
  423.     /** Note: '!' delimits Usenet nodes, '@' delimits ARPA nodes,
  424.               ':' delimits CSNet & Bitnet nodes, and '%' delimits
  425.           multiple stage ARPA hops... **/
  426.  
  427.     register int loc, i = 0, cnt = 0;
  428.     char     tempbuffer[SLEN];
  429.     
  430.  
  431.     for (loc = strlen(from)-1; loc >= 0 && cnt < 2; loc--) {
  432.       if (from[loc] == '!' || from[loc] == '@' ||
  433.           from[loc] == ':') cnt++;
  434.       if (cnt < 2) buffer[i++] = from[loc];
  435.     }
  436.  
  437.     buffer[i] = '\0';
  438.  
  439.     reverse(buffer);
  440.  
  441.     if ((strncmp(buffer,"To:", 3) == 0) && header_line)
  442.       buffer[2] = ' ';
  443.     else if ((strncmp(from, "To:", 3) == 0) && header_line) {
  444.       sprintf(tempbuffer,"To %s", buffer); 
  445.       strcpy(buffer, tempbuffer);
  446.     }
  447.     else if (strncmp(buffer, "To:", 3) == 0) {
  448.       for (i=3; i < strlen(buffer); i++)
  449.         tempbuffer[i-3] = buffer[i];
  450.       tempbuffer[i-3] = '\0';
  451.       strcpy(buffer, tempbuffer);
  452.     }
  453. }
  454.  
  455. char *format_long(inbuff, init_len)
  456. char *inbuff;
  457. int   init_len;
  458. {
  459.     /** Return buffer with \n\t sequences added at each point
  460.         where it would be more than 80 chars long.  It only 
  461.         allows the breaks at legal points (ie white spaces).
  462.         init-len is the characters already on the first line...
  463.         Changed so that if this is called while mailing without
  464.         the overhead of "msg", it'll include "\r\n\t" instead.
  465.     **/
  466.  
  467.     static char ret_buffer[VERY_LONG_STRING];
  468.     register int index = 0, current_length = 0, depth=15, i;
  469.     char     buffer[VERY_LONG_STRING];
  470.     char     *word, *bufptr;
  471.  
  472.     strcpy(buffer, inbuff);
  473.  
  474.     bufptr = (char *) buffer;
  475.  
  476.     current_length = init_len + 2;    /* for luck */
  477.  
  478.     while ((word = get_token(bufptr," ", depth)) != NULL) {
  479.       if (strlen(word) + current_length > 80) {
  480.         if (index > 0) {
  481.           if (mail_only)
  482.             ret_buffer[index++] = '\r';
  483.           ret_buffer[index++] = '\n';
  484.           ret_buffer[index++] = '\t';
  485.         }
  486.         for (i=0; i<strlen(word); i++)
  487.           ret_buffer[index++] = word[i];
  488.         current_length = strlen(word) + 8;    /* 8 = TAB */
  489.       }
  490.       else {
  491.         if (index > 0)
  492.           ret_buffer[index++] = ' ';
  493.         for (i=0; i<strlen(word); i++)
  494.           ret_buffer[index++] = word[i];
  495.         current_length += strlen(word) + 1;
  496.       }
  497.     
  498.       bufptr = NULL;
  499.     }
  500.     
  501.     ret_buffer[index] = '\0';
  502.  
  503.     return( (char *) ret_buffer);
  504. }
  505.  
  506. char *strip_commas(string)
  507. char *string;
  508. {
  509.     /** return string with all commas changed to spaces.  This IS
  510.         destructive and will permanently change the input string.. **/
  511.  
  512.     register int i;
  513.  
  514.     for (i=0; i < strlen(string); i++)
  515.       if (string[i] == COMMA)
  516.         string[i] = SPACE;
  517.  
  518.     return( (char *) string);
  519. }
  520.  
  521. char *strip_parens(string)
  522. char *string;
  523. {
  524.     /** Return string with all parenthesized information removed.
  525.         This is a non-destructive algorithm... **/
  526.  
  527.     static char  buffer[VERY_LONG_STRING];
  528.     register int i, depth = 0, buffer_index = 0;
  529.  
  530.     for (i=0; i < strlen(string); i++) {
  531.       if (string[i] == '(')
  532.         depth++;
  533.       else if (string[i] == ')') 
  534.         depth--;
  535.       else if (depth == 0)
  536.         buffer[buffer_index++] = string[i];
  537.     }
  538.     
  539.     buffer[buffer_index] = '\0';
  540.  
  541.     return( (char *) buffer);
  542. }
  543.  
  544. move_left(string, chars)
  545. char string[];
  546. int  chars;
  547. {
  548.     /** moves string chars characters to the left DESTRUCTIVELY **/
  549.  
  550.     register int i;
  551.  
  552.     chars--; /* index starting at zero! */
  553.  
  554.     for (i=chars; string[i] != '\0' && string[i] != '\n'; i++)
  555.       string[i-chars] = string[i];
  556.  
  557.     string[i-chars] = '\0';
  558. }
  559.  
  560. remove_first_word(string)
  561. char *string;
  562. {    /** removes first word of string, ie up to first non-white space
  563.         following a white space! **/
  564.  
  565.     register int loc;
  566.  
  567.     for (loc = 0; string[loc] != ' ' && string[loc] != '\0'; loc++) 
  568.         ;
  569.  
  570.     while (string[loc] == ' ' || string[loc] == '\t')
  571.       loc++;
  572.     
  573.     move_left(string, ++loc);
  574. }
  575.  
  576. char *tail_of_string(string, maxchars)
  577. char *string;
  578. int  maxchars;
  579. {
  580.     /** Return a string that is the last 'maxchars' characters of the
  581.         given string.  This is only used if the first word of the string
  582.         is longer than maxchars, else it will return what is given to
  583.         it... 
  584.     **/
  585.  
  586.     static char buffer[SLEN];
  587.     register int index, i;
  588.  
  589.     for (index=0;! whitespace(string[index]) && index < strlen(string); 
  590.          index++)
  591.       ;
  592.  
  593.     if (index < maxchars) {
  594.       strncpy(buffer, string, maxchars-2);    /* word too short */
  595.       buffer[maxchars-2] = '.';
  596.       buffer[maxchars-1] = '.';
  597.       buffer[maxchars]   = '.';
  598.       buffer[maxchars+1] = '\0';
  599.     } 
  600.     else {
  601.       i = maxchars;
  602.       buffer[i--] = '\0';
  603.       while (i > 1) 
  604.         buffer[i--] = string[index--];
  605.       buffer[2] = '.';
  606.       buffer[1] = '.';
  607.       buffer[0] = '.';
  608.     }
  609.  
  610.     return( (char *) buffer);
  611. }
  612.  
  613. reverse(string)
  614. char *string;
  615. {
  616.     /** reverse string... pretty trivial routine, actually! **/
  617.  
  618.     char buffer[SLEN];
  619.     register int i, j = 0;
  620.  
  621.     for (i = strlen(string)-1; i >= 0; i--)
  622.       buffer[j++] = string[i];
  623.  
  624.     buffer[j] = '\0';
  625.  
  626.     strcpy(string, buffer);
  627. }
  628.  
  629. int
  630. get_word(buffer, start, word)
  631. char *buffer, *word;
  632. int start;
  633. {
  634.     /**    return next word in buffer, starting at 'start'.
  635.         delimiter is space or end-of-line.  Returns the
  636.         location of the next word, or -1 if returning
  637.         the last word in the buffer.  -2 indicates empty
  638.         buffer!  **/
  639.  
  640.     register int loc = 0;
  641.  
  642.     while (buffer[start] == ' ' && buffer[start] != '\0')
  643.       start++;
  644.  
  645.     if (buffer[start] == '\0') return(-2);     /* nothing IN buffer! */
  646.  
  647.     while (buffer[start] != ' ' && buffer[start] != '\0')
  648.       word[loc++] = buffer[start++];
  649.  
  650.     word[loc] = '\0';
  651.     return(start);
  652. }
  653.  
  654. int
  655. chloc(string, ch)
  656. char *string, ch;
  657. {
  658.     /** returns the index of ch in string, or -1 if not in string **/
  659.     register int i;
  660.  
  661.     for (i=0; i<strlen(string); i++)
  662.       if (string[i] == ch) return(i);
  663.     return(-1);
  664. }
  665.  
  666. int
  667. two_words(string)
  668. char *string;
  669. {
  670.     /** is 'string' exactly two words?  Return TRUE or FALSE **/
  671.  
  672.     return( words_in_string(string) == 2 );
  673.  
  674. }
  675.  
  676. char *shift_lower(string)
  677. char *string;
  678. {
  679.     /** return 'string' shifted to lower case.  Do NOT touch the
  680.         actual string handed to us! **/
  681.  
  682.     static char buffer[LONG_SLEN];
  683.     register int i;
  684.  
  685.     for (i=0; i < strlen(string); i++)
  686.       if (isupper(string[i]))
  687.         buffer[i] = tolower(string[i]);
  688.       else
  689.         buffer[i] = string[i];
  690.     
  691.     buffer[strlen(string)] = 0;
  692.     
  693.     return( (char *) buffer);
  694. }
  695.  
  696. int
  697. words_in_string(buffer)
  698. char *buffer;
  699. {
  700.     /** This routine returns the number of words in the given line.
  701.         A word is defined as a series of characters surrounded by
  702.         either the beginning of the string, the end of the string,
  703.         or white space.
  704.         For example, the following line has 8 words:
  705.         "This is a test of the program, okay?"
  706.     **/
  707.  
  708.     register int count = 0, i = 0;
  709.     
  710.     while (buffer[i] != '\0') {
  711.       
  712.       while (whitespace(buffer[i])) i++;
  713.     
  714.       if (buffer[i] != '\0')
  715.           count++;
  716.  
  717.       while (! whitespace(buffer[i]) && buffer[i] != '\0') i++;
  718.     }
  719.     return(count);
  720. }
  721.  
  722. clean_up(buffer)
  723. char *buffer;
  724. {
  725.     /** This routine takes a string of the form "a:b" and returns it 
  726.             as just "b"... **/
  727.  
  728.     char mybuffer[SLEN];
  729.     register int loc, myloc = 0;
  730.  
  731.     for (loc=0; buffer[loc] != ':'; loc++)
  732.        ;
  733.  
  734.     while (buffer[++loc] != '\0')
  735.       mybuffer[myloc++] = buffer[loc];
  736.  
  737.     mybuffer[myloc] = '\0';
  738.  
  739.     strcpy(buffer, mybuffer);
  740. }
  741.  
  742. Centerline(line, string)
  743. int line;
  744. char *string;
  745. {
  746.     /** Output 'string' on the given line, centered. **/
  747.  
  748.     register int length, col;
  749.  
  750.     length = strlen(string);
  751.  
  752.     if (length > COLUMNS)
  753.       col = 0;
  754.     else
  755.       col = (COLUMNS - length) / 2;
  756.  
  757.     PutLine(line, col, string);
  758. }
  759.  
  760. char *argv_zero(string)
  761. char *string;
  762. {
  763.     /** given a string of the form "/something/name" return a
  764.         string of the form "name"... **/
  765.  
  766.     static char buffer[NLEN];
  767.     register int i, j=0;
  768.  
  769.     for (i=strlen(string)-1; string[i] != '/'; i--)
  770.       buffer[j++] = string[i];
  771.     buffer[j] = '\0';
  772.  
  773.     reverse(buffer);
  774.  
  775.     return( (char *) buffer);
  776. }
  777.  
  778. #define MAX_RECURSION        20        /* up to 20 deep recursion */
  779.  
  780. char *get_token(source, keys, depth)
  781. char *source, *keys;
  782. int   depth;
  783. {
  784.     /** This function is similar to strtok() (see "opt_utils")
  785.         but allows nesting of calls via pointers... 
  786.     **/
  787.  
  788.     register int  last_ch;
  789.     static   char *buffers[MAX_RECURSION];
  790.     char     *return_value, *sourceptr;
  791.  
  792.     if (depth > MAX_RECURSION) {
  793.        error1("get_token calls nested greater than %d deep!", 
  794.           MAX_RECURSION);
  795.        emergency_exit();
  796.     }
  797.  
  798.     if (source != NULL)
  799.       buffers[depth] = source;
  800.     
  801.     sourceptr = buffers[depth];
  802.     
  803.     if (*sourceptr == '\0') 
  804.       return(NULL);        /* we hit end-of-string last time!? */
  805.  
  806.     sourceptr += strspn(sourceptr, keys);      /* skip the bad.. */
  807.     
  808.     if (*sourceptr == '\0') {
  809.       buffers[depth] = sourceptr;
  810.       return(NULL);            /* we've hit end-of-string   */
  811.     }
  812.  
  813.     last_ch = strcspn(sourceptr, keys);   /* end of good stuff   */
  814.  
  815.     return_value = sourceptr;          /* and get the ret     */
  816.  
  817.     sourceptr += last_ch;              /* ...value            */
  818.  
  819.     if (*sourceptr != '\0')        /** don't forget if we're at end! **/
  820.       sourceptr++;                  
  821.     
  822.     return_value[last_ch] = '\0';          /* ..ending right      */
  823.  
  824.     buffers[depth] = sourceptr;          /* save this, mate!    */
  825.  
  826.     return((char *) return_value);         /* and we're outta here! */
  827. }
  828. END-OF-FILE
  829.  
  830. size=`wc -c < src/strings.c`
  831.  
  832. if [ $size != 10790 ]
  833. then
  834.   echo Warning: src/strings.c changed - should be 10790 bytes, not $size bytes
  835. fi
  836.  
  837. chmod 644 src/strings.c
  838.  
  839. # ---------- file src/syscall.c ----------
  840.  
  841.  
  842. if [ -f src/syscall.c ]
  843. then
  844.   echo File 'src/syscall.c' already exists\!
  845.   exit 1
  846. fi
  847.  
  848. echo extracting file src/syscall.c...
  849. cat << 'END-OF-FILE' > src/syscall.c
  850. /**            syscall.c        **/
  851.  
  852. /** These routines are used for user-level system calls, including the
  853.     '!' command and the '|' commands...
  854.  
  855.     (C) Copyright 1986 Dave Taylor
  856. **/
  857.  
  858. #include "headers.h"
  859.  
  860. #include <signal.h>
  861.  
  862. char *argv_zero();    
  863.  
  864. int
  865. subshell()
  866. {
  867.     /** spawn a subshell with either the specified command
  868.         returns non-zero if screen rewrite needed
  869.     **/
  870.  
  871.     char command[SLEN];
  872.     int  ret;
  873.  
  874.     PutLine(LINES-3,COLUMNS-40,"(use 'sh' or 'csh' for a shell)");
  875.     PutLine(LINES-2,0,"Shell Command: ");
  876.     command[0] = '\0';
  877.     (void) optionally_enter(command, LINES-2, 15, FALSE);
  878.     if (strlen(command) == 0) {
  879.       MoveCursor(LINES-2,0);    CleartoEOLN();
  880.       return(0);
  881.     }
  882.  
  883.     MoveCursor(LINES,0);     CleartoEOLN();
  884.     Raw(OFF);
  885.     if (cursor_control)  transmit_functions(OFF);
  886.     
  887.     ret = system_call(command, USER_SHELL);
  888.  
  889.     printf("\nPress <return> to return to MSG: ");
  890.     Raw(ON);
  891.     (void) getchar();
  892.     if (cursor_control)  transmit_functions(ON);
  893.  
  894.     if (ret != 0) error1("Return code was %d", ret);
  895.     return(1);
  896. }
  897.  
  898. system_call(string, shell_type)
  899. char *string;
  900. int   shell_type;
  901. {
  902.     /** execute 'string', setting uid to userid... **/
  903.     /** if shell-type is "SH" /bin/sh is used regardless of the 
  904.         users shell setting.  Otherwise, "USER_SHELL" is sent **/
  905.  
  906.     int status, pid, w;
  907.     register int (*istat)(), (*qstat)();
  908.     
  909.     dprint2("system_call('%s', %s)\n", string, 
  910.              shell_type == SH? "SH" : "USER-SHELL");
  911.  
  912.     if ((pid = fork()) == 0) {
  913.       setuid(userid);    /* back to the normal user! */
  914.       if (strlen(shell) > 0 && shell_type == USER_SHELL) {
  915.         execl(shell, argv_zero(shell), "-c", string, 0);
  916.       }
  917.       else 
  918.         execl("/bin/sh", "sh", "-c", string, 0);
  919.       _exit(127);
  920.     }
  921.  
  922.     istat = signal(SIGINT, SIG_IGN);
  923.     qstat = signal(SIGQUIT, SIG_IGN);
  924.  
  925.     while ((w = wait(&status)) != pid && w != -1)
  926.         ;
  927.  
  928.     if (w == -1) status = -1;
  929.     
  930.     signal(SIGINT, istat);
  931.     signal(SIGQUIT, qstat);
  932.  
  933.     return(status);
  934. }
  935.  
  936. int
  937. pipe()
  938. {
  939.     /** pipe the current message to the specified sequence.. **/
  940.  
  941.     char command[SLEN], buffer[LONG_SLEN];
  942.     int  ret, lines;
  943.  
  944.     PutLine(LINES-2,0,"Pipe current msg to: ");
  945.     command[0] = '\0';
  946.     (void) optionally_enter(command, LINES-2, 21, FALSE);
  947.     if (strlen(command) == 0) {
  948.       MoveCursor(LINES-2,0);    CleartoEOLN();
  949.       return(0);
  950.     }
  951.  
  952.     MoveCursor(LINES,0);     CleartoEOLN();
  953.     Raw(OFF);
  954.  
  955.     lines = header_table[current-1].lines;
  956.  
  957.     if (cursor_control)  transmit_functions(OFF);
  958.     
  959.     sprintf(buffer, "%s %s %d %d - | %s", cutfile, 
  960.         infile, header_table[current-1].offset,
  961.         lines, command);
  962.  
  963.     ret = system_call(buffer, USER_SHELL);
  964.  
  965.     printf("\nPress <return> to return to MSG: ");
  966.     Raw(ON);
  967.     (void) getchar();
  968.     if (cursor_control)  transmit_functions(ON);
  969.  
  970.     if (ret != 0) error1("Return code was %d", ret);
  971.     return(1);
  972. }
  973.  
  974. printmsg()
  975. {
  976.     /** print specified message using 'printout' variable.  
  977.         Error message iff printout not defined! **/
  978.  
  979.     FILE *temp;
  980.     char buffer[LONG_SLEN], filename[SLEN], printbuffer[LONG_SLEN];
  981.     int  retcode;
  982.  
  983.     dprint1("printmsg()\n\tprintout = %s\n", printout);
  984.     dprint1("\tcurrent message = %d\n", current);
  985.  
  986.     if (strlen(printout) == 0) {
  987.       error("PRINTMAIL not defined!  Don't know how to print message");
  988.       return;
  989.     }
  990.     
  991.     if (current == 0) {
  992.       error("No mail to print!");
  993.       return;
  994.     }
  995.  
  996.     sprintf(filename,"%s%d", temp_print, getpid());
  997.  
  998.     if ((temp = fopen(filename,"w")) == NULL) {
  999.       error1("Could not open file %s as a temporary file", filename);
  1000.       return;
  1001.     }
  1002.  
  1003.     copy_message("", temp, FALSE);
  1004.  
  1005.     fclose(temp);
  1006.  
  1007.     if (in_string(printout, "%s"))
  1008.       sprintf(printbuffer, printout, filename);
  1009.     else
  1010.       sprintf(printbuffer, "%s %s", printout, filename);
  1011.  
  1012.         sprintf(buffer,"(%s 2>&1 ) > /dev/null",
  1013.         printbuffer, filename);
  1014.  
  1015.       error("working...");
  1016.  
  1017.     if ((retcode = system_call(buffer, SH)) == 0)
  1018.       error("Message queued up to print");
  1019.     else
  1020.       error1("Printout failed with return code %d", retcode);
  1021.  
  1022.     unlink(filename);    /* remove da temp file! */
  1023. }
  1024. END-OF-FILE
  1025.  
  1026. size=`wc -c < src/syscall.c`
  1027.  
  1028. if [ $size != 3869 ]
  1029. then
  1030.   echo Warning: src/syscall.c changed - should be 3869 bytes, not $size bytes
  1031. fi
  1032.  
  1033. chmod 644 src/syscall.c
  1034.  
  1035. # ---------- file src/utils.c ----------
  1036.  
  1037.  
  1038. if [ -f src/utils.c ]
  1039. then
  1040.   echo File 'src/utils.c' already exists\!
  1041.   exit 1
  1042. fi
  1043.  
  1044. echo extracting file src/utils.c...
  1045. cat << 'END-OF-FILE' > src/utils.c
  1046. /**        utils.c        **/
  1047.  
  1048. /** Utility routines for MSG 
  1049.  
  1050.     All routines herein: (C) Copyright 1985 Dave Taylor
  1051. **/
  1052.  
  1053. #include "headers.h"
  1054. #include <sys/types.h>
  1055. #include <sys/stat.h>
  1056. #include <ctype.h>
  1057.  
  1058. #ifdef BSD
  1059. #undef tolower
  1060. #endif
  1061.  
  1062. #include <signal.h>
  1063. #include <errno.h>
  1064.  
  1065. emergency_exit()
  1066. {
  1067.     /** used in dramatic cases when we must leave without altering
  1068.         ANYTHING about the system... **/
  1069.  
  1070.     Raw(OFF);
  1071.     if (cursor_control)  transmit_functions(OFF);
  1072.     if (hp_terminal)     softkeys_off();
  1073.  
  1074.     if (cursor_control)
  1075.       MoveCursor(LINES, 0);
  1076.  
  1077.     printf("\n\rEmergency Exit taken!  All temp files intact!\n\r\n\r");
  1078.  
  1079.     exit(1);
  1080. }
  1081.  
  1082. leave(val)
  1083. int val;    /* not used, placeholder for signal catching! */
  1084. {
  1085.     char buffer[SLEN];
  1086.  
  1087.     dprint1("leave(%d)\n", val);
  1088.  
  1089.     Raw(OFF);
  1090.     if (cursor_control)  transmit_functions(OFF);
  1091.     if (hp_terminal)     softkeys_off();
  1092.  
  1093.     sprintf(buffer,"%s%d",temp_file, getpid());  /* editor buffer */
  1094.     (void) unlink(buffer);
  1095.  
  1096.     if (! mail_only) {
  1097.       sprintf(buffer,"%s%d",temp_file, getpid()+1);  /* editor buffer */
  1098.       (void) unlink(buffer);
  1099.     }
  1100.  
  1101.     sprintf(buffer,"%s%s",temp_mbox, username);  /* temp mailbox */
  1102.     (void) unlink(buffer);
  1103.  
  1104.     sprintf(buffer,"%s%s.lock",mailhome, username); /* lock file */
  1105.     (void) unlink(buffer);
  1106.  
  1107.     if (! mail_only)
  1108.       MoveCursor(LINES-1,0);
  1109.     putchar('\n');
  1110.  
  1111.     exit(0);
  1112. }
  1113.  
  1114. leave_locked(val)
  1115. int val;    /* not used, placeholder for signal catching! */
  1116. {
  1117.     /** same as leave routine, but don't disturb lock file **/
  1118.  
  1119.     char buffer[SLEN];
  1120.  
  1121.     dprint1("leave_locked(%d)\n", val);
  1122.  
  1123.     Raw(OFF);
  1124.     if (cursor_control)  transmit_functions(OFF);
  1125.     if (hp_terminal)     softkeys_off();
  1126.  
  1127.     sprintf(buffer,"%s%d",temp_file, getpid());  /* editor buffer */
  1128.     (void) unlink(buffer);
  1129.  
  1130.     sprintf(buffer,"%s%d",temp_file, getpid()+1);  /* editor buffer */
  1131.     (void) unlink(buffer);
  1132.  
  1133.     sprintf(buffer,"%s%s",temp_mbox, username);  /* temp mailbox */
  1134.     (void) unlink(buffer);
  1135.  
  1136.     MoveCursor(LINES-1,0);
  1137.     putchar('\n');
  1138.  
  1139.     exit(0);
  1140. }
  1141.  
  1142. int
  1143. get_page(current)
  1144. int current;
  1145. {
  1146.     /** ensure that 'current' is on the displayed page,
  1147.         returning non-zero iff the page changed! **/
  1148.  
  1149.     register int first_on_page, last_on_page;
  1150.  
  1151.     first_on_page = (header_page * headers_per_page) + 1;
  1152.  
  1153.     last_on_page = first_on_page + headers_per_page - 1;
  1154.  
  1155.     if (current > last_on_page) {
  1156.       header_page = (int) (current-1) / headers_per_page;
  1157.       return(1);
  1158.     }
  1159.     else if (current < first_on_page) {
  1160.       header_page = (int) (current-1) / headers_per_page;
  1161.       return(1);
  1162.     }
  1163.     else
  1164.       return(0);
  1165. }
  1166.  
  1167. int
  1168. copy_to_self(buffer)
  1169. char *buffer;
  1170. {
  1171.     /** returns true iff buffer = 'Cc: username' where username
  1172.         is the account name of the person sending the message.
  1173.         Used for weeding out 'Cc:' lines from the messages if
  1174.         'weed' is turned on. **/
  1175.  
  1176.     /** note: tail_of() is located in file "strings.c"  **/
  1177.  
  1178.     char name[SLEN], buf[SLEN];
  1179.     register int i=0, j=0;
  1180.     
  1181.     dprint1("copy_to_self(%s)\n", buffer);
  1182.     
  1183.     tail_of(header_table[current-1].from, name, FALSE);
  1184.  
  1185.     while (name[i] != '!' && i < strlen(name))
  1186.        i++;
  1187.  
  1188.     if (name[i] == '!') {
  1189.       for (i++; i < strlen(name); i++)
  1190.         name[j++] = name[i];
  1191.  
  1192.       name[j] = 0;
  1193.     }
  1194.  
  1195.     sprintf(buf, "Cc: %s\n", name);
  1196.  
  1197.     return( strcmp(buf, buffer) == 0 );
  1198. }
  1199. END-OF-FILE
  1200.  
  1201. size=`wc -c < src/utils.c`
  1202.  
  1203. if [ $size != 3154 ]
  1204. then
  1205.   echo Warning: src/utils.c changed - should be 3154 bytes, not $size bytes
  1206. fi
  1207.  
  1208. chmod 644 src/utils.c
  1209.  
  1210. # ---------- file src/validname.c ----------
  1211.  
  1212.  
  1213. if [ -f src/validname.c ]
  1214. then
  1215.   echo File 'src/validname.c' already exists\!
  1216.   exit 1
  1217. fi
  1218.  
  1219. echo extracting file src/validname.c...
  1220. cat << 'END-OF-FILE' > src/validname.c
  1221. /**            validname.c            **/
  1222.  
  1223. /** This routine takes a single address, no machine hops or
  1224.     anything, and returns 1 if it's valid and 0 if not.  The
  1225.     algorithm it uses is the same one that uux uses, namely:
  1226.  
  1227.     1. Is there a file '/usr/mail/%s'?  
  1228.     2. Is there a password entry for %s?
  1229.     
  1230.    (C) Copyright 1986 Dave Taylor 
  1231. **/
  1232.  
  1233. #include <stdio.h>
  1234.  
  1235. #include "defs.h"
  1236.  
  1237. int
  1238. valid_name(name)
  1239. char *name;
  1240. {
  1241.     /** does what it says above, boss! **/
  1242.  
  1243.     char filebuf[SLEN];
  1244.  
  1245. #ifdef NOCHECK_VALIDNAME
  1246.  
  1247.     return(1);        /* always say it's okay! */
  1248.  
  1249. #else
  1250.  
  1251.     sprintf(filebuf,"%s/%s", mailhome, name);
  1252.     
  1253.     if (access(filebuf, ACCESS_EXISTS) == 0)
  1254.       return(1);
  1255.  
  1256.     if (getpwnam(name) != NULL)
  1257.       return(1);
  1258.  
  1259.     return(0);
  1260.  
  1261. #endif
  1262.  
  1263. }
  1264. END-OF-FILE
  1265.  
  1266. size=`wc -c < src/validname.c`
  1267.  
  1268. if [ $size != 707 ]
  1269. then
  1270.   echo Warning: src/validname.c changed - should be 707 bytes, not $size bytes
  1271. fi
  1272.  
  1273. chmod 644 src/validname.c
  1274.  
  1275. # ---------- file src/Makefile ----------
  1276.  
  1277.  
  1278. if [ -f src/Makefile ]
  1279. then
  1280.   echo File 'src/Makefile' already exists\!
  1281.   exit 1
  1282. fi
  1283.  
  1284. echo extracting file src/Makefile...
  1285. cat << 'END-OF-FILE' > src/Makefile
  1286. #
  1287. #  Makefile for the MSG mail program.
  1288. #
  1289. #         (C) Copyright 1986, Dave Taylor
  1290. #
  1291. #  Last modification: January 23rd, 1986
  1292.  
  1293. CFILES=    addr_utils.c alias.c aliasdb.c aliaslib.c args.c curses.c date.c   \
  1294.     delete.c encode.c file.c file_utils.c fileio.c hdrconfg.c help.c   \
  1295.     initialize.c input_utils.c mailout.c mailtime.c mkhdrs.c msg.c     \
  1296.     newmbox.c notesfile.c output_utils.c pattern.c quit.c savecopy.c   \
  1297.     read_rc.c reply.c return_addr.c screen.c showmsg.c strings.c       \
  1298.     syscall.c utils.c validname.c softkeys.c opt_utils.c leavembox.c
  1299.  
  1300. HEADERS=../hdrs/curses.h ../hdrs/defs.h ../hdrs/headers.h ../hdrs/msg.h
  1301.  
  1302. OBJS=    addr_utils.o alias.o aliasdb.o aliaslib.o args.o curses.o date.o   \
  1303.     delete.o encode.o file.o file_utils.o fileio.o hdrconfg.o help.o   \
  1304.     initialize.o input_utils.o mailout.o mailtime.o mkhdrs.o msg.o     \
  1305.     newmbox.o notesfile.o output_utils.o pattern.o quit.o savecopy.o   \
  1306.     read_rc.o reply.o return_addr.o screen.o showmsg.o strings.o       \
  1307.     syscall.o utils.o validname.o softkeys.o opt_utils.o leavembox.o
  1308.  
  1309. # if on BSD use
  1310. # DEFINE=-DBSD
  1311. # else if on UTS use
  1312. # DEFINE=-DUTS
  1313. # else
  1314. DEFINE=
  1315.  
  1316. BIN=    ../bin
  1317. LIBS=   -ltermcap
  1318. CFLAGS= -O -I../hdrs
  1319. CC=    /bin/cc
  1320. RM=    /bin/rm -f
  1321.  
  1322. .c.o:   ${HEADERS}
  1323.     ${CC} -c ${CFLAGS} ${DEFINE} $*.c 
  1324.  
  1325. ../bin/msg: ${OBJS} ${EXTRA} ${HEADERS} ../hdrs/msg.h
  1326.     ${CC} -o ${BIN}/msg -n ${OBJS} ${LIBS}
  1327.  
  1328. curses.o: curses.c ../hdrs/curses.h
  1329.     ${CC} -c -O -DRAWMODE ${DEFINE} -I../hdrs curses.c
  1330.  
  1331. clean:
  1332.     ${RM} ${OBJS} LINT.OUT
  1333.  
  1334. lint: LINT.OUT
  1335.  
  1336. LINT.OUT: ${CFILES}
  1337.     lint -p -I../hdrs ${CFILES} > LINT.OUT
  1338.  
  1339. listing:
  1340.     @../bin/makelisting Makefile ${HEADERS} ${CFILES}
  1341.     @echo LISTING generated.
  1342. END-OF-FILE
  1343.  
  1344. size=`wc -c < src/Makefile`
  1345.  
  1346. if [ $size != 1647 ]
  1347. then
  1348.   echo Warning: src/Makefile changed - should be 1647 bytes, not $size bytes
  1349. fi
  1350.  
  1351. chmod 644 src/Makefile
  1352.  
  1353. if [ ! -d utils ]
  1354. then
  1355.   echo creating directory utils
  1356.   mkdir utils
  1357. fi
  1358.  
  1359. # ---------- file utils/answer.c ----------
  1360.  
  1361.  
  1362. if [ -f utils/answer.c ]
  1363. then
  1364.   echo File 'utils/answer.c' already exists\!
  1365.   exit 1
  1366. fi
  1367.  
  1368. echo extracting file utils/answer.c...
  1369. cat << 'END-OF-FILE' > utils/answer.c
  1370. /**            answer.c            **/
  1371.  
  1372. /** This program is a phone message transcription system, and
  1373.     is designed for secretaries and the like, to allow them to
  1374.     painlessly generate electronic mail instead of paper forms.
  1375.  
  1376.     Note: this program ONLY uses the local alias file, and does not
  1377.       even read in the system alias file at all.
  1378.  
  1379.     (C) Copyright 1986, Dave Taylor
  1380.  
  1381. **/
  1382.  
  1383. #include <stdio.h>
  1384. #include <fcntl.h>
  1385. #include <ctype.h>
  1386.  
  1387. #include "defs.h"    /* MSG system definitions  */
  1388.  
  1389. struct alias_rec user_hash_table  [MAX_UALIASES];
  1390.  
  1391. int user_data;        /* fileno of user data file   */
  1392.  
  1393. char *expand_group(), *get_alias_address(), *get_token();
  1394.  
  1395. main()
  1396. {
  1397.     FILE *fd;
  1398.     char *address, buffer[LONG_STRING], tempfile[SLEN];
  1399.     char  name[SLEN], user_name[SLEN];
  1400.     int   msgnum = 0, eof;
  1401.     
  1402.     read_alias_files();
  1403.  
  1404.     while (1) {
  1405.       if (msgnum > 9999) msgnum = 0;
  1406.     
  1407.       printf("\n-------------------------------------------------------------------------------\n");
  1408.  
  1409. prompt:   printf("\nMessage to: ");
  1410.       gets(user_name, SLEN);
  1411.       
  1412.       if ((strcmp(user_name,"quit") == 0) ||
  1413.           (strcmp(user_name,"exit") == 0) ||
  1414.           (strcmp(user_name,"done") == 0) ||
  1415.           (strcmp(user_name,"bye")  == 0))
  1416.          exit(0);
  1417.  
  1418.       if (translate(user_name, name) == 0)
  1419.         goto prompt;
  1420.  
  1421.       address = get_alias_address(name, 1, 0);
  1422.  
  1423.       if (strlen(address) == 0) {
  1424.         printf("Sorry, could not find '%s' [%s] in list!\n", user_name, 
  1425.            name);
  1426.         goto prompt;
  1427.       }
  1428.  
  1429.       sprintf(tempfile, "%s%d", temp_file, msgnum++);
  1430.  
  1431.       if ((fd = fopen(tempfile,"w")) == NULL)
  1432.         exit(printf("** Fatal Error: could not open %s to write\n",
  1433.          tempfile));
  1434.  
  1435.  
  1436.       printf("\nEnter message for %s ending with a blank line.\n\n", 
  1437.          user_name);
  1438.  
  1439.       fprintf(fd,"\n\n");
  1440.  
  1441.       do {
  1442.        printf("> ");
  1443.        if (! (eof = (gets(buffer, SLEN) == NULL))) 
  1444.          fprintf(fd, "%s\n", buffer);
  1445.       } while (! eof && strlen(buffer) > 0);
  1446.     
  1447.       fclose(fd);
  1448.  
  1449.       sprintf(buffer, "(%s -s \"While You Were Out\" %s < %s ; %s %s) &", 
  1450.               mailx, address, tempfile, remove, tempfile);
  1451.  
  1452.       system(buffer);
  1453.     }
  1454. }
  1455.  
  1456. int
  1457. translate(fullname, name)
  1458. char *fullname, *name;
  1459. {
  1460.     /** translate fullname into name..
  1461.            'first last'  translated to first_initial - underline - last
  1462.            'initial last' translated to initial - underline - last
  1463.         Return 0 if error.
  1464.     **/
  1465.     register int i, lastname = 0;
  1466.  
  1467.     for (i=0; i < strlen(fullname); i++) {
  1468.  
  1469.       if (isupper(fullname[i]))
  1470.          fullname[i] = fullname[i] - 'A' + 'a';
  1471.  
  1472.       if (fullname[i] == ' ') 
  1473.         if (lastname) {
  1474.           printf(
  1475.           "** Can't have more than 'FirstName LastName' as address!\n");
  1476.           return(0);
  1477.         }
  1478.         else
  1479.           lastname = i+1;
  1480.     
  1481.     }
  1482.  
  1483.     if (lastname) 
  1484.       sprintf(name, "%c_%s", fullname[0], (char *) fullname + lastname);
  1485.     else
  1486.       strcpy(name, fullname);
  1487.  
  1488.     return(1);
  1489. }
  1490.  
  1491.         
  1492. read_alias_files()
  1493. {
  1494.     /** read the user alias file **/
  1495.  
  1496.     char fname[SLEN];
  1497.     int  hash;
  1498.  
  1499.     sprintf(fname,  "%s/.alias_hash", getenv("HOME")); 
  1500.  
  1501.     if ((hash = open(fname, O_RDONLY)) == -1) 
  1502.       exit(printf("** Fatal Error: Could not open %s!\n", fname));
  1503.  
  1504.     read(hash, user_hash_table, sizeof user_hash_table);
  1505.     close(hash);
  1506.  
  1507.     sprintf(fname,  "%s/.alias_data", getenv("HOME")); 
  1508.  
  1509.     if ((user_data = open(fname, O_RDONLY)) == -1) 
  1510.       return;
  1511. }
  1512.  
  1513. char *get_alias_address(name, mailing, depth)
  1514. char *name;
  1515. int   mailing, depth;
  1516. {
  1517.     /** return the line from either datafile that corresponds 
  1518.         to the specified name.  If 'mailing' specified, then
  1519.         fully expand group names.  Returns NULL if not found.
  1520.         Depth is the nesting depth, and varies according to the
  1521.         nesting level of the routine.  **/
  1522.  
  1523.     static char buffer[VERY_LONG_STRING];
  1524.     int    loc;
  1525.  
  1526.     if ((loc = find(name, user_hash_table, MAX_UALIASES)) >= 0) {
  1527.       lseek(user_data, user_hash_table[loc].byte, 0L);
  1528.       get_line(user_data, buffer, LONG_STRING);
  1529.       if (buffer[0] == '!' && mailing)
  1530.         return( (char *) expand_group(buffer, depth));
  1531.       else
  1532.         return( (char *) buffer);
  1533.     }
  1534.     
  1535.     return( (char *) NULL);
  1536. }
  1537.  
  1538. char *expand_group(members, depth)
  1539. char *members;
  1540. int   depth;
  1541. {
  1542.     /** given a group of names separated by commas, this routine
  1543.         will return a string that is the full addresses of each
  1544.         member separated by spaces.  Depth is the current recursion
  1545.         depth of the expansion (for the 'get_token' routine) **/
  1546.  
  1547.     char   buffer[VERY_LONG_STRING];
  1548.     char   buf[LONG_STRING], *word, *address, *bufptr;
  1549.  
  1550.     strcpy(buf, members);     /* parameter safety! */
  1551.     buffer[0] = '\0';    /* nothing in yet!   */
  1552.     bufptr = (char *) buf;    /* grab the address  */
  1553.     depth++;        /* one more deeply into stack */
  1554.  
  1555.     while ((word = (char *) get_token(bufptr, "!, ", depth)) != NULL) {
  1556.       if ((address = (char *) get_alias_address(word, 1, depth)) == NULL) {
  1557.         fprintf(stderr, "Alias %s not found for group expansion!", word);
  1558.         return( (char *) NULL);
  1559.       }
  1560.       else if (strcmp(buffer,address) != 0) {
  1561.         sprintf(buffer,"%s %s", buffer, address);
  1562.       }
  1563.  
  1564.       bufptr = NULL;
  1565.     }
  1566.  
  1567.     return( (char *) buffer);
  1568. }
  1569.  
  1570. int
  1571. find(word, table, size)
  1572. char *word;
  1573. struct alias_rec table[];
  1574. int size;
  1575. {
  1576.     /** find word and return loc, or -1 **/
  1577.     register int loc;
  1578.     
  1579.     if (strlen(word) > 20)
  1580.       exit(printf("Bad alias name: %s.  Too long.\n", word));
  1581.  
  1582.     loc = hash_it(word, size);
  1583.  
  1584.     while (strcmp(word, table[loc].name) != 0) {
  1585.       if (table[loc].name[0] == '\0') 
  1586.         return(-1);
  1587.       loc = (loc + 1) % size; 
  1588.     }
  1589.  
  1590.     return(loc);
  1591. }
  1592.  
  1593. int
  1594. hash_it(string, table_size)
  1595. char *string;
  1596. int   table_size;
  1597. {
  1598.     /** compute the hash function of the string, returning
  1599.         it (mod table_size) **/
  1600.  
  1601.     register int i, sum = 0;
  1602.     
  1603.     for (i=0; string[i] != '\0'; i++)
  1604.       sum += (int) string[i];
  1605.  
  1606.     return(sum % table_size);
  1607. }
  1608.  
  1609. get_line(fd, buffer)
  1610. int fd;
  1611. char *buffer;
  1612. {
  1613.     /* read from file fd.  End read upon reading either 
  1614.        EOF or '\n' character (this is where it differs 
  1615.        from a straight 'read' command!) */
  1616.  
  1617.     register int i= 0;
  1618.     char     ch;
  1619.  
  1620.     while (read(fd, &ch, 1) > 0)
  1621.       if (ch == '\n' || ch == '\r') {
  1622.         buffer[i] = 0;
  1623.         return;
  1624.       }
  1625.       else
  1626.         buffer[i++] = ch;
  1627. }
  1628.  
  1629. print_long(buffer, init_len)
  1630. char *buffer;
  1631. int   init_len;
  1632. {
  1633.     /** print buffer out, 80 characters (or less) per line, for
  1634.         as many lines as needed.  If 'init_len' is specified, 
  1635.         it is the length that the first line can be.
  1636.     **/
  1637.  
  1638.     register int i, loc=0, space, length; 
  1639.  
  1640.     /* In general, go to 80 characters beyond current character
  1641.        being processed, and then work backwards until space found! */
  1642.  
  1643.     length = init_len;
  1644.  
  1645.     do {
  1646.       if (strlen(buffer) > loc + length) {
  1647.         space = loc + length;
  1648.         while (buffer[space] != ' ' && space > loc + 50) space--;
  1649.         for (i=loc;i <= space;i++)
  1650.           putchar(buffer[i]);
  1651.         putchar('\n');
  1652.         loc = space;
  1653.       }
  1654.       else {
  1655.         for (i=loc;i < strlen(buffer);i++)
  1656.           putchar(buffer[i]);
  1657.         putchar('\n');
  1658.         loc = strlen(buffer);
  1659.       }
  1660.       length = 80;
  1661.     } while (loc < strlen(buffer));
  1662. }
  1663.  
  1664. /****
  1665.      The following is a newly chopped version of the 'strtok' routine
  1666.   that can work in a recursive way (up to 20 levels of recursion) by
  1667.   changing the character buffer to an array of character buffers....
  1668. ****/
  1669.  
  1670. #define MAX_RECURSION        20        /* up to 20 deep recursion */
  1671.  
  1672. #undef  NULL
  1673. #define NULL            (char *) 0    /* for this routine only   */
  1674.  
  1675. extern int strspn();
  1676. extern char *strpbrk();
  1677.  
  1678. char *get_token(string, sepset, depth)
  1679. char *string, *sepset;
  1680. int  depth;
  1681. {
  1682.  
  1683.     /** string is the string pointer to break up, sepstr are the
  1684.         list of characters that can break the line up and depth
  1685.         is the current nesting/recursion depth of the call **/
  1686.  
  1687.     register char    *p, *q, *r;
  1688.     static char    *savept[MAX_RECURSION];
  1689.  
  1690.     /** is there space on the recursion stack? **/
  1691.  
  1692.     if (depth >= MAX_RECURSION) {
  1693.      fprintf(stderr,"Error: Get_token calls nested greated than %d deep!\n",
  1694.             MAX_RECURSION);
  1695.      exit(1);
  1696.     }
  1697.  
  1698.     /* set up the pointer for the first or subsequent call */
  1699.     p = (string == NULL)? savept[depth]: string;
  1700.  
  1701.     if(p == 0)        /* return if no tokens remaining */
  1702.         return(NULL);
  1703.  
  1704.     q = p + strspn(p, sepset);    /* skip leading separators */
  1705.  
  1706.     if (*q == '\0')        /* return if no tokens remaining */
  1707.         return(NULL);
  1708.  
  1709.     if ((r = strpbrk(q, sepset)) == NULL)    /* move past token */
  1710.         savept[depth] = 0;    /* indicate this is last token */
  1711.     else {
  1712.         *r = '\0';
  1713.         savept[depth] = ++r;
  1714.     }
  1715.     return(q);
  1716. }
  1717. END-OF-FILE
  1718.  
  1719. size=`wc -c < utils/answer.c`
  1720.  
  1721. if [ $size != 8207 ]
  1722. then
  1723.   echo Warning: utils/answer.c changed - should be 8207 bytes, not $size bytes
  1724. fi
  1725.  
  1726. chmod 644 utils/answer.c
  1727.  
  1728. # ---------- file utils/arepdaemon.c ----------
  1729.  
  1730.  
  1731. if [ -f utils/arepdaemon.c ]
  1732. then
  1733.   echo File 'utils/arepdaemon.c' already exists\!
  1734.   exit 1
  1735. fi
  1736.  
  1737. echo extracting file utils/arepdaemon.c...
  1738. cat << 'END-OF-FILE' > utils/arepdaemon.c
  1739. /**            arepdaemon.c            **/
  1740.  
  1741. /** (C) Copyright 1986 Dave Taylor            **/
  1742.  
  1743. /** Keep track of mail as it arrives, and respond by sending a 'recording'
  1744.     file to the sender as new mail is received.
  1745.  
  1746.     Note: the user program that interacts with this program is the
  1747.     'autoreply' program and that should be consulted for further
  1748.     usage information.
  1749.  
  1750.     This program is part of the 'autoreply' system, and is designed
  1751.     to run every hour and check all mailboxes listed in the file 
  1752.     "/etc/autoreply.data", where the data is in the form:
  1753.  
  1754.     username    replyfile    current-mailfile-size
  1755.  
  1756.     To avoid a flood of autoreplies, this program will NOT reply to mail 
  1757.     that contains header "X-Mailer: fastmail".  Further, each time the 
  1758.     program responds to mail, the 'mailfile size' entry is updated in
  1759.     the file /etc/autoreply.data to allow the system to be brought 
  1760.     down and rebooted without any loss of data or duplicate messages.
  1761.  
  1762.     This daemon also uses a lock semaphore file, /usr/spool/uucp/LCK..arep,
  1763.     to ensure that more than one copy of itself is never running.  For this
  1764.     reason, it is recommended that this daemon be started up each morning
  1765.     from cron, since it will either start since it's needed or simply see
  1766.     that the file is there and disappear.
  1767.  
  1768.     Since this particular program is the main daemon answering any
  1769.     number of different users, it must be run with uid root.
  1770.  
  1771.     (C) 1985, Dave Taylor, HP Colorado Networks Operation
  1772. **/
  1773.  
  1774. #include <stdio.h>
  1775. #include <time.h>
  1776. #include <sys/types.h>
  1777. #include <sys/stat.h>
  1778.  
  1779. #include "defs.h"
  1780.  
  1781. #define arep_lock_file    "/usr/spool/uucp/LCK..arep"
  1782.  
  1783. #define autoreply_file    "/etc/autoreply.data"
  1784. #define fastmail    "/usr/local/bin/fastmail"
  1785.  
  1786. #define logfile        "/etc/autoreply.log"    /* first choice   */
  1787. #define logfile2    "/tmp/autoreply.log"    /* second choice  */
  1788.  
  1789. #define BEGINNING    0        /* see fseek(3S) for info */
  1790. #define SLEEP_TIME    3600        /* run once an hour       */
  1791. #define MAX_PEOPLE    20        /* max number in program  */
  1792.  
  1793. #define EXISTS        00        /* lock file exists??     */
  1794. #define MODE        0777        /* lockfile creation mode */
  1795.  
  1796. #define NLEN        20
  1797.  
  1798. #define remove_return(s)    if (strlen(s) > 0) { \
  1799.                       if (s[strlen(s)-1] == '\n') \
  1800.                     s[strlen(s)-1] = '\0'; \
  1801.                         }
  1802.  
  1803. struct replyrec {
  1804.     char     username[NLEN];        /* login name of user */
  1805.     char    mailfile[SLEN];        /* name of mail file  */
  1806.     char    replyfile[SLEN];    /* name of reply file */
  1807.     long    mailsize;        /* mail file size     */
  1808.     int     in_list;        /* for new replies    */
  1809.       } reply_table[MAX_PEOPLE];
  1810.  
  1811. FILE  *logfd;                /* logfile (log action)   */
  1812. long  autoreply_size = 0L;        /* size of autoreply file */
  1813. int   active = 0;            /* # of people 'enrolled' */
  1814.  
  1815. FILE  *open_logfile();            /* forward declaration    */
  1816.  
  1817. long  bytes();                /*       ditto           */
  1818.  
  1819. main()
  1820. {
  1821.     long size;
  1822.     int  person, data_changed;
  1823.  
  1824.     if (! lock())
  1825.       exit(0);    /* already running! */
  1826.  
  1827.     while (1) {
  1828.  
  1829.       logfd = open_logfile();    /* open the log */
  1830.  
  1831.       /* 1. check to see if autoreply table has changed.. */
  1832.  
  1833.       if ((size = bytes(autoreply_file)) != autoreply_size) {
  1834.         read_autoreply_file(); 
  1835.         autoreply_size = size;
  1836.       }
  1837.  
  1838.       /* 2. now for each active person... */
  1839.     
  1840.       data_changed = 0;
  1841.  
  1842.       for (person = 0; person < active; person++) {
  1843.         if ((size = bytes(reply_table[person].mailfile)) != 
  1844.         reply_table[person].mailsize) {
  1845.           if (size > reply_table[person].mailsize)
  1846.             read_newmail(person);
  1847.           /* else mail removed - resync */
  1848.           reply_table[person].mailsize = size;
  1849.           data_changed++;
  1850.         }
  1851.       }
  1852.  
  1853.       /* 3. if data changed, update autoreply file */
  1854.  
  1855.       if (data_changed)
  1856.         update_autoreply_file();
  1857.  
  1858.       close_logfile();        /* close the logfile again */
  1859.  
  1860.       /* 4. Go to sleep...  */
  1861.  
  1862.       sleep(SLEEP_TIME);
  1863.     }
  1864. }
  1865.  
  1866. int
  1867. read_autoreply_file()
  1868. {
  1869.     /** We're here because the autoreply file has changed size!!  It
  1870.         could either be because someone has been added or because
  1871.         someone has been removed...since the list will always be in
  1872.         order (nice, eh?) we should have a pretty easy time of it...
  1873.     **/
  1874.  
  1875.     FILE *file;
  1876.     char username[SLEN],     replyfile[SLEN];
  1877.     int  person;
  1878.      long size;
  1879.     
  1880.     log("Autoreply data file has changed!  Reading...");
  1881.  
  1882.     if ((file = fopen(autoreply_file,"r")) == NULL) {
  1883.       log("No-one is using autoreply...");
  1884.       return(0);
  1885.     }
  1886.     
  1887.     for (person = 0; person < active; person++)
  1888.       reply_table[person].in_list = 0;
  1889.     
  1890.     while (fscanf(file, "%s %s %dl", username, replyfile, &size) != EOF) {
  1891.       /* check to see if this person is already in the list */
  1892.       if ((person = in_list(username)) != -1) {
  1893.         reply_table[person].in_list = 1;
  1894.         reply_table[person].mailsize = size;     /* sync */
  1895.       }
  1896.       else {     /* if not, add them */
  1897.         if (active == MAX_PEOPLE) {
  1898.           unlock();
  1899.           exit(log("Couldn't add %s - already at max people!", 
  1900.                  username));
  1901.         }
  1902.         log("adding %s to the active list", username);
  1903.         strcpy(reply_table[active].username, username);
  1904.         sprintf(reply_table[active].mailfile, "/usr/mail/%s", username);
  1905.         strcpy(reply_table[active].replyfile, replyfile);
  1906.         reply_table[active].mailsize = size;
  1907.         reply_table[active].in_list = 1;    /* obviously! */
  1908.         active++;
  1909.       }
  1910.     }
  1911.  
  1912.     /** now check to see if anyone has been removed... **/
  1913.  
  1914.     for (person = 0; person < active; person++)
  1915.       if (reply_table[person].in_list == 0) {
  1916.          log("removing %s from the active list", 
  1917.           reply_table[person].username);
  1918.         strcpy(reply_table[person].username, 
  1919.            reply_table[active-1].username);
  1920.         strcpy(reply_table[person].mailfile, 
  1921.            reply_table[active-1].mailfile);
  1922.         strcpy(reply_table[person].replyfile, 
  1923.            reply_table[active-1].replyfile);
  1924.         reply_table[person].mailsize = reply_table[active-1].mailsize;
  1925.         active--;
  1926.       }
  1927. }
  1928.  
  1929. update_autoreply_file()
  1930. {
  1931.     /** update the entries in the autoreply file... **/
  1932.  
  1933.     FILE *file;
  1934.     register int person;
  1935.  
  1936.     if ((file = fopen(autoreply_file,"w")) == NULL) {
  1937.           log("Couldn't update autoreply file!");
  1938.       return;
  1939.     }
  1940.  
  1941.     for (person = 0; person < active; person++)
  1942.       fprintf(file, "%s %s %ld\n",
  1943.           reply_table[person].username,
  1944.           reply_table[person].replyfile,
  1945.           reply_table[person].mailsize);
  1946.  
  1947.     fclose(file);
  1948.  
  1949.     printf("updated autoreply file\n");
  1950.     autoreply_size = bytes(autoreply_file);
  1951. }
  1952.  
  1953. int
  1954. in_list(name)
  1955. char *name;
  1956. {
  1957.     /** search the current active reply list for the specified username.
  1958.         return the index if found, or '-1' if not. **/
  1959.  
  1960.     register int index;
  1961.  
  1962.     for (index = 0; index < active; index++)
  1963.       if (strcmp(name, reply_table[index].username) == 0)
  1964.         return(index);
  1965.     
  1966.     return(-1);
  1967. }
  1968.  
  1969. read_newmail(person)
  1970. int person;
  1971. {
  1972.     /** Read the new mail for the specified person. **/
  1973.  
  1974.     
  1975.     FILE *mailfile;
  1976.     char from_whom[LONG_SLEN], subject[SLEN];
  1977.     int  sendit;
  1978.  
  1979.     log("New mail for %s", reply_table[person].username);
  1980.  
  1981.         if ((mailfile = fopen(reply_table[person].mailfile,"r")) == NULL)
  1982.            return(log("can't open mailfile for user %s", 
  1983.             reply_table[person].username));
  1984.  
  1985.         if (fseek(mailfile, reply_table[person].mailsize, BEGINNING) == -1)
  1986.            return(log("couldn't seek to %ld in mail file!", 
  1987.                    reply_table[person].mailsize));
  1988.  
  1989.     while (get_return(mailfile, person, from_whom, subject, &sendit) != -1)
  1990.       if (sendit)
  1991.         reply_to_mail(person, from_whom, subject);
  1992.  
  1993.     return;
  1994. }
  1995.  
  1996. int
  1997. get_return(file, person, from, subject, sendit)
  1998. FILE *file;
  1999. int  person, *sendit;
  2000. char *from, *subject;
  2001. {
  2002.     /** Reads the new message and return the from and subject lines.
  2003.         sendit is set to true iff it isn't a machine generated msg
  2004.     **/
  2005.     
  2006.     char name1[SLEN], name2[SLEN], lastname[SLEN];
  2007.     char buffer[LONG_SLEN], hold_return[NLEN];
  2008.     int done = 0, in_header = 0;
  2009.  
  2010.     from[0] = '\0';
  2011.     *sendit = 1;
  2012.  
  2013.     while (! done) {
  2014.  
  2015.       if (fgets(buffer, LONG_SLEN, file) == NULL)
  2016.     return(-1);
  2017.  
  2018.       if (first_word(buffer, "From ")) {
  2019.     in_header++;
  2020.     sscanf(buffer, "%*s %s", hold_return);
  2021.       }
  2022.       else if (in_header) {
  2023.         if (first_word(buffer, ">From")) {
  2024.       sscanf(buffer,"%*s %s %*s %*s %*s %*s %*s %*s %*s %s", name1, name2);
  2025.       add_site(from, name2, lastname);
  2026.         }
  2027.         else if (first_word(buffer,"Subject:")) {
  2028.       remove_return(buffer);
  2029.       strcpy(subject, (char *) (buffer + 8));
  2030.         }
  2031.         else if (first_word(buffer,"X-Mailer: fastmail"))
  2032.       *sendit = 0;
  2033.         else if (strlen(buffer) == 1)
  2034.       done = 1;
  2035.       }
  2036.     }
  2037.  
  2038.     if (from[0] == '\0')
  2039.       strcpy(from, hold_return); /* default address! */
  2040.     else
  2041.       add_site(from, name1, lastname);    /* get the user name too! */
  2042.  
  2043.     return(0);
  2044. }
  2045.  
  2046. add_site(buffer, site, lastsite)
  2047. char *buffer, *site, *lastsite;
  2048. {
  2049.     /** add site to buffer, unless site is 'uucp', or the same as 
  2050.         lastsite.   If not, set lastsite to site.
  2051.     **/
  2052.  
  2053.     char local_buffer[LONG_SLEN], *strip_parens();
  2054.  
  2055.     if (strcmp(site, "uucp") != 0)
  2056.       if (strcmp(site, lastsite) != 0) {
  2057.           if (buffer[0] == '\0')
  2058.             strcpy(buffer, strip_parens(site));         /* first in list! */
  2059.           else {
  2060.             sprintf(local_buffer,"%s!%s", buffer, strip_parens(site));
  2061.             strcpy(buffer, local_buffer);
  2062.           }
  2063.           strcpy(lastsite, strip_parens(site)); /* don't want THIS twice! */
  2064.        }
  2065. }
  2066.  
  2067. remove_first_word(string)
  2068. char *string;
  2069. {    /** removes first word of string, ie up to first non-white space
  2070.         following a white space! **/
  2071.  
  2072.     register int loc;
  2073.  
  2074.     for (loc = 0; string[loc] != ' ' && string[loc] != '\0'; loc++) 
  2075.         ;
  2076.  
  2077.     while (string[loc] == ' ' || string[loc] == '\t')
  2078.       loc++;
  2079.     
  2080.     move_left(string, loc);
  2081. }
  2082.  
  2083. move_left(string, chars)
  2084. char string[];
  2085. int  chars;
  2086. {
  2087.     /** moves string chars characters to the left DESTRUCTIVELY **/
  2088.  
  2089.     register int i;
  2090.  
  2091.     chars--; /* index starting at zero! */
  2092.  
  2093.     for (i=chars; string[i] != '\0' && string[i] != '\n'; i++)
  2094.       string[i-chars] = string[i];
  2095.  
  2096.     string[i-chars] = '\0';
  2097. }
  2098.  
  2099. reply_to_mail(person, from, subject)
  2100. int   person;
  2101. char *from, *subject;
  2102. {
  2103.     /** Respond to the message from the specified person with the
  2104.         specified subject... **/
  2105.     
  2106.     char buffer[SLEN];
  2107.  
  2108.     if (strlen(subject) == 0)
  2109.       strcpy(subject, "Auto-reply Mail");
  2110.     else if (! first_word(subject,"Auto-reply")) {
  2111.       sprintf(buffer, "Auto-reply to:%s", subject);
  2112.       strcpy(subject, buffer);
  2113.     }
  2114.  
  2115.     log("auto-replying to '%s'", from);
  2116.  
  2117.     mail(from, subject, reply_table[person].replyfile, person);
  2118. }    
  2119.  
  2120. reverse(string)
  2121. char *string;
  2122. {
  2123.     /** reverse string... pretty trivial routine, actually! **/
  2124.  
  2125.     char buffer[SLEN];
  2126.     register int i, j = 0;
  2127.  
  2128.     for (i = strlen(string)-1; i >= 0; i--)
  2129.       buffer[j++] = string[i];
  2130.  
  2131.     buffer[j] = '\0';
  2132.  
  2133.     strcpy(string, buffer);
  2134. }
  2135.  
  2136. long
  2137. bytes(name)
  2138. char *name;
  2139. {
  2140.     /** return the number of bytes in the specified file.  This
  2141.         is to check to see if new mail has arrived....  **/
  2142.  
  2143.     int ok = 1;
  2144.     extern int errno;    /* system error number! */
  2145.     struct stat buffer;
  2146.  
  2147.     if (stat(name, &buffer) != 0)
  2148.       if (errno != 2) {
  2149.        unlock();
  2150.        exit(fprintf(stderr,"Error %d attempting fstat on %s", errno, name));
  2151.       }
  2152.       else
  2153.         ok = 0;
  2154.     
  2155.     return(ok ? buffer.st_size : 0);
  2156. }
  2157.  
  2158. mail(to, subject, filename, person)
  2159. char *to, *subject, *filename;
  2160. int   person;
  2161. {
  2162.     /** Mail 'file' to the user from person... **/
  2163.     
  2164.     char buffer[VERY_LONG_STRING];
  2165.  
  2166.     sprintf(buffer, "%s -f '%s [autoreply]' -s '%s' %s %s",
  2167.         fastmail, reply_table[person].username,
  2168.             subject, filename, to);
  2169.     
  2170.     system(buffer);
  2171. }
  2172.  
  2173. log(message, arg)
  2174. char *message;
  2175. char *arg;
  2176. {
  2177.     /** Put log entry into log file.  Use the format:
  2178.           date-time: <message>
  2179.     **/
  2180.  
  2181.     struct tm *localtime(), *thetime;
  2182.     long      time(), clock;
  2183.     char      buffer[SLEN];
  2184.  
  2185.     /** first off, get the time and date **/
  2186.  
  2187.     clock = time((long *) 0);       /* seconds since ???   */
  2188.     thetime = localtime(&clock);    /* and NOW the time... */
  2189.  
  2190.     /** then put the message out! **/
  2191.  
  2192.     sprintf(buffer, message, arg);
  2193.  
  2194.     fprintf(logfd,"%d/%d-%d:%02d: %s\n", 
  2195.         thetime->tm_mon+1, thetime->tm_mday,
  2196.             thetime->tm_hour,  thetime->tm_min,
  2197.             buffer);
  2198. }
  2199.  
  2200. FILE *open_logfile()
  2201. {
  2202.     /** open the logfile.  returns a valid file descriptor **/
  2203.  
  2204.     FILE *fd;
  2205.  
  2206.     if ((fd = fopen(logfile, "a")) == 0)
  2207.       if ((fd = fopen(logfile2, "a")) == 0) {
  2208.         unlock();
  2209.         exit(1);    /* give up! */
  2210.       }
  2211.  
  2212.     return( (FILE *) fd);
  2213. }
  2214.  
  2215. close_logfile()
  2216. {
  2217.     /** Close the logfile until needed again. **/
  2218.  
  2219.     fclose(logfd);
  2220. }
  2221.  
  2222. char *strip_parens(string)
  2223. char *string;
  2224. {
  2225.     /** Return string with all parenthesized information removed.
  2226.         This is a non-destructive algorithm... **/
  2227.  
  2228.     static char  buffer[LONG_SLEN];
  2229.     register int i, depth = 0, buffer_index = 0;
  2230.  
  2231.     for (i=0; i < strlen(string); i++) {
  2232.       if (string[i] == '(')
  2233.         depth++;
  2234.       else if (string[i] == ')') 
  2235.         depth--;
  2236.       else if (depth == 0)
  2237.         buffer[buffer_index++] = string[i];
  2238.     }
  2239.     
  2240.     buffer[buffer_index] = '\0';
  2241.  
  2242.     return( (char *) buffer);
  2243. }
  2244.  
  2245. /*** LOCK and UNLOCK - ensure only one copy of this daemon running at any
  2246.      given time by using a file existance semaphore (wonderful stuff!) ***/
  2247.  
  2248. lock()
  2249. {
  2250.     /** Try to create the lock file.  If it's there, or we can't
  2251.         create it for some stupid reason, return zero, otherwise,
  2252.         a non-zero return code indicates success in locking this
  2253.         process in. **/
  2254.  
  2255.     if (access(arep_lock_file, EXISTS) == 0)
  2256.       return(0);     /* file already exists!! */
  2257.  
  2258.     if (creat(arep_lock_file, MODE) == -1)
  2259.       return(0);    /* can't create file!!   */
  2260.  
  2261.     return(1);
  2262. }
  2263.  
  2264. unlock()
  2265. {
  2266.     /** remove lock file if it's there! **/
  2267.  
  2268.     (void) unlink(arep_lock_file);
  2269. }
  2270. END-OF-FILE
  2271.  
  2272. size=`wc -c < utils/arepdaemon.c`
  2273.  
  2274. if [ $size != 13340 ]
  2275. then
  2276.   echo Warning: utils/arepdaemon.c changed - should be 13340 bytes, not $size bytes
  2277. fi
  2278.  
  2279. chmod 644 utils/arepdaemon.c
  2280.  
  2281. # ---------- file utils/autoreply.c ----------
  2282.  
  2283.  
  2284. if [ -f utils/autoreply.c ]
  2285. then
  2286.   echo File 'utils/autoreply.c' already exists\!
  2287.   exit 1
  2288. fi
  2289.  
  2290. echo extracting file utils/autoreply.c...
  2291. cat << 'END-OF-FILE' > utils/autoreply.c
  2292. /**            autoreply.c            **/
  2293.  
  2294. /** This is the front-end for the autoreply system, and performs two 
  2295.     functions: it either adds the user to the list of people using the
  2296.     autoreply function (starting the daemon if no-one else) or removes
  2297.     a user from the list of people.
  2298.  
  2299.     Usage:  autoreply filename
  2300.         autoreply "off"
  2301.     or  autoreply        [to find current status]
  2302.     
  2303.     (C) 1986, Dave Taylor
  2304. **/
  2305.  
  2306. #include <stdio.h>
  2307. #include <errno.h>
  2308. #include <sys/types.h>
  2309. #include <sys/stat.h>
  2310.  
  2311. #define  SLEN        80            /* a normal string      */
  2312. #define  NLEN        20            /* a short string       */
  2313.  
  2314. #define  READ_ACCESS    04               /* is file readable?    */
  2315.  
  2316. #define  mailhome    "/usr/mail"        /* where new mail lives */
  2317. #define  tempdir    "/tmp/arep"        /* file prefix          */
  2318. #define  autoreply_file    "/etc/autoreply.data"   /* autoreply data file  */
  2319.  
  2320. extern   int errno;                /* system error code    */
  2321. char     username[NLEN];            /* login name of user   */
  2322.  
  2323. main(argc, argv)
  2324. int    argc;
  2325. char *argv[];
  2326. {
  2327.     char filename[SLEN];
  2328.  
  2329.     if (argc > 2) {
  2330.       printf("Usage: %s <filename>\tto start autoreply,\n", argv[0]);
  2331.       printf("       %s off\t\tto turn off autoreply\n", argv[0]);
  2332.       printf("   or  %s    \t\tto check current status\n", argv[0]);
  2333.       exit(1);
  2334.     }
  2335.  
  2336.     (void) cuserid(username);
  2337.  
  2338.     if (strcmp(argv[1], "off") == 0 || argc == 1) 
  2339.       remove_user((argc == 1));
  2340.     else {
  2341.       strcpy(filename, argv[1]);
  2342.       if (access(filename,READ_ACCESS) != 0) {
  2343.         printf("Error: Can't read file '%s'\n", filename);
  2344.         exit(1);
  2345.       }
  2346.       
  2347.       if (filename[0] != '/') /* prefix home directory */
  2348.         sprintf(filename,"%s/%s", getenv("HOME"), argv[1]);
  2349.  
  2350.       add_user(filename);
  2351.     }
  2352.  
  2353.     exit(0);
  2354. }
  2355.  
  2356. remove_user(stat_only)
  2357. int stat_only;
  2358. {
  2359.     /** Remove the user from the list of currently active autoreply 
  2360.         people.  If 'stat_only' is set, then just list the name of
  2361.         the file being used to autoreply with, if any. **/
  2362.  
  2363.     FILE *temp, *repfile;
  2364.     char  tempfile[SLEN], user[SLEN], filename[SLEN];
  2365.     int   c, copied = 0, found = 0;
  2366.     long  filesize, bytes();
  2367.  
  2368.     if (! stat_only) {
  2369.       sprintf(tempfile, "%s.%06d", tempdir, getpid());
  2370.  
  2371.       if ((temp = fopen(tempfile, "w")) == NULL) {
  2372.         printf("Error: couldn't open tempfile '%s'.  Not removed\n",
  2373.             tempfile);
  2374.         exit(1);
  2375.       }
  2376.     }
  2377.  
  2378.     if ((repfile = fopen(autoreply_file, "r")) == NULL) {
  2379.       if (stat_only) {
  2380.         printf("You're not currently autoreplying to mail.\n");
  2381.         exit(0);
  2382.       }
  2383.       printf("No-one is autoreplying to their mail!\n");
  2384.       exit(0);
  2385.     }
  2386.  
  2387.     /** copy out of real replyfile... **/
  2388.  
  2389.     while (fscanf(repfile, "%s %s %ld", user, filename, &filesize) != EOF) 
  2390.  
  2391.       if (strcmp(user, username) != 0) {
  2392.         if (! stat_only) {
  2393.           copied++;
  2394.           fprintf(tempfile, "%s %s %ld\n", user, filename, filesize);
  2395.         }
  2396.       }
  2397.       else {
  2398.         if (stat_only) {
  2399.           printf("You're currently autoreplying to mail with the file %s\n",              filename); 
  2400.           exit(0);
  2401.         }
  2402.         found++;
  2403.       }
  2404.  
  2405.     fclose(temp);
  2406.     fclose(repfile);
  2407.  
  2408.     if (! found) {
  2409.       printf("You're not currently autoreplying to mail%s\n",
  2410.           stat_only? "." : "!");
  2411.       if (! stat_only)
  2412.         unlink(tempfile);
  2413.       exit(! stat_only);
  2414.     }
  2415.  
  2416.     /** now copy tempfile back into replyfile **/
  2417.  
  2418.     if (copied == 0) {    /* removed the only person! */
  2419.       unlink(autoreply_file);
  2420.     }
  2421.     else {            /* save everyone else   */
  2422.       
  2423.       if ((temp = fopen(tempfile,"r")) == NULL) {
  2424.         printf("Error: couldn't reopen tempfile '%s'.  Not removed.\n",
  2425.             tempfile);
  2426.         unlink(tempfile);
  2427.         exit(1);
  2428.       }
  2429.  
  2430.       if ((repfile = fopen(autoreply_file, "w")) == NULL) {
  2431.         printf(
  2432.           "Error: couldn't reopen autoreply file for writing!  Not removed.\n");
  2433.         unlink(tempfile);
  2434.         exit(1);
  2435.       }
  2436.  
  2437.       while ((c = getc(temp)) != EOF)
  2438.         putc(c, repfile);
  2439.  
  2440.       fclose(temp);
  2441.       fclose(repfile);
  2442.     
  2443.     }
  2444.     unlink(tempfile);
  2445.  
  2446.     if (found > 1)
  2447.       printf("Warning: your username appeared %d times!!   Removed all\n", 
  2448.           found);
  2449.     else
  2450.       printf("You've been removed from the autoreply table.\n");
  2451. }
  2452.  
  2453. add_user(filename)
  2454. char *filename;
  2455. {
  2456.     /** add the user to the autoreply file... **/
  2457.  
  2458.     FILE *repfile;
  2459.     char  mailfile[SLEN];
  2460.     long  bytes();
  2461.  
  2462.     if ((repfile = fopen(autoreply_file, "a")) == NULL) {
  2463.       printf("Error: couldn't open the autoreply file!  Not added\n");
  2464.       exit(1);
  2465.     }
  2466.     
  2467.     sprintf(mailfile,"%s/%s", mailhome, username);
  2468.  
  2469.     fprintf(repfile,"%s %s %ld\n", username, filename, bytes(mailfile));
  2470.  
  2471.     fclose(repfile);
  2472.  
  2473.     printf("You've been added to the autoreply system.\n");
  2474. }
  2475.  
  2476.  
  2477. long
  2478. bytes(name)
  2479. char *name;
  2480. {
  2481.     /** return the number of bytes in the specified file.  This
  2482.         is to check to see if new mail has arrived....  **/
  2483.  
  2484.     int ok = 1;
  2485.     extern int errno;    /* system error number! */
  2486.     struct stat buffer;
  2487.  
  2488.     if (stat(name, &buffer) != 0)
  2489.       if (errno != 2)
  2490.        exit(fprintf(stderr,"Error %d attempting fstat on %s", errno, name));
  2491.       else
  2492.         ok = 0;
  2493.     
  2494.     return(ok ? buffer.st_size : 0L);
  2495. }
  2496. END-OF-FILE
  2497.  
  2498. size=`wc -c < utils/autoreply.c`
  2499.  
  2500. if [ $size != 4840 ]
  2501. then
  2502.   echo Warning: utils/autoreply.c changed - should be 4840 bytes, not $size bytes
  2503. fi
  2504.  
  2505. chmod 644 utils/autoreply.c
  2506.  
  2507. echo done
  2508.  
  2509. exit 0
  2510.  
  2511.  
  2512.  
  2513.  
  2514.