home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / mmdf / mmdf-IIb.43 / uip / unsupported / autores.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-03-28  |  13.7 KB  |  658 lines

  1. #ifndef lint
  2. static char sccsid[] = "@(#)autores.c    1.6 (UKC) 14/2/86";
  3. #endif  lint
  4. /***
  5.  
  6. * program name:
  7.     autores.c
  8. * function:
  9.     Send an automatic reply to mail depending on the subject field
  10.     The subject field is used to select a file in 
  11.     /usr/lib/mmdf/auto which is interpreted as a mail item to send out
  12.     Subject lines starting with 'Re:' are ignored
  13.     If the first line of the file starts with '~', it is taken
  14.     to be the Subject line for the outgoing mail.
  15.     A line should be installed in the mmdf aliases file of the form
  16.         information:mmdf|/usr/lib/mmdf/autores "$(sender)"
  17.     If there are two parameters, the subject line is ignored and the
  18.     second parameter is used to select a file
  19. * switches:
  20.     Called with the return address
  21.     and optionally a named file
  22. * libraries used:
  23.     standard
  24. * compile time parameters:
  25.     cc -o autores autores.c
  26. * history:
  27.     Written Feb 1986
  28.     Peter Collinson UKC
  29.  
  30.     Timothy Wood AMC-LSSA Jan. 1988
  31.     Modified to accomodate SYS5 and added a Makefile.real and
  32.     "gen" (so that the unsupported directory looks like the other
  33.     directories) that will use libmmdf.a and the standard set of 
  34.     Makefile.com compiler and linker options and so that a call to
  35.     cnvtdate can be used instead of the Berkeley time code.  Added
  36.     some security so that only the "srcdir" can be searched (could
  37.     use relative pathnames, before).
  38.  
  39.     Timothy Wood AMC-LSSA Jan. 1988
  40.     Modifications made for the Plexus P-60 Sys 3.2
  41.  
  42. ***/
  43. #include <stdio.h>
  44. #include <ctype.h>
  45. #include <sys/types.h>
  46. #include <fcntl.h>
  47.  
  48. #ifdef SYS5
  49. #  include <time.h>
  50. #  include "cnvtdate.h"
  51. #  ifdef PLEXUS
  52.     char *index(), *rindex();
  53.     char *strcpy();
  54. #  else PLEXUS
  55. #    include <string.h>
  56. #  endif PLEXUS
  57. #else
  58. #  include <sys/time.h>
  59. #  include <sys/timeb.h>
  60. #  include <strings.h>        /* added TW */
  61. #  include <sys/wait.h>
  62. #endif SYS5
  63.  
  64. /* Externals from conf.c used in building pathnames for autores */
  65.     extern char *locname;
  66.     extern char *locdomain;
  67.     extern char *cmddfldir;
  68.     extern char *logdfldir;
  69.  
  70. /*
  71.  *    Source directory
  72.  */
  73. char *badpath; /* added TW */
  74. /* char *srcdir = "/prog/mmdf2/distribution"; /* requested file storage. */
  75. char *srcdir[128];
  76.  
  77. /*
  78.  *    who to reply to
  79.  */
  80. char *sender; 
  81.  
  82. /*
  83.  *    system log file
  84.  */
  85. /* char *logfile = "/prog/mmdf2/log/autores.log"; /* Change for your sys */
  86. char *logfile[128];
  87. int    logfd = -1;
  88. int    logpid;
  89.  
  90. /*
  91.  *    file to look for
  92.  */
  93. char *command;
  94. int    fromarg;
  95. /* char    submit[]    = "/prog/mmdf2/submit";  /* Change for your sys */
  96. char    submit[128];
  97. char    subargs[]    = "-vmltnqxto,*";
  98. /* char    signature[]    = "info-request@xls-plexus02"; /* Your address */
  99. char    signature[128];
  100.  
  101. int    pipein[2];    /* pipes for communication */
  102. int    pipeout[2];
  103.  
  104. FILE    *pout;        /* re-opened FILE pointer for pipeout */
  105. FILE    *pin;        /* re-opened FILE pointer for pipein */
  106.  
  107. /*
  108.  *    error response line
  109.  */
  110. char    errline[BUFSIZ];
  111. int    senderror;
  112.  
  113. char    stdinfo[] =    /* Put out in each message */
  114. "\n\
  115. An index of the available information can be obtained by mailing to\n\
  116. info-request@xls-plexus01.amc-hq.arpa with a Subject: line containing\n\
  117. only the word \"index\"\n\
  118. i.e.\n\
  119.     Subject: index\n\
  120. \n";
  121.  
  122. /*
  123.  *    Data structure used to scan and recognise an inbound mail message
  124.  *    All this is overkill but I had the code hanging around and I am
  125.  *    never one to re-write stuff which works
  126.  */
  127. typedef struct
  128. {    char    *header;
  129.     char    *dataline;
  130.     int    hadthis;
  131. } Header_line;
  132.  
  133. Header_line header_line[] =
  134. {    { "subject", },
  135.     { 0, }
  136. };
  137. #define HSUBJECT    0
  138.  
  139.  
  140. main(argc, argv)
  141. char **argv;
  142. {
  143.     strcpy(srcdir, cmddfldir);
  144.     strcat(srcdir, "/distribution");
  145.     strcpy(logfile, logdfldir);
  146.     strcat(logfile, "/autores.log");
  147.     strcpy(submit, cmddfldir);
  148.     strcat(submit, "/submit");
  149.     strcpy(signature, "info-request@");
  150.     strcat(signature, locname);
  151.     strcat(signature, ".");
  152.     strcat(signature, locdomain);
  153.     openlog();    
  154.     if (argc == 3)
  155.     {    command = argv[2];
  156.         fromarg++;
  157.     }
  158.     else
  159.     if (argc != 2)
  160.         fatal("Usage: autores sender\n");
  161.     sender = argv[1];
  162.     if (chdir(srcdir) < 0)
  163.         fatal("No source directory\n");    
  164.     /*
  165.      *    Mail header decoding
  166.      *    all we want is the subject line
  167.      */
  168.     if (fromarg == 0)
  169.     {    if (readheader(stdin)) /* if not OK */
  170.             command = NULL;
  171.     }
  172.     clear_input(stdin);
  173.     if (command)
  174.         /* Make sure they aren't getting out of bounds. TW */
  175.         /* Use "rindex" to maintain BSD compat */
  176.         if((badpath = rindex(command, '/')) == NULL)  /* TW */
  177.             send_info(command);
  178.         else    /* TW */
  179.         {    /* TW */
  180.             log("Caught %s snooping around.\n", sender); /* TW */
  181.             log("His command was %s.\n", command);    /* TW */
  182.             usererror("Attempted to access unauthorized info.\n");
  183.         }    /* TW */
  184.     if (senderror)
  185.         send_error();
  186.     closelog();
  187.     exit(0);
  188. }
  189.  
  190. /*
  191.  *    Read an incoming mail item looking for the subject line
  192.  *    This all borrowed from another program
  193.  */
  194. readheader(fin)
  195. FILE *fin;
  196. {    register char *cp;
  197.     char *index();
  198.  
  199.     if (get_header_lines(fin))
  200.         return(1);
  201.     if (header_line[HSUBJECT].hadthis == 0)
  202.     {    usererror("No Subject: line found\n");
  203.         return(1);
  204.     }
  205.     command = header_line[HSUBJECT].dataline;        
  206.     /*
  207.      * look for Re: bits in lines
  208.      */
  209.     while ((*command == 'R' || *command == 'r') &&
  210.            (command[1] == 'e' || command[1] == 'E' ) &&
  211.            (command[2] == ':'))
  212.     {    log("Re: found request from %s ignored\n", sender);
  213.         return(1);
  214.     }
  215.     return(0);
  216. }
  217.  
  218. /*
  219.  *    Scan the inbound mail header
  220.  */
  221. get_header_lines(fin)
  222. FILE *fin;
  223. {    register char *p;
  224.     register char *startfield;
  225.     register Header_line *hp;
  226.     char    line[BUFSIZ];
  227.     int    peekc;
  228.     Header_line *look_header();
  229.     char    *storestr();
  230.     char    *storepair();
  231.     char     *index();
  232.     
  233.     for (;;)
  234.     {    if (fgets(line, sizeof line - 1, fin) == NULL)
  235.         {    usererror("Unexpected end of mail input file\n");
  236.             return(1);
  237.         }
  238.         peekc = getc(fin);
  239.         (void) ungetc(peekc, fin);
  240.         if (line[0] == '\n')
  241.             break;
  242.         hp = (Header_line *)0;
  243.         if (p = index(line, ':'))
  244.         {    *p++ = '\0';
  245.             if (hp = look_header(line))
  246.             {    /* we want to know about this line */
  247.                 if (hp->hadthis++)
  248.                 {    /* we have had this line before */
  249.                     usererror("More than one %s header line found\n", hp->header);
  250.                     return(1);
  251.                 }
  252.                 /* clean up this line */
  253.                 if (*p == ' ') p++;
  254.                 startfield = p;
  255.                 p = index(startfield, '\n');
  256.                 if (p == NULL)
  257.                     line[BUFSIZ-1] = '\0';
  258.                 else
  259.                     *p = '\0';
  260.                 hp->dataline = storestr(startfield);
  261.             }
  262.         }
  263.         /*
  264.          *    cope with continuation lines
  265.          */
  266.         while (peekc == ' ' || peekc == '\t')
  267.         {    if (fgets(line, sizeof line -1, fin) == NULL)
  268.             {    usererror("Unexpected end of mail input file\n");
  269.                 return(1);
  270.             }
  271.             peekc = getc(fin);
  272.             (void) ungetc(peekc, fin);
  273.             /*
  274.              * if hp is set then we need to concatenate the
  275.              * new bit onto the old stored piece
  276.              */
  277.             if (hp)
  278.             {    if (p = index(line, '\n'))
  279.                     *p = '\0';
  280.                 else    line[BUFSIZ-1] = '\0';
  281.                 hp->dataline = storepair(hp->dataline, line, 1);
  282.             }
  283.         }
  284.     }
  285.     return(0);
  286. }
  287.  
  288. /*
  289.  *    scan the Header_line structure looking for a matching
  290.  *    string which is a header - use equstr to match
  291.  */
  292. Header_line *
  293. look_header(str)
  294. char *str;
  295. {    register Header_line *hp;
  296.     for (hp = header_line; hp->header; hp++)
  297.         if (equstr(str, hp->header) == 0)
  298.             return(hp);
  299.     return((Header_line *)0);
  300. }
  301.  
  302. /*
  303.  *    read very hard on the file descriptor throwing the data away
  304.  */
  305. clear_input(fin)
  306. FILE *fin;
  307. {    register c;
  308.     while ((c = getc(fin)) != EOF);
  309. }
  310.  
  311. /*
  312.  *    Send information
  313.  */
  314. send_info(cmd)
  315. register char *cmd;
  316. {    register char *p;
  317.     register bytes;
  318.     char    line[BUFSIZ];
  319.     FILE *fin;
  320.     
  321.     /* This is ok as far as it goes but does not cover the case
  322.        of subdir/../../someotherdirectory/someotherfile, etc  TW.
  323.     */
  324.     /*
  325.      *    first clean up the command
  326.      *    All must start with an alpha character
  327.      */
  328.     while (!isalpha(*cmd))
  329.         cmd++;
  330.     for (p = cmd; *p; p++)
  331.     {    if (isupper(*p))
  332.             *p = tolower(*p);
  333.         if (isspace(*p) || ! isprint(*p))
  334.         {    *p = '\0';
  335.             break;
  336.         }
  337.     }
  338.     if ((fin = fopen(cmd, "r")) == NULL)
  339.     {    usererror("No information on: %s\n", cmd);
  340.         return;
  341.     }
  342.     log("%s requests %s\n", sender, cmd);
  343.     /* Subject is the 1st line of source - assuming is starts with '~' */
  344.     fgets(line, sizeof line, fin);
  345.     init_mail();
  346.     mail_header(cmd, line[0] == '~' ? &line[1] : NULL);
  347.     fprintf(pout, "Thank you for your information request\n");
  348.     fprintf(pout, stdinfo);
  349.     fprintf(pout, "-----%s-----\n", cmd);
  350.     /*
  351.      * replace initial line if it is not a comment
  352.      */
  353.     if (line[0] != '~')
  354.         fputs(line, pout);
  355.     /*
  356.      *    now read the remainder and send to pipe
  357.      */
  358.     while (bytes = fread(line, 1, sizeof line, fin))
  359.         fwrite(line, 1, bytes, pout);
  360.     (void) fclose(pout);
  361.     mail_termination();
  362. }
  363.  
  364. /*
  365.  *    Send an error reply
  366.  */
  367. send_error()
  368. {    init_mail();
  369.     mail_header("Error response", NULL);
  370.     if (command)
  371.         fprintf(pout, "Your request for information with a subject of `%s'\n", command);
  372.     else
  373.         fprintf(pout, "Your request for information\n");
  374.     fprintf(pout, "has failed. The reason was:\n\n%s\n", errline);
  375.     fprintf(pout, stdinfo);
  376.     (void) fclose(pout);
  377.     mail_termination();
  378. }
  379.  
  380. /*
  381.  *    Initialise a pipe to submit
  382.  */
  383. init_mail()
  384. {    register pid;
  385.     register i;
  386.     char    *subcmd;
  387. #ifndef SYS5
  388.     char    *rindex();
  389. #endif SYS5
  390.     char    *maildate();
  391.         
  392.     subcmd = rindex(submit, '/');
  393.     if (subcmd)
  394.         subcmd++;
  395.     else
  396.         subcmd = submit;
  397.         
  398.     (void) pipe(pipein);    /* parent will read from pipein[0] */
  399.     (void) pipe(pipeout);    /* parent will write to pipeout[1] */
  400.     
  401.     if ((pid = fork()) < 0)
  402.     {    fatal("Cannot create a process for mail submission\n");
  403.         return;
  404.     }
  405.     if (pid == 0)
  406.     {    /* child */
  407.         /* stdin is pipeout[0] */
  408.         /* stdout/stderr is pipein[1] */
  409.         (void) close(pipeout[1]);
  410.         (void) close(pipein[0]);
  411.         (void) close(0);
  412.         (void) dup(pipeout[0]);
  413.         (void) close(pipeout[0]);
  414.         (void) close(1);
  415.         (void) dup(pipein[1]);
  416.         (void) close(pipein[1]);
  417.         (void) close(2);
  418.         (void) dup(1);
  419.         for (i = 3; i < 20; i++)
  420.             (void) close(i);
  421.         execl(submit, subcmd, subargs, 0);
  422.         (void) close(0);
  423.         (void) close(1);
  424.         (void) close(2);
  425.         exit(1);
  426.     }
  427.     /*
  428.      *    Parent
  429.      */
  430.     (void) close(pipein[1]);
  431.     (void) close(pipeout[0]);
  432.     pout = fdopen(pipeout[1], "w");
  433.     pin = fdopen(pipein[0], "r");
  434. }
  435.  
  436. /*
  437.  *    Deal with the termination of the mail process
  438.  */
  439. mail_termination()
  440. {    char    logbuf[BUFSIZ];
  441. #ifndef SYS5
  442.     union    wait retstat;
  443. #else SYS5
  444.     int *retstat;
  445.     int retcode;
  446. #endif SYS5
  447.  
  448.     while(fgets(logbuf, sizeof logbuf, pin))
  449.         log("%s", logbuf);
  450.     (void) fclose(pin);
  451.     
  452. #ifndef SYS5
  453.     if (wait(&retstat) > 0)
  454.     {    if (retstat.w_retcode == 9 &&
  455.             retstat.w_termsig == 0)
  456.         {    log("Autoresend - successful submit\n");
  457.             return;
  458.         }
  459.     }
  460.     log("Submit failed, returning %x %d\n", retstat, retstat);
  461. #else SYS5
  462.     retcode = wait(&retstat); 
  463.     if(retcode < 0)
  464.     {
  465.         log("Submit failed, returned %d - %d\n", retcode, &retstat);
  466.         return;
  467.     }
  468.     else
  469.     {
  470.         log("Autoresend - successful submission.\n");
  471.         return;
  472.     }
  473. #endif SYS5
  474. }
  475.  
  476. /*
  477.  *    Do a mail header
  478.  */
  479. mail_header(cmd, subject)
  480. char *cmd;
  481. char *subject;
  482. {
  483.     fprintf(pout, "%s\n", signature);    /* special validation argument */
  484.     fprintf(pout, "To: %s\n", sender);
  485.      fprintf(pout, "From: Information service <%s>\n", signature);
  486.     if (subject)
  487.         fprintf(pout, "Subject: Re: %s - %s", cmd, subject);
  488.     else    fprintf(pout, "Subject: Re: %s\n", cmd);
  489.     fprintf(pout, "Date: %s\n", maildate());
  490.     fprintf(pout, "\n");
  491. }
  492.  
  493. /*
  494.  *    return a static string with the data in RFC822 format
  495.  */
  496. char *
  497. maildate()
  498. {
  499.     static    char datbuf[64];
  500. #ifndef SYS5
  501.     static char *day[] = {
  502.         "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
  503.     };
  504.     static char *month[] = {
  505.         "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  506.         "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
  507.     };
  508.     struct timeb    timeb;
  509.     extern char *timezone();
  510.     extern struct tm  *localtime ();
  511.      register struct tm  *i;
  512.         
  513.     ftime(&timeb);
  514.     i = localtime ((time_t *) & timeb.time);
  515.     (void) sprintf(datbuf, "%s, %d %s %d %d:%02d:%02d %s",
  516.         day[i -> tm_wday], i -> tm_mday, month[i -> tm_mon],
  517.         i -> tm_year, i -> tm_hour, i -> tm_min, i -> tm_sec,
  518.             timezone (timeb.timezone, i -> tm_isdst));
  519. #else SYS5
  520.     cnvtdate(TIMREG, datbuf);
  521. #endif SYS5
  522.     return(datbuf);
  523. }
  524.      
  525. /*
  526.  *    See if two strings are the same irrespective of case
  527.  *    return 0 if equal, 1 otherwise
  528.  */
  529. equstr(a, b)
  530. register char *a, *b;
  531. {    register ca, cb;
  532.     while (ca = *a)
  533.     {    cb = *b;
  534.         if (cb == 0)
  535.             return(1);
  536.         if (ca != cb)
  537.         {    if (isupper(ca))
  538.                 ca = tolower(ca);
  539.             if (isupper(cb))
  540.                 cb = tolower(cb);
  541.             if (ca != cb)
  542.                 return(1);
  543.         }
  544.         a++;
  545.         b++;
  546.     }
  547.     return(*b == '\0' ? 0 : 1);
  548. }
  549.  
  550. /*
  551.  *    string management routines
  552.  */
  553. char *
  554. storestr(str)
  555. char *str;
  556. {    register nchs;
  557.     char *area;
  558.     char *malloc();
  559.     
  560.     nchs = strlen(str) + 1;
  561.     if ((area = malloc((unsigned) nchs)) == NULL)
  562.         fatal("No memory for string storage\n");
  563. #ifdef SYS5
  564.     strcpy(area, str);
  565. #else SYS5
  566.     bcopy(str, area, nchs);
  567. #endif SYS5
  568.     return (area);
  569. }
  570.  
  571. /*
  572.  *    Concatenate and store a pair of strings
  573.  *    the last parameter is used as a mask to indicate that one or other
  574.  *    of the paramaters can be free()'d
  575.  */
  576. char *
  577. storepair(a, b, msk)
  578. char *a;
  579. char *b;
  580. {    register nchs;
  581.     register alen;
  582.     register blen;
  583.     char *area;
  584.  
  585.     alen = strlen(a);
  586.     blen = strlen(b);
  587.     nchs = alen + blen + 1;
  588.     if ((area = malloc((unsigned) nchs)) == NULL)
  589.         fatal("No memory for string storage\n");
  590. #ifdef SYS5
  591.     strcpy(area, a);
  592.     strcat(&area[alen], b);
  593. #else SYS5
  594.     bcopy(a, area, alen);
  595.     bcopy(b, &area[alen], blen+1);
  596. #endif SYS5
  597.     if (msk & 01)
  598.         free(a);
  599.     if (msk & 02)
  600.         free(b);
  601.     return(area);
  602. }
  603.  
  604. /*
  605.  *    set up an error reply line
  606.  */
  607. /*VARARGS1*/
  608. usererror(fmt, a, b, c, d)
  609. char *fmt;
  610. {    (void) sprintf(errline, fmt, a, b, c, d);
  611.     senderror++;
  612.     log(fmt, a, b, c, d);
  613.  
  614. }
  615.  
  616. /*
  617.  *    open the log file
  618.  */
  619. openlog()
  620. {
  621.     logpid = getpid();
  622.     
  623.     /* May as well create it if it isn't there.  TW */
  624.     logfd = open(logfile, O_CREAT|O_WRONLY|O_APPEND, 0644);
  625.  
  626. }
  627.  
  628. /*VARARGS1*/
  629. log(fmt, a, b, c, d)
  630. char *fmt;
  631. {    char line[BUFSIZ];
  632.     time_t ti;
  633.     char *ctime();
  634.     register hdrlen;
  635.     
  636.     if (logfd < 0)
  637.         return;
  638.     
  639.     (void) time(&ti);
  640.     (void) sprintf(line, "%6d %15.15s: ", logpid, ctime(&ti)+4);
  641.     hdrlen = strlen(line);
  642.     (void) sprintf(&line[hdrlen], fmt, a, b, c, d);
  643.     write(logfd, line, strlen(line));
  644. }
  645.  
  646. closelog()
  647. {    if (logfd >= 0)
  648.         close(logfd);
  649. }
  650.  
  651. /*VARARGS1*/
  652. fatal(fmt, a, b, c, d)
  653. char *fmt;
  654. {    log(fmt, a, b, c, d);
  655.     closelog();
  656.     exit(0);
  657. }
  658.