home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / files / telecomm / nhclb120 / smtpserv.c < prev    next >
C/C++ Source or Header  |  1993-09-26  |  18KB  |  823 lines

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