home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 5 / DATAFILE_PDCD5.iso / internet / netlite2 / NET / c / SMTPCLI < prev    next >
Encoding:
Text File  |  1993-04-13  |  26.6 KB  |  815 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.  *      Limit on max simultaneous sessions, reuse of connections - 12/87 NN2Z
  10.  *      Added return of mail to sender as well as batching of commands 1/88 nn2z
  11.  */
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <stdarg.h>
  16. #include <time.h>
  17. #include "werr.h"
  18. #include "global.h"
  19. #include "netuser.h"
  20. #include "mbuf.h"
  21. #include "timer.h"
  22. #include "tcp.h"
  23. #include "smtp.h"
  24. #include "cmdparse.h"
  25. #include "misc.h"
  26. #include "arc.h"
  27.  
  28. static int dosmtpmaxcli(int, char **);
  29. static int setsmtpmode(int, char **);
  30. static int dogateway(int, char **);
  31. static int dokick(int, char **);
  32. static int dotimer(int, char **);
  33. static void abort_trans(struct smtp_cb *);
  34. static void quit(struct smtp_cb *);
  35. static void smtp_rec(struct tcb *, int16);
  36. static void smtp_cts(struct tcb *, int16);
  37. static int sendwindow(struct smtp_cb *, struct mbuf *, int16);
  38. static void smtp_state(struct tcb *, char, char);
  39. static void sendit(struct smtp_cb *, char *, ...);
  40. static void del_session(struct smtp_cb *);
  41. static void retmail(struct smtp_cb *);
  42. static struct smtp_cb *lookup(int32);
  43. static struct smtp_cb *newcb(void);
  44. static void execjobs(void);
  45. static int nextjob(struct smtp_cb *);
  46. static void logerr(struct smtp_cb *);
  47.  
  48. extern int16 lport;                     /* local port placeholder */
  49. static struct timer smtpcli_t;
  50. int32 gateway;
  51.  
  52. int16   smtpmaxcli  = MAXSESSIONS;      /* the max client connections allowed */
  53. int16   smtpsessions = 0;               /* number of client connections
  54.                                         * currently open */
  55. int16   smtpmode = 0;
  56.  
  57. static struct smtp_cb *cli_session[MAXSESSIONS]; /* queue of client sessions  */
  58.  
  59. static char quitcmd[] = "QUIT\r\n";
  60. static char eom[] = "\r\n.\r\n";
  61.  
  62. struct cmds smtpcmds[] = {
  63.         "gateway",      dogateway,      0,      NULLCHAR,       NULLCHAR,
  64.         "kick",         dokick,         0,      NULLCHAR,       NULLCHAR,
  65.         "mode",         setsmtpmode,    0,      NULLCHAR,       NULLCHAR,
  66.         "maxclients",   dosmtpmaxcli,   0,      NULLCHAR,       NULLCHAR,
  67.         "timer",        dotimer,        0,      NULLCHAR,       NULLCHAR,
  68.         NULLCHAR,       NULLFP,         0,      
  69.         "subcommands: gateway mode maxclients timer",
  70.                 NULLCHAR,
  71. };
  72.  
  73. int dosmtp(int argc, char **argv)
  74. {
  75.         return subcmd(smtpcmds,argc,argv);
  76. }
  77.  
  78. static int dosmtpmaxcli(int argc, char **argv)
  79. {
  80.         int x;
  81.         if (argc > 2) {
  82.                 x = atoi(argv[1]);
  83.                 if (x <= MAXSESSIONS)
  84.                         smtpmaxcli = x;
  85.         }
  86.         return 0;
  87. }
  88.  
  89. static int setsmtpmode(int argc, char **argv)
  90. {
  91.         if (argc > 1) {
  92.                 switch(*argv[1]) {
  93.                 case 'q':
  94.                         smtpmode |= QUEUE;
  95.                         break;
  96.                 case 'r':
  97.                         smtpmode &= ~QUEUE;
  98.                         break;
  99.                 default:
  100.                         break;
  101.                 }
  102.         }
  103.         return 0;
  104. }
  105.  
  106. static int dokick(int argc, char **argv)
  107. {
  108.         argc = argc;
  109.         argv = argv;
  110.  
  111.         return smtptick();
  112. }
  113.  
  114. static int dogateway(int argc, char **argv)
  115. {
  116.         int32 n;
  117.         extern char badhost[];
  118.  
  119.         if (argc > 1) {
  120.                 if ((n = resolve(argv[1])) == 0) {
  121.                       werr(0,badhost,argv[1]);
  122.                       return 1;
  123.                 }
  124.         }
  125.  
  126.         return 0;
  127. }
  128.  
  129. /* Set outbound spool poll interval */
  130. static int dotimer(int argc, char **argv)
  131. {
  132.         if (argc > 1) {
  133.                 smtpcli_t.func = (void (*)())smtptick;/* what to call on timeout */
  134.                 smtpcli_t.arg = NULLCHAR;               /* dummy value */
  135.                 smtpcli_t.start = (int32)atoi(argv[1])*(1000/MSPTICK); /* set timer duration */
  136.                 start_timer(&smtpcli_t);                /* and fire it up */
  137.         }
  138.  
  139.         return 0;
  140. }
  141.  
  142. /* this is the routine that gets called every so often to do outgoing mail
  143.    processing */
  144. int smtptick(void)
  145. {
  146.         register struct smtp_cb *cb;
  147.         struct smtp_job *jp;
  148.         char    tmpstring[LINELEN], wfilename[13];
  149.         char    from[LINELEN], to[LINELEN];
  150.         int32 destaddr;
  151.         FILE *wfile;
  152.  
  153.         for (filedir(mailqueue,0,wfilename); wfilename[0] != '\0'; filedir(mailqueue,1,wfilename)){
  154.                 /* lock this file from the smtp daemon */
  155.                 if (mlock(mailqdir, wfilename))
  156.                         continue;
  157.  
  158.                 sprintf(tmpstring,"%s.work.%s",mailqdir,wfilename);
  159.                 if ((wfile = fopen(tmpstring,"r")) == NULLFILE) {
  160.                         /* probably too many open files */
  161.                         rmlock(mailqdir, wfilename);
  162.                         /* continue to next message. The failure
  163.                          * may be temporary */
  164.                         continue;
  165.                 }
  166.  
  167.                 fgets(tmpstring,LINELEN,wfile);  /* read target host */
  168.                 rip(tmpstring);
  169.  
  170.                 if ((destaddr = mailroute(tmpstring)) == 0) {
  171.                         fclose(wfile);
  172.                         werr(0,"** smtp: Unknown address %s\n",tmpstring);
  173.                         rmlock(mailqdir, wfilename);
  174.                         continue;
  175.                 }
  176.  
  177.                 if ((cb = lookup(destaddr)) == NULLCB) {
  178.                         /* there are enough processes running already */
  179.                         if (smtpsessions >= smtpmaxcli) {
  180.                                fclose(wfile);
  181.                                rmlock(mailqdir, wfilename);
  182.                                break;
  183.                         }
  184.                         if ((cb = newcb()) == NULLCB) {
  185.                                fclose(wfile);
  186.                                rmlock(mailqdir, wfilename);
  187.                                break;
  188.                         } 
  189.                         cb->ipdest = destaddr;
  190.                 } else {
  191.                         /* This system is already is sending mail lets not
  192.                          * interfere with its send queue.
  193.                          */
  194.                         if (cb->state != CLI_INIT_STATE) {
  195.                                fclose(wfile);
  196.                                rmlock(mailqdir, wfilename);
  197.                                continue;
  198.                         }
  199.                 }
  200.  
  201.                 fgets(from,LINELEN,wfile);       /* read from */
  202.                 rip(from);
  203.                 if ((jp = setupjob(cb, wfilename, from)) == NULLJOB) {
  204.                         fclose(wfile);
  205.                         rmlock(mailqdir, wfilename);
  206.                         del_session(cb);
  207.                         break;
  208.                 }
  209.                 while (fgets(to,LINELEN,wfile) != NULLCHAR) {
  210.                         rip(to);
  211.                         if (addlist(&jp->to,to,DOMAIN) == NULLLIST) {
  212.                                   fclose(wfile);
  213.                                   del_session(cb);
  214.                         }
  215.                 }
  216.                 fclose(wfile);
  217.         }
  218.  
  219.         /* start sending that mail */
  220.         execjobs();
  221.  
  222.         /* Restart timer */
  223.         start_timer(&smtpcli_t);
  224.         return(0);
  225. }
  226.  
  227. /* this is the master state machine that handles a single SMTP transaction */
  228. void smtp_transaction(register struct smtp_cb *cb)
  229. {
  230.         register char reply;
  231.         register struct list *tp;
  232.         int16 cnt;
  233.         struct mbuf *bp,*bpl;
  234.         char tbuf[LINELEN];
  235.         int rcode;
  236.  
  237.         /* Another line follows; ignore this one */
  238.         if(cb->buf[0] == '0' || cb->buf[3] == '-')
  239.                 return;
  240.  
  241.         reply = cb->buf[0];
  242.         rcode = atoi(cb->buf);
  243.  
  244.         /* if service shuting down */
  245.         if (rcode == 421) {
  246.                 quit(cb);
  247.                 return;
  248.         }
  249.  
  250.         switch(cb->state) {
  251.         case CLI_OPEN_STATE:
  252.                 if (reply != '2')
  253.                         quit(cb);
  254.                 else {
  255.                         cb->state = CLI_HELO_STATE;
  256.                         sendit(cb,"HELO %s\r\nMAIL FROM:<%s>\r\n",
  257.                         hostname,cb->jobq->from);
  258.                 }
  259.                 break;
  260.         case CLI_HELO_STATE:
  261.                 if (reply != '2')
  262.                         quit(cb);
  263.                 else 
  264.                         cb->state = CLI_MAIL_STATE;
  265.                 break;                  
  266.         case CLI_MAIL_STATE:
  267.                 if (reply != '2')
  268.                         quit(cb);
  269.                 else {
  270.                         cb->state = CLI_RCPT_STATE;
  271.                         cb->rcpts = 0;
  272.                         bpl = NULLBUF;
  273.                         for (tp = cb->jobq->to; tp != NULLLIST; tp = tp->next){
  274.                                 sprintf(tbuf,"RCPT TO:<%s>\r\n",tp->val);
  275.                                 bp = qdata(tbuf,(int16)strlen(tbuf));
  276.                                 if (bp == NULLBUF) {
  277.                                         free_p(bpl);
  278.                                         quit(cb);
  279.                                         return;
  280.                                 }
  281.                                 append(&bpl,bp);
  282.                                 cb->rcpts++;
  283.                         }
  284.                         send_tcp(cb->tcb,bpl);
  285.                 }
  286.                 break;
  287.         case CLI_RCPT_STATE:
  288.                 if (reply == '5') {
  289.                         logerr(cb);
  290.                 } else if (reply == '2') {
  291.                         cb->goodrcpt =1;
  292.                 } else {
  293.                         /* some kind of temporary failure */
  294.                         abort_trans(cb);
  295.                         break;
  296.                 }
  297.                 /* if more rcpts stay in this state */
  298.                 if (--cb->rcpts != 0)
  299.                         break;
  300.  
  301.                 /* check for no good rcpt on the list */
  302.                 if (cb->goodrcpt == 0) {
  303.                         if (cb->errlog != NULLLIST)
  304.                                 retmail(cb);
  305.                         remove(cb->wname);       /* unlink workfile */
  306.                         remove(cb->tname);       /* unlink text */
  307.                         abort_trans(cb);
  308.                         break;
  309.                 }
  310.                 /* if this file open fails abort */
  311.                 if ((cb->tfile = fopen(cb->tname,"r")) == NULLFILE)
  312.                         abort_trans(cb);
  313.                 else {
  314.                         /* optimize for slow packet links by sending
  315.                          * DATA cmd and the 1st window of text
  316.                          */
  317.                         if (cb->tcb->window <= cb->tcb->sndcnt)
  318.                                 cnt = 0;
  319.                         else
  320.                                 cnt = cb->tcb->window - cb->tcb->sndcnt;
  321.                         bp = qdata("DATA\r\n",6);
  322.                         cb->cts = 1;
  323.                         cb->state = CLI_SEND_STATE;
  324.                         if (sendwindow(cb,bp,cnt) == EOF)
  325.                                 cb->cts = 0;
  326.                 }
  327.                 break;
  328.         case CLI_SEND_STATE:
  329.                 if (reply == '3') {
  330.                         cb->state = CLI_UNLK_STATE;
  331.                 } else {
  332.                         /* change cts to transmit upcall queueing more data */
  333.                         cb->cts = 0;
  334.                         quit(cb);
  335.                 }
  336.                 break;
  337.         case CLI_UNLK_STATE:
  338.                 /* if a good transfer or permanent failure remove job */
  339.                 if (reply == '2' || reply == '5') {
  340.                         if (reply == '5')
  341.                                 logerr(cb);
  342.                         /* close and unlink the textfile */
  343.                         if(cb->tfile != NULLFILE) {
  344.                                 fclose(cb->tfile);
  345.                                 cb->tfile = NULLFILE;
  346.                         }
  347.                         if (cb->errlog != NULLLIST)
  348.                                 retmail(cb);
  349.                         remove(cb->tname);
  350.                         remove(cb->wname);       /* unlink workfile */
  351.                 }
  352.                 if (nextjob(cb)) {
  353.                         cb->state = CLI_MAIL_STATE;
  354.                         sendit(cb,"MAIL FROM:<%s>\r\n",cb->jobq->from);
  355.                 } else 
  356.                         /* the quit sent already in smtp_cts */
  357.                         cb->state = CLI_QUIT_STATE;
  358.                 break;
  359.         case CLI_IDLE_STATE:    /* used after a RSET and more mail to send */
  360.                 if (reply != '2')
  361.                         quit(cb);
  362.                 else {
  363.                         cb->state = CLI_MAIL_STATE;
  364.                         sendit(cb,"MAIL FROM:<%s>\r\n",cb->jobq->from);
  365.                 }
  366.                 break;                  
  367.         case CLI_QUIT_STATE:
  368.                 break;
  369.         }
  370. }
  371.  
  372. /* abort the currrent job.
  373.  * If more work exists set up the next job if
  374.  * not then shut down.
  375. */
  376. static void abort_trans(register struct smtp_cb *cb)
  377. {
  378.         if(cb->tfile != NULLFILE) {
  379.                 fclose(cb->tfile);
  380.                 cb->tfile = NULLFILE;
  381.         }
  382.         if (nextjob(cb)) {
  383.                 sendit(cb,"RSET\r\n");
  384.                 cb->state = CLI_IDLE_STATE;
  385.         } else 
  386.                 quit(cb);
  387. }
  388.  
  389. /* close down link after a failure */
  390. static void quit(struct smtp_cb *cb)
  391. {
  392.         cb->state = CLI_QUIT_STATE;
  393.         sendit(cb,quitcmd);             /* issue a quit command */
  394.         close_tcp(cb->tcb);             /* close up connection */
  395. }
  396.  
  397. /* smtp receiver upcall routine.  fires up the state machine to parse input */
  398. static void smtp_rec(struct tcb *tcb, int16 cnt)
  399. {
  400.         register struct smtp_cb *cb;
  401.         char c;
  402.         struct mbuf *bp;
  403.  
  404.         cb = (struct smtp_cb *)tcb->user;       /* point to our struct */
  405.         recv_tcp(tcb, &bp, cnt);  /* suck up chars from low level routine */
  406.  
  407.         /* Assemble input line in buffer, return if incomplete */
  408.         while (pullup(&bp, &c, 1) == 1) {
  409.                 switch(c) {
  410.                 case '\r':      /* strip cr's */
  411.                         continue;
  412.                 case '\n':      /* line is finished, go do it! */
  413.                         cb->buf[cb->cnt] = '\0';
  414.                         smtp_transaction(cb);
  415.                         cb->cnt = 0;
  416.                         break;
  417.                 default:        /* other chars get added to buffer */
  418.                         if (cb->cnt != LINELEN-1)
  419.                                 cb->buf[cb->cnt++] = c;
  420.                         break;
  421.                 }
  422.         }
  423. }
  424.  
  425. /* smtp transmitter ready upcall routine.  twiddles cts flag */
  426. static void smtp_cts(struct tcb *tcb, int16 cnt)
  427. {
  428.         register struct smtp_cb *cb;
  429.  
  430.         cb = (struct smtp_cb *)tcb->user;       /* point to our struct */
  431.  
  432.         /* don't do anything until/unless we're supposed to be sending */
  433.         if (cb->cts == 0) return;
  434.  
  435.         if (sendwindow(cb, NULLBUF, cnt) == EOF) cb->cts = 0;
  436. }
  437.  
  438. /* fill the rest of the window with data and send out the eof commands.
  439. * It is done this way to minimize the number of packets sent.
  440. */
  441. static int sendwindow(register struct smtp_cb *cb, struct mbuf *ibp, int16 cnt)
  442. {
  443.         struct mbuf *bpl;
  444.         register struct mbuf *bp;
  445.         char *cp;
  446.         int c;
  447.         
  448.         bpl = ibp;
  449.         if ((bp = alloc_mbuf(cnt)) == NULLBUF) {
  450.                 /* Hard to know what to do here */
  451.                 return EOF;
  452.         }
  453.         cp = bp->data;
  454.         while (cnt > 1 && (c = getc(cb->tfile)) != EOF) {
  455.                 if (c == '\n') {
  456.                         *cp++ = '\r';
  457.                         bp->cnt++;
  458.                         cnt--;
  459.                 }
  460.                 *cp++ = c;
  461.                 bp->cnt++;
  462.                 cnt--;
  463.         }
  464.         append(&bpl,bp);
  465.         if (cnt > 1) {  /* EOF seen */
  466.                 fclose(cb->tfile);
  467.                 cb->tfile = NULLFILE;
  468.                 /* send the end of data character. */
  469.                 if (cnt < sizeof(eom) - 1) {
  470.                         bp = qdata(eom,5);
  471.                         append(&bpl,bp);
  472.                         cnt = 0;        /* dont let anyone else in */
  473.                 } else {
  474.                         memcpy(&bp->data[bp->cnt],eom,sizeof(eom) - 1);
  475.                         bp->cnt += sizeof(eom) - 1;
  476.                         cnt -= sizeof(eom) - 1;
  477.                 }
  478.                 /* send the quit in this packet if last job */
  479.                 if (cb->jobq->next == NULLJOB) {
  480.                         if (cnt < sizeof(quitcmd) - 1) {
  481.                                 bp = qdata(quitcmd,sizeof(quitcmd) - 1);
  482.                                 append(&bpl,bp);
  483.                         } else {
  484.                                 memcpy(&bp->data[bp->cnt],
  485.                                 quitcmd,sizeof(quitcmd) - 1);
  486.                                 bp->cnt += sizeof(quitcmd) - 1;
  487.                         }
  488.                 }
  489.                 send_tcp(cb->tcb,bpl);
  490.                 if (cb->jobq->next == NULLJOB)
  491.                         close_tcp(cb->tcb);     /* close up connection */
  492.                 return EOF;
  493.         } else {
  494.                 send_tcp(cb->tcb,bpl);
  495.                 return 0;
  496.         }
  497. }
  498.  
  499. /* smtp state change upcall routine. */
  500. static void smtp_state(register struct tcb *tcb, char old, char new)
  501. {
  502.         register struct smtp_cb *cb;
  503.  
  504.         old = old;
  505.  
  506.         cb = (struct smtp_cb *)tcb->user;
  507.         switch(new) {
  508.         case ESTABLISHED:
  509.                 cb->state = CLI_OPEN_STATE;     /* shouldn't be needed */
  510.                 break;
  511.         case CLOSE_WAIT:
  512.                 close_tcp(tcb);                 /* shut things down */
  513.                 break;
  514.         case CLOSED:
  515.                 /* if this close was not done by us ie. a RST */
  516.                 if(cb->tfile != NULLFILE)
  517.                         fclose(cb->tfile);
  518.                 del_session(cb);
  519.                 del_tcp(tcb);
  520.                 break;
  521.         }
  522. }
  523.  
  524. /* Send message back to server */
  525. static void sendit(struct smtp_cb *cb, char *fmt, ...)
  526. {
  527.         va_list argptr;
  528.         struct mbuf *bp;
  529.         char tmpstring[256];
  530.  
  531.         va_start(argptr,fmt);
  532.         vsprintf(tmpstring,fmt,argptr);
  533.         va_end(argptr);
  534.  
  535.         bp = qdata(tmpstring,(int16)strlen(tmpstring));
  536.         send_tcp(cb->tcb,bp);
  537. }
  538.  
  539. /* create mail lockfile */
  540. int mlock(char *dir, char *id)
  541. {
  542.         char lockname[LINELEN];
  543.         FILE *fp;
  544.         /* Try to create the lock file in an atomic operation */
  545.         sprintf(lockname,"%s.lock.%s",dir,id);
  546.         if((fp = fopen(lockname, "w")) == NULL)
  547.                 return -1;
  548.         fclose(fp);
  549.         return 0;
  550. }
  551.  
  552. /* remove mail lockfile */
  553. int rmlock(char *dir, char *id)
  554. {
  555.         char lockname[LINELEN];
  556.         sprintf(lockname,"%s.lock.%s",dir,id);
  557.         return(remove(lockname));
  558. }
  559.  
  560. /* free the message struct and data */
  561. static void del_session(register struct smtp_cb *cb)
  562. {
  563.         register struct smtp_job *jp,*tp;
  564.         register int i;
  565.  
  566.         if (cb == NULLCB)
  567.                 return;
  568.         for(i=0; i<MAXSESSIONS; i++) 
  569.                 if(cli_session[i] == cb) {
  570.                         cli_session[i] = NULLCB;
  571.                         break;
  572.                 }
  573.  
  574.         if(cb->wname != NULLCHAR)
  575.                 free(cb->wname);
  576.         if(cb->tname != NULLCHAR)
  577.                 free(cb->tname);
  578.         for (jp = cb->jobq; jp != NULLJOB;jp = tp) {
  579.                         tp = jp->next;
  580.                         del_job(jp);
  581.         }
  582.         del_list(cb->errlog);
  583.         free((char *)cb);
  584.         smtpsessions--; /* number of connections active */
  585. }
  586.  
  587. void del_job(register struct smtp_job *jp)
  588. {
  589.         if ( *jp->jobname != '\0')
  590.                 rmlock(mailqdir,jp->jobname);
  591.         if(jp->from != NULLCHAR)
  592.                 free(jp->from);
  593.         del_list(jp->to);
  594.         free((char *)jp);
  595. }
  596.  
  597. /* delete a list of list structs */
  598. void del_list(struct list *lp)
  599. {
  600.         register struct list *tp, *tp1;
  601.         for (tp = lp; tp != NULLLIST; tp = tp1) {
  602.                         tp1 = tp->next;
  603.                         if(tp->val != NULLCHAR)
  604.                                 free(tp->val);
  605.                         free((char *)tp);
  606.         }
  607. }
  608.  
  609. /* return message to sender */
  610. static void retmail(struct smtp_cb *cb)
  611. {
  612.         register struct list *lp;
  613.         register FILE *tfile;
  614.         register int c;
  615.         FILE *infile;
  616.         char *host,*to;
  617.         time_t t;
  618.  
  619.         /* A null From<> so no looping replys to MAIL-DAEMONS */
  620.         to = cb->jobq->from;
  621.         if (*to == '\0')
  622.                 return;
  623.         if ((host = strchr(to,'@')) == NULLCHAR)
  624.                 host = hostname;
  625.         else
  626.                 host++;
  627.         if ((infile = fopen(cb->tname,"r")) == NULLFILE)
  628.                 return;
  629.         if ((tfile = tmpfile()) == NULLFILE) {
  630.                 fclose(infile);
  631.                 return;
  632.         }
  633.         time(&t);
  634.         fprintf(tfile,"Date: %s",ptime(&t));
  635.         fprintf(tfile,"Message-Id: <%ld@%s>\n",get_msgid(),hostname);
  636.         fprintf(tfile,"From: MAILER-DAEMON@%s\n",hostname);
  637.         fprintf(tfile,"To: %s\n",to);
  638.         fprintf(tfile,"Subject: Failed mail\n\n");
  639.         fprintf(tfile,"  ===== transcript follows =====\n\n");
  640.  
  641.         for (lp = cb->errlog; lp != NULLLIST; lp = lp->next)
  642.                 fprintf(tfile,"%s\n",lp->val);
  643.  
  644.         fprintf(tfile,"\n  ===== Unsent message follows ====\n");
  645.  
  646.         while((c = getc(infile)) != EOF)
  647.                 if (putc(c,tfile) == EOF)
  648.                         break;
  649.         fclose(infile);
  650.         fseek(tfile,0L,0);
  651.         if ((smtpmode & QUEUE) != 0)
  652.                 router_queue(cb->tcb,tfile,"",(struct list *)to);
  653.         else
  654.                 queuejob(cb->tcb,tfile,host,to,"");
  655.         fclose(tfile);
  656. }
  657.  
  658. /* look to see if a smtp control block exists for this ipdest */
  659. static struct smtp_cb *lookup(int32 destaddr)
  660. {
  661.         register int i;
  662.  
  663.         for(i=0; i<MAXSESSIONS; i++) {
  664.                 if (cli_session[i] == NULLCB)
  665.                         continue;
  666.                 if(cli_session[i]->ipdest == destaddr)
  667.                         return cli_session[i];
  668.         }
  669.         return NULLCB;
  670. }
  671.  
  672. /* create a new  smtp control block */
  673. static struct smtp_cb *newcb(void)
  674. {
  675.         register int i;
  676.         register struct smtp_cb *cb;
  677.  
  678.         for(i=0; i<MAXSESSIONS; i++) {
  679.                 if(cli_session[i] == NULLCB) {
  680.                         cb = (struct smtp_cb *)calloc(1,sizeof(struct smtp_cb));
  681.                         if (cb == NULLCB)
  682.                                 return(NULLCB);
  683.                         cb->wname = malloc((unsigned)strlen(mailqdir)+JOBNAME+6);
  684.                         if (cb->wname == NULLCHAR) {
  685.                                 free((char *)cb);
  686.                                 return(NULLCB);
  687.                         }
  688.                         cb->tname = malloc((unsigned)strlen(mailqdir)+JOBNAME+6);
  689.                         if (cb->tname == NULLCHAR) {
  690.                                 free(cb->wname);
  691.                                 free((char *)cb);
  692.                                 return(NULLCB);
  693.                         }
  694.                         cb->state = CLI_INIT_STATE;
  695.                         cli_session[i] = cb;
  696.                         smtpsessions++; /* number of connections active */
  697.                         return(cb);
  698.                 }
  699.         }
  700.         return NULLCB;
  701. }
  702.  
  703. static void execjobs(void)
  704. {
  705.         struct socket lsocket, fsocket;
  706.         register struct smtp_cb *cb;
  707.         register int i;
  708.  
  709.         for(i=0; i<MAXSESSIONS; i++) {
  710.                 cb = cli_session[i];
  711.                 if (cb == NULLCB) 
  712.                         continue;
  713.                 if(cb->state != CLI_INIT_STATE)
  714.                         continue;
  715.  
  716.                 sprintf(cb->tname,"%s.text.%s",mailqdir,cb->jobq->jobname);
  717.                 sprintf(cb->wname,"%s.work.%s",mailqdir,cb->jobq->jobname);
  718.  
  719.                 /* setup the socket */
  720.                 fsocket.address = cb->ipdest;
  721.                 fsocket.port = SMTP_PORT;
  722.                 lsocket.address = ip_addr;      /* our ip address */
  723.                 lsocket.port = lport++;         /* next unused port */
  724.  
  725.                 /* open smtp connection */
  726.                 cb->state = CLI_OPEN_STATE;     /* init state placeholder */
  727.                 cb->tcb = open_tcp(&lsocket,&fsocket,TCP_ACTIVE,tcp_window,
  728.                         (void(*)())smtp_rec,(void(*)())smtp_cts,(void(*)())smtp_state,0,(char *)cb);
  729.                 cb->tcb->user = (char *)cb;     /* Upward pointer */
  730.         }
  731. }
  732.         
  733. /* add this job to control block queue */
  734. struct smtp_job *setupjob(struct smtp_cb *cb, char *id, char *from)
  735. {
  736.         register struct smtp_job *p1,*p2;
  737.  
  738.         p1 = (struct smtp_job *)calloc(1,sizeof(struct smtp_job));
  739.         if (p1 == NULLJOB)
  740.                 return NULLJOB;
  741.         p1->from = malloc((unsigned)strlen(from) + 1);
  742.         if (p1->from == NULLCHAR) {
  743.                 free((char *)p1);
  744.                 return NULLJOB;
  745.         }
  746.         strcpy(p1->from,from);
  747.         strcpy(p1->jobname,id);
  748.         /* now add to end of jobq */
  749.         if ((p2 = cb->jobq) == NULLJOB)
  750.                 cb->jobq = p1;
  751.         else {
  752.                 while(p2->next != NULLJOB)
  753.                         p2 = p2->next;
  754.                 p2->next = p1;
  755.         }
  756.         return p1;
  757. }
  758.  
  759. /* called to advance to the next job */
  760. static int nextjob(register struct smtp_cb *cb)
  761. {
  762.         register struct smtp_job *jp;
  763.  
  764.  
  765.         jp = cb->jobq->next;
  766.         del_job(cb->jobq);
  767.         if (jp == NULLJOB) {
  768.                 cb->jobq = NULLJOB;
  769.                 return 0;
  770.         }
  771.         /* remove the error log of previous message */
  772.         del_list(cb->errlog);
  773.         cb->errlog = NULLLIST;
  774.         cb->goodrcpt = 0;
  775.         cb->jobq = jp;
  776.         sprintf(cb->tname,"%s.text.%s",mailqdir,jp->jobname);
  777.         sprintf(cb->wname,"%s.work.%s",mailqdir,jp->jobname);
  778.         return 1;
  779. }
  780.  
  781.  
  782. /* mail routing funtion. For now just used the hosts file */
  783. int32 mailroute(char *dest)
  784. {
  785.         int32 destaddr;
  786.  
  787.         /* look up address or use the gateway */
  788.         if ((destaddr = resolve(dest)) == 0)
  789.                 if (gateway != 0) 
  790.                         destaddr = gateway; /* Use the gateway  */
  791.         return destaddr;
  792.         
  793. }
  794.  
  795. /* save error reply for in error list */
  796. static void logerr(struct smtp_cb *cb)
  797. {
  798.         register struct list *lp,*tp;
  799.         if ((tp = (struct list *)calloc(1,sizeof(struct list))) == NULLLIST)
  800.                 return;
  801.         if ((tp->val = malloc((unsigned)strlen(cb->buf)+1)) == NULLCHAR) {
  802.                 free((char *)tp);
  803.                 return;
  804.         }
  805.         /* find end of list */
  806.         if ((lp = cb->errlog) == NULLLIST)
  807.                 cb->errlog = tp;
  808.         else {
  809.                 while(lp->next != NULLLIST)
  810.                         lp = lp->next;
  811.                 lp->next = tp;
  812.         }
  813.         strcpy(tp->val,cb->buf);
  814. }
  815.