Commit dfea4511 authored by rswindell's avatar rswindell
Browse files

New feature requested by Jeffs (REGION14):

FidoNet netmail in the normal mail base (data/mail.*) will now be exported to
FTS-1 (*.msg) files automatically. One way in which the FTN netmail can end up
in the mail base is by using the (legacy/runemaster) Web UI. You should also
get the updated savemsg.ssjs if you're going to use this feature.
To disable this feature use the (new) '-c' option.
Normally, the exported msgs will be deleted unless the '-d' option is used in
which case the messages are just marked as "sent", so they won't be exported
again. This feature does not yet support file attachments.

This will likely lead to the SMTP server supporting the sending of FTN netmail.
Apparently we have to find a better way to encode FTN addresses within
RFC2822-compliant header fields first.

If you're using a BSO/FLO-style mailer, this feature works with the '-f' option
so the full path of an outbound netmail may be SMB->*.MSG->PKT. Direct
export to PKT is certainly possible in the future.

Incremented SBBSecho version to 2.30.
parent aa45c5e7
......@@ -313,6 +313,7 @@ add_executable(sbbsecho
userdat.c
rechocfg.c
msg_id.c
getmail.c
)
require_libs(sbbsecho xpdev smblib)
......
......@@ -187,6 +187,7 @@ SBBSECHO_OBJS = \
$(OBJODIR)$(DIRSEP)userdat$(OFILE) \
$(OBJODIR)$(DIRSEP)rechocfg$(OFILE) \
$(OBJODIR)$(DIRSEP)msg_id$(OFILE) \
$(OBJODIR)$(DIRSEP)getmail$(OFILE) \
$(SMB_OBJS)
ECHOCFG_OBJS = \
......
......@@ -67,7 +67,8 @@
smb_t *smb,*email;
long misc=(IMPORT_PACKETS|IMPORT_NETMAIL|IMPORT_ECHOMAIL|EXPORT_ECHOMAIL
|DELETE_NETMAIL|DELETE_PACKETS);
ulong netmail=0;
BOOL export_netmail_option=TRUE;
ulong netmail=0; /* statistic */
char tmp[256],pkt_type=0;
int secure,cur_smb=0;
FILE *fidologfile=NULL;
......@@ -419,19 +420,22 @@ size_t fwrite_crlf(char* buf, size_t len, FILE* fp)
If file is non-zero, will set file attachment bit (for bundles).
Returns 0 on success.
******************************************************************************/
int create_netmail(char *to, char *subject, char *body, faddr_t dest, BOOL file_attached)
int create_netmail(char *to, char *from, char *subject, char *body, faddr_t dest, time_t t, BOOL file_attached)
{
FILE *fstream;
char str[256],fname[MAX_PATH+1];
FILE *fp;
char fname[MAX_PATH+1];
ushort attr=0;
int fmsg;
uint i;
static uint startmsg;
time_t t;
faddr_t faddr;
fmsghdr_t hdr;
struct tm *tm;
if(from==NULL)
from="SBBSecho";
if(to==NULL)
to="Sysop";
if(!startmsg) startmsg=1;
i=matchnode(dest,0);
if(i<cfg.nodecfgs) {
......@@ -444,90 +448,77 @@ int create_netmail(char *to, char *subject, char *body, faddr_t dest, BOOL file_
}
MKDIR(scfg.netmail_dir);
do {
for(i=startmsg;i;i++) {
sprintf(fname,"%s%u.msg",scfg.netmail_dir,i);
if(!fexistcase(fname))
break;
}
if(!i) {
lprintf(LOG_WARNING,"Directory full: %s",scfg.netmail_dir);
return(-1);
}
startmsg=i+1;
if((fstream=fnopen(&fmsg,fname,O_RDWR|O_CREAT))==NULL) {
lprintf(LOG_ERR,"ERROR %u (%s) line %d opening %s",errno,strerror(errno),__LINE__,fname);
return(-1);
}
faddr=getsysfaddr(dest.zone);
memset(&hdr,0,sizeof(fmsghdr_t));
hdr.origzone=faddr.zone;
hdr.orignet=faddr.net;
hdr.orignode=faddr.node;
hdr.origpoint=faddr.point;
hdr.destzone=dest.zone;
hdr.destnet=dest.net;
hdr.destnode=dest.node;
hdr.destpoint=dest.point;
hdr.attr=(FIDO_PRIVATE|FIDO_KILLSENT|FIDO_LOCAL);
if(file_attached)
hdr.attr|=FIDO_FILE;
if(attr&ATTR_HOLD)
hdr.attr|=FIDO_HOLD;
if(attr&ATTR_CRASH)
hdr.attr|=FIDO_CRASH;
sprintf(hdr.from,"SBBSecho");
t=time(NULL);
tm=localtime(&t);
sprintf(hdr.time,"%02u %3.3s %02u %02u:%02u:%02u"
,tm->tm_mday,mon[tm->tm_mon],TM_YEAR(tm->tm_year)
,tm->tm_hour,tm->tm_min,tm->tm_sec);
for(i=startmsg;i;i++) {
sprintf(fname,"%s%u.msg",scfg.netmail_dir,i);
if(!fexistcase(fname))
break;
}
if(!i) {
lprintf(LOG_WARNING,"Directory full: %s",scfg.netmail_dir);
return(-1);
}
startmsg=i+1;
if((fp=fnopen(&fmsg,fname,O_RDWR|O_CREAT))==NULL) {
lprintf(LOG_ERR,"ERROR %u (%s) line %d opening %s",errno,strerror(errno),__LINE__,fname);
return(-1);
}
if(to)
SAFECOPY(hdr.to,to);
faddr=getsysfaddr(dest.zone);
memset(&hdr,0,sizeof(fmsghdr_t));
hdr.origzone=faddr.zone;
hdr.orignet=faddr.net;
hdr.orignode=faddr.node;
hdr.origpoint=faddr.point;
hdr.destzone=dest.zone;
hdr.destnet=dest.net;
hdr.destnode=dest.node;
hdr.destpoint=dest.point;
hdr.attr=(FIDO_PRIVATE|FIDO_KILLSENT|FIDO_LOCAL);
if(file_attached)
hdr.attr|=FIDO_FILE;
if(attr&ATTR_HOLD)
hdr.attr|=FIDO_HOLD;
if(attr&ATTR_CRASH)
hdr.attr|=FIDO_CRASH;
tm=localtime(&t);
sprintf(hdr.time,"%02u %3.3s %02u %02u:%02u:%02u"
,tm->tm_mday,mon[tm->tm_mon],TM_YEAR(tm->tm_year)
,tm->tm_hour,tm->tm_min,tm->tm_sec);
SAFECOPY(hdr.to,to);
SAFECOPY(hdr.from,from);
SAFECOPY(hdr.subj,subject);
fwrite(&hdr,sizeof(fmsghdr_t),1,fp);
fprintf(fp,"\1INTL %hu:%hu/%hu %hu:%hu/%hu\r"
,hdr.destzone,hdr.destnet,hdr.destnode
,hdr.origzone,hdr.orignet,hdr.orignode);
/* Add FSC-53 FLAGS kludge */
fprintf(fp,"\1FLAGS");
if(attr&ATTR_DIRECT)
fprintf(fp," DIR");
if(file_attached) {
if(misc&TRUNC_BUNDLES)
fprintf(fp," TFS");
else
SAFECOPY(hdr.to,"SYSOP");
SAFECOPY(hdr.subj,subject);
fwrite(&hdr,sizeof(fmsghdr_t),1,fstream);
sprintf(str,"\1INTL %hu:%hu/%hu %hu:%hu/%hu\r"
,hdr.destzone,hdr.destnet,hdr.destnode
,hdr.origzone,hdr.orignet,hdr.orignode);
fwrite(str,strlen(str),1,fstream);
/* Add FSC-53 FLAGS kludge */
fprintf(fstream,"\1FLAGS");
if(attr&ATTR_DIRECT)
fprintf(fstream," DIR");
if(file_attached) {
if(misc&TRUNC_BUNDLES)
fprintf(fstream," TFS");
else
fprintf(fstream," KFS");
}
fprintf(fstream,"\r");
fprintf(fp," KFS");
}
fprintf(fp,"\r");
if(hdr.destpoint) {
sprintf(str,"\1TOPT %hu\r",hdr.destpoint);
fwrite(str,strlen(str),1,fstream);
}
if(hdr.origpoint) {
sprintf(str,"\1FMPT %hu\r",hdr.origpoint);
fwrite(str,strlen(str),1,fstream);
}
if(!file_attached || (!(attr&ATTR_DIRECT) && file_attached))
fwrite_crlf(body,strlen(body)+1,fstream); /* Write additional NULL */
else
fwrite("\0",1,1,fstream); /* Write NULL */
fclose(fstream);
} while(!fexistcase(fname));
return(0);
if(hdr.destpoint)
fprintf(fp,"\1TOPT %hu\r",hdr.destpoint);
if(hdr.origpoint)
fprintf(fp,"\1FMPT %hu\r",hdr.origpoint);
if(!file_attached || (!(attr&ATTR_DIRECT) && file_attached))
fwrite_crlf(body,strlen(body)+1,fp); /* Write additional NULL */
else
fwrite("\0",1,1,fp); /* Write NULL */
printf("Created %s\n", fname);
return fclose(fp);
}
/******************************************************************************
......@@ -563,7 +554,7 @@ void file_to_netmail(FILE *infile,char *title,faddr_t addr,char *to)
}
if(ftell(infile)<l)
strcat(buf,"\r\nContinued in next message...\r\n");
create_netmail(to,title,buf,addr,FALSE);
create_netmail(to,/* from: */NULL, title,buf,addr,time(NULL),FALSE);
}
free(buf);
}
......@@ -715,7 +706,7 @@ void netmail_arealist(enum arealist_type type, faddr_t addr, char* to)
}
strListSortAlpha(area_list);
if(!strListCount(area_list))
create_netmail(to,title,"None.",addr,FALSE);
create_netmail(to,/* from: */NULL,title,"None.",addr,time(NULL),FALSE);
else {
FILE* fp;
if((fp=tmpfile())==NULL) {
......@@ -1031,7 +1022,7 @@ void alter_areas(str_list_t add_area, str_list_t del_area, faddr_t addr, char* t
fprintf(nmfile,"%s not found.\r\n",add_area[i]);
}
if(!ftell(nmfile))
create_netmail(to,"Area Change Request","No changes made.",addr,FALSE);
create_netmail(to,/* from: */NULL,"Area Change Request","No changes made.",addr,time(NULL),FALSE);
else
file_to_netmail(nmfile,"Area Change Request",addr,to);
fclose(nmfile);
......@@ -1229,7 +1220,7 @@ void command(char* instr, faddr_t addr, char* to)
fread(buf,l,1,stream);
fclose(stream);
buf[l]=0;
create_netmail(to,"Area Manager Help",buf,addr,FALSE);
create_netmail(to,/* from: */NULL,"Area Manager Help",buf,addr,time(NULL),FALSE);
free(buf);
return;
}
......@@ -1278,7 +1269,7 @@ void command(char* instr, faddr_t addr, char* to)
,(i>=0 && i<cfg.arcdefs)?cfg.arcdef[i].name:p,0);
cfg.nodecfg[node].arctype=i;
sprintf(str,"Compression type changed to %s.",(i>=0 && i<cfg.arcdefs)?cfg.arcdef[i].name:p);
create_netmail(to,"Compression Type Change",str,addr,FALSE);
create_netmail(to,/* from: */NULL,"Compression Type Change",str,addr,time(NULL),FALSE);
return;
}
......@@ -1294,46 +1285,46 @@ void command(char* instr, faddr_t addr, char* to)
if(!stricmp(temp,cfg.nodecfg[node].password)) {
sprintf(str,"Your password was already set to %s."
,cfg.nodecfg[node].password);
create_netmail(to,"Password Change Request",str,addr,FALSE);
create_netmail(to,/* from: */NULL,"Password Change Request",str,addr,time(NULL),FALSE);
return;
}
alter_config(addr,cfg.nodecfg[node].password,temp,1);
sprintf(str,"Your password has been changed from %s to %.25s."
,cfg.nodecfg[node].password,temp);
sprintf(cfg.nodecfg[node].password,"%.25s",temp);
create_netmail(to,"Password Change Request",str,addr,FALSE);
create_netmail(to,/* from: */NULL,"Password Change Request",str,addr,time(NULL),FALSE);
return;
}
if((p=strstr(instr,"RESCAN"))!=NULL) {
export_echomail("",addr);
create_netmail(to,"Rescan Areas"
create_netmail(to,/* from: */NULL,"Rescan Areas"
,"All connected areas carried by your hub have been rescanned."
,addr,FALSE);
,addr,time(NULL),FALSE);
return;
}
if((p=strstr(instr,"ACTIVE"))!=NULL) {
if(!(cfg.nodecfg[node].attr&ATTR_PASSIVE)) {
create_netmail(to,"Reconnect Disconnected Areas"
,"Your areas are already connected.",addr,FALSE);
create_netmail(to,/* from: */NULL,"Reconnect Disconnected Areas"
,"Your areas are already connected.",addr,time(NULL),FALSE);
return;
}
alter_config(addr,0,0,3);
create_netmail(to,"Reconnect Disconnected Areas"
,"Temporarily disconnected areas have been reconnected.",addr,FALSE);
create_netmail(to,/* from: */NULL,"Reconnect Disconnected Areas"
,"Temporarily disconnected areas have been reconnected.",addr,time(NULL),FALSE);
return;
}
if((p=strstr(instr,"PASSIVE"))!=NULL) {
if(cfg.nodecfg[node].attr&ATTR_PASSIVE) {
create_netmail(to,"Temporarily Disconnect Areas"
,"Your areas are already temporarily disconnected.",addr,FALSE);
create_netmail(to,/* from: */NULL,"Temporarily Disconnect Areas"
,"Your areas are already temporarily disconnected.",addr,time(NULL),FALSE);
return;
}
alter_config(addr,0,0,2);
create_netmail(to,"Temporarily Disconnect Areas"
,"Your areas have been temporarily disconnected.",addr,FALSE);
create_netmail(to,/* from: */NULL,"Temporarily Disconnect Areas"
,"Your areas have been temporarily disconnected.",addr,time(NULL),FALSE);
return;
}
......@@ -1397,8 +1388,8 @@ char* process_areafix(faddr_t addr, char* inbuf, char* password, char* to)
i=matchnode(addr,0);
if(i>=cfg.nodecfgs) {
lprintf(LOG_NOTICE,"Areafix not configured for %s", smb_faddrtoa(&addr,NULL));
create_netmail(to,"Areafix Request"
,"Your node is not configured for Areafix, please contact your hub.\r\n",addr,FALSE);
create_netmail(to,/* from: */NULL,"Areafix Request"
,"Your node is not configured for Areafix, please contact your hub.\r\n",addr,time(NULL),FALSE);
sprintf(body,"An areafix request was made by node %s.\r\nThis node "
"is not currently configured for areafix.\r\n"
,smb_faddrtoa(&addr,NULL));
......@@ -1412,7 +1403,7 @@ char* process_areafix(faddr_t addr, char* inbuf, char* password, char* to)
}
if(stricmp(cfg.nodecfg[i].password,password)) {
create_netmail(to,"Areafix Request","Invalid Password.",addr,FALSE);
create_netmail(to,/* from: */NULL,"Areafix Request","Invalid Password.",addr,time(NULL),FALSE);
sprintf(body,"Node %s attempted an areafix request using an invalid "
"password.\r\nThe password attempted was %s.\r\nThe correct password "
"for this node is %s.\r\n",smb_faddrtoa(&addr,NULL),password
......@@ -1457,7 +1448,7 @@ char* process_areafix(faddr_t addr, char* inbuf, char* password, char* to)
}
if(!percent && !strListCount(add_area) && !strListCount(del_area)) {
create_netmail(to,"Areafix Request","No commands to process.",addr,FALSE);
create_netmail(to,/* from: */NULL,"Areafix Request","No commands to process.",addr,time(NULL),FALSE);
sprintf(body,"Node %s attempted an areafix request with an empty message "
"body or with no valid commands.\r\n",smb_faddrtoa(&addr,NULL));
strListFree(&add_area);
......@@ -1654,9 +1645,11 @@ int attachment(char *bundlename,faddr_t dest, int mode)
if(mfncrc[crcidx]==fncrc)
break;
if(crcidx==num_mfncrc)
if(create_netmail(/* To: */NULL,str
if(create_netmail(/* To: */NULL
,/* from: */NULL
,/* subj: */str
,(misc&TRUNC_BUNDLES) ? "\1FLAGS TFS\r" : "\1FLAGS KFS\r"
,attach.dest,TRUE))
,attach.dest,time(NULL),TRUE))
error=1;
}
fclose(stream);
......@@ -1729,9 +1722,9 @@ void pack_bundle(char *infile,faddr_t dest)
if(misc&FLO_MAILER)
i=write_flofile(infile,dest,TRUE /* bundle */);
else
i=create_netmail(/* To: */NULL,infile
i=create_netmail(/* To: */NULL,/* from: */NULL,infile
,(misc&TRUNC_BUNDLES) ? "\1FLAGS TFS\r" : "\1FLAGS KFS\r"
,dest,TRUE);
,dest,time(NULL),TRUE);
if(i) bail(1);
return;
}
......@@ -4055,6 +4048,85 @@ void export_echomail(char *sub_code,faddr_t addr)
}
}
/* New Feature (as of Nov-22-2015):
Export NetMail from SMB (data/mail) to .msg format
*/
int export_netmail(void)
{
int i;
char* txt;
smbmsg_t msg;
lprintf(LOG_DEBUG,"Exporting Outbound NetMail from %smail",scfg.data_dir);
if(email->shd_fp==NULL) {
sprintf(email->file,"%smail",scfg.data_dir);
email->retry_time=scfg.smb_retry_time;
if((i=smb_open(email))!=SMB_SUCCESS) {
lprintf(LOG_ERR,"ERROR %d (%s) line %d opening %s",i,email->last_error,__LINE__,email->file);
return i;
}
}
if((i=smb_locksmbhdr(email)) != SMB_SUCCESS) {
lprintf(LOG_ERR,"ERROR %d (%s) line %d locking %s",i,email->last_error,__LINE__,email->file);
return i;
}
memset(&msg, 0, sizeof(msg));
rewind(email->sid_fp);
for(;!feof(email->sid_fp);msg.offset++) {
smb_freemsgmem(&msg);
if(fread(&msg.idx, sizeof(msg.idx), 1, email->sid_fp) != 1)
break;
if((msg.idx.attr&MSG_DELETE) || msg.idx.to != 0)
continue;
if(smb_getmsghdr(email, &msg) != SMB_SUCCESS)
continue;
if(msg.to_ext != 0 || msg.to_net.type != NET_FIDO)
continue;
printf("\nMsg #%u from %s to %s "
,msg.hdr.number, msg.from, smb_faddrtoa(msg.to_net.addr,NULL));
if(msg.hdr.netattr&MSG_SENT) {
printf("already sent\n");
continue;
}
if((txt=smb_getmsgtxt(email,&msg,GETMSGTXT_ALL)) == NULL) {
lprintf(LOG_ERR,"!ERROR %d getting message text for mail msg #%u"
, email->last_error, msg.hdr.number);
continue;
}
create_netmail(msg.to, msg.from, msg.subj, txt, *(faddr_t*)msg.to_net.addr, msg.hdr.when_written.time
,/* file_attached */FALSE);
FREE_AND_NULL(txt);
if(misc&DELETE_NETMAIL) {
/* Delete exported netmail */
msg.hdr.attr |= MSG_DELETE;
if(smb_updatemsg(email, &msg) != SMB_SUCCESS)
lprintf(LOG_ERR,"!ERROR %d deleting mail msg #%u"
,email->last_error, msg.hdr.number);
if(msg.hdr.auxattr&MSG_FILEATTACH)
delfattach(&scfg,&msg);
fseek(email->sid_fp, msg.offset*sizeof(msg.idx), SEEK_SET);
} else {
/* Just mark as "sent" */
msg.hdr.netattr |= MSG_SENT;
if(smb_putmsghdr(email, &msg) != SMB_SUCCESS)
lprintf(LOG_ERR,"!ERROR %d updating msg header for mail msg #%u"
, email->last_error, msg.hdr.number);
}
}
smb_freemsgmem(&msg);
return smb_unlocksmbhdr(email);
}
char* freadstr(FILE* fp, char* str, size_t maxlen)
{
int ch;
......@@ -4132,7 +4204,7 @@ int main(int argc, char **argv)
"o: import all netmail regardless of destination address\n"
"s: import private echomail override (strip private status)\n"
"!: notify users of received echomail @: prompt for key upon exiting (debug)\n"
" W: prompt for key upon abnormal exit";
"c: do not export netmail (to *.msg) W: prompt for key upon abnormal exit";
if((email=(smb_t *)malloc(sizeof(smb_t)))==NULL) {
printf("ERROR allocating memory for email.\n");
......@@ -4186,6 +4258,9 @@ int main(int argc, char **argv)
case 'B':
misc|=LOCAL_NETMAIL;
break;
case 'C':
export_netmail_option = FALSE;
break;
case 'D':
misc&=~DELETE_NETMAIL;
break;
......@@ -4985,6 +5060,9 @@ int main(int argc, char **argv)
if(misc&EXPORT_ECHOMAIL)
export_echomail(sub_code,addr);
if(export_netmail_option)
export_netmail();
if(misc&PACK_NETMAIL) {
memset(&msg_seen,0,sizeof(addrlist_t));
......
......@@ -8,7 +8,7 @@
* @format.tab-size 4 (Plain Text/Source Code File Header) *
* @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
* *
* Copyright 2015 Rob Swindell - http://www.synchro.net/copyright.html *
* Copyright Rob Swindell - http://www.synchro.net/copyright.html *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
......@@ -38,7 +38,7 @@
/* Portions written by Allen Christiansen 1994-1996 */
#define SBBSECHO_VERSION_MAJOR 2
#define SBBSECHO_VERSION_MINOR 27
#define SBBSECHO_VERSION_MINOR 30
#define SBBSECHO_PRODUCT_CODE 0x12FF /* from http://ftsc.org/docs/ftscprod.013 */
......
......@@ -160,6 +160,7 @@
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ClCompile Include="getmail.c" />
<ClCompile Include="load_cfg.c">
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment