Commit c3ae3857 authored by rswindell's avatar rswindell
Browse files

Cool new feature {tm}:

FidoNet NetMail can now be gated to an SMTP client (as before), but replies are
now successfully gated back to FTN NetMail. This uses a new more RFC-compliant
To/From address header field format, so older messages (previously gated to
an SMTP client) cannot be successfully replied-to. Tested with Microsoft
"Windows Live Mail 2012" (previously known as Outlook Express).
Test reports/results with other SMTP mail clients would be welcome.

Requires SBBSecho v2.30 or later. File attachments are not yet supported.
parent 80fb6cb9
......@@ -217,7 +217,7 @@ add_library(ftpsrvr SHARED ftpsrvr.c nopen.c)
require_libs(ftpsrvr xpdev smblib comio)
target_link_libraries(ftpsrvr sbbs)
add_library(mailsrvr SHARED mailsrvr.c mxlookup.c mime.c ars.c base64.c)
add_library(mailsrvr SHARED mailsrvr.c mxlookup.c mime.c nopen.c ars.c base64.c)
require_libs(mailsrvr xpdev smblib comio)
target_link_libraries(mailsrvr sbbs)
......
......@@ -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 2013 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 *
......@@ -40,6 +40,8 @@
#include "gen_defs.h"
#define FIDO_TLD ".fidonet" /* Fake TLD for gating netmail through SMTP */
#define FIDO_NAME_LEN 36 /* Includes '\0' terminator */
#define FIDO_SUBJ_LEN 72 /* Includes '\0' terminator */
#define FIDO_TIME_LEN 20 /* Includes '\0' terminator */
......
......@@ -452,6 +452,32 @@ static BOOL sockgetrsp(SOCKET socket, char* rsp, char *buf, int len)
return(TRUE);
}
/* non-standard, but documented (mostly) in draft-newman-msgheader-originfo-05 */
void originator_info(SOCKET socket, smbmsg_t* msg)
{
char* user = msg->from_ext;
char* login = smb_get_hfield(msg,SENDERUSERID,NULL);
char* server = smb_get_hfield(msg,SENDERSERVER,NULL);
char* client = smb_get_hfield(msg,SENDERHOSTNAME,NULL);
char* addr = smb_get_hfield(msg,SENDERIPADDR,NULL);
char* prot = smb_get_hfield(msg,SENDERPROTOCOL,NULL);
char* port = smb_get_hfield(msg,SENDERPORT,NULL);
char* time = smb_get_hfield(msg,SENDERTIME,NULL);
if(user || login || server || client || addr || prot || port || time)
sockprintf(socket
,"X-Originator-Info: account=%s; login-id=%s; server=%s; client=%s; addr=%s; prot=%s; port=%s; time=%s"
,user
,login
,server
,client
,addr
,prot
,port
,time
);
}
/* RFC822: The maximum total length of a text line including the
<CRLF> is 1000 characters (but not counting the leading
dot duplicated for transparency).
......@@ -493,20 +519,31 @@ static ulong sockmimetext(SOCKET socket, smbmsg_t* msg, char* msgtxt, ulong maxl
if((p=smb_get_hfield(msg,RFC822FROM,NULL))!=NULL)
s=sockprintf(socket,"From: %s",p); /* use original RFC822 header field */
else {
char fromname[256];
SAFECOPY(fromname, msg->from);
if(msg->from_net.type==NET_QWK && msg->from_net.addr!=NULL)
SAFEPRINTF2(fromaddr,"%s!%s"
,(char*)msg->from_net.addr
,usermailaddr(&scfg,fromhost,msg->from));
else if(msg->from_net.type==NET_FIDO && msg->from_net.addr!=NULL)
SAFECOPY(fromaddr,smb_faddrtoa((faddr_t *)msg->from_net.addr,NULL));
else if(msg->from_net.type!=NET_NONE && msg->from_net.addr!=NULL)
else if(msg->from_net.type==NET_FIDO && msg->from_net.addr!=NULL) {
faddr_t* faddr = (faddr_t *)msg->from_net.addr;
char faddrstr[128];
SAFEPRINTF2(fromname,"%s (%s)", msg->from, smb_faddrtoa(faddr, NULL));
if(faddr->point)
SAFEPRINTF4(faddrstr,"p%hu.f%hu.n%hu.z%hu"FIDO_TLD
,faddr->point, faddr->node, faddr->net, faddr->zone);
else
SAFEPRINTF3(faddrstr,"f%hu.n%hu.z%hu"FIDO_TLD
,faddr->node, faddr->net, faddr->zone);
SAFEPRINTF2(fromaddr,"%s@%s", usermailaddr(NULL,fromhost,msg->from), faddrstr);
} else if(msg->from_net.type!=NET_NONE && msg->from_net.addr!=NULL)
SAFECOPY(fromaddr,(char*)msg->from_net.addr);
else
usermailaddr(&scfg,fromaddr,msg->from);
if(fromaddr[0]=='<')
s=sockprintf(socket,"From: \"%s\" %s",msg->from,fromaddr);
s=sockprintf(socket,"From: \"%s\" %s",fromname,fromaddr);
else
s=sockprintf(socket,"From: \"%s\" <%s>",msg->from,fromaddr);
s=sockprintf(socket,"From: \"%s\" <%s>",fromname,fromaddr);
}
if(!s)
return(0);
......@@ -529,6 +566,8 @@ static ulong sockmimetext(SOCKET socket, smbmsg_t* msg, char* msgtxt, ulong maxl
s=sockprintf(socket,"To: %s",(char*)msg->to_net.addr);
else
s=sockprintf(socket,"To: \"%s\" <%s>",msg->to,(char*)msg->to_net.addr);
} else if(msg->to_net.type==NET_FIDO) {
s=sockprintf(socket,"To: \"%s (%s)\"",msg->to, smb_faddrtoa((fidoaddr_t*)msg->to_net.addr, NULL));
} else {
usermailaddr(&scfg,toaddr,msg->to);
s=sockprintf(socket,"To: \"%s\" <%s>",msg->to,toaddr);
......@@ -559,17 +598,7 @@ static ulong sockmimetext(SOCKET socket, smbmsg_t* msg, char* msgtxt, ulong maxl
if(!sockprintf(socket,"In-Reply-To: %s",msg->reply_id))
return(0);
/* non-standard, but documented (mostly) in draft-newman-msgheader-originfo-05 */
sockprintf(socket,"Originator-Info: account=%s; login-id=%s; server=%s; client=%s; addr=%s; prot=%s; port=%s; time=%s"
,msg->from_ext
,smb_get_hfield(msg,SENDERUSERID,NULL)
,smb_get_hfield(msg,SENDERSERVER,NULL)
,smb_get_hfield(msg,SENDERHOSTNAME,NULL)
,smb_get_hfield(msg,SENDERIPADDR,NULL)
,smb_get_hfield(msg,SENDERPROTOCOL,NULL)
,smb_get_hfield(msg,SENDERPORT,NULL)
,smb_get_hfield(msg,SENDERTIME,NULL)
);
originator_info(socket, msg);
for(i=0;i<msg->total_hfields;i++) {
if(msg->hfield[i].type==RFC822HEADER) {
......@@ -3228,7 +3257,7 @@ static void smtp_thread(void* arg)
}
if(nettype!=NET_NONE) {
smb_hfield(&newmsg, RECIPIENTNETTYPE, sizeof(nettype), &nettype);
smb_hfield_str(&newmsg, RECIPIENTNETADDR, rcpt_addr);
smb_hfield_netaddr(&newmsg, RECIPIENTNETADDR, rcpt_addr, &nettype);
}
if(agent!=newmsg.to_agent)
smb_hfield(&newmsg, RECIPIENTAGENT, sizeof(agent), &agent);
......@@ -3247,6 +3276,15 @@ static void smtp_thread(void* arg)
,socket, newmsg.hdr.number, sender, sender_ext, smb_netaddrstr(&msg.from_net,tmp), rcpt_name, rcpt_addr);
if(relay_user.number!=0)
user_sent_email(&scfg, &relay_user, 1, usernum==1);
if(nettype == NET_FIDO && scfg.netmail_sem[0])
ftouch(mailcmdstr(scfg.netmail_sem
,msgtxt_fname, newtxt_fname, logtxt_fname
,rcptlst_fname, proc_err_fname
,host_name, host_ip, relay_user.number
,rcpt_addr
,sender, sender_addr, reverse_path, str));
if(!(startup->options&MAIL_OPT_NO_NOTIFY) && usernum) {
if(newmsg.idx.to)
for(i=1;i<=scfg.sys_nodes;i++) {
......@@ -3844,6 +3882,37 @@ static void smtp_thread(void* arg)
/* RELAY */
dest_port=inet_addrport(&server_addr);
SAFECOPY(dest_host,tp+1);
if(relay_user.number && scfg.total_faddrs) {
char* ftn_tld = strstr(dest_host, FIDO_TLD);
if(ftn_tld != NULL && ftn_tld[strlen(FIDO_TLD)] == 0) {
fidoaddr_t faddr = scfg.faddr[0];
faddr.point = 0;
if((sscanf(dest_host,"p%hu.f%hu.n%hu.z%hu.fidonet"
,&faddr.point
,&faddr.node
,&faddr.net
,&faddr.zone)==4
||
sscanf(dest_host,"f%hu.n%hu.z%hu.fidonet"
,&faddr.node
,&faddr.net
,&faddr.zone)==3
) && faddr.zone) {
lprintf(LOG_INFO,"%04d SMTP %s relaying to FidoNet address: %s (%s)"
,socket, relay_user.alias, tp+1, smb_faddrtoa(&faddr, NULL));
fprintf(rcptlst,"[%u]\n",rcpt_count++);
fprintf(rcptlst,"%s=%s\n",smb_hfieldtype(RECIPIENT),rcpt_addr);
fprintf(rcptlst,"%s=%u\n",smb_hfieldtype(RECIPIENTNETTYPE),NET_FIDO);
fprintf(rcptlst,"%s=%s\n",smb_hfieldtype(RECIPIENTNETADDR),smb_faddrtoa(&faddr,NULL));
sockprintf(socket,ok_rsp);
state=SMTP_STATE_RCPT_TO;
continue;
}
}
}
cp=strrchr(dest_host,':');
if(cp!=NULL) {
*cp=0;
......@@ -3916,7 +3985,7 @@ static void smtp_thread(void* arg)
}
FIND_ALPHANUMERIC(p); /* Skip '<' or '"' */
truncstr(p,"\"");
truncstr(p,"\"");
p=alias(&scfg,p,name_alias_buf);
if(p==name_alias_buf)
......
......@@ -192,6 +192,7 @@
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ClCompile Include="nopen.c" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\xpdev\xpdev_mt.vcxproj">
......
......@@ -129,6 +129,7 @@ FTP_OBJS = $(MTOBJODIR)$(DIRSEP)ftpsrvr$(OFILE) \
MAIL_OBJS = $(MTOBJODIR)$(DIRSEP)mailsrvr$(OFILE) \
$(MTOBJODIR)$(DIRSEP)mxlookup$(OFILE) \
$(MTOBJODIR)$(DIRSEP)mime$(OFILE) \
$(MTOBJODIR)$(DIRSEP)nopen$(OFILE) \
$(MTOBJODIR)$(DIRSEP)ars$(OFILE) \
$(MTOBJODIR)$(DIRSEP)base64$(OFILE)
......
......@@ -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 2014 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 *
......@@ -536,9 +536,12 @@ extern "C" int DLLCALL savemsg(scfg_t* cfg, smb_t* smb, smbmsg_t* msg, client_t*
smb_hfield_str(msg,FIDOPID,msg_program_id(pid));
if((i=smb_addmsg(smb,msg,storage,dupechk_hashes,xlat,(uchar*)msgbuf,NULL))==SMB_SUCCESS
&& msg->to!=NULL /* no recipient means no header created at this stage */)
signal_sub_sem(cfg,smb->subnum);
&& msg->to!=NULL /* no recipient means no header created at this stage */) {
if(smb->subnum == INVALID_SUB) {
if(msg->to_net.type == NET_FIDO)
ftouch(cmdstr(cfg,NULL,cfg->netmail_sem,nulstr,nulstr,NULL));
} else
signal_sub_sem(cfg,smb->subnum);
}
return(i);
}
......@@ -2197,12 +2197,15 @@ void DLLCALL resetdailyuserdat(scfg_t* cfg, user_t* user, BOOL write)
}
/****************************************************************************/
/* Get dotted-equivalent email address for user 'name'. */
/* 'addr' is the target buffer for the full address. */
/* Pass cfg=NULL to NOT have "@address" portion appended. */
/****************************************************************************/
char* DLLCALL usermailaddr(scfg_t* cfg, char* addr, const char* name)
{
int i;
if(!VALID_CFG(cfg) || addr==NULL || name==NULL)
if(addr==NULL || name==NULL)
return(NULL);
if(strchr(name,'@')!=NULL) { /* Avoid double-@ */
......@@ -2222,8 +2225,10 @@ char* DLLCALL usermailaddr(scfg_t* cfg, char* addr, const char* name)
addr[i]='.';
strlwr(addr);
}
strcat(addr,"@");
strcat(addr,cfg->sys_inetaddr);
if(VALID_CFG(cfg)) {
strcat(addr,"@");
strcat(addr,cfg->sys_inetaddr);
}
return(addr);
}
......@@ -2547,21 +2552,25 @@ BOOL DLLCALL can_user_post(scfg_t* cfg, uint subnum, user_t* user, client_t* cli
/* 'reason' is an (optional) pointer to a text.dat item number */
/* usernumber==0 for netmail */
/****************************************************************************/
BOOL DLLCALL can_user_send_mail(scfg_t* cfg, uint usernumber, user_t* user, uint* reason)
BOOL DLLCALL can_user_send_mail(scfg_t* cfg, enum SMB_NET_TYPE net_type, uint usernumber, user_t* user, uint* reason)
{
if(reason!=NULL)
*reason=R_Email;
if(user==NULL || user->number==0)
return FALSE;
if(usernumber>1 && user->rest&FLAG('E')) /* local mail restriction? */
if(net_type==NET_NONE && usernumber>1 && user->rest&FLAG('E')) /* local mail restriction? */
return FALSE;
if(reason!=NULL)
*reason=NoNetMailAllowed;
if(usernumber==0 && user->rest&FLAG('M')) /* netmail restriction */
if(net_type!=NET_NONE && user->rest&FLAG('M')) /* netmail restriction */
return FALSE;
if(net_type==NET_FIDO && !(cfg->netmail_misc&NMAIL_ALLOW)) /* Fido netmail globally disallowed */
return FALSE;
if(net_type==NET_INTERNET && !(cfg->inetmail_misc&NMAIL_ALLOW)) /* Internet mail globally disallowed */
return FALSE;
if(reason!=NULL)
*reason=R_Feedback;
if(usernumber==1 && user->rest&FLAG('S')) /* feedback restriction? */
if(net_type==NET_NONE && usernumber==1 && user->rest&FLAG('S')) /* feedback restriction? */
return FALSE;
if(reason!=NULL)
*reason=TooManyEmailsToday;
......
......@@ -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 2014 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 *
......@@ -115,7 +115,7 @@ DLLEXPORT int DLLCALL user_rec_len(int offset);
DLLEXPORT BOOL DLLCALL can_user_access_sub(scfg_t* cfg, uint subnum, user_t* user, client_t* client);
DLLEXPORT BOOL DLLCALL can_user_read_sub(scfg_t* cfg, uint subnum, user_t* user, client_t* client);
DLLEXPORT BOOL DLLCALL can_user_post(scfg_t* cfg, uint subnum, user_t* user, client_t* client, uint* reason);
DLLEXPORT BOOL DLLCALL can_user_send_mail(scfg_t* cfg, uint usernumber, user_t* user, uint* reason);
DLLEXPORT BOOL DLLCALL can_user_send_mail(scfg_t* cfg, enum SMB_NET_TYPE, uint usernumber, user_t* user, uint* reason);
DLLEXPORT BOOL DLLCALL is_user_subop(scfg_t* cfg, uint subnum, user_t* user, client_t* client);
DLLEXPORT BOOL DLLCALL is_download_free(scfg_t* cfg, uint dirnum, user_t* user, client_t* client);
DLLEXPORT BOOL DLLCALL filter_ip(scfg_t* cfg, const char* prot, const char* reason, const char* host
......
......@@ -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 2014 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 *
......@@ -2229,7 +2229,9 @@ char* DLLCALL cmdstr(scfg_t* cfg, user_t* user, const char* instr, const char* f
{
char str[MAX_PATH+1];
int i,j,len;
static char buf[512];
if(cmd==NULL) cmd=buf;
len=strlen(instr);
for(i=j=0;i<len && j<MAX_PATH;i++) {
if(instr[i]=='%') {
......
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