home *** CD-ROM | disk | FTP | other *** search
- /* smtpcli.c
- * 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.
- */
-
- #include <stdio.h>
- #include "machdep.h"
- #include "netuser.h"
- #include "mbuf.h"
- #include "timer.h"
- #include "tcp.h"
- #include "smtp.h"
-
- extern int16 lport; /* local port placeholder */
- int32 aton();
- static void sendit();
- static struct timer smtpcli_t;
- char *index(),*rindex();
-
- /* init routine called when program fired up */
- smtpclinit()
- {
- int dosmtptick();
-
- smtpcli_t.func = (void (*)())dosmtptick;/* what to call on timeout */
- smtpcli_t.arg = 0; /* dummy value */
- smtpcli_t.start = SMTPCLITIME; /* set timer duration */
- start_timer(&smtpcli_t); /* and fire it up */
- }
-
- /* this is the routine that gets called every so often to do outgoing mail
- processing */
- int
- dosmtptick()
- {
- char lfilename[LINELEN],
- tmpstring[LINELEN],
- wfilename[13],
- *ptr;
- FILE *lfile;
- struct smtp_msg *mp;
- struct socket lsocket, fsocket;
- char *calloc(),*malloc();
- void smtp_rec(), smtp_cts(), smtp_state();
-
- /* printf("DOSMTPTICK() entered\n"); */
- lsocket.address = ip_addr; /* our ip address */
- fsocket.port = SMTP_PORT;
- /* if lock file exists in mqueue dir, return */
- sprintf(lfilename,"%s%s",MAILQDIR,"lockfile");
- if ((lfile = fopen(lfilename,"x")) == NULL)
- return;
- /* get next work filename from mqueue directory */
- sprintf(tmpstring,"%s%s",MAILQDIR,"*.wrk");
- #ifndef AMIGA
- filedir(tmpstring,0,wfilename);
- #endif
- if (wfilename[0] == '\0')
- return; /* no work to be done */
- /* if we have work, rebuild the exact (non-wild) filename */
- mp = (struct smtp_msg *)calloc(1,sizeof (struct smtp_msg));
- sprintf(tmpstring,"%s%s",MAILQDIR,wfilename);
- ptr = &tmpstring[0];
- mp->filename = malloc((unsigned)strlen(ptr)+1);
- strcpy(mp->filename,ptr);
- /* printf("work file name: %s\n",mp->filename); /* debug only */
- mp->wfile = fopen(mp->filename,"r");
- /* get ip address, from stuff, to stuff */
- fgets(tmpstring,LINELEN,mp->wfile); /* read target ip addr */
- /* printf("target ip addr: %s\n",tmpstring); */
- fgets(mp->toaddr,LINELEN,mp->wfile); /* who to */
- rip(mp->toaddr);
- /* printf("addressee: %s\n",mp->toaddr); */
- fgets(mp->fromaddr,LINELEN,mp->wfile); /* who from */
- rip(mp->fromaddr);
- /* printf("sender: %s\n",mp->fromaddr); */
- fclose(mp->wfile);
- /* set up the rest of the socket info from what we got */
- fsocket.address = aton(tmpstring); /* destination ip address */
- lsocket.port = lport++; /* next unused port */
- /* open smtp connection */
- mp->state = CLI_OPEN_STATE; /* init state placeholder */
- /* printf("Opening TCP connection for SMTP client\n"); */
- mp->tcb = open_tcp(&lsocket,&fsocket,TCP_ACTIVE,1024,
- smtp_rec,smtp_cts,smtp_state,0,(int *)mp);
- mp->tcb->user = (int *)mp; /* Upward pointer */
-
- /* printf("releasing lock\n"); */
- if (lfile != NULL) { /* release lock */
- fclose(lfile);
- unlink(lfilename);
- }
- }
-
- /* replace terminating end of line marker(s) with null */
- rip(s)
- char *s;
- {
- char *c;
-
- c=s;
- while (*c != '\0') {
- switch (*c) {
- case '\r':
- case '\n':
- *c='\0';
- break;
- default:
- c++;
- break;
- }
- }
- }
-
- /* this is the master state machine that handles a single SMTP transaction */
- smtp_transaction(mp)
- struct smtp_msg *mp;
- {
- char tmpstring[LINELEN]; /* where we build command lines */
-
- /* printf("SMTP_TRANSACTION() called, state=%u\n",mp->state); */
- if (affirmative(mp)) {
- switch(mp->state) {
- case CLI_OPEN_STATE:
- mp->state = CLI_MAIL_STATE;
- /* issue MAIL command */
- /* printf("FROMADDR = %s\n",mp->fromaddr); */
- sprintf(tmpstring,"mail from:<%s>\r\n",mp->fromaddr);
- sendit(mp,tmpstring);
- break;
- case CLI_MAIL_STATE:
- mp->state = CLI_RCPT_STATE;
- /* issue RCPT command */
- sprintf(tmpstring,"rcpt to:<%s>\r\n",mp->toaddr);
- sendit(mp,tmpstring);
- break;
- case CLI_RCPT_STATE:
- mp->state = CLI_SEND_STATE;
- /* open text file */
- strcpy(tmpstring,mp->filename);
- strcpy(index(tmpstring,'.'),".txt");
- /* printf("text filename: %s",tmpstring); */
- mp->tfile = fopen(tmpstring,"r");
- /* issue DATA command */
- sprintf(tmpstring,"data\r\n");
- sendit(mp,tmpstring);
- break;
- case CLI_SEND_STATE:
- /* the transmitter upcall routine will advance the
- state pointer on end of file, so we do nada... */
- break;
- case CLI_UNLK_STATE:
- unlink(mp->filename); /* unlink workfile */
- /* close and unlink the textfile */
- fclose(mp->tfile);
- strcpy(tmpstring,mp->filename);
- strcpy(index(tmpstring,'.'),".txt");
- unlink(tmpstring);
- mp->state = CLI_QUIT_STATE;
- /* issue a quit command */
- sprintf(tmpstring,"quit\r\n");
- sendit(mp,tmpstring);
- break;
- case CLI_QUIT_STATE:
- /* either start next transaction, or quit */
- close_tcp(mp->tcb); /* close up connection */
- break;
- }
- } else { /* if we get here, means we got a negative reply */
- /* for the moment, just let that hose us... */
- mp->state = CLI_QUIT_STATE;
- /* issue a quit command */
- sprintf(tmpstring,"quit\r\n");
- sendit(mp,tmpstring);
- }
- }
-
- /* return true if the passed string contains a positive response code */
- affirmative(mp)
- struct smtp_msg *mp;
- {
- /* 2 is always good, 3 is ok if we've just sent 'data' command */
- if ((*mp->buf = '2') ||
- ((*mp->buf = '3') && (mp->state = CLI_DATA_STATE)))
- return 1;
- else return 0;
- }
-
- /* smtp receiver upcall routine. fires up the state machine to parse input */
- static
- void
- smtp_rec(tcb,cnt)
- struct tcb *tcb;
- int16 cnt;
- {
- register struct smtp_msg *mp;
- char *inet_ntoa(), c;
- struct mbuf *bp;
- /* may want a void line here for procedures used */
-
- /* printf("SMTP_REC called\n"); */
- mp = (struct smtp_msg *)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(pullup(&bp,&c,1) == 1) {
- switch(c) {
- case '\r': /* strip cr's */
- continue;
- case '\n': /* line is finished, go do it! */
- mp->buf[mp->cnt] = '\0';
- smtp_transaction(mp);
- break;
- default: /* other chars get added to buffer */
- mp->buf[mp->cnt++] = c;
- break;
- }
- }
- }
-
- /* smtp transmitter ready upcall routine. twiddles cts flag */
- static
- void
- smtp_cts(tcb,cnt)
- struct tcb *tcb;
- int16 cnt;
- {
- register struct smtp_msg *mp;
- struct mbuf *bp;
- char tmpstring[LINELEN];
- char *cp;
- int c;
-
- /* printf("SMTP_CTS called\n"); */
- mp = (struct smtp_msg *)tcb->user; /* point to our struct */
-
- /* don't do anything until/unless we're supposed to be sending */
- if(mp->state != CLI_SEND_STATE) return;
-
- if((bp = alloc_mbuf(cnt)) == NULLBUF){
- /* Hard to know what to do here */
- return;
- }
- cp = bp->data;
- while(cnt > 1 && (c = getc(mp->tfile)) != EOF){
- *cp++ = c;
- bp->cnt++;
- cnt--;
- }
- if(bp->cnt != 0)
- send_tcp(tcb,bp);
- else
- free_p(bp);
-
- if(cnt > 1){ /* EOF seen */
- sprintf(tmpstring,"\r\n.\r\n");
- sendit(mp,tmpstring);
- mp->state = CLI_UNLK_STATE;
- }
- }
-
- /* smtp state change upcall routine. cans connection on error */
- static
- void
- smtp_state(tcb,old,new)
- struct tcb *tcb;
- char old,new;
- {
- struct smtp_msg *mp;
-
- /* printf("SMTP_STATE called, state=%u\n",new); */
- mp = (struct smtp_msg *)tcb->user;
- switch(new) {
- case ESTABLISHED:
- mp->state = CLI_OPEN_STATE; /* shouldn't be needed */
- break;
- case CLOSE_WAIT:
- close_tcp(tcb); /* shut things down */
- /* may want to do something here to shut down
- the rest of the transaction? */
- break;
- case CLOSED:
- del_tcp(tcb); /* hosed for good */
- if(mp->filename != NULLCHAR)
- free(mp->filename);
- free((char *)mp);
- break;
- }
- }
-
- /* Send message back to server */
- static
- void
- sendit(mp,message)
- struct smtp_msg *mp;
- char *message;
- {
- struct mbuf *bp,*qdata();
-
- /* printf("SENDIT called: %s",message); */
- bp = qdata(message,(int16)strlen(message));
- send_tcp(mp->tcb,bp);
- }
-