/* ax_mbx.c, non xobbs part. This version has some of the new mbox features. * Code is Unix compatible. K5JB * 3/3/90 added check for disconnected link during a download and stifled * use of memory a bit during that process - K5JB * 6/6/91 added time out timers to AX25 and Netrom sessions. Set it at * 10 minutes. * 6/25/91 Version with selective file reading, beginning with v.i.9 * l lists message headers, ls shows directories, r [n] reads message n, * k [n] kills message n. If only one message, r or k can be used without * a number. On connect, maximum of last 5 messages shown. * 6/29/91 Made change to ax25subr.c to trap double freeing of axp in * del_ax25 which occurs on disconnection during download over ax25 link. * It didn't seem to happen with netrom link. Rearranged handling of abort * function for download. (Later undid this) * 7/11/91 Revised file sending to use transmit upcall, added prompting * to the timer chain because this module gets no signal that file sending * is completed. Re-arranged struct mbx to match struct session so t_upcall * could be used. Made the message list function also a t_upcall. * 7/15/91 Changed mind on listing last 5 messages on connect. Only lists * unread messages on connect. L lists all messages. Added LL # command * at the cost of 146 bytes. To compile in, use #define LLCMD * 7/17/91 - Felt guilty so did some cleanup and squeezed 692 bytes out * of her. Replaced the fancy send parser, mbx_to(), which saved 608 * of those bytes. Most of rest was saved by reusing tmpbuf[] where I * could. Another 112 bytes were saved by making message header strings * into fixed arrays and using calloc() to init. * 8/12/91 - Fixed broken 'g' command caused by using tmpbuf incorrectly. * Added clarification to result of kill command. * 2/24/92 - added build_line() to cut dupe code (saved 128 bytes) and * added some static declarations to make functions private to this module. * 3/13/91 - Completed adding the SID2 support for ax25 mbxcall and added * ability to read a sub directory off of the public mbox directory. * 3/25/91 added a stat() to the readany() function to prevent user from * "getting" a directory in Unix * 9/5/92 Cleared up some refs to NULL. Note that NULL and NULLCHAR are * not the same thing. * 10/14/92 Added "w" (what) an alias for the ls command w/o args and added * a "jheard" which uses code ifdefed with AX25_HEARD. Also did some cosmetic * work on user responses. With addition of ax25 T4 timer, this really * doesn't need mboxwait any more. 11/25/92 * 3/3/92 Added "s" arg to mbox to permit sending a butt-in string (k29) * 9/93 some changes for OS9/K by N0QBJ and K5JB. Some error messages * made optionally verbose. Define VERBOSE is you want them; don't if you * want to keep the module smaller. * 12/23/93, general housekeeping and crunching. Corrected error in * send from a BBS. in the line sp k5jb @ w1aw < jy1, the @ was being * punched out. Changed callsigns to lower case which cut SMTP processing * down by one cycle. At request of one user to add more BBS features, I * was inspired to define NOPLAYBBS to see what we could save if we didn't * receive BBS forwarded mail, it is 532 bytes. k34 */ #undef VERBOSE /* error message in newmailfile() */ /* 10 minutes plus a little bit... */ #define MBOXLIFE 600050L /* don't think we need this with added ax25 t4 */ #include "options.h" #include "config.h" #ifdef AX25 #ifdef AXMBX #include #include #ifdef MSDOS #include #endif #include #include #ifdef UNIX #include #include #define SEEK_SET 0 #endif #include "global.h" #include "mbuf.h" #include "ax25.h" #include "timer.h" #include "iface.h" #include "lapb.h" #ifdef NETROM #include "netrom.h" #include "nr4.h" #endif #include "ax_mbx.h" #include "cmdparse.h" #include "netuser.h" #include "tcp.h" #ifdef _OSK #include "os9stat.h" #endif /* #define USERWATCH to watch user's actions */ #define LLCMD /* this adds 146 bytes */ #define SIZE_NAME 10 /* the 3 below, are defined in files.c */ extern char *helpbox; extern char *public; extern char *mailspool; extern char hostname[]; /* miscellaneous declarations */ int queuejob(),validate_address(),start_timer(),stop_timer(),pax25(), disc_ax25(),mbx_line(); void rip(),free(),genlog(),send_ax25(),free_mbx(); #ifdef NETROM int send_nr4(); void disc_nr4(); #endif extern FILE *dir(); extern void filedir(); extern char versionf[]; #ifndef FALSE #define FALSE 0 #define TRUE 1 #endif struct mbx *mbox[NUMMBX]; int ax25mbox = 1; /* k34 */ #ifdef MB_BUTTIN int butt_flag = FALSE; extern char butt_msg1[]; /* defined in motd.c */ int motd(); static char butt_msg2[] = "I'm at the console. To do chat, send a \"c\" (QRX for prompt).\015"; #endif static char mbbanner[] = "[NET-$]\015Welcome to the %s TCP/IP Mailbox. I'll see if you have mail...\015"; #ifdef LLCMD static char mbmenu[] = "Read #, Kill #, List, LLast #, Send, Chat, What, Help, Bye >\015"; #else static char mbmenu[] = "Read #, Kill #, List, Send, Chat, What, Help, Bye >\015"; #endif char *sorry = "Sorry, My owner didn't read Chapter 2.\015"; static char tmpbuf[MBXLINE]; /* used by various routines */ char *cp; /* utility pointer */ struct mbuf *free_p(); /* collected some common frees here */ static void free_misc(m) struct mbx *m; { if (m->to != NULLCHAR) free(m->to); #ifndef NOPLAYBBS if (m->tofrom != NULLCHAR) free(m->tofrom); if (m->tomsgid != NULLCHAR) free(m->tomsgid); #endif m->to = m->tofrom = m->tomsgid = NULLCHAR; } static void free_mbx(m) /* called by mbx_state, mbx_nr4state, and mbx_line when we */ struct mbx *m;/* come back from chat (ax25 or netrom) */ { genlog(m->name, "outa here"); free_misc(m); if(m->name != NULLCHAR){ free(m->name); m->name = NULLCHAR; } if(m->upload != NULLFILE){ #if defined(_OSK) && !defined(_UCC) /* Coherent could use this too if */ tmpclose(m->upload); /* somebody would do a tmpfile thing for it */ #else #ifdef UNIX if(pclose(m->upload) < 0) /* only needed in case of a directory read */ #endif fclose(m->upload); #endif m->upload = NULLFILE; free(m->ufile); m->ufile = NULLCHAR; } if (m->tfile != NULLFILE) #if defined(_OSK) && !defined(_UCC) tmpclose(m->tfile); #else fclose(m->tfile); #endif if(m->mboxwait.state != TIMER_STOP) stop_timer(&m->mboxwait); if(m->prompter.state != TIMER_STOP) stop_timer(&m->prompter); mbox[m->mbnum] = NULLMBX; free(m); #ifdef MB_BUTTIN /* and finally ... */ butt_flag = FALSE; *butt_msg1 = '\0'; #endif } static int mbx_msg(m,msg) struct mbx *m; char msg[]; { int len; struct mbuf *bp; struct ax25_cb *axp; #ifdef NETROM struct nr4cb *cb; #endif len = strlen(msg); switch (m->type){ case MBX_AX25: axp = m->cb.ax25_cb; if ((bp = alloc_mbuf(len+1)) == NULLBUF){ disc_ax25(axp); return(-1); } bp->cnt = len + 1; *bp->data = PID_NO_L3; memcpy(bp->data+1, msg, len); send_ax25(axp,bp); break; #ifdef NETROM case MBX_NETROM: cb = m->cb.nr4_cb; if ((bp = alloc_mbuf(len)) == NULLBUF){ disc_nr4(cb); return(-1); } bp->cnt = len; memcpy(bp->data, msg, len); send_nr4(cb, bp); break; #endif } return(0); } static void domboxdisplay(m,remote) struct mbx *m; int remote; { int i; struct mbx *lm; static char *states[] = {"NONE","CMD","SUBJ","DATA","SEND","DISC"}; #ifdef NETROM static char *mbtype[] = {"NONE","AX25 ","NET/ROM"}; #else static char *mbtype[] = {"NONE","AX25 "}; #endif sprintf(tmpbuf," User State Type &cb ms left\015"); if(remote) mbx_msg(m,tmpbuf); else{ rip(tmpbuf); printf("%s\n",tmpbuf); } for (i = 0;i < NUMMBX;i++){ if ((lm = mbox[i]) != NULLMBX){ #ifdef NETROM /* %-8x is deliberate */ sprintf(tmpbuf," %-10s %-4s %-7s %-8x %ld\015", lm->name, states[lm->state], mbtype[lm->type], lm->type == MBX_AX25 ? (char *)lm->cb.ax25_cb : (char *)lm->cb.nr4_cb, lm->mboxwait.count * MSPTICK); #else sprintf(tmpbuf," %-10s %-4s %-7s %-8x %ld\015", lm->name, states[lm->state], mbtype[lm->type], (char *)lm->cb.ax25_cb, lm->mboxwait.count * MSPTICK); #endif if(remote) mbx_msg(m,tmpbuf); else{ rip(tmpbuf); printf("%s\n",tmpbuf); } } } } int dombox(argc, argv) int argc; char *argv[]; { if (argc < 2){ printf("mailbox is %s\n", ax25mbox ? "on" : "off"); domboxdisplay(NULLMBX,0); /* the 0 indicates local, 1 is remote */ return(0); } if(argv[1][1] == 'n' || argv[1][1] == 'f'){ /* k34 */ ax25mbox = argv[1][1] == 'n' ? 1 : 0; return 0; } #ifdef MB_BUTTIN /* note that if there are mult. users message can go */ if (*argv[1] == 's'){ /* to ANY one of them */ int i; for (i = 0;i < NUMMBX;i++) if (mbox[i] != NULLMBX) break; if(i == NUMMBX){ printf("No one on mbox\n"); return(0); } butt_flag = TRUE; /* prompt routine will send our message */ if(argc > 2){ /* We have something to say */ argc--; argv++; motd(argc,argv); } } #endif /* MB_BUTTIN */ else #ifdef MB_BUTTIN printf("usage: mbox [on|off] [send []]\n"); #else printf("usage: mbox [on|off]\n"); #endif return(0); } static void errorexit(m,msg) struct mbx *m; char *msg; { int doexit(); extern int exitval; exitval = 1; genlog(m->name,msg); doexit(); } static struct mhdr * inithdr(m) struct mbx *m; { struct mhdr *mhdr; struct mhdr *newhdr; int i; /* calloc used to fill struct with zeros */ if((newhdr = (struct mhdr *)calloc(1,sizeof(struct mhdr))) == NULLMSGHDR) errorexit(m,"inithdr: No memory!"); /* no point in hanging around */ if(m->msgs == 0){ mhdr = m->firsthdr = newhdr; mhdr->next = NULLMSGHDR; mhdr->prev = NULLMSGHDR; }else{ for(i=m->msgs,mhdr = m->firsthdr;i > 1;i--) mhdr = mhdr->next; mhdr->next = newhdr; newhdr->prev = mhdr; mhdr = newhdr; } m->msgs += 1; mhdr->msgnr = m->msgs; #ifdef TURKEYS /* if you deal with MSYS people and the like, use this: strcpy(mhdr->from,"(no From:)"); /* costs around 84 bytes */ strcpy(mhdr->subj,"(no Subject:)"); strcpy(mhdr->date,"(no Date:)"); #endif return(mhdr); } static struct mbx * newmbx() { int i; struct mbx *m; for (i = 0;i < NUMMBX;i++) if (mbox[i] == NULLMBX){ if ((m = mbox[i] = (struct mbx *)calloc(1,sizeof(struct mbx))) == NULLMBX) return(NULLMBX); m->mbnum = i; m->msgs = 0; m->state = MBX_CMD; /* start in command state */ m->prompter.state = TIMER_STOP; m->promptwait = 0; return(m); } /* If we get here, there are no free mailbox sessions */ return(NULLMBX); } static int g_args(m) /* return offset to first letter of arg */ struct mbx *m; /* or nul if none detected after command */ { int i = 0; do i++; while((m->line[i] != ' ') && (m->line[i] != '\0')); if(m->line[i] != '\0'){ do i++; while((m->line[i] == ' ') && (m->line[i] != '\0')); if(m->line[i] != '\0') return(i); } return(0); } static void build_line(m,bp) struct mbx *m; struct mbuf *bp; { char c; while (pullup(&bp,&c,1) == 1){ if(c == '\012') /* skip linefeeds */ continue; if (c == '\015'){ *m->lp = '\0'; /* null terminate */ if (mbx_line(m) == -1){ /* call the line processor */ free_p(bp); /* toss the rest */ break; /* get out - we're obsolete */ } m->lp = m->line; /* reset the pointer */ }else if ((m->lp - m->line) == (MBXLINE - 1)){ *m->lp++ = c; *m->lp = '\0'; if (mbx_line(m) == -1){ free_p(bp); break; } m->lp = m->line; }else *m->lp++ = c; } } /* receive upcall for ax.25 */ /* mbx_rx collects lines, and calls mbx_line when they are complete. */ /* If the lines get too long, it arbitrarily breaks them. */ void mbx_rx(axp,cnt) struct ax25_cb *axp; int16 cnt; { struct mbuf *bp, *recv_ax25(); struct mbx *m; m = (struct mbx *)axp->user; start_timer(&m->mboxwait); /* reset idle timer */ if ((bp = recv_ax25(axp,cnt)) == NULLBUF) return; build_line(m,bp); } static void cleanup(m) struct mbx *m; { struct mhdr *mhdr; struct mhdr *tmphdr; int i; for(i=0,mhdr=m->firsthdr;imsgs;i++){ tmphdr = mhdr->next; free(mhdr); mhdr = tmphdr; } m->msgs = 0; } /* state upcall for ax.25 */ void mbx_state(axp,old,new) struct ax25_cb *axp; int old, new; { struct mbx *m; #ifdef SID2 void mbx_incom(); #endif if (new == DISCONNECTED){ m = (struct mbx *)axp->user; if(m->msgs) cleanup(m); /* leave mail file alone if we get here */ axp->user = NULLCHAR; free_mbx(m); } #ifdef SID2 /* this is a hell of a thing to do in a state upcall... * Will come here because it earlier recognized connect to mbxcall * and s_upcall switched to this function - K5JB */ if(old == DISCONNECTED && new == CONNECTED) mbx_incom(axp,0); /* take another shot at it */ #endif } static void mailfetch(m) struct mbx *m; { FILE *mailfile; char tmpline[40]; int i; struct mhdr *mhdr; char *txtname; /* may be smaller code to do txtname[40] */ if((txtname = (char *)malloc(sizeof(char) * (strlen(mailspool) + strlen(m->name) + 6))) == 0) return; sprintf(txtname,"%s/%s.txt",mailspool,m->name); if((mailfile = fopen(txtname,"r")) == NULLFILE){ free(txtname); return; } while(fgets(tmpbuf,MBXLINE,mailfile) != NULLCHAR){ rip(tmpbuf); /* From k5jb@k5jbgucci Mon Jun 17 11:32:55 1991 */ if(strncmp(tmpbuf,"From ",5) == 0){ /* guess we could save this in */ mhdr = inithdr(m); /* case mail header was noncompliant */ #ifdef UNIX mhdr->fileptr = ftell(mailfile) - strlen(tmpbuf) - 1; /* the EOL */ #else mhdr->fileptr = ftell(mailfile) - strlen(tmpbuf) - 2; /* the EOL */ #endif /* inithdr already incremented msgs */ if(m->msgs > 1) /* size is int & fileptr long, but that's OK */ mhdr->prev->size = (int)(mhdr->fileptr - mhdr->prev->fileptr); continue; } if(m->msgs == 0) break; /* badly formed file */ /* Note that many mailers are not RFC-822 compliant here Date: Mon, 17 Jun 91 11:32:04 CDT */ if(strncmp(tmpbuf,"Date:",5) == 0){ int colons = 0; cp = &tmpbuf[11]; /* sizeof mhdr->date is 16 chars */ for(i=0;i < sizeof(mhdr->date) - 1 && *cp;i++){ if(*cp == ':') if(colons++) break; /* Common error, we only want one colon */ tmpline[i] = *cp++; } tmpline[i] = '\0'; strcpy(mhdr->date,tmpline); continue; } /* From: k5jb@k5jbgucci (K5JB_Gucci) or Joe, K5JB */ if(strncmp(tmpbuf,"From:",5) == 0){ /* is a common RFC-822 From: field */ if((cp = strchr(tmpbuf,'<')) == NULLCHAR) /* no '<' found */ cp = &tmpbuf[5]; cp++; /* sizeof mhdr->from is 23 chars */ for(i=0;ifrom) - 1;i++){ if(*cp <= ' ' || *cp == '>') /* don't want spaces here */ break; tmpline[i] = *cp++; } tmpline[i] = '\0'; strcpy(mhdr->from,tmpline); continue; } /* Subject: First Message */ if(strncmp(tmpbuf,"Subje",5) == 0){ cp = &tmpbuf[9]; /* sizeof mhdr->subj is 31 chars */ for(i=0;isubj) - 1 && *cp >= ' ';i++) /* space ok here */ tmpline[i] = *cp++; /* but no ctrl chars */ tmpline[i] = '\0'; strcpy(mhdr->subj,tmpline); continue; } /* Status: R */ if(strncmp(tmpbuf,"Status",6) == 0){ mhdr->status |= STATREAD; continue; } } mhdr->size = (int)ftell(mailfile) - ((m->msgs == 1) ? 0 : (int) mhdr->fileptr); fclose(mailfile); free(txtname); return; } static void /* thought this was clever of me. Since we don't know when */ do_prompt(m) /* t_upcall is finished, we put our prompt on timer chain */ struct mbx *m; /* if promptwait flag != 0. Otherwise, send prompt now. */ { if(m->promptwait != 0){ if((m->prompter.state == TIMER_EXPIRE || m->prompter.state == TIMER_STOP) && m->state == MBX_SEND && m->upload != NULLFILE){ /* reset the timer for another promptwait in secs. */ m->prompter.start = m->promptwait * 1000L / MSPTICK; m->prompter.func = (void(*)())do_prompt; m->prompter.arg = (char *)(m); start_timer(&m->prompter); return; } if(m->prompter.state != TIMER_STOP) stop_timer(&m->prompter); if(m->state == MBX_SEND && m->upload == NULLFILE){ m->state = MBX_CMD; /* here is where we get the state change */ /* after a file download - state change on */ m->promptwait = 0; /* abort happens in mbx_line() */ } } #ifdef MB_BUTTIN if(butt_flag){ butt_flag = FALSE; if(*butt_msg1 != '\0'){ mbx_msg(m, butt_msg1); *butt_msg1 = '\0'; } mbx_msg(m,butt_msg2); } #endif #ifndef NOPLAYBBS mbx_msg(m, (m->sid & MBX_SID) ? ">\015" : mbmenu); #else mbx_msg(m, mbmenu); #endif } /* modified from doupload from session.c - triggers the t_upcall mechanism * which will queue outgoing lines, and close file and free filename when * EOF is reached. In case of Unix pipe, the close will have error but * it shouldn't hurt anything */ static void read_fd(m,fd) /* hand this an open file descriptor - it will launch */ struct mbx *m; /* yer file with t_upcall, followed by a prompt from */ FILE *fd; /* timer daemon. Abort sensed in mbx_line() */ { struct ax25_cb *axp; #ifdef NETROM struct nr4cb *cb; #endif switch(m->type){ case MBX_AX25: axp = m->cb.ax25_cb; break; #ifdef NETROM case MBX_NETROM: cb = m->cb.nr4_cb; break; #endif } m->upload = fd; m->ufile = (char *)malloc(5); /* something for the upcall to free */ strcpy(m->ufile,"NADA"); m->state = MBX_SEND; m->promptwait = 5; /* indicates 5 sec delays */ do_prompt(m); /* start the prompt daemon */ /* All set, kick transmit upcall to get things rolling */ switch(m->type){ case MBX_AX25: (*axp->t_upcall)(axp,axp->paclen * axp->maxframe); break; #ifdef NETROM case MBX_NETROM: (*cb->t_upcall)(cb, NR4MAXINFO); break; #endif } } static int /* this queues things to a temporary file. Return */ showlist(m,full) /* is not currently tested. Full is zero on connect */ struct mbx *m; /* "full" can contain number of messages we want to */ int full; /* list. Added list header k35 */ { int i,new = 0,rtn = 0; struct mhdr *mhdr; extern FILE *tmpfile(); #ifdef LLCMD if(full < 0 || full > m->msgs) full = m->msgs; /* catch the clowns */ #endif if(!m->msgs){ rtn = mbx_msg(m,"You have no mail.\015"); do_prompt(m); /* will fall through to return after else */ }else{ mhdr = m->firsthdr; for(i=0;imsgs;i++){ /* find out how many were unread */ if(!mhdr->status & STATREAD) new++; mhdr = mhdr->next; } sprintf(tmpbuf,"You have %d message%s %d unread.\015", m->msgs,m->msgs > 1 ? "s." : ".", new); if(!full) if(new){ strcat(tmpbuf,"Unread one"); strcat(tmpbuf,new == 1 ? " is:\015" : "s are:\015"); }else{ mbx_msg(m,tmpbuf); do_prompt(m); return(0); } strcat(tmpbuf, " Nr: From: Date & Time: Size: Subject:\015"); mbx_msg(m,tmpbuf); /* prepare a temp file. read_fd will do m->upload = m->upload */ if ((m->upload = tmpfile()) == NULLFILE) return(-1); /* No test for this currently */ mhdr = m->firsthdr; new = 0; /* reuse for first message to show */ #ifdef LLCMD if(full && (full != m->msgs)){ /* user used ll # command */ #ifdef OLD /* eliminated with the header thing above */ fprintf(m->upload,"The last %d %s:\015",full,full > 1 ? "are" : "is"); #endif for(i=m->msgs;i>full;i--,new++) mhdr = mhdr->next; } #endif for(i=new;imsgs;i++,mhdr = mhdr->next) if(!(mhdr->status & STATREAD) || full) fprintf(m->upload,"%s%s%3d %-22s %-16s%5d %s\015", mhdr->status & STATREAD ? "R" : " ", mhdr->status & STATKILL ? "K" : " ",mhdr->msgnr, mhdr->from,mhdr->date,mhdr->size,mhdr->subj); rewind(m->upload); read_fd(m,m->upload); /* will launch a prompt when done */ } return(rtn); /* probably will change to no return value */ } /* Shut down the mailbox communications connection */ static void mbx_disc(m) struct mbx *m; { if(m->mboxwait.state == TIMER_EXPIRE) genlog(m->name,"mbox timeout"); else{ stop_timer(&m->mboxwait); genlog(m->name,"mbox disconnect"); } switch (m->type){ case MBX_AX25: disc_ax25(m->cb.ax25_cb); break; #ifdef NETROM case MBX_NETROM: disc_nr4(m->cb.nr4_cb); break; #endif } } /* If f_name is nul, checks for mail belonging to current mbox user * and sends any mail found. If f_name is supplied, will download * specified file, get command prefixes with public directory - * make sure there are no binaries or monsters in there! * Returns TRUE if successful, FALSE if not. */ static int readany(m,f_name) struct mbx *m; char *f_name; { FILE *anyfile; #ifdef UNIX struct stat statbuf; #endif #ifdef USERWATCH printf("Current mbox user: %s is reading a file.\n",m->name); fflush(stdout); #endif if(f_name[0] == '\0') sprintf(tmpbuf,"%s/%s.txt",mailspool,m->name); else sprintf(tmpbuf,"%s",f_name); #ifdef UNIX /* prevent user from "getting" directory */ /* an alternative is to fopen with file mode "r+" but files have to * be rw to be downloaded. MS-DOS won't fopen a dir name. */ if(stat(tmpbuf,&statbuf) == -1 || statbuf.st_mode & S_IFDIR) return FALSE; #endif if ((anyfile = fopen(tmpbuf,"r")) != NULLFILE){ read_fd(m,anyfile); return TRUE; }else return FALSE; } /* put a duplicated routine here and added tolower() k34 */ void tidy_call(m,addrp) struct mbx *m; char *addrp; { char *cp; if((m->name = (char *)malloc(sizeof(char) * SIZE_NAME)) != NULLCHAR) pax25(m->name,addrp); if((cp = strchr(m->name,'-')) != NULLCHAR) *cp = '\0'; cp = m->name; while(*cp) *cp++ = (char)tolower(*cp); /* k34 */ m->lp = m->line; /* point line pointer at buffer */ } void mbx_incom_common(m,axp,cnt) struct mbx *m; struct ax25_cb *axp; int16 cnt; { struct mbuf *bp, *recv_ax25(); #ifdef SID2 extern struct ax25_addr bbscall; int addreq(); #endif /* add an idle timer to the mailbox */ m->mboxwait.start = MBOXLIFE / MSPTICK; /* 10 minutes */ m->mboxwait.func = (void(*)())mbx_disc; m->mboxwait.arg = (char *)m; start_timer(&m->mboxwait); /* don't need this test if no NETROM, but sure ugly to ifdef it out */ if(axp != NULLAX25){ /* The following is necessary because we didn't know we had a * "real" ax25 connection until a data packet came in. We * can't be spitting banners out at every station who connects, * since they might be a net/rom or IP station. Sorry. * * If ax25 mbxcall is defined, we can respond right away to one * who connects to us using that call - K5JB */ #ifdef SID2 /* if call came with mboxcall, we don't gobble packet */ /* but if it came with our regular call, we do */ if(!addreq(&axp->addr.source,&bbscall)){ bp = recv_ax25(axp,cnt); /* get the initial input */ free_p(bp); /* and throw it away to avoid confusion */ } #else bp = recv_ax25(axp,cnt); free_p(bp); #endif } /* Say hi */ (void)sprintf(tmpbuf,mbbanner,hostname); mbx_msg(m,tmpbuf); #ifdef NETROM if(axp == NULLAX25) genlog(m->name,"N/R mbox connect"); else #endif genlog(m->name,"AX.25 mbox connect"); mailfetch(m); showlist(m,0); /* the 0 is for a partial list - can return an error */ } /* Incoming mailbox session via ax.25 */ void mbx_incom(axp,cnt) register struct ax25_cb *axp; int16 cnt; { struct mbx *m; struct mbuf *recv_ax25(); void ax_tx(); if ((m = newmbx()) == NULLMBX){ /* m->msgs will be 0 */ disc_ax25(axp); /* no memory! disc_ax25() will call lapbstate() */ /* which has axp->s_upcall still = NULLVFP ?? */ return; } m->type = MBX_AX25; /* this is an ax.25 mailbox session */ m->cb.ax25_cb = axp; /* free() used on name on exit */ tidy_call(m,&axp->addr.dest); axp->r_upcall = mbx_rx; axp->s_upcall = mbx_state; axp->t_upcall = ax_tx; /* used for file uploading - in ax25cmd.c */ axp->user = (char *)m; mbx_incom_common(m,axp,cnt); } /* Incoming mailbox session via net/rom */ #ifdef NETROM void mbx_nr4incom(cb) register struct nr4cb *cb; { struct mbx *m; void mbx_nr4rx(), mbx_nr4state(), nr4_tx(); if ((m = newmbx()) == NULLMBX){ disc_nr4(cb); /* no memory! */ return; } m->type = MBX_NETROM; /* mailbox session type is net/rom */ m->cb.nr4_cb = cb; tidy_call(m,&cb->user); cb->r_upcall = mbx_nr4rx; cb->s_upcall = mbx_nr4state; cb->t_upcall = nr4_tx; /* in nr4cmd.c */ cb->puser = (char *)m; mbx_incom_common(m,NULLAX25,0); /* using 2nd arg as a flag here */ } /* receive upcall for net/rom */ /* mbx_nr4rx collects lines, and calls mbx_line when they are complete. */ /* If the lines get too long, it arbitrarily breaks them. */ void mbx_nr4rx(cb,cnt) struct nr4cb *cb; int16 cnt; { struct mbuf *bp; struct mbx *m; m = (struct mbx *)cb->puser; start_timer(&m->mboxwait); /* reset idle timer */ if ((bp = recv_nr4(cb,cnt)) == NULLBUF) return; build_line(m,bp); } /* state upcall for net/rom */ void mbx_nr4state(cb,unused,new) struct nr4cb *cb; int unused, new; { struct mbx *m; m = (struct mbx *)cb->puser; if (new == NR4STDISC){ if(m->msgs) cleanup(m); /* leave mail file alone if we get here */ cb->puser = NULLCHAR; free_mbx(m); } } #endif /* NETROM */ static void newmailfile(m) struct mbx *m; { FILE *mailfile, *bakfile; char *outfile,*infile; struct mhdr *mhdr; int save = 0; char *errormsg = "newmailfile: No memory"; #ifndef VERBOSE char *derrormsg = "newmailfile: Disk error"; #endif int i; for(i=0,mhdr = m->firsthdr;imsgs;i++,mhdr = mhdr->next){ if(mhdr->status & (STATKILL | STATNREAD)){ save = 1; break; } } if(save){ save = 0; /* we'll reuse this to detect no messages to save */ /* No attempt to salvage a bad situation */ if((outfile = (char *)malloc(sizeof(char) * (strlen(mailspool) + strlen(m->name) + 6))) == 0) errorexit(m,errormsg); sprintf(outfile,"%s/%s.txt",mailspool,m->name); if((infile = (char *)malloc(sizeof(char) * (strlen(mailspool) + strlen(m->name) + 6))) == 0){ errorexit(m,errormsg); } sprintf(infile,"%s/%s.bak",mailspool,m->name); /* we'll rename name.txt to name.bak and take input from name.bak */ unlink(infile); /* don't care about error */ if(rename(outfile,infile) != 0) /* Unix equiv is in that file set */ #ifdef VERBOSE errorexit(m,"mail file rename failed"); #else errorexit(m,derrormsg); #endif if((bakfile = fopen(infile,"r")) == NULLFILE) #ifdef VERBOSE errorexit(m,"backup mail file open for read failed"); #else errorexit(m,derrormsg); #endif if((mailfile = fopen(outfile,"w")) == NULLFILE) #ifdef VERBOSE errorexit(m,"new mail file open for write failed"); #else errorexit(m,derrormsg); #endif for(i=0,mhdr = m->firsthdr;imsgs;i++,mhdr = mhdr->next){ if(mhdr->status & STATKILL) continue; if(fseek(bakfile,mhdr->fileptr,SEEK_SET) != 0) #ifdef VERBOSE errorexit(m,"backup mail file seek failed"); #else errorexit(m,derrormsg); #endif /* this is very paranoid */ if(fgets(tmpbuf,MBXLINE,bakfile) == NULLCHAR) #ifdef VERBOSE errorexit(m,"backup file is empty"); #else errorexit(m,derrormsg); #endif /* print that first "From " line */ fprintf(mailfile,"%s",tmpbuf); save = 1; while(fgets(tmpbuf,MBXLINE,bakfile) != NULLCHAR){ if(strncmp(tmpbuf,"From ",5) == 0) break; fprintf(mailfile,"%s",tmpbuf); if(mhdr->status & STATNREAD && strncmp(tmpbuf,"Subje",5) == 0) #if defined(UNIX) || defined(_OSK) fprintf(mailfile,"Status: R\n"); #else fprintf(mailfile,"Status: R\r\n"); #endif } } fclose(mailfile); fclose(bakfile); if(!save) /* nothing saved? - most typical case */ unlink(outfile); free(outfile); free(infile); } /* if save (the first one) */ return; } /* will copy desired message to name.$$$ - leaves it there to peruse later. File descriptor of open file is passed to read_fd for sending */ static FILE * queuemsg(mhdr,m) struct mhdr *mhdr; struct mbx *m; { FILE *txtfile, *tmp_file; char *txtname,*tmpname; if((txtname = (char *)malloc(sizeof(char) * (strlen(mailspool) + strlen(m->name) + 6 ))) == 0) return(NULLFILE); sprintf(txtname,"%s/%s.txt",mailspool,m->name); if((txtfile = fopen(txtname,"r")) == NULLFILE){ free(txtname); return(NULLFILE); } if((tmpname = (char *)malloc(sizeof(char) * (strlen(mailspool) + strlen(m->name) + 6))) == 0){ free(txtname); return(NULLFILE); } /* could use tmpfile() but thought the $$$ file would be interesting */ sprintf(tmpname,"%s/%s.$$$",mailspool,m->name); /* In the following w+t puts \r\r\n in the file */ if((tmp_file = fopen(tmpname,"w+")) == NULLFILE){ free(txtname); free(tmpname); return(NULLFILE); } /* Position pointer and get that first "from" line out of the way */ if(fseek(txtfile,mhdr->fileptr,SEEK_SET) != 0 || fgets(tmpbuf,MBXLINE,txtfile) == NULLCHAR){ fclose(txtfile); free(txtname); free(tmpname); return(NULLFILE); } fprintf(tmp_file,"%s",&tmpbuf[0]); while(fgets(tmpbuf,MBXLINE,txtfile) != NULLCHAR){ if(strncmp(tmpbuf,"From ",5) == 0) break; fprintf(tmp_file,"%s",&tmpbuf[0]); } fflush(tmp_file); rewind(tmp_file); fclose(txtfile); free(txtname); free(tmpname); return(tmp_file); } /* This opens the data file and writes the mail header into it. * Returns 0 if OK, and -1 if not. */ static int mbx_data(m) struct mbx *m; { time_t t, time(); char *ptime(); extern FILE *tmpfile(); extern long get_msgid(); /* note that get_msgid() can fail, but we can notify user later */ if ((m->tfile = tmpfile()) == NULLFILE) return(-1); time(&t); fprintf(m->tfile,"Date: %s",ptime(&t)); /* if we define NOPLAYBBS, BBS forwards don't get special treatment */ #ifndef NOPLAYBBS if (m->tomsgid) fprintf(m->tfile, "Message-Id: <%s@%s>\n", m->tomsgid, hostname); else fprintf(m->tfile,"Message-Id: <%ld@%s>\n",get_msgid(),hostname); #define FANCY_RETURN /* I don't know if we would ever use this or not */ #ifdef FANCY_RETURN fprintf(m->tfile,"From: %s%s%s@%s\nTo: %s\nSubject: %s\n", m->tofrom ? m->tofrom : "", m->tofrom ? "%" : "", m->name, hostname,m->to,m->line); #else fprintf(m->tfile,"From: %s@%s\nTo: %s\nSubject: %s\n", m->tofrom ? m->tofrom : m->name, hostname,m->to,m->line); #endif /* S-Msgtype helps us distinguish such messages to avoid errors in using * "send reply". stype will probably have ' ' most of time (s joe@host) * but may have 'E', for example if user does, send joe@host, no harm */ fprintf(m->tfile,"X-Msgtype: %s %c\n", m->sid & MBX_SID ? "BBS" : "NET Mbox", m->stype); #else /* NOPLAYBBS is defined */ fprintf(m->tfile,"From: %s@%s\nTo: %s\nSubject: %s\n", m->name, hostname,m->to,m->line); fprintf(m->tfile,"X-Msgtype: NET Mbox\n"); #endif fprintf(m->tfile,"\n"); return(0); } /* replacement send command parser. Saved 608 bytes - K5JB */ static int /* "S" already OK, type (T,B,P,' '), if any recorded. */ mbx_to(m) /* Comes here with whole line entact. Returns -1 on error */ struct mbx *m; { char *cp1,*cp2; cp2 = cp1 = m->line; while(*cp1) *cp1++ = (char)tolower(*cp1); /* k34 */ cp1 = m->line; if((cp1 = strchr(cp1,' ')) == NULLCHAR) /* find first space after 's' */ return(-1); while(*cp1 != '\0'&& *cp1 == ' ') /* any more? */ cp1++; /* now should be at recipient */ while(*cp1) /* remove _all_ spaces from rest of line */ if(*cp1 == ' ') /* move recipient to front of line */ cp1++; else *cp2++ = *cp1++; /* k34 */ *cp2 = '\0'; /* *cp2 = *cp1; would do same thing */ cp1 = m->line; /* will test for null line in a moment */ cp2 = tmpbuf; tmpbuf[0] = '\0'; /* k35 - missed this, would accept "S " */ while(*cp1){ /* get to, upto and include '@' */ #ifndef NOPLAYBBS if(*cp1 == '@' || *cp1 == '<' || *cp1 == '$') #else if(*cp1 == '@') #endif break; *cp2++ = *cp1++; /* K34 */ } if(!tmpbuf[0] || tmpbuf[0] == '@') return(-1); /* only had "@...", or send line incomplete */ switch(*cp1){ #ifndef NOPLAYBBS case '<': case '$': *cp2 = '\0'; break; #endif case '@': /* see what is after the '@' */ *cp2++ = '@'; /* wasn't copied earlier */ if(!*(++cp1)) /* only had "tocall@" */ return(-1); while(*cp1){ /* upto next delimiter */ #ifndef NOPLAYBBS if(*cp1 == '<' || *cp1 == '$') break; #endif *cp2++ = *cp1++; } } /* switch */ *cp2 = '\0'; if ((m->to = malloc(strlen(tmpbuf) + 1)) == NULLCHAR) return(-1); /* no room for to address */ strcpy(m->to,tmpbuf); #ifndef NOPLAYBBS if(*cp1 == '<'){ cp2 = tmpbuf; /* reset target pointer */ if(!*(++cp1)) /* only had "<" */ return(-1); while(*cp1 && *cp1 != '$') /* see what is after the '<' */ *cp2++ = *cp1++; *cp2 = '\0'; if (cp2 == tmpbuf || (m->tofrom = malloc(strlen(tmpbuf) + 1)) == NULLCHAR) return(-1); /* no tofrom or no room for tofrom address */ strcpy(m->tofrom,tmpbuf); } if(*cp1 == '$'){ cp2 = tmpbuf; /* reset target pointer */ while(*cp1){ /* see what is after the '$' assume BBS won't jack */ *cp2++ = *cp1++; /* around with us */ } *cp2 = '\0'; if ((m->tomsgid = malloc(strlen(tmpbuf) + 1)) == NULLCHAR) return(-1); /* no room for BID */ strcpy(m->tomsgid,tmpbuf); } #endif return(0); } static int mbx_line(m) /* returns -1 if there is a disc to dump */ struct mbx *m; /* receive buffers */ { int do_cmd(), do_subj(), do_data(); switch(m->state){ case MBX_SEND: /* user sent a character during download */ if(m->upload != NULLFILE){ /* t_upcall sets NULLFILE when finished */ #if defined(_OSK) && !defined(_UCC) tmpclose(m->upload); #else #ifdef UNIX if(pclose(m->upload) < 0) /* only needed in case of a directory */ #endif /* read in Unix which uses a pipe */ fclose(m->upload); #endif m->upload = NULLFILE; /* do_prompt daemon will clean up timer */ free(m->ufile); mbx_msg(m,"\015Interrupted at your request.\015"); } /* rethink this - seems inconsistent to be outside if() above */ if(m->prompter.state != TIMER_STOP) stop_timer(&m->prompter); m->promptwait = 0; m->state = MBX_CMD; /* this state means send was completed */ do_prompt(m); return(0); case MBX_CMD: return(do_cmd(m)); case MBX_SUBJ: return(do_subj(m)); case MBX_DATA: return(do_data(m)); /* m->state set to MBX_DISC by read_fd if cb->state != 0 -1 is needed to * dump queued buffers */ case MBX_DISC: return(-1); } return(0); /* shouldn't get here */ } static int /* only return -1 on disconnect */ do_cmd(m) struct mbx *m; { #ifdef NETROM void nr4_session(); #endif #ifdef SHOWNODES register struct nrroute_tab *rp; char buf[16]; #endif #ifdef AX25_HEARD char *pp; extern char *homedir; extern char *buildheard(); #endif /* 40 is way much for tempstr1. It only has filename */ char tempstr1[40]; /* suspect tmpbuf[] would be safe. */ char tempstr2[40]; /* only used for filedir() */ int times, j, i = 0; FILE *d_file; struct mhdr *mhdr; /* temporary message header pointer */ int atoi(); void ax_session(), mbx_disc(); #define WHAT #ifdef WHAT if(m->line[0] == 'w' || m->line[0] == 'W'){ /* make a "what" command */ m->line[0] = 'l'; m->line[1] = 's'; m->line[2] = '\0'; } #endif /* roadmap: we do switch, then do_prompt, then return 0, unless we are * disconnecting or closing mailbox, then we return -1 */ switch (tolower(m->line[0])){ case 'b': /* bye - bye */ if(m->msgs){ newmailfile(m); cleanup(m); } mbx_disc(m); return(-1); /* tell line processor to quit */ case 'c': /* chat */ #ifndef AX_MOTD mbx_msg(m,"Messages not saved. If I don't respond, Disconnect, reconnect and send mail.\015"); #endif stop_timer(&m->mboxwait); if(m->msgs){ newmailfile(m); cleanup(m); } genlog(m->name,"went to chat"); switch (m->type){ case MBX_AX25: m->cb.ax25_cb->user = NULLCHAR; ax_session(m->cb.ax25_cb,0); /* make it a chat session */ break; /* this hands cb->state off to ax_state which */ /* is benign with respect to struct mbx */ #ifdef NETROM case MBX_NETROM: m->cb.nr4_cb->puser = NULLCHAR; nr4_session(m->cb.nr4_cb); break; #endif } free_mbx(m); return(-1); case 'm': sprintf(tmpbuf,"I have mail for: "); times = 0; sprintf(tempstr2,"%s/*.txt",mailspool); /* drat! Hate this! */ for(;;){ filedir(tempstr2,times++,tempstr1); if(tempstr1[0] == '\0') break; for(j=0;j<8;j++) if(tempstr1[j] == '.'){ tempstr1[j] = '\0'; break; } sprintf(&tmpbuf[strlen(tmpbuf)],"%s ",tempstr1); if(strlen(tmpbuf) > 70){ strcat(tmpbuf,"\015"); mbx_msg(m,tmpbuf); tmpbuf[0] = '\0'; } } if(times == 1) strcat(tmpbuf,"Nobody!"); strcat(tmpbuf,"\015"); mbx_msg(m,tmpbuf); break; case 'l': /* l[l n] (mail) or ls (dir) command, with optional */ i = 0; switch(tolower(m->line[1])){ /* arguments */ #ifdef LLCMD case 'l': /* "ll" */ i = g_args(m); /* this will require a space before the number */ i = atoi(&m->line[i]); /* note fall through */ #endif default: /* no second character */ showlist(m,i == 0 ? m->msgs : i); /* show a full list */ return(0); case 's': /* ls command */ i = g_args(m); #ifndef CLOSEDOOR if(m->line[i] == '-' && m->line[i+1] != '\0') /* trapdoor */ d_file = dir(&m->line[i+1],1); else #endif { /* in the following, we will hope that not more than * one user at a time uses tmpbuf */ #ifdef UNIX if(i){ /* Just in case we had a long line from a loose upload */ m->line[MBXLINE - strlen(public) - 2] = '\0'; sprintf(tmpbuf,"%s/%s",public,&m->line[i]); }else sprintf(tmpbuf,"%s",public); /* first stop the .. trick then remove noxious chars */ for(i=0;i' || tmpbuf[i] == '<'){ tmpbuf[i] = '\0'; break; } d_file = dir(tmpbuf,1); #else /* deal with MSDOS */ #define SUBDIR /* this costs us 192 bytes */ #ifdef SUBDIR if(i){ /* First shorten line if necessary */ m->line[MBXLINE - strlen(public) - 6] = '\0'; sprintf(tmpbuf,"%s",&m->line[i]); for(j=0;jline,"%s/%s",public,tmpbuf); if((d_file = dir(m->line,1)) == NULLFILE){ /* then try for a directory - here is where "6" * came from in the truncation above */ sprintf(m->line,"%s/%s/*.*",public,tmpbuf); d_file = dir(m->line,1); } }else #endif { /* for the else above */ /* no arg, just show public directory */ sprintf(m->line,"%s/*.*",public); d_file = dir(&m->line,1); } #endif } /* else normal ls command */ if(d_file != NULLFILE){ read_fd(m,d_file); return(0); }else mbx_msg(m,"Nothing found.\015"); } /* l command (second character) switch */ break; case 'd': /* 'download' - alias added k29 */ case 'g': /* get a file, needs argument */ i = g_args(m); if(!i) mbx_msg(m,"No file specified.\015"); else{ #ifndef CLOSEDOOR if(m->line[i] == '-') /* a little frivolity here */ j = readany(m,&m->line[i+1]); /* read any file, anywhere, */ else /* if you know this */ #endif { sprintf(tmpbuf,"%s/%s",public,&m->line[i]); sprintf(m->line,"%s",tmpbuf); /* readany() reuses tmpbuf */ j = readany(m,m->line); } if(j) return(0); mbx_msg(m,"File not found.\015"); } break; case 'h': if(!(m->line[1] == '\0' || tolower(m->line[3]) == 'p')) /* k35 */ break; /* happens a lot, with "Hello" for example; send huh? */ if(readany(m,helpbox)) return(0); mbx_msg(m,"No help available\015"); break; #ifdef AX25_HEARD case 'j': pp = buildheard(1); /* the '1' is a flag that this is the mailbox */ if(pp == NULLCHAR){ mbx_msg(m,"No heard list available\015"); break; } readany(m,pp); /* won't worry about errors */ free(pp); return(0); /* readany() takes care of next prompt */ #endif case 'k': if(m->msgs == 0) break; i = g_args(m); if(!i && m->msgs > 1) mbx_msg(m,"Follow K with a space and number\015"); else{ j = ((m->msgs == 1) ? 1 : atoi(&m->line[i])); if(j == 0 || j > m->msgs) break; mhdr = m->firsthdr; while(--j) mhdr = mhdr->next; mhdr->status |= STATKILL; sprintf(tmpbuf,"Nr. %d is history after you do \"Bye\"!\015",mhdr->msgnr); mbx_msg(m,tmpbuf); } break; case 'r': if(m->msgs == 0){ mbx_msg(m,"No mail waiting\015"); break; } i = g_args(m); if(!i && m->msgs > 1) mbx_msg(m,"Follow R with a space and number\015"); else{ j = ((m->msgs == 1) ? 1 : atoi(&m->line[i])); if(j == 0 || j > m->msgs) break; mhdr = m->firsthdr; while(--j) mhdr = mhdr->next; if((d_file = queuemsg(mhdr,m)) == NULLFILE) /* see below */ /* fatal -- maybe add recovery? */ errorexit(m,"queuemsg file fail"); read_fd(m,d_file); /* this could be added to queuemsg */ /* if new read we will have to add a line to new file */ if(!mhdr->status & STATREAD) mhdr->status |= (STATREAD | STATNREAD); return(0); } break; case 's': { int badsend = 0; /* Get S-command type (B,P,T, etc.) */ if (m->line[1] == '\0') m->stype = ' '; /* used as a flag later */ else m->stype = toupper(m->line[1]); if (mbx_to(m) == -1){ #ifndef NOPLAYBBS if (m->sid & MBX_SID) mbx_msg(m,"NO\015"); else #endif mbx_msg(m,"Oops! Use: s to, or s to@where\015"); badsend++; }else{ strcpy(tmpbuf,m->to); /* v_a() punches out the '@' k34 */ if (validate_address(tmpbuf) == 0){ #ifndef NOPLAYBBS if (m->sid & MBX_SID) mbx_msg(m, "NO\015"); else #endif mbx_msg(m, "Bad user or host name\015"); free_misc(m); badsend++; } } if (!badsend){ m->state = MBX_SUBJ; #ifndef NOPLAYBBS mbx_msg(m, (m->sid & MBX_SID) ? "OK\015" : "Subject:\015"); #else mbx_msg(m,"Subject:\015"); #endif return(0); } break; } /* encapsulates badsend */ case 'u': domboxdisplay(m,1); /* the 0 indicates local, 1 is remote */ break; case 'v': sprintf(tmpbuf,"This is version %s\015",versionf); mbx_msg(m,tmpbuf); break; #ifndef NOPLAYBBS case '[': /* This is a BBS - say "OK", not "Subject:" */ { if (m->line[strlen(m->line) - 1] == ']'){ /* must be an SID */ m->sid = MBX_SID; #ifdef NOTNEEDED /* declare int len=strlen(m->line) if you use this */ /* Now check to see if this is an RLI board. */ if (len >= 5) /* [RLI] at a minimum */ if (strncmp(&m->line[1],"RLI",3) == 0) m->sid |= MBX_SID_RLI; #endif mbx_msg(m,">\015"); return(0); } break; /* We'll do Huh? */ } case 'f': /* "F>" */ if (m->line[1] == '>' && (m->sid & MBX_SID)){ #ifdef NOTNEEDED /* RLI BBS' expect us to disconnect if we */ /* have no mail for them, which of course */ /* we don't, being rather haughty about our */ /* protocol superiority. */ if (m->sid & MBX_SID_RLI){ mbx_disc(m); return(-1); } else mbx_msg(m,">\015"); return(0); #else mbx_disc(m); /* why hang around, just disconnect */ return(-1); #endif } #endif /* NOPLAYBBS */ /* Otherwise drop through to "huh?" */ default: mbx_msg(m,"Huh?\015"); } /* switch */ do_prompt(m); /* all breaks from switch come here. When file sent, */ return(0); /* with read_fd, prompt handled with timer daemon */ } static int do_subj(m) struct mbx *m; { if (mbx_data(m) == -1){ mbx_msg(m,sorry); do_prompt(m); free_misc(m); m->state = MBX_CMD; return(0); } m->state = MBX_DATA; #ifndef NOPLAYBBS if ((m->sid & MBX_SID) == 0) #endif mbx_msg(m, "Enter message. Finish with /EX or ^Z in first column:\015"); return(0); } static int do_data(m) struct mbx *m; { char *host; if(m->line[0] == 0x1a || strcmp(m->line, "/ex") == 0 || strcmp(m->line, "/EX") == 0){ if((host = strchr(m->to,'@')) == NULLCHAR) host = hostname; /* use our hostname */ else host++; /* use the host part of address */ /* make up full from name for work file */ (void)sprintf(tmpbuf,"%s@%s",m->name,hostname); fseek(m->tfile,0L,0); /* reset to beginning */ if (queuejob((struct tcb *)0,m->tfile,host,m->to,tmpbuf) != 0) mbx_msg(m,sorry); free_misc(m); #if defined(_OSK) && !defined(_UCC) tmpclose(m->tfile); #else fclose(m->tfile); #endif m->tfile = NULLFILE; m->state = MBX_CMD; do_prompt(m); return(0); } /* otherwise, ordinary line */ /* prevent dot only from getting into mail stream (rare) - k35 */ if(m->line[0] == '.' && m->line[1] == '\0') strcat(m->line," "); fprintf(m->tfile,"%s\n",m->line); return(0); } #endif /* AXMBX */ #endif /* AX25 */