home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / TELECOM / UUCPbb_2_1_src.lzh / UUCPBB21 / rmail.c < prev    next >
Text File  |  1994-09-27  |  29KB  |  1,114 lines

  1. /*  rmail.c   This program routes mail to a local or remote user.
  2.     Copyright (C) 1990, 1993  Rick Adams and Bob Billson
  3.  
  4.     This file is part of the OS-9 UUCP package, UUCPbb.
  5.  
  6.     This program is free software; you can redistribute it and/or modify
  7.     it under the terms of the GNU General Public License as published by
  8.     the Free Software Foundation; either version 2 of the License, or
  9.     (at your option) any later version.
  10.  
  11.     This program is distributed in the hope that it will be useful,
  12.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.     GNU General Public License for more details.
  15.  
  16.     You should have received a copy of the GNU General Public License
  17.     along with this program; if not, write to the Free Software
  18.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  
  20.     The author of UUCPbb, Bob Billson, can be contacted at:
  21.     bob@kc2wz.bubble.org  or  uunet!kc2wz!bob  or  by snail mail:
  22.     21 Bates Way, Westfield, NJ 07090
  23. */
  24.  /****************************************\
  25.  * Usage: rmail [file] "site!user[@site]" *
  26.  \****************************************/
  27.  
  28. #define MAIN
  29.  
  30. #include "uucp.h" 
  31. #include <time.h>
  32. #include <modes.h>
  33. #include <direct.h>
  34. #include <signal.h>
  35. #include <ctype.h>
  36. #ifndef _OSK
  37. #include <os9.h>
  38. #endif
  39.  
  40. #define DELIVERED    0
  41. #define UNDELIVERED  1 
  42. #define UNKWNUSER    2
  43. #define UNKWNSITE    3
  44. #define NOTBOUNCED   4
  45. #define BOUNCED      5
  46. #define FRMSIZE     19
  47. #define SUBJSIZE    27
  48. #define WORDSIZE    30
  49.  
  50. extern QQ unsigned myuid;
  51. extern QQ unsigned validuid;                      /* defined in validuser.c */
  52. extern QQ char *uucphost, *bithost, *inhost;
  53. extern QQ char *nodename, *sitename, *errorsto;
  54. extern char temp[], user[], fname[];
  55.  
  56. QQ char *errmsg = "ERROR--";
  57. QQ flag logopen = FALSE;
  58. QQ int debug = 0;
  59. QQ char *filename;
  60. QQ int fileowner;                                 /* owner of passed file */
  61. QQ FILE *log;
  62. QQ char *userdir;                                 /* used by dolocal() */
  63. char mailstring[80];                              /*                   */
  64.  
  65. /*
  66. QQ unsigned errorsID;
  67. */
  68. static char address[512], line[512], line2[512];
  69. void openlog(), closelog(), logerror();
  70. long _gs_size();
  71.  
  72.  
  73. main (argc, argv)
  74. int argc;
  75. char *argv[];
  76. {
  77.      register FILE *file;
  78.      flag delivered;
  79.      int interrupt();
  80.  
  81.      userdir = NULL;
  82.      homedir = NULL;
  83.      log = NULL;
  84.  
  85. #ifdef _OSK
  86.      pflinit();                              /* longs will be printed */
  87. #endif
  88.      intercept (interrupt);
  89.  
  90.      switch (argc)
  91.        {
  92.           case 2:
  93.                if (argv[1][0] == '-'  &&  argv[1][1] == '?')
  94.                     usage();
  95.  
  96.                strcpy (address, argv[1]);
  97.                file = stdin;
  98.                *filename = '\0';
  99.                break;
  100.  
  101.           case 3:
  102.                strcpy (address, argv[2]);
  103.                filename = argv[1];
  104.  
  105.                if ((file = fopen (filename, "r")) == NULL)
  106.                  {
  107.                     sprintf (temp, "can't open input file %s", filename);
  108.                     logerror (temp);
  109.                     exit (UNDELIVERED);
  110.                  }
  111.                break;
  112.  
  113.           default:
  114.                usage();
  115.        }
  116.  
  117.      if ((logdir = getenv ("LOGDIR")) != NULL)
  118.           logdir = strdup (logdir);
  119.      else 
  120.           logdir = LOGDIR;
  121.  
  122.      openlog();
  123.  
  124.      /* find out who owns the file we were passed */
  125.      fileowner = who_owns_the (file);
  126.      asetuid (fileowner);
  127.  
  128.      if (getparam() == FALSE)
  129.           errorexit (UNDELIVERED);
  130.  
  131.      getuser (user);
  132.      getuserdir();
  133.  
  134.      /* make sure we are superuser */
  135.      asetuid (0);
  136.  
  137.      /* is this a local delivery by uucp? */
  138.      if ((strnucmp (argv[1], "D.", 2) == 0)
  139.           && (strchr (address, '!') == NULL)
  140.           && (strchr (address, '@') == NULL))
  141.        {
  142.           strcpy (user, "uucp");
  143.        }
  144.      else if (*user == '\0')
  145.        {
  146.           sprintf (temp, "user '%s' not in password file", user);
  147.           logerror (temp);
  148.           bouncemail (file, UNKWNUSER);
  149.        }
  150.  
  151.      /* Validate address, adding missing net information if address is
  152.         unparsable or to a nonexistent user, BOUNCE! */
  153.  
  154.      if (validaddr() == FALSE)
  155.           bouncemail (file, UNKWNSITE);
  156.  
  157.      /* local or remote delivery? */
  158.      if ((strchr (address, '!') != NULL) || (strchr (address, '@') != NULL))
  159.        {
  160.           free (userdir);
  161.           delivered = doremote (file);
  162.        }
  163.      else
  164.           delivered = dolocal (file);
  165.  
  166.      /* if we can't deliver the mail, return it to the sender */
  167.      if (delivered == UNDELIVERED)
  168.           bouncemail (file, UNKWNSITE);
  169.      else
  170.           fclose (file);
  171.  
  172.      closelog();
  173.      exit (delivered);
  174. }
  175.  
  176.  
  177.  
  178. int who_owns_the (file)
  179. FILE *file;
  180. {
  181.      struct fildes buffer;
  182.  
  183.      _gs_gfd (file->_fd, &buffer, sizeof (buffer));
  184. #ifndef _OSK
  185.      return ((int) buffer.fd_own);
  186. #else
  187.      return (atoi (buffer.fd_own));
  188. #endif
  189. }
  190.  
  191.  
  192.  
  193. int getuserdir()
  194. {
  195.      register char *p;
  196.  
  197.      if (strrchr (homedir, '/') == NULL)
  198.        {
  199.           closelog();
  200.           exit (UNDELIVERED);
  201.        }
  202.  
  203.      /* determine if there are two '/'s in the path */
  204.      if ((p = strchr (homedir, '/')) != NULL  &&  strchr (p+1, '/') != NULL)
  205.        {
  206.           p = strrchr (homedir, '/');
  207.           *p = '\0';
  208.        }
  209.      userdir = strdup (homedir);
  210.  
  211.      if (userdir == NULL)
  212.        {
  213.           closelog();
  214.           exit (UNDELIVERED);
  215.        }
  216.      *p = '/';
  217. }
  218.  
  219.  
  220.  
  221. /* validate the address */
  222.  
  223. int validaddr()
  224. {
  225.      char *p;
  226.      flag bang;
  227.      FILE *fp;
  228.      register char *b = strchr (address, '!');   /* Bang */
  229.      char *a = strrchr (address, '@');           /* At   */
  230.      char *c = strchr (address, '%');    /* user%mynode.uucp@somewhere.else */
  231.  
  232.      /* local mail hiding as remote mail or mail passing through */
  233.  
  234.      if (b)
  235.        {
  236.           bang = TRUE;
  237.           *b = '\0';
  238.        }
  239.      else
  240.           bang = FALSE;
  241.  
  242.      /* Handle user%ournode.uucp@someplace.else or user%ournode@someplace.
  243.         This just rewrites those as user.  This may be somewhat a hack, but it
  244.         is useful for those who don't have a proper domain name.  I suspect
  245.         that this rewrite might not actually be needed, as the receiving uucp
  246.         site should relay the message back.  --BAS  */
  247.  
  248.      if (c)
  249.        {
  250.           int nodelen = strlen (nodename);
  251.  
  252.           if (strnucmp (c+1, nodename, nodelen) == 0)
  253.                if (( *(c+1+nodelen) == '@') ||
  254.                    (strnucmp (c+1+nodelen,".uucp@",6) == 0))
  255.                  {
  256.                     *c = '\0';
  257.                     return (TRUE);
  258.                  }
  259.        }
  260.  
  261.      /* user@ournode.domain  or  ournode!user */
  262.      if ((a  &&  (strucmp ((a+1), nodename) == 0
  263.                   || strucmp ((a+1), sitename) == 0)) 
  264.           || (bang && (strucmp (address, nodename) == 0
  265.                   || strucmp (address, sitename) == 0)))
  266.        {
  267.           /* put ! back if it was there before */
  268.           if (bang)
  269.                *b = '!';
  270.  
  271.           *a = '\0';
  272.  
  273.           /* remove any leading !s, we know it goes here */
  274.           if ((p = strrchr (address, '!')) != NULL)
  275.                strcpy (address, (p+1));
  276.  
  277.           if (fixpercent (address)  &&  a)
  278.                *a = '\0';
  279.  
  280.           a = strrchr (address, '@');
  281.           b = strchr (address, '!');
  282.        }
  283.      else
  284.        {
  285.           /* put ! back if it was there before */
  286.           if (bang)
  287.                *b = '!';
  288.         }
  289.  
  290.      /* local mail */
  291.      if (!b  &&  !a)
  292.        {
  293.           /* mail to "nobody" == bit bucket or for the file server? */
  294.           if (strucmp (address, "nobody") == 0
  295.               || strucmp (address, "fileserv") == 0
  296.               || strucmp (address, "mail-server") == 0)
  297.             {
  298.                return (TRUE);
  299.             }
  300.  
  301.           /* if local user has a forward file, forward the mail there */
  302. #ifdef _OSK
  303.           sprintf (fname, "%s/%s/%s", userdir, address, _FRWRD);
  304. #else
  305.           sprintf (fname, "%s/%s/%s/%s", userdir, address, uudir, _FRWRD);
  306. #endif
  307.           if ((fp = fopen (fname, "r")) != NULL)
  308.                if (mfgets (address, sizeof (address), fp) != NULL)
  309.                     return ( validaddr() );
  310.  
  311.           if (doalias (address))
  312.                return ( validaddr() );
  313.  
  314.           return (validuser (address));
  315.        }
  316.  
  317.      /* poorly formed address */
  318.      else if (a  &&  b > a)
  319.           return (FALSE);
  320.  
  321.      /* UUCP-style beginning
  322.         address in form:  site!site2!user or domain2.domain1!site!user  */
  323.  
  324.      else if (b)
  325.        {
  326.           /* Get 1st node to send to */
  327.           *b = '\0';
  328.           strcpy (line, address);
  329.           *b = '!';
  330.  
  331.           /* Strip off leading "nodename!" if addressed to our node.  Check
  332.              to see if the address is aliased. */
  333.  
  334.           if ((strucmp (line, nodename) == 0)
  335.                || (strucmp (line, sitename) == 0))
  336.             {
  337.                strcpy (address, strcpy (line, (b + 1)));
  338.                doalias (address);
  339.                return (validaddr());
  340.             }
  341.  
  342.           /* domain address?  use leftmost domain as node */
  343.           if ((p = strchr (line, '.')) != NULL)
  344.                *p = '\0';
  345.  
  346.           /* do we talk directly to them? */
  347.           if (findent (line, SYSTEMS, line2, sizeof (line2)) == TRUE)
  348.                strcat (line, b);
  349.           else
  350.                /* no, we need to prepend the UUCP smarthost address */
  351.                strcat (strcpy (line, uucphost), address);
  352.        }
  353.  
  354.      /* internet address or bitnet address to be internet-ized.  Address
  355.         arrives in the form:
  356.             user@domain2.domain1, user%domain2.domain1@node, or user@node
  357.         which becomes 'user@node.bitnet'. */
  358.  
  359.      else if (((p = strchr (a, '.')) != NULL)  ||  (*bithost == '\0'))
  360.        {
  361.           if (!p  &&  *bithost == '\0')
  362.                strcat (address, ".bitnet");
  363.  
  364.           *a++ = '\0';
  365.           strcpy (line, a);
  366.  
  367.           /* Strip off '@nodename' if addressed to our node.
  368.              Check to see if address is aliased. */
  369.  
  370.           if ((strucmp (line, nodename) == 0)
  371.                 || (strucmp (line, sitename) == 0))
  372.             {
  373.                fixpercent (address);
  374.                strcpy (address, strcpy (line, address));
  375.                doalias (address);
  376.                return (validaddr());
  377.             }
  378.  
  379.           /* use leftmost domain as node */
  380.           *p = '\0';
  381.           strcpy (line, a);
  382.  
  383.           /* do we talk directly to them? */
  384.           if (findent (line, SYSTEMS, line2, sizeof (line2)) == TRUE)
  385.             {
  386.                fixpercent (address);
  387.                sprintf (line, "%s!%s", a, address);
  388.             }
  389.           else
  390.             {
  391.                /* need to prepend our internet host address */
  392.                *p = '.';
  393.                *--a = '@';
  394.                strcat (strcpy (line, inhost), address);
  395.             }
  396.        }
  397.  
  398.      /* bitnet address */
  399.      else
  400.           strcat (strcpy (line, bithost), address);
  401.  
  402.      strcpy (address, line);
  403.      return (TRUE);
  404. }
  405.  
  406.  
  407.  
  408. /* Deal with internet '%'.  Changes rightmost '%' in 'string' to '@' if
  409.    found and returns TRUE; otherwise returns FALSE. */
  410.  
  411. int fixpercent (string)
  412. char *string;
  413. {
  414.      register char *p;
  415.  
  416.      if ((p = strrchr (string, '%')) != NULL)
  417.        {
  418.           *p = '@';
  419.           return (TRUE);
  420.        }
  421.      return (FALSE);
  422. }
  423.  
  424.  
  425.  
  426. /* dolocal  --local mail delivery
  427.  
  428.               Returns DELIVERED if delivery was successful.  UNDELIVERED if
  429.               delivery failed. */
  430.  
  431. int dolocal (file)
  432. FILE *file;
  433. {
  434.      char mailbox[256], envelop[16];
  435.      struct sgtbuf tod;
  436.      register FILE *mailfile;
  437.      FILE *mail_list;
  438.      char *ptmp;
  439.      long linecount, msgsize, movemail();
  440.  
  441.      /* mail for user 'nobody', it goes in the bit bucket */
  442.      if (strucmp (address, "nobody") == 0)
  443.           return (DELIVERED);
  444.  
  445.      /* be sure we are super user */
  446.      asetuid (0);
  447.  
  448.      /* If sent to user 'fileserv' fork the fileserver program. */
  449.      if (strucmp (address, "fileserv") == 0)
  450.           return (forkfileserv (file));
  451.  
  452.      /* If sent to user 'mail-server' fork a program named 'mailserver'.
  453.  
  454.         Currently, 'mailserver' does not exit.  This pseudo-user is provided
  455.         for those who wish to write their own application software to
  456.         interface with UUCP mail.  The only requirement is that the
  457.         application read its standard input; for the entire message, header
  458.         and all, will be piped to it.  It is up to the application to
  459.         deal with the message.
  460.  
  461.         No error is returned if the mailserver program cannot be forked.  The
  462.         message is silently discarded.
  463.  
  464.         The next version of RMail will allow for multiple psuedo-users
  465.         applications.  Each need only read their standard input for the
  466.         message. */
  467.  
  468.      if (strucmp (address, "mail-server") == 0)
  469.           return (forkmailserver (file));
  470.  
  471.      /* get forwarding, if any */
  472. #ifdef _OSK
  473.      sprintf (fname, "%s/.%s", userdir, address);
  474. #else
  475.      sprintf (fname, "%s/%s/%s", userdir, uudir, address);
  476. #endif
  477.  
  478.      if ((mailfile = fopen (fname, "r")) != NULL)
  479.        {
  480.           register char *p;
  481.  
  482.           if (mfgets (temp, 30, mailfile) == NULL)
  483.             {
  484.                sprintf (line2, "dolocal: empty forwarding file: %s", fname);
  485.                logerror (line2);
  486.                return (UNDELIVERED);
  487.             }
  488.  
  489.           strcpy (address, temp);
  490.           fclose (mailfile);
  491.  
  492.           /* If forwarded to a news gateway, post to local news group.
  493.              Gatewaying to worldwide newsgroups would invite abuses (it's not
  494.              in the proper format to be posted, anyway) */
  495.  
  496.           sprintf (temp, "%s.", nodename);
  497.  
  498.           if ((strncmp (address, temp, strlen (temp)) == 0)
  499.                || (strncmp (address, "local.", 6) ==0))
  500.             {
  501.                return (gateway (file, filename, address));
  502.             }
  503.        }
  504.  
  505.      /* Look for the environment MAIL.  If that doesn't exist, look in the
  506.         the Parameters file for the 'maildir' parameter. */
  507.  
  508.      if ((maildir = getenv ("MAIL")) != NULL)
  509.           maildir = strdup (maildir);
  510.      else if ((maildir = getdirs ("maildir")) == NULL)
  511.           fatal ("MAIL undefined");
  512.  
  513.      /* change to user's mailbox directory */
  514.      sprintf (mailbox, "%s/%s", maildir, address);
  515.  
  516. #ifdef DEBUG
  517.      sprintf (line2, "dolocal: changing to mailbox: %s", mailbox);
  518.      logerror (line2);
  519. #endif
  520.  
  521.      if (chdir (mailbox) == ERROR)
  522.        {
  523.           sprintf (line2, "dolocal: can't change to mailbox: %s", mailbox);
  524.           fatal (line2);
  525.        }
  526.  
  527.      /* Create the envelope.  Account for new millenium in case this code is
  528.         is still being used after 1999. :-) */
  529.  
  530.      getime (&tod);
  531.      sprintf (envelop, "m%02d%02d%02d%02d%02d%02d%02d",
  532.                        (tod.t_year >= 92) && (tod.t_year <= 99)  ? 19  : 20,
  533.                        tod.t_year, tod.t_month, tod.t_day, tod.t_hour,
  534.                        tod.t_minute, tod.t_second);
  535.  
  536.      /* new line for letterfile */
  537.      memset (mailstring, '\0', sizeof (mailstring));
  538.      sprintf (mailstring, "N%s|", envelop);
  539.  
  540.      /* set uid to that of recipient */
  541.      asetuid (validuid);
  542.  
  543.      /* put the envelop in the mailbox */
  544.      if ((mailfile = fopen (envelop, "w")) == NULL)
  545.        {
  546.           sprintf (line2, "dolocal: can't put letter in mailbox: %s",
  547.                           address);
  548.           fatal (line2);
  549.        }
  550.  
  551.      /* open letter list for updating */
  552.      if ((mail_list = fopen ("mail..list", "a")) == NULL)
  553.        {
  554.           sprintf (line2, "dolocal: can't update mail..list file with: %s",
  555.                           envelop);
  556.           fatal (line2);
  557.        }
  558.  
  559.      fixperms (mailfile);
  560.  
  561.      /* move the mail message */
  562.      linecount = movemail (file, mailfile, TRUE);
  563.  
  564.      /* If the file size is 0 or we can't get the size, something got trashed.
  565.         Delete the letter file and report the letter as undeliverable. */
  566.  
  567.      if ((msgsize = _gs_size (fileno (mailfile))) <= 0)
  568.        {
  569.           fclose (mailfile);
  570.           fclose (mail_list);
  571.           unlink (envelop);
  572.           exit (UNDELIVERED);
  573.        }
  574.  
  575.      /* update the mail..list */
  576.      fputs (mailstring, mail_list);
  577.  
  578. #ifndef _OSK
  579.      fprintf (mail_list, "|%ld|%ld\n", linecount, msgsize);
  580. #else
  581.      fprintf (mail_list, "|%d|%d\n", (int) linecount, msgsize);
  582. #endif
  583.      fclose (mailfile);
  584.      fclose (mail_list);
  585.      return (DELIVERED);
  586. }
  587.  
  588.  
  589.  
  590. /* doremote  --queue job for remote mail delivery  */
  591.  
  592. int doremote (file)
  593. FILE *file;
  594. {
  595.      char cname[15], xname[14], dname[14], jname[14], seq[5];
  596.      register FILE *qfile;
  597.      char *p;
  598.      long movemail();
  599.  
  600.      /* parse system and address...if a bad address, bounce it back */
  601.      if ((p = strchr (address, '!')) == NULL)
  602.           return (UNDELIVERED);
  603.  
  604.      *p++ = '\0';
  605.  
  606.      /* Now p points to recipient name, address points to system.  Go to
  607.         proper spool directory.  If we can't change to the spool directory, we
  608.         don't talk to this site so bounce the mail. */
  609.  
  610.      if ((spooldir = getdirs ("spooldir")) == NULL)
  611.           fatal ("spooldir not in Parameters");
  612.  
  613.      sprintf (line, "%s/%s", spooldir, address);
  614.  
  615. #ifdef DEBUG
  616.      sprintf (line2, "doremote: spooldir = %s\n", line);
  617.      logerror (line2);
  618. #endif
  619.  
  620.      asetuid (0);
  621.      if (chdir (line) == ERROR)
  622.        {
  623.           sprintf (line2, "doremote: can't change to spool directory: %s",
  624.                           address);
  625.           fatal (line2);
  626.        }
  627.  
  628.      /* get a unique ID for the work files */
  629.      strcpy (seq, genseq());
  630.  
  631.      /* Figure out all the file names.  To be compatible with other UUCPs,
  632.         system names are truncated to 7 characters. */
  633.  
  634.      /* D.sysnameXXXX filename (mail data file) */
  635.      sprintf (dname, "D.%.7s%s", nodename, seq);
  636.  
  637.      /* D.sysnameXXXX file (job file) */
  638.      sprintf (jname, "D.%.7s%s", address, seq);
  639.  
  640.      /* C.sysnameCXXXX (control file) */
  641.      sprintf (cname, "C.%.7sC%s", address, seq);
  642.  
  643.      /* X.sysnameXXXX (execute file) */
  644.      sprintf (xname, "X.%.7s%s", address, seq);
  645.  
  646.      /* write mail to mail data file */
  647.      asetuid (0);
  648.      if ((qfile = fopen (dname, "w")) == NULL)
  649.           fatal ("doremote: can't create data (D.<ournode>) file");
  650.  
  651.      /* make file secure and change ownership to sender */
  652.      fixperms (qfile);
  653.      chown (dname, fileowner);
  654.  
  655.      /* move the mail message */
  656.      movemail (file, qfile, FALSE);
  657.  
  658.      if (_gs_size (fileno (qfile)) <= 0)
  659.        {
  660.           fclose (qfile);
  661.           unlink (qfile);
  662.           fatal ("doremote: error writing data (D.) file");
  663.        }
  664.  
  665.      fclose (qfile);
  666.  
  667.      /* write job file */
  668.      if ((qfile = fopen (jname, "w")) == NULL)
  669.        {
  670.           unlink (dname);
  671.           fatal ("doremote: can't create job (D.<remote>) file");
  672.        }
  673.  
  674.      /* make file secure and change ownership to sender */
  675.      fixperms (qfile);
  676.      chown (jname, fileowner);
  677.      fprintf (qfile, "U %s %s\x0A", user, nodename);
  678.      fprintf (qfile, "F %s\x0A", dname);
  679.      fprintf (qfile, "I %s\x0A", dname);
  680.      fprintf (qfile, "C rmail %s \x0A", p);
  681.      fclose (qfile);
  682.  
  683.      /* write control file */
  684.      if ((qfile = fopen (cname, "w")) == NULL)
  685.        {
  686.           unlink (dname);
  687.           unlink (jname);
  688.           fatal ("doremote: can't open control (C.<remote>) file");
  689.        }
  690.  
  691.      /* make file secure and change ownership to sender */
  692.      fixperms (qfile);
  693.      chown (cname, fileowner);
  694.      fprintf (qfile, "S %s %s %s - %s 0666 %s\n",
  695.                       dname, dname, user, dname, user);
  696.  
  697.      fprintf (qfile, "S %s %s %s - %s 0666 %s\n",
  698.                       jname, xname, user, jname, user);
  699.      fclose (qfile);
  700.      return (DELIVERED);
  701. }
  702.  
  703.  
  704.  
  705. long movemail (file, mailfile, islocal)
  706. FILE *file, *mailfile;
  707. flag islocal;
  708. {
  709.      char neighbor[40], addr[256], subj[SUBJSIZE], frm[FRMSIZE];
  710.      register char *words[WORDSIZE];
  711.      char crlf, *strpbrk(), *grabfrom();
  712.      flag weorig;
  713.      int n;
  714.      long linecount, forwardseq();
  715.  
  716.      /* processing local or remote mail? */
  717.      crlf = islocal  ? '\x0D' : '\x0A';
  718.  
  719.      /* Collapse all From & >From lines to a single line only final From line
  720.         will contain valid username. */
  721.  
  722.      *addr = *neighbor = '\0';
  723.      getline (file, line);
  724.  
  725.      while (((n = findstr (1, line, "From ")) <= 2)  &&  (n > 0))
  726.        {
  727.           strcpy (line2, line);
  728.           n = getargs (words, line2, WORDSIZE);
  729.  
  730.           if (*addr != '\0')
  731.                strcat (addr, "!");
  732.  
  733.           if (findstr (1, line, " remote from ") != 0)
  734.             {
  735.                if (*neighbor == '\0')
  736.                     strcpy (neighbor, words[n - 1]);
  737.  
  738.                /* Did we get a valid address, or a munged attempt? */
  739.                if (findstr (1, *(words + 1), "uucp") != 0)
  740.                     strcat (strcpy (line, addr), words[n - 1]);
  741.                else
  742.                     sprintf (line, "%s%s!%s",
  743.                                    addr, words[n - 1], words[1]);
  744.             }
  745.           else
  746.                strcat (strcpy (line, addr), words[1]);
  747.  
  748.           strcpy (addr, line);
  749.           getline (file, line);
  750.        }
  751.  
  752.      /* Add this only if outgoing. */
  753.      if (!islocal)
  754.           sprintf (line2, " remote from %s", nodename);
  755.      else
  756.           *line2 = '\0';
  757.  
  758.      fprintf (mailfile, "%sFrom %s %s%s%c",
  759.                         islocal ? ">" : "",
  760.                         addr, date822(), line2, crlf);
  761.  
  762.      /* did we originate mail? */
  763.      if (strpbrk (words[1], "!@%") == NULL   &&  *neighbor == '\0')
  764.           weorig = TRUE;
  765.      else
  766.           weorig = FALSE;
  767.  
  768.      /* If mail is not between users on this system, add:
  769.  
  770.         Received: [from someone@this.site] by our.site (RMail OS-9 UUCP)
  771.                 id <AA12345@our.site>; Wed, 15 Sep 93 07:41 -0400  */
  772.  
  773.      if (!islocal || (islocal && !weorig))
  774.        {
  775.           if (*neighbor != '\0')
  776.                sprintf (line2, " from %s", neighbor);
  777.           else
  778.                *line2 = '\0';
  779.  
  780. #ifndef _OSK
  781.           fprintf (mailfile, "Received:%s by %s (RMail OS-9 UUCP)%c",
  782. #else
  783. # ifndef _OS9K
  784.           fprintf (mailfile, "Received:%s by %s (RMail OS-9/68K UUCP)%c",
  785. # else
  786.           fprintf (mailfile, "Received:%s by %s (RMail OS-9000 UUCP)%c",
  787. # endif
  788. #endif
  789.                              line2, sitename, crlf);
  790.  
  791.           fprintf (mailfile, "\tid <AA%05ld@%s>; %s%c",
  792.                              forwardseq (weorig), sitename, date822(), crlf);
  793.        }
  794.  
  795.      /* copy the rest of header */
  796.      *frm = *subj = '\0';
  797.      do
  798.        {
  799.           flag gotfrom = FALSE, gotsubj = FALSE;
  800.  
  801.           if (islocal)
  802.                if (*line == 'F'  &&  !gotfrom)
  803.                  {
  804.                     if (strnucmp (line, "From: ", 6) == 0)
  805.                       {
  806.                          strncpy0 (frm, grabfrom (line), FRMSIZE);
  807.                          gotfrom = TRUE;
  808.                       }
  809.                  }
  810.                else if (*line == 'S'  &&  !gotsubj)
  811.                     if (strnucmp (line, "Subject: ", 9) == 0
  812.                          ||  strnucmp (line, "Subj: ", 6) == 0)
  813.                       {
  814.                          int len;
  815.  
  816.                          strncpy0 (subj, getstring (line), SUBJSIZE);
  817.                          gotsubj = TRUE;
  818.                       }
  819.           fprintf (mailfile, "%s%c", line, crlf);
  820.  
  821.           if (*line == '\0')
  822.                break;
  823.        }
  824.      while (getline (file, line) != -1);
  825.  
  826.      /* copy rest of message body unchanged */
  827.      linecount = 0;
  828.      while (getline (file, line) != -1)
  829.        {
  830.           fprintf (mailfile, "%s%c", line, crlf);
  831.           ++linecount;
  832.        }
  833.  
  834.      /* Add From: and Subject: to mail..list line, if local delivery */
  835.      if (islocal)
  836.        {
  837.           sprintf (line, "%s|%s", 
  838.                          *frm != '\0' ? frm : " ",
  839.                          *subj != '\0' ? subj : " ");
  840.  
  841.           strcat (mailstring, line);
  842.        }
  843.      fflush (mailfile);
  844.      return (linecount);
  845. }
  846.  
  847.  
  848.  
  849. /* Return pointer to real name or address if no real name in From: line */
  850.  
  851. char *grabfrom (fromline)
  852. char *fromline;
  853. {
  854.      register char *p;
  855.  
  856.      p = getrealname (fromline);
  857.  
  858.      if (*p == '\0')
  859.           p = getval (fromline);
  860.  
  861.      return (p);
  862. }
  863.  
  864.  
  865.  
  866. long forwardseq (weorig)
  867. flag weorig;
  868. {
  869.      char buf[7];
  870.      FILE *fp;
  871.      long sequence, atol();
  872.  
  873.      /* mail originates with us, repeat the message-id number */
  874.      if (weorig)
  875.        {
  876.           if ((fp = fopen (MAILSEQ, "r")) == NULL)
  877.                return (1L);
  878.  
  879.           mfgets (buf, sizeof (buf), fp);
  880.           return (atol (buf));
  881.        }
  882.  
  883.      /* didn't originate with us, give a consecutive id number */
  884.      sprintf (fname, "%s/sequence.rmail", UUCPSYS);
  885.  
  886.      if ((fp = fopen (fname, "r")) == NULL)
  887.        {
  888.           if ((fp = fopen (fname, "w")) == NULL)
  889.               return (1L);
  890.  
  891.           fputs ("1\n", fp);
  892.           sequence = 1;
  893.        }
  894.      else
  895.        {
  896.           mfgets (buf, sizeof (buf), fp);
  897.           fclose (fp);
  898.           sequence = atol (buf) + 1;
  899.  
  900.           /* wrap around above 99,9999 */
  901.           if (sequence > 99999)
  902.                sequence = 1;
  903.  
  904.           if ((fp = fopen (fname, "w")) != NULL)
  905. #ifndef _OSK
  906.                fprintf (fp, "%ld\n", sequence);
  907. #else
  908.                fprintf (fp, "%d\n", sequence);
  909. #endif
  910.           else
  911.                return (sequence);
  912.  
  913.           return (sequence);
  914.        }
  915.      fixperms (fp);
  916.      fclose (fp);
  917.      return (sequence);
  918. }
  919.  
  920.  
  921.  
  922. int gateway (file, filename, newsgroup)
  923. FILE *file;
  924. char *filename, *newsgroup;
  925. {
  926.      fclose (file);
  927.      sprintf (temp, "rnews -n%s %s", newsgroup, filename);
  928.      system (temp);
  929.      unlink (filename);
  930.      return (DELIVERED);
  931. }
  932.  
  933.  
  934.  
  935. int forkfileserv (fp)
  936. FILE *fp;
  937. {
  938.      register char *p;
  939.      int count;
  940.      FILE *pipe;
  941.  
  942.      p = line2;
  943.  
  944.      if ((pipe = popen ("fileserv", "w")) == NULL)
  945.        {
  946.           logerror ("forkfileserv: can't open pipe to FILESERV");
  947.           return (UNDELIVERED);
  948.        }
  949.  
  950.      closelog();
  951.  
  952.      while ((count = fread (p, sizeof (char), sizeof (line2), fp)) != 0)
  953.           fwrite (p, sizeof (char), count, pipe);
  954.  
  955.      pclose (pipe);
  956.      return (DELIVERED);
  957. }
  958.  
  959.  
  960.  
  961. /* We always report success, even if we can't fork the program mailserver. */
  962.  
  963. int forkmailserver (fp)
  964. FILE *fp;
  965. {
  966.      register char *p;
  967.      int count;
  968.      FILE *pipe;
  969.  
  970.      p = line2;
  971.      if ((pipe = popen ("mailserver", "w")) != NULL)
  972.        {
  973.           closelog();
  974.  
  975.           while ((count = fread (p, sizeof (char), sizeof (line2), fp)) != 0)
  976.                fwrite (p, sizeof (char), count, pipe);
  977.  
  978.           pclose (pipe);
  979.        }
  980.      return (DELIVERED);
  981. }
  982.  
  983.  
  984.  
  985. /* For now all bounced mail gets sent to the 'errorsto' user. They will have
  986.    manually return it to the sender. */
  987.  
  988. int bouncemail (file, reason)
  989. FILE *file;
  990. int reason;
  991. {
  992.      /* Global string 'address' already has errorsto user name.  validuid
  993.         already has errorsto's UID.  */
  994.  
  995.      dolocal (file);
  996.      closelog();
  997.      exit (0);
  998. }
  999.  
  1000.  
  1001.  
  1002. /* Open the uulog file if we can.  The directory it is in is given by the
  1003.    environment variable LOGDIR.  If we can't open uulog, write to the standard
  1004.    error path instead. */
  1005.  
  1006. void openlog()
  1007. {
  1008.      if (logopen)
  1009.           return;
  1010.  
  1011.      strcat (strcpy (fname, logdir), "/uulog");
  1012.  
  1013.      if ((log = fopen (fname, "a")) != NULL)
  1014.        {
  1015.           setbuf (log, NULL);
  1016.           logopen = TRUE;
  1017.        }
  1018.      else
  1019.           log = stderr;
  1020. }
  1021.  
  1022.  
  1023.  
  1024. /* Close the uulog file if it was opened. */
  1025.  
  1026. void closelog()
  1027. {
  1028.      if (log == stderr)
  1029.           return;
  1030.  
  1031.      if (logopen)
  1032.           fclose (log);
  1033.  
  1034.      logopen = FALSE;
  1035. }
  1036.  
  1037.  
  1038.  
  1039. /* Log an error message */
  1040.  
  1041. void logerror (msg)
  1042. char *msg;
  1043. {
  1044.      openlog();
  1045.  
  1046.      if (logopen)
  1047.           fprintf (log, "rmail %s %s %s%s\n",
  1048.                         *nodename != '\0'  ? nodename : "uucp",
  1049.                         gtime(), errmsg, msg);
  1050.      else
  1051.           fprintf (stderr, "rmail: %s\n", msg);
  1052.  
  1053.      closelog();
  1054. }
  1055.  
  1056.  
  1057.  
  1058. /* exit with error if we receive a signal */
  1059.  
  1060. int interrupt (sig)
  1061. int sig;
  1062. {
  1063.      closelog();
  1064.      exit (ABORT);
  1065. }
  1066.  
  1067.  
  1068.  
  1069. int fatal (msg)
  1070. char *msg;
  1071. {
  1072.      fprintf (stderr, "rmail: %s", msg);
  1073.  
  1074.      if (logopen)
  1075.           fprintf (log, "rmail %s %s %s%s", nodename, gtime(), errmsg, msg);
  1076.  
  1077.      if (errno != 0)
  1078.        {
  1079.           sprintf (fname, "...error #%d", errno);
  1080.  
  1081.           if (logopen)
  1082.                fputs (fname, log);
  1083.  
  1084.           fputs (fname, stderr);
  1085.        }
  1086.  
  1087.      if (log != NULL)
  1088.           putc ('\n', log);
  1089.  
  1090.      putc ('\n', stderr);
  1091.      closelog();
  1092.      exit (UNDELIVERED);
  1093. }
  1094.  
  1095.  
  1096.  
  1097. void errorexit (sig)
  1098. int sig;
  1099. {
  1100.      closelog();
  1101.      exit (sig);
  1102. }
  1103.  
  1104.  
  1105.  
  1106. int usage()
  1107. {
  1108.      fputs ("usage: rmail [file] \"site!user[@site]\"\n\n", stderr);
  1109.      fprintf (stderr, "v%s (%s) This is free software released under the GNU General Public\n",
  1110.                       version, VERDATE);
  1111.      fputs ("License.  Please send suggestions/bug reports to:  bob@kc2wz.bubble.org\n", stderr);
  1112.      exit (0);
  1113. }
  1114.