home *** CD-ROM | disk | FTP | other *** search
/ ARM Club 3 / TheARMClub_PDCD3.iso / hensa / internet / tcpip / src205 / TCPIP_Src / SMTP / c / smtpserv < prev   
Encoding:
Text File  |  1995-04-24  |  20.9 KB  |  896 lines

  1. /* SMTP Server state machine - see RFC 821
  2.  *  enhanced 4/88 Dave Trulli nn2z
  3.  */
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <time.h>
  8. #include <ctype.h>
  9. #include "global.h"
  10. #include "mbuf.h"
  11. #include "netuser.h"
  12. #include "timer.h"
  13. #include "tcp.h"
  14. #include "smtp.h"
  15. #include "misc.h"
  16. #include "bbc.h"
  17.  
  18. static void s_mail(struct tcb *, char, char);
  19. static void r_mail(struct tcb *, int);
  20. static void doline(struct mail *);
  21. static struct mail *mail_create(struct tcb *);
  22. static void mail_delete(struct mail *);
  23. static void docommand(struct mail *);
  24. static char *getname(char *);
  25. static void deliver(struct mail *);
  26.  
  27. int inourdomain(char *host);
  28.  
  29. /* Command table */
  30. static char *commands[] = {
  31.   "helo",
  32. #define HELO_CMD        0
  33.   "noop",
  34. #define NOOP_CMD        1
  35.   "mail from:",
  36. #define MAIL_CMD        2
  37.   "quit",
  38. #define QUIT_CMD        3
  39.   "rcpt to:",
  40. #define RCPT_CMD        4
  41.   "help",
  42. #define HELP_CMD        5
  43.   "data",
  44. #define DATA_CMD        6
  45.   "rset",
  46. #define RSET_CMD        7
  47.   NULLCHAR
  48. };
  49.  
  50. /* Reply messages */
  51. static char help[]     = "214-Commands:\r\n214-HELO NOOP MAIL QUIT RCPT HELP DATA RSET\r\n214 End\r\n";
  52. static char banner[]   = "220 %s - SMTP ready\r\n";
  53. static char banner2[]  = "220 %s, Greetings %s - SMTP ready\r\n";
  54. static char closing[]  = "221 Closing\r\n";
  55. static char ok[]       = "250 OK\r\n";
  56. static char reset[]    = "250 Reset state\r\n";
  57. static char sent[]     = "250 Sent\r\n";
  58. static char ourname[]  = "250 %s, Share and Enjoy!\r\n";
  59. static char ourname2[] = "250 %s, Suffering from an identity crisis are we?\r\n";
  60. static char enter[]    = "354 Enter mail, end with . on its own\r\n";
  61. static char ioerr[]    = "452 Temp file write error\r\n";
  62. static char mboxerr[]  = "452 Mailbox write error\r\n";
  63. static char badcmd[]   = "500 Command unrecognized\r\n";
  64. static char syntax[]   = "501 Syntax error\r\n";
  65. static char needrcpt[] = "503 Need RCPT (recipient)\r\n";
  66. static char unknown[]  = "550 <%s> address unknown\r\n";
  67.  
  68. static struct tcb *smtp_tcb;
  69. /* Start up SMTP receiver service */
  70. int smtp1(int argc, char **argv)
  71. {
  72.   struct socket lsocket;
  73.  
  74.   lsocket.address = ip_addr;
  75.   if(argc < 2)
  76.     lsocket.port = SMTP_PORT;
  77.   else
  78.       lsocket.port = atoi(argv[1]);
  79.  
  80.   smtp_tcb = open_tcp(&lsocket,NULLSOCK,
  81.   TCP_SERVER,0,(void(*)())r_mail,NULLVFP,(void(*)())s_mail,0,(char *)NULL);
  82.   return(0);
  83. }
  84.  
  85. /* Shutdown SMTP service (existing connections are allowed to finish) */
  86. int smtp0(void)
  87. {
  88.   if(smtp_tcb != NULLTCB)
  89.     close_tcp(smtp_tcb);
  90.   return(0);
  91. }
  92.  
  93. /* SMTP connection state change upcall handler */
  94. static void s_mail(struct tcb *tcb, char old, char new)
  95. {
  96.   struct mail *mp;
  97.  
  98.   old = old;
  99.  
  100.   switch(new)
  101.   {
  102. #ifdef  QUICKSTART
  103.   case SYN_RECEIVED:
  104. #else
  105.   case ESTABLISHED:
  106. #endif
  107.     if((mp = mail_create(tcb)) == NULLMAIL)
  108.     {
  109.       close_tcp(tcb);
  110.       break;
  111.     }
  112.     {
  113.       char *nmebuf;
  114.       nmebuf = inet_ntoa(mp->tcb->conn.remote.address);
  115.       rip(nmebuf);
  116.       mp->system = NULL;
  117.       if (!isdigit(*nmebuf))
  118.       {
  119.         if (mp->system = (char *)malloc(strlen(nmebuf)+1), mp->system!=NULL)
  120.           strcpy(mp->system, nmebuf);
  121.       }
  122.     }
  123.     if (mp->system)
  124.       tprintf(mp->tcb,banner2,hostname,mp->system);
  125.     else
  126.       tprintf(mp->tcb,banner,hostname);
  127.     log_event(tcb,"open SMTP");
  128.     break;
  129.   case CLOSE_WAIT:
  130.     close_tcp(tcb);
  131.     break;
  132.   case CLOSED:
  133.     log_event(tcb,"close SMTP");
  134.     mp = (struct mail *)tcb->user;
  135.     mail_delete(mp);
  136.     del_tcp(tcb);
  137.     /* Check if server is being shut down */
  138.     if(tcb == smtp_tcb)
  139.       smtp_tcb = NULLTCB;
  140.     break;
  141.   }
  142. }
  143.  
  144. /* SMTP receiver upcall handler */
  145. static void r_mail(struct tcb *tcb, int cnt)
  146. {
  147.   register struct mail *mp;
  148.   char c;
  149.   struct mbuf *bp;
  150.  
  151.   if((mp = (struct mail *)tcb->user) == NULLMAIL)
  152.   {
  153.     /* Unknown session */
  154.     close_tcp(tcb);
  155.     return;
  156.   }
  157.   recv_tcp(tcb, &bp, cnt);
  158.   /* Assemble an input line in the session buffer.
  159.      Return if incomplete */
  160.   while(pullone(&bp, &c) == 1)
  161.   {
  162.     switch(c)
  163.     {
  164.     case '\r':      /* Strip cr's */
  165.       continue;
  166.  
  167.     case '\n':      /* Complete line; process it */
  168.       mp->buf[mp->cnt++] = '\n';
  169.       mp->buf[mp->cnt] = '\0';
  170.       doline(mp);
  171.       break;
  172.  
  173.     default:        /* Assemble line */
  174.       mp->buf[mp->cnt++] = c;
  175.       if(mp->cnt > LINELEN - 2)
  176.       {
  177.         mp->buf[mp->cnt] = '\0';
  178.         doline(mp);
  179.         mp->cnt = 0;
  180.       }
  181.       break;
  182.     }
  183.   }
  184. }
  185. /* Process a line read on an SMTP connection (any state) */
  186. static void doline(register struct mail *mp)
  187. {
  188.   switch(mp->state)
  189.   {
  190.   case COMMAND_STATE:
  191.     docommand(mp);
  192.     break;
  193.  
  194.   case DATA_STATE:
  195.     tcp_output(mp->tcb);    /* Send ACK; disk I/O is slow */
  196.     if (mp->buf[0] == '.' && mp->buf[1] == '\n' && mp->buf[2] == '\0')
  197.     {
  198.       mp->state = COMMAND_STATE;
  199.       /* Also sends appropriate response */
  200.       deliver(mp);
  201.       fclose(mp->data);
  202.       mp->data = NULLFILE;
  203.       del_list(mp->to);
  204.       mp->to = NULLLIST;
  205.       break;
  206.     }
  207.     /* for UNIX mail compatiblity */
  208.     if (strncmp(mp->buf, "From ", 5) == 0)
  209.       putc('>', mp->data);
  210.     if (strncmp(mp->buf, "..", 2) == 0)
  211.       memmove(&mp->buf[0], &mp->buf[1], strlen(mp->buf));
  212.     /* Append to data file */
  213.     if (fprintf(mp->data, "%s", mp->buf) < 0)
  214.     {
  215.       mp->state = COMMAND_STATE;
  216.       tprintf(mp->tcb, ioerr);
  217.     }
  218.     break;
  219.   }
  220.   mp->cnt = 0;
  221. }
  222. /* Create control block, initialize */
  223. static struct mail *mail_create(register struct tcb *tcb)
  224. {
  225.   register struct mail *mp;
  226.  
  227.   if((mp = (struct mail *)calloc(1,sizeof (struct mail))) == NULLMAIL)
  228.     return NULLMAIL;
  229.   mp->tcb = tcb;          /* Downward pointer */
  230.   tcb->user = (char *)mp; /* Upward pointer */
  231.   return mp;
  232. }
  233.  
  234. /* Free resources, delete control block */
  235. static void mail_delete(register struct mail *mp)
  236. {
  237.  
  238.   if (mp == NULLMAIL)
  239.     return;
  240.   if(mp->system != NULLCHAR)
  241.     free(mp->system);
  242.   if(mp->from != NULLCHAR)
  243.     free(mp->from);
  244.   if(mp->data != NULLFILE)
  245.     fclose(mp->data);
  246.   del_list(mp->to);
  247.   free((char *)mp);
  248. }
  249.  
  250. /* Parse and execute mail commands */
  251. static void docommand(register struct mail *mp)
  252. {
  253.   register char **cmdp,*arg,*cp,*cmd;
  254.   struct list *ap;
  255.   time_t t;
  256.   char address_type;
  257.  
  258.   cmd = mp->buf;
  259.   if (mp->cnt < 4)
  260.   {
  261.     /* Can't be a legal SMTP command */
  262.     log_event(mp->tcb,"SMTP Error - short command \"%s\"", cmd);
  263.     tprintf(mp->tcb,badcmd);
  264.     return;
  265.   }
  266.   cmd = mp->buf;
  267.  
  268.   /* Translate entire buffer to lower case */
  269.   for (cp = cmd; *cp != '\0'; cp++)
  270.     *cp = tolower(*cp);
  271.  
  272.   /* Find command in table; if not present, return syntax error */
  273.   for (cmdp = commands; *cmdp != NULLCHAR; cmdp++)
  274.     if (strncmp(*cmdp,cmd,strlen(*cmdp)) == 0)
  275.       break;
  276.  
  277.   if (*cmdp == NULLCHAR)
  278.   {
  279.     log_event(mp->tcb,"SMTP Error - bad command \"%s\"", cmd);
  280.     tprintf(mp->tcb, badcmd);
  281.     return;
  282.   }
  283.   arg = &cmd[strlen(*cmdp)];
  284.   /* Skip spaces after command */
  285.   while (*arg == ' ')
  286.     arg++;
  287.   /* Execute specific command */
  288.   switch(cmdp-commands)
  289.   {
  290.   case HELO_CMD:
  291. /*
  292.     if (mp->system != NULLCHAR)
  293.       free(mp->system);
  294. */
  295.     rip(arg);
  296.     if (mp->system!=NULL)
  297.     {
  298.       if (stricmp(mp->system, arg))
  299.         tprintf(mp->tcb,ourname2,hostname);
  300.       else
  301.         tprintf(mp->tcb,ourname,hostname);
  302.     }
  303.     else
  304.     {
  305.       if((mp->system = malloc((unsigned)strlen(arg)+1)) == NULLCHAR)
  306.       {
  307.         /* If the system is out of memory, just close */
  308.         close_tcp(mp->tcb);
  309.         break;
  310.       }
  311.       else
  312.       {
  313.         strcpy(mp->system,arg);
  314.         tprintf(mp->tcb,ourname,hostname);
  315.       }
  316.     }
  317.     break;
  318.  
  319.   case NOOP_CMD:
  320.     tprintf(mp->tcb,ok);
  321.     break;
  322.  
  323.   case MAIL_CMD:
  324.     if (mp->from != NULLCHAR)
  325.       free(mp->from);
  326.     if ((mp->from = malloc((unsigned)strlen(arg)+1)) == NULLCHAR)
  327.     {
  328.       /* If the system is out of memory, just close */
  329.       close_tcp(mp->tcb);
  330.       break;
  331.     }
  332.     else
  333.     {
  334.       if((cp = getname(arg)) == NULLCHAR)
  335.       {
  336.         tprintf(mp->tcb,syntax);
  337.         break;
  338.       }
  339.       strcpy(mp->from,cp);
  340.       tprintf(mp->tcb,ok);
  341.     }
  342.     break;
  343.  
  344.   case QUIT_CMD:
  345.     tprintf(mp->tcb,closing);
  346.     close_tcp(mp->tcb);
  347.     break;
  348.  
  349.   case RCPT_CMD:  /* Specify recipient */
  350.     if((cp = getname(arg)) == NULLCHAR)
  351.     {
  352.       tprintf(mp->tcb,syntax);
  353.       break;
  354.     }
  355.  
  356.     /* check if address is ok */
  357.     if ((address_type = validate_address(cp)) == BADADDR)
  358.     {
  359.       tprintf(mp->tcb,unknown, cp);
  360.       break;
  361.     }
  362.     /* if a local address check for an alias */
  363.     if (address_type == LOCAL)
  364.       expandalias(&mp->to, cp);
  365.     else
  366.         /* a remote address is added to the list */
  367.       addlist(&mp->to, cp, address_type);
  368.     tprintf(mp->tcb, ok);
  369.     break;
  370.  
  371.   case HELP_CMD:
  372.     tprintf(mp->tcb,help);
  373.     break;
  374.  
  375.   case DATA_CMD:
  376.     if (mp->to == NULLLIST)
  377.     {
  378.       tprintf(mp->tcb,needrcpt);
  379.       break;
  380.     }
  381.     tcp_output(mp->tcb);    /* Send ACK; disk I/O is slow */
  382.     if((mp->data = tmpfile()) == NULLFILE){
  383.       tprintf(mp->tcb,ioerr);
  384.       break;
  385.     }
  386.     /* Add timestamp; ptime adds newline */
  387.     time(&t);
  388.     fprintf(mp->data, "Received: ");
  389.     if(mp->system != NULLCHAR)
  390.       fprintf(mp->data, "from %s ", mp->system);
  391.     ap = mp->to;
  392.     fprintf(mp->data, "by %s with SMTP\n\tid AA%ld for %s ; %s",
  393.     hostname, get_msgid(), ap->val, ptime(&t));
  394.     if(ferror(mp->data))
  395.     {
  396.       tprintf(mp->tcb,ioerr);
  397.     }
  398.     else
  399.     {
  400.       mp->state = DATA_STATE;
  401.       tprintf(mp->tcb,enter);
  402.     }
  403.     break;
  404.  
  405.   case RSET_CMD:
  406.     del_list(mp->to);
  407.     mp->to = NULLLIST;
  408.     mp->state = COMMAND_STATE;
  409.     tprintf(mp->tcb, reset);
  410.     break;
  411.   }
  412. }
  413. /* Given a string of the form <user@host>, extract the part inside the
  414.  * brackets and return a pointer to it.
  415.  */
  416. static char *getname(register char *cp)
  417. {
  418.   register char *cp1;
  419.  
  420.   if((cp = strchr(cp,'<')) == NULLCHAR)
  421.     return NULLCHAR;
  422.   cp++;   /* cp -> first char of name */
  423.   if((cp1 = strchr(cp,'>')) == NULLCHAR)
  424.     return NULLCHAR;
  425.   *cp1 = '\0';
  426.   return cp;
  427. }
  428.  
  429. /* Deliver mail to the appropriate mail boxes and delete temp file */
  430. static void deliver(register struct mail *mp)
  431. {
  432.   int ret;
  433.  
  434.   /* send to the rqueue */
  435.   if ((smtpmode & QUEUE) != 0)
  436.   {
  437.     ret = router_queue(mp->tcb,mp->data,mp->from,mp->to);
  438.     if (ret != 0)
  439.       tprintf(mp->tcb,ioerr);
  440.   }
  441.   else
  442.   {
  443.     ret = mailit(mp->tcb,mp->data,mp->from,mp->to);
  444.     if (ret != 0)
  445.       tprintf(mp->tcb,mboxerr);
  446.   }
  447.   if (ret == 0)
  448.     tprintf(mp->tcb, sent);
  449. }
  450.  
  451. /* used to save local mail or reroute remote mail */
  452. int mailit(struct tcb *tcb, FILE *data, char *from, struct list *to)
  453. {
  454.   register struct list *ap;
  455.   register FILE *fp;
  456.   int     i,n,c;
  457.   char    mailfile[256];
  458.   char    *cp;
  459.   char    *desthost;
  460.   int     fail = 0;
  461.   time_t  t;
  462.  
  463.   for (ap = to; ap != NULLLIST; ap = ap->next)
  464.   {
  465.     fseek(data, 0L, 0);       /* rewind */
  466.  
  467.     /* non local mail queue it */
  468.     if (ap->type == DOMAIN)
  469.     {
  470.       if ((desthost = strchr(ap->val,'@')) != NULLCHAR);
  471.       desthost++;
  472.       fail = queuejob(tcb, data, desthost, ap->val, from);
  473.     }
  474.     else
  475.     {
  476.       /* strip off host name */
  477.       if ((cp = strchr(ap->val,'@')) != NULLCHAR)
  478.         *cp = '\0';
  479.  
  480. /*
  481.       if (*ap->val=='\"')
  482.         memmove(ap->val, ap->val+1, strlen(ap->val+1)+1);
  483.  
  484.       if (cp = strchr(ap->val, '\"'), cp!=NULLCHAR)
  485.         *cp = '\0';
  486. */
  487.       /* remove foreign crap from file name */
  488.       for (i=0, n=0; ap->val[i]>=' '; i++)
  489.       {
  490.         if ( ap->val[i]!='\"' && ap->val[i]!='#' && ap->val[i]!='<' && ap->val[i]!='>' &&
  491.              ap->val[i]!='*' && ap->val[i]!='$' && ap->val[i]!='&' && ap->val[i]!=':' &&
  492.              ap->val[i]!='^' ) /* anything missed? "." and " " are ok - handled below */
  493.         ap->val[n++] = ap->val[i];
  494.       }
  495.       ap->val[n] = '\0';
  496.  
  497.       /* truncate long user names */
  498.       cp = strchr(ap->val, '.');
  499.       if (cp != NULL && (ap->val + strlen(ap->val) - cp) > MBOXLEN)
  500.         cp[MBOXLEN] = '\0';
  501.  
  502.       /* if mail file is busy save it in our smtp queue
  503.          and let the smtp daemon try later. */
  504.       if (mlock(mailspool, ap->val))
  505.       {
  506.         char buf[64];
  507.         char *q[2];
  508.  
  509.         /*
  510.          * Strip spaces or dots from multi-part name
  511.          * so that you end up with a name like "JoeB" from Joe.Bloggs or "Joe Bloggs"
  512.          * XXX Is JBloggs better?
  513.          */
  514.         cp = strtok(ap->val, ". ");
  515.         q[0] = cp;
  516.  
  517.         while (cp!=NULLCHAR)
  518.         {
  519.           q[1] = cp;
  520.           cp = strtok(NULLCHAR, ". ");
  521.         }
  522.  
  523.         if (q[0]!=q[1] && q[1]!=NULLCHAR)
  524.           sprintf(buf, "%c%s%c%s", toupper(*q[0]), q[0]+1, toupper(*q[1]), q[1]+1);
  525.         else
  526.           sprintf(buf, "%s", q[0]);
  527.         /* Ensure maxlength is 10 chars */
  528.         if (strlen(buf) > MBOXLEN)
  529.           buf[MBOXLEN] = '\0';
  530. /*
  531.         while (cp = strchr(ap->val,'.'), cp != NULLCHAR)
  532.           *cp = '/';
  533. */
  534.         strcpy(ap->val, buf);
  535.  
  536.         if (mlock(mailspool, ap->val))
  537.         {
  538.           fail = queuejob(tcb, data, hostname, ap->val, from);
  539.         }
  540.       }
  541.  
  542.       if (fail == 0)
  543.       {
  544.         sprintf(mailfile, "%s.text.%s", mailspool, ap->val);
  545.         if ((fp = fopen(mailfile, "a+")), fp != NULLFILE)
  546.         {
  547.           time(&t);
  548.           if (smtp_sep == sep_RNEWS || smtp_sep == sep_RMAIL)
  549.           {
  550.             fseek(data, 0, SEEK_END);
  551.             fprintf(fp, "#! %s %ld\n", (smtp_sep == sep_RNEWS)?"rnews":"rmail", ftell(data)+1);
  552.             fseek(data, 0, SEEK_SET);
  553.           }
  554.           else if (smtp_sep == sep_CTLA)
  555.           {
  556.             fprintf(fp, "%c\n", 0x01);
  557.           }
  558.           else
  559.           {
  560.             fprintf(fp, "From %s %s", from, ctime(&t));
  561.           }
  562.           while ((c = getc(data)) != EOF)
  563.           {
  564.             if (putc(c, fp) == EOF)
  565.               break;
  566.           }
  567.           if (ferror(fp))
  568.             fail = 1;
  569.           else
  570.             fprintf(fp,"\n");
  571.           /* Leave a blank line between msgs */
  572.           fclose(fp);
  573.           cwprintf(NULL, "New mail arrived for %s from %s\r\n", ap->val, from);
  574.         }
  575.         else
  576.         {
  577.           fail = 1;
  578.         }
  579.         rmlock(mailspool,ap->val);
  580.         if (fail)
  581.         {
  582.           log_event(tcb,"SMTP Fail:  %d", fail);
  583.           break;
  584.         }
  585.         log_event(tcb,"SMTP recv: To: %s From: %s", ap->val, from);
  586.         log_event(tcb,"Mail written as %s", mailfile);
  587.       }
  588.     }
  589.   }
  590.   return(fail);
  591. }
  592.  
  593. /* Return Date/Time in Arpanet format in passed string */
  594. char *ptime(time_t *t)
  595. {
  596.   /* Print out the time and date field as
  597.            *              "DAY day MONTH year hh:mm:ss ZONE"
  598.            */
  599.   register struct tm *ltm;
  600.   static char str[40];
  601.   static char *days[7] = {
  602.     "Sun","Mon","Tue","Wed","Thu","Fri","Sat"   };
  603.  
  604.   static char *months[12] = {
  605.     "Jan","Feb","Mar","Apr","May","Jun",
  606.     "Jul","Aug","Sep","Oct","Nov","Dec"   };
  607.  
  608.   /* Read the system time */
  609.   ltm = gmtime(t);
  610.  
  611.   /* rfc 822 format */
  612.  
  613.   sprintf(str,"%s, %.2d %s %02d %02d:%02d:%02d GMT\n",
  614.   days[ltm->tm_wday],
  615.   ltm->tm_mday,
  616.   months[ltm->tm_mon],
  617.   ltm->tm_year,
  618.   ltm->tm_hour,
  619.   ltm->tm_min,
  620.   ltm->tm_sec);
  621.  
  622.   return(str);
  623. }
  624.  
  625. long  get_msgid(void)
  626. {
  627.   char sfilename[LINELEN];
  628.   char s[20];
  629.   register long sequence = 0;
  630.   FILE *sfile;
  631.  
  632.   sprintf(sfilename,"%s.sequence",mailqdir);
  633.   sfile = fopen(sfilename,"r");
  634.  
  635.   /* if sequence file exists, get the value, otherwise set it */
  636.   if (sfile != NULL) {
  637.     fgets(s,sizeof(s),sfile);
  638.     sequence = atol(s);
  639.     /* Keep it in range of and 8 digit number to use for dos name prefix. */
  640.     if (sequence < 0L || sequence > 99999999L )
  641.       sequence = 0;
  642.     fclose(sfile);
  643.   }
  644.  
  645.   /* increment sequence number, and write to sequence file */
  646.   sfile = fopen(sfilename,"w");
  647.   fprintf(sfile,"%ld",++sequence);
  648.   fclose(sfile);
  649.   return sequence;
  650. }
  651.  
  652. #ifdef  MSDOS
  653. /* Illegal characters in a DOS filename */
  654. static char baddoschars[] = "\"[]:|<>+=;,";
  655. #endif
  656.  
  657. /* test if mail address is valid */
  658. int validate_address(char *s)
  659. {
  660.   char *cp;
  661.   int32 addr;
  662.   char  address_type;
  663.  
  664.   /* if address has @ in it the check dest address */
  665.   if ((cp = strchr(s,'@')) != NULLCHAR)
  666.   {
  667.     cp++;
  668.     /* 1st check if its our hostname
  669.        if not then check the hosts file and see
  670.        if we can resolve ther address to a know site
  671.        or one of our aliases */
  672.     if (stricmp(cp, hostname)!=0 && !inourdomain(cp))
  673.     {
  674.       if ((addr = mailroute(cp)) == 0 && (smtpmode & QUEUE) == 0)
  675.         return BADADDR;
  676.       if (addr != ip_addr)
  677.         return DOMAIN;
  678.     }
  679.  
  680.     /* on a local address remove the host name part */
  681.     *--cp = '\0';
  682.   }
  683.  
  684.   /* if using an external router leave address alone */
  685.   if ((smtpmode & QUEUE) != 0)
  686.     return LOCAL;
  687.  
  688.   /* check for the user%host hack */
  689.   if ((cp = strchr(s,'%')) != NULLCHAR)
  690.   {
  691.     *cp = '@';
  692.     cp++;
  693.     /* reroute based on host name following the % seperator */
  694.     if (mailroute(cp) == 0)
  695.       return BADADDR;
  696.     else
  697.       return DOMAIN;
  698.   }
  699.   address_type = LOCAL;
  700.  
  701. #ifdef MSDOS    /* dos file name checks */
  702.   /* Check for characters illegal in MS-DOS file names */
  703.   for (cp = baddoschars; *cp != '\0'; cp++)
  704.   {
  705.     if (strchr(s, *cp) != NULLCHAR)
  706.       return BADADDR;
  707.   }
  708. #endif
  709.   return LOCAL;
  710. }
  711.  
  712. /* place a mail job in the outbound queue */
  713. int queuejob(struct tcb *tcb, FILE *dfile, char *host, char *to, char *from)
  714. {
  715.   FILE *fp;
  716.   char tmpstring[50];
  717.   char prefix[9];
  718.   register int c;
  719.  
  720.   sprintf(prefix,"%ld",get_msgid());
  721.   log_event(tcb,"SMTP queue job %s To: %s From: %s",prefix,to,from);
  722.   mlock(mailqdir,prefix);
  723.   sprintf(tmpstring,"%s.text.%s",mailqdir,prefix);
  724.   if((fp = fopen(tmpstring,"w")) == NULLFILE) {
  725.     rmlock(mailqdir,prefix);
  726.     return 1;
  727.   }
  728.   while((c = getc(dfile)) != EOF)
  729.     if(putc(c,fp) == EOF)
  730.       break;
  731.   if(ferror(fp)){
  732.     fclose(fp);
  733.     rmlock(mailqdir,prefix);
  734.     return 1;
  735.   }
  736.   fclose(fp);
  737.   sprintf(tmpstring,"%s.work.%s",mailqdir,prefix);
  738.   if((fp = fopen(tmpstring,"w")) == NULLFILE) {
  739.     rmlock(mailqdir,prefix);
  740.     return 1;
  741.   }
  742.   fprintf(fp,"%s\n%s\n%s\n",host,from,to);
  743.   fclose(fp);
  744.   rmlock(mailqdir,prefix);
  745.   return 0;
  746. }
  747.  
  748. /* Deliver mail to the appropriate mail boxes */
  749. int router_queue(struct tcb *tcb, FILE *data, char *from, struct list *to)
  750. {
  751.   int c;
  752.   register struct list *ap;
  753.   FILE *fp;
  754.   char tmpstring[50];
  755.   char prefix[9];
  756.  
  757.   sprintf(prefix,"%ld",get_msgid());
  758.   mlock(routeqdir,prefix);
  759.   sprintf(tmpstring,"%s.text.%s",routeqdir,prefix);
  760.   if((fp = fopen(tmpstring,"w")) == NULLFILE) {
  761.     rmlock(routeqdir,prefix);
  762.     return 1;
  763.   }
  764.   fseek(data,0L,0);       /* rewind */
  765.   while((c = getc(data)) != EOF)
  766.     if(putc(c,fp) == EOF)
  767.       break;
  768.   if(ferror(fp)){
  769.     fclose(fp);
  770.     rmlock(routeqdir,prefix);
  771.     return 1;
  772.   }
  773.   fclose(fp);
  774.   sprintf(tmpstring,"%s.work.%s",routeqdir,prefix);
  775.   if((fp = fopen(tmpstring,"w")) == NULLFILE) {
  776.     rmlock(routeqdir,prefix);
  777.     return 1;
  778.   }
  779.   fprintf(fp,"From: %s\n",from);
  780.   for(ap = to;ap != NULLLIST;ap = ap->next) {
  781.     fprintf(fp,"To: %s\n",ap->val);
  782.   }
  783.   fclose(fp);
  784.   rmlock(routeqdir,prefix);
  785.   log_event(tcb,"SMTP rqueue job %s From: %s",prefix,from);
  786.   return 0;
  787. }
  788.  
  789. /* add an element to the front of the list pointed to by head
  790. ** return NULLLIST if out of memory.
  791. */
  792. struct list *addlist(struct list **head, char *val, int type)
  793. {
  794.   register struct list *tp;
  795.  
  796.   tp = (struct list *)calloc(1,sizeof(struct list));
  797.   if (tp == NULLLIST)
  798.     return NULLLIST;
  799.  
  800.   tp->next = NULLLIST;
  801.  
  802.   /* allocate storage for the char string */
  803.   if ((tp->val = malloc((unsigned)strlen(val)+1)) == NULLCHAR)
  804.   {
  805.     free((char *)tp);
  806.     return NULLLIST;
  807.   }
  808.   strcpy(tp->val,val);
  809.   tp->type = type;
  810.  
  811.   /* add entry to front of existing list */
  812.   if (*head == NULLLIST)
  813.   {
  814.     *head = tp;
  815.   }
  816.   else
  817.   {
  818.     tp->next = *head;
  819.     *head = tp;
  820.   }
  821.   return tp;
  822.  
  823. }
  824.  
  825. #define SKIPWORD(X) while(*X && *X!=' ' && *X!='\t' && *X!='\n' && *X!= ',') X++;
  826. #define SKIPSPACE(X) while(*X ==' ' || *X =='\t' || *X =='\n' || *X == ',') X++;
  827.  
  828. /* check for and alias and expand alias into a address list */
  829. struct list *expandalias(struct list **head, char *user)
  830. {
  831.   FILE *fp;
  832.   register char *s,*p,*h;
  833.   int inalias;
  834.   struct list *tp;
  835.   char buf[LINELEN];
  836.  
  837.  
  838.   /* no alias file found */
  839.   if ((fp = fopen(alias, "r")) == NULLFILE)
  840.     return addlist(head, user, LOCAL);
  841.  
  842.   inalias = 0;
  843.   while (fgets(buf, LINELEN, fp) != NULLCHAR)
  844.   {
  845.     p = buf;
  846.     if ( *p == '#' || *p == '\0')
  847.       continue;
  848.     rip(p);
  849.  
  850.     /* if not in an matching entry skip continuation lines */
  851.     if (!inalias && isspace(*p))
  852.       continue;
  853.  
  854.     /* when processing an active alias check for a continuation */
  855.     if (inalias)
  856.     {
  857.       if (!isspace(*p))
  858.         break;  /* done */
  859.     }
  860.     else
  861.     {
  862.       s = p;
  863.       SKIPWORD(p);
  864.       *p++ = '\0';    /* end the alias name */
  865.       if (stricmp(s, user) != 0)
  866.         continue;       /* no match go on */
  867.       inalias = 1;
  868.     }
  869.  
  870.     /* process the recipients on the alias line */
  871.     SKIPSPACE(p);
  872.     while(*p != '\0' && *p != '#')
  873.     {
  874.       s = p;
  875.       SKIPWORD(p);
  876.       if (*p != '\0')
  877.         *p++ = '\0';
  878.  
  879.       /* find hostname */
  880.       if ((h = strchr(s, '@')) != NULLCHAR)
  881.         tp = addlist(head,s,DOMAIN);
  882.       else
  883.         tp = addlist(head,s,LOCAL);
  884.       SKIPSPACE(p);
  885.     }
  886.   }
  887.   fclose(fp);
  888.  
  889.   if (inalias)    /* found and processed and alias. */
  890.     return tp;
  891.  
  892.   /* no alias found treat as a local address */
  893.   return addlist(head, user, LOCAL);
  894. }
  895.  
  896.