home *** CD-ROM | disk | FTP | other *** search
/ High Voltage Shareware / high1.zip / high1 / DIR3 / KA9Q212.ZIP / SMTPSERV.C < prev    next >
C/C++ Source or Header  |  1993-07-16  |  33KB  |  1,492 lines

  1. /* SMTP Server state machine - see RFC 821
  2.  *  enhanced 4/88 Dave Trulli nn2z
  3.  */
  4.  
  5. /****************************************************************************
  6. *    $Id: smtpserv.c 1.12 93/07/16 11:50:36 ROOT_DOS Exp $
  7. *    25 Jun 92    paul@wolf.demon.co.uk added automated mail bouncing        *
  8. *    13 Jul 92    1.3        GT    Remove 1.2 changes.                                *
  9. *   27 Aug 92   1.6     mt@kram.demon.co.uk added smtp separator            *
  10. *    03 Sep 92    1.7        GT    Fix missing BOUNCER conditional.                *
  11. *    08 Dec 92    1.8        mt@kram.org: Occasional pwait() during copy            *
  12. *                        cms@home:     Alias-File Mail Bouncing System        *
  13. *    19 Mar 93    1.9        GT    Debugging mailit.                                *
  14. *    04 Apr 93    1.10    GT    Re-enable beep.                                    *
  15. *    05 Apr 93    1.11    GT    Reinstate delay call.                            *
  16. *    08 May 93    1.12    GT    Fix warnings.                                    *
  17. *                        IAY    Improve behaviour of rest of system                *
  18. *                            while this module is copying files,                *
  19. *                            particularly while in SMTP MODE QUEUE.            *
  20. *                        IAY    Fix dot transparency as per RFC 821.            *
  21. *                        GBD    Fix alias expansion to allow multiple spaces.    *
  22. ****************************************************************************/
  23.  
  24. /*
  25. ** The following definition controls how often the copy_data
  26. ** function calls pwait().  Lower numbers mean better response
  27. ** to other things that may be going on at the expense of the
  28. ** speed of that particular function.
  29. */
  30. #define COPY_DATA_WAIT 1
  31.  
  32. #include <stdio.h>
  33. #include <time.h>
  34.  
  35. #undef    DEBUG_LOCKS
  36.  
  37. #ifdef NOVELL
  38.  
  39. #include "nit.h"
  40. #include <io.h>
  41. #include <dos.h>
  42. #include <dir.h>
  43. #include <time.h>
  44.  
  45. #endif
  46.  
  47. extern    char    novell_server_name[128];
  48. extern    char    novell_mail_ext[4];
  49. extern    unsigned short    novell_start;
  50. extern    char    *smtp_separator;
  51. extern    int        Smtpbeep;
  52.  
  53. #ifdef UNIX
  54. #include <sys/types.h>
  55. #endif
  56. #if    defined(__STDC__) || defined(__TURBOC__)
  57. #include <stdarg.h>
  58. #endif
  59. #include <ctype.h>
  60. #include <setjmp.h>
  61. #include "global.h"
  62. #include "mbuf.h"
  63. #include "cmdparse.h"
  64. #include "socket.h"
  65. #include "iface.h"
  66. #include "proc.h"
  67. #include "smtp.h"
  68. #include "commands.h"
  69. #include "dirutil.h"
  70. #include "mailbox.h"
  71. #include "bm.h"
  72. #include "domain.h"
  73. #include "files.h"
  74. #include "ip.h"
  75.  
  76. char *Days[7] =
  77. {
  78.     "Sun","Mon","Tue","Wed","Thu","Fri","Sat"
  79. }
  80. ;
  81. char *Months[12] =
  82. {
  83.     "Jan","Feb","Mar","Apr","May","Jun",
  84.     "Jul","Aug","Sep","Oct","Nov","Dec"
  85. }
  86. ;
  87.  
  88.  
  89.  
  90. static void copy_data __ARGS((FILE *from, FILE *to));
  91. static struct list *expandalias __ARGS((struct list **head,char *user));
  92. static int  getmsgtxt __ARGS((struct smtpsv *mp));
  93. static struct smtpsv *mail_create __ARGS((void));
  94. static void mail_clean __ARGS((struct smtpsv *mp));
  95. static int mailit __ARGS((FILE *data,char *from,struct list *tolist));
  96. static int router_queue __ARGS((FILE *data,char *from,struct list *to));
  97. static void smtplog __ARGS((char *fmt,...));
  98. static void smtpserv __ARGS((int s,void *unused,void *p));
  99. static int mailuser __ARGS((FILE *data,char *from,char *to));
  100. static int validate_user __ARGS((char *user));
  101. static int validate_sender __ARGS((char *sender));
  102. static int remlist __ARGS((struct list **head, struct list *unwanted));
  103.  
  104. /* Command table */
  105. static char *commands[] =
  106. {
  107.     "helo",
  108. #define    HELO_CMD    0
  109.     "noop",
  110. #define    NOOP_CMD    1
  111.     "mail from:",
  112. #define    MAIL_CMD    2
  113.     "quit",
  114. #define    QUIT_CMD    3
  115.     "rcpt to:",
  116. #define    RCPT_CMD    4
  117.     "help",
  118. #define    HELP_CMD    5
  119.     "data",
  120. #define    DATA_CMD    6
  121.     "rset",
  122. #define    RSET_CMD    7
  123.     "expn",
  124. #define EXPN_CMD    8
  125.     NULLCHAR
  126. }
  127. ;
  128.  
  129. /* Reply messages */
  130. static char Help[] = "214-Commands:\n214-HELO NOOP MAIL QUIT RCPT HELP DATA RSET EXPN\n214 End\n";
  131. static char Banner[] = "220 %s SMTP ready\n";
  132. static char Closing[] = "221 Closing\n";
  133. static char Ok[] = "250 Ok\n";
  134. static char Reset[] = "250 Reset state\n";
  135. static char Sent[] = "250 Sent\n";
  136. static char Ourname[] = "250 %s, Have fun, but don't burn the gravy!\n";
  137. static char Unwanted[] = "250 Local policy blocks mail from <%s>\n";
  138. static char Enter[] = "354 Enter mail, end with .\n";
  139. static char Ioerr[] = "452 Temp file write error\n";
  140. static char Badcmd[] = "500 Command unrecognized\n";
  141. static char Lowmem[] = "421 System overloaded, try again later\n";
  142. static char Syntax[] = "501 Syntax error\n";
  143. static char Needrcpt[] = "503 Need RCPT (recipient)\n";
  144. static char Needsender[] = "503 Local policy blocking mail from you\n";
  145. static char Unknown[] = "550 <%s> address unknown\n";
  146. static char Noalias[] = "550 No alias for <%s>\n";
  147. static char UnknownRcpt[]="550 Unknown recipient <%s>\n";
  148. static failure fail;
  149. static int bad_sender;
  150. char default_address[SLINELEN];
  151.  
  152. static int Ssmtp = -1; /* prototype socket for service */
  153.  
  154. /* Start up SMTP receiver service */
  155. int
  156. smtp1(argc,argv,p)
  157. int argc;
  158. char *argv[];
  159. void *p;
  160. {
  161.     struct sockaddr_in lsocket;
  162.     int s;
  163.  
  164.     if(Ssmtp != -1)
  165.     {
  166.         return 0;
  167.     }
  168.     psignal(Curproc,0);    /* Don't keep the parser waiting */
  169.     chname(Curproc,"SMTP listener");
  170.  
  171.     lsocket.sin_family = AF_INET;
  172.     lsocket.sin_addr.s_addr = INADDR_ANY;
  173.     if(argc < 2)
  174.         lsocket.sin_port = IPPORT_SMTP;
  175.     else
  176.         lsocket.sin_port = atoi(argv[1]);
  177.  
  178.     Ssmtp = socket(AF_INET,SOCK_STREAM,0);
  179.     bind(Ssmtp,(char *)&lsocket,sizeof(lsocket));
  180.     listen(Ssmtp,1);
  181.     for(;;)
  182.     {
  183.         if((s = accept(Ssmtp,NULLCHAR,(int *)NULL)) == -1)
  184.             break;    /* Service is shutting down */
  185.  
  186.         if(availmem() < Memthresh)
  187.         {
  188.             usprintf(s,Lowmem);
  189.             shutdown(s,1);
  190.         }
  191.         else
  192.         {
  193.             /* Spawn a server */
  194.             newproc("SMTP server",2048,smtpserv,s,NULL,NULL,0);
  195.         }
  196.     }
  197.     return 0;
  198. }
  199.  
  200. /* Shutdown SMTP service (existing connections are allowed to finish) */
  201. int
  202. smtp0(argc,argv,p)
  203. int argc;
  204. char *argv[];
  205. void *p;
  206. {
  207.     close_s(Ssmtp);
  208.     Ssmtp = -1;
  209.     return 0;
  210. }
  211.  
  212. static void
  213. smtpserv(s,unused,p)
  214. int s;
  215. void *unused;
  216. void *p;
  217. {
  218.     struct smtpsv *mp;
  219.     char **cmdp,buf[LINELEN],*arg,*cp,*cmd,*newaddr;
  220.     struct list *ap,*list;
  221.     int cnt;
  222.     char address_type;
  223.  
  224.     sockmode(s,SOCK_ASCII);
  225.     sockowner(s,Curproc);        /* We own it now */
  226.     log(s,"open SMTP");
  227.  
  228.     if((mp = mail_create()) == NULLSMTPSV)
  229.     {
  230.         tprintf(Nospace);
  231.         log(s,"close SMTP - no space");
  232.         close_s(s);
  233.         return;
  234.     }
  235.     mp->s = s;
  236.  
  237.     (void) usprintf(s,Banner,Hostname);
  238.  
  239. loop:
  240.     if ((cnt = recvline(s,buf,sizeof(buf))) == -1)
  241.     {
  242.         /* He closed on us */
  243.         goto quit;
  244.     }
  245.     if(cnt < 4)
  246.     {
  247.         /* Can't be a legal command */
  248.         usprintf(mp->s,Badcmd);
  249.         goto loop;
  250.     }    
  251.     rip(buf);
  252.     cmd = buf;
  253.  
  254.     /* Translate entire buffer to lower case */
  255.     for(cp = cmd;*cp != '\0';cp++)
  256.         *cp = tolower(*cp);
  257.  
  258.     /* Find command in table; if not present, return syntax error */
  259.     for(cmdp = commands;*cmdp != NULLCHAR;cmdp++)
  260.         if(strncmp(*cmdp,cmd,strlen(*cmdp)) == 0)
  261.             break;
  262.     if(*cmdp == NULLCHAR)
  263.     {
  264.         (void) usprintf(mp->s,Badcmd);
  265.         goto loop;
  266.     }
  267.     arg = &cmd[strlen(*cmdp)];
  268.     /* Skip spaces after command */
  269.     while(*arg == ' ')
  270.         arg++;
  271.     /* Execute specific command */
  272.     switch(cmdp-commands)
  273.     {
  274.     case HELO_CMD:
  275.         free(mp->system);
  276.         mp->system = strdup(arg);
  277.         (void) usprintf(mp->s,Ourname,Hostname);
  278.         break;
  279.     case NOOP_CMD:
  280.         (void) usprintf(mp->s,Ok);
  281.         break;
  282.     case MAIL_CMD:
  283.         bad_sender = 0;
  284.         if((cp = getname(arg)) == NULLCHAR)
  285.         {
  286.             (void) usprintf(mp->s,Syntax);
  287.             break;
  288.         }
  289.         if (!validate_sender(cp))
  290.         {
  291.             (void) usprintf(mp->s,Unwanted,cp);
  292.             smtplog("rejected: from: %s",cp);
  293.             bad_sender = 1;
  294.             break;
  295.         }
  296.         free(mp->from);
  297.         mp->from = strdup(cp);
  298.         (void) usprintf(mp->s,Ok);
  299.         break;
  300.     case QUIT_CMD:
  301.         (void) usprintf(mp->s,Closing);
  302.         goto quit;
  303.     case RCPT_CMD:
  304.         /* Specify recipient */
  305.         fail = NO_FAIL;
  306.         if((cp = getname(arg)) == NULLCHAR)
  307.         {
  308.             (void) usprintf(mp->s,Syntax);
  309.             break;
  310.         }
  311.  
  312.         /* rewrite address if possible */
  313.         if((newaddr = rewrite_address(cp)) != NULLCHAR)
  314.         {
  315.             strcpy(buf,newaddr);
  316.             cp = buf;
  317.             free(newaddr);
  318.         }
  319.  
  320.         /* check if address is ok */
  321.         if ((address_type = validate_address(cp)) == BADADDR)
  322.         {
  323.             (void) usprintf(mp->s,Unknown,cp);
  324.             break;
  325.         }
  326.  
  327.         /* if a local address check for an alias */
  328.         if (address_type == LOCAL)
  329.         {
  330.             expandalias(&mp->to, cp);
  331.             for (ap = mp->to; ap != NULLLIST; ap = ap->next)
  332.             {
  333.                 if (ap->type == LOCAL)
  334.                 {
  335.                     if (!validate_user(ap->val))
  336.                     {
  337.                         switch (fail)
  338.                         {
  339.                         case FAIL_DELIVER:
  340.                             break;
  341.                         case FAIL_DEFAULT:
  342.                             expandalias(&ap->next, default_address);
  343.                             if (validate_user(ap->next->val))
  344.                                 {
  345.                                 remlist(&mp->to, ap);
  346.                                 break;
  347.                                 }
  348.                                 /* else fall through to fail */
  349.                         default:
  350.                             usprintf(mp->s,UnknownRcpt,ap->val);
  351.                             fail = FAIL_BAD;
  352.                             break;
  353.                         }
  354.                     if (fail == FAIL_BAD)
  355.                         break;
  356.                     }
  357.                 }
  358.             }
  359.             if (fail == FAIL_BAD)
  360.                 break;
  361.  
  362.         }
  363.         else
  364.             /* a remote address is added to the list */
  365.             addlist(&mp->to, cp, address_type);
  366.  
  367.         (void) usprintf(mp->s,Ok);
  368.         break;
  369.     case HELP_CMD:
  370.         (void) usprintf(mp->s,Help);
  371.         break;
  372.     case DATA_CMD:
  373.         if ((mp->to == NULLLIST) || fail == FAIL_BAD)
  374.             (void) usprintf(mp->s,Needrcpt);
  375.         else if (bad_sender)
  376.             (void) usprintf(mp->s,Needsender);
  377.         else if ((mp->data = tmpfile()) == NULLFILE)
  378.             (void) usprintf(mp->s,Ioerr);
  379.         else
  380.             getmsgtxt(mp);
  381.         break;
  382.     case RSET_CMD:
  383.         del_list(mp->to);
  384.         mp->to = NULLLIST;
  385.         fail = NO_FAIL;
  386.         (void) usprintf(mp->s,Reset);
  387.         break;
  388.     case EXPN_CMD:
  389.         if (*arg == '\0')
  390.         {
  391.             (void) usprintf(mp->s,Syntax);
  392.             break;
  393.         }
  394.  
  395.         list = NULLLIST;
  396.         /* rewrite address if possible */
  397.         if((newaddr = rewrite_address(arg)) != NULLCHAR)
  398.             if(strcmp(newaddr,arg) == 0)
  399.             {
  400.                 free(newaddr);
  401.                 newaddr = NULLCHAR;
  402.             }
  403.             else
  404.             {
  405.                 strcpy(buf,newaddr);
  406.                 arg = buf;
  407.             }
  408.         list = NULLLIST;
  409.         expandalias(&list,arg);
  410.         if (strcmp(list->val,arg) == 0 && list->next == NULLLIST)
  411.             if(newaddr == NULLCHAR)
  412.             {
  413.                 (void) usprintf(mp->s,Noalias,arg);
  414.                 del_list(list);
  415.                 break;
  416.             }
  417.         ap = list;
  418.         while (ap->next != NULLLIST)
  419.         {
  420.             (void) usprintf(mp->s,"250-%s\n",ap->val);
  421.             ap = ap->next;
  422.         }
  423.         usprintf(mp->s,"250 %s\n",ap->val);
  424.         del_list(list);
  425.         free(newaddr);
  426.         break;
  427.     }
  428.     goto loop;
  429.  
  430. quit:
  431.     log(mp->s,"close SMTP");
  432.     close_s(mp->s);
  433.     mail_clean(mp);
  434.     smtptick(NULL);            /* start SMTP daemon immediately */
  435. }
  436.  
  437. /* read the message text */
  438. static int
  439. getmsgtxt(mp)
  440. struct smtpsv *mp;
  441. {
  442.     char buf[LINELEN];
  443.     register char *p = buf;
  444.     long t;
  445.  
  446.     /* Add timestamp; ptime adds newline */
  447.     time(&t);
  448.     fprintf(mp->data,"Received: ");
  449.     if(mp->system != NULLCHAR)
  450.         fprintf(mp->data,"from %s ",mp->system);
  451.     fprintf(mp->data,"by %s with SMTP\n\tid AA%ld ; %s",
  452.       Hostname, get_msgid(), ptime(&t));
  453.     if(ferror(mp->data))
  454.     {
  455.         (void) usprintf(mp->s,Ioerr);
  456.         return 1;
  457.     }
  458.     else
  459.     {
  460.         (void) usprintf(mp->s,Enter);
  461.     }
  462.     while(1)
  463.     {
  464.         if(recvline(mp->s,p,sizeof(buf)) == -1)
  465.         {
  466.             return 1;
  467.         }
  468.  
  469.         rip(p);
  470.  
  471.         /*
  472.         ** If the line starts with a '.', this is either
  473.         ** the end of the message or a line where a dot
  474.         ** has been added for "dot transparency"
  475.         */
  476.  
  477.         if (*p == '.')
  478.         {
  479.             /*
  480.             ** Strip off leading '.'; if there is nothing
  481.             ** else on the line, this is the end of the
  482.             ** data.  Otherwise, we have managed to remove
  483.             ** the protecting dot and p now points at the
  484.             ** unprotected message line.
  485.             */
  486.             if (*++p == '\0')
  487.             {
  488.                 /* Also sends appropriate response */
  489.                 if (mailit(mp->data,mp->from,mp->to) != 0)
  490.                     (void) usprintf(mp->s,Ioerr);
  491.                 else
  492.                     (void) usprintf(mp->s,Sent);
  493.                 fclose(mp->data);
  494.                 mp->data = NULLFILE;
  495.                 del_list(mp->to);
  496.                 mp->to = NULLLIST;
  497.                 return 0;
  498.             }
  499.  
  500.         }
  501.  
  502.         /* for UNIX mail compatiblity */
  503.         if (strncmp(p,"From ",5) == 0)
  504.             (void) putc('>',mp->data);
  505.         /* Append to data file */
  506.         if(fprintf(mp->data,"%s\n",p) < 0)
  507.         {
  508.             (void) usprintf(mp->s,Ioerr);
  509.             return 1;
  510.         }
  511.     }
  512. }
  513.  
  514. /* Create control block, initialize */
  515. static struct smtpsv *
  516. mail_create()
  517. {
  518.     register struct smtpsv *mp;
  519.  
  520.     mp = (struct smtpsv *)callocw(1,sizeof(struct smtpsv));
  521.     mp->from = strdup("");    /* Default to null From address */
  522.     return mp;
  523. }
  524.  
  525. /* Free resources, delete control block */
  526. static void
  527. mail_clean(mp)
  528. register struct smtpsv *mp;
  529. {
  530.     if (mp == NULLSMTPSV)
  531.         return;
  532.     free(mp->system);
  533.     free(mp->from);
  534.     if(mp->data != NULLFILE)
  535.         fclose(mp->data);
  536.     del_list(mp->to);
  537.     free((char *)mp);
  538. }
  539.  
  540.  
  541. /* Given a string of the form <user@host>, extract the part inside the
  542.  * brackets and return a pointer to it.
  543.  */
  544. char *
  545. getname(cp)
  546. register char *cp;
  547. {
  548.     register char *cp1;
  549.  
  550.     if ((cp = strchr(cp,'<')) == NULLCHAR)
  551.         return NULLCHAR;
  552.     cp++;    /* cp -> first char of name */
  553.     if ((cp1 = strchr(cp,'>')) == NULLCHAR)
  554.         return NULLCHAR;
  555.     *cp1 = '\0';
  556.     return cp;
  557. }
  558.  
  559. #ifdef NOVELL
  560.  
  561. long int get_mail_id(char *user,char *server)
  562. {
  563.     int        connectionID=1;
  564.     int        cCode=0;
  565.     int        DefCon;
  566.     long    int retval;
  567.     int        err;
  568.  
  569.     cCode=GetConnectionID(server,&connectionID);
  570.  
  571.     DefCon=GetDefaultConnectionID();
  572.  
  573.     if(DefCon!=connectionID)
  574.     {
  575.         SetPreferredConnectionID(connectionID);
  576.     }
  577.  
  578.     cCode=GetBinderyObjectID(user,OT_USER,&retval);
  579.  
  580.     if(cCode!=0)
  581.     {
  582.         retval=0;
  583.     }
  584.  
  585.     if(DefCon!=connectionID)
  586.     {
  587.         SetPrimaryConnectionID(DefCon);
  588.     }
  589.     return    retval;
  590. }
  591.  
  592. void send_alert(char *user,char *server,char *from)
  593. {
  594.     int        numcon,conlist[100],reslist[100];
  595.     int        connectionID=1;
  596.     int        cCode=0;
  597.     int        DefCon;
  598.     long    int retval;
  599.     int        err;
  600.     char    message[128];
  601.  
  602.     cCode=GetConnectionID(server,&connectionID);
  603.  
  604.     DefCon=GetDefaultConnectionID();
  605.  
  606.     if(DefCon!=connectionID)
  607.     {
  608.         SetPreferredConnectionID(connectionID);
  609.     }
  610.  
  611.     cCode=GetObjectConnectionNumbers(user,OT_USER,&numcon,conlist,100);
  612.  
  613.     sprintf(message,"You have mail from %s",from);
  614.  
  615.     message[55]=0; /* Nasty truncation to cope with bindings */
  616.  
  617.     cCode=SendBroadcastMessage(message,conlist,reslist,numcon);
  618.  
  619.     if(DefCon!=connectionID)
  620.     {
  621.         SetPrimaryConnectionID(DefCon);
  622.     }
  623. }
  624.  
  625. #endif
  626.  
  627. /*
  628. ** copy_data
  629. **
  630. ** This function copies all available data from an input file to an
  631. ** output file.  This is done in chunks of LINELEN for efficiency.
  632. ** In addition, the function deschedules itself every so often so
  633. ** that large copy operations of this type do not completely block
  634. ** processing of other operations.
  635. */
  636. static void
  637. copy_data ( from, to )
  638. FILE *from, *to;
  639. {
  640.     int c;
  641.     #if COPY_DATA_WAIT != 1
  642.         int counter = 0;
  643.     #endif
  644.     char buf[LINELEN];
  645.     while ( (c = fread(buf, 1, sizeof(buf), from) ) > 0)
  646.     {
  647.         if (fwrite(buf, 1, c, to) != c)
  648.             break;
  649.         #if COPY_DATA_WAIT == 1
  650.             pwait(NULL);
  651.         #else
  652.             if (++counter == COPY_DATA_WAIT)
  653.             {
  654.                 pwait(NULL);
  655.                 counter = 0;
  656.             }
  657.         #endif
  658.     }
  659. }
  660.  
  661. /* General mailit function. It takes a list of addresses which have already
  662. ** been verified and expanded for aliases. Base on the current mode the message
  663. ** is place in an mbox, the outbound smtp queue or the rqueue interface
  664. */
  665. static int
  666. mailit(data,from,tolist)
  667. FILE *data;
  668. char *from;
  669. struct list *tolist;
  670. {
  671.     struct list *ap, *dlist = NULLLIST;
  672.     register FILE *fp;
  673.     char    mailbox[85], *cp, *host, *qhost;
  674.     int    fail = 0;
  675.     time_t    t;
  676.  
  677.     if ((Smtpmode & QUEUE) != 0)
  678.         return(router_queue(data,from,tolist));
  679.  
  680.     do
  681.     {
  682.         qhost = NULLCHAR;
  683.         for(ap = tolist;ap != NULLLIST;ap = ap->next)
  684.         {
  685. #if    defined (DEBUG_LOCKS)
  686.             smtplog ("mailit (): ap->val = %s", ap->val);
  687.             smtplog ("mailit (): ap->type = %d", ap->type);
  688. #endif
  689.             if (ap->type == DOMAIN)
  690.             {
  691.                 if ((host = strrchr(ap->val,'@')) != NULLCHAR)
  692.                     host++;
  693.                 else
  694.                     host = Hostname;
  695.                 if(qhost == NULLCHAR)
  696.                     qhost = host;
  697.                 if(stricmp(qhost,host) == 0)
  698.                 {
  699.                     ap->type = BADADDR;
  700.                     addlist(&dlist,ap->val,0);
  701.                 }
  702.             }
  703.         }
  704.         if(qhost != NULLCHAR)
  705.         {
  706. #if    defined (DEBUG_LOCKS)
  707.             smtplog ("mailit (): qhost = %s, queueing", qhost);
  708. #endif
  709.             rewind(data);
  710.             queuejob(data,qhost,dlist,from,NULL);
  711.             del_list(dlist);
  712.             dlist = NULLLIST;
  713.         }
  714.     }
  715.     while(qhost != NULLCHAR)
  716.         ;
  717.  
  718.     for(ap = tolist;ap != NULLLIST;ap = ap->next)
  719.     {
  720.         if(ap->type != LOCAL)
  721.         {
  722.             ap->type = DOMAIN;
  723.             continue;
  724.         }
  725.         rewind(data);
  726.         /* strip off host name of LOCAL addresses */
  727.         if ((cp = strchr(ap->val,'@')) != NULLCHAR)
  728.             *cp = '\0';
  729.  
  730.         /* truncate long user names */
  731.         if (strlen(ap->val) > MBOXLEN)
  732.             ap->val[MBOXLEN] = '\0';
  733.  
  734.         /* if mail file is busy save it in our smtp queue
  735.          * and let the smtp daemon try later.
  736.          */
  737.  
  738. #ifdef NOVELL
  739.         if(!novell_start)
  740.         {
  741. #endif
  742.             if (mlock(Mailspool,ap->val))
  743.             {
  744.                 int32 msgid;
  745.  
  746. #if    defined (DEBUG_LOCKS)
  747.                 smtplog ("mailit (): mail spool file %s, %s locked, queueing",
  748.                          Mailspool, ap->val);
  749. #endif
  750.                 addlist(&dlist,ap->val,0);
  751.                 fail = queuejob(data,Hostname,dlist,from,&msgid);
  752.                 if (!fail)
  753.                     delay_job(msgid);
  754.  
  755.                 del_list(dlist);
  756.                 dlist = NULLLIST;
  757.             }
  758. #ifdef NOVELL
  759.         }
  760. #endif
  761.         else
  762.         {
  763.             char buf[LINELEN];
  764.             int tocnt = 0;
  765.             extern int smtpverbose;
  766.  
  767. #ifdef NOVELL
  768.             long int oid;
  769.             char    box[13];
  770.             struct    ffblk    fblock;
  771.             static    int    done_rand=0;
  772.  
  773.             if(novell_start)
  774.             {
  775.                 oid=get_mail_id(ap->val,novell_server_name);
  776.  
  777.                 ltoa(oid,box,16);
  778.  
  779.                 if(!done_rand)
  780.                 {
  781.                     randomize(); /* This is non-deterministic */
  782.                     done_rand=1;
  783.                 }
  784.  
  785.                 do
  786.                 {
  787.                     sprintf(mailbox,"%s/%s/%s/%04x%04x.%s",novell_server_name,"SYS:/MAIL",box,rand(),rand(),novell_mail_ext);
  788.                 }
  789.                 while(!findfirst(mailbox,&fblock,0))
  790.                     ;
  791.             }
  792.             else
  793. #endif
  794.             {
  795.                 sprintf(mailbox,"%s/%s.txt",Mailspool,ap->val);
  796.             }
  797.  
  798. #ifndef    AMIGA
  799.             if((fp = fopen(mailbox,APPEND_TEXT)) != NULLFILE)
  800.             {
  801. #    ifdef NOVELL
  802.                 if(novell_start)
  803.                 {
  804.                     send_alert(ap->val,novell_server_name,from);
  805.                 }
  806. #    endif
  807.  
  808. #else
  809.             if((fp = fopen(mailbox,"r+")) != NULLFILE)
  810.             {
  811.                 (void) fseek(fp, 0L, 2);
  812. #endif
  813.                 time(&t);
  814.                 if (smtp_separator)
  815.                     fprintf(fp, "%s\n", smtp_separator);
  816.                 fprintf(fp,"From %s %s",from,ctime(&t));
  817.                 host = NULLCHAR;
  818.                 while(fgets(buf,sizeof(buf),data) != NULLCHAR)
  819.                 {
  820.                     if(buf[0] == '\n')
  821.                     {
  822.                         if(tocnt == 0)
  823.                             fprintf(fp,"%s%s\n",
  824.                               Hdrs[APPARTO],
  825.                               ap->val);
  826.                         fputc('\n',fp);
  827.                         break;
  828.                     }
  829.                     fputs(buf,fp);
  830.                     rip(buf);
  831.                     switch(htype(buf))
  832.                     {
  833.                     case TO:
  834.                     case CC:
  835.                         ++tocnt;
  836.                         break;
  837.                     case RRECEIPT:
  838.                         if((cp = getaddress(buf,0))
  839.                           != NULLCHAR)
  840.                         {
  841.                             free(host);
  842.                             host = strdup(cp);
  843.                         }
  844.                         break;
  845.                     }
  846.                 }
  847.                 copy_data(data, fp);
  848.                 if(ferror(fp))
  849.                     fail = 1;
  850.                 else
  851.                     fprintf(fp,"\n");
  852.                 /* Leave a blank line between msgs */
  853.                 fclose(fp);
  854.  
  855.                 if (smtpverbose)
  856.                 {
  857.                     tprintf("New mail arrived for %s\n",ap->val);
  858.                 }
  859.  
  860.                 if (Smtpbeep)
  861.                     printf("\a\a");
  862.  
  863.                 if(host != NULLCHAR)
  864.                 {
  865.                     rewind(data); /* Send return receipt */
  866.                     mdaemon(data,host,NULLLIST,0);
  867.                     free(host);
  868.                 }
  869.             }
  870.             else
  871.                 fail = 1;
  872. #ifdef NOVELL
  873.             if(!novell_start)
  874.             {
  875.                 (void) rmlock(Mailspool,ap->val);
  876.             }
  877. #else
  878.             (void) rmlock(Mailspool,ap->val);
  879. #endif
  880.             if (fail)
  881.             {
  882.                 break;
  883.             }
  884.             smtplog("deliver: To: %s From: %s",ap->val,from);
  885.         }
  886.     }
  887.     return fail;
  888. }
  889.  
  890. /* Return Date/Time in Arpanet format in passed string */
  891. char *
  892. ptime(t)
  893. long *t;
  894. {
  895.     /* Print out the time and date field as
  896.      *        "DAY day MONTH year hh:mm:ss ZONE"
  897.      */
  898.     register struct tm *ltm;
  899.     static char tz[4];
  900.     static char str[40];
  901.     char *p, *getenv();
  902.     /* Read the system time */
  903.     ltm = localtime(t);
  904.  
  905.     if (*tz == '\0')
  906.         if ((p = getenv("TZ")) == NULL)
  907.             strcpy(tz,"UTC");
  908.         else
  909.             strncpy(tz,p,3);
  910.  
  911.     /* rfc 822 format */
  912.     sprintf(str,"%s, %.2d %s %02d %02d:%02d:%02d %.3s\n",
  913.       Days[ltm->tm_wday],
  914.       ltm->tm_mday,
  915.       Months[ltm->tm_mon],
  916.       ltm->tm_year,
  917.       ltm->tm_hour,
  918.       ltm->tm_min,
  919.       ltm->tm_sec,
  920.       tz);
  921.     return(str);
  922. }
  923.  
  924. long
  925. get_msgid()
  926. {
  927.     char sfilename[LINELEN];
  928.     char s[20];
  929.     register long sequence = 0;
  930.     FILE *sfile;
  931.  
  932.     sprintf(sfilename,"%s/sequence.seq",Mailqdir);
  933.     sfile = fopen(sfilename,READ_TEXT);
  934.  
  935.     /* if sequence file exists, get the value, otherwise set it */
  936.     if (sfile != NULL)
  937.     {
  938.         (void) fgets(s,sizeof(s),sfile);
  939.         sequence = atol(s);
  940.         /* Keep it in range of and 8 digit number to use for dos name prefix. */
  941.         if (sequence < 0L || sequence > 99999999L )
  942.             sequence = 0;
  943.         fclose(sfile);
  944.     }
  945.  
  946.     /* increment sequence number, and write to sequence file */
  947.     sfile = fopen(sfilename,WRITE_TEXT);
  948.     fprintf(sfile,"%ld",++sequence);
  949.     fclose(sfile);
  950.     return sequence;
  951. }
  952.  
  953. #ifdef    MSDOS
  954. /* Illegal characters in a DOS filename */
  955. static char baddoschars[] = "\"[]:|<>+=;,";
  956. #endif
  957.  
  958. /* test if mail address is valid */
  959. int
  960. validate_address(s)
  961. char *s;
  962. {
  963.     char *cp, *t;
  964.     int32 addr;
  965.  
  966.     /* if address has @ in it the check dest address */
  967.     if (*s == '@' && (cp = strrchr(s,':')) != NULLCHAR)
  968.         for (t = s,cp++; (*t++ = *cp++) != 0; )
  969.             ;
  970.     if ((cp = strrchr(s,'@')) != NULLCHAR)
  971.     {
  972.         cp++;
  973.         /* 1st check if its our hostname
  974.         * if not then check the hosts file and see
  975.         * if we can resolve ther address to a know site
  976.         * or one of our aliases
  977.         */
  978.         if (strcmp(cp,Hostname) != 0)
  979.         {
  980.             if ((addr = mailroute(cp, 0)) == 0
  981.               && (Smtpmode & QUEUE) == 0)
  982.                 return BADADDR;
  983.             if (ismyaddr(addr) == NULLIF)
  984.                 return DOMAIN;
  985.         }
  986.  
  987.         /* on a local address remove the host name part */
  988.         *--cp = '\0';
  989.     }
  990.  
  991.     /* if using an external router leave address alone */
  992.     if ((Smtpmode & QUEUE) != 0)
  993.         return LOCAL;
  994.  
  995.     /* check for the user%host hack */
  996.     if ((cp = strrchr(s,'%')) != NULLCHAR)
  997.     {
  998.         *cp = '@';
  999.         cp++;
  1000.         /* reroute based on host name following the % seperator */
  1001.         if (mailroute(cp, 0) == 0)
  1002.             return BADADDR;
  1003.         else
  1004.             return DOMAIN;
  1005.     }
  1006.  
  1007. #ifdef MSDOS    /* dos file name checks */
  1008.     /* Check for characters illegal in MS-DOS file names */
  1009.     for(cp = baddoschars;*cp != '\0';cp++)
  1010.     {
  1011.         if(strchr(s,*cp) != NULLCHAR)
  1012.             return BADADDR;    
  1013.     }
  1014. #endif
  1015.     return LOCAL;
  1016. }
  1017.  
  1018. /* place a mail job in the outbound queue */
  1019. int
  1020. queuejob(dfile,host,to,from,msgid)
  1021. FILE *dfile;
  1022. char *host;
  1023. struct list *to;
  1024. char *from;
  1025. int32 *msgid;
  1026. {
  1027.     FILE *fp;
  1028.     struct list *ap;
  1029.     char tmpstring[50], prefix[9], buf[LINELEN];
  1030.     register int cnt;
  1031.     int32 this_msgid;
  1032.  
  1033.     this_msgid = get_msgid();
  1034.     sprintf(prefix,"%ld",this_msgid);
  1035.     if (msgid)
  1036.         *msgid = this_msgid;
  1037.     mlock(Mailqdir,prefix);
  1038.     sprintf(tmpstring,"%s/%s.txt",Mailqdir,prefix);
  1039.     if((fp = fopen(tmpstring,WRITE_TEXT)) == NULLFILE)
  1040.     {
  1041.         (void) rmlock(Mailqdir,prefix);
  1042.         return 1;
  1043.     }
  1044.     while((cnt = fread(buf, 1, LINELEN, dfile)) > 0)
  1045.         if(fwrite(buf, 1, cnt, fp) != cnt)
  1046.             break;
  1047.     if(ferror(fp))
  1048.     {
  1049.         fclose(fp);
  1050.         (void) rmlock(Mailqdir,prefix);
  1051.         return 1;
  1052.     }
  1053.     fclose(fp);
  1054.     sprintf(tmpstring,"%s/%s.wrk",Mailqdir,prefix);
  1055.     if((fp = fopen(tmpstring,WRITE_TEXT)) == NULLFILE)
  1056.     {
  1057.         (void) rmlock(Mailqdir,prefix);
  1058.         return 1;
  1059.     }
  1060.     fprintf(fp,"%s\n%s\n",host,from);
  1061.     for(ap = to; ap != NULLLIST; ap = ap->next)
  1062.     {
  1063.         fprintf(fp,"%s\n",ap->val);
  1064.         smtplog("queue job %s To: %s From: %s",prefix,ap->val,from);
  1065.     }
  1066.     fclose(fp);
  1067.     (void) rmlock(Mailqdir,prefix);
  1068.     return 0;
  1069. }
  1070.  
  1071. /* Deliver mail to the appropriate mail boxes */
  1072. static int
  1073. router_queue(data,from,to)
  1074. FILE *data;
  1075. char *from;
  1076. struct list *to;
  1077. {
  1078.     register struct list *ap;
  1079.     FILE *fp;
  1080.     char tmpstring[50];
  1081.     char prefix[9];
  1082.  
  1083.     sprintf(prefix,"%ld",get_msgid());
  1084.     mlock(Routeqdir,prefix);
  1085.     sprintf(tmpstring,"%s/%s.txt",Routeqdir,prefix);
  1086.     if((fp = fopen(tmpstring,WRITE_TEXT)) == NULLFILE)
  1087.     {
  1088.         (void) rmlock(Routeqdir,prefix);
  1089.         return 1;
  1090.     }
  1091.     rewind(data);
  1092.     copy_data(data, fp);
  1093.     if(ferror(fp))
  1094.     {
  1095.         fclose(fp);
  1096.         (void) rmlock(Routeqdir,prefix);
  1097.         return 1;
  1098.     }
  1099.     fclose(fp);
  1100.     sprintf(tmpstring,"%s/%s.wrk",Routeqdir,prefix);
  1101.     if((fp = fopen(tmpstring,WRITE_TEXT)) == NULLFILE)
  1102.     {
  1103.         (void) rmlock(Routeqdir,prefix);
  1104.         return 1;
  1105.     }
  1106.     fprintf(fp,"From: %s\n",from);
  1107.     for(ap = to;ap != NULLLIST;ap = ap->next)
  1108.     {
  1109.         fprintf(fp,"To: %s\n",ap->val);
  1110.     }
  1111.     fclose(fp);
  1112.     (void) rmlock(Routeqdir,prefix);
  1113.     smtplog("rqueue job %s From: %s",prefix,from);
  1114.     return 0;
  1115. }
  1116.  
  1117. /* add an element to the front of the list pointed to by head
  1118. ** return NULLLIST if out of memory.
  1119. */
  1120. struct list *
  1121. addlist(head,val,type)
  1122. struct list **head;
  1123. char *val;
  1124. int type;
  1125. {
  1126.     register struct list *tp;
  1127.  
  1128.     tp = (struct list *)callocw(1,sizeof(struct list));
  1129.  
  1130.     tp->next = NULLLIST;
  1131.  
  1132.     /* allocate storage for the char string */
  1133.     tp->val = strdup(val);
  1134.     tp->type = type;
  1135.  
  1136.     /* add entry to front of existing list */
  1137.     if (*head == NULLLIST)
  1138.         *head = tp;
  1139.     else
  1140.     {
  1141.         tp->next = *head;
  1142.         *head = tp;
  1143.     }
  1144.     return tp;
  1145.  
  1146. }
  1147.  
  1148. /* Remove and entry from the list ...            CMS 19/12/92
  1149.     return TRUE on success or FALSE on failure */
  1150. static int remlist(struct list **head, struct list *unwanted)
  1151.     {
  1152.     struct list *ptr, **prev;
  1153.     prev = head;
  1154.     for (ptr = *head; ptr; ptr = ptr->next)
  1155.         if (ptr == unwanted)
  1156.             {
  1157.             *prev = ptr->next;
  1158.             free (ptr);
  1159.             break;
  1160.             }
  1161.         else prev = &ptr->next;
  1162.     return ptr == unwanted;
  1163.     }
  1164.  
  1165. #define SKIPWORD(X) while(*X && *X!=' ' && *X!='\t' && *X!='\n' && *X!= ',') X++;
  1166. #define SKIPSPACE(X) while(*X ==' ' || *X =='\t' || *X =='\n' || *X == ',') X++;
  1167.  
  1168. /* check for and alias and expand alias into a address list */
  1169. static struct list *
  1170. expandalias(head, user)
  1171. struct list **head;
  1172. char *user;
  1173. {
  1174.     FILE *fp;
  1175.     register char *s,*p;
  1176.     struct rr *rrp, *rrlp;
  1177.     int inalias = 0;
  1178.     struct list *tp;
  1179.     char buf[LINELEN];
  1180.  
  1181.     /* no alias file found */
  1182.     if ((fp = fopen(Alias, READ_TEXT)) == NULLFILE)
  1183.     {
  1184.         fail = FAIL_DELIVER;
  1185.         /* Try MB, MG or MR domain name records */
  1186.         rrlp = rrp = resolve_mailb(user);
  1187.         while(rrp != NULLRR)
  1188.         {
  1189.             if(rrp->rdlength > 0)
  1190.             {
  1191.                 /* remove the trailing dot */
  1192.                 rrp->rdata.name[rrp->rdlength-1] = '\0';
  1193.                 /* replace first dot with @ if there is no @ */
  1194.                 if(strchr(rrp->rdata.name,'@') == NULLCHAR
  1195.                   && (p = strchr(rrp->rdata.name,'.')) !=
  1196.                   NULLCHAR)
  1197.                     *p = '@';
  1198.                 if(strchr(rrp->rdata.name,'@') != NULLCHAR)
  1199.                     tp = addlist(head,rrp->rdata.name,
  1200.                       DOMAIN);
  1201.                 else
  1202.                     tp = addlist(head,rrp->rdata.name,
  1203.                       LOCAL);
  1204.                 ++inalias;
  1205.             }
  1206.             rrp = rrp->next;
  1207.         }
  1208.         free_rr(rrlp);
  1209.         if(inalias)
  1210.             return tp;
  1211.         else
  1212.             return addlist(head, user, LOCAL);
  1213.     }
  1214.  
  1215.     while (fgets(buf,LINELEN,fp) != NULLCHAR)
  1216.     {
  1217.         p = buf;
  1218.         if ( *p == '#' || *p == '\0')
  1219.             continue;
  1220.         rip(p);
  1221.  
  1222.         /* if not in an matching entry skip continuation lines */
  1223.         if (!inalias && isspace(*p))
  1224.             continue;
  1225.  
  1226.         /* when processing an active alias check for a continuation */
  1227.         if (inalias)
  1228.         {
  1229.             if (!isspace(*p))
  1230.                 break;    /* done */
  1231.         }
  1232.         else
  1233.         {
  1234.             s = p;
  1235.             SKIPWORD(p);
  1236.             *p++ = '\0';    /* end the alias name */
  1237.             SKIPSPACE (p);
  1238.             if (fail == NO_FAIL && strcmp(s, "default") == 0)
  1239.                 if (strncmp(p, "deliver", 3) == 0)
  1240.                     fail = FAIL_DELIVER;
  1241.                 else {
  1242.                     fail = FAIL_DEFAULT;
  1243.                     strcpy(default_address, p);
  1244.                     }
  1245.             if (strcmp(s,user) != 0)
  1246.                 continue;    /* no match go on */
  1247.             inalias = 1;
  1248.         }
  1249.  
  1250.         /* process the recipients on the alias line */
  1251.         SKIPSPACE(p);
  1252.         while(*p != '\0' && *p != '#')
  1253.         {
  1254.             s = p;
  1255.             SKIPWORD(p);
  1256.             if (*p != '\0')
  1257.                 *p++ = '\0';
  1258.  
  1259.             /* find hostname */
  1260.             if (strchr(s,'@') != NULLCHAR)
  1261.                 tp = addlist(head,s,DOMAIN);
  1262.             else
  1263.                 tp = addlist(head,s,LOCAL);
  1264.             SKIPSPACE(p);
  1265.         }
  1266.     }
  1267.     (void) fclose(fp);
  1268.  
  1269.     if (inalias)    /* found and processed and alias. */
  1270.         return tp;
  1271.  
  1272.     /* no alias found treat as a local address */
  1273.     return addlist(head, user, LOCAL);
  1274. }
  1275.  
  1276. #if    defined(ANSIPROTO)
  1277. static void
  1278. smtplog(char *fmt, ...)
  1279. {
  1280.     va_list ap;
  1281.     char *cp;
  1282.     long t;
  1283.     FILE *fp;
  1284.  
  1285.     if ((fp = fopen(Maillog,APPEND_TEXT)) == NULLFILE)
  1286.         return;
  1287.     time(&t);
  1288.     cp = ctime(&t);
  1289.     rip(cp);
  1290.     fprintf(fp,"%s ",cp);
  1291.     va_start(ap,fmt);
  1292.     vfprintf(fp,fmt,ap);
  1293.     va_end(ap);
  1294.     fprintf(fp,"\n");
  1295.     fclose(fp);
  1296. }
  1297.  
  1298. #else
  1299.  
  1300. static void
  1301. smtplog(fmt,arg1,arg2,arg3,arg4)
  1302. char *fmt;
  1303. int arg1,arg2,arg3,arg4;
  1304. {
  1305.     char *cp;
  1306.     long t;
  1307.     FILE *fp;
  1308.  
  1309.     if ((fp = fopen(Maillog,APPEND_TEXT)) == NULLFILE)
  1310.         return;
  1311.     time(&t);
  1312.     cp = ctime(&t);
  1313.     rip(cp);
  1314.     fprintf(fp,"%s ",cp);
  1315.     fprintf(fp,fmt,arg1,arg2,arg3,arg4);
  1316.     fprintf(fp,"\n");
  1317.     fclose(fp);
  1318. }
  1319. #endif
  1320.  
  1321. /* send mail to a single user. Can be called from the ax24 mailbox or
  1322. ** from the return mail function in the smtp client
  1323. */
  1324. static int
  1325. mailuser(data,from,to)
  1326. FILE *data;
  1327. char *from;
  1328. char *to;
  1329. {
  1330.  
  1331.     int address_type, ret;
  1332.     struct list *tolist = NULLLIST;
  1333.  
  1334.     /* check if address is ok */
  1335.     if ((address_type = validate_address(to)) == BADADDR)
  1336.     {
  1337.         return 1;
  1338.     }
  1339.     /* if a local address check for an alias */
  1340.     if (address_type == LOCAL)
  1341.         expandalias(&tolist, to);
  1342.     else
  1343.         /* a remote address is added to the list */
  1344.         addlist(&tolist, to, address_type);
  1345.     ret = mailit(data,from,tolist);
  1346.     del_list(tolist);
  1347.     return ret;
  1348.  
  1349. }
  1350.  
  1351. /* Mailer daemon return mail mechanism */
  1352. int
  1353. mdaemon(data,to,lp,bounce)
  1354. FILE *data;        /* pointer to rewound data file */
  1355. char *to;        /* Overridden by Errors-To: line if bounce is true */
  1356. struct list *lp;    /* error log for failed mail */
  1357. int bounce;        /* True for failed mail, otherwise return receipt */
  1358. {
  1359.     time_t t;
  1360.     FILE *tfile;
  1361.     char buf[LINELEN], *cp, *newto = NULLCHAR;
  1362.     int cnt;
  1363.     if(to == NULLCHAR || (to != NULLCHAR && *to == '\0') || bounce)
  1364.     {
  1365.         while(fgets(buf,sizeof(buf),data) != NULLCHAR)
  1366.         {
  1367.             if(buf[0] == '\n')
  1368.                 break;
  1369.             /* Look for Errors-To: */
  1370.             if(htype(buf) == ERRORSTO &&
  1371.               (cp = getaddress(buf,0)) != NULLCHAR)
  1372.             {
  1373.                 free(newto);
  1374.                 newto = strdup(cp);
  1375.                 break;
  1376.             }
  1377.         }
  1378.         if(newto == NULLCHAR && ((to != NULLCHAR && *to == '\0') ||
  1379.           to == NULLCHAR))
  1380.             return -1;
  1381.         rewind(data);
  1382.     }
  1383.     if((tfile = tmpfile()) == NULLFILE)
  1384.         return -1;
  1385.     time(&t);
  1386.     fprintf(tfile,"%s%s",Hdrs[DATE],ptime(&t));
  1387.     fprintf(tfile,"%s<%ld@%s>\n",Hdrs[MSGID],get_msgid(),Hostname);
  1388.     fprintf(tfile,"%sMAILER-DAEMON@%s (Mail Delivery Subsystem)\n",
  1389.       Hdrs[FROM],Hostname);
  1390.     fprintf(tfile,"%s%s\n",Hdrs[TO],newto != NULLCHAR ? newto : to);
  1391.     fprintf(tfile,"%s%s\n\n",Hdrs[SUBJECT],
  1392.       bounce ? "Failed mail" : "Return receipt");
  1393.     if(bounce)
  1394.     {
  1395.         fprintf(tfile,"  ===== transcript follows =====\n\n");
  1396.         for (; lp != NULLLIST; lp = lp->next)
  1397.             fprintf(tfile,"%s\n",lp->val);
  1398.         fprintf(tfile,"\n");
  1399.     }
  1400.     fprintf(tfile,"  ===== %s follows ====\n",
  1401.       bounce ? "Unsent message" : "Message header");
  1402.  
  1403.     while(fgets(buf,sizeof(buf),data) != NULLCHAR)
  1404.     {
  1405.         if(buf[0] == '\n')
  1406.             break;
  1407.         fputs(buf,tfile);
  1408.     }
  1409.     if(bounce)
  1410.     {
  1411.         fputc('\n',tfile);
  1412.         while((cnt = fread(buf,1,sizeof(buf),data)) > 0)
  1413.             fwrite(buf,1,cnt,tfile);
  1414.     }
  1415.     fseek(tfile,0L,0);
  1416.     /* A null From<> so no looping replys to MAIL-DAEMONS */
  1417.     (void) mailuser(tfile,"",newto != NULLCHAR ? newto : to);
  1418.     fclose(tfile);
  1419.     free(newto);
  1420.     return 0;
  1421. }
  1422.  
  1423. /* Check to see that we are accepting mail from this sender. If we aren't
  1424.  * then tell 'em that mail from them is Unwanted. I added this facility to
  1425.  * allow auto-rejection of messages from auto-reply daemons. G7LEU
  1426.  */
  1427. static int
  1428. validate_sender(sender)
  1429. char *sender;
  1430. {
  1431.     FILE *fp;
  1432.     char buf[LINELEN + 1], *p;
  1433.     if ((fp = fopen(Mailkill, READ_TEXT)) == NULLFILE)
  1434.         /* Can't open SMTP reject file so let 'em through */
  1435.         return 1;
  1436.     while (fgets(buf,LINELEN,fp) != NULLCHAR)
  1437.         {
  1438.         p = buf;
  1439.         if (*p == '#' || *p == '\0')
  1440.             continue;
  1441.         rip(p);
  1442.         if (!stricmp(p, sender))
  1443.             {
  1444.             extern int smtpverbose;
  1445.             if (smtpverbose)
  1446.                 tprintf("SMTP: Rejected mail from '%s'\n", sender);
  1447.             fclose(fp);
  1448.             return 0;
  1449.             }
  1450.         }
  1451.     fclose(fp);
  1452.     /* Sender OK */
  1453.     return 1;
  1454. }
  1455.  
  1456.  
  1457. /* Check to see if a local user actually exists - use the FTPUSERS file
  1458.  * Returns 0 if the user doesn't exist, 1 otherwise
  1459.  */
  1460. static int
  1461. validate_user(user)
  1462. char *user;
  1463. {
  1464.     char *cp;
  1465.  
  1466. /* always allow 'postmaster' */
  1467.     if (stricmp(user,"postmaster")==0)
  1468.     {
  1469.         return 1;
  1470.     }
  1471. /* otherwise check the ftpusers file */
  1472.  
  1473. #    ifdef NOVELL
  1474.     if(novell_start)
  1475.     {
  1476.         if(!get_mail_id(user,novell_server_name))
  1477.         {
  1478.             return    0;
  1479.         }
  1480.     }
  1481.     else
  1482. #    endif
  1483.     {
  1484.         if ((cp=userlookup(user,NULL,NULLCHARP,NULLINT,NULL)) == NULLCHAR)
  1485.         {
  1486.             return 0;
  1487.         }
  1488.         free(cp);
  1489.     }
  1490.     return 1;
  1491. }
  1492.