home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-06-06 | 27.1 KB | 1,194 lines |
- /*
- * Client routines for Simple Mail Transfer Protocol ala RFC821
- * A.D. Barksdale Garbee II, aka Bdale, N3EUA
- * Copyright 1986 Bdale Garbee, All Rights Reserved.
- * Permission granted for non-commercial copying and use, provided
- * this notice is retained.
- * Modified 14 June 1987 by P. Karn for symbolic target addresses,
- * also rebuilt locking mechanism
- * Limit on max simultaneous sessions, reuse of connections - 12/87 NN2Z
- * Added return of mail to sender as well as batching of commands 1/88 nn2z
- */
- #include <ctype.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <stdarg.h>
- #include <time.h>
- #include "global.h"
- #include "netuser.h"
- #include "mbuf.h"
- #include "domain.h"
- #include "timer.h"
- #include "tcp.h"
- #include "smtp.h"
- #include "trace.h"
- #include "cmdparse.h"
- #include "misc.h"
- #include "arc.h"
- #include "resuser.h"
- #include "Terminal.h"
- #include "vterm.h"
-
- static int dosep(int, char **);
- static int dosmtpmaxcli(int, char **);
- static int setsmtpmode(int, char **);
- static int dogateway(int, char **);
- static int dosmtptrace(int, char **);
- static int dotimer(int, char **);
- static void abort_trans(struct smtp_cb *);
- static void quit(struct smtp_cb *);
- static void smtp_rec(struct tcb *, int);
- static void smtp_cts(struct tcb *, int);
- static int sendwindow(struct smtp_cb *, struct mbuf *, int);
- static void smtp_state(struct tcb *, char, char);
- static void sendit(struct smtp_cb *, char *, ...);
- static void del_session(struct smtp_cb *);
- static void retmail(struct smtp_cb *);
- static struct smtp_cb *lookup(int32);
- static struct smtp_cb *newcb(void);
- static void execjobs(void);
- static int nextjob(struct smtp_cb *);
- static void logerr(struct smtp_cb *);
- static int setsmtplate(int argc, char **argv);
-
- int inourdomain(char *host);
-
- static int smtp_delay_close = 0; /* off */
-
- extern int lport; /* local port placeholder */
- static struct timer smtpcli_t;
- int32 gateway;
-
- #ifdef SMTPTRACE
- static int smtptrace = 0; /* used for trace level */
- #endif
-
- int smtpmaxcli = MAXSESSIONS; /* the max client connections allowed */
- int smtpsessions = 0; /* number of client connections
- currently open */
- int smtpmode = 0;
-
- int smtp_sep = sep_UNIX;
-
- static Terminal *smtp_win = NULL;
-
- static struct smtp_cb *cli_session[MAXSESSIONS]; /* queue of client sessions */
-
- static char quitcmd[] = "QUIT\r\n";
- static char eom[] = "\r\n.\r\n";
- static char *seps[] = {"From", "Ctrl-A", "#! rnews", "#! rmail"};
-
- struct cmds smtpcmds[] = {
- "gateway", dogateway, 0, NULLCHAR, NULLCHAR,
- "mode", setsmtpmode, 0, NULLCHAR, NULLCHAR,
- "delay", setsmtplate, 0, NULLCHAR, NULLCHAR,
- "kick", smtptick, 0, NULLCHAR, NULLCHAR,
- "maxclients", dosmtpmaxcli, 0, NULLCHAR, NULLCHAR,
- "separator", dosep, 0, NULLCHAR, NULLCHAR,
- "timer", dotimer, 0, NULLCHAR, NULLCHAR,
- #ifdef SMTPTRACE
- "trace", dosmtptrace, 0, NULLCHAR, NULLCHAR,
- #endif
- NULLCHAR, NULLFP, 0,
- "subcommands: delay gateway mode kick maxclients separator timer trace",
- NULLCHAR,
- };
-
- int dosmtp(int argc, char **argv)
- {
- return subcmd(smtpcmds, argc, argv);
- }
-
- static int dosmtpmaxcli(int argc, char **argv)
- {
- int x;
- if (argc < 2)
- cwprintf(NULL, "%d\r\n",smtpmaxcli);
- else {
- x = atoi(argv[1]);
- if (x > MAXSESSIONS)
- cwprintf(NULL, "max clients must be <= %d\r\n",MAXSESSIONS);
- else
- smtpmaxcli = x;
- }
- return 0;
- }
-
- static int setsmtpmode(int argc, char **argv)
- {
- if (argc < 2)
- {
- cwprintf(NULL, "smtp mode: %s\r\n",
- (smtpmode & QUEUE) ? "queue" : "route");
- }
- else
- {
- switch(*argv[1])
- {
- case 'q':
- smtpmode |= QUEUE;
- break;
- case 'r':
- smtpmode &= ~QUEUE;
- break;
- default:
- cwprintf(NULL, "Usage: smtp mode [queue | route]\r\n");
- break;
- }
- }
- return 0;
- }
-
- static int setsmtplate(int argc, char **argv)
- {
- if (argc < 2)
- cwprintf(NULL, "smtp delay shutdown: %s\r\n", (smtp_delay_close) ? "yes" : "no");
- else
- {
- switch(*argv[1])
- {
- case 'y':
- smtp_delay_close = 1;
- break;
- case 'n':
- smtp_delay_close = 0;
- break;
- default:
- cwprintf(NULL, "Usage: smtp delay [yes | no]\r\n");
- break;
- }
- }
- return 0;
- }
-
- static int dogateway(int argc, char **argv)
- {
- int32 n;
- extern char badhost[];
-
- if(argc < 2)
- {
- cwprintf(NULL, "%s\r\n", inet_ntoa(gateway));
- }
- else if ((n = resolve(argv[1])) == 0)
- {
- cwprintf(NULL, badhost,argv[1]);
- return 1;
- }
- else
- gateway = n;
- return 0;
- }
-
- #ifdef SMTPTRACE
- static int dosmtptrace(int argc, char **argv)
- {
- if (argc < 2)
- cwprintf(NULL, "%d\r\n",smtptrace);
- else
- smtptrace = atoi(argv[1]);
- return 0;
- }
- #endif
-
- /* Set outbound spool poll interval */
- static int dotimer(int argc, char **argv)
- {
- if(argc < 2)
- {
- cwprintf(NULL, "%lu/%lu\r\n",
- (smtpcli_t.start - smtpcli_t.count)/(1000/MSPTICK),
- smtpcli_t.start/(1000/MSPTICK));
- return 0;
- }
- smtpcli_t.func = (void (*)())smtptick;/* what to call on timeout */
- smtpcli_t.arg = NULLCHAR; /* dummy value */
- smtpcli_t.start = (int32)atoi(argv[1])*(1000/MSPTICK); /* set timer duration */
- start_timer(&smtpcli_t); /* and fire it up */
- return 0;
- }
-
- /* this is the routine that gets called every so often to do outgoing mail
- processing */
- int smtptick(void)
- {
- register struct smtp_cb *cb;
- struct smtp_job *jp;
- struct list *ap;
- char tmpstring[LINELEN], wfilename[13];
- char from[LINELEN], to[LINELEN];
- int32 destaddr;
- FILE *wfile;
-
- smtp_win = Window_Open(NULL, "SMTP", term_NO_INPUT | term_DONT_DESTROY);
- vterm_visible(smtp_win->vt, 40, 8);
- vterm_setflags(smtp_win->vt, VTSW_WRAP, VTSW_WRAP);
-
- #ifdef SMTPTRACE
- if (smtptrace > 5)
- {
- cwprintf(smtp_win, "smtp daemon entered\r\n");
- }
- #endif
-
- for (filedir(mailqueue, 0, wfilename); wfilename[0] != '\0'; filedir(mailqueue, 1, wfilename))
- {
- /* lock this file from the smtp daemon */
- if (mlock(mailqdir, wfilename))
- continue;
-
- sprintf(tmpstring,"%s.work.%s",mailqdir,wfilename);
- if ((wfile = fopen(tmpstring,"r")) == NULLFILE)
- {
- /* probably too many open files */
- rmlock(mailqdir, wfilename);
- /* continue to next message. The failure
- may be temporary */
- continue;
- }
-
- fgets(tmpstring, LINELEN, wfile); /* read target host */
- rip(tmpstring);
-
- if ((destaddr = mailroute(tmpstring)) == 0)
- {
- fclose(wfile);
- cwprintf(smtp_win, "** smtp: Unknown address %s\r\n",tmpstring);
- rmlock(mailqdir, wfilename);
- continue;
- }
-
- if ((cb = lookup(destaddr)) == NULLCB)
- {
- /* there are enough processes running already */
- if (smtpsessions >= smtpmaxcli)
- {
- #ifdef SMTPTRACE
- if (smtptrace)
- {
- cwprintf(smtp_win, "smtp daemon: too many processes\r\n");
- }
- #endif
- fclose(wfile);
- rmlock(mailqdir, wfilename);
- break;
- }
- if ((cb = newcb()) == NULLCB)
- {
- fclose(wfile);
- rmlock(mailqdir, wfilename);
- break;
- }
- cb->ipdest = destaddr;
- }
- else
- {
- /* This system is already is sending mail lets not
- interfere with its send queue.*/
- if (cb->state != CLI_INIT_STATE)
- {
- fclose(wfile);
- rmlock(mailqdir, wfilename);
- continue;
- }
- }
-
- fgets(from,LINELEN,wfile); /* read from */
- rip(from);
- if ((jp = setupjob(cb, wfilename, from)) == NULLJOB)
- {
- fclose(wfile);
- rmlock(mailqdir, wfilename);
- del_session(cb);
- break;
- }
- while (fgets(to, LINELEN, wfile) != NULLCHAR)
- {
- rip(to);
- if (addlist(&jp->to, to, DOMAIN) == NULLLIST)
- {
- fclose(wfile);
- del_session(cb);
- }
- }
- fclose(wfile);
- #ifdef SMTPTRACE
- if (smtptrace > 1)
- {
- cwprintf(smtp_win, "queue job %s From: %s To:", wfilename, from);
- for (ap = jp->to; ap != NULLLIST; ap = ap->next)
- cwprintf(smtp_win, " %s",ap->val);
- cwprintf(smtp_win, "\r\n");
- }
- #endif
- }
- if (smtp_win && smtpsessions == 0)
- {
- smtp_win->Flags.flags.dont_destroy = FALSE;
- Window_Close(smtp_win);
- smtp_win = NULL;
- }
-
- /* start sending that mail */
- execjobs();
-
- /* Restart timer */
- start_timer(&smtpcli_t);
- return(0);
- }
-
- /* this is the master state machine that handles a single SMTP transaction */
- void smtp_transaction(register struct smtp_cb *cb)
- {
- register char reply;
- register struct list *tp;
- int cnt;
- struct mbuf *bp,*bpl;
- char tbuf[LINELEN];
- int rcode;
-
- #ifdef SMTPTRACE
- if (smtptrace > 5)
- cwprintf(smtp_win, "smtp_transaction() enter state=%u\r\n",cb->state);
- if (smtptrace)
- {
- cwprintf(smtp_win, "%s\r\n", cb->buf);
- }
- #endif
- /* Another line follows; ignore this one */
- if(cb->buf[0] == '0' || cb->buf[3] == '-')
- return;
-
- reply = cb->buf[0];
- rcode = atoi(cb->buf);
-
- /* if service shuting down */
- if (rcode == 421 || (rcode == 221 && smtp_delay_close))
- {
- quit(cb);
- return;
- }
-
- switch(cb->state)
- {
- case CLI_OPEN_STATE:
- if (reply != '2')
- {
- quit(cb);
- }
- else
- {
- cb->state = CLI_HELO_STATE;
- sendit(cb, "HELO %s\r\nMAIL FROM:<%s>\r\n",
- hostname, cb->jobq->from);
- }
- break;
-
- case CLI_HELO_STATE:
- if (reply != '2')
- quit(cb);
- else
- cb->state = CLI_MAIL_STATE;
- break;
-
- case CLI_MAIL_STATE:
- if (reply != '2')
- quit(cb);
- else
- {
- cb->state = CLI_RCPT_STATE;
- cb->rcpts = 0;
- bpl = NULLBUF;
- for (tp = cb->jobq->to; tp != NULLLIST; tp = tp->next)
- {
- sprintf(tbuf, "RCPT TO:<%s>\r\n", tp->val);
- bp = qdata(tbuf, strlen(tbuf));
- if (bp == NULLBUF)
- {
- free_p(bpl);
- quit(cb);
- return;
- }
- append(&bpl,bp);
- cb->rcpts++;
- #ifdef SMTPTRACE
- if (smtptrace)
- {
- cwprintf(smtp_win, ">>> %s\r\n",tbuf);
- }
- #endif
- }
- send_tcp(cb->tcb,bpl);
- }
- break;
- case CLI_RCPT_STATE:
- if (reply == '5')
- {
- logerr(cb);
- }
- else if (reply == '2')
- {
- cb->goodrcpt =1;
- }
- else
- {
- /* some kind of temporary failure */
- abort_trans(cb);
- break;
- }
- /* if more rcpts stay in this state */
- if (--cb->rcpts != 0)
- break;
-
- /* check for no good rcpt on the list */
- if (cb->goodrcpt == 0)
- {
- if (cb->errlog != NULLLIST)
- retmail(cb);
- remove(cb->wname); /* unlink workfile */
- remove(cb->tname); /* unlink text */
- newsbase_update(0);
- abort_trans(cb);
- break;
- }
- /* if this file open fails abort */
- if ((cb->tfile = fopen(cb->tname, "r")) == NULLFILE)
- abort_trans(cb);
- else
- {
- /* optimize for slow packet links by sending
- DATA cmd and the 1st window of text */
- if (cb->tcb->window <= cb->tcb->sndcnt)
- cnt = 0;
- else
- cnt = cb->tcb->window - cb->tcb->sndcnt;
- bp = qdata("DATA\r\n", 6);
- cb->cts = 1;
- cb->state = CLI_SEND_STATE;
- if (sendwindow(cb, bp, cnt) == EOF)
- cb->cts = 0;
- }
- break;
-
- case CLI_SEND_STATE:
- if (reply == '3')
- {
- cb->state = CLI_UNLK_STATE;
- }
- else
- {
- /* change cts to transmit upcall queueing more data */
- cb->cts = 0;
- quit(cb);
- }
- break;
-
- case CLI_UNLK_STATE:
- /* if a good transfer or permanent failure remove job */
- if (reply == '2' || reply == '5')
- {
- if (reply == '5')
- logerr(cb);
- /* close and unlink the textfile */
- if(cb->tfile != NULLFILE)
- {
- fclose(cb->tfile);
- cb->tfile = NULLFILE;
- }
- if (cb->errlog != NULLLIST)
- retmail(cb);
- remove(cb->tname);
- remove(cb->wname); /* unlink workfile */
- log_event(cb->tcb,"SMTP sent job %s To: %s From: %s",
- cb->jobq->jobname,cb->jobq->to->val,cb->jobq->from);
- newsbase_update(0);
- }
- if (nextjob(cb))
- {
- cb->state = CLI_MAIL_STATE;
- sendit(cb,"MAIL FROM:<%s>\r\n",cb->jobq->from);
- }
- else
- {
- /* the quit sent already in smtp_cts */
- cb->state = CLI_QUIT_STATE;
- /* ... unless delay close set */
- if (smtp_delay_close)
- sendit(cb, quitcmd);
- }
- break;
-
- case CLI_IDLE_STATE: /* used after a RSET and more mail to send */
- if (reply != '2')
- quit(cb);
- else
- {
- cb->state = CLI_MAIL_STATE;
- sendit(cb,"MAIL FROM:<%s>\r\n",cb->jobq->from);
- }
- break;
-
- case CLI_QUIT_STATE:
- break;
- }
- }
-
- /* abort the currrent job.
- If more work exists set up the next job if
- not then shut down. */
- static void abort_trans(register struct smtp_cb *cb)
- {
- if(cb->tfile != NULLFILE)
- {
- fclose(cb->tfile);
- cb->tfile = NULLFILE;
- }
- if (nextjob(cb))
- {
- sendit(cb,"RSET\r\n");
- cb->state = CLI_IDLE_STATE;
- }
- else
- quit(cb);
- }
-
- /* close down link after a failure */
- static void quit(struct smtp_cb *cb)
- {
- cb->state = CLI_QUIT_STATE;
- sendit(cb,quitcmd); /* issue a quit command */
- close_tcp(cb->tcb); /* close up connection */
- }
-
- /* smtp receiver upcall routine. fires up the state machine to parse input */
- static void smtp_rec(struct tcb *tcb, int cnt)
- {
- BOOL incomplete = FALSE;
- register struct smtp_cb *cb;
- char c;
- struct mbuf *bp;
-
- #ifdef SMTPTRACE
- if (smtptrace > 7)
- {
- cwprintf(smtp_win, "smtp_rec called\r\n");
- }
- #endif
- cb = (struct smtp_cb *) tcb->user; /* point to our struct */
- recv_tcp(tcb, &bp, cnt); /* suck up chars from low level routine */
-
- /* Assemble input line in buffer, return if incomplete */
- while(pullone(&bp, &c) == 1)
- {
- switch(c)
- {
- case '\r': /* strip cr's */
- continue;
-
- case '\n': /* line is finished, go do it! */
- cb->buf[cb->cnt] = '\0';
- smtp_transaction(cb);
- cb->cnt = 0;
- incomplete = FALSE;
- break;
-
- default: /* other chars get added to buffer */
- cb->buf[cb->cnt++] = c;
- if (cb->cnt == 1 && incomplete && c == '.')
- {
- cb->buf[cb->cnt++] = c;
- incomplete = FALSE;
- }
- if(cb->cnt > LINELEN - 2)
- {
- cb->buf[cb->cnt] = '\0';
- smtp_transaction(cb);
- cb->cnt = 0;
- incomplete = TRUE;
- }
- break;
- }
- }
- }
-
- /* smtp transmitter ready upcall routine. twiddles cts flag */
- static void smtp_cts(struct tcb *tcb, int cnt)
- {
- register struct smtp_cb *cb;
-
- #ifdef SMTPTRACE
- if (smtptrace > 7)
- {
- cwprintf(smtp_win, "smtp_cts called avail %d\r\n",cnt);
- }
- #endif
- cb = (struct smtp_cb *)tcb->user; /* point to our struct */
-
- /* don't do anything until/unless we're supposed to be sending */
- if(cb->cts == 0)
- return;
-
- if (sendwindow(cb, NULLBUF, cnt) == EOF)
- cb->cts = 0;
- }
-
- /* fill the rest of the window with data and send out the eof commands.
- It is done this way to minimize the number of packets sent. */
- static int sendwindow(register struct smtp_cb *cb, struct mbuf *ibp, int cnt)
- {
- struct mbuf *bpl;
- register struct mbuf *bp;
- char *cp;
- int c;
-
- bpl = ibp;
- if ((bp = alloc_mbuf(cnt)) == NULLBUF)
- {
- /* Hard to know what to do here */
- return EOF;
- }
- cp = bp->data;
- while(cnt > 1 && (c = getc(cb->tfile)) != EOF)
- {
- if (c == '\n')
- {
- *cp++ = '\r';
- bp->cnt++;
- cnt--;
- }
- *cp++ = c;
- bp->cnt++;
- cnt--;
-
- if (c == '\n')
- {
- if (c = getc(cb->tfile), c == '.')
- {
- *cp++ = '.';
- bp->cnt++;
- cnt--;
- }
- ungetc(c, cb->tfile);
- }
- }
- append(&bpl, bp);
- if (cnt > 1)
- { /* EOF seen */
- fclose(cb->tfile);
- cb->tfile = NULLFILE;
- /* send the end of data character. */
- if (cnt < sizeof(eom) - 1)
- {
- bp = qdata(eom, 5);
- append(&bpl,bp);
- cnt = 0; /* dont let anyone else in */
- }
- else
- {
- memcpy(&bp->data[bp->cnt], eom, sizeof(eom) - 1);
- bp->cnt += sizeof(eom) - 1;
- cnt -= sizeof(eom) - 1;
- }
- /* send the quit in this packet if last job */
- if (cb->jobq->next == NULLJOB && !smtp_delay_close)
- {
- if (cnt < sizeof(quitcmd) - 1)
- {
- bp = qdata(quitcmd,sizeof(quitcmd) - 1);
- append(&bpl,bp);
- }
- else
- {
- memcpy(&bp->data[bp->cnt],
- quitcmd,sizeof(quitcmd) - 1);
- bp->cnt += sizeof(quitcmd) - 1;
- }
- }
- send_tcp(cb->tcb, bpl);
- if (cb->jobq->next == NULLJOB)
- {
- close_tcp(cb->tcb); /* close up connection */
- }
- return EOF;
- }
- else
- {
- send_tcp(cb->tcb, bpl);
- return 0;
- }
- }
-
- /* smtp state change upcall routine. */
- static void smtp_state(register struct tcb *tcb, char old, char new)
- {
- register struct smtp_cb *cb;
- extern char *tcpstates[];
-
- #ifdef SMTPTRACE
- if (smtptrace > 7)
- {
- cwprintf(smtp_win, "smtp_state called: %s\r\n",tcpstates[new]);
- }
- #endif
- cb = (struct smtp_cb *)tcb->user;
- switch(new)
- {
- case ESTABLISHED:
- cb->state = CLI_OPEN_STATE; /* shouldn't be needed */
- break;
- case CLOSE_WAIT:
- close_tcp(tcb); /* shut things down */
- break;
- case CLOSED:
- /* if this close was not done by us ie. a RST */
- if(cb->tfile != NULLFILE)
- fclose(cb->tfile);
- if (old == CLI_OPEN_STATE && cb->ipdest != gateway && gateway != NULL)
- {
- struct socket lsocket, fsocket;
-
- del_tcp(tcb);
- fsocket.address = gateway;
- fsocket.port = SMTP_PORT;
- lsocket.address = ip_addr;
- lsocket.port = lport++;
- #ifdef SMTPTRACE
- if (smtptrace)
- {
- cwprintf(smtp_win, "SMTP: Trying Connection to %s\r\n", inet_ntoa(fsocket.address));
- }
- #endif
- cb->state = CLI_OPEN_STATE;
- cb->tcb = open_tcp(&lsocket, &fsocket, TCP_ACTIVE, tcp_window,
- (void(*)())smtp_rec, (void(*)())smtp_cts, (void(*)())smtp_state, 0, (char *)cb);
- cb->tcb->user = (char *)cb;
- }
- else
- {
- del_session(cb);
- del_tcp(tcb);
- }
- break;
- }
- }
-
- /* Send message back to server */
- static void sendit(struct smtp_cb *cb, char *fmt, ...)
- {
- va_list argptr;
- struct mbuf *bp;
- char tmpstring[256];
-
- va_start(argptr,fmt);
- vsprintf(tmpstring,fmt,argptr);
- va_end(argptr);
-
- #ifdef SMTPTRACE
- if (smtptrace) {
- cwprintf(smtp_win, ">>> %s\r\n", tmpstring);
- }
- #endif
- bp = qdata(tmpstring, strlen(tmpstring));
- send_tcp(cb->tcb, bp);
- }
-
- /* create mail lockfile */
- int mlock(char *dir, char *id)
- {
- char lockname[LINELEN];
- FILE *fp;
- /* Try to create the lock file in an atomic operation */
- sprintf(lockname,"%s.lock.%s",dir,id);
- if((fp = fopen(lockname, "w")) == NULL)
- return -1;
- fclose(fp);
- return 0;
- }
-
- /* remove mail lockfile */
- int rmlock(char *dir, char *id)
- {
- char lockname[LINELEN];
- sprintf(lockname,"%s.lock.%s",dir,id);
- return(remove(lockname));
- }
-
- /* free the message struct and data */
- static void del_session(register struct smtp_cb *cb)
- {
- register struct smtp_job *jp,*tp;
- register int i;
-
- if (cb == NULLCB)
- return;
- for (i = 0; i < MAXSESSIONS; i++)
- if (cli_session[i] == cb)
- {
- cli_session[i] = NULLCB;
- break;
- }
-
- if (cb->wname != NULLCHAR)
- free(cb->wname);
- if (cb->tname != NULLCHAR)
- free(cb->tname);
- for (jp = cb->jobq; jp != NULLJOB;jp = tp)
- {
- tp = jp->next;
- del_job(jp);
- }
- del_list(cb->errlog);
- free((char *)cb);
- smtpsessions--; /* number of connections active */
- if (smtp_win && smtpsessions == 0)
- {
- smtp_win->Flags.flags.dont_destroy = FALSE;
- Window_Close(smtp_win);
- smtp_win = NULL;
- }
- }
-
- void del_job(register struct smtp_job *jp)
- {
- if ( *jp->jobname != '\0')
- rmlock(mailqdir,jp->jobname);
- if(jp->from != NULLCHAR)
- free(jp->from);
- del_list(jp->to);
- free((char *)jp);
- }
-
- /* delete a list of list structs */
- void del_list(struct list *lp)
- {
- register struct list *tp, *tp1;
- for (tp = lp; tp != NULLLIST; tp = tp1) {
- tp1 = tp->next;
- if(tp->val != NULLCHAR)
- free(tp->val);
- free((char *)tp);
- }
- }
-
- /* return message to sender */
- static void retmail(struct smtp_cb *cb)
- {
- register struct list *lp;
- register FILE *tfile;
- register int c;
- FILE *infile;
- char *host,*to;
- time_t t;
- #ifdef SMTPTRACE
- if (smtptrace > 5) {
- cwprintf(smtp_win, "smtp job %s returned to sender\r\n",cb->wname);
- }
- #endif
- /* A null From<> so no looping replys to MAIL-DAEMONS */
- to = cb->jobq->from;
- if (*to == '\0')
- return;
- if ((host = strchr(to,'@')) == NULLCHAR)
- host = hostname;
- else
- host++;
- if ((infile = fopen(cb->tname,"r")) == NULLFILE)
- return;
- if ((tfile = tmpfile()) == NULLFILE) {
- fclose(infile);
- return;
- }
- time(&t);
- fprintf(tfile,"Date: %s",ptime(&t));
- fprintf(tfile,"Message-Id: <%ld@%s>\n",get_msgid(),hostname);
- fprintf(tfile,"From: MAILER-DAEMON@%s\n",hostname);
- fprintf(tfile,"To: %s\n",to);
- fprintf(tfile,"Subject: Failed mail\n\n");
- fprintf(tfile," ===== transcript follows =====\n\n");
-
- for (lp = cb->errlog; lp != NULLLIST; lp = lp->next)
- fprintf(tfile,"%s\n",lp->val);
-
- fprintf(tfile,"\n ===== Unsent message follows ====\n");
-
- while((c = getc(infile)) != EOF)
- if (putc(c,tfile) == EOF)
- break;
- fclose(infile);
- fseek(tfile,0L,0);
- if ((smtpmode & QUEUE) != 0)
- router_queue(cb->tcb,tfile,"",(struct list *)to);
- else
- queuejob(cb->tcb,tfile,host,to,"");
- fclose(tfile);
- }
-
- /* look to see if a smtp control block exists for this ipdest */
- static struct smtp_cb *lookup(int32 destaddr)
- {
- register int i;
-
- for(i=0; i<MAXSESSIONS; i++) {
- if (cli_session[i] == NULLCB)
- continue;
- if(cli_session[i]->ipdest == destaddr)
- return cli_session[i];
- }
- return NULLCB;
- }
-
- /* create a new smtp control block */
- static struct smtp_cb *newcb(void)
- {
- register int i;
- register struct smtp_cb *cb;
-
- for (i = 0; i < MAXSESSIONS; i++)
- {
- if (cli_session[i] == NULLCB)
- {
- cb = (struct smtp_cb *)calloc(1,sizeof(struct smtp_cb));
- if (cb == NULLCB)
- return(NULLCB);
- cb->wname = malloc((unsigned)strlen(mailqdir) + JOBNAME + 6);
- if (cb->wname == NULLCHAR)
- {
- free((char *)cb);
- return(NULLCB);
- }
- cb->tname = malloc((unsigned) strlen(mailqdir) + JOBNAME + 6);
- if (cb->tname == NULLCHAR)
- {
- free(cb->wname);
- free((char *)cb);
- return(NULLCB);
- }
- cb->state = CLI_INIT_STATE;
- cli_session[i] = cb;
- smtpsessions++; /* number of connections active */
- return(cb);
- }
- }
- return NULLCB;
- }
-
- static void execjobs(void)
- {
- struct socket lsocket, fsocket;
- register struct smtp_cb *cb;
- register int i;
-
- for (i = 0; i < MAXSESSIONS; i++)
- {
- cb = cli_session[i];
- if (cb == NULLCB)
- continue;
- if(cb->state != CLI_INIT_STATE)
- continue;
-
- sprintf(cb->tname, "%s.text.%s", mailqdir, cb->jobq->jobname);
- sprintf(cb->wname, "%s.work.%s", mailqdir, cb->jobq->jobname);
-
- /* setup the socket */
- fsocket.address = cb->ipdest;
- fsocket.port = SMTP_PORT;
- lsocket.address = ip_addr; /* our ip address */
- lsocket.port = lport++; /* next unused port */
- #ifdef SMTPTRACE
- if (smtptrace)
- {
- cwprintf(smtp_win, "SMTP: Trying Connection to %s\r\n",inet_ntoa(fsocket.address));
- }
- #endif
-
- /* open smtp connection */
- cb->state = CLI_OPEN_STATE; /* init state placeholder */
- cb->tcb = open_tcp(&lsocket, &fsocket, TCP_ACTIVE, tcp_window,
- (void(*)())smtp_rec, (void(*)())smtp_cts, (void(*)())smtp_state, 0, (char *)cb);
- cb->tcb->user = (char *)cb; /* Upward pointer */
- }
- }
-
- /* add this job to control block queue */
- struct smtp_job *setupjob(struct smtp_cb *cb, char *id, char *from)
- {
- register struct smtp_job *p1,*p2;
-
- p1 = (struct smtp_job *)calloc(1,sizeof(struct smtp_job));
- if (p1 == NULLJOB)
- return NULLJOB;
- p1->from = malloc((unsigned)strlen(from) + 1);
- if (p1->from == NULLCHAR)
- {
- free((char *)p1);
- return NULLJOB;
- }
- strcpy(p1->from,from);
- strcpy(p1->jobname,id);
- /* now add to end of jobq */
- if ((p2 = cb->jobq) == NULLJOB)
- cb->jobq = p1;
- else
- {
- while(p2->next != NULLJOB)
- p2 = p2->next;
- p2->next = p1;
- }
- return p1;
- }
-
- /* called to advance to the next job */
- static int nextjob(register struct smtp_cb *cb)
- {
- register struct smtp_job *jp;
-
-
- jp = cb->jobq->next;
- del_job(cb->jobq);
- if (jp == NULLJOB)
- {
- cb->jobq = NULLJOB;
- return 0;
- }
- /* remove the error log of previous message */
- del_list(cb->errlog);
- cb->errlog = NULLLIST;
- cb->goodrcpt = 0;
- cb->jobq = jp;
- sprintf(cb->tname,"%s.text.%s",mailqdir,jp->jobname);
- sprintf(cb->wname,"%s.work.%s",mailqdir,jp->jobname);
- #ifdef SMTPTRACE
- if (smtptrace > 5)
- {
- cwprintf(smtp_win, "sending job %s\r\n",jp->jobname);
- }
- #endif
- return 1;
-
- }
-
-
- /* mail routing funtion. For now just used the hosts file */
- int32 mailroute(char *dest)
- {
- int32 destaddr;
-
- /* KA9Q doesn't work out that an address is unreachable.
- Kludgy fix: use the gateway if one exists and assume that its
- router is more clever. */
-
- /* if ((destaddr = mxresolve(dest)) == 0)
- {
- if (gateway != 0)
- destaddr = gateway;
- } */
-
- /* Yet another hack -
- if the dest is in our domain, direct it to us
- */
- if (inourdomain(dest))
- destaddr = ip_addr;
-
- destaddr = resolve(dest);
-
- /*
- cwprintf(NULL, "Mailroute to: %s %.8x\n", dest, destaddr);
- cwprintf(NULL, "Mailroute ip addr: %.8x\n", ip_addr);
- cwprintf(NULL, "Mailroute gateway: %.8x\n", gateway);
- */
-
- if (destaddr == ip_addr)
- return destaddr;
-
- else if (gateway != 0)
- destaddr = gateway;
-
- else
- {
- if ((destaddr = mxresolve(dest)) == 0)
- if (gateway != 0)
- destaddr = gateway;
- }
- return destaddr;
- }
-
- /* save error reply for in error list */
- static void logerr(struct smtp_cb *cb)
- {
- register struct list *lp,*tp;
- if ((tp = (struct list *)calloc(1,sizeof(struct list))) == NULLLIST)
- return;
- if ((tp->val = malloc((unsigned)strlen(cb->buf)+1)) == NULLCHAR) {
- free((char *)tp);
- return;
- }
- /* find end of list */
- if ((lp = cb->errlog) == NULLLIST)
- cb->errlog = tp;
- else {
- while(lp->next != NULLLIST)
- lp = lp->next;
- lp->next = tp;
- }
- strcpy(tp->val,cb->buf);
- }
-
- static int dosep(int argc, char **argv)
- {
- if (argc < 2)
- {
- cwprintf(NULL, "smtp separator: %s\r\n", seps[smtp_sep]);
- }
- else
- {
- switch(tolower(*argv[1]))
- {
- case '^':
- case 'a':
- smtp_sep = sep_CTLA;
- break;
- case 'r':
- if (tolower(*(argv[1]+1))=='m')
- smtp_sep = sep_RMAIL;
- else
- smtp_sep = sep_RNEWS;
- break;
- default:
- smtp_sep = sep_UNIX;
- break;
- }
- }
- return 0;
- }
-
- /* Return true if host is a possible sub-domain
- of our domain - for eg
- user.ourhost.domain is acceptable, but
- hourhost.domain is not.
- */
- int inourdomain(char *host)
- {
- int n1 = strlen(host);
- int n2 = strlen(hostname); /* actually our domain */
-
- if (n1<n2)
- return (!stricmp(hostname, host+(n1-n2)) && host[(n1-n2)-1]=='.');
-
- return 0;
- }
-
- void newsbase_update(int type)
- {
- wimp_msgstr msg;
-
- msg.hdr.size = 20+12+8;
- msg.hdr.your_ref = 0;
- msg.hdr.action = 0xfeed12; /* Newsbase Queue Update */
- msg.data.words[0] = 11;
- msg.data.words[1] = type;
- msg.data.words[2] = -1;
- sprintf(msg.data.chars+12, "ka9q");
- wimp_sendmessage(wimp_ESEND, &msg, 0);
- }
-