smtpcli.c
上传用户:hepax88
上传日期:2007-01-03
资源大小:1101k
文件大小:22k
源码类别:

TCP/IP协议栈

开发平台:

Visual C++

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