home *** CD-ROM | disk | FTP | other *** search
/ Media Share 9 / MEDIASHARE_09.ISO / hamradio / s920603.zip / SMTPSERV.C < prev    next >
C/C++ Source or Header  |  1992-05-19  |  24KB  |  1,011 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 UNIX
  7. #include <sys/types.h>
  8. #endif
  9. #if    defined(__STDC__) || defined(__TURBOC__)
  10. #include <stdarg.h>
  11. #endif
  12. #include <ctype.h>
  13. #include <setjmp.h>
  14. #include "global.h"
  15. #include "mbuf.h"
  16. #include "cmdparse.h"
  17. #include "socket.h"
  18. #include "iface.h"
  19. #include "proc.h"
  20. #include "smtp.h"
  21. #include "commands.h"
  22. #include "dirutil.h"
  23. #include "mailbox.h"
  24. #include "bm.h"
  25. #include "domain.h"
  26.  
  27. char *Days[7] = {  "Sun","Mon","Tue","Wed","Thu","Fri","Sat" };
  28. char *Months[12] = { "Jan","Feb","Mar","Apr","May","Jun",
  29.         "Jul","Aug","Sep","Oct","Nov","Dec" };
  30.  
  31.  
  32.  
  33. static struct list *expandalias __ARGS((struct list **head,char *user));
  34. static int  getmsgtxt __ARGS((struct smtpsv *mp));
  35. static struct smtpsv *mail_create __ARGS((void));
  36. static void mail_clean __ARGS((struct smtpsv *mp));
  37. static int mailit __ARGS((FILE *data,char *from,struct list *tolist));
  38. static int router_queue __ARGS((FILE *data,char *from,struct list *to));
  39. static void smtplog __ARGS((char *fmt,...));
  40. static void smtpserv __ARGS((int s,void *unused,void *p));
  41. static int mailuser __ARGS((FILE *data,char *from,char *to));
  42.  
  43. /* Command table */
  44. static char *commands[] = {
  45.     "helo",
  46. #define    HELO_CMD    0
  47.     "noop",
  48. #define    NOOP_CMD    1
  49.     "mail from:",
  50. #define    MAIL_CMD    2
  51.     "quit",
  52. #define    QUIT_CMD    3
  53.     "rcpt to:",
  54. #define    RCPT_CMD    4
  55.     "help",
  56. #define    HELP_CMD    5
  57.     "data",
  58. #define    DATA_CMD    6
  59.     "rset",
  60. #define    RSET_CMD    7
  61.     "expn",
  62. #define EXPN_CMD    8
  63.     NULLCHAR
  64. };
  65.  
  66. /* Reply messages */
  67. static char Help[] = "214-Commands:\n214-HELO NOOP MAIL QUIT RCPT HELP DATA RSET EXPN\n214 End\n";
  68. static char Banner[] = "220 %s SMTP ready\n";
  69. static char Closing[] = "221 Closing\n";
  70. static char Ok[] = "250 Ok\n";
  71. static char Reset[] = "250 Reset state\n";
  72. static char Sent[] = "250 Sent\n";
  73. static char Ourname[] = "250 %s, Share and Enjoy!\n";
  74. static char Enter[] = "354 Enter mail, end with .\n";
  75. static char Ioerr[] = "452 Temp file write error\n";
  76. static char Badcmd[] = "500 Command unrecognized\n";
  77. static char Lowmem[] = "421 System overloaded, try again later\n";
  78. static char Syntax[] = "501 Syntax error\n";
  79. static char Needrcpt[] = "503 Need RCPT (recipient)\n";
  80. static char Unknown[] = "550 <%s> address unknown\n";
  81. static char Noalias[] = "550 No alias for <%s>\n";
  82.  
  83. static int Ssmtp = -1; /* prototype socket for service */
  84.  
  85. /* Start up SMTP receiver service */
  86. int
  87. smtp1(argc,argv,p)
  88. int argc;
  89. char *argv[];
  90. void *p;
  91. {
  92.     struct sockaddr_in lsocket;
  93.     int s;
  94.     FILE *network;
  95.  
  96.     if(Ssmtp != -1){
  97.         return 0;
  98.     }
  99.     psignal(Curproc,0);    /* Don't keep the parser waiting */
  100.     chname(Curproc,"SMTP listener");
  101.  
  102.     lsocket.sin_family = AF_INET;
  103.     lsocket.sin_addr.s_addr = INADDR_ANY;
  104.     if(argc < 2)
  105.         lsocket.sin_port = IPPORT_SMTP;
  106.     else
  107.         lsocket.sin_port = atoi(argv[1]);
  108.  
  109.     Ssmtp = socket(AF_INET,SOCK_STREAM,0);
  110.     bind(Ssmtp,(char *)&lsocket,sizeof(lsocket));
  111.     listen(Ssmtp,1);
  112.     for(;;){
  113.         if((s = accept(Ssmtp,NULLCHAR,(int *)NULL)) == -1)
  114.             break;    /* Service is shutting down */
  115.  
  116.         network = fdopen(s,"r+t");
  117.         if(availmem() != 0){
  118.             fprintf(network,Lowmem);
  119.             fclose(network);
  120.         } else {
  121.             /* Spawn a server */
  122.             newproc("SMTP server",2048,smtpserv,s,(void *)network,NULL,0);
  123.         }
  124.     }
  125.     return 0;
  126. }
  127.  
  128. /* Shutdown SMTP service (existing connections are allowed to finish) */
  129. int
  130. smtp0(argc,argv,p)
  131. int argc;
  132. char *argv[];
  133. void *p;
  134. {
  135.     close_s(Ssmtp);
  136.     Ssmtp = -1;
  137.     return 0;
  138. }
  139.  
  140. static void
  141. smtpserv(s,n,p)
  142. int s;
  143. void *n;
  144. void *p;
  145. {
  146.     struct smtpsv *mp;
  147.     char **cmdp,buf[LINELEN],*arg,*cp,*cmd,*newaddr;
  148.     struct list *ap,*list;
  149.     int cnt;
  150.     char address_type;
  151.     FILE *network;
  152.  
  153.     network = (FILE *)n;
  154.     sockowner(fileno(network),Curproc);        /* We own it now */
  155.     log(fileno(network),"open SMTP");
  156.  
  157.     if((mp = mail_create()) == NULLSMTPSV){
  158.         printf(Nospace);
  159.         log(fileno(network),"close SMTP - no space");
  160.         fclose(network);
  161.         return;
  162.     }
  163.     mp->network = network;
  164.  
  165.     (void) fprintf(network,Banner,Hostname);
  166.  
  167. loop:    if (fgets(buf,sizeof(buf),network) == NULLCHAR) {
  168.         /* He closed on us */
  169.         goto quit;
  170.     }
  171.     cnt = strlen(buf);
  172.     if(cnt < 4){
  173.         /* Can't be a legal command */
  174.         fprintf(network,Badcmd);
  175.         goto loop;
  176.     }    
  177.     rip(buf);
  178.     cmd = buf;
  179.  
  180.     /* Translate entire buffer to lower case */
  181.     for(cp = cmd;*cp != '\0';cp++)
  182.         *cp = tolower(*cp);
  183.  
  184.     /* Find command in table; if not present, return syntax error */
  185.     for(cmdp = commands;*cmdp != NULLCHAR;cmdp++)
  186.         if(strncmp(*cmdp,cmd,strlen(*cmdp)) == 0)
  187.             break;
  188.     if(*cmdp == NULLCHAR){
  189.         (void) fprintf(network,Badcmd);
  190.         goto loop;
  191.     }
  192.     arg = &cmd[strlen(*cmdp)];
  193.     /* Skip spaces after command */
  194.     while(*arg == ' ')
  195.         arg++;
  196.     /* Execute specific command */
  197.     switch(cmdp-commands) {
  198.     case HELO_CMD:
  199.         free(mp->system);
  200.         mp->system = strdup(arg);
  201.         (void) fprintf(network,Ourname,Hostname);
  202.         break;
  203.     case NOOP_CMD:
  204.         (void) fprintf(network,Ok);
  205.         break;
  206.     case MAIL_CMD:
  207.         if((cp = getname(arg)) == NULLCHAR){
  208.             (void) fprintf(network,Syntax);
  209.             break;
  210.         }
  211.         free(mp->from);
  212.         mp->from = strdup(cp);
  213.         (void) fprintf(network,Ok);
  214.         break;
  215.     case QUIT_CMD:
  216.         (void) fprintf(network,Closing);
  217.         goto quit;
  218.     case RCPT_CMD:    /* Specify recipient */
  219.         if((cp = getname(arg)) == NULLCHAR){
  220.             (void) fprintf(network,Syntax);
  221.             break;
  222.         }
  223.  
  224.         /* rewrite address if possible */
  225.         if((newaddr = rewrite_address(cp)) != NULLCHAR) {
  226.             strcpy(buf,newaddr);
  227.             cp = buf;
  228.             free(newaddr);
  229.         }
  230.  
  231.         /* check if address is ok */
  232.         if ((address_type = validate_address(cp)) == BADADDR) {
  233.             (void) fprintf(network,Unknown,cp);
  234.             break;
  235.         }
  236.         /* if a local address check for an alias */
  237.         if (address_type == LOCAL)
  238.             expandalias(&mp->to, cp);
  239.         else
  240.             /* a remote address is added to the list */
  241.             addlist(&mp->to, cp, address_type);
  242.  
  243.         (void) fprintf(network,Ok);
  244.         break;
  245.     case HELP_CMD:
  246.         (void) fprintf(network,Help);
  247.         break;
  248.     case DATA_CMD:
  249.         if(mp->to == NULLLIST)
  250.             (void) fprintf(network,Needrcpt);
  251.         else if ((mp->data = tmpfile()) == NULLFILE)
  252.             (void) fprintf(network,Ioerr);
  253.          else
  254.             getmsgtxt(mp);
  255.         break;
  256.     case RSET_CMD:
  257.         del_list(mp->to);
  258.         mp->to = NULLLIST;
  259.         (void) fprintf(network,Reset);
  260.         break;
  261.     case EXPN_CMD:
  262.         if (*arg == '\0') {
  263.             (void) fprintf(network,Syntax);
  264.             break;
  265.         }
  266.  
  267.         list = NULLLIST;
  268.         /* rewrite address if possible */
  269.         if((newaddr = rewrite_address(arg)) != NULLCHAR)
  270.             if(strcmp(newaddr,arg) == 0) {
  271.                 free(newaddr);
  272.                 newaddr = NULLCHAR;
  273.             }
  274.             else {
  275.                 strcpy(buf,newaddr);
  276.                 arg = buf;
  277.             }
  278.         list = NULLLIST;
  279.         expandalias(&list,arg);
  280.         if (strcmp(list->val,arg) == 0 && list->next == NULLLIST)
  281.             if(newaddr == NULLCHAR) {
  282.                 (void) fprintf(network,Noalias,arg);
  283.                 del_list(list);
  284.                 break;
  285.             }
  286.         ap = list;
  287.         while (ap->next != NULLLIST) {
  288.             (void) fprintf(network,"250-%s\n",ap->val);
  289.             ap = ap->next;
  290.         }
  291.         fprintf(network,"250 %s\n",ap->val);
  292.         del_list(list);
  293.         free(newaddr);
  294.         break;
  295.     }
  296.     goto loop;
  297.  
  298. quit:
  299.     log(fileno(network),"close SMTP");
  300.     fclose(network);
  301.     mail_clean(mp);
  302.     smtptick(NULL);            /* start SMTP daemon immediately */
  303. }
  304.  
  305. /* read the message text */
  306. static int
  307. getmsgtxt(mp)
  308. struct smtpsv *mp;
  309. {
  310.     char buf[LINELEN];
  311.     register char *p = buf;
  312.     long t;
  313.     FILE *network;
  314.     FILE *data;
  315.  
  316.     network = mp->network;
  317.     data = mp->data;
  318.     /* Add timestamp; ptime adds newline */
  319.     time(&t);
  320.     fprintf(data,"Received: ");
  321.     if(mp->system != NULLCHAR)
  322.         fprintf(data,"from %s ",mp->system);
  323.     fprintf(data,"by %s with SMTP\n\tid AA%ld ; %s",
  324.             Hostname, get_msgid(), ptime(&t));
  325.     if(ferror(data)){
  326.         (void) fprintf(network,Ioerr);
  327.         return 1;
  328.     } else {
  329.         (void) fprintf(network,Enter);
  330.     }
  331.     while(1) {
  332.         if(fgets(p,sizeof(buf),network) == NULL){
  333.             return 1;
  334.         }
  335.         rip(p);
  336.         /* check for end of message ie a . or escaped .. */
  337.         if (*p == '.') {
  338.             if (*++p == '\0') {
  339.                 /* Also sends appropriate response */
  340.                 if (mailit(data,mp->from,mp->to) != 0)
  341.                     (void) fprintf(network,Ioerr);
  342.                 else
  343.                     (void) fprintf(network,Sent);
  344.                 fclose(data);
  345.                 data = NULLFILE;
  346.                 del_list(mp->to);
  347.                 mp->to = NULLLIST;
  348.                 return 0;
  349.             } else if (!(*p == '.' && *(p+1) == '\0'))
  350.                 p--;
  351.         }
  352.         /* for UNIX mail compatiblity */
  353.         if (strncmp(p,"From ",5) == 0)
  354.             (void) putc('>',data);
  355.         /* Append to data file */
  356.         if(fprintf(data,"%s\n",p) < 0) {
  357.             (void) fprintf(network,Ioerr);
  358.             return 1;
  359.         }
  360.     }
  361.     return 0;
  362. }
  363.  
  364. /* Create control block, initialize */
  365. static struct smtpsv *
  366. mail_create()
  367. {
  368.     register struct smtpsv *mp;
  369.  
  370.     mp = (struct smtpsv *)callocw(1,sizeof(struct smtpsv));
  371.     mp->from = strdup("");    /* Default to null From address */
  372.     return mp;
  373. }
  374.  
  375. /* Free resources, delete control block */
  376. static void
  377. mail_clean(mp)
  378. register struct smtpsv *mp;
  379. {
  380.     if (mp == NULLSMTPSV)
  381.         return;
  382.     free(mp->system);
  383.     free(mp->from);
  384.     if(mp->data != NULLFILE)
  385.         fclose(mp->data);
  386.     del_list(mp->to);
  387.     free((char *)mp);
  388. }
  389.  
  390.  
  391. /* Given a string of the form <user@host>, extract the part inside the
  392.  * brackets and return a pointer to it.
  393.  */
  394. char *
  395. getname(cp)
  396. register char *cp;
  397. {
  398.     register char *cp1;
  399.  
  400.     if ((cp = strchr(cp,'<')) == NULLCHAR)
  401.         return NULLCHAR;
  402.     cp++;    /* cp -> first char of name */
  403.     if ((cp1 = strchr(cp,'>')) == NULLCHAR)
  404.         return NULLCHAR;
  405.     *cp1 = '\0';
  406.     return cp;
  407. }
  408.  
  409.         
  410. /* General mailit function. It takes a list of addresses which have already
  411. ** been verified and expanded for aliases. Base on the current mode the message
  412. ** is place in an mbox, the outbound smtp queue or the rqueue interface
  413. */
  414. static int
  415. mailit(data,from,tolist)
  416. FILE *data;
  417. char *from;
  418. struct list *tolist;
  419. {
  420.     struct list *ap, *dlist = NULLLIST;
  421.     register FILE *fp;
  422.     char    mailbox[50], *cp, *host, *qhost;
  423.     int    c, fail = 0;
  424.     time_t    t;
  425.  
  426.     if ((Smtpmode & QUEUE) != 0)
  427.         return(router_queue(data,from,tolist));
  428.  
  429.     do {
  430.         qhost = NULLCHAR;
  431.         for(ap = tolist;ap != NULLLIST;ap = ap->next)
  432.             if (ap->type == DOMAIN) {
  433.                 if ((host = strrchr(ap->val,'@')) != NULLCHAR)
  434.                     host++;
  435.                 else
  436.                     host = Hostname;
  437.                 if(qhost == NULLCHAR)
  438.                          qhost = host;
  439.                 if(stricmp(qhost,host) == 0) {
  440.                     ap->type = BADADDR;
  441.                     addlist(&dlist,ap->val,0);
  442.                 }
  443.             }
  444.         if(qhost != NULLCHAR) {
  445.             rewind(data);
  446.             queuejob(data,qhost,dlist,from);
  447.             del_list(dlist);
  448.             dlist = NULLLIST;
  449.         }
  450.     } while(qhost != NULLCHAR);
  451.  
  452.     for(ap = tolist;ap != NULLLIST;ap = ap->next) {
  453.         if(ap->type != LOCAL) {
  454.             ap->type = DOMAIN;
  455.             continue;
  456.         }
  457.         rewind(data);
  458.         /* strip off host name of LOCAL addresses */
  459.         if ((cp = strchr(ap->val,'@')) != NULLCHAR)
  460.             *cp = '\0';
  461.  
  462.         /* truncate long user names */
  463.         if (strlen(ap->val) > MBOXLEN)
  464.             ap->val[MBOXLEN] = '\0';
  465.  
  466.         /* if mail file is busy save it in our smtp queue
  467.          * and let the smtp daemon try later.
  468.          */
  469.         if (mlock(Mailspool,ap->val)) {
  470.             addlist(&dlist,ap->val,0);
  471.             fail = queuejob(data,Hostname,dlist,from);
  472.             del_list(dlist);
  473.             dlist = NULLLIST;
  474.         }
  475.         else {
  476.             char buf[LINELEN];
  477.             int tocnt = 0;
  478.             sprintf(mailbox,"%s/%s.txt",Mailspool,ap->val);
  479. #ifndef    AMIGA
  480.             if((fp = fopen(mailbox,APPEND_TEXT)) != NULLFILE) {
  481. #else
  482.             if((fp = fopen(mailbox,"r+")) != NULLFILE) {
  483.                 (void) fseek(fp, 0L, 2);
  484. #endif
  485.                 time(&t);
  486.                 fprintf(fp,"From %s %s",from,ctime(&t));
  487.                 host = NULLCHAR;
  488.                 while(fgets(buf,sizeof(buf),data) != NULLCHAR){
  489.                     if(buf[0] == '\n'){
  490.                         if(tocnt == 0)
  491.                             fprintf(fp,"%s%s\n",
  492.                                 Hdrs[APPARTO],
  493.                                 ap->val);
  494.                         fputc('\n',fp);
  495.                         break;
  496.                     }
  497.                     fputs(buf,fp);
  498.                     rip(buf);
  499.                     switch(htype(buf)){
  500.                     case TO:
  501.                     case CC:
  502.                         ++tocnt;
  503.                         break;
  504.                     case RRECEIPT:
  505.                         if((cp = getaddress(buf,0))
  506.                            != NULLCHAR){
  507.                             free(host);
  508.                             host = strdup(cp);
  509.                         }
  510.                         break;
  511.                     }
  512.                 }
  513.                 while((c = fread(buf,1,sizeof(buf),data)) > 0)
  514.                     if(fwrite(buf,1,c,fp) != c)
  515.                         break;
  516.                 if(ferror(fp))
  517.                     fail = 1;
  518.                 else
  519.                     fprintf(fp,"\n");
  520.                 /* Leave a blank line between msgs */
  521.                 fclose(fp);
  522.                 printf("New mail arrived for %s\n",ap->val);
  523.                 if(host != NULLCHAR){
  524.                     rewind(data); /* Send return receipt */
  525.                     mdaemon(data,host,NULLLIST,0);
  526.                     free(host);
  527.                 }
  528.             } else 
  529.                 fail = 1;
  530.             (void) rmlock(Mailspool,ap->val);
  531.             if (fail)
  532.                 break;
  533.             smtplog("deliver: To: %s From: %s",ap->val,from);
  534.         }
  535.     }
  536.     return fail;
  537. }
  538.  
  539. /* Return Date/Time in Arpanet format in passed string */
  540. char *
  541. ptime(t)
  542. long *t;
  543. {
  544.     /* Print out the time and date field as
  545.      *        "DAY day MONTH year hh:mm:ss ZONE"
  546.      */
  547.     register struct tm *ltm;
  548.     static char tz[4];
  549.     static char str[40];
  550.     char *p, *getenv();
  551.     /* Read the system time */
  552.     ltm = localtime(t);
  553.  
  554.     if (*tz == '\0')
  555.         if ((p = getenv("TZ")) == NULL)
  556.             strcpy(tz,"UTC");
  557.         else
  558.             strncpy(tz,p,3);
  559.  
  560.     /* rfc 822 format */
  561.     sprintf(str,"%s, %.2d %s %02d %02d:%02d:%02d %.3s\n",
  562.         Days[ltm->tm_wday],
  563.         ltm->tm_mday,
  564.         Months[ltm->tm_mon],
  565.         ltm->tm_year,
  566.         ltm->tm_hour,
  567.         ltm->tm_min,
  568.         ltm->tm_sec,
  569.         tz);
  570.     return(str);
  571. }
  572.  
  573. long 
  574. get_msgid()
  575. {
  576.     char sfilename[LINELEN];
  577.     char s[20];
  578.     register long sequence = 0;
  579.     FILE *sfile;
  580.  
  581.     sprintf(sfilename,"%s/sequence.seq",Mailqdir);
  582.     sfile = fopen(sfilename,READ_TEXT);
  583.  
  584.     /* if sequence file exists, get the value, otherwise set it */
  585.     if (sfile != NULL) {
  586.         (void) fgets(s,sizeof(s),sfile);
  587.         sequence = atol(s);
  588.     /* Keep it in range of and 8 digit number to use for dos name prefix. */
  589.         if (sequence < 0L || sequence > 99999999L )
  590.             sequence = 0;
  591.         fclose(sfile);
  592.     }
  593.  
  594.     /* increment sequence number, and write to sequence file */
  595.     sfile = fopen(sfilename,WRITE_TEXT);
  596.     fprintf(sfile,"%ld",++sequence);
  597.     fclose(sfile);
  598.     return sequence;
  599. }
  600.  
  601. #ifdef    MSDOS
  602. /* Illegal characters in a DOS filename */
  603. static char baddoschars[] = "\"[]:|<>+=;,";
  604. #endif
  605.  
  606. /* test if mail address is valid */
  607. int
  608. validate_address(s)
  609. char *s;
  610. {
  611.     char *cp;
  612.     int32 addr;
  613.  
  614.     /* if address has @ in it the check dest address */
  615.     if ((cp = strrchr(s,'@')) != NULLCHAR) {
  616.         cp++;
  617.         /* 1st check if its our hostname
  618.         * if not then check the hosts file and see
  619.         * if we can resolve ther address to a know site
  620.         * or one of our aliases
  621.         */
  622.         if (strcmp(cp,Hostname) != 0) {
  623.             if ((addr = mailroute(cp)) == 0
  624.                 && (Smtpmode & QUEUE) == 0)
  625.                 return BADADDR;
  626.             if (ismyaddr(addr) == NULLIF)
  627.                 return DOMAIN;
  628.         }
  629.         
  630.         /* on a local address remove the host name part */
  631.         *--cp = '\0';
  632.     }
  633.  
  634.     /* if using an external router leave address alone */
  635.     if ((Smtpmode & QUEUE) != 0)
  636.         return LOCAL;
  637.  
  638.     /* check for the user%host hack */
  639.     if ((cp = strrchr(s,'%')) != NULLCHAR) {
  640.         *cp = '@';
  641.         cp++;
  642.         /* reroute based on host name following the % seperator */
  643.         if (mailroute(cp) == 0)
  644.             return BADADDR;
  645.         else
  646.             return DOMAIN;
  647.     }
  648.  
  649. #ifdef MSDOS    /* dos file name checks */
  650.     /* Check for characters illegal in MS-DOS file names */
  651.     for(cp = baddoschars;*cp != '\0';cp++){
  652.         if(strchr(s,*cp) != NULLCHAR)
  653.             return BADADDR;    
  654.     }
  655. #endif
  656.     return LOCAL;
  657. }
  658.  
  659. /* place a mail job in the outbound queue */
  660. int
  661. queuejob(dfile,host,to,from)
  662. FILE *dfile;
  663. char *host;
  664. struct list *to;
  665. char *from;
  666. {
  667.     FILE *fp;
  668.     struct list *ap;
  669.     char tmpstring[50], prefix[9], buf[LINELEN];
  670.     register int cnt;
  671.  
  672.     sprintf(prefix,"%ld",get_msgid());
  673.     mlock(Mailqdir,prefix);
  674.     sprintf(tmpstring,"%s/%s.txt",Mailqdir,prefix);
  675.     if((fp = fopen(tmpstring,WRITE_TEXT)) == NULLFILE) {
  676.         (void) rmlock(Mailqdir,prefix);
  677.         return 1;
  678.     }
  679.     while((cnt = fread(buf, 1, LINELEN, dfile)) > 0)
  680.         if(fwrite(buf, 1, cnt, fp) != cnt)
  681.             break;
  682.     if(ferror(fp)){
  683.         fclose(fp);
  684.         (void) rmlock(Mailqdir,prefix);
  685.         return 1;
  686.     }
  687.     fclose(fp);
  688.     sprintf(tmpstring,"%s/%s.wrk",Mailqdir,prefix);
  689.     if((fp = fopen(tmpstring,WRITE_TEXT)) == NULLFILE) {
  690.         (void) rmlock(Mailqdir,prefix);
  691.         return 1;
  692.     }
  693.     fprintf(fp,"%s\n%s\n",host,from);
  694.     for(ap = to; ap != NULLLIST; ap = ap->next) {
  695.         fprintf(fp,"%s\n",ap->val);
  696.         smtplog("queue job %s To: %s From: %s",prefix,ap->val,from);
  697.     }
  698.     fclose(fp);
  699.     (void) rmlock(Mailqdir,prefix);
  700.     return 0;
  701. }
  702.  
  703. /* Deliver mail to the appropriate mail boxes */
  704. static int
  705. router_queue(data,from,to)
  706. FILE *data;
  707. char *from;
  708. struct list *to;
  709. {
  710.     int c;
  711.     register struct list *ap;
  712.     FILE *fp;
  713.     char tmpstring[50];
  714.     char prefix[9];
  715.  
  716.     sprintf(prefix,"%ld",get_msgid());
  717.     mlock(Routeqdir,prefix);
  718.     sprintf(tmpstring,"%s/%s.txt",Routeqdir,prefix);
  719.     if((fp = fopen(tmpstring,WRITE_TEXT)) == NULLFILE) {
  720.         (void) rmlock(Routeqdir,prefix);
  721.         return 1;
  722.     }
  723.     rewind(data);
  724.     while((c = getc(data)) != EOF)
  725.         if(putc(c,fp) == EOF)
  726.             break;
  727.     if(ferror(fp)){
  728.         fclose(fp);
  729.         (void) rmlock(Routeqdir,prefix);
  730.         return 1;
  731.     }
  732.     fclose(fp);
  733.     sprintf(tmpstring,"%s/%s.wrk",Routeqdir,prefix);
  734.     if((fp = fopen(tmpstring,WRITE_TEXT)) == NULLFILE) {
  735.         (void) rmlock(Routeqdir,prefix);
  736.         return 1;
  737.     }
  738.     fprintf(fp,"From: %s\n",from);
  739.     for(ap = to;ap != NULLLIST;ap = ap->next) {
  740.         fprintf(fp,"To: %s\n",ap->val);
  741.     }
  742.     fclose(fp);
  743.     (void) rmlock(Routeqdir,prefix);
  744.     smtplog("rqueue job %s From: %s",prefix,from);
  745.     return 0;
  746. }
  747.  
  748. /* add an element to the front of the list pointed to by head 
  749. ** return NULLLIST if out of memory.
  750. */
  751. struct list *
  752. addlist(head,val,type)
  753. struct list **head;
  754. char *val;
  755. int type;
  756. {
  757.     register struct list *tp;
  758.  
  759.     tp = (struct list *)callocw(1,sizeof(struct list));
  760.  
  761.     tp->next = NULLLIST;
  762.  
  763.     /* allocate storage for the char string */
  764.     tp->val = strdup(val);
  765.     tp->type = type;
  766.  
  767.     /* add entry to front of existing list */
  768.     if (*head == NULLLIST)
  769.         *head = tp;
  770.     else {
  771.         tp->next = *head;
  772.         *head = tp;
  773.     }
  774.     return tp;
  775.  
  776. }
  777.  
  778. #define SKIPWORD(X) while(*X && *X!=' ' && *X!='\t' && *X!='\n' && *X!= ',') X++;
  779. #define SKIPSPACE(X) while(*X ==' ' || *X =='\t' || *X =='\n' || *X == ',') X++;
  780.  
  781. /* check for and alias and expand alias into a address list */
  782. static struct list *
  783. expandalias(head, user)
  784. struct list **head;
  785. char *user;
  786. {
  787.     FILE *fp;
  788.     register char *s,*p;
  789.     struct rr *rrp, *rrlp;
  790.     int inalias = 0;
  791.     struct list *tp;
  792.     char buf[LINELEN];
  793.     
  794.     /* no alias file found */
  795.     if ((fp = fopen(Alias, READ_TEXT)) == NULLFILE) {
  796.         /* Try MB, MG or MR domain name records */
  797.         rrlp = rrp = resolve_mailb(user);
  798.         while(rrp != NULLRR){
  799.             if(rrp->rdlength > 0){
  800.                 /* remove the trailing dot */
  801.                 rrp->rdata.name[rrp->rdlength-1] = '\0';
  802.                 /* replace first dot with @ if there is no @ */
  803.                 if(strchr(rrp->rdata.name,'@') == NULLCHAR
  804.                    && (p = strchr(rrp->rdata.name,'.')) !=
  805.                    NULLCHAR)
  806.                     *p = '@';
  807.                 if(strchr(rrp->rdata.name,'@') != NULLCHAR)
  808.                     tp = addlist(head,rrp->rdata.name,
  809.                              DOMAIN);
  810.                 else
  811.                     tp = addlist(head,rrp->rdata.name,
  812.                              LOCAL);
  813.                 ++inalias;
  814.             }
  815.             rrp = rrp->next;
  816.         }
  817.         free_rr(rrlp);
  818.         if(inalias)
  819.             return tp;
  820.         else
  821.             return addlist(head, user, LOCAL);
  822.     }
  823.  
  824.     while (fgets(buf,LINELEN,fp) != NULLCHAR) {
  825.         p = buf;
  826.         if ( *p == '#' || *p == '\0')
  827.             continue;
  828.         rip(p);
  829.  
  830.         /* if not in an matching entry skip continuation lines */
  831.         if (!inalias && isspace(*p))
  832.             continue;
  833.  
  834.         /* when processing an active alias check for a continuation */
  835.         if (inalias) {
  836.             if (!isspace(*p)) 
  837.                 break;    /* done */
  838.         } else {
  839.             s = p;
  840.             SKIPWORD(p);
  841.             *p++ = '\0';    /* end the alias name */
  842.             if (strcmp(s,user) != 0)
  843.                 continue;    /* no match go on */
  844.             inalias = 1;
  845.         }
  846.  
  847.         /* process the recipients on the alias line */
  848.         SKIPSPACE(p);
  849.         while(*p != '\0' && *p != '#') {
  850.             s = p;
  851.             SKIPWORD(p);
  852.             if (*p != '\0')
  853.                 *p++ = '\0';
  854.  
  855.             /* find hostname */
  856.             if (strchr(s,'@') != NULLCHAR)
  857.                 tp = addlist(head,s,DOMAIN);
  858.             else
  859.                 tp = addlist(head,s,LOCAL);
  860.             SKIPSPACE(p);
  861.         }
  862.     }
  863.     (void) fclose(fp);
  864.  
  865.     if (inalias)    /* found and processed and alias. */
  866.         return tp;
  867.  
  868.     /* no alias found treat as a local address */
  869.     return addlist(head, user, LOCAL);
  870. }
  871.  
  872. #if    defined(ANSIPROTO)
  873. static void
  874. smtplog(char *fmt, ...)
  875. {
  876.     va_list ap;
  877.     char *cp;
  878.     long t;
  879.     FILE *fp;
  880.  
  881.     if ((fp = fopen(Maillog,APPEND_TEXT)) == NULLFILE)
  882.         return;
  883.     time(&t);
  884.     cp = ctime(&t);
  885.     rip(cp);
  886.     fprintf(fp,"%s ",cp);
  887.     va_start(ap,fmt);
  888.     vfprintf(fp,fmt,ap);
  889.     va_end(ap);
  890.     fprintf(fp,"\n");
  891.     fclose(fp);
  892. }
  893.  
  894. #else
  895.  
  896. static void
  897. smtplog(fmt,arg1,arg2,arg3,arg4)
  898. char *fmt;
  899. int arg1,arg2,arg3,arg4;
  900. {
  901.     char *cp;
  902.     long t;
  903.     FILE *fp;
  904.  
  905.     if ((fp = fopen(Maillog,APPEND_TEXT)) == NULLFILE)
  906.         return;
  907.     time(&t);
  908.     cp = ctime(&t);
  909.     rip(cp);
  910.     fprintf(fp,"%s ",cp);
  911.     fprintf(fp,fmt,arg1,arg2,arg3,arg4);
  912.     fprintf(fp,"\n");
  913.     fclose(fp);
  914. }
  915. #endif
  916.  
  917. /* send mail to a single user. Can be called from the ax24 mailbox or
  918. ** from the return mail function in the smtp client 
  919. */
  920. static int
  921. mailuser(data,from,to)
  922. FILE *data;
  923. char *from;
  924. char *to;
  925. {
  926.  
  927.         int address_type, ret;
  928.         struct list *tolist = NULLLIST;
  929.  
  930.         /* check if address is ok */
  931.         if ((address_type = validate_address(to)) == BADADDR) {
  932.             return 1;
  933.         }
  934.         /* if a local address check for an alias */
  935.         if (address_type == LOCAL)
  936.             expandalias(&tolist, to);
  937.         else
  938.             /* a remote address is added to the list */
  939.             addlist(&tolist, to, address_type);
  940.         ret = mailit(data,from,tolist);
  941.         del_list(tolist);
  942.         return ret;
  943.  
  944. }
  945.  
  946. /* Mailer daemon return mail mechanism */
  947. int
  948. mdaemon(data,to,lp,bounce)
  949. FILE *data;        /* pointer to rewound data file */
  950. char *to;        /* Overridden by Errors-To: line if bounce is true */
  951. struct list *lp;    /* error log for failed mail */
  952. int bounce;        /* True for failed mail, otherwise return receipt */
  953. {
  954.     time_t t;
  955.     FILE *tfile;
  956.     char buf[LINELEN], *cp, *newto = NULLCHAR;
  957.     int cnt;
  958.     if(to == NULLCHAR || (to != NULLCHAR && *to == '\0') || bounce){
  959.         while(fgets(buf,sizeof(buf),data) != NULLCHAR) {
  960.             if(buf[0] == '\n')
  961.                 break;
  962.             /* Look for Errors-To: */
  963.             if(htype(buf) == ERRORSTO &&
  964.                (cp = getaddress(buf,0)) != NULLCHAR){
  965.                 free(newto);
  966.                 newto = strdup(cp);
  967.                 break;
  968.             }
  969.         }
  970.         if(newto == NULLCHAR && ((to != NULLCHAR && *to == '\0') ||
  971.            to == NULLCHAR))
  972.             return -1;
  973.         rewind(data);
  974.     }
  975.     if((tfile = tmpfile()) == NULLFILE)
  976.         return -1;
  977.     time(&t);
  978.     fprintf(tfile,"%s%s",Hdrs[DATE],ptime(&t));
  979.     fprintf(tfile,"%s<%ld@%s>\n",Hdrs[MSGID],get_msgid(),Hostname);
  980.     fprintf(tfile,"%sMAILER-DAEMON@%s (Mail Delivery Subsystem)\n",
  981.         Hdrs[FROM],Hostname);
  982.     fprintf(tfile,"%s%s\n",Hdrs[TO],newto != NULLCHAR ? newto : to);
  983.     fprintf(tfile,"%s%s\n\n",Hdrs[SUBJECT],
  984.         bounce ? "Failed mail" : "Return receipt");
  985.     if(bounce) {
  986.         fprintf(tfile,"  ===== transcript follows =====\n\n");
  987.         for (; lp != NULLLIST; lp = lp->next)
  988.             fprintf(tfile,"%s\n",lp->val);
  989.         fprintf(tfile,"\n");
  990.     }
  991.     fprintf(tfile,"  ===== %s follows ====\n",
  992.         bounce ? "Unsent message" : "Message header");
  993.  
  994.     while(fgets(buf,sizeof(buf),data) != NULLCHAR){
  995.         if(buf[0] == '\n')
  996.             break;
  997.         fputs(buf,tfile);
  998.     }
  999.     if(bounce){
  1000.         fputc('\n',tfile);
  1001.         while((cnt = fread(buf,1,sizeof(buf),data)) > 0)
  1002.             fwrite(buf,1,cnt,tfile);
  1003.     }
  1004.     fseek(tfile,0L,0);
  1005.     /* A null From<> so no looping replys to MAIL-DAEMONS */
  1006.     (void) mailuser(tfile,"",newto != NULLCHAR ? newto : to);
  1007.     fclose(tfile);
  1008.     free(newto);
  1009.     return 0;
  1010. }
  1011.