home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Spezial / SPEZIAL2_97.zip / SPEZIAL2_97.iso / ANWEND / ONLINE / ELM23-2 / ELM23-2.ZIP / utils / rcvmail.c < prev    next >
C/C++ Source or Header  |  1997-02-02  |  9KB  |  458 lines

  1. /* rcvmail.c - simple delivery agent for IBM sendmail
  2.  *
  3.  * Author:  Kai Uwe Rommel <rommel@ars.de>
  4.  * Created: Mon Jul 22 1996
  5.  */
  6.  
  7. static char *rcsid =
  8. "$Id: rcvmail.c,v 1.1 1997/02/02 20:23:22 rommel Exp rommel $";
  9. static char *rcsrev = "$Revision: 1.1 $";
  10.  
  11. /*
  12.  * $Log: rcvmail.c,v $
  13.  * Revision 1.1  1997/02/02 20:23:22  rommel
  14.  * Initial revision
  15.  * 
  16.  */
  17.  
  18. #include <stdio.h>
  19. #include <string.h>
  20. #include <process.h>
  21. #include <time.h>
  22. #include <fcntl.h>
  23.  
  24. #define INCL_NOPM
  25. #include <os2.h>
  26.  
  27. #include <os2elm.h>
  28. #include <pwd.h>
  29.  
  30. char *mailboxdir;
  31. char *recipient;
  32.  
  33. char *uupc;
  34. char uupcdelimiter[21];
  35.  
  36. char from[256], to[32768];
  37. int bytes;
  38.  
  39. char *strip_parens(char *string)
  40. {
  41.   /**
  42.     Remove parenthesized information from a string.  More specifically,
  43.     comments as defined in RFC822 are removed.  This procedure is
  44.     non-destructive - a pointer to static data is returned.
  45.     **/
  46.   static char  buffer[32768];
  47.   register char *bufp;
  48.   register int depth;
  49.  
  50.   for ( bufp = buffer, depth = 0 ; *string != '\0' ; ++string ) {
  51.     switch ( *string ) {
  52.     case '(':            /* begin comment on '('        */
  53.       ++depth;
  54.       break;
  55.     case ')':            /* decr nesting level on ')'    */
  56.       --depth;
  57.       break;
  58.     case '\\':            /* treat next char literally    */
  59.       if ( *++string == '\0' ) {        /* gracefully handle    */
  60.     *bufp++ = '\\';            /* '\' at end of string    */
  61.     --string;                /* even tho it's wrong    */
  62.       } else if ( depth == 0 ) {
  63.     *bufp++ = '\\';
  64.     *bufp++ = *string;
  65.       }
  66.       break;
  67.     default:            /* a regular char        */
  68.       if ( depth == 0 )
  69.     *bufp++ = *string;
  70.       break;
  71.     }
  72.   }
  73.   *bufp = '\0';
  74.   return( (char *) buffer);
  75. }
  76.  
  77. void get_address_from(char *prefix, char *line, char *buffer)
  78. {
  79.   register char *s;
  80.  
  81.   /**  Skip start of line over prefix, e.g. "From:".  **/
  82.   line += strlen(prefix);
  83.  
  84.   /**  If there is a '<' then copy from it to '>' into the buffer.  **/
  85.   if ( (s = strchr(line,'<')) != NULL ) 
  86.   {
  87.     while ( ++s , *s != '\0' && *s != '>' ) 
  88.     {
  89.       if ( !isspace(*s) )
  90.     *buffer++ = *s;
  91.     }
  92.     *buffer = '\0';
  93.     return;
  94.   }
  95.  
  96.   /**  Otherwise, strip comments and get address with whitespace elided.  **/
  97.   for ( s = strip_parens(line) ; *s != '\0' ; ++s ) 
  98.   {
  99.     if ( !isspace(*s) )
  100.       *buffer++ = *s;
  101.   }
  102.   *buffer = '\0';
  103. }
  104.  
  105. int nextline(FILE *file, char *buffer, int size)
  106. {
  107.   int len;
  108.  
  109.   if (fgets(buffer, size, file) == NULL)
  110.     return -1;
  111.  
  112.   len = strlen(buffer);
  113.  
  114.   if (buffer[len - 1] == '\n')
  115.     buffer[--len] = 0;
  116.  
  117.   return len;
  118. }
  119.  
  120. void checkfirst(char *line)
  121. {
  122.   char buffer[5120], *ptr, *timestr;
  123.   time_t now;
  124.   
  125.   if (strncmp(line, "From ", 5) == 0)
  126.   {
  127.     ptr = strchr(line + 5, ' ');
  128.  
  129.     /* Work around a bug in IBM's sendmail: Sometimes,
  130.        sendmail does not replace $d with the current date.
  131.        Rather, it just drops $d and the line will have
  132.        the two spaces surrounding $d in the `Dl' line of
  133.        sendmail.cf). */
  134.  
  135.     if (ptr && ptr[0] == ' ' && ptr[1] == ' ')
  136.     {
  137.       ptr[0] = 0;
  138.       ptr += 2;
  139.       time(&now);
  140.       timestr = ctime(&now);
  141.       timestr[strlen(timestr) - 1] = 0; /* kill \n */
  142.       sprintf (buffer, "%s %s %s", line, timestr, ptr);
  143.       strcpy(line, buffer);
  144.     }
  145.   }
  146. }
  147.  
  148. int scanmail(FILE *mail, FILE *mailbox, char *from, char *to)
  149. {
  150.   char buffer[32768], buffer2[32768];
  151.   int len, bytes = 0, inheader = 1, first = 1;
  152.  
  153.   *from = *to = 0;
  154.  
  155.   while ((len = nextline(mail, buffer, sizeof(buffer))) != -1)
  156.   {
  157.     if (first)
  158.     {
  159.       first = 0;
  160.       checkfirst(buffer);
  161.     }
  162.  
  163.     fprintf(mailbox, "%s\n", buffer);
  164.     bytes += len + 1; /* don't forget \n */
  165.  
  166.     if (inheader)
  167.     {
  168.       while (buffer[strlen(buffer) - 1] == ',')
  169.       {
  170.     if ((len = nextline(mail, buffer2, sizeof(buffer2))) == -1)
  171.       break;
  172.  
  173.     fprintf(mailbox, "%s\n", buffer2);
  174.     strcat(buffer, buffer2);
  175.     bytes += len + 1;
  176.       }
  177.  
  178.       if (strnicmp(buffer, "Resent-To:", 10) == 0)
  179.     get_address_from("Resent-To:", buffer, to);
  180.       if (strnicmp(buffer, "To:", 3) == 0 && *to == 0)
  181.     get_address_from("To:", buffer, to);
  182.  
  183.       if (strnicmp(buffer, "Resent-From:", 12) == 0)
  184.     get_address_from("Resent-From:", buffer, from);
  185.       if (strnicmp(buffer, "From:", 5) == 0 && *from == 0)
  186.     get_address_from("From:", buffer, from);
  187.  
  188.       if (len == 0)
  189.     inheader = 0;
  190.     }
  191.   }
  192.  
  193.   return bytes;
  194. }
  195.  
  196. void logentry(char *msg)
  197. {
  198.   char filename[256], datetime[32];
  199.   FILE *log;
  200.   time_t now;
  201.   struct tm *tm;
  202.  
  203.   time(&now);
  204.   tm = localtime(&now);
  205.   strftime(datetime, sizeof(datetime), "%m/%d-%H:%M", tm);
  206.  
  207.   strcpy(filename, logdir);
  208.   strcat(filename, "/");
  209.   strcat(filename, "rcvmail.log");
  210.  
  211.   if ((log = fopen(filename, "a")) != NULL)
  212.   {
  213.     fprintf(log, "%s %s\n", datetime, msg);
  214.     fclose(log);
  215.   }
  216. }
  217.  
  218. void success(int bytes, char *from, char *to, char *realto)
  219. {
  220.   char buffer[32768];
  221.  
  222.   sprintf(buffer, "delivering mail (%d bytes) from %s to %s (%s)", 
  223.       bytes, from, realto, to);
  224.  
  225.   logentry(buffer);
  226. }
  227.  
  228. int deliver(FILE *mail, FILE *file, char *delim)
  229. {
  230.   char buffer[5120];
  231.  
  232.   rewind(mail);
  233.  
  234.   if (delim)
  235.     fprintf(file, "%s\n", delim);
  236.  
  237.   while (fgets(buffer, sizeof(buffer), mail) != NULL)
  238.     if (fputs(buffer, file) == EOF)
  239.       return 1;
  240.  
  241.   return 0;
  242. }
  243.  
  244. int deliver_file(FILE *mail, char *name)
  245. {
  246.   char mailbox[256], msg[512];
  247.   FILE *file;
  248.   int rc, i;
  249.  
  250.   strcpy(mailbox, mailboxdir);
  251.   strcat(mailbox, "/");
  252.   strcat(mailbox, name);
  253.  
  254.   for (i = 0; i < 5; i++)
  255.     if ((file = fopen(mailbox, "a")) != 0)
  256.       break;
  257.     else
  258.       sleep(1);
  259.  
  260.   if (file == NULL)
  261.   {
  262.     sprintf(msg, "failed to open to %s", mailbox);
  263.     logentry(msg);
  264.     return 0;
  265.   }
  266.  
  267.   rc = deliver(mail, file, uupc);
  268.  
  269.   fclose(file);
  270.  
  271.   if (rc == 0)
  272.   {
  273.     success(bytes, from, to, name);
  274.     return 1;
  275.   }
  276.  
  277.   return 0;
  278. }
  279.  
  280. int deliver_pipe(FILE *mail, char *cmd)
  281. {
  282.   char msg[512];
  283.   FILE *pipe;
  284.   int rc;
  285.  
  286.   if ((pipe = popen(cmd + 1, "w")) == NULL)
  287.   {
  288.     sprintf(msg, "failed to execute '%s'", cmd + 1);
  289.     logentry(msg);
  290.     return 0;
  291.   }
  292.  
  293.   rc = deliver(mail, pipe, NULL);
  294.  
  295.   pclose(pipe);
  296.  
  297.   if (rc == 0)
  298.   {
  299.     success(bytes, from, to, cmd);
  300.     return 1;
  301.   }
  302.  
  303.   return 0;
  304. }
  305.  
  306. int deliver_remote(FILE *mail, char *address)
  307. {
  308.   char filename[256], cmd[512];
  309.   FILE *file;
  310.   int rc, i;
  311.  
  312.   for (i = 0; i < 5; i++)
  313.   {
  314.     if (tmpnam(filename) != NULL)
  315.       if ((file = fopen(filename, "w")) != 0)
  316.     break;
  317.  
  318.     sleep(1);
  319.   }
  320.  
  321.   if (file == NULL)
  322.     return logentry("failed to create temporary file"), 0;
  323.  
  324.   rc = deliver(mail, file, NULL);
  325.  
  326.   fclose(file);
  327.  
  328.   sprintf(cmd, "sndmail -bg -af %s -f %s %s", filename, recipient, address);
  329.   rc = system(cmd);
  330.  
  331.   if (rc == 0)
  332.   {
  333.     success(bytes, from, to, address);
  334.     return 1;
  335.   }
  336.  
  337.   return 0;
  338. }
  339.  
  340. int deliver_user(FILE *mail, char *name)
  341. {
  342.   struct passwd *user;
  343.   char filename[256], buffer[5120];
  344.   FILE *fwd;
  345.   int len, delivered = 0;
  346.  
  347.   if ((user = getpwnam(name)) == NULL)
  348.   {
  349.     if (stricmp(name, recipient) == 0)
  350.       name = postmaster; /* original recipient unknown */
  351.     else
  352.       return 0; /* else deliver to original recipient */
  353.   }
  354.  
  355.   if (user && user->pw_dir)
  356.   {
  357.     strcpy(filename, user->pw_dir);
  358.     strcat(filename, "/forward");
  359.  
  360.     if ((fwd = fopen(filename, "r")) != NULL)
  361.     {
  362.       fcntl(fileno(fwd), F_SETFD, FD_CLOEXEC);
  363.  
  364.       while (fgets(buffer, sizeof(buffer), fwd) != NULL)
  365.       {
  366.     len = strlen(buffer);
  367.  
  368.     if (buffer[len - 1] == '\n')
  369.       buffer[--len] = 0;
  370.  
  371.     switch (buffer[0])
  372.     {
  373.     case '|':
  374.       delivered += deliver_pipe(mail, buffer);
  375.       break;
  376.     case '\\':
  377.       delivered += deliver_file(mail, buffer + 1);
  378.       break;
  379.     default:
  380.       if (stricmp(buffer, recipient) != 0) /* no circular forwarding! */
  381.       {
  382.         if (strchr(buffer, '@'))
  383.           delivered += deliver_remote(mail, buffer);
  384.         else
  385.           delivered += deliver_user(mail, buffer);
  386.       }
  387.       break;
  388.     }
  389.       }
  390.  
  391.       fclose(fwd);
  392.     }
  393.   }
  394.  
  395.   if (!delivered)
  396.     delivered += deliver_file(mail, name);
  397.  
  398.   return delivered;
  399. }
  400.  
  401. int main(int argc, char **argv)
  402. {
  403.   char mailfile[256], cmd[512];
  404.   FILE *mail;
  405.   int i;
  406.   struct passwd *pwent;
  407.  
  408.   if (argc != 3 && argc != 4)
  409.     return printf("This program is only called internally from sendmail.\n"), 1;
  410.  
  411.   initpaths();
  412.  
  413.   if (stricmp(argv[1], "-u") == 0)
  414.   {
  415.     memset(uupcdelimiter, '\001', 20);
  416.     uupcdelimiter[20] = 0;
  417.     uupc = uupcdelimiter;
  418.  
  419.     argc--;
  420.     argv++;
  421.   }
  422.  
  423.   mailboxdir = argv[1];
  424.   recipient = argv[2];
  425.  
  426.   for (i = 0; i < 5; i++)
  427.   {
  428.     if (tmpnam(mailfile) != NULL)
  429.       if ((mail = fopen(mailfile, "w")) != 0)
  430.     break;
  431.  
  432.     sleep(1);
  433.   }
  434.  
  435.   if (mail == NULL)
  436.     return logentry("failed to create temporary file"), 1;
  437.  
  438.   bytes = scanmail(stdin, mail, from, to);
  439.   fclose(mail);
  440.  
  441.   sprintf(cmd,"rcvfilt %s %s", mailfile, recipient);
  442.   system(cmd);
  443.  
  444.   if ((mail = fopen(mailfile, "r")) == 0)
  445.     return logentry("failed to reopen temporary file"), 1;
  446.  
  447.   fcntl(fileno(mail), F_SETFD, FD_CLOEXEC);
  448.  
  449.   deliver_user(mail, recipient);
  450.  
  451.   fclose(mail);
  452.   unlink(mailfile);
  453.  
  454.   return 0;
  455. }
  456.  
  457. /* end of rcvmail.c */
  458.