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

TCP/IP协议栈

开发平台:

Visual C++

  1. /* SMTP Server state machine - see RFC 821
  2.  *  enhanced 4/88 Dave Trulli nn2z
  3.  */
  4. #include <stdio.h>
  5. #include <time.h>
  6. #ifdef UNIX
  7. #include <sys/types.h>
  8. #endif
  9. #if defined(__STDC__) || defined(__TURBOC__)
  10. #include <stdarg.h>
  11. #endif
  12. #include <ctype.h>
  13. #include <setjmp.h>
  14. #include "global.h"
  15. #include "mbuf.h"
  16. #include "cmdparse.h"
  17. #include "socket.h"
  18. #include "iface.h"
  19. #include "proc.h"
  20. #include "smtp.h"
  21. #include "commands.h"
  22. #include "dirutil.h"
  23. #include "mailbox.h"
  24. #include "bm.h"
  25. #include "domain.h"
  26. char *Days[7] = {  "Sun","Mon","Tue","Wed","Thu","Fri","Sat" };
  27. char *Months[12] = { "Jan","Feb","Mar","Apr","May","Jun",
  28. "Jul","Aug","Sep","Oct","Nov","Dec" };
  29. static struct list *expandalias(struct list **head,char *user);
  30. static int  getmsgtxt(struct smtpsv *mp);
  31. static struct smtpsv *mail_create(void);
  32. static void mail_clean(struct smtpsv *mp);
  33. static int mailit(FILE *data,char *from,struct list *tolist);
  34. static int router_queue(FILE *data,char *from,struct list *to);
  35. static void smtplog(char *fmt,...);
  36. static void smtpserv(int s,void *unused,void *p);
  37. static int mailuser(FILE *data,char *from,char *to);
  38. /* Command table */
  39. static char *commands[] = {
  40. "helo",
  41. "noop",
  42. "mail from:",
  43. "quit",
  44. "rcpt to:",
  45. "help",
  46. "data",
  47. "rset",
  48. "expn",
  49. NULL
  50. };
  51. enum smtp_cmd {
  52. HELO_CMD,
  53. NOOP_CMD,
  54. MAIL_CMD,
  55. QUIT_CMD,
  56. RCPT_CMD,
  57. HELP_CMD,
  58. DATA_CMD,
  59. RSET_CMD,
  60. EXPN_CMD
  61. };
  62. /* Reply messages */
  63. static char Help[] = "214-Commands:n214-HELO NOOP MAIL QUIT RCPT HELP DATA RSET EXPNn214 Endn";
  64. static char Banner[] = "220 %s SMTP readyn";
  65. static char Closing[] = "221 Closingn";
  66. static char Ok[] = "250 Okn";
  67. static char Reset[] = "250 Reset staten";
  68. static char Sent[] = "250 Sentn";
  69. static char Ourname[] = "250 %s, Share and Enjoy!n";
  70. static char Enter[] = "354 Enter mail, end with .n";
  71. static char Ioerr[] = "452 Temp file write errorn";
  72. static char Badcmd[] = "500 Command unrecognizedn";
  73. static char Lowmem[] = "421 System overloaded, try again latern";
  74. static char Syntax[] = "501 Syntax errorn";
  75. static char Needrcpt[] = "503 Need RCPT (recipient)n";
  76. static char Unknown[] = "550 <%s> address unknownn";
  77. static char Noalias[] = "550 No alias for <%s>n";
  78. static int Ssmtp = -1; /* prototype socket for service */
  79. /* Start up SMTP receiver service */
  80. int
  81. smtp1(argc,argv,p)
  82. int argc;
  83. char *argv[];
  84. void *p;
  85. {
  86. struct sockaddr_in lsocket;
  87. int s;
  88. FILE *network;
  89. if(Ssmtp != -1){
  90. return 0;
  91. }
  92. ksignal(Curproc,0); /* Don't keep the parser waiting */
  93. chname(Curproc,"SMTP listener");
  94. lsocket.sin_family = AF_INET;
  95. lsocket.sin_addr.s_addr = INADDR_ANY;
  96. if(argc < 2)
  97. lsocket.sin_port = IPPORT_SMTP;
  98. else
  99. lsocket.sin_port = atoi(argv[1]);
  100. Ssmtp = socket(AF_INET,SOCK_STREAM,0);
  101. bind(Ssmtp,(struct sockaddr *)&lsocket,sizeof(lsocket));
  102. listen(Ssmtp,1);
  103. for(;;){
  104. if((s = accept(Ssmtp,NULL,(int *)NULL)) == -1)
  105. break; /* Service is shutting down */
  106. network = fdopen(s,"r+t");
  107. if(availmem() != 0){
  108. fprintf(network,Lowmem);
  109. fclose(network);
  110. } else {
  111. /* Spawn a server */
  112. newproc("SMTP server",2048,smtpserv,s,(void *)network,NULL,0);
  113. }
  114. }
  115. return 0;
  116. }
  117. /* Shutdown SMTP service (existing connections are allowed to finish) */
  118. int
  119. smtp0(argc,argv,p)
  120. int argc;
  121. char *argv[];
  122. void *p;
  123. {
  124. close_s(Ssmtp);
  125. Ssmtp = -1;
  126. return 0;
  127. }
  128. static void
  129. smtpserv(s,n,p)
  130. int s;
  131. void *n;
  132. void *p;
  133. {
  134. struct smtpsv *mp;
  135. char **cmdp,buf[LINELEN],*arg,*cp,*cmd,*newaddr;
  136. struct list *ap,*list;
  137. int cnt;
  138. char address_type;
  139. FILE *network;
  140. network = (FILE *)n;
  141. sockowner(fileno(network),Curproc); /* We own it now */
  142. logmsg(fileno(network),"open SMTP");
  143. if((mp = mail_create()) == NULL){
  144. printf(Nospace);
  145. logmsg(fileno(network),"close SMTP - no space");
  146. fclose(network);
  147. return;
  148. }
  149. mp->network = network;
  150. (void) fprintf(network,Banner,Hostname);
  151. loop: if (fgets(buf,sizeof(buf),network) == NULL) {
  152. /* He closed on us */
  153. goto quit;
  154. }
  155. cnt = strlen(buf);
  156. if(cnt < 4){
  157. /* Can't be a legal command */
  158. fprintf(network,Badcmd);
  159. goto loop;
  160. }
  161. rip(buf);
  162. cmd = buf;
  163. /* Translate entire buffer to lower case */
  164. for(cp = cmd;*cp != '';cp++)
  165. *cp = tolower(*cp);
  166. /* Find command in table; if not present, return syntax error */
  167. for(cmdp = commands;*cmdp != NULL;cmdp++)
  168. if(strncmp(*cmdp,cmd,strlen(*cmdp)) == 0)
  169. break;
  170. if(*cmdp == NULL){
  171. (void) fprintf(network,Badcmd);
  172. goto loop;
  173. }
  174. arg = &cmd[strlen(*cmdp)];
  175. /* Skip spaces after command */
  176. while(*arg == ' ')
  177. arg++;
  178. /* Execute specific command */
  179. switch(cmdp-commands) {
  180. case HELO_CMD:
  181. free(mp->system);
  182. mp->system = strdup(arg);
  183. (void) fprintf(network,Ourname,Hostname);
  184. break;
  185. case NOOP_CMD:
  186. (void) fprintf(network,Ok);
  187. break;
  188. case MAIL_CMD:
  189. if((cp = getname(arg)) == NULL){
  190. (void) fprintf(network,Syntax);
  191. break;
  192. }
  193. free(mp->from);
  194. mp->from = strdup(cp);
  195. (void) fprintf(network,Ok);
  196. break;
  197. case QUIT_CMD:
  198. (void) fprintf(network,Closing);
  199. goto quit;
  200. case RCPT_CMD: /* Specify recipient */
  201. if((cp = getname(arg)) == NULL){
  202. (void) fprintf(network,Syntax);
  203. break;
  204. }
  205. /* rewrite address if possible */
  206. if((newaddr = rewrite_address(cp)) != NULL) {
  207. strcpy(buf,newaddr);
  208. cp = buf;
  209. free(newaddr);
  210. }
  211. /* check if address is ok */
  212. if ((address_type = validate_address(cp)) == BADADDR) {
  213. (void) fprintf(network,Unknown,cp);
  214. break;
  215. }
  216. /* if a local address check for an alias */
  217. if (address_type == LOCAL)
  218. expandalias(&mp->to, cp);
  219. else
  220. /* a remote address is added to the list */
  221. addlist(&mp->to, cp, address_type);
  222. (void) fprintf(network,Ok);
  223. break;
  224. case HELP_CMD:
  225. (void) fprintf(network,Help);
  226. break;
  227. case DATA_CMD:
  228. if(mp->to == NULL)
  229. (void) fprintf(network,Needrcpt);
  230. else if ((mp->data = tmpfile()) == NULL)
  231. (void) fprintf(network,Ioerr);
  232.  else
  233. getmsgtxt(mp);
  234. break;
  235. case RSET_CMD:
  236. del_list(mp->to);
  237. mp->to = NULL;
  238. (void) fprintf(network,Reset);
  239. break;
  240. case EXPN_CMD:
  241. if (*arg == '') {
  242. (void) fprintf(network,Syntax);
  243. break;
  244. }
  245. list = NULL;
  246. /* rewrite address if possible */
  247. if((newaddr = rewrite_address(arg)) != NULL)
  248. if(strcmp(newaddr,arg) == 0) {
  249. free(newaddr);
  250. newaddr = NULL;
  251. }
  252. else {
  253. strcpy(buf,newaddr);
  254. arg = buf;
  255. }
  256. list = NULL;
  257. expandalias(&list,arg);
  258. if (strcmp(list->val,arg) == 0 && list->next == NULL)
  259. if(newaddr == NULL) {
  260. (void) fprintf(network,Noalias,arg);
  261. del_list(list);
  262. break;
  263. }
  264. ap = list;
  265. while (ap->next != NULL) {
  266. (void) fprintf(network,"250-%sn",ap->val);
  267. ap = ap->next;
  268. }
  269. fprintf(network,"250 %sn",ap->val);
  270. del_list(list);
  271. free(newaddr);
  272. break;
  273. }
  274. goto loop;
  275. quit:
  276. logmsg(fileno(network),"close SMTP");
  277. fclose(network);
  278. mail_clean(mp);
  279. smtptick(0L); /* start SMTP daemon immediately */
  280. }
  281. /* read the message text */
  282. static int
  283. getmsgtxt(mp)
  284. struct smtpsv *mp;
  285. {
  286. char buf[LINELEN];
  287. register char *p = buf;
  288. long t;
  289. FILE *network;
  290. FILE *data;
  291. char *cp;
  292. network = mp->network;
  293. data = mp->data;
  294. /* Add timestamp; ptime adds newline */
  295. time(&t);
  296. fprintf(data,"Received: ");
  297. if(mp->system != NULL)
  298. fprintf(data,"from %s ",mp->system);
  299. fprintf(data,"by %s with SMTPntid AA%ld ; %s",
  300. Hostname, get_msgid(), ptime(&t));
  301. if(ferror(data)){
  302. (void) fprintf(network,Ioerr);
  303. return 1;
  304. } else {
  305. (void) fprintf(network,Enter);
  306. }
  307. while(1) {
  308. if(fgets(p,sizeof(buf),network) == NULL){
  309. return 1;
  310. }
  311. rip(p);
  312. /* check for end of message ie a . or escaped .. */
  313. if (*p == '.') {
  314. if (*++p == '') {
  315. /* Also sends appropriate response */
  316. if (mailit(data,mp->from,mp->to) != 0)
  317. (void) fprintf(network,Ioerr);
  318. else
  319. (void) fprintf(network,Sent);
  320. fclose(data);
  321. data = NULL;
  322. del_list(mp->to);
  323. mp->to = NULL;
  324. return 0;
  325. } else if (!(*p == '.' && *(p+1) == ''))
  326. p--;
  327. }
  328. #ifdef MSDOS
  329. while((cp = strchr(p,CTLZ)) != NULL)
  330. *cp = 'n';
  331. #endif
  332. /* for UNIX mail compatiblity */
  333. if (strncmp(p,"From ",5) == 0)
  334. (void) putc('>',data);
  335. /* Append to data file */
  336. if(fprintf(data,"%sn",p) < 0) {
  337. (void) fprintf(network,Ioerr);
  338. return 1;
  339. }
  340. }
  341. return 0;
  342. }
  343. /* Create control block, initialize */
  344. static struct smtpsv *
  345. mail_create()
  346. {
  347. register struct smtpsv *mp;
  348. mp = (struct smtpsv *)callocw(1,sizeof(struct smtpsv));
  349. mp->from = strdup(""); /* Default to null From address */
  350. return mp;
  351. }
  352. /* Free resources, delete control block */
  353. static void
  354. mail_clean(mp)
  355. register struct smtpsv *mp;
  356. {
  357. if (mp == NULL)
  358. return;
  359. free(mp->system);
  360. free(mp->from);
  361. if(mp->data != NULL)
  362. fclose(mp->data);
  363. del_list(mp->to);
  364. free(mp);
  365. }
  366. /* Given a string of the form <user@host>, extract the part inside the
  367.  * brackets and return a pointer to it.
  368.  */
  369. char *
  370. getname(cp)
  371. register char *cp;
  372. {
  373. register char *cp1;
  374. if ((cp = strchr(cp,'<')) == NULL)
  375. return NULL;
  376. cp++; /* cp -> first char of name */
  377. if ((cp1 = strchr(cp,'>')) == NULL)
  378. return NULL;
  379. *cp1 = '';
  380. return cp;
  381. }
  382. /* General mailit function. It takes a list of addresses which have already
  383. ** been verified and expanded for aliases. Base on the current mode the message
  384. ** is place in an mbox, the outbound smtp queue or the rqueue interface
  385. */
  386. static int
  387. mailit(data,from,tolist)
  388. FILE *data;
  389. char *from;
  390. struct list *tolist;
  391. {
  392. struct list *ap, *dlist = NULL;
  393. register FILE *fp;
  394. char mailbox[50], *cp, *host, *qhost;
  395. int c, fail = 0;
  396. time_t t;
  397. if ((Smtpmode & QUEUE) != 0)
  398. return(router_queue(data,from,tolist));
  399. do {
  400. qhost = NULL;
  401. for(ap = tolist;ap != NULL;ap = ap->next)
  402. if (ap->type == DOMAIN) {
  403. if ((host = strrchr(ap->val,'@')) != NULL)
  404. host++;
  405. else
  406. host = Hostname;
  407. if(qhost == NULL)
  408.       qhost = host;
  409. if(stricmp(qhost,host) == 0) {
  410. ap->type = BADADDR;
  411. addlist(&dlist,ap->val,0);
  412. }
  413. }
  414. if(qhost != NULL) {
  415. rewind(data);
  416. queuejob(data,qhost,dlist,from);
  417. del_list(dlist);
  418. dlist = NULL;
  419. }
  420. } while(qhost != NULL);
  421. for(ap = tolist;ap != NULL;ap = ap->next) {
  422. if(ap->type != LOCAL) {
  423. ap->type = DOMAIN;
  424. continue;
  425. }
  426. rewind(data);
  427. /* strip off host name of LOCAL addresses */
  428. if ((cp = strchr(ap->val,'@')) != NULL)
  429. *cp = '';
  430. /* truncate long user names */
  431. if (strlen(ap->val) > MBOXLEN)
  432. ap->val[MBOXLEN] = '';
  433. /* if mail file is busy save it in our smtp queue
  434.  * and let the smtp daemon try later.
  435.  */
  436. if (mlock(Mailspool,ap->val)) {
  437. addlist(&dlist,ap->val,0);
  438. fail = queuejob(data,Hostname,dlist,from);
  439. del_list(dlist);
  440. dlist = NULL;
  441. }
  442. else {
  443. char buf[LINELEN];
  444. int tocnt = 0;
  445. sprintf(mailbox,"%s/%s.txt",Mailspool,ap->val);
  446. #ifndef AMIGA
  447. if((fp = fopen(mailbox,APPEND_TEXT)) != NULL) {
  448. #else
  449. if((fp = fopen(mailbox,"r+")) != NULL) {
  450. (void) fseek(fp, 0L, 2);
  451. #endif
  452. time(&t);
  453. fprintf(fp,"From %s %s",from,ctime(&t));
  454. host = NULL;
  455. while(fgets(buf,sizeof(buf),data) != NULL){
  456. if(buf[0] == 'n'){
  457. if(tocnt == 0)
  458. fprintf(fp,"%s%sn",
  459. Hdrs[APPARTO],
  460. ap->val);
  461. fputc('n',fp);
  462. break;
  463. }
  464. fputs(buf,fp);
  465. rip(buf);
  466. switch(htype(buf)){
  467. case TO:
  468. case CC:
  469. ++tocnt;
  470. break;
  471. case RRECEIPT:
  472. if((cp = getaddress(buf,0))
  473.    != NULL){
  474. free(host);
  475. host = strdup(cp);
  476. }
  477. break;
  478. }
  479. }
  480. while((c = fread(buf,1,sizeof(buf),data)) > 0)
  481. if(fwrite(buf,1,c,fp) != c)
  482. break;
  483. if(ferror(fp))
  484. fail = 1;
  485. else
  486. fprintf(fp,"n");
  487. /* Leave a blank line between msgs */
  488. fclose(fp);
  489. printf("New mail arrived for %sn",ap->val);
  490. if(host != NULL){
  491. rewind(data); /* Send return receipt */
  492. mdaemon(data,host,NULL,0);
  493. free(host);
  494. }
  495. } else 
  496. fail = 1;
  497. (void) rmlock(Mailspool,ap->val);
  498. if (fail)
  499. break;
  500. smtplog("deliver: To: %s From: %s",ap->val,from);
  501. }
  502. }
  503. return fail;
  504. }
  505. /* Return Date/Time in Arpanet format in passed string */
  506. char *
  507. ptime(t)
  508. long *t;
  509. {
  510. /* Print out the time and date field as
  511.  * "DAY day MONTH year hh:mm:ss ZONE"
  512.  */
  513. register struct tm *ltm;
  514. static char tz[4];
  515. static char str[40];
  516. char *p, *getenv();
  517. /* Read the system time */
  518. ltm = localtime(t);
  519. if (*tz == '')
  520. if ((p = getenv("TZ")) == NULL)
  521. strcpy(tz,"UTC");
  522. else
  523. strncpy(tz,p,3);
  524. /* rfc 822 format */
  525. sprintf(str,"%s, %.2d %s %02d %02d:%02d:%02d %.3sn",
  526. Days[ltm->tm_wday],
  527. ltm->tm_mday,
  528. Months[ltm->tm_mon],
  529. ltm->tm_year,
  530. ltm->tm_hour,
  531. ltm->tm_min,
  532. ltm->tm_sec,
  533. tz);
  534. return(str);
  535. }
  536. long 
  537. get_msgid()
  538. {
  539. char sfilename[LINELEN];
  540. char s[20];
  541. register long sequence = 0;
  542. FILE *sfile;
  543. sprintf(sfilename,"%s/sequence.seq",Mailqdir);
  544. sfile = fopen(sfilename,READ_TEXT);
  545. /* if sequence file exists, get the value, otherwise set it */
  546. if (sfile != NULL) {
  547. (void) fgets(s,sizeof(s),sfile);
  548. sequence = atol(s);
  549. /* Keep it in range of and 8 digit number to use for dos name prefix. */
  550. if (sequence < 0L || sequence > 99999999L )
  551. sequence = 0;
  552. fclose(sfile);
  553. }
  554. /* increment sequence number, and write to sequence file */
  555. sfile = fopen(sfilename,WRITE_TEXT);
  556. fprintf(sfile,"%ld",++sequence);
  557. fclose(sfile);
  558. return sequence;
  559. }
  560. #ifdef MSDOS
  561. /* Illegal characters in a DOS filename */
  562. static char baddoschars[] = ""[]:|<>+=;,";
  563. #endif
  564. /* test if mail address is valid */
  565. int
  566. validate_address(s)
  567. char *s;
  568. {
  569. char *cp;
  570. int32 addr;
  571. /* if address has @ in it the check dest address */
  572. if ((cp = strrchr(s,'@')) != NULL) {
  573. cp++;
  574. /* 1st check if its our hostname
  575. * if not then check the hosts file and see
  576. * if we can resolve ther address to a know site
  577. * or one of our aliases
  578. */
  579. if (strcmp(cp,Hostname) != 0) {
  580. if ((addr = mailroute(cp)) == 0
  581. && (Smtpmode & QUEUE) == 0)
  582. return BADADDR;
  583. if (ismyaddr(addr) == NULL)
  584. return DOMAIN;
  585. }
  586. /* on a local address remove the host name part */
  587. *--cp = '';
  588. }
  589. /* if using an external router leave address alone */
  590. if ((Smtpmode & QUEUE) != 0)
  591. return LOCAL;
  592. /* check for the user%host hack */
  593. if ((cp = strrchr(s,'%')) != NULL) {
  594. *cp = '@';
  595. cp++;
  596. /* reroute based on host name following the % seperator */
  597. if (mailroute(cp) == 0)
  598. return BADADDR;
  599. else
  600. return DOMAIN;
  601. }
  602. #ifdef MSDOS /* dos file name checks */
  603. /* Check for characters illegal in MS-DOS file names */
  604. for(cp = baddoschars;*cp != '';cp++){
  605. if(strchr(s,*cp) != NULL)
  606. return BADADDR;
  607. }
  608. #endif
  609. return LOCAL;
  610. }
  611. /* place a mail job in the outbound queue */
  612. int
  613. queuejob(dfile,host,to,from)
  614. FILE *dfile;
  615. char *host;
  616. struct list *to;
  617. char *from;
  618. {
  619. FILE *fp;
  620. struct list *ap;
  621. char tmpstring[50], prefix[9], buf[LINELEN];
  622. register int cnt;
  623. sprintf(prefix,"%ld",get_msgid());
  624. mlock(Mailqdir,prefix);
  625. sprintf(tmpstring,"%s/%s.txt",Mailqdir,prefix);
  626. if((fp = fopen(tmpstring,WRITE_TEXT)) == NULL) {
  627. (void) rmlock(Mailqdir,prefix);
  628. return 1;
  629. }
  630. while((cnt = fread(buf, 1, LINELEN, dfile)) > 0)
  631. if(fwrite(buf, 1, cnt, fp) != cnt)
  632. break;
  633. if(ferror(fp)){
  634. fclose(fp);
  635. (void) rmlock(Mailqdir,prefix);
  636. return 1;
  637. }
  638. fclose(fp);
  639. sprintf(tmpstring,"%s/%s.wrk",Mailqdir,prefix);
  640. if((fp = fopen(tmpstring,WRITE_TEXT)) == NULL) {
  641. (void) rmlock(Mailqdir,prefix);
  642. return 1;
  643. }
  644. fprintf(fp,"%sn%sn",host,from);
  645. for(ap = to; ap != NULL; ap = ap->next) {
  646. fprintf(fp,"%sn",ap->val);
  647. smtplog("queue job %s To: %s From: %s",prefix,ap->val,from);
  648. }
  649. fclose(fp);
  650. (void) rmlock(Mailqdir,prefix);
  651. return 0;
  652. }
  653. /* Deliver mail to the appropriate mail boxes */
  654. static int
  655. router_queue(data,from,to)
  656. FILE *data;
  657. char *from;
  658. struct list *to;
  659. {
  660. int c;
  661. register struct list *ap;
  662. FILE *fp;
  663. char tmpstring[50];
  664. char prefix[9];
  665. sprintf(prefix,"%ld",get_msgid());
  666. mlock(Routeqdir,prefix);
  667. sprintf(tmpstring,"%s/%s.txt",Routeqdir,prefix);
  668. if((fp = fopen(tmpstring,WRITE_TEXT)) == NULL) {
  669. (void) rmlock(Routeqdir,prefix);
  670. return 1;
  671. }
  672. rewind(data);
  673. while((c = getc(data)) != EOF)
  674. if(putc(c,fp) == EOF)
  675. break;
  676. if(ferror(fp)){
  677. fclose(fp);
  678. (void) rmlock(Routeqdir,prefix);
  679. return 1;
  680. }
  681. fclose(fp);
  682. sprintf(tmpstring,"%s/%s.wrk",Routeqdir,prefix);
  683. if((fp = fopen(tmpstring,WRITE_TEXT)) == NULL) {
  684. (void) rmlock(Routeqdir,prefix);
  685. return 1;
  686. }
  687. fprintf(fp,"From: %sn",from);
  688. for(ap = to;ap != NULL;ap = ap->next) {
  689. fprintf(fp,"To: %sn",ap->val);
  690. }
  691. fclose(fp);
  692. (void) rmlock(Routeqdir,prefix);
  693. smtplog("rqueue job %s From: %s",prefix,from);
  694. return 0;
  695. }
  696. /* add an element to the front of the list pointed to by head 
  697. ** return NULL if out of memory.
  698. */
  699. struct list *
  700. addlist(head,val,type)
  701. struct list **head;
  702. char *val;
  703. int type;
  704. {
  705. register struct list *tp;
  706. tp = (struct list *)callocw(1,sizeof(struct list));
  707. tp->next = NULL;
  708. /* allocate storage for the char string */
  709. tp->val = strdup(val);
  710. tp->type = type;
  711. /* add entry to front of existing list */
  712. if (*head == NULL)
  713. *head = tp;
  714. else {
  715. tp->next = *head;
  716. *head = tp;
  717. }
  718. return tp;
  719. }
  720. #define SKIPWORD(X) while(*X && *X!=' ' && *X!='t' && *X!='n' && *X!= ',') X++;
  721. #define SKIPSPACE(X) while(*X ==' ' || *X =='t' || *X =='n' || *X == ',') X++;
  722. /* check for and alias and expand alias into a address list */
  723. static struct list *
  724. expandalias(head, user)
  725. struct list **head;
  726. char *user;
  727. {
  728. FILE *fp;
  729. register char *s,*p;
  730. struct rr *rrp, *rrlp;
  731. int inalias = 0;
  732. struct list *tp;
  733. char buf[LINELEN];
  734. /* no alias file found */
  735. if ((fp = fopen(Alias, READ_TEXT)) == NULL) {
  736. /* Try MB, MG or MR domain name records */
  737. rrlp = rrp = resolve_mailb(user);
  738. while(rrp != NULL){
  739. if(rrp->rdlength > 0){
  740. /* remove the trailing dot */
  741. rrp->rdata.name[rrp->rdlength-1] = '';
  742. /* replace first dot with @ if there is no @ */
  743. if(strchr(rrp->rdata.name,'@') == NULL
  744.    && (p = strchr(rrp->rdata.name,'.')) !=
  745.    NULL)
  746. *p = '@';
  747. if(strchr(rrp->rdata.name,'@') != NULL)
  748. tp = addlist(head,rrp->rdata.name,
  749.      DOMAIN);
  750. else
  751. tp = addlist(head,rrp->rdata.name,
  752.      LOCAL);
  753. ++inalias;
  754. }
  755. rrp = rrp->next;
  756. }
  757. free_rr(rrlp);
  758. if(inalias)
  759. return tp;
  760. else
  761. return addlist(head, user, LOCAL);
  762. }
  763. while (fgets(buf,LINELEN,fp) != NULL) {
  764. p = buf;
  765. if ( *p == '#' || *p == '')
  766. continue;
  767. rip(p);
  768. /* if not in an matching entry skip continuation lines */
  769. if (!inalias && isspace(*p))
  770. continue;
  771. /* when processing an active alias check for a continuation */
  772. if (inalias) {
  773. if (!isspace(*p)) 
  774. break; /* done */
  775. } else {
  776. s = p;
  777. SKIPWORD(p);
  778. *p++ = ''; /* end the alias name */
  779. if (strcmp(s,user) != 0)
  780. continue; /* no match go on */
  781. inalias = 1;
  782. }
  783. /* process the recipients on the alias line */
  784. SKIPSPACE(p);
  785. while(*p != '' && *p != '#') {
  786. s = p;
  787. SKIPWORD(p);
  788. if (*p != '')
  789. *p++ = '';
  790. /* find hostname */
  791. if (strchr(s,'@') != NULL)
  792. tp = addlist(head,s,DOMAIN);
  793. else
  794. tp = addlist(head,s,LOCAL);
  795. SKIPSPACE(p);
  796. }
  797. }
  798. (void) fclose(fp);
  799. if (inalias) /* found and processed and alias. */
  800. return tp;
  801. /* no alias found treat as a local address */
  802. return addlist(head, user, LOCAL);
  803. }
  804. static void
  805. smtplog(char *fmt, ...)
  806. {
  807. va_list ap;
  808. char *cp;
  809. long t;
  810. FILE *fp;
  811. if ((fp = fopen(Maillog,APPEND_TEXT)) == NULL)
  812. return;
  813. time(&t);
  814. cp = ctime(&t);
  815. rip(cp);
  816. fprintf(fp,"%s ",cp);
  817. va_start(ap,fmt);
  818. vfprintf(fp,fmt,ap);
  819. va_end(ap);
  820. fprintf(fp,"n");
  821. fclose(fp);
  822. }
  823. /* send mail to a single user. Can be called from the ax24 mailbox or
  824. ** from the return mail function in the smtp client 
  825. */
  826. static int
  827. mailuser(data,from,to)
  828. FILE *data;
  829. char *from;
  830. char *to;
  831. {
  832. int address_type, ret;
  833. struct list *tolist = NULL;
  834. /* check if address is ok */
  835. if ((address_type = validate_address(to)) == BADADDR) {
  836. return 1;
  837. }
  838. /* if a local address check for an alias */
  839. if (address_type == LOCAL)
  840. expandalias(&tolist, to);
  841. else
  842. /* a remote address is added to the list */
  843. addlist(&tolist, to, address_type);
  844. ret = mailit(data,from,tolist);
  845. del_list(tolist);
  846. return ret;
  847. }
  848. /* Mailer daemon return mail mechanism */
  849. int
  850. mdaemon(data,to,lp,bounce)
  851. FILE *data; /* pointer to rewound data file */
  852. char *to; /* Overridden by Errors-To: line if bounce is true */
  853. struct list *lp; /* error log for failed mail */
  854. int bounce; /* True for failed mail, otherwise return receipt */
  855. {
  856. time_t t;
  857. FILE *tfile;
  858. char buf[LINELEN], *cp, *newto = NULL;
  859. int cnt;
  860. if(to == NULL || (to != NULL && *to == '') || bounce){
  861. while(fgets(buf,sizeof(buf),data) != NULL) {
  862. if(buf[0] == 'n')
  863. break;
  864. /* Look for Errors-To: */
  865. if(htype(buf) == ERRORSTO &&
  866.    (cp = getaddress(buf,0)) != NULL){
  867. free(newto);
  868. newto = strdup(cp);
  869. break;
  870. }
  871. }
  872. if(newto == NULL && ((to != NULL && *to == '') ||
  873.    to == NULL))
  874. return -1;
  875. rewind(data);
  876. }
  877. if((tfile = tmpfile()) == NULL)
  878. return -1;
  879. time(&t);
  880. fprintf(tfile,"%s%s",Hdrs[DATE],ptime(&t));
  881. fprintf(tfile,"%s<%ld@%s>n",Hdrs[MSGID],get_msgid(),Hostname);
  882. fprintf(tfile,"%sMAILER-DAEMON@%s (Mail Delivery Subsystem)n",
  883. Hdrs[FROM],Hostname);
  884. fprintf(tfile,"%s%sn",Hdrs[TO],newto != NULL ? newto : to);
  885. fprintf(tfile,"%s%snn",Hdrs[SUBJECT],
  886. bounce ? "Failed mail" : "Return receipt");
  887. if(bounce) {
  888. fprintf(tfile,"  ===== transcript follows =====nn");
  889. for (; lp != NULL; lp = lp->next)
  890. fprintf(tfile,"%sn",lp->val);
  891. fprintf(tfile,"n");
  892. }
  893. fprintf(tfile,"  ===== %s follows ====n",
  894. bounce ? "Unsent message" : "Message header");
  895. while(fgets(buf,sizeof(buf),data) != NULL){
  896. if(buf[0] == 'n')
  897. break;
  898. fputs(buf,tfile);
  899. }
  900. if(bounce){
  901. fputc('n',tfile);
  902. while((cnt = fread(buf,1,sizeof(buf),data)) > 0)
  903. fwrite(buf,1,cnt,tfile);
  904. }
  905. fseek(tfile,0L,0);
  906. /* A null From<> so no looping replys to MAIL-DAEMONS */
  907. (void) mailuser(tfile,"",newto != NULL ? newto : to);
  908. fclose(tfile);
  909. free(newto);
  910. return 0;
  911. }