1765 lines
44 KiB
C
1765 lines
44 KiB
C
/* 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 <string.h>
|
|
#include <stdio.h>
|
|
#ifdef MSDOS
|
|
#include <dos.h>
|
|
#endif
|
|
#include <time.h>
|
|
#include <ctype.h>
|
|
#ifdef UNIX
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#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 [<line>]]\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;i<m->msgs;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 <k5jb@k5jb>
|
|
*/
|
|
if(strncmp(tmpbuf,"From:",5) == 0){
|
|
/* <user@host> 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;i<sizeof(mhdr->from) - 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;i<sizeof(mhdr->subj) - 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;i<m->msgs;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;i<m->msgs;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;i<m->msgs;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;i<m->msgs;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<strlen(tmpbuf);i++)
|
|
if((tmpbuf[i] == '.' && tmpbuf[i+1] == '.') ||
|
|
tmpbuf[i] == '|' || tmpbuf[i] == ';' ||
|
|
tmpbuf[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;j<strlen(tmpbuf);j++) /* remove any .. */
|
|
if(tmpbuf[j] == '.' && tmpbuf[i+1] == '.'){
|
|
tmpbuf[j] = '\0';
|
|
break;
|
|
}
|
|
sprintf(m->line,"%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 */
|