home *** CD-ROM | disk | FTP | other *** search
/ The Pier Shareware 6 / The_Pier_Shareware_Number_6_(The_Pier_Exchange)_(1995).iso / 024 / psi110g.zip / SMTPCLI.C < prev    next >
C/C++ Source or Header  |  1994-08-29  |  32KB  |  1,194 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. /* Mods by G1EMM and PA0GRI */
  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. #ifdef  LZW
  38. #include "lzw.h"
  39. #endif
  40. #include "timer.h"
  41. #include "netuser.h"
  42. #include "smtp.h"
  43. #include "dirutil.h"
  44. #include "commands.h"
  45. #include "session.h"
  46. #include "files.h"
  47.   
  48. #ifdef HOPPER
  49. #include "ip.h"
  50. int UseHopper = 1;      /* G8FSL SMTP hopper default ON */
  51. static int dohopper __ARGS((int argc,char *argv[],void *p));  /* g8fsl */
  52. #endif
  53.  
  54. struct timer Smtpcli_t;        /* not static because referenced in dosend() */
  55. static int32 Gateway;
  56. static int smtp_running=0;
  57.   
  58. #ifdef SMTPTRACE
  59. unsigned short Smtptrace = 0;        /* used for trace level */
  60. static int dosmtptrace __ARGS((int argc,char *argv[],void *p));
  61. static char smtp_recv[] = "smtpcli recv: %s\n";
  62. #endif
  63.   
  64. static unsigned  short Smtpmaxcli  = MAXSESSIONS;   /* the max client connections allowed */
  65. static int Smtpsessions = 0;        /* number of client connections
  66.                     * currently open */
  67. #ifdef  LZW
  68. int Smtpslzw = 1;
  69. int Smtpclzw = 1;
  70. static int Smtpbatch = 1;
  71. #else
  72. static int Smtpbatch = 0;
  73. #endif
  74. int Smtpmode = 0;
  75. int SmtpBidCheck = 1;
  76.   
  77. int Smtpquiet = 0;
  78. int UseMX = 0;          /* use MX records in domain lookup */
  79.   
  80. static struct smtpcli *cli_session[MAXSESSIONS]; /* queue of client sessions  */
  81.   
  82. static void smtp_fwd __ARGS((int unused,void *t,void *p));
  83. static void del_job __ARGS((struct smtp_job *jp));
  84. static void del_session __ARGS((struct smtpcli *cb));
  85. static int dogateway __ARGS((int argc,char *argv[],void *p));
  86. static int dosmtpmaxcli __ARGS((int argc,char *argv[],void *p));
  87. static int dotimer __ARGS((int argc,char *argv[],void *p));
  88. static int doquiet __ARGS((int argc,char *argv[],void *p));
  89. static int doclzw __ARGS((int argc,char *argv[],void *p));
  90. static int doslzw __ARGS((int argc,char *argv[],void *p));
  91. static int dousemx __ARGS((int argc,char *argv[],void *p));
  92. static int dosmtpkill __ARGS((int argc,char *argv[],void *p));
  93. static int dosmtplist __ARGS((int argc,char *argv[],void *p));
  94. static int dobatch __ARGS((int argc,char *argv[],void *p));
  95. static void execjobs __ARGS((void));
  96. static int getresp __ARGS((struct smtpcli *ftp,int mincode));
  97. static void logerr __ARGS((struct smtpcli *cb,char *line));
  98. static struct smtpcli *lookup __ARGS((int32 destaddr));
  99. static struct smtpcli *newcb __ARGS((void));
  100. static int next_job __ARGS((struct smtpcli *cb));
  101. static void retmail __ARGS((struct smtpcli *cb));
  102. static void sendcmd __ARGS((struct smtpcli *cb,char *fmt,...));
  103. static int smtpsendfile __ARGS((struct smtpcli *cb));
  104. static int setsmtpmode __ARGS((int argc,char *argv[],void *p));
  105. static struct smtp_job *setupjob __ARGS((struct smtpcli *cb,char *id,char *from));
  106. static void smtp_send __ARGS((int unused,void *cb1,void *p));
  107. static int smtpkick __ARGS((int argc,char *argv[],void *p));
  108. static int dosmtpt4 __ARGS((int argc,char *argv[],void *p));
  109. static int dosmtpservtdisc __ARGS((int argc,char *argv[],void *p));
  110. static int dobidcheck __ARGS((int argc,char *argv[],void *p));
  111.   
  112. static struct cmds Smtpcmds[] = {
  113.     "batch",    dobatch,    0,  0,  NULLCHAR,
  114.     "bidcheck", dobidcheck, 0,  0,  NULLCHAR,
  115.     "gateway",  dogateway,  0,  0,  NULLCHAR,
  116. #ifdef HOPPER
  117.     "hopper",   dohopper,   0,  0,  NULLCHAR,   /* g8fsl */
  118. #endif
  119.     "kick",     smtpkick,   0,  0,  NULLCHAR,
  120.     "kill",     dosmtpkill, 0,  2,  "kill <jobnumber>",
  121.     "list",     dosmtplist, 0,  0,  NULLCHAR,
  122.     "maxclients",   dosmtpmaxcli,   0,  0,  NULLCHAR,
  123.     "mode",     setsmtpmode,    0,  0,  NULLCHAR,
  124.     "quiet",    doquiet,    0,  0,  NULLCHAR,
  125. #ifdef  LZW
  126.     "reclzw",   doslzw,     0,  0,  NULLCHAR,
  127.     "sendlzw",  doclzw,     0,  0,  NULLCHAR,
  128. #endif
  129.     "tdisc",    dosmtpservtdisc,0,0,NULLCHAR,
  130.     "timer",    dotimer,    0,  0,  NULLCHAR,
  131. #ifdef SMTPTRACE
  132.     "trace",    dosmtptrace,    0,  0,  NULLCHAR,
  133. #endif
  134.     "t4",       dosmtpt4,   0,  0,  NULLCHAR,
  135.     "usemx",    dousemx,    0,  0,  NULLCHAR,
  136.     NULLCHAR,
  137. };
  138.   
  139. int
  140. dosmtp(argc,argv,p)
  141. int argc;
  142. char *argv[];
  143. void *p;
  144. {
  145.     return subcmd(Smtpcmds,argc,argv,p);
  146. }
  147.   
  148. int Smtpt4;
  149.   
  150. static int
  151. dosmtpt4(argc,argv,p)
  152. int argc;
  153. char *argv[];
  154. void *p;
  155. {
  156.     return setint(&Smtpt4,"SMTP T4",argc,argv);
  157. }
  158.   
  159. int SmtpServTdisc;
  160.   
  161. static int
  162. dosmtpservtdisc(argc,argv,p)
  163. int argc;
  164. char *argv[];
  165. void *p;
  166. {
  167.     return setint(&SmtpServTdisc,"Server tdisc (sec)",argc,argv);
  168. }
  169.   
  170. static int
  171. dobatch(argc,argv,p)
  172. int argc;
  173. char *argv[];
  174. void *p;
  175. {
  176.     return setbool(&Smtpbatch,"SMTP batching",argc,argv);
  177. }
  178.   
  179. static int
  180. dobidcheck(argc,argv,p)
  181. int argc;
  182. char *argv[];
  183. void *p;
  184. {
  185.     return setbool(&SmtpBidCheck,"SMTP BID Checking",argc,argv);
  186. }
  187.   
  188. #ifdef LZW
  189. static int
  190. doclzw(argc,argv,p)
  191. int argc;
  192. char *argv[];
  193. void *p;
  194. {
  195.     return setbool(&Smtpclzw,"SMTP send lzw",argc,argv);
  196. }
  197. #endif
  198.   
  199. static int
  200. doquiet(argc,argv,p)
  201. int argc;
  202. char *argv[];
  203. void *p;
  204. {
  205.     return setbool(&Smtpquiet,"SMTP quiet",argc,argv);
  206. }
  207.   
  208. #ifdef LZW
  209. static int
  210. doslzw(argc,argv,p)
  211. int argc;
  212. char *argv[];
  213. void *p;
  214. {
  215.     return setbool(&Smtpslzw,"SMTP recv lzw",argc,argv);
  216. }
  217. #endif
  218.   
  219. static int
  220. dousemx(argc,argv,p)
  221. int argc;
  222. char *argv[];
  223. void *p;
  224. {
  225.     return setbool(&UseMX,"MX records used",argc,argv);
  226. }
  227. static int
  228. dosmtpmaxcli(argc,argv,p)
  229. int argc;
  230. char *argv[];
  231. void *p;
  232. {
  233.     return setshort(&Smtpmaxcli,"Max clients",argc,argv);
  234. }
  235.   
  236. static int
  237. setsmtpmode(argc,argv,p)
  238. int argc;
  239. char *argv[];
  240. void *p;
  241. {
  242.     if (argc < 2) {
  243.         tprintf("smtp mode: %s\n",
  244.         (Smtpmode & QUEUE) ? "queue" : "route");
  245.     } else {
  246.         switch(*argv[1]) {
  247.             case 'q':
  248.                 Smtpmode |= QUEUE;
  249.                 break;
  250.             case 'r':
  251.                 Smtpmode &= ~QUEUE;
  252.                 break;
  253.             default:
  254.                 tputs("Usage: smtp mode [queue | route]\n");
  255.                 break;
  256.         }
  257.     }
  258.     return 0;
  259. }
  260.  
  261. static int
  262. dogateway(argc,argv,p)
  263. int argc;
  264. char *argv[];
  265. void *p;
  266. {
  267.     int32 n;
  268.   
  269.     if(argc < 2){
  270.         tprintf("%s\n",inet_ntoa(Gateway));
  271.     } else if((n = resolve(argv[1])) == 0){
  272.         tprintf(Badhost,argv[1]);
  273.         return 1;
  274.     } else
  275.         Gateway = n;
  276.     return 0;
  277. }
  278.   
  279. #ifdef HOPPER
  280. static int
  281. dohopper(argc,argv,p)
  282. int argc;
  283. char *argv[];
  284. void *p;
  285. {
  286.     return setbool(&UseHopper,"mail hopper",argc,argv);
  287. }
  288. #endif
  289.  
  290. #ifdef SMTPTRACE
  291. static int
  292. dosmtptrace(argc,argv,p)
  293. int argc;
  294. char *argv[];
  295. void *p;
  296. {
  297.     return setshort(&Smtptrace,"SMTP tracing",argc,argv);
  298. }
  299. #endif
  300.   
  301. /* list jobs waiting to be sent in the mqueue */
  302. static int
  303. dosmtplist(argc,argv,p)
  304. int argc;
  305. char *argv[];
  306. void *p;
  307. {
  308.     char tstring[80];
  309.     char line[20];
  310.     char host[LINELEN];
  311.     char to[LINELEN];
  312.     char from[LINELEN];
  313.     char *cp;
  314.     char status;
  315.     int flowsave;
  316.     struct ffblk ff;
  317.     struct ftime *ft;
  318.     FILE *fp;
  319.   
  320.     flowsave = Current->flowmode;
  321.     Current->flowmode = 1; /* Enable the more mechanism */
  322.     tputs("S   Job   Size Date  Time  Host                 From\n");
  323.     filedir(Mailqueue,0,line);
  324.     while(line[0] != '\0') {
  325.         sprintf(tstring,"%s/%s",Mailqdir,line);
  326.         if ((fp = fopen(tstring,READ_TEXT)) == NULLFILE) {
  327.             tprintf("Can't open %s: %s\n",tstring,sys_errlist[errno]);
  328.             continue;
  329.         }
  330.         if ((cp = strrchr(line,'.')) != NULLCHAR)
  331.             *cp = '\0';
  332.         sprintf(tstring,"%s/%s.lck",Mailqdir,line);
  333.         if (access(tstring,0))
  334.             status = ' ';
  335.         else
  336.             status = 'L';
  337.         /* This is a no-no for Borland compilers...
  338.          * Blows up DV and OS/2 VDM !
  339.          * stat(tstring,&stbuf);
  340.          */
  341.         sprintf(tstring,"%s/%s.txt",Mailqdir,line);
  342.         findfirst(tstring,&ff,0);
  343.         ft = (struct ftime *) &ff.ff_ftime;
  344.   
  345.         fgets(host,sizeof(host),fp);
  346.         rip(host);
  347.         fgets(from,sizeof(from),fp);
  348.         rip(from);
  349.   
  350.         tprintf("%c %5s %6ld %02d/%02d %02d:%02d %-20s %s\n  To:",
  351.         status, line,
  352.         ff.ff_fsize,
  353.         ft->ft_month,ft->ft_day,
  354.         ft->ft_hour,ft->ft_min,
  355.         host,from);
  356.         while (fgets(to,sizeof(to),fp) != NULLCHAR) {
  357.             rip(to);
  358.             tprintf(" %s",to);
  359.         }
  360.         tputc('\n');
  361.         (void) fclose(fp);
  362.         pwait(NULL);
  363.         filedir(Mailqueue,1,line);
  364.     }
  365.     Current->flowmode = flowsave;
  366.     return 0;
  367. }
  368.   
  369. /* kill a job in the mqueue */
  370. static int
  371. dosmtpkill(argc,argv,p)
  372. int argc;
  373. char *argv[];
  374. void *p;
  375. {
  376.     char s[SLINELEN];
  377.     char *cp,c;
  378.     sprintf(s,"%s/%s.lck",Mailqdir,argv[1]);
  379.     cp = strrchr(s,'.');
  380.     if (!access(s,0)) {
  381.         Current->ttystate.echo = Current->ttystate.edit = 0;
  382.         c = keywait("Warning, job is locked by SMTP. Remove (y/n)? ",0);
  383.         Current->ttystate.echo = Current->ttystate.edit = 1;
  384.         if (c != 'y')
  385.             return 0;
  386.         (void) unlink(s);
  387.     }
  388.     strcpy(cp,".wrk");
  389.     if (unlink(s))
  390.         tprintf("Job id %s not found\n",argv[1]);
  391.     strcpy(cp,".txt");
  392.     (void) unlink(s);
  393.     return 0;
  394. }
  395.   
  396. /* Set outbound spool scan interval */
  397. static int
  398. dotimer(argc,argv,p)
  399. int argc;
  400. char *argv[];
  401. void *p;
  402. {
  403.     if(argc < 2){
  404.         tprintf("smtp timer = %lu/%lu\n",
  405.         read_timer(&Smtpcli_t)/1000L,
  406.         dur_timer(&Smtpcli_t)/1000L);
  407.         return 0;
  408.     }
  409.     Smtpcli_t.func = (void (*)__ARGS((void*)))smtptick;/* what to call on timeout */
  410.     Smtpcli_t.arg = NULL;       /* dummy value */
  411.     set_timer(&Smtpcli_t,atol(argv[1])*1000L);  /* set timer duration */
  412.     start_timer(&Smtpcli_t);        /* and fire it up */
  413.     return 0;
  414. }
  415.   
  416. static int
  417. smtpkick(argc,argv,p)
  418. int argc;
  419. char *argv[];
  420. void *p;
  421. {
  422.     int32 addr = 0;
  423.     if(argc > 1 && (addr = resolve(argv[1])) == 0){
  424.         tprintf(Badhost,argv[1]);
  425.         return 1;
  426.     }
  427.     smtptick((void *)addr);
  428.     return 0;
  429. }
  430.   
  431. /* This is the routine that gets called every so often to do outgoing
  432.  * mail processing. When called with a null argument, it runs the entire
  433.  * queue; if called with a specific non-zero IP address from the remote
  434.  * kick server, it only starts up sessions to that address.
  435.  */
  436. void
  437. smtptick(t)
  438. void *t;
  439. {
  440.     if (!smtp_running) {
  441.         smtp_running=1;
  442.         if(newproc("smtp_fwd", 2048, smtp_fwd, 0, t,NULL,0) == NULLPROC) {
  443.             start_timer(&Smtpcli_t);
  444.             smtp_running = 0;
  445.         }
  446.     }
  447. }
  448.   
  449.   
  450. /* The old smtptick function now becomes a process "smtp_fwd"
  451. */
  452.   
  453. static void
  454. smtp_fwd(unused,t,p)
  455. int unused;
  456. void *t;
  457. void *p;
  458. {
  459.     register struct smtpcli *cb;
  460.     struct smtp_job *jp;
  461.     struct list *ap;
  462.     char    tmpstring[LINELEN], wfilename[13], prefix[9];
  463.     char    from[LINELEN], to[LINELEN];
  464.     char *cp, *cp1;
  465.     int32 destaddr,target;
  466.     FILE *wfile;
  467.   
  468.     target = (int32)t;
  469. #ifdef SMTPTRACE
  470.     if (Smtptrace > 5)
  471.         printf("smtp daemon entered, target = %s\n",inet_ntoa(target));
  472. #endif
  473.     if(availmem() < Memthresh){
  474.         /* Memory is tight, don't do anything */
  475.         /* Restart timer */
  476.         start_timer(&Smtpcli_t);
  477.         smtp_running = 0;
  478.         return;
  479.     }
  480.     for(filedir(Mailqueue,0,wfilename);wfilename[0] != '\0';
  481.     filedir(Mailqueue,1,wfilename)){
  482.   
  483.         /* save the prefix of the file name which it job id */
  484.         cp = wfilename;
  485.         cp1 = prefix;
  486.         while (*cp && *cp != '.')
  487.             *cp1++ = *cp++;
  488.         *cp1 = '\0';
  489.   
  490.         /* lock this file from the smtp daemon */
  491.         if (mlock(Mailqdir,prefix))
  492.             continue;
  493.   
  494.         sprintf(tmpstring,"%s/%s",Mailqdir,wfilename);
  495.         if ((wfile = fopen(tmpstring,READ_TEXT)) == NULLFILE) {
  496.             /* probably too many open files */
  497.             (void) rmlock(Mailqdir,prefix);
  498.             /* continue to next message. The failure
  499.             * may be temporary */
  500.             continue;
  501.         }
  502.   
  503.         (void) fgets(tmpstring,LINELEN,wfile);  /* read target host */
  504.         rip(tmpstring);
  505.   
  506.         if ((destaddr = mailroute(tmpstring)) == 0) {
  507.             fclose(wfile);
  508.             printf("** smtp: Unknown address %s\n",tmpstring);
  509.             (void) rmlock(Mailqdir,prefix);
  510.             continue;
  511.         }
  512.         if(target != 0 && destaddr != target){
  513.             fclose(wfile);
  514.             (void) rmlock(Mailqdir,prefix);
  515.             continue;   /* Not the proper target of a kick */
  516.         }
  517.         if ((cb = lookup(destaddr)) == NULLSMTPCLI) {
  518.             /* there are enough processes running already */
  519.             if (Smtpsessions >= Smtpmaxcli) {
  520. #ifdef SMTPTRACE
  521.                 if (Smtptrace>1) {
  522.                     printf("smtp daemon: too many processes\n");
  523.                 }
  524. #endif
  525.                 fclose(wfile);
  526.                 (void) rmlock(Mailqdir,prefix);
  527.                 break;
  528.             }
  529.             if ((cb = newcb()) == NULLSMTPCLI) {
  530.                 fclose(wfile);
  531.                 (void) rmlock(Mailqdir,prefix);
  532.                 break;
  533.             }
  534.             cb->ipdest = destaddr;
  535.             cb->destname = strdup(tmpstring);
  536.         } else {
  537.             if(cb->lock){
  538.                 /* This system is already is sending mail lets not
  539.                 * interfere with its send queue.
  540.                 */
  541.                 fclose(wfile);
  542.                 (void) rmlock(Mailqdir,prefix);
  543.                 continue;
  544.             }
  545.         }
  546.   
  547.         (void) fgets(from,LINELEN,wfile);   /* read from */
  548.         rip(from);
  549.         if ((jp = setupjob(cb,prefix,from)) == NULLJOB) {
  550.             fclose(wfile);
  551.             (void) rmlock(Mailqdir,prefix);
  552.             del_session(cb);
  553.             break;
  554.         }
  555.         while (fgets(to,LINELEN,wfile) != NULLCHAR) {
  556.             rip(to);
  557.             if (addlist(&jp->to,to,DOMAIN) == NULLLIST) {
  558.                 fclose(wfile);
  559.                 del_session(cb);
  560.             }
  561.         }
  562.         fclose(wfile);
  563. #ifdef SMTPTRACE
  564.         if (Smtptrace > 2) {
  565.             printf("queue job %s From: %s To:",prefix,from);
  566.             for (ap = jp->to; ap != NULLLIST; ap = ap->next)
  567.                 printf(" %s",ap->val);
  568.             printf("\n");
  569.         }
  570. #endif
  571.     }
  572.   
  573.     /* start sending that mail */
  574.     execjobs();
  575.   
  576.     /* Restart timer */
  577.     start_timer(&Smtpcli_t);
  578.     smtp_running = 0;
  579.     return;
  580. }
  581.   
  582. /* This is the master state machine that handles a single SMTP transaction.
  583.  * It is called with a queue of jobs for a particular host.
  584.  * The logic is complicated by the "Smtpbatch" variable, which controls
  585.  * the batching of SMTP commands. If Smtpbatch is true, then many of the
  586.  * SMTP commands are sent in one swell foop before waiting for any of
  587.  * the responses. Unfortunately, this breaks many brain-damaged SMTP servers
  588.  * out there, so provisions have to be made to operate SMTP in lock-step mode.
  589.  */
  590. static void
  591. smtp_send(unused,cb1,p)
  592. int unused;
  593. void *cb1;
  594. void *p;
  595. {
  596.     register struct smtpcli *cb;
  597.     register struct list *tp;
  598.     struct sockaddr_in fsocket;
  599.     char *cp;
  600.     int rcode;
  601.     int rcpts;
  602.     int goodrcpt;
  603.     int i;
  604.     int smtpbatch;
  605.     int init = 1;
  606. #ifdef  LZW
  607.     int lzwmode, lzwbits;
  608.     extern int16 Lzwbits;
  609.     extern int Lzwmode;
  610. #endif
  611.   
  612.     cb = (struct smtpcli *)cb1;
  613.     cb->lock = 1;
  614.     fsocket.sin_family = AF_INET;
  615.     fsocket.sin_addr.s_addr = cb->ipdest;
  616.     fsocket.sin_port = IPPORT_SMTP;
  617.   
  618.     cb->s = socket(AF_INET,SOCK_STREAM,0);
  619.     sockmode(cb->s,SOCK_ASCII);
  620.     setflush(cb->s,-1); /* We'll explicitly flush before reading */
  621. #ifdef SMTPTRACE
  622.     if (Smtptrace>1)
  623.         printf("SMTP client Trying...\n");
  624. #endif
  625.     /* Set a timeout for this connection */
  626.     alarm(Smtpt4 * 1000L);
  627.     if(connect(cb->s,(char *)&fsocket,SOCKSIZE) != 0){
  628.         alarm(0L);
  629.         close_s(cb->s);     /* to make sure it's closed */
  630.         if(Smtpt4 && Gateway
  631.            && (fsocket.sin_addr.s_addr != Gateway)
  632. #ifdef HOPPER
  633.            && (Gateway != Ip_addr)       /* g8fsl via g0mhd */
  634. #endif
  635.           ) {
  636.             /* Try it via the gateway */
  637.             fsocket.sin_addr.s_addr = Gateway;
  638.             cb->s = socket(AF_INET,SOCK_STREAM,0);
  639.             sockmode(cb->s,SOCK_ASCII);
  640.             setflush(cb->s,-1); /* We'll explicitly flush before reading */
  641. #ifdef SMTPTRACE
  642.             if (Smtptrace>1)
  643.                 printf("SMTP client Trying gateway...\n");
  644. #endif
  645.             /* Set a timeout for this connection */
  646.             alarm(Smtpt4 * 1000L);
  647.             if(connect(cb->s,(char *)&fsocket,SOCKSIZE) != 0){
  648.                 alarm(0L);
  649.                 cp = sockerr(cb->s);
  650.                 close_s(cb->s);     /* to make sure it's closed */
  651. #ifdef SMTPTRACE
  652.                 if (Smtptrace>1)
  653.                     printf("Connect failed: %s\n",cp != NULLCHAR ? cp : "");
  654. #endif
  655.                 log(cb->s,"SMTP %s Connect failed: %s",psocket(&fsocket),
  656.                 cp != NULLCHAR ? cp : "");
  657.                 goto quit;
  658.             }
  659.         } else {
  660.             goto quit;
  661.         }
  662.     }
  663.     alarm(0L);
  664. #ifdef SMTPTRACE
  665.     if (Smtptrace>1)
  666.         printf("Connected\n");
  667. #endif
  668.   
  669. #ifdef  LZW
  670.     rcode = getresp(cb,200);
  671.     if(rcode == -1 || rcode >= 400)
  672.         goto quit;
  673.   
  674.     if(Smtpclzw) {
  675.         char cp[LINELEN];
  676.         sendcmd(cb,"XLZW %d %d\n",Lzwbits,Lzwmode);
  677.         usflush(cb->s);
  678.         if(recvline(cb->s,cp,sizeof(cp)) == -1)
  679.             goto quit;
  680.         rip(cp);
  681. #ifdef  SMTPTRACE
  682.         if(Smtptrace>1)
  683.             printf(smtp_recv,cp);/* Display to user */
  684. #endif
  685.         rcode = lzwmode = lzwbits = 0;
  686.         sscanf(cp,"%d %d %d",&rcode,&lzwbits,&lzwmode);
  687.         if((rcode >= 200) && (rcode < 300)) {
  688.             smtpbatch = 1;
  689.             if(lzwmode != Lzwmode || lzwbits != Lzwbits) {
  690.                 lzwmode = LZWCOMPACT;
  691.                 lzwbits = LZWBITS;
  692.             }
  693.             lzwinit(cb->s,lzwbits,lzwmode);
  694.         } else {
  695.             smtpbatch = Smtpbatch;
  696.         }
  697.     } else {
  698.         smtpbatch = Smtpbatch;
  699.     }
  700. #else
  701.     smtpbatch = Smtpbatch;
  702.     if(!smtpbatch){
  703.         rcode = getresp(cb,200);
  704.         if(rcode == -1 || rcode >= 400)
  705.             goto quit;
  706.     }
  707. #endif
  708.     /* Say HELO */
  709.     sendcmd(cb,"HELO %s\n",Hostname);
  710.     if(!smtpbatch){
  711.         rcode = getresp(cb,200);
  712.         if(rcode == -1 || rcode >= 400)
  713.             goto quit;
  714.     }
  715.     do {    /* For each message... */
  716.  
  717.         /* if this file open fails, skip it */
  718.         if ((cb->tfile = fopen(cb->tname,READ_TEXT)) == NULLFILE)
  719.             continue;
  720.  
  721.         /* Send MAIL and RCPT commands */
  722.         sendcmd(cb,"MAIL FROM:<%s>\n",cb->jobq->from);
  723.         if(!smtpbatch){
  724.             rcode = getresp(cb,200);
  725.             if(rcode == -1 || rcode >= 400)
  726.                 goto quit;
  727.         }
  728.         rcpts = 0;
  729.         goodrcpt = 0;
  730.         for (tp = cb->jobq->to; tp != NULLLIST; tp = tp->next){
  731.             sendcmd(cb,"RCPT TO:<%s>\n",tp->val);
  732.             if(!smtpbatch){
  733.                 rcode = getresp(cb,200);
  734.                 if(rcode == -1)
  735.                     goto quit;
  736.                 if(rcode < 400)
  737.                     goodrcpt = 1; /* At least one good */
  738.             }
  739.             rcpts++;
  740.         }
  741.         /* Send DATA command */
  742.         sendcmd(cb,"DATA\n");
  743.         if(!smtpbatch){
  744.             rcode = getresp(cb,200);
  745.             if(rcode == -1 || rcode >= 400)
  746.                 goto quit;
  747.         }
  748.         if(smtpbatch){
  749.             /* Now wait for the responses to come back. The first time
  750.              * we do this, we wait first for the start banner and
  751.              * HELO response. In any case, we wait for the response to
  752.              * the MAIL command here.
  753.              */
  754. #ifdef  LZW
  755.             for(i= init ? 2 : 1;i > 0;i--){
  756. #else
  757.             for(i= init ? 3 : 1;i > 0;i--){
  758. #endif
  759.                 rcode = getresp(cb,200);
  760.                 if(rcode == -1 || rcode >= 400)
  761.                     goto quit;
  762.             }
  763.             init = 0;
  764.   
  765.             /* Now process the responses to the RCPT commands */
  766.             for(i=rcpts;i!=0;i--){
  767.                 rcode = getresp(cb,200);
  768.                 if(rcode == -1)
  769.                     goto quit;
  770.                 if(rcode < 400)
  771.                     goodrcpt = 1; /* At least one good */
  772.             }
  773.             /* And finally get the response to the DATA command.
  774.              * Some servers will return failure here if no recipients
  775.              * are valid, some won't.
  776.              */
  777.             rcode = getresp(cb,200);
  778.             if(rcode == -1 || rcode >= 400)
  779.                 goto quit;
  780.   
  781.             /* check for no good rcpt on the list */
  782.             if (goodrcpt == 0){
  783.                 sendcmd(cb,".\n");  /* Get out of data mode */
  784.                 goto quit;
  785.             }
  786.         }
  787.         /* Send the file. This also closes it */
  788.         smtpsendfile(cb);
  789.   
  790.         /* Wait for the OK response */
  791.         rcode = getresp(cb,200);
  792.         if(rcode == -1)
  793.             goto quit;
  794.         if((rcode >= 200 && rcode < 300) || rcode >= 500){
  795.             /* if a good transfer or permanent failure remove job */
  796.   
  797.             if (cb->errlog != NULLLIST)
  798.                 retmail(cb);
  799.             /* Unlink the textfile */
  800.             (void) unlink(cb->tname);
  801.             (void) unlink(cb->wname);   /* unlink workfile */
  802.             log(cb->s,"SMTP sent job %s To: %s From: %s",
  803.             cb->jobq->jobname,cb->jobq->to->val,cb->jobq->from);
  804.         }
  805.     } while(next_job(cb));
  806. quit:
  807.     sendcmd(cb,"QUIT\n");
  808.     if (cb->errlog != NULLLIST){
  809.         retmail(cb);
  810.         (void) unlink(cb->wname);   /* unlink workfile */
  811.         (void) unlink(cb->tname);   /* unlink text */
  812.     }
  813.     (void) close_s(cb->s);
  814.     if(cb->tfile != NULLFILE)
  815.         fclose(cb->tfile);
  816.     cb->lock = 0;
  817.     del_session(cb);
  818. }
  819.   
  820. /* free the message struct and data */
  821. static void
  822. del_session(cb)
  823. register struct smtpcli *cb;
  824. {
  825.     register struct smtp_job *jp,*tp;
  826.     register int i;
  827.  
  828.     if (cb == NULLSMTPCLI)
  829.         return;
  830.     for(i=0; i<MAXSESSIONS; i++)
  831.         if(cli_session[i] == cb) {
  832.             cli_session[i] = NULLSMTPCLI;
  833.             break;
  834.         }
  835.  
  836.     free(cb->wname);
  837.     free(cb->tname);
  838.     free(cb->destname);
  839.     for (jp = cb->jobq; jp != NULLJOB;jp = tp) {
  840.         tp = jp->next;
  841.         del_job(jp);
  842.     }
  843.     del_list(cb->errlog);
  844.     free((char *)cb);
  845.     Smtpsessions--; /* number of connections active */
  846. }
  847.  
  848. static void
  849. del_job(jp)
  850. register struct smtp_job *jp;
  851. {
  852.     if ( *jp->jobname != '\0')
  853.         (void) rmlock(Mailqdir,jp->jobname);
  854.     free(jp->from);
  855.     del_list(jp->to);
  856.     free((char *)jp);
  857. }
  858.  
  859. /* delete a list of list structs */
  860. void
  861. del_list(lp)
  862. struct list *lp;
  863. {
  864.     register struct list *tp, *tp1;
  865.     for (tp = lp; tp != NULLLIST; tp = tp1) {
  866.         tp1 = tp->next;
  867.         free(tp->val);
  868.         free((char *)tp);
  869.     }
  870. }
  871.  
  872. /* stub for calling mdaemon to return message to sender */
  873. static void
  874. retmail(cb)
  875. struct smtpcli *cb;
  876. {
  877.     FILE *infile;
  878. #ifdef SMTPTRACE
  879.     if (Smtptrace > 5) {
  880.         printf("smtp job %s returned to sender\n",cb->wname);
  881.     }
  882. #endif
  883.     if ((infile = fopen(cb->tname,READ_TEXT)) == NULLFILE)
  884.         return;
  885.     mdaemon(infile,cb->jobq->from,cb->errlog,1);
  886.     fclose(infile);
  887. }
  888.  
  889. /* look to see if a smtp control block exists for this ipdest */
  890. static struct smtpcli *
  891. lookup(destaddr)
  892. int32 destaddr;
  893. {
  894.     register int i;
  895.  
  896.     for(i=0; i<MAXSESSIONS; i++) {
  897.         if (cli_session[i] == NULLSMTPCLI)
  898.             continue;
  899.         if(cli_session[i]->ipdest == destaddr)
  900.             return cli_session[i];
  901.     }
  902.     return NULLSMTPCLI;
  903. }
  904.   
  905. /* create a new  smtp control block */
  906. static struct smtpcli *
  907. newcb()
  908. {
  909.     register int i;
  910.     register struct smtpcli *cb;
  911.  
  912.     for(i=0; i<MAXSESSIONS; i++) {
  913.         if(cli_session[i] == NULLSMTPCLI) {
  914.             cb = (struct smtpcli *)callocw(1,sizeof(struct smtpcli));
  915.             cb->wname = mallocw((unsigned)strlen(Mailqdir)+JOBNAME);
  916.             cb->tname = mallocw((unsigned)strlen(Mailqdir)+JOBNAME);
  917.             cli_session[i] = cb;
  918.             Smtpsessions++; /* number of connections active */
  919.             return(cb);
  920.         }
  921.     }
  922.     return NULLSMTPCLI;
  923. }
  924.  
  925. static void
  926. execjobs()
  927. {
  928.     register struct smtpcli *cb;
  929.     register int i, insave, outsave;
  930.  
  931.     for(i=0; i<MAXSESSIONS; i++) {
  932.         cb = cli_session[i];
  933.         if (cb == NULLSMTPCLI)
  934.             continue;
  935.         if(cb->lock)
  936.             continue;
  937.  
  938.         sprintf(cb->tname,"%s/%s.txt",Mailqdir,cb->jobq->jobname);
  939.         sprintf(cb->wname,"%s/%s.wrk",Mailqdir,cb->jobq->jobname);
  940.   
  941.         /* This solves the nasty hack in mailbox.c, from Mark ve3dte */
  942.         insave = Curproc->input;
  943.         outsave = Curproc->output;
  944.         Curproc->input = -1;
  945.         Curproc->output = -1;
  946.         /* Now we can call newproc with null parent sockets! */
  947.         newproc("smtp_send", 1536, smtp_send, 0, cb,NULL,0);
  948.         /* now restore parent sockets so parent can continue */
  949.         Curproc->input = insave;
  950.         Curproc->output = outsave;
  951.   
  952. #ifdef SMTPTRACE
  953.         if (Smtptrace>1)
  954.             printf("Trying Connection to %s\n",inet_ntoa(cb->ipdest));
  955. #endif
  956.  
  957.     }
  958. }
  959.   
  960. /* add this job to control block queue */
  961. static struct smtp_job *
  962. setupjob(cb,id,from)
  963. struct smtpcli *cb;
  964. char *id,*from;
  965. {
  966.     register struct smtp_job *p1,*p2;
  967.  
  968.     p1 = (struct smtp_job *)callocw(1,sizeof(struct smtp_job));
  969.     p1->from = strdup(from);
  970.     strcpy(p1->jobname,id);
  971. /* now add to end of jobq */
  972.     if ((p2 = cb->jobq) == NULLJOB)
  973.         cb->jobq = p1;
  974.     else {
  975.         while(p2->next != NULLJOB)
  976.             p2 = p2->next;
  977.         p2->next = p1;
  978.     }
  979.     return p1;
  980. }
  981.   
  982. /* called to advance to the next job */
  983. static int
  984. next_job(cb)
  985. register struct smtpcli *cb;
  986. {
  987.     register struct smtp_job *jp;
  988.  
  989.     jp = cb->jobq->next;
  990.     del_job(cb->jobq);
  991. /* remove the error log of previous message */
  992.     del_list(cb->errlog);
  993.     cb->errlog = NULLLIST;
  994.     cb->jobq = jp;
  995.     if (jp == NULLJOB)
  996.         return 0;
  997.     sprintf(cb->tname,"%s/%s.txt",Mailqdir,jp->jobname);
  998.     sprintf(cb->wname,"%s/%s.wrk",Mailqdir,jp->jobname);
  999. #ifdef SMTPTRACE
  1000.     if (Smtptrace > 5) {
  1001.         printf("sending job %s\n",jp->jobname);
  1002.     }
  1003. #endif
  1004.     return 1;
  1005.  
  1006. }
  1007.   
  1008.   
  1009. /* Mail routing function. */
  1010. int32
  1011. mailroute(dest)
  1012. char *dest;
  1013. {
  1014.     int32 destaddr = 0L;
  1015.  
  1016. #ifdef HOPPER
  1017.     struct route *rp;
  1018. #endif
  1019.   
  1020. #ifdef SMTPTRACE
  1021.     if (Smtptrace > 6)
  1022.         printf("Route lookup for = %s\n",dest);
  1023. #endif
  1024.  
  1025. #ifdef HOPPER
  1026.     if (*dest == '\0'){
  1027. #ifdef SMTPTRACE
  1028.         if (Smtptrace > 6)
  1029.             printf("Local mail\n");
  1030. #endif
  1031.         return Ip_addr;
  1032.     }
  1033. #endif
  1034.  
  1035.     /* look up address or use the gateway */
  1036.     if(UseMX){
  1037.         destaddr = resolve_mx(dest);
  1038. #ifdef SMTPTRACE
  1039.         if (Smtptrace > 6)
  1040.             printf("MX lookup returned = %s\n",inet_ntoa(destaddr));
  1041. #endif
  1042.     }
  1043.     if(destaddr == 0L)
  1044.         if((destaddr = resolve(dest)) == 0L)
  1045.             if (Gateway != 0L)
  1046.                 destaddr = Gateway; /* Use the gateway  */
  1047. #ifdef SMTPTRACE
  1048.     if (Smtptrace > 6)
  1049.         printf("Address resolver returned = %s\n",inet_ntoa(destaddr));
  1050. #endif
  1051.  
  1052. #ifdef HOPPER
  1053.     if (UseHopper && (destaddr != Ip_addr)) {
  1054.         if ((rp=rt_lookup(destaddr)) != NULLROUTE)
  1055.             if (rp->gateway != 0L)
  1056.                 destaddr=rp->gateway;
  1057. #ifdef SMTPTRACE
  1058.         if (Smtptrace > 6)
  1059.             printf("Hopper returned = %s\n",inet_ntoa(destaddr));
  1060. #endif
  1061.     }
  1062. #endif
  1063.  
  1064. #ifdef SMTPTRACE
  1065.     if (Smtptrace > 6)
  1066.         printf("Mailroute returned = %s\n",inet_ntoa(destaddr));
  1067. #endif
  1068.     return destaddr;
  1069.  
  1070. }
  1071.   
  1072. /* save line in error list */
  1073. static void
  1074. logerr(cb,line)
  1075. struct smtpcli *cb;
  1076. char *line;
  1077. {
  1078.     register struct list *lp,*tp;
  1079.     tp = (struct list *)callocw(1,sizeof(struct list));
  1080.     tp->val = strdup(line);
  1081.     /* find end of list */
  1082.     if ((lp = cb->errlog) == NULLLIST)
  1083.         cb->errlog = tp;
  1084.     else {
  1085.         while(lp->next != NULLLIST)
  1086.             lp = lp->next;
  1087.         lp->next = tp;
  1088.     }
  1089. }
  1090.  
  1091. static int
  1092. smtpsendfile(cb)
  1093. register struct smtpcli *cb;
  1094. {
  1095.     int error = 0;
  1096.  
  1097.     strcpy(cb->buf,"\n");
  1098.     while(fgets(cb->buf,sizeof(cb->buf),cb->tfile) != NULLCHAR) {
  1099.     /* Escape a single '.' character at the beginning of a line */
  1100.         if(strcmp(cb->buf,".\n") == 0)
  1101.             usputc(cb->s,'.');
  1102.         usputs(cb->s,cb->buf);
  1103.     }
  1104.     fclose(cb->tfile);
  1105.     cb->tfile = NULLFILE;
  1106.     /* Send the end-of-message command */
  1107.     if(cb->buf[strlen(cb->buf)-1] == '\n')
  1108.         sendcmd(cb,".\n");
  1109.     else
  1110.         sendcmd(cb,"\n.\n");
  1111.     return error;
  1112. }
  1113.  
  1114. /* do a printf() on the socket with optional local tracing */
  1115. #ifdef  ANSIPROTO
  1116. static void
  1117. sendcmd(struct smtpcli *cb,char *fmt, ...)
  1118. {
  1119.     va_list args;
  1120.  
  1121.     va_start(args,fmt);
  1122. #ifdef  SMTPTRACE
  1123.     if(Smtptrace>1){
  1124.         printf("smtp sent: ");
  1125.         vprintf(fmt,args);
  1126.     }
  1127. #endif
  1128.     vsprintf(cb->buf,fmt,args);
  1129.     usputs(cb->s,cb->buf);
  1130.     va_end(args);
  1131. }
  1132. #else
  1133. static void
  1134. sendcmd(cb,fmt,arg1,arg2,arg3,arg4)
  1135. struct smtpcli *cb;
  1136. char *fmt;
  1137. int arg1,arg2,arg3,arg4;
  1138. {
  1139. #ifdef  SMTPTRACE
  1140.     if(Smtptrace>1){
  1141.         printf("smtp sent: ");
  1142.         printf(fmt,arg1,arg2,arg3,arg4);
  1143.     }
  1144. #endif
  1145.     sprintf(cb->buf,fmt,arg1,arg2,arg3,arg4);
  1146.     usputs(cb->s,cb->buf);
  1147. }
  1148. #endif
  1149.   
  1150. /* Wait for, read and display response from server. Return the result code. */
  1151. static int
  1152. getresp(cb,mincode)
  1153. struct smtpcli *cb;
  1154. int mincode;    /* Keep reading until at least this code comes back */
  1155. {
  1156.     int rval;
  1157.     char line[LINELEN];
  1158.  
  1159.     usflush(cb->s);
  1160.     for(;;){
  1161.     /* Get line */
  1162.         if(recvline(cb->s,line,LINELEN) == -1){
  1163.             rval = -1;
  1164.             break;
  1165.         }
  1166.         rip(line);      /* Remove cr/lf */
  1167.         rval = atoi(line);
  1168. #ifdef  SMTPTRACE
  1169.         if(Smtptrace>1)
  1170.             printf(smtp_recv,line);/* Display to user */
  1171. #endif
  1172.         if(rval >= 500) {   /* Save permanent error replies */
  1173.             char tmp[LINELEN];
  1174.             if(cb->errlog == NULLLIST) {
  1175.                 sprintf(tmp,"While talking to %s:",
  1176.                 cb->destname);
  1177.                 logerr(cb,tmp);
  1178.             }
  1179.             if(cb->buf[0] != '\0') { /* Save offending command */
  1180.                 rip(cb->buf);
  1181.                 sprintf(tmp,">>> %s",cb->buf);
  1182.                 logerr(cb,tmp);
  1183.                 cb->buf[0] = '\0';
  1184.             }
  1185.             sprintf(tmp,"<<< %s",line);
  1186.             logerr(cb,tmp);     /* save the error reply */
  1187.         }
  1188.         /* Messages with dashes are continued */
  1189.         if(line[3] != '-' && rval >= mincode)
  1190.             break;
  1191.     }
  1192.     return rval;
  1193. }
  1194.