/* mailb.c */ /* * Includes */ #include #include #include "vmail.h" #include "dfault.h" #include "evtdef.h" #include "hstdef.h" #include "prodef.h" #include "mailpi.h" #include "cliutl.h" #include "tsxutl.h" #include "kbdutl.h" #include "rtfile.h" #include "inicli.h" #include "suspnd.h" #include "usrblk.h" #include "rcdlck.h" #include "mailbx.h" #include "datime.h" /* * Internal routines */ extern VOID printtxt(); extern int finduniq(); extern int toggle(); extern VOID prnthelp(); extern int mailpi(); extern VOID more(); extern VOID mailexit(); extern int question(); extern int rtresp(); extern int tstbrk(); extern int loadpath(); extern VOID lcd(); extern VOID ldelete(); extern VOID ldelfil(); extern VOID lls(); extern VOID lmkdir(); extern VOID lprotect(); extern VOID setfilp(); extern VOID lrename(); extern VOID newname(); extern VOID lrmdir(); extern VOID rmdir(); extern VOID lunprotect(); extern VOID clrfilp(); extern VOID lsterr(); extern int mailgets(); extern int getword(); extern char *stptok(); extern char *stpblk(); extern int checkusps(); extern int Scompass(); extern VOID strlwr(); extern int strmatch(); extern VOID getinfo(); extern int wrtmsg(); extern VOID sendmail(); extern int send(); extern VOID lsendmail(); extern int lsend(); extern int lsend(); extern VOID scrnview(); extern VOID mailrsp(); extern int mailopen(); extern int mailreplies(); extern int rgetline(); extern int checkevent(); /* * Defines */ #define FALSE 0 #define TRUE 1 #define SUCCESS 2 #define HAVEDATA 4 #define ERROR -1 #define NONE -2 #define ABORT -3 #define INCOMPLETE -4 #define AMBIGUOUS -5 #define BUFFERS 2048 #define RSPSTRING 200 #define GENBUFR 200 /* * Global Variables For MAIL Control Channel */ extern int pswdreqd; /* password required */ extern int fromtty; /* tty / file input flag */ extern int hash, /* hash mark flag */ verbose, /* print mail transactions */ prompt, /* prompt for answer */ wild, /* wild cards enabled */ uflag, /* username / password flag */ lflag, /* local mail flag */ msgcnt, /* number of unread mail messages */ msgflag, /* created message flag */ mailcskt; /* socket for outgoing mail */ /* * Global Buffers / Pointers */ #define INFO_LEN (80) #define HDR_R (0x0001) #define HDR_D (0x0002) #define HDR_F (0x0004) #define HDR_M (0x0008) #define HDR_T (0x0010) #define HDR_S (0x0020) extern struct mesginfo { char rcvd[INFO_LEN]; char date[INFO_LEN]; char from[INFO_LEN]; char mesgid[INFO_LEN]; char to[INFO_LEN]; char to_user[INFO_LEN]; char to_dest[INFO_LEN]; char to_host[INFO_LEN]; char subject[INFO_LEN]; char filename[INFO_LEN]; char expanded[INFO_LEN]; }; extern struct mesginfo header; /* message header information */ extern struct userblock user; /* usernames / passwords / mailboxes */ extern char xs[BUFFERS]; /* buffer space for incoming data */ /* and TSXUTL.C command files */ extern char ml_cmnd[GENBUFR], /* command string */ scratch[GENBUFR], /* scratch string */ rsp[RSPSTRING], /* response string */ filespec[GENBUFR], /* current file filespec */ mailspec[GENBUFR], /* mailbox file filespec */ username[USERPASSLEN+2], /* username */ password[USERPASSLEN+2], /* password */ mailpath[DIRPATHLEN+2], /* mailbox path */ lclmpath[DIRPATHLEN+2], /* local mail path */ uspspath[DIRPATHLEN+2], /* path returned by checkusps */ defpath[GENBUFR], /* default path */ pathname[GENBUFR]; /* space to keep path name */ extern char * ipadd; /* intermediate IP Address */ extern char * pass; /* password file */ extern char fromfile[20]; /* command file */ extern FILE *fromfp; /* command file */ VOID sendmail() { int i,sprompt; if(mailopen(header.to_host) != TRUE) { if(msgflag) { kbprintf("?-MAIL-Message saved in file %s\r\n", header.expanded); } return; } if(send()) { kbprintf("?-MAIL-Send mail aborting\r\n"); if(msgflag) { kbprintf("?-MAIL-Message saved in file %s\r\n", header.expanded); msgflag = 0; } mailrsp("RSET"); mailreplies(&i); } mailrsp("QUIT"); do { i = mailreplies(&i); } while(i != ABORT && i != NONE); /* * close connection */ skclose(mailcskt); skrelease(mailcskt,1); mailcskt = -1; /* * Ask about temporary file */ if(msgflag) { sprompt = prompt; prompt = TRUE; kb_puts("?-MAIL-"); sprintf(ml_cmnd,"LDEL %s", header.filename); mailpi(ml_cmnd); prompt = sprompt; msgflag = 0; } } int send() { FILE *fp; int finished,rcode,sverbose; int hashcnt,hashnum; struct socket *skt; if(mailreplies(&rcode) != TRUE) { kbprintf("?-MAIL-Invalid reply from %s\r\n", header.to); return(1); } skt = mapskt(mailcskt); sprintf(rsp,"HELO %s", skt->hostname); mailrsp(rsp); if(mailreplies(&rcode) != TRUE) { kbprintf("?-MAIL-Invalid reply from %s\r\n", header.to); return(1); } skt = mapskt(mailcskt); sprintf(rsp,"MAIL FROM:<%s@%s>", header.from, skt->hostname); mailrsp(rsp); if(mailreplies(&rcode) != TRUE) { kbprintf("?-MAIL-Invalid reply from %s\r\n", header.to); return(1); } sprintf(rsp,"RCPT TO:<%s>", header.to); mailrsp(rsp); if(mailreplies(&rcode) != TRUE) { kbprintf("?-MAIL-User '%s' unknown\r\n", header.to); return(1); } sprintf(rsp,"DATA"); mailrsp(rsp); if(mailrepies(&rcode) != INCOMPLETE) { kbprintf("?-MAIL-Message transfer aborted\r\n"); return(1); } if((fp = rtopen(header.filename,"r",0,0)) == NULL) { kbprintf("?-MAIL-Unable to open message file %s\r\n", header.expanded); return(1); } /* * Send the Header */ skt = mapskt(mailcskt); sprintf(rsp,"Received: by %s", header.rcvd); mailrsp(rsp); sprintf(rsp,"Date: %s", header.date); mailrsp(rsp); sprintf(rsp,"From: <%s@%s>", header.from, skt->hostname); mailrsp(rsp); sprintf(rsp,"Message-Id: %s @%s", header.expanded, skt->hostname); mailrsp(rsp); sprintf(rsp,"To: %s", header.to_dest); mailrsp(rsp); sprintf(rsp,"Subject: %s", header.subject); mailrsp(rsp); /* * Start Message */ kb_puts("... Sending Message File ...\r\n"); sverbose = verbose; verbose = 0; mailrsp(""); /* * Transfer Message File */ finished = FALSE; hashnum = 0; hashcnt = 0; rsp[0] = '\.'; do { if(skroom(mailcskt) > LOWWATER) { if(fgetss(rsp+1,RSPSTRING-2,fp) != NULL) { if(rsp[1] != '\.') { mailrsp(rsp+1); } else { mailrsp(rsp); } if(hash) { hashcnt += strlen(rsp+1); /* * hash mark printing */ if(hashcnt >= HASHSIZE) { hashcnt -= HASHSIZE; if(++hashnum >= 75) { kb_puts("#\r\n"); hashnum = 0; } else { kb_out('#'); } } } } else { finished = TRUE; if(hash && hashnum) { kb_puts("\r\n"); } } } else { suspnd(0); } } while(finished != TRUE && !sktest(mailcskt) && !tstbrk()); /* * End Message */ mailrsp("."); verbose = sverbose; rtclose(fp); if(mailreplies(&rcode) != TRUE) { kbprintf("?-MAIL-Invalid reply from %s\r\n", header.to); return(1); } return(0); } VOID lsendmail() { int sprompt; if(lsend()) { kbprintf("?-MAIL-Send local mail aborting\r\n"); if(msgflag) { kbprintf("?-MAIL-Message saved in file %s\r\n", header.expanded); msgflag = 0; } } /* * Ask about temporary file */ if(msgflag) { sprompt = prompt; prompt = TRUE; kb_puts("?-MAIL-"); sprintf(ml_cmnd,"LDEL %s", header.filename); mailpi(ml_cmnd); prompt = sprompt; msgflag = 0; } } int lsend() { FILE *inp,*oup; int c,idx; /* * Load directory path */ if(loadpath(defpath)) return(1); if((inp = rtopen(header.filename,"r",0,0)) == NULL) { kb_puts("?-MAIL-Unable to open message file %s\r\n", header.expanded); return(1); } /* * Create a unique file name for temporary mail data */ sprintf(filespec,"wf:mailbx.%03d", tljobn); /* * Open mail file */ if((oup = fopen(filespec, "wn")) == NULL) { rtclose(inp); kb_puts("?-MAIL-Unable to Create Temporary File\r\n"); return(1); } /* * Write the Header */ fprintf(oup,"Received: by %s\r\n", header.rcvd); fprintf(oup,"Date: %s\r\n", header.date); fprintf(oup,"From: %s\r\n", header.from); fprintf(oup,"Message-Id: %s\r\n", header.expanded); fprintf(oup,"To: %s\r\n", header.to_user); fprintf(oup,"Subject: %s\r\n", header.subject); fprintf(oup,"\r\n"); /* * Copy message to the temporary file */ while((c = getc(inp)) != EOF) { putc(c,oup); } fclose(oup); rtclose(inp); /* * Load local mail directory path and update index file */ if(loadpath(lclmpath)) { return(1); } /* * The mailidx file must be locked to ensure * no other process has simultaneous access to * the file while the index is being updated. * If TSX+ is not sysgened for shared-file * record locking then record locking does not occur. */ idx = modidx(header.to_user,0,INC_MLID|SET_RCVD|CLR_READ); if(!idx) { /* * Create index file if not opened */ if(!makidx(header.to_user)) { kb_puts( "?-MAIL-Failed to create index file\r\n"); return(1); } else { idx=modidx(header.to_user,1, SET_MLID|SET_RCVD|CLR_READ); if(!idx) { kb_puts( "?-MAIL-Failed to update index file\r\n"); return(1); } } } if((inp = fopen(filespec,"rn")) == NULL) { kb_puts("?-MAIL-Unable to Read Temporary File\r\n"); return(1); } /* * Open new file */ sprintf(mailspec,"%-.6s.%03d", header.to_user, idx); if((oup = rtopen(mailspec,"wn",0,0)) == NULL) { kb_puts("?-MAIL-Unable to Create File\r\n"); fclose(inp); return(1); } /* * copy mail to a new file */ while((c = getc(inp)) != EOF) { putc(c,oup); } rtclose(oup); fclose(inp); /* * Delete temporary file */ delete(filespec); return(0); } /* * scrnview * * View data on screen */ VOID scrnview(cnt) int cnt; { int i; /* * put on screen */ for(i=0; i= 0) { flag = 1; } else { flag = 0; } while(flag && !tstbrk()) { if(Sgetevent(ABORTCLASS,&cl,&dat)) mailexit(ABORT); errhandle(); ev = Sgetevent(CONCLASS,&cl,&dat); switch(ev) { case CONOPEN: /* * Log the Session */ sprintf(scratch,"MAIL: %s", header.to_host); logsession(dat,scratch); return(TRUE); case CONCLOSE: case CONFAIL: flag = 0; break; default: if(ev) { Stmrset(cl,ev,dat,1); } else { suspnd(0); } } } /* * error on open */ skclose(mailcskt); mailcskt = skrelease(mailcskt,1); errhandle(); kbprintf("?-MAIL-Unable to connect to %s\r\n",dst); return(FALSE); } /* * mailreplies * * get responses to commands to server * return TRUE on successful completion, * INCOMPLETE if more commands needed for operation, * NONE on lost connection, ABORT on an abort, and ERROR on failure * PRELIMINARY responses wait for completion */ int mailreplies(rcode) int *rcode; { int abrtcnt,cnt,digit,j; abrtcnt = 0; j = 0; loop: while(1) { /* * get line from remote host */ cnt = rgetline(); if(cnt == NONE) /* * lost connection */ return(NONE); if(cnt == ABORT) /* * user abort */ return(ABORT); if(!sscanf(xs,"%d", rcode)) /* * continuation line */ *rcode = -1; /* * informative message */ if(verbose) scrnview(cnt); if(xs[3] == '-') { /* * line with continuations * remember end code */ j = *rcode; continue; } else if(j) { if(*rcode == j) { /* * end of continuation */ j = 0; } else { continue; } } /* * first digit */ digit = (int)(*rcode/100); if(abrtcnt) { switch(digit) { case 1: /* preliminary */ continue; case 2: /* positive completion */ case 3: /* intermediate */ case 4: /* transient negative completion */ case 5: /* Permanent negative completion */ default: return(ABORT); } } else { switch(digit) { case 1: /* preliminary */ continue; case 2: /* positive completion */ return(TRUE); case 3: /* intermediate */ return(INCOMPLETE); case 4: /* transient negative completion */ case 5: /* Permanent negative completion */ default: return(ERROR); } } } } /* * rgetline - get a line from remote server * * return ABORT on an abort, NONE on lost connection, * length of received line on success */ int rgetline() { int cnt,i,ev; i = 0; while(1) { ev = checkevent(); switch(ev) { case NONE: /* lost connection */ skdeque(mailcskt); case ABORT: /* abort */ return(ev); case HAVEDATA: /* * get some from queue */ while(1) { cnt = skread(mailcskt,&xs[i],1); if(!cnt) /* * nothing available */ break; if(xs[i++] == '\n') { /* * end of line */ xs[i] = '\0'; skdeque(mailcskt); /* * return line length */ return(i); } if(i > BUFFERS - 2) i = BUFFERS - 2; } break; default: /* ignore other events */ suspnd(10); break; } } } /* * checkevent * * get and process network events * returns ABORT on an abort, HAVEDATA if data available * on command connection, NONE if connection lost. * TRUE if no relevant event. */ int checkevent() { int cl,ev,dat; /* * check for abort */ if(tstbrk()) return(ABORT); /* * look for events */ ev = Sgetevent(CONCLASS | MSGCLASS | ERRCLASS | ABORTCLASS, &cl,&dat); if(ev) { switch(cl) { case ABORTCLASS: /* abort */ mailexit(ABORT); break; case ERRCLASS: /* error messages */ case MSGCLASS: /* messages */ kb_puts(skerrstring(ev)); kb_nline(); break; case CONCLASS: /* connection */ switch(ev) { case CONDATA: /* * data has arrived */ return(HAVEDATA); case CONCLOSE: /* * connection lost */ skclose(mailcskt); return(NONE); default: break; } break; default: break; } } return(TRUE); }