diff --git a/src/sbbs3/CMakeLists.txt b/src/sbbs3/CMakeLists.txt index 5cc631a88c078cb2358f1e8615d72cdba96d9971..527b07314850f332e5def005a56c61d403444d83 100644 --- a/src/sbbs3/CMakeLists.txt +++ b/src/sbbs3/CMakeLists.txt @@ -313,6 +313,7 @@ add_executable(sbbsecho userdat.c rechocfg.c msg_id.c + getmail.c ) require_libs(sbbsecho xpdev smblib) diff --git a/src/sbbs3/objects.mk b/src/sbbs3/objects.mk index 44df1777e39bbf2658660fc05f58bec2bf611648..7786de477539b18feff45be80a5d03e9d74365ca 100644 --- a/src/sbbs3/objects.mk +++ b/src/sbbs3/objects.mk @@ -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 = \ diff --git a/src/sbbs3/sbbsecho.c b/src/sbbs3/sbbsecho.c index aab8489c7a89e66fd47a783d04b21428a2438a7d..82bb5519b02edb1a3754611a0bd3f60a081417c8 100644 --- a/src/sbbs3/sbbsecho.c +++ b/src/sbbs3/sbbsecho.c @@ -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)); diff --git a/src/sbbs3/sbbsecho.h b/src/sbbs3/sbbsecho.h index 4d131780e94c6807cf89981053a90731552a3277..fc6005da56e2f43cbcdb1f9a0029dc13b403f74b 100644 --- a/src/sbbs3/sbbsecho.h +++ b/src/sbbs3/sbbsecho.h @@ -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 */ diff --git a/src/sbbs3/sbbsecho.vcxproj b/src/sbbs3/sbbsecho.vcxproj index aea58d8890bdac164ac71dfc5534d4761981ebb6..72d2f7c035f5093833fc6854a40f77ca99c0250d 100644 --- a/src/sbbs3/sbbsecho.vcxproj +++ b/src/sbbs3/sbbsecho.vcxproj @@ -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>