home *** CD-ROM | disk | FTP | other *** search
/ HAM Radio 3 / hamradioversion3.0examsandprograms1992.iso / misc / 9q920411 / smtpcli.c < prev    next >
C/C++ Source or Header  |  1991-07-11  |  23KB  |  960 lines

  1. /*
  2.  *    CLIENT routines for Simple Mail Transfer Protocol ala RFC821
  3.  *    A.D. Barksdale Garbee II, aka Bdale, N3EUA
  4.  *    Copyright 1986 Bdale Garbee, All Rights Reserved.
  5.  *    Permission granted for non-commercial copying and use, provided
  6.  *    this notice is retained.
  7.  *     Modified 14 June 1987 by P. Karn for symbolic target addresses,
  8.  *    also rebuilt locking mechanism
  9.  *    Copyright 1987 1988 David Trulli, All Rights Reserved.
  10.  *    Permission granted for non-commercial copying and use, provided
  11.  *    this notice is retained.
  12.  */
  13. #include <stdio.h>
  14. #include <fcntl.h>
  15. #include <time.h>
  16. #include <setjmp.h>
  17. #ifdef UNIX
  18. #include <sys/types.h>
  19. #endif
  20. #ifdef    AMIGA
  21. #include <stat.h>
  22. #else
  23. #include <sys/stat.h>
  24. #endif
  25. #ifdef    __TURBOC__
  26. #include <dir.h>
  27. #include <io.h>
  28. #endif
  29. #include "global.h"
  30. #ifdef    ANSIPROTO
  31. #include <stdarg.h>
  32. #endif
  33. #include "mbuf.h"
  34. #include "cmdparse.h"
  35. #include "proc.h"
  36. #include "socket.h"
  37. #include "timer.h"
  38. #include "netuser.h"
  39. #include "smtp.h"
  40. #include "dirutil.h"
  41. #include "commands.h"
  42. #include "session.h"
  43.  
  44. static struct timer Smtpcli_t;
  45. static int32 Gateway;
  46.  
  47. #ifdef SMTPTRACE
  48. static unsigned short Smtptrace = 0;        /* used for trace level */
  49. static int dosmtptrace __ARGS((int argc,char *argv[],void *p));
  50. #endif
  51.  
  52. static unsigned  short Smtpmaxcli  = MAXSESSIONS;    /* the max client connections allowed */
  53. static int Smtpsessions = 0;        /* number of client connections
  54.                     * currently open */
  55. static int Smtpbatch;
  56. int    Smtpmode = 0;
  57.  
  58. static struct smtpcli *cli_session[MAXSESSIONS]; /* queue of client sessions  */
  59.  
  60. static void del_job __ARGS((struct smtp_job *jp));
  61. static void del_session __ARGS((struct smtpcli *cb));
  62. static int dogateway __ARGS((int argc,char *argv[],void *p));
  63. static int dosmtpmaxcli __ARGS((int argc,char *argv[],void *p));
  64. static int dotimer __ARGS((int argc,char *argv[],void *p));
  65. static int dosmtpkill __ARGS((int argc,char *argv[],void *p));
  66. static int dosmtplist __ARGS((int argc,char *argv[],void *p));
  67. static int dobatch __ARGS((int argc,char *argv[],void *p));
  68. static void execjobs __ARGS((void));
  69. static int getresp __ARGS((struct smtpcli *ftp,int mincode));
  70. static void logerr __ARGS((struct smtpcli *cb,char *line));
  71. static struct smtpcli *lookup __ARGS((int32 destaddr));
  72. static struct smtpcli *newcb __ARGS((void));
  73. static int next_job __ARGS((struct smtpcli *cb));
  74. static void retmail __ARGS((struct smtpcli *cb));
  75. static void sendcmd __ARGS((struct smtpcli *cb,char *fmt,...));
  76. static int smtpsendfile __ARGS((struct smtpcli *cb));
  77. static int setsmtpmode __ARGS((int argc,char *argv[],void *p));
  78. static struct smtp_job *setupjob __ARGS((struct smtpcli *cb,char *id,char *from));
  79. static void smtp_send __ARGS((int unused,void *cb1,void *p));
  80. static int smtpkick __ARGS((int argc,char *argv[],void *p));
  81.  
  82. static struct cmds Smtpcmds[] = {
  83.     "batch",    dobatch,    0,    0,    NULLCHAR,
  84.     "gateway",    dogateway,    0,    0,    NULLCHAR,
  85.     "mode",        setsmtpmode,    0,    0,    NULLCHAR,
  86.     "kick",        smtpkick,    0,    0,    NULLCHAR,
  87.     "kill",        dosmtpkill,    0,    2,    "kill <jobnumber>",
  88.     "list",        dosmtplist,    0,    0,    NULLCHAR,
  89.     "maxclients",    dosmtpmaxcli,    0,    0,    NULLCHAR,
  90.     "timer",    dotimer,    0,    0,    NULLCHAR,
  91. #ifdef SMTPTRACE
  92.     "trace",    dosmtptrace,    0,    0,    NULLCHAR,
  93. #endif
  94.     NULLCHAR,
  95. };
  96.  
  97. int
  98. dosmtp(argc,argv,p)
  99. int argc;
  100. char *argv[];
  101. void *p;
  102. {
  103.     return subcmd(Smtpcmds,argc,argv,p);
  104. }
  105.  
  106. static int
  107. dobatch(argc,argv,p)
  108. int argc;
  109. char *argv[];
  110. void *p;
  111. {
  112.     return setbool(&Smtpbatch,"SMTP batching",argc,argv);
  113. }
  114. static int
  115. dosmtpmaxcli(argc,argv,p)
  116. int argc;
  117. char *argv[];
  118. void *p;
  119. {
  120.     return setshort(&Smtpmaxcli,"Max clients",argc,argv);
  121. }
  122.  
  123. static int
  124. setsmtpmode(argc,argv,p)
  125. int argc;
  126. char *argv[];
  127. void *p;
  128. {
  129.     if (argc < 2) {
  130.         tprintf("smtp mode: %s\n",
  131.             (Smtpmode & QUEUE) ? "queue" : "route");
  132.     } else {
  133.         switch(*argv[1]) {
  134.         case 'q':
  135.             Smtpmode |= QUEUE;
  136.             break;
  137.         case 'r':
  138.             Smtpmode &= ~QUEUE;
  139.             break;
  140.         default:
  141.             tprintf("Usage: smtp mode [queue | route]\n");
  142.             break;
  143.         }
  144.     }
  145.     return 0;
  146. }
  147. static int
  148. dogateway(argc,argv,p)
  149. int argc;
  150. char *argv[];
  151. void *p;
  152. {
  153.     int32 n;
  154.  
  155.     if(argc < 2){
  156.         tprintf("%s\n",inet_ntoa(Gateway));
  157.     } else if((n = resolve(argv[1])) == 0){
  158.         tprintf(Badhost,argv[1]);
  159.         return 1;
  160.     } else
  161.         Gateway = n;
  162.     return 0;
  163. }
  164.  
  165. #ifdef SMTPTRACE
  166. static int
  167. dosmtptrace(argc,argv,p)
  168. int argc;
  169. char *argv[];
  170. void *p;
  171. {
  172.     return setshort(&Smtptrace,"SMTP tracing",argc,argv);
  173. }
  174. #endif
  175.  
  176. /* list jobs wating to be sent in the mqueue */
  177. static int
  178. dosmtplist(argc,argv,p)
  179. int argc;
  180. char *argv[];
  181. void *p;
  182. {
  183.     char tstring[80];
  184.     char line[20];
  185.     char host[LINELEN];
  186.     char to[LINELEN];
  187.     char from[LINELEN];
  188.     char *cp;
  189.     char    status;
  190.     struct stat stbuf;
  191.     struct tm *tminfo, *localtime();
  192.     FILE *fp;
  193.  
  194.     Current->flowmode = 1; /* Enable the more mechanism */
  195.     tprintf("S     Job    Size Date  Time  Host                 From\n");
  196.     filedir(Mailqueue,0,line);
  197.     while(line[0] != '\0') {
  198.         sprintf(tstring,"%s/%s",Mailqdir,line);
  199.         if ((fp = fopen(tstring,READ_TEXT)) == NULLFILE) {
  200.             tprintf("Can't open %s: %s\n",tstring,sys_errlist[errno]);
  201.             continue;
  202.         }
  203.         if ((cp = strrchr(line,'.')) != NULLCHAR)
  204.             *cp = '\0';
  205.         sprintf(tstring,"%s/%s.lck",Mailqdir,line);
  206.         if (access(tstring,0))
  207.             status = ' ';
  208.         else
  209.             status = 'L';
  210.         sprintf(tstring,"%s/%s.txt",Mailqdir,line);
  211.         stat(tstring,&stbuf);
  212.         tminfo = localtime(&stbuf.st_ctime);
  213.         fgets(host,sizeof(host),fp);
  214.         rip(host);
  215.         fgets(from,sizeof(from),fp);
  216.         rip(from);
  217.         tprintf("%c %7s %7ld %02d/%02d %02d:%02d %-20s %s\n      ",
  218.             status, line, stbuf.st_size,
  219.             tminfo->tm_mon+1,
  220.             tminfo->tm_mday,
  221.             tminfo->tm_hour,
  222.             tminfo->tm_min,
  223.             host,from);
  224.         while (fgets(to,sizeof(to),fp) != NULLCHAR) {
  225.             rip(to);
  226.             tprintf("%s ",to);
  227.         }
  228.         tprintf("\n");
  229.         (void) fclose(fp);
  230.         pwait(NULL);
  231.         filedir(Mailqueue,1,line);
  232.     }
  233.     Current->flowmode = 0;
  234.     return 0;
  235. }
  236.  
  237. /* kill a job in the mqueue */
  238. static int
  239. dosmtpkill(argc,argv,p)
  240. int argc;
  241. char *argv[];
  242. void *p;
  243. {
  244.     char s[SLINELEN];
  245.     char *cp,c;
  246.     sprintf(s,"%s/%s.lck",Mailqdir,argv[1]);
  247.     cp = strrchr(s,'.');
  248.     if (!access(s,0)) {
  249.         Current->ttystate.echo = Current->ttystate.edit = 0;
  250.         c = keywait("Warning, the job is locked by SMTP. Remove (y/n)? ",0);
  251.         Current->ttystate.echo = Current->ttystate.edit = 1;
  252.         if (c != 'y')
  253.             return 0;
  254.         (void) unlink(s);
  255.     }
  256.     strcpy(cp,".wrk");
  257.     if (unlink(s))
  258.         tprintf("Job id %s not found\n",argv[1]);
  259.     strcpy(cp,".txt");
  260.     (void) unlink(s);
  261.     return 0;
  262. }
  263.  
  264. /* Set outbound spool scan interval */
  265. static int
  266. dotimer(argc,argv,p)
  267. int argc;
  268. char *argv[];
  269. void *p;
  270. {
  271.     if(argc < 2){
  272.         tprintf("%lu/%lu\n",
  273.         read_timer(&Smtpcli_t) /1000L,
  274.         dur_timer(&Smtpcli_t)/ 1000L);
  275.         return 0;
  276.     }
  277.     Smtpcli_t.func = (void (*)())smtptick;/* what to call on timeout */
  278.     Smtpcli_t.arg = NULL;        /* dummy value */
  279.     set_timer(&Smtpcli_t,atol(argv[1])*1000L);    /* set timer duration */
  280.     start_timer(&Smtpcli_t);        /* and fire it up */
  281.     return 0;
  282. }
  283.  
  284. static int
  285. smtpkick(argc,argv,p)
  286. int argc;
  287. char *argv[];
  288. void *p;
  289. {
  290.     int32 addr = 0;
  291.     if(argc > 1 && (addr = resolve(argv[1])) == 0){
  292.         tprintf(Badhost,argv[1]);
  293.         return 1;
  294.     }
  295.     smtptick((void *)addr);
  296.     return 0;
  297. }
  298.  
  299. /* This is the routine that gets called every so often to do outgoing
  300.  * mail processing. When called with a null argument, it runs the entire
  301.  * queue; if called with a specific non-zero IP address from the remote
  302.  * kick server, it only starts up sessions to that address.
  303.  */
  304. int
  305. smtptick(t)
  306. void *t;
  307. {
  308.     register struct smtpcli *cb;
  309.     struct smtp_job *jp;
  310.     struct list *ap;
  311.     char    tmpstring[LINELEN], wfilename[13], prefix[9];
  312.     char    from[LINELEN], to[LINELEN];
  313.     char *cp, *cp1;
  314.     int32 destaddr,target;
  315.     FILE *wfile;
  316.  
  317.     target = (int32)t;
  318. #ifdef SMTPTRACE
  319.     if (Smtptrace > 5)
  320.         printf("smtp daemon entered, target = %s\n",inet_ntoa(target));
  321. #endif
  322.     if(availmem() < Memthresh){
  323.         /* Memory is tight, don't do anything */
  324.         /* Restart timer */
  325.         start_timer(&Smtpcli_t);
  326.         return 0;
  327.     }
  328.     for(filedir(Mailqueue,0,wfilename);wfilename[0] != '\0';
  329.         filedir(Mailqueue,1,wfilename)){
  330.  
  331.         /* save the prefix of the file name which it job id */
  332.         cp = wfilename;
  333.         cp1 = prefix;
  334.         while (*cp && *cp != '.')
  335.             *cp1++ = *cp++;
  336.         *cp1 = '\0';
  337.  
  338.         /* lock this file from the smtp daemon */
  339.         if (mlock(Mailqdir,prefix))
  340.             continue;
  341.  
  342.         sprintf(tmpstring,"%s/%s",Mailqdir,wfilename);
  343.         if ((wfile = fopen(tmpstring,READ_TEXT)) == NULLFILE) {
  344.             /* probably too many open files */
  345.             (void) rmlock(Mailqdir,prefix);
  346.             /* continue to next message. The failure
  347.             * may be temporary */
  348.             continue;
  349.         }
  350.  
  351.         (void) fgets(tmpstring,LINELEN,wfile);    /* read target host */
  352.         rip(tmpstring);
  353.  
  354.         if ((destaddr = mailroute(tmpstring)) == 0) {
  355.             fclose(wfile);
  356.             printf("** smtp: Unknown address %s\n",tmpstring);
  357.             (void) rmlock(Mailqdir,prefix);
  358.             continue;
  359.         }
  360.         if(target != 0 && destaddr != target){
  361.             fclose(wfile);
  362.             (void) rmlock(Mailqdir,prefix);
  363.             continue;    /* Not the proper target of a kick */
  364.         }
  365.         if ((cb = lookup(destaddr)) == NULLSMTPCLI) {
  366.             /* there are enough processes running already */
  367.             if (Smtpsessions >= Smtpmaxcli) {
  368. #ifdef SMTPTRACE
  369.                 if (Smtptrace) {
  370.                     printf("smtp daemon: too many processes\n");
  371.                 }
  372. #endif
  373.                 fclose(wfile);
  374.                 (void) rmlock(Mailqdir,prefix);
  375.                 break;
  376.             }
  377.             if ((cb = newcb()) == NULLSMTPCLI) {
  378.                 fclose(wfile);
  379.                 (void) rmlock(Mailqdir,prefix);
  380.                 break;
  381.             } 
  382.             cb->ipdest = destaddr;
  383.             cb->destname = strdup(tmpstring);
  384.         } else {
  385.             if(cb->lock){
  386.                 /* This system is already is sending mail lets not
  387.                 * interfere with its send queue.
  388.                 */
  389.                 fclose(wfile);
  390.                 (void) rmlock(Mailqdir,prefix);
  391.                 continue;
  392.             }
  393.         }
  394.  
  395.         (void) fgets(from,LINELEN,wfile);    /* read from */
  396.         rip(from);
  397.         if ((jp = setupjob(cb,prefix,from)) == NULLJOB) {
  398.             fclose(wfile);
  399.             (void) rmlock(Mailqdir,prefix);
  400.             del_session(cb);
  401.             break;
  402.         }
  403.         while (fgets(to,LINELEN,wfile) != NULLCHAR) {
  404.             rip(to);
  405.             if (addlist(&jp->to,to,DOMAIN) == NULLLIST) {
  406.                 fclose(wfile);
  407.                 del_session(cb);
  408.             }
  409.         }
  410.         fclose(wfile);
  411. #ifdef SMTPTRACE
  412.         if (Smtptrace > 1) {
  413.             printf("queue job %s From: %s To:",prefix,from);
  414.             for (ap = jp->to; ap != NULLLIST; ap = ap->next)
  415.                 printf(" %s",ap->val);
  416.             printf("\n");
  417.         }
  418. #endif
  419.     }
  420.  
  421.     /* start sending that mail */
  422.     execjobs();
  423.  
  424.     /* Restart timer */
  425.     start_timer(&Smtpcli_t);
  426.     return 0;
  427. }
  428.  
  429. /* This is the master state machine that handles a single SMTP transaction.
  430.  * It is called with a queue of jobs for a particular host.
  431.  * The logic is complicated by the "Smtpbatch" variable, which controls
  432.  * the batching of SMTP commands. If Smtpbatch is true, then many of the
  433.  * SMTP commands are sent in one swell foop before waiting for any of
  434.  * the responses. Unfortunately, this breaks many brain-damaged SMTP servers
  435.  * out there, so provisions have to be made to operate SMTP in lock-step mode.
  436.  */
  437. static void
  438. smtp_send(unused,cb1,p)
  439. int unused;
  440. void *cb1;
  441. void *p;
  442. {
  443.     register struct smtpcli *cb;
  444.     register struct list *tp;
  445.     struct sockaddr_in fsocket;
  446.     char *cp;
  447.     int rcode;
  448.     int rcpts;
  449.     int goodrcpt;
  450.     int i;
  451.     int init = 1;
  452.  
  453.     cb = (struct smtpcli *)cb1;
  454.     cb->lock = 1;
  455.     fsocket.sin_family = AF_INET;
  456.     fsocket.sin_addr.s_addr = cb->ipdest;
  457.     fsocket.sin_port = IPPORT_SMTP;
  458.  
  459.     cb->s = socket(AF_INET,SOCK_STREAM,0);
  460.     sockmode(cb->s,SOCK_ASCII);
  461.     setflush(cb->s,-1);    /* We'll explicitly flush before reading */
  462. #ifdef SMTPTRACE
  463.     if (Smtptrace) 
  464.         printf("SMTP client Trying...\n");
  465. #endif
  466.     if(connect(cb->s,(char *)&fsocket,SOCKSIZE) == 0){
  467. #ifdef SMTPTRACE
  468.     if (Smtptrace) 
  469.         printf("Connected\n");
  470. #endif
  471.         ;
  472.     } else {
  473.         cp = sockerr(cb->s);
  474. #ifdef SMTPTRACE
  475.         if (Smtptrace) 
  476.             printf("Connect failed: %s\n",cp != NULLCHAR ? cp : "");
  477. #endif
  478.         log(cb->s,"SMTP %s Connect failed: %s",psocket(&fsocket),
  479.             cp != NULLCHAR ? cp : "");
  480.     }
  481.     if(!Smtpbatch){
  482.         rcode = getresp(cb,200);
  483.         if(rcode == -1 || rcode >= 400)
  484.             goto quit;
  485.     }
  486.     /* Say HELO */
  487.     sendcmd(cb,"HELO %s\n",Hostname);
  488.     if(!Smtpbatch){
  489.         rcode = getresp(cb,200);
  490.         if(rcode == -1 || rcode >= 400)
  491.             goto quit;
  492.     }
  493.     do {    /* For each message... */
  494.  
  495.         /* if this file open fails, skip it */
  496.         if ((cb->tfile = fopen(cb->tname,READ_TEXT)) == NULLFILE)
  497.             continue;
  498.  
  499.         /* Send MAIL and RCPT commands */
  500.         sendcmd(cb,"MAIL FROM:<%s>\n",cb->jobq->from);
  501.         if(!Smtpbatch){
  502.             rcode = getresp(cb,200);
  503.             if(rcode == -1 || rcode >= 400)
  504.                 goto quit;
  505.         }
  506.         rcpts = 0;
  507.         goodrcpt = 0;
  508.         for (tp = cb->jobq->to; tp != NULLLIST; tp = tp->next){
  509.             sendcmd(cb,"RCPT TO:<%s>\n",tp->val);
  510.             if(!Smtpbatch){
  511.                 rcode = getresp(cb,200);
  512.                 if(rcode == -1)
  513.                     goto quit;
  514.                 if(rcode < 400)
  515.                     goodrcpt = 1; /* At least one good */
  516.             }
  517.             rcpts++;
  518.         }
  519.         /* Send DATA command */
  520.         sendcmd(cb,"DATA\n");
  521.         if(!Smtpbatch){
  522.             rcode = getresp(cb,200);
  523.             if(rcode == -1 || rcode >= 400)
  524.                 goto quit;
  525.         }
  526.         if(Smtpbatch){
  527.             /* Now wait for the responses to come back. The first time
  528.              * we do this, we wait first for the start banner and
  529.              * HELO response. In any case, we wait for the response to
  530.              * the MAIL command here.
  531.              */
  532.             for(i= init ? 3 : 1;i > 0;i--){
  533.                 rcode = getresp(cb,200);
  534.                 if(rcode == -1 || rcode >= 400)
  535.                     goto quit;
  536.             }
  537.             init = 0;
  538.  
  539.             /* Now process the responses to the RCPT commands */
  540.             for(i=rcpts;i!=0;i--){
  541.                 rcode = getresp(cb,200);
  542.                 if(rcode == -1)
  543.                     goto quit;
  544.                 if(rcode < 400)
  545.                     goodrcpt = 1; /* At least one good */
  546.             }
  547.             /* And finally get the response to the DATA command.
  548.              * Some servers will return failure here if no recipients
  549.              * are valid, some won't.
  550.              */
  551.             rcode = getresp(cb,200);
  552.             if(rcode == -1 || rcode >= 400)
  553.                 goto quit;
  554.  
  555.             /* check for no good rcpt on the list */
  556.             if (goodrcpt == 0){
  557.                 sendcmd(cb,".\n");  /* Get out of data mode */
  558.                 goto quit;
  559.             }
  560.         }
  561.         /* Send the file. This also closes it */
  562.         smtpsendfile(cb);
  563.  
  564.         /* Wait for the OK response */
  565.         rcode = getresp(cb,200);
  566.         if(rcode == -1)
  567.             goto quit;
  568.         if((rcode >= 200 && rcode < 300) || rcode >= 500){
  569.             /* if a good transfer or permanent failure remove job */
  570.  
  571.             if (cb->errlog != NULLLIST)
  572.                 retmail(cb);
  573.             /* Unlink the textfile */
  574.             (void) unlink(cb->tname);
  575.             (void) unlink(cb->wname);    /* unlink workfile */
  576.             log(cb->s,"SMTP sent job %s To: %s From: %s",
  577.              cb->jobq->jobname,cb->jobq->to->val,cb->jobq->from);
  578.         }
  579.     } while(next_job(cb));
  580. quit:
  581.     sendcmd(cb,"QUIT\n");
  582.     if (cb->errlog != NULLLIST){
  583.         retmail(cb);
  584.         (void) unlink(cb->wname);    /* unlink workfile */
  585.         (void) unlink(cb->tname);    /* unlink text */
  586.     }
  587.     (void) close_s(cb->s);
  588.     if(cb->tfile != NULLFILE)
  589.         fclose(cb->tfile);
  590.     cb->lock = 0;
  591.     del_session(cb);
  592. }
  593.  
  594.  
  595. /* create mail lockfile */
  596. int
  597. mlock(dir,id)
  598. char *dir,*id;
  599. {
  600.     char lockname[LINELEN];
  601.     int fd;
  602.  
  603. #ifdef    MSDOS
  604.     if(strlen(id) > 8) {        /* truncate long filenames */
  605.         id[8] = '\0';
  606.         if(id[7] == '/')
  607.             id[7] = '\0';
  608.     }
  609. #endif
  610.     /* Try to create the lock file in an atomic operation */
  611.     sprintf(lockname,"%s/%s.lck",dir,id);
  612. #ifdef        AMIGA
  613.     /* don't ask, really, just don't ask... I'd do file locking on
  614.      * an Amiga much more differently than this.
  615.      */
  616.     if(access(lockname, 0) == 0)
  617.         return -1;
  618. #endif
  619.     if((fd = open(lockname, O_WRONLY|O_EXCL|O_CREAT,0600)) == -1)
  620.         return -1;
  621.     close(fd);
  622.     return 0;
  623. }
  624.  
  625. /* remove mail lockfile */
  626. int
  627. rmlock(dir,id)
  628. char *dir,*id;
  629. {
  630.     char lockname[LINELEN];
  631. #ifdef    MSDOS
  632.     if(strlen(id) > 8) {        /* truncate long filenames */
  633.         id[8] = '\0';
  634.         if(id[7] == '/')
  635.             id[7] = '\0';
  636.     }
  637. #endif
  638.     sprintf(lockname,"%s/%s.lck",dir,id);
  639.     return(unlink(lockname));
  640. }
  641.  
  642. /* free the message struct and data */
  643. static void
  644. del_session(cb)
  645. register struct smtpcli *cb;
  646. {
  647.     register struct smtp_job *jp,*tp;
  648.     register int i;
  649.  
  650.     if (cb == NULLSMTPCLI)
  651.         return;
  652.     for(i=0; i<MAXSESSIONS; i++) 
  653.         if(cli_session[i] == cb) {
  654.             cli_session[i] = NULLSMTPCLI;
  655.             break;
  656.         }
  657.  
  658.     free(cb->wname);
  659.     free(cb->tname);
  660.     free(cb->destname);
  661.     for (jp = cb->jobq; jp != NULLJOB;jp = tp) {
  662.             tp = jp->next;
  663.             del_job(jp);
  664.     }
  665.     del_list(cb->errlog);
  666.     free((char *)cb);
  667.     Smtpsessions--;    /* number of connections active */
  668. }
  669.  
  670. static void
  671. del_job(jp)
  672. register struct smtp_job *jp;
  673. {
  674.     if ( *jp->jobname != '\0')
  675.         (void) rmlock(Mailqdir,jp->jobname);
  676.     free(jp->from);
  677.     del_list(jp->to);
  678.     free((char *)jp);
  679. }
  680.  
  681. /* delete a list of list structs */
  682. void
  683. del_list(lp)
  684. struct list *lp;
  685. {
  686.     register struct list *tp, *tp1;
  687.     for (tp = lp; tp != NULLLIST; tp = tp1) {
  688.         tp1 = tp->next;
  689.         free(tp->val);
  690.         free((char *)tp);
  691.     }
  692. }
  693.  
  694. /* stub for calling mdaemon to return message to sender */
  695. static void
  696. retmail(cb)
  697. struct smtpcli *cb;
  698. {
  699.     FILE *infile;
  700. #ifdef SMTPTRACE
  701.     if (Smtptrace > 5) {
  702.         printf("smtp job %s returned to sender\n",cb->wname);
  703.     }
  704. #endif
  705.     if ((infile = fopen(cb->tname,READ_TEXT)) == NULLFILE)
  706.         return;
  707.     mdaemon(infile,cb->jobq->from,cb->errlog,1);
  708.     fclose(infile);
  709. }
  710.  
  711. /* look to see if a smtp control block exists for this ipdest */
  712. static struct smtpcli *
  713. lookup(destaddr)
  714. int32 destaddr;
  715. {
  716.     register int i;
  717.  
  718.     for(i=0; i<MAXSESSIONS; i++) {
  719.         if (cli_session[i] == NULLSMTPCLI)
  720.             continue;
  721.         if(cli_session[i]->ipdest == destaddr)
  722.             return cli_session[i];
  723.     }
  724.     return NULLSMTPCLI;
  725. }
  726.  
  727. /* create a new  smtp control block */
  728. static struct smtpcli *
  729. newcb()
  730. {
  731.     register int i;
  732.     register struct smtpcli *cb;
  733.  
  734.     for(i=0; i<MAXSESSIONS; i++) {
  735.         if(cli_session[i] == NULLSMTPCLI) {
  736.             cb = (struct smtpcli *)callocw(1,sizeof(struct smtpcli));
  737.             cb->wname = mallocw((unsigned)strlen(Mailqdir)+JOBNAME);
  738.             cb->tname = mallocw((unsigned)strlen(Mailqdir)+JOBNAME);
  739.             cli_session[i] = cb;
  740.             Smtpsessions++;    /* number of connections active */
  741.             return(cb);
  742.         }
  743.     }
  744.     return NULLSMTPCLI;
  745. }
  746.  
  747. static void
  748. execjobs()
  749. {
  750.     register struct smtpcli *cb;
  751.     register int i;
  752.  
  753.     for(i=0; i<MAXSESSIONS; i++) {
  754.         cb = cli_session[i];
  755.         if (cb == NULLSMTPCLI) 
  756.             continue;
  757.         if(cb->lock)
  758.             continue;
  759.  
  760.         sprintf(cb->tname,"%s/%s.txt",Mailqdir,cb->jobq->jobname);
  761.         sprintf(cb->wname,"%s/%s.wrk",Mailqdir,cb->jobq->jobname);
  762.  
  763.         newproc("smtp_send", 1024, smtp_send, 0, cb,NULL,0);
  764.  
  765. #ifdef SMTPTRACE
  766.         if (Smtptrace) 
  767.             printf("Trying Connection to %s\n",inet_ntoa(cb->ipdest));
  768. #endif
  769.  
  770.  
  771.     }
  772. }
  773.     
  774. /* add this job to control block queue */
  775. static struct smtp_job *
  776. setupjob(cb,id,from)
  777. struct smtpcli *cb;
  778. char *id,*from;
  779. {
  780.     register struct smtp_job *p1,*p2;
  781.  
  782.     p1 = (struct smtp_job *)callocw(1,sizeof(struct smtp_job));
  783.     p1->from = strdup(from);
  784.     strcpy(p1->jobname,id);
  785.     /* now add to end of jobq */
  786.     if ((p2 = cb->jobq) == NULLJOB)
  787.         cb->jobq = p1;
  788.     else {
  789.         while(p2->next != NULLJOB)
  790.             p2 = p2->next;
  791.         p2->next = p1;
  792.     }
  793.     return p1;
  794. }
  795.  
  796. /* called to advance to the next job */
  797. static int
  798. next_job(cb)
  799. register struct smtpcli *cb;
  800. {
  801.     register struct smtp_job *jp;
  802.  
  803.     jp = cb->jobq->next;
  804.     del_job(cb->jobq);
  805.     /* remove the error log of previous message */
  806.     del_list(cb->errlog);
  807.     cb->errlog = NULLLIST;
  808.     cb->jobq = jp;
  809.     if (jp == NULLJOB)
  810.         return 0;
  811.     sprintf(cb->tname,"%s/%s.txt",Mailqdir,jp->jobname);
  812.     sprintf(cb->wname,"%s/%s.wrk",Mailqdir,jp->jobname);
  813. #ifdef SMTPTRACE
  814.     if (Smtptrace > 5) {
  815.         printf("sending job %s\n",jp->jobname);
  816.     }
  817. #endif
  818.         return 1;
  819.  
  820. }
  821.  
  822.  
  823. /* Mail routing function. For now just use the hosts file */
  824. int32
  825. mailroute(dest)
  826. char *dest;
  827. {
  828.     int32 destaddr;
  829.  
  830.     /* look up address or use the gateway */
  831.     destaddr = resolve_mx(dest);
  832.     if (destaddr == 0 && (destaddr = resolve(dest)) == 0)
  833.         if (Gateway != 0) 
  834.             destaddr = Gateway; /* Use the gateway  */
  835.     return destaddr;
  836.     
  837. }
  838.  
  839. /* save line in error list */
  840. static void
  841. logerr(cb,line)
  842. struct smtpcli *cb;
  843. char *line;
  844. {
  845.     register struct list *lp,*tp;
  846.     tp = (struct list *)callocw(1,sizeof(struct list));
  847.     tp->val = strdup(line);
  848.     /* find end of list */
  849.     if ((lp = cb->errlog) == NULLLIST)
  850.         cb->errlog = tp;
  851.     else {
  852.         while(lp->next != NULLLIST)
  853.             lp = lp->next;
  854.         lp->next = tp;
  855.     }
  856. }
  857.  
  858. static int
  859. smtpsendfile(cb)
  860. register struct smtpcli *cb;
  861. {
  862.     int error = 0;
  863.  
  864.     strcpy(cb->buf,"\n");
  865.     while(fgets(cb->buf,sizeof(cb->buf),cb->tfile) != NULLCHAR) {
  866.         /* Escape a single '.' character at the beginning of a line */
  867.         if(strcmp(cb->buf,".\n") == 0)
  868.             usputc(cb->s,'.');
  869.         usputs(cb->s,cb->buf);
  870.     }
  871.     fclose(cb->tfile);
  872.     cb->tfile = NULLFILE;
  873.     /* Send the end-of-message command */
  874.     if(cb->buf[strlen(cb->buf)-1] == '\n')
  875.         sendcmd(cb,".\n");
  876.     else
  877.         sendcmd(cb,"\n.\n");
  878.     return error;
  879. }
  880. /* do a printf() on the socket with optional local tracing */
  881. #ifdef    ANSIPROTO
  882. static void
  883. sendcmd(struct smtpcli *cb,char *fmt, ...)
  884. {
  885.     va_list args;
  886.  
  887.     va_start(args,fmt);
  888. #ifdef    SMTPTRACE
  889.     if(Smtptrace){
  890.         printf("smtp sent: ");
  891.         vprintf(fmt,args);
  892.     }
  893. #endif
  894.     vsprintf(cb->buf,fmt,args);
  895.     usputs(cb->s,cb->buf);
  896.     va_end(args);
  897. }
  898. #else
  899. static void
  900. sendcmd(cb,fmt,arg1,arg2,arg3,arg4)
  901. struct smtpcli *cb;
  902. char *fmt;
  903. int arg1,arg2,arg3,arg4;
  904. {
  905. #ifdef    SMTPTRACE
  906.     if(Smtptrace){
  907.         printf("smtp sent: ");
  908.         printf(fmt,arg1,arg2,arg3,arg4);
  909.     }
  910. #endif
  911.     sprintf(cb->buf,fmt,arg1,arg2,arg3,arg4);
  912.     usputs(cb->s,cb->buf);
  913. }
  914. #endif
  915.  
  916. /* Wait for, read and display response from server. Return the result code. */
  917. static int
  918. getresp(cb,mincode)
  919. struct smtpcli *cb;
  920. int mincode;    /* Keep reading until at least this code comes back */
  921. {
  922.     int rval;
  923.     char line[LINELEN];
  924.  
  925.     usflush(cb->s);
  926.     for(;;){
  927.         /* Get line */
  928.         if(recvline(cb->s,line,LINELEN) == -1){
  929.             rval = -1;
  930.             break;
  931.         }
  932.         rip(line);        /* Remove cr/lf */
  933.         rval = atoi(line);
  934. #ifdef    SMTPTRACE
  935.         if(Smtptrace)
  936.             printf("smtp recv: %s\n",line);/* Display to user */
  937. #endif
  938.         if(rval >= 500) {    /* Save permanent error replies */
  939.             char tmp[LINELEN];
  940.             if(cb->errlog == NULLLIST) {
  941.                 sprintf(tmp,"While talking to %s:",
  942.                     cb->destname);
  943.                 logerr(cb,tmp);
  944.             }
  945.             if(cb->buf[0] != '\0') { /* Save offending command */
  946.                 rip(cb->buf);
  947.                 sprintf(tmp,">>> %s",cb->buf);
  948.                 logerr(cb,tmp);
  949.                 cb->buf[0] = '\0';
  950.             }
  951.             sprintf(tmp,"<<< %s",line);
  952.             logerr(cb,tmp);        /* save the error reply */
  953.         }
  954.         /* Messages with dashes are continued */
  955.         if(line[3] != '-' && rval >= mincode)
  956.             break;
  957.     }
  958.     return rval;
  959. }
  960.