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