home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Pier Shareware 6
/
The_Pier_Shareware_Number_6_(The_Pier_Exchange)_(1995).iso
/
024
/
psi110g.zip
/
MBOXMAIL.C
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-26
|
45KB
|
1,383 lines
/* The are the MAILCMDS */
#include <time.h>
#include <ctype.h>
#ifdef MSDOS
#include <alloc.h>
#endif
#ifdef UNIX
#include <sys/types.h>
#include <sys/stat.h>
#endif
#include "global.h"
#ifdef MAILCMDS
#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 "pktdrvr.h"
#include "ax25.h"
#include "mailbox.h"
#include "ax25mail.h"
#include "nr4mail.h"
#include "cmdparse.h"
#include "mailfor.h"
/* By setting the fp to NULL, we can check in exitbbs()
* wether a tempfile has been closed or not - WG7J
*/
#define MYFCLOSE(x) { fclose(x); x = (FILE *) 0; }
char CcLine[] = "Cc: ";
char Mbwarning[] = "Third Party mail is not permitted.\n";
char InvalidNameChars[] = "?*<>[],;:+=\"";
int MbSent;
int MbRead;
int MbRecvd;
#ifdef MBFWD
int MbForwarded;
#endif
int
dosid(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct mbx *m;
char *cp;
m = (struct mbx *)p;
if(argc == 1)
return 1;
if(argv[1][strlen(argv[1]) - 1] != ']') /* must be an SID */
return 1;
#ifdef notdef
if(m->stype == 'Z' && strncmp(argv[1],"cz",2) == 0) {
/* LAN-LINK's [ZCZ] */
m->sid |= MBX_LL;
return 0;
}
#endif
/* Other bbs's */
m->sid = MBX_SID;
/* Now check to see if this is an RLI board.
* As usual, Hank does it a bit differently from
* the rest of the world.
*/
if(m->stype == 'R' && strncmp(argv[1],"li",2) == 0)/* [RLI] at a minimum */
m->sid |= MBX_RLI_SID;
/* Or maybe it is F6FBB ? */
else if(m->stype == 'F')
m->sid |= MBX_FBB;
/* Check to see if the BBS supports a kludge called "hierarchical
* routing designators."
*
* No need to check for ']' -- it must be there or this is not
* a valid mbox id -- it is checked earlier (fix de OH3LKU)
*
* Sid format is [BBSTYPE-VERSION-OPTIONS]
* check for LAST -, to allow for version portion. - WG7J
*/
if((cp = strrchr(argv[1],'-')) != NULLCHAR) {
cp++;
/* Okay, now parse the options */
if((strchr(cp,'h') != NULLCHAR) && (strchr(cp,'$') != NULLCHAR))
m->sid |= MBX_HIER_SID;
if(strchr(cp,'m') != NULLCHAR)
m->sid |= MBX_MID;
}
return 0;
}
int
doarea(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct mbx *m;
FILE *fp;
char buf[MBXLINE];
m = (struct mbx *) p;
if(argc < 2){
#ifdef USERLOG
if(m->stype == 'N') {
listnewmail(m,0);
return 0;
}
#endif
tprintf("Current message area is: %s\n\n",m->area);
tprintf("Available areas are:\n%-15s",m->name);
if(m->stype == 'F')
tputs(" Your private mail area\n");
else
tputc('\n');
if((fp = fopen(Arealist,READ_TEXT)) == NULLFILE)
return 0;
if(m->stype == 'F')
sendfile(fp,m->user,ASCII_TYPE,0,m);
else {
/* send only the area names, not the description */
while(fgets(buf,MBXLINE,fp) != NULLCHAR) {
if(buf[0] != '#') { /* skip comments */
firsttoken(buf);
tprintf("%s\n",buf);
}
}
tputs("\nType AF to get description of areas\n\n");
}
fclose(fp);
return 0;
} else {
dotformat(argv[1]);
if(!strcmp(m->name,argv[1]) || isarea(argv[1]) ||
((m->privs&SYSOP_CMD) && strpbrk(argv[1],InvalidNameChars)==NULLCHAR
&& *(argv[1]+strlen(argv[1])-1)!='.' )){
changearea(m,argv[1]);
if(m->areatype == PRIVATE)
tputs("You have ");
else
tprintf("%s: ",m->area);
if(m->nmsgs){
#ifdef USERLOG
tprintf("%d message%s - %d new.\n",m->nmsgs,
m->nmsgs == 1 ? " " : "s ", m->newmsgs);
#else
if(m->areatype == PRIVATE)
tprintf("%d message%s - %d new.\n", m->nmsgs,
m->nmsgs == 1 ? " " : "s ", m->newmsgs);
else
tprintf("%d message%s.\n", m->nmsgs,
m->nmsgs == 1 ? "" : "s");
#endif
} else
tputs("0 messages.\n");
} else
tprintf("No such message area: %s\n",argv[1]);
}
return 0;
}
/* subroutine to do the actual switch from one area to another */
/* USERLOGGING added by WG7J */
void
changearea(m,area)
struct mbx *m;
char *area;
{
if (m->area[0]) { /* current area non-null? */
#ifdef USERLOG
setlastread(m);
#endif
closenotes(m);
}
dotformat(area);
strcpy(m->area,area);
/* Check areas first, so regular users loging in with areaname
* cannot gain permission to kill messages in areas
* (if univperm in ftpusers doesn't allow that)
*/
if(isarea(area))
m->areatype = AREA;
else if(!strcmp(m->name,area))
m->areatype = PRIVATE;
else /* Sysop checking someone else's area */
m->areatype = USER;
#ifdef USERLOG
/* only read last read message-id if this is not a bbs,
* current area is a public area and not 'help'
* or area starts with 'sys'
*/
if(!(m->sid & MBX_SID))
if( (strcmp(area,"help") && m->areatype == AREA) || \
!strncmp(m->area,"sys",3) || \
(m->privs & MBX_SYSOP) )
getlastread(m);
#endif
scanmail(m);
}
/* States for send line parser state machine */
#define LOOK_FOR_USER 2
#define IN_USER 3
#define AFTER_USER 4
#define LOOK_FOR_HOST 5
#define IN_HOST 6
#define AFTER_HOST 7
#define LOOK_FOR_FROM 8
#define IN_FROM 9
#define AFTER_FROM 10
#define LOOK_FOR_MSGID 11
#define IN_MSGID 12
#define FINAL_STATE 13
#define ERROR_STATE 14
/* Prepare the addressee. If the address is bad, return -1, otherwise
* return 0
*/
int
mbx_to(argc,argv,p)
int argc;
char *argv[];
void *p;
{
char *cp;
int state, i;
char *user, *host, *from, *msgid;
int userlen = 0, hostlen = 0, fromlen = 0, msgidlen = 0;
struct mbx *m;
m = (struct mbx *)p;
/* Free anything that might be allocated
* since the last call to mbx_to() or mbx_reply()
*/
free(m->to);
m->to = NULLCHAR;
free(m->tofrom);
m->tofrom = NULLCHAR;
free(m->tomsgid);
m->tomsgid = NULLCHAR;
free(m->origto);
m->origto = NULLCHAR;
free(m->origbbs);
m->origbbs = NULLCHAR;
free(m->subject);
m->subject = NULLCHAR;
free(m->date);
m->date = NULLCHAR;
if(argc == 1)
return -1;
i = 1;
cp = argv[i];
state = LOOK_FOR_USER;
while(state < FINAL_STATE){
#ifdef MBDEBUG
tprintf("State is %d, char is %c\n", state, *cp);
#endif
switch(state){
case LOOK_FOR_USER:
if(*cp == '@' || *cp == '<' || *cp == '$'){
state = ERROR_STATE; /* no user */
} else {
user = cp; /* point at start */
userlen++; /* start counting */
state = IN_USER;
}
break;
case IN_USER:
switch(*cp){
case '\0':
state = AFTER_USER; /* done with username */
break;
case '@':
state = LOOK_FOR_HOST; /* hostname should follow */
break;
case '<':
state = LOOK_FOR_FROM; /* from name should follow */
break;
case '$':
state = LOOK_FOR_MSGID; /* message id should follow */
break;
default:
userlen++; /* part of username */
}
break;
case AFTER_USER:
switch(*cp){
case '@':
state = LOOK_FOR_HOST; /* hostname follows */
break;
case '<':
state = LOOK_FOR_FROM; /* fromname follows */
break;
case '$':
state = LOOK_FOR_MSGID; /* message id follows */
break;
default:
state = ERROR_STATE;
}
break;
case LOOK_FOR_HOST:
if(*cp == '@' || *cp == '<' || *cp == '$'){
state = ERROR_STATE;
break;
}
if(*cp == '\0')
break;
host = cp;
hostlen++;
state = IN_HOST;
break;
case IN_HOST:
switch(*cp){
case '\0':
state = AFTER_HOST; /* found user@host */
break;
case '@':
state = ERROR_STATE; /* user@host@? */
break;
case '<':
state = LOOK_FOR_FROM; /* fromname follows */
break;
case '$':
state = LOOK_FOR_MSGID; /* message id follows */
break;
default:
hostlen++;
}
break;
case AFTER_HOST:
switch(*cp){
case '@':
state = ERROR_STATE; /* user@host @ */
break;
case '<':
state = LOOK_FOR_FROM; /* user@host < */
break;
case '$':
state = LOOK_FOR_MSGID; /* user@host $ */
break;
default:
state = ERROR_STATE; /* user@host foo */
}
break;
case LOOK_FOR_FROM:
if(*cp == '@' || *cp == '<' || *cp == '$'){
state = ERROR_STATE;
break;
}
if(*cp == '\0')
break;
from = cp;
fromlen++;
state = IN_FROM;
break;
case IN_FROM:
switch(*cp){
case '\0':
state = AFTER_FROM; /* user@host <foo */
break;
case '<':
state = ERROR_STATE; /* user@host <foo< */
break;
case '$':
state = LOOK_FOR_MSGID; /* message id follows */
break;
default:
fromlen++;
}
break;
case AFTER_FROM:
switch(*cp){
case '@': /* user@host <foo @ */
case '<': /* user@host <foo < */
state = ERROR_STATE;
break;
case '$':
state = LOOK_FOR_MSGID; /* user@host <foo $ */
break;
default:
state = ERROR_STATE; /* user@host foo */
}
break;
case LOOK_FOR_MSGID:
if(*cp == '\0')
break;
msgid = cp;
msgidlen++;
state = IN_MSGID;
break;
case IN_MSGID:
if(*cp == '\0')
state = FINAL_STATE;
else
msgidlen++;
break;
default:
/* what are we doing in this state? */
state = ERROR_STATE;
}
if(*(cp) == '\0'){
++i;
if(i < argc)
cp = argv[i];
else break;
} else
++cp;
}
if(state == ERROR_STATE || state == LOOK_FOR_HOST
|| state == LOOK_FOR_FROM || state == LOOK_FOR_MSGID)
return -1; /* syntax error */
m->to = mallocw(userlen + hostlen + 2);
strncpy(m->to, user, userlen);
m->to[userlen] = '\0';
if(hostlen){
m->to[userlen] = '@';
strncpy(m->to + userlen + 1, host, hostlen);
m->to[userlen + hostlen + 1] = '\0';
}
if(fromlen){
m->tofrom = mallocw(fromlen + 1);
strncpy(m->tofrom, from, fromlen);
m->tofrom[fromlen] = '\0';
}
if(msgidlen){
m->tomsgid = mallocw(msgidlen + 1);
strncpy(m->tomsgid, msgid, msgidlen);
m->tomsgid[msgidlen] = '\0';
}
return 0;
}
/* This opens the data file and writes the mail header into it.
* Returns 0 if OK, and -1 if not.
*/
int
mbx_data(m,cclist,extra)
struct mbx *m;
struct list *cclist; /* list of carbon copy recipients */
char *extra; /* optional extra header lines */
{
time_t t;
struct list *ap;
int cccnt = 0;
#ifdef notdef
time(&t);
/*These 2 lines get added again when the smtp-server handles the mail
*not really needed - WG7J
*/
fprintf(m->tfile,Hdrs[RECEIVED]);
if(m->tofrom != NULLCHAR)
fprintf(m->tfile,"from %s ",m->name);
fprintf(m->tfile,"by %s (%s)\n\tid AA%ld ; %s",
Hostname, Version, get_msgid(),ptime(&t));
#endif
/* If m->date is set, use this one (comes from bbs-forwarded mail) */
if(m->date != NULLCHAR)
fprintf(m->tfile,"%s%s",Hdrs[DATE],m->date);
else {
time(&t);
fprintf(m->tfile,"%s%s",Hdrs[DATE],ptime(&t));
}
/* Bulletin ID, if any */
fprintf(m->tfile,Hdrs[MSGID]);
if(m->tomsgid)
fprintf(m->tfile,"<%s@%s.bbs>\n", m->tomsgid, m->name);
else
fprintf(m->tfile,"<%ld@%s>\n",get_msgid(), Hostname);
/* From : , could use 'real bbs address', if origbbs is set */
fprintf(m->tfile,Hdrs[FROM]);
if(m->tofrom) { /* BBS style '< call' */
if(m->origbbs != NULLCHAR)
fprintf(m->tfile,"%s@%s\n",m->tofrom,m->origbbs);
else
fprintf(m->tfile,"%s%%%s.bbs@%s\n",m->tofrom, m->name, Hostname);
} else {
if(m->origbbs != NULLCHAR)
fprintf(m->tfile,"%s@%s\n",m->name,m->origbbs);
else {
int found = 0;
char *cp,*cp2;
FILE *fp;
char line[128];
if((fp = fopen(Pdbase,READ_TEXT)) != NULLFILE) {
while(fgets(line,128,fp) != NULLCHAR) {
rip(line);
cp = skipwhite(line);
if(*cp == '#')
continue;
/* Now find end of fist entry */
cp2 = cp;
while(*cp2 && *cp2 != ' ' && *cp2 != '\t')
cp2++;
if(*cp2 == '\0') /* No additional data */
continue;
*cp2 = '\0'; /* terminate first entry */
if(!stricmp(cp,m->name)) {
/* Found one, now get the name */
cp = skipwhite(++cp2);
if(*cp) {
found = 1;
fprintf(m->tfile,"%s <%s@%s>\n",cp,m->name,Hostname);
}
}
}
fclose(fp);
}
if(!found)
fprintf(m->tfile,"%s@%s\n",m->name,Hostname);
}
}
#if defined USERLOG && defined REGISTER
if((m->sid & MBX_REPLYADDR) && m->IPemail)
fprintf(m->tfile,"%s%s\n",Hdrs[REPLYTO],m->IPemail);
#endif /* REPLY-TO HEADER */
fprintf(m->tfile,"%s%s\n",Hdrs[TO],m->origto != NULLCHAR ? m->origto : m->to);
/* Write Cc: line */
for(ap = cclist; ap != NULLLIST; ap = ap->next) {
if(cccnt == 0){
fprintf(m->tfile,"%s",Hdrs[CC]);
cccnt = 4;
}
else {
fprintf(m->tfile,", ");
cccnt += 2;
}
if(cccnt + strlen(ap->val) > 80 - 3) {
fprintf(m->tfile,"\n ");
cccnt = 4;
}
fputs(ap->val,m->tfile);
cccnt += strlen(ap->val);
}
if(cccnt)
fputc('\n',m->tfile);
fprintf(m->tfile,"%s%s\n",Hdrs[SUBJECT],m->subject);
if(!isspace(m->stype) && ((m->stype != 'R' && m->stype != 'F') ||
(m->sid & MBX_SID) !=0))
fprintf(m->tfile,"%s%c\n", Hdrs[BBSTYPE],m->stype);
#ifdef notdef
/*not really needed, the 'From <user%fwdbbs@host>' shows this too!*/
/* Also store the 'real smtp from' address */
if((m->tofrom != NULLCHAR) && (m->origbbs != NULLCHAR))
fprintf(m->tfile,"%s%s%%%s@%s\n",Hdrs[XFROM],m->tofrom,m->name, Hostname);
#endif
if(extra != NULLCHAR)
fprintf(m->tfile,extra);
return 0;
}
/* Returns true if string is in history file or if string appears to be a
* message id generated by our system.
*/
int
msgidcheck(string)
char *string;
{
FILE *fp;
char *cp,buf[LINELEN];
if(string == NULLCHAR)
return 0;
/* BID's that we have generated ourselves are not kept in the history
* file. Such BID's are in the nnnn_hhhh form, where hhhh is a part of
* our hostname, truncated so that the BID is no longer than 11
* characters.
*/
if((cp = strchr(string,'_')) != NULLCHAR && *(cp+1) != '\0' &&
strnicmp(cp+1,Hostname,strlen(cp+1)) == 0)
return 1;
if((fp = fopen(Historyfile,READ_TEXT)) == NULLFILE)
return 0;
while(fgets(buf,LINELEN,fp) != NULLCHAR) {
firsttoken(buf);
if(stricmp(string,buf) == 0) { /* found */
fclose(fp);
return 1;
}
}
fclose(fp);
return 0;
}
/* Attempt to determine if this is third-pary mail. */
int
thirdparty(m)
struct mbx *m;
{
char buf[MBXLINE], *cp, *rp;
FILE *fp;
if(strchr(m->to,'@') != NULLCHAR || strchr(m->to,'%') != NULLCHAR
|| strchr(m->to,'!') != NULLCHAR)
return 0;
rp = strdup(Hostname);
if((cp = strchr(rp, '.')) != NULLCHAR)
*cp = '\0';
if(stricmp(m->to,rp) == 0){
free(rp);
return -1;
}
free(rp);
if(stricmp(m->to,"sysop") == 0)
return -1;
if((fp = fopen(Arealist,READ_TEXT)) == NULLFILE)
return 0;
while(fgets(buf,MBXLINE,fp) != NULLCHAR){
/* The first word on each line is all that matters */
firsttoken(buf);
if(stricmp(m->to,buf) == 0){
fclose(fp);
return -1;
}
}
fclose(fp);
return 0;
}
/* Move messages from current area to another */
int
dombmovemail(argc,argv,p)
int argc;
char *argv[];
void *p;
{
long pos;
int num,i,j;
int move[NARG];
char *to;
struct mbx *m;
char *cp;
FILE * Mfile; /* file to move to */
int not_area; /* is to-file an area or a regular file? */
struct let *cmsg;
int thisone;
int start;
int end;
char *area;
struct mailindex ind;
char buf[MBXLINE];
m = (struct mbx *)p;
if(argc == 1) {
tputs("Syntax: MM area - moves current message\n"
" MM n1 [n2...] area - move message n1 (n2...)\n");
return 0;
}
if(argc == 2) {
/* NO message #, use current message */
num = 1;
to = argv[1];
move[0] = m->current;
} else {
/* See if x - y format was used and use a for i = x to y loop */
if(argv[2][0] == '-') {
num=0;
start = atoi(argv[1]);
end = atoi(argv[3]);
if(start < 0 || start > m->nmsgs || end < 0 || end > m->nmsgs ) {
tprintf(Badmsg,start);
start = end+1;
}
for(i=start;i<=end;i++) {
if((move[num]=i) != 0 ) {
if(move[num] <= m->nmsgs)
num++;
} else
tprintf(Badmsg,argv[i]);
} /* endfor */
} else {
/* Scan all message # to move */
num=0;
for(i=1;i<argc-1;i++) {
if( (move[num]=atoi(argv[i])) != 0 ) {
if(move[num] <= m->nmsgs)
num++;
} else
tprintf(Badmsg,argv[i]);
}
}
to = argv[argc-1];
}
#ifdef UNIX
if (*to == '/') { /* not area if begins with slash */
#else
if (*to == '/' || *to == '\\' || *(to+1) == ':') { /* not area if begins with slash or drive spec */
#endif
not_area=1;
strncpy(buf, to, sizeof(buf)); buf[sizeof(buf)-1] = '\0';
}
else {
int c;
not_area=0;
dotformat(to);
if (!isarea(to)) {
tprintf("%s is not a public area... Are you sure? ",to);
if(charmode_ok(m))
c = tkeywait("Move(N=no)?",0);
else /* For AX.25 and NET/ROM connects */
c = mykeywait("Move(N=No)?",m);
if(c == -1 || c == 'n' || c == 'N') {
tputs("Aborted.\n");
return 0;
}
} /* endif */
dirformat(to);
/* Now try to lock the destination file */
if(mlock(Mailspool,to) == -1) {
tprintf("Can't lock '%s', please try later\n",to);
return 0;
}
sprintf(buf,"%s/%s.txt",Mailspool,to);
}
/* open the destination file for appending, and set file pos for ftell() */
if( ((Mfile=fopen(buf,"a+")) == NULLFILE) || fseek(Mfile, 0L, SEEK_END)) {
tprintf("Can't open/seek '%s'\n",buf);
if(!not_area) rmlock(Mailspool,to);
return 0;
}
/* Open the mailbox file for reading */
area = strdup(m->area);
dirformat(area);
sprintf(buf,"%s/%s.txt",Mailspool,area);
if((m->mfile=fopen(buf,"rt")) == NULLFILE) {
tprintf("Can't open '%s'\n",buf);
fclose(Mfile);
if(!not_area) rmlock(Mailspool,to);
free(area);
return 0;
}
memset(&ind,0,sizeof(struct mailindex));
/* Okay, let's do the work */
for(i=0;i<num;i++) {
thisone = move[i];
cmsg = &m->mbox[thisone];
/* find start of this message */
fseek(m->mfile,cmsg->start,0);
/* Get the index for this message */
get_index(thisone,area,&ind);
/* now read this message */
fgets(buf,MBXLINE,m->mfile); /* The 'From ' line */
pos = ftell(Mfile);
fputs(buf,Mfile);
while(fgets(buf,MBXLINE,m->mfile)!= NULL) {
if(!strncmp(buf,"From ",5))
break;
fputs(buf,Mfile);
}
if (!not_area) {
/* Update the index with the new message */
ind.size = ftell(Mfile) - pos;
if (write_index(to,&ind) == -1)
log(m->user, "index update failed for %s", to);
}
if((m->stype == 'C') || (m->stype == 'c')) {
tprintf("Message %d copied...\n",thisone);
} else {
/* delete this message */
cmsg->status |= BM_DELETE;
m->change = 1;
tprintf("Message %d moved...\n",thisone);
}
}
fclose(Mfile);
free(area);
fclose(m->mfile);
m->mfile = NULL;
if(!not_area) rmlock(Mailspool,to);
return 0;
}
/*Some additional security - WG7J
*NO_3PARTY = disallow all 3rd party mail
*NO_SENDCMD = only allow mail to sysop
*/
int
dosend(argc,argv,p)
int argc;
char *argv[];
void *p;
{
int cccnt = 0, fail = 0;
char *host, *cp, fullfrom[MBXLINE], sigwork[LINELEN], *rhdr = NULLCHAR;
struct list *ap, *cclist = NULLLIST;
struct mbx *m;
FILE *fp;
#ifdef notdef
time_t now;
#endif
int done = 0;
char *cp2;
int c;
#ifdef RLINE
struct tm t;
#define ODLEN 16
#define OBLEN 32
char tmpline[MBXLINE];
char fwdbbs[NUMFWDBBS][FWDBBSLEN+1];
int myfwds = 0;
int i;
int zulu;
int check_r = 0;
int found_r = 0;
char origdate[ODLEN];
char origbbs[OBLEN];
int loops = 0;
char Me[15];
origdate[0] = '\0';
origbbs[0] = '\0';
#endif
m = (struct mbx *)p;
if((m->stype != 'R' || (m->sid & MBX_SID)) && mbx_to(argc,argv,m)
== -1){
tputs((m->sid & MBX_SID) ? "NO - syntax error\n" : \
"S command syntax error - format is:\n" \
"S[C|F] name [@ host] [< from_addr] [$bulletin_id]\n" \
"SR [number]\n");
#ifdef MAILERROR
mail_error("%s: MBOX S syntax error - %s\n",m->name,cmd_line(argc,argv,m->stype));
#endif
return 0;
}
/*Check for send permission */
if(m->privs & NO_SENDCMD) { /*is this to 'SYSOP' or 'sysop' ?*/
if(stricmp(m->to,"sysop")) {
tputs((m->sid & MBX_SID) ? "NO - permission denied\n" : \
"Sorry, only mail to 'sysop' allowed!\n");
#ifdef MAILERROR
mail_error("%s: no mail permission - %s\n",m->name,m->to);
#endif
return 0;
}
}
/* Check for a BID on bulletins from other bbs's - WG7J */
if((m->sid & MBX_SID) && !NoBid &&
(m->stype == 'B') && (m->tomsgid == NULLCHAR)) {
tputs("NO - No BID!\n");
log(m->user,"MBOX %s: SB without BID - %s",m->name,m->to);
#ifdef MAILERROR
mail_error("MBOX %s: SB without BID - %s",m->name,m->to);
#endif
return 0;
}
if(m->stype != 'R' && msgidcheck(m->tomsgid)) {
if(m->sid & MBX_SID)
tputs("NO - ");
tprintf("Already have %s\n",m->tomsgid);
return 0;
}
if(m->stype == 'R' && !(m->sid & MBX_SID) &&
mbx_reply(argc,argv,m,&cclist,&rhdr) == -1) {
tputs("Can not reply\n");
return 0;
}
if((cp = rewrite_address(m->to)) != NULLCHAR)
if(strcmp(m->to,cp) != 0){
m->origto = m->to;
m->to = cp;
}
else
free(cp);
/* refuse any mail that gets rewritten into 'refuse' - WG7J */
if(!strcmp(m->to,"refuse")) {
tputs((m->sid & MBX_SID) ? "NO - refused\n" : \
"Bad user or hostname, please mail 'sysop' for help\n");
return 0;
}
if( (!ThirdParty && !(m->privs & SYSOP_CMD)) || (m->privs & NO_3PARTY) )
if(thirdparty(m) == 0){
tputs(Mbwarning);
#ifdef MAILERROR
mail_error("%s: 3rd party mail refused - %s\n",m->name,m->to);
#endif
return 0;
}
/* Send the new 'To:' line to sysops only - WG7J */
if((m->privs&SYSOP_CMD) && (m->origto != NULLCHAR || m->stype == 'R') \
&& !(m->sid & MBX_SID))
tprintf("To: %s\n", m->to);
if(validate_address(m->to) == 0){
tputs((m->sid & MBX_SID) ? "NO - bad address\n" : \
"Bad user or hostname, please mail 'sysop' for help\n");
free(rhdr);
del_list(cclist);
/* We don't free any more buffers here. They are freed upon
* the next call to mbx_to() or to domboxbye()
*/
return 0;
}
/* Display the Cc: line (during SR command) */
for(ap = cclist; ap != NULLLIST; ap = ap->next) {
if(cccnt == 0){
tprintf("%s",Hdrs[CC]);
cccnt = 4;
}
else {
tputs(", ");
cccnt += 2;
}
if(cccnt + strlen(ap->val) > 80 - 3) {
tputs("\n ");
cccnt = 4;
}
tputs(ap->val);
cccnt += strlen(ap->val);
}
if(cccnt)
tputc('\n');
/* If the the command was 'SC' then read the Cc: list now - WG7J */
if((m->stype == 'C') && !(m->sid & MBX_SID)) {
m->stype = 'P'; /* make everything private */
tputs(CcLine);
if(mbxrecvline(m) != -1) {
if(strlen(m->line)) {
if(*m->line == 0x01) { /* CTRL-A, abort */
free(rhdr);
del_list(cclist);
tputs(MsgAborted);
return 0;
}
cp = m->line;
/* get all the Cc addresses, separated by comma's */
while((cp2=strchr(cp,',')) != NULLCHAR) {
*cp2 = '\0';
/*get rid of leading spaces or tabs*/
while(*cp == ' ' || *cp == '\t')
cp++;
if(strlen(cp))
addlist(&cclist,cp,0);
cp = cp2 + 1;
}
/* Do the last or only one */
/* get rid of leading spaces or tabs*/
while(*cp == ' ' || *cp == '\t')
cp++;
if(strlen(cp))
addlist(&cclist,cp,0);
}
} else {
free(rhdr);
del_list(cclist);
return 0;
}
}
/* Now check to make sure we can create the needed tempfiles - WG7J */
if((m->tfile = tmpfile()) == NULLFILE) {
free(rhdr);
del_list(cclist);
/*
tputs((m->sid & MBX_SID) ? "NO - no temp file\n" : \
"Can't create temp file for mail\n");
return 0;
*/
/* instead of saying NO and have the other bbs think we already
* have the message, disconnect !
*/
if(m->sid & MBX_SID)
return -2;
/* tell regualr users about it */
tputs("Can't create temp file for mail\n");
return 0;
}
#ifdef RLINE
/* Only accept R: lines from bbs's */
if((m->sid & MBX_SID)&&(Rdate || Rreturn || Rfwdcheck || Mbloophold)){
/* Going to interpret R:headers,
* we need another tempfile !
*/
if((m->tfp = tmpfile()) == NULLFILE) {
free(rhdr);
del_list(cclist);
/*
tputs("NO - no temp file\n");
return 0;
*/
/* disconnect to avoid the other bbs to think that we already have
* the message !
*/
return -2;
}
/* Now we got enough :-) */
check_r = 1;
Checklock++;
/* Set the call, used in loop detect code - WG7J */
if(Mbloophold) {
pax25(Me,Mycall);
if((cp = strchr(Me,'-')) != NULLCHAR)
*cp = '\0'; /* remove SSID */
}
}
#endif
m->state = MBX_SUBJ;
if(m->stype != 'R' || (m->sid & MBX_SID)) {
tputs((m->sid & MBX_SID) ? "OK\n" : "Subject:\n");
if(mbxrecvline(m) == -1) {
#ifdef RLINE
if(check_r) {
MYFCLOSE(m->tfp);
Checklock--;
}
#endif
return 0;
}
}
else /* Replying to a message */
tprintf("Subject: %s\n",m->line);
m->subject = strdup(m->line);
#ifdef RLINE
if(!check_r) {
#endif
mbx_data(m,cclist,rhdr);
/*Finish smtp headers*/
fprintf(m->tfile,"\n");
#ifdef RLINE
}
#endif
m->state = MBX_DATA;
if(!(m->sid & MBX_SID) && m->stype != 'F')
tprintf("Enter message. %s",Howtoend);
if(m->stype != 'F' || (m->sid & MBX_SID) != 0) {
while(mbxrecvline(m) != -1){
if(m->line[0] == 0x01){ /* CTRL-A */
MYFCLOSE(m->tfile);
#ifdef RLINE
if(check_r)
MYFCLOSE(m->tfp);
#endif
tputs(MsgAborted);
free(rhdr);
del_list(cclist);
return 0;
}
if(m->line[0] != CTLZ && stricmp(m->line, "/ex")) {
#ifdef RLINE
if(check_r) {
/* Check for R: lines to start with */
if(!strncmp(m->line,"R:",2)) { /*found one*/
found_r = 1;
/*Write this line to the second tempfile
*for later rewriting to the real one
*/
fprintf(m->tfp,"%s\n",m->line);
/* Find the '@[:]CALL.STATE.COUNTRY'or
* or the '?[:]CALL.STATE.COUNTRY' string
* The : is optional.
*/
if( ((cp=strchr(m->line,'@')) != NULLCHAR) ||
((cp=strchr(m->line,'?')) != NULLCHAR) ) {
if((cp2=strchr(cp,' ')) != NULLCHAR)
*cp2 = '\0';
if((cp2=strchr(cp,'\n')) != NULLCHAR)
*cp2 = '\0';
if((cp2=strchr(cp,'\t')) != NULLCHAR)
*cp2 = '\0';
/* Some bbs's send @bbs instead of @:bbs*/
if (*++cp == ':')
cp++;
/* if we use 'return addres'
* copy whole 'domain' name
*/
if(Rreturn)
if(strlen(cp) <= OBLEN)
strcpy(origbbs,cp);
/* Optimize forwarding ? */
if(Rfwdcheck || Mbloophold) {
/*if there is a HADDRESS, cut off after '.'*/
if((cp2=strchr(cp,'.')) != NULLCHAR)
*cp2 = '\0';
if(Mbloophold)
/* check to see if this is my call ! */
if(!stricmp(Me,cp))
loops++;
/*cross-check with MyFwds list*/
if(Rfwdcheck) {
for(i=0;i<Numfwds;i++) {
if(!strcmp(MyFwds[i],cp)) {
/*Found one !*/
strcpy(fwdbbs[myfwds++],cp);
break;
}
}
}
}
}
if(Rdate) {
/* Find the 'R:yymmdd/hhmmz' string */
if((cp=strchr(m->line,' ')) != NULLCHAR) {
*cp = '\0';
if(strlen(m->line+2) <= ODLEN)
strcpy(origdate,m->line+2);
}
}
} else {
/* The previous line was last R: line
* so we're done checking
* now write the smtp headers and
* all saved R: lines to the right tempfile
*/
check_r = 0;
Checklock--;
/*Did we actually find one ?*/
if(found_r) {
if(Rreturn)
m->origbbs = strdup(strlwr(origbbs));
if(Rdate) {
if((cp=strchr(origdate,'/')) != NULLCHAR) {
if((*(cp+5) == 'z') || (*(cp+5) == 'Z')) {
*(cp+5) = '\0';
zulu = 1;
}
t.tm_min = atoi(cp+3);
*(cp+3) = '\0';
t.tm_hour = atoi(cp+1);
*cp = '\0';
t.tm_mday = atoi(&origdate[4]);
origdate[4] = '\0';
t.tm_mon = (atoi(&origdate[2]) - 1);
origdate[2] = '\0';
t.tm_year = atoi(origdate);
/* Set the date in rfc 822 format */
m->date = mallocw(40);
sprintf(m->date,"%.2d %s %02d %02d:%02d:00 %.3s\n",
t.tm_mday,
Months[t.tm_mon],
t.tm_year,
t.tm_hour,
t.tm_min,
zulu ? "UTC" : "");
}
}
}
/* Now write the headers,
* possibly adding Xforwarded lines for bulletins,
* or anything that has a BID.
* Add the X-Forwarded lines and loop detect
* headers FIRST,
* this speeds up forwarding...
*/
if(Mbloophold && loops >= Mbloophold)
fprintf(m->tfile,"%sLoop\n",Hdrs[XBBSHOLD]);
if(Rfwdcheck && found_r && \
((m->stype == 'B') || (m->tomsgid)) ){
/*write Xforwarded headers*/
for(i=0;i<myfwds;i++) {
fprintf(m->tfile,"%s%s\n",Hdrs[XFORWARD],fwdbbs[i]);
}
}
/*write regular headers*/
mbx_data(m,cclist,rhdr);
/* Finish smtp headers */
fprintf(m->tfile,"\n");
/* Now copy the R: lines back */
if(found_r) {
rewind(m->tfp);
while(fgets(tmpline,sizeof(tmpline),m->tfp)!=NULLCHAR)
fputs(tmpline,m->tfile);
}
MYFCLOSE(m->tfp);
/* And add this first non-R: line */
fprintf(m->tfile,"%s\n",m->line);
if(m->line[strlen(m->line)-1] == CTLZ)
goto eol_ctlz;
}
} else
#endif
fprintf(m->tfile,"%s\n",m->line);
if(m->line[strlen(m->line)-1] == CTLZ)
goto eol_ctlz;
} else {
eol_ctlz:
#ifdef RLINE
if(check_r) {
/* Hmm, this means we never finished the R: headers
* tmp file still open !
*/
MYFCLOSE(m->tfp);
}
#endif
done = 1; /* To indicate the difference between
* mbxrecvline() returning -1 and /ex ! - WG7J
* Now also used to indicate if the message should
* be sent or not !
*/
/* Now ask users if they want to send this ! - WG7J */
if( Mbsendquery && !(m->sid & MBX_SID)) {
if(m->type == TELNET_LINK || m->type == TIP_LINK)
c = tkeywait("Send(N=no)?",0);
else /* For AX.25 and NET/ROM connects */
c = mykeywait("Send(N=no)?",m);
if(c == -1 || c == 'n' || c == 'N') {
done = 0; /* signal delete of message */
tputs(MsgAborted);
}
}
break; /* all done */
}
}
if(!done) {
/* We did NOT get ^Z or /EX, but mbxrecvline returned -1 !!!
* This means the connection is gone ! - WG7J
* Now can also mean that the user doesn't want to send msg !
*/
MYFCLOSE(m->tfile);
#ifdef RLINE
if(check_r)
MYFCLOSE(m->tfp);
#endif
del_list(cclist);
free(rhdr); /*Just in case*/
return 0;
}
} else {
fprintf(m->tfile,"----- Forwarded message -----\n\n");
msgtofile(m);
fprintf(m->tfile,"----- End of forwarded message -----\n");
}
free(rhdr);
/* Insert customised signature if one is found */
if(!(m->sid & MBX_SID)) { /* not a forwarding BBS */
sprintf(sigwork,"%s/%s.sig",Signature,
m->tofrom ? m->tofrom : m->name);
if((fp = fopen(sigwork,READ_TEXT)) != NULLFILE){
while(fgets(sigwork,LINELEN,fp) != NULLCHAR)
fputs(sigwork,m->tfile);
fclose(fp);
}
}
if((host = strrchr(m->to,'@')) == NULLCHAR) {
host = Hostname; /* use our hostname */
if(m->origto != NULLCHAR) {
/* rewrite_address() will be called again by our
* SMTP server, so revert to the original address.
*/
free(m->to);
m->to = m->origto;
m->origto = NULLCHAR;
}
}
else
host++; /* use the host part of address */
/* make up full from name for work file */
if(m->tofrom != NULLCHAR)
sprintf(fullfrom,"%s%%%s@%s",m->tofrom, m->name, Hostname);
else
sprintf(fullfrom,"%s@%s",m->name,Hostname);
if(cclist != NULLLIST && stricmp(host,Hostname) != 0) {
fseek(m->tfile,0L,0); /* reset to beginning */
fail = queuejob(m->tfile,Hostname,cclist,fullfrom);
del_list(cclist);
cclist = NULLLIST;
}
addlist(&cclist,m->to,0);
fseek(m->tfile,0L,0);
fail += queuejob(m->tfile,host,cclist,fullfrom);
del_list(cclist);
MYFCLOSE(m->tfile);
if(fail){
if(!(m->sid & MBX_SID)) /* only when we're not a bbs */
tputs("Couldn't queue msg!\n");
} else {
if(m->sid & MBX_SID)
MbRecvd++;
else {
tputs("Msg queued\n");
MbSent++;
}
#ifdef notdef
/* BID is now saved in the smtp server ! - WG7J */
if(m->tomsgid != NULLCHAR && \
(fp = fopen(Historyfile,APPEND_TEXT)) != NULLFILE) {
/* Timestamp added to allow automatic expiry of bid file - WG7J */
time(&now);
fprintf(fp,"%s %ld\n",m->tomsgid,now); /* Save BID */
fclose(fp);
}
#endif
}
/* Instead of kicking off the smtp now, let it happen in a short time.
* That way the user gets the prompt back immediately, and the smtp kick
* will run when the user most likely is working on typing the next command.
* this *should* improve the user's perception of system's speed, and
* might speed up bbs forwarding a bit too... :-) - WG7J
*/
{
#define WAITTM 5000L
extern struct timer Smtpcli_t;
int32 t,orig_dur;
stop_timer(&Smtpcli_t);
orig_dur = Smtpcli_t.duration;
t = read_timer(&Smtpcli_t);
if(t <= 0 || t > WAITTM)
set_timer(&Smtpcli_t,WAITTM); /* set timer duration */
if(Smtpcli_t.func == NULL) { /* in case not set yet */
Smtpcli_t.func = (void (*)__ARGS((void*)))smtptick;/* what to call on timeout */
Smtpcli_t.arg = NULL; /* dummy value */
}
start_timer(&Smtpcli_t); /* and fire it up */
Smtpcli_t.duration = orig_dur; /* then back to previous interval */
}
#ifdef notdef
smtptick(NULL); /* wake SMTP to send that mail */
#endif
return 0;
}
#endif /* MAILCMDS */