📄 mailbox.c
字号:
/* There are only two functions in this mailbox code that depend on the
* underlying protocol, namely mbx_getname() and dochat(). All the other
* functions can hopefully be used without modification on other stream
* oriented protocols than AX.25 or NET/ROM.
*
*/
#include <stdio.h>
#include <time.h>
#include <ctype.h>
#ifdef UNIX
#include <sys/types.h>
#include <sys/stat.h>
#endif
#include "global.h"
#include "config.h"
#include "timer.h"
#include "proc.h"
#include "socket.h"
#include "usock.h"
#include "session.h"
#include "smtp.h"
#include "dirutil.h"
#include "telnet.h"
#include "ftp.h"
#include "ftpserv.h"
#include "commands.h"
#include "netuser.h"
#include "files.h"
#include "bm.h"
#include "mailbox.h"
#include "ax25mail.h"
#include "nr4mail.h"
#include "cmdparse.h"
/*
#define MBDEBUG
*/
struct mbx *Mbox[NUMMBX];
static char *Motd = NULL;
static int Attended = TRUE; /* default to attended mode */
unsigned Maxlet = BM_NLET;
char Noperm[] = "Permission denied.\n";
char Nosock[] = "Can't create socket\n";
static char Mbbanner[] = "[NET-H$]\nWelcome %s to the %s TCP/IP Mailbox (%s)\n%s";
static char Mbmenu[] = "Current msg# %d : A,B,C,D,E,F,G,H,I,J,K,L,N,R,S,T,U,V,W,Z,? >\n";
static char Longmenu1[] = "(?)help (A)rea (B)ye (C)hat (D)ownload (E)scape (F)inger\n";
static char Longmenu2[] = "(G)ateway (H)elp (I)nfo (J)heard (K)ill (L)ist (N)etrom\n";
static char Longmenu3[] = "(R)ead (S)end (T)elnet (U)pload (V)erbose (W)hat (Z)ap\n";
static char Loginbanner[] = "\nKA9Q NOS (%s)\n\n";
static char Howtoend[] = "Terminate with /EX or ^Z in first column (^A aborts):\n";
static int doarea(int argc,char *argv[],void *p);
static int mbx_getname(struct mbx *m);
/************************************************************************/
/* C O M M A N D S */
/************************************************************************/
static int doattend(int argc,char *argv[],void *p);
static int domaxmsg(int argc,char *argv[],void *p);
static int domotd(int argc,char *argv[],void *p);
static int dotimeout(int argc,char *argv[],void *p);
/* mbox subcommand table */
static struct cmds Mbtab[] = {
"attend", doattend, 0, 0, NULL,
#ifdef AX25
"kick", dombkick, 0, 0, NULL,
#endif
"maxmsg", domaxmsg, 0, 0, NULL,
"motd", domotd, 0, 0, NULL,
"status", domboxdisplay, 0, 0, NULL,
#ifdef AX25
"timer", dombtimer, 0, 0, NULL,
#endif
"tiptimeout", dotimeout, 0, 0, NULL,
NULL,
};
int
dombox(argc,argv,p)
int argc;
char *argv[];
void *p;
{
if(argc == 1)
return domboxdisplay(argc,argv,p);
return subcmd(Mbtab,argc,argv,p);
}
/* if unattended mode is set, ax25, telnet and maybe other sessions will
* be restricted.
*/
static int
doattend(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return setbool(&Attended,"Attended flag",argc,argv);
}
static int
domaxmsg(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return setuns(&Maxlet,"Maximum messages per area",argc,argv);
}
static int
domotd(argc,argv,p)
int argc;
char *argv[];
void *p;
{
if(argc > 2) {
printf("Usage: mbox motd \"<your message>\"\n");
return 0;
}
if(argc < 2) {
if(Motd != NULL)
puts(Motd);
}
else {
if(Motd != NULL){
free(Motd);
Motd = NULL; /* reset the pointer */
}
if(!strlen(argv[1]))
return 0; /* clearing the buffer */
Motd = mallocw(strlen(argv[1])+5);/* allow for the EOL char */
strcpy(Motd, argv[1]);
strcat(Motd, "\n"); /* add the EOL char */
}
return 0;
}
int
domboxdisplay(argc,argv,p)
int argc;
char *argv[];
void *p;
{
int i, j, len;
struct mbx *m;
struct sockaddr fsocket;
static char *states[] = {"LOGIN","CMD","SUBJ","DATA","REVFWD",
"TRYING","FORWARD"};
printf("User State S# Where\n");
for (i = 0; i < NUMMBX; i++){
if((m = Mbox[i]) != NULL){
len = MAXSOCKSIZE;
j = getpeername(fileno(m->user),&fsocket,&len);
printf("%-11s%-9s%-4u%s\n",m->name,
states[m->state],fileno(m->user),
j != -1 ? psocket(&fsocket): "");
}
}
return 0;
}
static int
dotimeout(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return setuns(&Tiptimeout,"Tip connection timeout",argc,argv);
}
/**********************************************************************/
void
listusers(network)
FILE *network;
{
FILE *outsave;
fprintf(network,"\nCurrent remote users:\n");
outsave = stdout;
stdout = network;
domboxdisplay(0,NULL,NULL);
stdout = outsave;
}
struct mbx *
newmbx()
{
int i;
struct mbx *m;
for(i = 0; i < NUMMBX; i++){
if(Mbox[i] == NULL){
m = Mbox[i] = (struct mbx *)callocw(1,sizeof(struct mbx));
m->mbnum = i;
return m;
}
}
/* If we get here, there are no free mailbox sessions */
return NULL;
}
static int
mbx_getname(m)
struct mbx *m;
{
#ifdef AX25
char *cp;
#endif
union sp sp;
struct sockaddr tmp;
char buf[MBXLINE];
int len = MAXSOCKSIZE;
int anony = 0;
int oldmode;
sp.sa = &tmp;
sp.sa->sa_family = AF_LOCAL; /* default to AF_LOCAL */
getpeername(fileno(m->user),&tmp,&len);
m->path = mallocw(MBXLINE);
/* This is one of the two parts of the mbox code that depends on the
* underlying protocol. We have to figure out the name of the
* calling station. This is only practical when AX.25 or NET/ROM is
* used. Telnet users have to identify themselves by a login procedure.
*/
switch(sp.sa->sa_family){
#ifdef AX25
case AF_NETROM:
case AF_AX25:
/* NETROM and AX25 socket address structures are "compatible" */
pax25(m->name,sp.ax->ax25_addr);
cp = strchr(m->name,'-');
if(cp != NULL) /* get rid of SSID */
*cp = '\0';
/* SMTP wants the name to be in lower case */
cp = m->name;
while(*cp){
if(isupper(*cp))
*cp = tolower(*cp);
++cp;
}
anony = 1;
/* Try to find the privileges of this user from the userfile */
if((m->privs = userlogin(m->name,buf,&m->path,MBXLINE,&anony)) == -1)
if((m->privs = userlogin("bbs",buf,&m->path,MBXLINE,&anony)) == -1)
if((m->privs = userlogin("anonymous",buf,&m->path,MBXLINE,
&anony)) == -1){
m->privs = 0;
free(m->path);
m->path = NULL;
}
if(m->privs & EXCLUDED_CMD)
return -1;
return 0;
#endif
case AF_LOCAL:
case AF_INET:
m->state = MBX_LOGIN;
printf(Loginbanner,Hostname);
for(;;){
fputs("login: ",stdout);
if(mbxrecvline(m->user,m->name,sizeof(m->name),-1) == EOF)
return -1;
if(*m->name == '\0')
continue;
printf("Password: %c%c%c",IAC,WILL,TN_ECHO);
oldmode = fmode(m->user,STREAM_BINARY);
if(mbxrecvline(m->user,buf,MBXLINE,-1) == EOF)
return -1;
printf("%c%c%c",IAC,WONT,TN_ECHO);
fmode(m->user,oldmode);
putchar('\n');
#ifdef notdef
/* This is needed if the password was send before the
* telnet no-echo options were received. We neeed to
* flush the eold sequence from the input buffers, sigh
*/
if(socklen(fileno(m->user),0))/* discard any remaining input */
recv_mbuf(fileno(m->user),NULL,0,NULL,0);
#endif
if((m->privs = userlogin(m->name,buf,&m->path,MBXLINE,&anony))
!= -1){
if(anony)
logmsg(fileno(m->user),"MBOX login: %s Password: %s",m->name,buf);
else
logmsg(fileno(m->user),"MBOX login: %s",m->name);
if(m->privs & EXCLUDED_CMD)
return -1;
return 0;
}
printf("Login incorrect\n");
*m->name = '\0'; /* wipe any garbage */
}
}
return 0;
}
/* Incoming mailbox session */
void
mbx_incom(s,t,p)
int s;
void *t;
void *p;
{
struct mbx *m;
struct usock *up;
char *buf[3];
int rval;
FILE *network;
sockowner(s,Curproc); /* We own it now */
if(p == NULL)
network = fdopen(s,"r+t");
else
network = (FILE *)p;
/* Secede from the parent's sockets, and use the network socket that
* was passed to us for both input and output. The reference
* count on this socket will still be 1; this allows the domboxbye()
* command to work by closing that socket with a single call.
* If we return, the socket will be closed automatically.
*/
fclose(stdin);
stdin = fdup(network);
fclose(stdout);
stdout = fdup(network);
logmsg(fileno(network),"open MBOX");
if((m = newmbx()) == NULL){
printf("Too many mailbox sessions\n");
return;
}
m->user = network;
m->escape = 24; /* default escape character is Ctrl-X */
m->type = (int) t;
/* get the name of the remote station */
if(mbx_getname(m) == -1) {
exitbbs(m);
return;
}
m->state = MBX_CMD; /* start in command state */
/* Now say hi */
printf(Mbbanner,m->name,Hostname,Version,
Motd != NULL ? Motd : "");
/* Enable our local message area */
buf[1] = m->name;
doarea(2,buf,m);
printf(Mbmenu,m->current);
while(mbxrecvline(network,m->line,MBXLINE,-1) != EOF){
if((rval = mbx_parse(m)) == -2)
break;
if(rval == 1)
printf("Bad syntax.\n");
if(!(m->sid & MBX_SID) && isnewprivmail(m) > 0L)
printf("You have new mail.\n");
scanmail(m);
printf((m->sid & MBX_SID) ? ">\n" : Mbmenu, m->current);
m->state = MBX_CMD;
}
exitbbs(m);
/* nasty hack! we may have screwed up reference count */
/* by invoking newproc("smtp_send",....); Fudge it! */
if((up = itop(fileno(stdout))) != NULL)
up->refcnt = 1;
fclose(stdout);
}
void
exitbbs(m)
struct mbx *m;
{
closenotes(m);
free(m->to);
free(m->tofrom);
free(m->origto);
free(m->tomsgid);
free(m->path);
free(m->mbox);
Mbox[m->mbnum] = NULL;
free(m);
}
/**********************************************************************/
static int dochat(int argc,char *argv[],void *p);
static int dodownload(int argc,char *argv[],void *p);
static int dombupload(int argc,char *argv[],void *p);
static int dowhat(int argc,char *argv[],void *p);
static int dozap(int argc,char *argv[],void *p);
static int dosend(int argc,char *argv[],void *p);
static int dosid(int argc,char *argv[],void *p);
static int dosysop(int argc,char *argv[],void *p);
static int dostars(int argc,char *argv[],void *p);
static int dombhelp(int argc,char *argv[],void *p);
static int dombtelnet(int argc,char *argv[],void *p);
static int dombfinger(int argc,char *argv[],void *p);
static void gw_alarm(void *p);
static void gw_input(int s,void *notused,void *p);
static void gw_superv(int null,void *proc,void *p);
static int mbx_to(int argc,char *argv[],void *p);
static int mbx_data(struct mbx *m,struct list *cclist,char *extra);
static int msgidcheck(char *string);
static int uuencode(FILE *infile,FILE *outfile,char *infilename);
static struct cmds Mbcmds[] = {
"", doreadnext, 0, 0, NULL,
"area", doarea, 0, 0, NULL,
"send", dosend, 0, 0, NULL,
"read", doreadmsg, 0, 2, "R numbers",
"verbose", doreadmsg, 0, 2, "V numbers",
#ifdef AX25
"jheard", doaxheard, 0, 0, NULL,
#endif
"kill", dodelmsg, 0, 2, "K numbers",
"list", dolistnotes, 0, 0, NULL,
"escape", dombescape, 0, 0, NULL,
"download", dodownload, 0, 2, "D[U] filename",
"upload", dombupload, 0, 2, "U filename",
"what", dowhat, 0, 0, NULL,
"zap", dozap, 0, 2, "Z filename",
#ifdef AX25
"gateway", dogateway, 0, 3, "G interface callsigns",
#endif
"telnet", dombtelnet, 0, 2, "T hostname",
"finger", dombfinger, 0, 0, NULL,
#ifdef NETROM
"netrom", dombnetrom, 0, 0, NULL,
#endif
"chat", dochat, 0, 0, NULL,
"bye", domboxbye, 0, 0, NULL,
"help", dombhelp, 0, 0, NULL,
"info", dombhelp, 0, 0, NULL,
"?", dombhelp, 0, 0, NULL,
"[", dosid, 0, 0, NULL,
#ifdef AX25
"f>", dorevfwd, 0, 0, NULL,
#endif
"@", dosysop, 0, 0, NULL,
"***", dostars, 0, 0, NULL,
NULL, NULL, 0, 0, "Huh?",
};
/* "twocmds" defines the MBL/RLI two-letter commands, eg. "SB", "SP" and so on.
* They have to be treated specially since cmdparse() wants a space between
* the actual command and its arguments.
* "SP FOO" is converted to "s foo" and the second command letter is saved
* in m->stype. Longer commands like "SEND" are unaffected, except for
* commands starting with "[", i.e. the SID, since we don't know what it will
* look like.
*/
static char twocmds[] = "slrd["; /* S,L,R,D are two-letter commands */
int
mbx_parse(m)
struct mbx *m;
{
char *cp;
int i;
char *newargv[2];
/* Translate entire buffer to lower case */
for (cp = m->line; *cp != '\0'; ++cp)
if(isupper(*cp))
*cp = tolower(*cp);
/* Skip any spaces at the begining */
for(cp = m->line;isspace(*cp);++cp)
;
m->stype = ' ';
if(*cp != '\0' && *(cp+1) != '\0')
for(i=0; i<strlen(twocmds); ++i){
if(*cp == twocmds[i] && (isspace(*(cp+2)) || *(cp+2) == '\0'
|| *cp == '[')){
if(islower(*(++cp)))
m->stype = toupper(*cp); /* Save the second character */
else
m->stype = *cp;
*cp = ' ';
break;
}
}
/* See if the input line consists solely of digits */
cp = m->line;
for(cp = m->line;isspace(*cp);++cp)
;
newargv[1] = cp;
for(;*cp != '\0' && isdigit(*cp);++cp)
;
if(*cp == '\0' && strlen(newargv[1]) > 0) {
newargv[0] = "read";
return doreadmsg(2,newargv,(void *)m);
}
else
return cmdparse(Mbcmds,m->line,(void *)m);
}
/* This works like recvline(), but telnet options are answered and the
* terminating newline character is not put into the buffer. If the
* incoming character equals the value of escape, any queued input is
* flushed and -2 returned.
*/
int
mbxrecvline(network,buf,len,escape)
FILE *network;
char *buf;
int len;
int escape;
{
int c, cnt = 0, opt;
if(buf == NULL)
return 0;
fflush(stdout);
while((c = getc(network)) != EOF){
if(c == IAC){ /* Telnet command escape */
if((c = getc(network)) == EOF)
break;
if(c > 250 && c < 255 && (opt = getc(network)) != EOF){
#ifdef foo
switch(c){
case WILL:
printf("%c%c%c",IAC,DONT,opt);
break;
case WONT:
printf("%c%c%c",IAC,DONT,opt);
break;
case DO:
printf("%c%c%c",IAC,WONT,opt);
break;
case DONT:
printf("%c%c%c",IAC,WONT,opt);
}
#endif
/* to be fixed fflush(stdout);*/
continue;
}
if(c != IAC && (c = fgetc(network)) == EOF)
break;
}
/* ordinary character */
if(c == '\r' || c == '\n')
break;
if(c == escape){
if(socklen(fileno(network),0)) /* discard any remaining input */
recv_mbuf(fileno(network),NULL,0,NULL,0);
cnt = -2;
break;
}
*buf++ = c;
++cnt;
if(cnt == len - 1)
break;
}
if(c == EOF && cnt == 0)
return -1;
*buf = '\0';
return cnt;
}
int
domboxbye(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct mbx *m;
m = (struct mbx *)p;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -