diff --git a/APRSCode.c b/APRSCode.c
index 67ab0c2..4cdcd60 100644
--- a/APRSCode.c
+++ b/APRSCode.c
@@ -8844,7 +8844,7 @@ int GetAPRSPageInfo(char * Buffer, double N, double S, double W, double E, int a
if (lastLat != ptr->Lat)
Len += sprintf(&Buffer[Len],"%.4f,%.4f,\r\n|", ptr->Lat, ptr->Lon); //Add current position to end of track
else
- Len += sprintf(&Buffer[Len],"\r\n|", ptr->Lat, ptr->Lon);
+ Len += sprintf(&Buffer[Len],"\r\n|");
}
}
}
diff --git a/BBSHTMLConfig.c b/BBSHTMLConfig.c
index f965f27..69899ac 100644
--- a/BBSHTMLConfig.c
+++ b/BBSHTMLConfig.c
@@ -1681,6 +1681,85 @@ VOID ProcessConfUpdate(struct HTTPConnectionInfo * Session, char * MsgPtr, char
HoldAt = GetMultiStringInput(input, "Hat=");
HoldBID = GetMultiStringInput(input, "HBID=");
+ // Look for fbb style filters
+
+ input = strstr(input, "&Action=");
+
+ // delete old list
+
+ while(Filters && Filters->Next)
+ {
+ FBBFilter * next = Filters->Next;
+ free(Filters);
+ Filters = next;
+ }
+
+ free(Filters);
+ Filters = NULL;
+
+ while (input)
+ {
+ // extract and validate before saving
+
+ FBBFilter Filter;
+ FBBFilter * PFilter;
+
+ memset(&Filter, 0, sizeof(FBBFilter));
+
+ Filter.Action = toupper(input[8]);
+
+ input = strstr(input, "&Type=");
+
+ if (Filter.Action == 'H' || Filter.Action == 'R')
+ {
+ Filter.Type = toupper(input[6]);
+ input = strstr(input, "&From=");
+ memcpy(Filter.From, &input[6], 10);
+ input = strstr(input, "&TO=");
+ strlop(Filter.From, '&');
+ _strupr(Filter.From);
+ memcpy(Filter.TO, &input[4], 10);
+ input = strstr(input, "&AT=");
+ strlop(Filter.TO, '&');
+ _strupr(Filter.TO);
+ memcpy(Filter.AT, &input[4], 10);
+ input = strstr(input, "&BID=");
+ strlop(Filter.AT, '&');
+ _strupr(Filter.AT);
+ memcpy(Filter.BID, &input[5], 10);
+ input = strstr(input, "&MaxLen=");
+ strlop(Filter.BID, '&');
+ _strupr(Filter.BID);
+ Filter.MaxLen = atoi(&input[8]);
+
+ if (Filter.Type == '&') Filter.Type = '*';
+ if (Filter.From[0] == 0) strcpy(Filter.From, "*");
+ if (Filter.TO[0] == 0) strcpy(Filter.TO, "*");
+ if (Filter.AT[0] == 0) strcpy(Filter.AT, "*");
+ if (Filter.BID[0] == 0) strcpy(Filter.BID, "*");
+
+ // add to list
+
+ PFilter = zalloc(sizeof(FBBFilter));
+
+ memcpy(PFilter, &Filter, sizeof(FBBFilter));
+
+ if (Filters == 0)
+ Filters = PFilter;
+ else
+ {
+ FBBFilter * p = Filters;
+
+ while (p->Next)
+ p = p->Next;
+
+ p->Next = PFilter;
+ }
+ }
+
+ input = strstr(input, "&Action=");
+ }
+
SaveConfig(ConfigName);
GetConfig(ConfigName);
}
@@ -2437,7 +2516,7 @@ VOID SendFwdDetails(struct UserInfo * User, char * Reply, int * ReplyLen, char *
VOID SendConfigPage(char * Reply, int * ReplyLen, char * Key)
{
- int Len;
+ int Len, i;
char HF[2048] = "";
char HT[2048] = "";
@@ -2449,6 +2528,12 @@ VOID SendConfigPage(char * Reply, int * ReplyLen, char * Key)
char RB[2048] = "";
char WPTO[10000] = "";
+ char FBBFilters[100000] = "";
+
+
+ char * ptr = FBBFilters;
+ FBBFilter * Filter = Filters;
+
SetMultiStringValue(RejFrom, RF);
SetMultiStringValue(RejTo, RT);
SetMultiStringValue(RejAt, RA);
@@ -2459,7 +2544,44 @@ VOID SendConfigPage(char * Reply, int * ReplyLen, char * Key)
SetMultiStringValue(HoldBID, HB);
SetMultiStringValue(SendWPAddrs, WPTO);
+ // set up FB style fiters
+ ptr += sprintf(ptr,
+ "
| Action | Type | From | To | @BBS | Bid | Max Size |
");
+
+ while(Filter)
+ {
+ ptr += sprintf(ptr, ""
+ " | "
+ " | "
+ " | "
+ " | "
+ " | "
+ " | "
+ " |
",
+ Filter->Action, Filter->Type, Filter->From, Filter->TO, Filter->AT, Filter->BID, Filter->MaxLen);
+
+ Filter = Filter->Next;
+ }
+
+ // Add a few blank entries for input
+
+ for (i = 0; i < 5; i++)
+ {
+ ptr += sprintf(ptr, ""
+ " | "
+ " | "
+ " | "
+ " | "
+ " | "
+ " | "
+ " |
", ' ', ' ', "", "", "", "", 0);
+ }
+
+ ptr += sprintf(ptr, "
");
+
+ Debugprintf("%d", strlen(FBBFilters));
+
Len = sprintf(Reply, ConfigTemplate,
BBSName, Key, Key, Key, Key, Key, Key, Key, Key, Key,
BBSName, SYSOPCall, HRoute,
@@ -2490,7 +2612,7 @@ VOID SendConfigPage(char * Reply, int * ReplyLen, char * Key)
(SendWPType == 0) ? CHKD : UNC,
(SendWPType == 1) ? CHKD : UNC,
WPTO,
- RF, RT, RA, RB, HF, HT, HA, HB);
+ RF, RT, RA, RB, HF, HT, HA, HB, FBBFilters);
*ReplyLen = Len;
}
diff --git a/BBSUtilities.c b/BBSUtilities.c
index 413a121..1d3c1f2 100644
--- a/BBSUtilities.c
+++ b/BBSUtilities.c
@@ -45,6 +45,7 @@ BOOL OpenMon;
int reportNewMesageEvents = 0;
+FBBFilter * Filters = NULL;
extern struct ConsoleInfo BBSConsole;
@@ -2078,10 +2079,37 @@ int CountConnectionsOnPort(int CheckPort)
return Count;
}
+/*
+REJECT.SYS (\FBB\SYSTEM).
+
+ This file is in SYSTEM-directory. With this file it is possible to reject or
+hold certain types or sizes of messages.
+
+The first letter of each valid line specifies the action :
+
+R = Reject : The message will not be received.
+H = Hold : The message will be received but held until the sysop reviews.
+L = Local Hold : Only messages created on this BBS will be held.
+
+ # File for rejecting messages. They are rejected with N-BID:
+ #
+ # Type, from, @BBS, to, BID, maximum size:
+ #
+ # * and ? can be used as wildcards (as in MS-DOS)
+ #
+ R B TOTO ALL TATA * 0
+ R B * * VENTE * 0
+ R B * VENTE * * 0
+ H * P1RAT * * * 0
+ L B * * * * 0
+ */
-BOOL CheckRejFilters(char * From, char * To, char * ATBBS, char * BID, char Type)
+
+BOOL CheckRejFilters(char * From, char * To, char * ATBBS, char * BID, char Type, int Len)
{
char ** Calls;
+ FBBFilter * p = Filters;
+ char ToCopy[256];
if (Type == 'B' && FilterWPBulls && _stricmp(To, "WP") == 0)
return TRUE;
@@ -2145,6 +2173,43 @@ BOOL CheckRejFilters(char * From, char * To, char * ATBBS, char * BID, char Type
Calls++;
}
}
+
+ // check fbb reject.sys type filters
+
+ strcpy(ToCopy, To);
+ _strupr(ToCopy);
+
+ while (p)
+ {
+ if (p->Action != 'R')
+ goto Continue;
+
+ if (p->Type != Type && p->Type != '*')
+ goto Continue;
+
+ if (wildcardcompare(From, p->From) == 0)
+ goto Continue;
+
+ if (wildcardcompare(ToCopy, p->TO) == 0)
+ goto Continue;
+
+ if (ATBBS)
+ if (wildcardcompare(ATBBS, p->AT) == 0)
+ goto Continue;
+
+ if (BID)
+ if (wildcardcompare(BID, p->BID) == 0)
+ goto Continue;
+
+ if (p->MaxLen && Len < p->MaxLen)
+ goto Continue;
+
+ return TRUE; // Hold
+
+Continue:
+ p = p->Next;
+ }
+
return FALSE; // Ok to accept
}
@@ -2175,9 +2240,12 @@ BOOL CheckValidCall(char * From)
return FALSE;
}
-BOOL CheckHoldFilters(char * From, char * To, char * ATBBS, char * BID)
+BOOL wildcardcompare(char * Target, char * Match);
+
+BOOL CheckHoldFilters(struct MsgInfo * Msg, char * From, char * To, char * ATBBS, char * BID)
{
char ** Calls;
+ FBBFilter * p = Filters;
if (HoldFrom && From)
{
@@ -2238,6 +2306,38 @@ BOOL CheckHoldFilters(char * From, char * To, char * ATBBS, char * BID)
Calls++;
}
}
+
+ // check fbb reject.sys type filters
+
+ while (p)
+ {
+ if (p->Action != 'H')
+ goto Continue;
+
+ if (p->Type != Msg->type && p->Type != '*')
+ goto Continue;
+
+ if (wildcardcompare(Msg->from, p->From) == 0)
+ goto Continue;
+
+ if (wildcardcompare(Msg->to, p->TO) == 0)
+ goto Continue;
+
+ if (wildcardcompare(Msg->via, p->AT) == 0)
+ goto Continue;
+
+ if (wildcardcompare(Msg->bid, p->BID) == 0)
+ goto Continue;
+
+ if (p->MaxLen && Msg->length < p->MaxLen)
+ goto Continue;
+
+ return TRUE; // Hold
+
+Continue:
+ p = p->Next;
+ }
+
return FALSE; // Ok to accept
}
@@ -5361,7 +5461,7 @@ BOOL CreateMessage(CIRCUIT * conn, char * From, char * ToCall, char * ATBBS, cha
}
else
{
- if (CheckRejFilters(From, ToCall, ATBBS, BID, MsgType))
+ if (CheckRejFilters(From, ToCall, ATBBS, BID, MsgType, 0))
{
if ((conn->BBSFlags & BBS))
{
@@ -6169,7 +6269,7 @@ nextline:
HoldReason = "Bad word in title or body";
}
- if (CheckHoldFilters(Msg->from, Msg->to, Msg->via, Msg->bid))
+ if (CheckHoldFilters(Msg, Msg->from, Msg->to, Msg->via, Msg->bid))
{
Msg->status = 'H';
HoldReason = "Matched Hold Filters";
@@ -9441,6 +9541,9 @@ VOID SaveConfig(char * ConfigName)
char Size[80];
struct BBSForwardingInfo DummyForwardingInfo;
char Line[1024];
+ char FBBString[8192]= "";
+ FBBFilter * p = Filters;
+ char * ptr = FBBString;
if (configSaved == 0)
{
@@ -9566,6 +9669,18 @@ VOID SaveConfig(char * ConfigName)
SaveMultiStringValue(group, "HoldAt", HoldAt);
SaveMultiStringValue(group, "HoldBID", HoldBID);
+ // Save FBB Filters
+
+ while (p)
+ {
+ ptr += sprintf(ptr, "%c|%c|%s|%s|%s|%s|%d|",
+ p->Action, p->Type, p->From, p->TO, p->AT, p->BID, p->MaxLen);
+
+ p = p->Next;
+ }
+
+ SaveStringValue(group, "FBBFilters", FBBString);
+
SaveIntValue(group, "SendWP", SendWP);
SaveIntValue(group, "SendWPType", SendWPType);
SaveIntValue(group, "FilterWPBulls", FilterWPBulls);
@@ -9964,7 +10079,8 @@ BOOL GetConfig(char * ConfigName)
char Size[80];
config_setting_t *setting;
const char * ptr;
-
+ char FBBString[8192]= "";
+ FBBFilter f;
config_init(&cfg);
/* Read the file. If there is an error, report it and exit. */
@@ -10161,6 +10277,89 @@ BOOL GetConfig(char * ConfigName)
HoldAt = GetMultiStringValue(group, "HoldAt");
HoldBID = GetMultiStringValue(group, "HoldBID");
+ // Get FBB Filters
+
+ GetStringValue(group, "FBBFilters", FBBString);
+
+ ptr = FBBString;
+
+ // delete old list
+
+ while(Filters && Filters->Next)
+ {
+ FBBFilter * next = Filters->Next;
+ free(Filters);
+ Filters = next;
+ }
+
+ free(Filters);
+ Filters = NULL;
+
+ while (ptr && ptr[0])
+ {
+ FBBFilter * PFilter;
+
+ f.Action = ptr[0];
+ f.Type = ptr[2];
+ ptr = &ptr[4];
+
+ memcpy(f.From, ptr, 10);
+ strlop(f.From, '|');
+ ptr = strlop(ptr, '|');
+
+ memcpy(f.TO, ptr, 10);
+ strlop(f.TO, '|');
+ ptr = strlop(ptr, '|');
+
+ memcpy(f.AT, ptr, 10);
+ strlop(f.AT, '|');
+ ptr = strlop(ptr, '|');
+
+ memcpy(f.BID, ptr, 10);
+ strlop(f.BID, '|');
+ ptr = strlop(ptr, '|');
+
+ f.MaxLen = atoi(ptr);
+
+ // add to list
+
+ f.Next = 0;
+
+ PFilter = zalloc(sizeof(FBBFilter));
+
+ memcpy(PFilter, &f, sizeof(FBBFilter));
+
+ if (Filters == 0)
+ Filters = PFilter;
+ else
+ {
+ FBBFilter * p = Filters;
+
+ while (p->Next)
+ p = p->Next;
+
+ p->Next = PFilter;
+ }
+
+ ptr = strlop(ptr, '|');
+ }
+
+
+
+
+
+//f.Action, f.Type, f.From, f.TO, f.AT, f.BID, &f.MaxLen);
+
+/* while (p)
+ {
+ ptr += sprintf(ptr, "%c|%c|%s|%s|%s|%s|%d|",
+ p->Action, p->Type, p->From, p->TO, p->AT, p->BID, p->MaxLen);
+
+ p = p->Next;
+ }
+
+*/
+
// Send WP Params
SendWP = GetIntValue(group, "SendWP");
diff --git a/BPQMail.aps b/BPQMail.aps
index 2e2b5fe..694b39f 100644
Binary files a/BPQMail.aps and b/BPQMail.aps differ
diff --git a/BPQMail.c b/BPQMail.c
index b244671..3475f84 100644
--- a/BPQMail.c
+++ b/BPQMail.c
@@ -1118,6 +1118,9 @@
// Fix recently introduced crash when "Don't allow new users" is set (81)
// Skip comments before TIMES at start of Connect Script (83)
+// 6.0.25.1 ??
+
+// Aff FBB reject.sys style filters (3)
#include "bpqmail.h"
#include "winstdint.h"
diff --git a/BPQMail.rc b/BPQMail.rc
index 24bda1f..75ae17f 100644
--- a/BPQMail.rc
+++ b/BPQMail.rc
@@ -254,7 +254,7 @@ END
IDD_USEREDIT DIALOGEX 20, 20, 293, 281
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Edit User"
-FONT 8, "System"
+FONT 8, "System", 0, 0, 0x1
BEGIN
COMBOBOX 5000,7,10,57,123,CBS_SIMPLE | CBS_SORT | CBS_UPPERCASE |
WS_VSCROLL | WS_TABSTOP
@@ -1072,39 +1072,45 @@ BEGIN
ES_AUTOHSCROLL
END
-FILTERS DIALOG DISCARDABLE 26, 5, 382, 287
+FILTERS DIALOG DISCARDABLE 26, 5, 382, 371
STYLE WS_CHILD | WS_VISIBLE
FONT 8, "System"
BEGIN
- LTEXT "Reject Messages:",IDC_STATIC,162,29,70,10
- LTEXT "From",IDC_STATIC,83,155,28,10
- EDITTEXT IDC_HOLDFROM,58,167,64,83,ES_MULTILINE | ES_UPPERCASE |
+ LTEXT "Reject Messages:",IDC_STATIC,162,26,70,10
+ LTEXT "From",IDC_STATIC,83,137,28,10
+ EDITTEXT IDC_HOLDFROM,58,149,64,83,ES_MULTILINE | ES_UPPERCASE |
ES_AUTOVSCROLL | ES_WANTRETURN
- LTEXT "To",IDC_STATIC,152,155,27,10
- EDITTEXT IDC_HOLDTO,126,167,64,83,ES_MULTILINE | ES_UPPERCASE |
+ LTEXT "To",IDC_STATIC,152,137,27,10
+ EDITTEXT IDC_HOLDTO,126,149,64,83,ES_MULTILINE | ES_UPPERCASE |
ES_AUTOVSCROLL | ES_WANTRETURN
- LTEXT "At",IDC_STATIC,223,155,15,10
- EDITTEXT IDC_HOLDAT,194,167,64,83,ES_MULTILINE | ES_UPPERCASE |
+ LTEXT "At",IDC_STATIC,223,137,15,10
+ EDITTEXT IDC_HOLDAT,194,149,64,83,ES_MULTILINE | ES_UPPERCASE |
ES_AUTOVSCROLL | ES_WANTRETURN
- DEFPUSHBUTTON "Save",IDC_FILTERSAVE,171,266,50,14,BS_CENTER |
+ DEFPUSHBUTTON "Save",IDC_FILTERSAVE,171,341,50,14,BS_CENTER |
BS_VCENTER
LTEXT "From",IDC_STATIC,83,40,28,10
- EDITTEXT IDC_REJFROM,58,52,64,83,ES_MULTILINE | ES_UPPERCASE |
+ EDITTEXT IDC_REJFROM,58,52,64,67,ES_MULTILINE | ES_UPPERCASE |
ES_AUTOVSCROLL | ES_WANTRETURN
LTEXT "To",IDC_STATIC,154,40,27,10
- EDITTEXT IDC_REJTO,126,52,64,83,ES_MULTILINE | ES_UPPERCASE |
+ EDITTEXT IDC_REJTO,126,52,64,68,ES_MULTILINE | ES_UPPERCASE |
ES_AUTOVSCROLL | ES_WANTRETURN
LTEXT "At",IDC_STATIC,223,40,15,10
- EDITTEXT IDC_REJAT,194,52,64,83,ES_MULTILINE | ES_UPPERCASE |
+ EDITTEXT IDC_REJAT,194,52,64,68,ES_MULTILINE | ES_UPPERCASE |
ES_AUTOVSCROLL | ES_WANTRETURN
LTEXT "Message Filtering Setup.",IDC_STATIC,152,10,95,15
- LTEXT "Hold Messages:",IDC_STATIC,166,143,60,9
- EDITTEXT IDC_REJBID,262,52,64,83,ES_MULTILINE | ES_UPPERCASE |
+ LTEXT "Hold Messages:",IDC_STATIC,166,128,60,9
+ EDITTEXT IDC_REJBID,262,52,64,68,ES_MULTILINE | ES_UPPERCASE |
ES_AUTOVSCROLL | ES_WANTRETURN
- EDITTEXT IDC_HOLDBID,262,167,64,83,ES_MULTILINE | ES_UPPERCASE |
+ EDITTEXT IDC_HOLDBID,262,149,64,83,ES_MULTILINE | ES_UPPERCASE |
ES_AUTOVSCROLL | ES_WANTRETURN
- LTEXT "BID",IDC_STATIC,289,155,15,10
+ LTEXT "BID",IDC_STATIC,289,137,15,10
LTEXT "BID",IDC_STATIC,289,41,15,10
+ EDITTEXT IDC_REJSYS,58,265,270,66,ES_MULTILINE | ES_UPPERCASE |
+ ES_AUTOVSCROLL | ES_WANTRETURN
+ LTEXT "Composite Rules (like fbb reject.sys)",IDC_STATIC,152,
+ 236,134,9
+ LTEXT "Action, Type, from, @BBS, to, BID, maximum size",
+ IDC_STATIC,59,251,247,9
END
WPUPDATE DIALOG DISCARDABLE 26, 5, 382, 287
@@ -1258,6 +1264,7 @@ BEGIN
"FILTERS", DIALOG
BEGIN
RIGHTMARGIN, 377
+ BOTTOMMARGIN, 355
END
IDD_RMSBULLDLG, DIALOG
@@ -1444,6 +1451,11 @@ BEGIN
0x0000
END
+FILTERS AFX_DIALOG_LAYOUT MOVEABLE PURE
+BEGIN
+ 0x0000
+END
+
/////////////////////////////////////////////////////////////////////////////
//
diff --git a/BPQMail.vcproj b/BPQMail.vcproj
index 3c7ef20..3bfb0b5 100644
--- a/BPQMail.vcproj
+++ b/BPQMail.vcproj
@@ -68,7 +68,7 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/BPQMail.vcxproj b/BPQMail.vcxproj
index 2ebc492..5aa7387 100644
--- a/BPQMail.vcxproj
+++ b/BPQMail.vcxproj
@@ -5,23 +5,16 @@
Debug
Win32
-
- Debug
- x64
-
Release
Win32
-
- Release
- x64
-
{3766AA10-C777-4ED8-A83D-F1452DE9B665}
TelnetServer
Win32Proj
+ 10.0.17763.0
@@ -30,39 +23,21 @@
NotSet
true
-
- Application
- v141
- NotSet
- true
-
Application
v141
false
NotSet
-
- Application
- v141
- false
- NotSet
-
-
-
-
-
-
-
<_ProjectFileVersion>15.0.28307.799
@@ -72,17 +47,11 @@
C:\Dev\Msdev2005\Intermed\$(SolutionName)\$(ProjectName)\$(Configuration)\
true
-
- true
-
C:\Dev\Msdev2005\$(SolutionName)\$(ProjectName)\$(Configuration)\
C:\Dev\Msdev2005\Intermed\$(SolutionName)\$(ProjectName)\$(Configuration)\
false
-
- false
-
@@ -117,40 +86,6 @@
MachineX86
-
-
-
-
-
-
- Disabled
- ..\CKernel;..\CInclude;..\CommonSource;..\BPQMail;%(AdditionalIncludeDirectories)
- WIN32;_DEBUG;_WINDOWS;_USE_32BIT_TIME_T;%(PreprocessorDefinitions)
- EnableFastChecks
- MultiThreadedDebug
- true
-
-
- Level3
- ProgramDatabase
- CompileAsC
-
-
- ..\Include;%(AdditionalIncludeDirectories)
-
-
- ..\lib\bpq32.lib;wsock32.lib;comctl32.lib;winmm.lib;..\lib\libconfig.lib;DbgHelp.lib;%(AdditionalDependencies)
- c:\DevProgs\bpq32\BPQMail.exe
- false
- LIBCMT;%(IgnoreSpecificDefaultLibraries)
- true
- $(IntDir)$(TargetName).pdb
- true
- $(IntDir)BBSListings\bpqmail.map
- true
- Windows
-
-
@@ -186,124 +121,58 @@
MachineX86
-
-
-
-
-
-
-
-
-
-
- MaxSpeed
- false
- ..\CKernel;..\CInclude;..\CommonSource;..\BPQMail;%(AdditionalIncludeDirectories)
- WIN32;NDEBUG;_WINDOWS;_USE_32BIT_TIME_T;%(PreprocessorDefinitions)
- MultiThreaded
-
-
- Level3
- ProgramDatabase
- CompileAsC
-
-
- ..\Include;%(AdditionalIncludeDirectories)
-
-
- ..\lib\bpq32.lib;wsock32.lib;comctl32.lib;winmm.lib;..\lib\libconfig.lib;DbgHelp.lib;%(AdditionalDependencies)
- c:\DevProgs\bpq32\BPQMail.exe
- true
- c:\DevProgs\bpq32\BPQMail.pdb
- true
- c:\DevProgs\bpq32\BPQMail.map
- Windows
- true
- true
-
-
-
-
$(IntDir)%(Filename)1.obj
- $(IntDir)%(Filename)1.obj
$(IntDir)%(Filename)1.xdc
- $(IntDir)%(Filename)1.xdc
All
- All
$(IntDir)
- $(IntDir)
$(IntDir)%(Filename)1.obj
- $(IntDir)%(Filename)1.obj
$(IntDir)%(Filename)1.xdc
- $(IntDir)%(Filename)1.xdc
$(IntDir)%(Filename)1.obj
- $(IntDir)%(Filename)1.obj
$(IntDir)%(Filename)1.xdc
- $(IntDir)%(Filename)1.xdc
$(IntDir)%(Filename)1.obj
- $(IntDir)%(Filename)1.obj
$(IntDir)%(Filename)1.xdc
- $(IntDir)%(Filename)1.xdc
$(IntDir)%(Filename)1.obj
- $(IntDir)%(Filename)1.obj
$(IntDir)%(Filename)1.xdc
- $(IntDir)%(Filename)1.xdc
All
- All
$(IntDir)
- $(IntDir)
$(IntDir)
- $(IntDir)
$(IntDir)%(Filename)1.xdc
- $(IntDir)%(Filename)1.xdc
$(IntDir)%(Filename)1.obj
- $(IntDir)%(Filename)1.obj
$(IntDir)%(Filename)1.xdc
- $(IntDir)%(Filename)1.xdc
$(IntDir)%(Filename)1.obj
- $(IntDir)%(Filename)1.obj
$(IntDir)%(Filename)1.xdc
- $(IntDir)%(Filename)1.xdc
$(IntDir)%(Filename)1.obj
- $(IntDir)%(Filename)1.obj
$(IntDir)%(Filename)1.xdc
- $(IntDir)%(Filename)1.xdc
$(IntDir)%(Filename)1.obj
- $(IntDir)%(Filename)1.obj
$(IntDir)%(Filename)1.xdc
- $(IntDir)%(Filename)1.xdc
$(IntDir)%(Filename)1.obj
- $(IntDir)%(Filename)1.obj
$(IntDir)%(Filename)1.xdc
- $(IntDir)%(Filename)1.xdc
$(IntDir)%(Filename)1.obj
- $(IntDir)%(Filename)1.obj
$(IntDir)%(Filename)1.xdc
- $(IntDir)%(Filename)1.xdc
@@ -312,25 +181,17 @@
$(IntDir)%(Filename)1.obj
- $(IntDir)%(Filename)1.obj
$(IntDir)%(Filename)1.xdc
- $(IntDir)%(Filename)1.xdc
$(IntDir)%(Filename)1.obj
- $(IntDir)%(Filename)1.obj
$(IntDir)%(Filename)1.xdc
- $(IntDir)%(Filename)1.xdc
$(IntDir)%(Filename)1.obj
- $(IntDir)%(Filename)1.obj
$(IntDir)%(Filename)1.xdc
- $(IntDir)%(Filename)1.xdc
$(IntDir)%(Filename)1.obj
- $(IntDir)%(Filename)1.obj
$(IntDir)%(Filename)1.xdc
- $(IntDir)%(Filename)1.xdc
diff --git a/BPQMailrc.h b/BPQMailrc.h
index e13267c..750d898 100644
--- a/BPQMailrc.h
+++ b/BPQMailrc.h
@@ -255,6 +255,8 @@
#define IDC_REJFROM 7077
#define IDC_REJTO 7078
#define IDC_REJAT 7079
+#define IDC_HOLDFROM2 7080
+#define IDC_REJSYS 7080
#define IDM_HOUSEKEEPING 9000
#define IDM_PR 9001
#define IDM_PUR 9002
@@ -322,7 +324,7 @@
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE 30012
+#define _APS_NEXT_RESOURCE_VALUE 30013
#define _APS_NEXT_COMMAND_VALUE 40027
#define _APS_NEXT_CONTROL_VALUE 1093
#define _APS_NEXT_SYMED_VALUE 101
diff --git a/Bpq32.c b/Bpq32.c
index 5ee2c61..7a6faab 100644
--- a/Bpq32.c
+++ b/Bpq32.c
@@ -1183,6 +1183,8 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses
// Version 6.0.25.?
// Fix 64 bit compatibility problems in SCSTracker and UZ7HO drivers
+// Add Chat PACLEN config (5)
+// Fix NC to Application Call (6)
#define CKernel
diff --git a/CBPQ32.vcproj b/CBPQ32.vcproj
index f1a0357..00bdf96 100644
--- a/CBPQ32.vcproj
+++ b/CBPQ32.vcproj
@@ -20,7 +20,7 @@
rtcflags == p_linkini)
{
- conn->paclen = 236;
+ conn->paclen = chatPaclen;
// Run first line of connect script
@@ -86,8 +87,10 @@ int Connected(int Stream)
conn->Secure_Session = GetConnectionInfo(Stream, callsign,
&port, &conn->SessType, &paclen, &maxframe, &l4window);
- conn->paclen = paclen;
+ if (paclen > chatPaclen || paclen == 0)
+ paclen = chatPaclen;
+ conn->paclen = paclen;
strlop(callsign, ' '); // Remove trailing spaces
memcpy(conn->Callsign, callsign, 10);
diff --git a/CommonCode.c b/CommonCode.c
index 7060c77..433ed71 100644
--- a/CommonCode.c
+++ b/CommonCode.c
@@ -68,8 +68,11 @@ VOID WriteMiniDump();
void printStack(void);
char * FormatMH(PMHSTRUC MH, char Format);
void WriteConnectLog(char * fromCall, char * toCall, UCHAR * Mode);
+void SendDataToPktMap(char *Msg);
+
extern BOOL LogAllConnects;
+
extern VOID * ENDBUFFERPOOL;
@@ -3302,6 +3305,8 @@ VOID SendLocation()
SendReportMsg((char *)&AXMSG.DEST, Len + 16);
+ SendDataToPktMap("");
+
return;
}
@@ -4749,6 +4754,229 @@ void GetPortCTEXT(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CM
Debugprintf("CTEXT Read for ports %s\r", &PortList[1]);
}
+SOCKET OpenHTTPSock(char * Host)
+{
+ SOCKET sock = 0;
+ struct sockaddr_in destaddr;
+ struct sockaddr_in sinx;
+ int addrlen=sizeof(sinx);
+ struct hostent * HostEnt;
+ int err;
+ u_long param=1;
+ BOOL bcopt=TRUE;
+
+ destaddr.sin_family = AF_INET;
+ destaddr.sin_port = htons(80);
+
+ // Resolve name to address
+
+ HostEnt = gethostbyname (Host);
+
+ if (!HostEnt)
+ {
+ err = WSAGetLastError();
+
+ Debugprintf("Resolve Failed for %s %d %x", "api.winlink.org", err, err);
+ return 0 ; // Resolve failed
+ }
+
+ memcpy(&destaddr.sin_addr.s_addr,HostEnt->h_addr,4);
+
+ // Allocate a Socket entry
+
+ sock = socket(AF_INET,SOCK_STREAM,0);
+
+ if (sock == INVALID_SOCKET)
+ return 0;
+
+ setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, (const char FAR *)&bcopt,4);
+
+ sinx.sin_family = AF_INET;
+ sinx.sin_addr.s_addr = INADDR_ANY;
+ sinx.sin_port = 0;
+
+ if (bind(sock, (struct sockaddr *) &sinx, addrlen) != 0 )
+ return FALSE;
+
+ if (connect(sock,(struct sockaddr *) &destaddr, sizeof(destaddr)) != 0)
+ {
+ err=WSAGetLastError();
+ closesocket(sock);
+ return 0;
+ }
+
+ return sock;
+}
+
+static char HeaderTemplate[] = "POST %s HTTP/1.1\r\n"
+ "Accept: application/json\r\n"
+// "Accept-Encoding: gzip,deflate,gzip, deflate\r\n"
+ "Content-Type: application/json\r\n"
+ "Host: %s:%d\r\n"
+ "Content-Length: %d\r\n"
+ //r\nUser-Agent: BPQ32(G8BPQ)\r\n"
+// "Expect: 100-continue\r\n"
+ "\r\n{%s}";
+
+
+VOID SendWebRequest(SOCKET sock, char * Host, char * Request, char * Params, int Len, char * Return)
+{
+ int InputLen = 0;
+ int inptr = 0;
+ char Buffer[2048];
+ char Header[2048];
+ char * ptr, * ptr1;
+ int Sent;
+
+ sprintf(Header, HeaderTemplate, Request, Host, 80, Len + 2, Params);
+ Sent = send(sock, Header, (int)strlen(Header), 0);
+
+ if (Sent == -1)
+ {
+ int Err = WSAGetLastError();
+ Debugprintf("Error %d from Web Update send()", Err);
+ return;
+ }
+
+ while (InputLen != -1)
+ {
+ InputLen = recv(sock, &Buffer[inptr], 2048 - inptr, 0);
+
+ if (InputLen == -1 || InputLen == 0)
+ {
+ int Err = WSAGetLastError();
+ Debugprintf("Error %d from Web Update recv()", Err);
+ return;
+ }
+
+ // As we are using a persistant connection, can't look for close. Check
+ // for complete message
+
+ inptr += InputLen;
+
+ Buffer[inptr] = 0;
+
+ ptr = strstr(Buffer, "\r\n\r\n");
+
+ if (ptr)
+ {
+ // got header
+
+ int Hddrlen = (int)(ptr - Buffer);
+
+ ptr1 = strstr(Buffer, "Content-Length:");
+
+ if (ptr1)
+ {
+ // Have content length
+
+ int ContentLen = atoi(ptr1 + 16);
+
+ if (ContentLen + Hddrlen + 4 == inptr)
+ {
+ // got whole response
+
+ if (strstr(Buffer, " 200 OK"))
+ {
+ if (Return)
+ {
+ memcpy(Return, ptr + 4, ContentLen);
+ Return[ContentLen] = 0;
+ }
+ else
+ Debugprintf("Map Database update ok");
+
+ }
+ else
+ {
+ strlop(Buffer, 13);
+ Debugprintf("Map Update Params - %s", Params);
+ Debugprintf("Map Update failed - %s", Buffer);
+ }
+ return;
+ }
+ }
+ else
+ {
+ ptr1 = strstr(_strlwr(Buffer), "transfer-encoding:");
+
+ if (ptr1)
+ {
+ // Just accept anything until I've sorted things with Lee
+ Debugprintf("%s", ptr1);
+ Debugprintf("Web Database update ok");
+ return;
+ }
+ }
+ }
+ }
+}
+
+// https://packetnodes.spots.radio/api/NodeData/{callsign}
+
+//SendHTTPRequest(sock, "/account/exists", Message, Len, Response);
+
+extern char MYALIASLOPPED[10];
+
+void SendDataToPktMap(char *Msg)
+{
+ SOCKET sock;
+ char Return[256];
+ char Request[64];
+ char Params[16384];
+ char * ptr = Params;
+
+ sprintf(Request, "/api/NodeData/%s", MYNODECALL);
+
+ // This builds the request and sends it
+
+ // Minimum header seems to be
+
+ // "nodeAlias": "BPQ",
+ // "location": {"locator": "IO68VL"},
+ // "software": {"name": "BPQ32","version": "6.0.24.3"},
+
+ ptr += sprintf(ptr, "\"nodeAlias\": \"%s\",\r\n", MYALIASLOPPED);
+ ptr += sprintf(ptr, "\"locator\": \"%s\",\r\n", LOCATOR);
+#ifdef LINBPQ
+ ptr += sprintf(ptr, "\"software\": \"LinBPQ\",\"version\": \"%s\",\r\n", VersionString);
+#else
+ ptr += sprintf(ptr, "\"software\": \"BPQ32\",\"version\": \"%s\",\r\n", VersionString);
+#endif
+
+
+
+
+ // "contact": "string",
+ // "neighbours": [{"node": "G7TAJ","port": "30"}]
+
+ return;
+
+
+ sock = OpenHTTPSock("packetnodes.spots.radio");
+
+ SendWebRequest(sock, "packetnodes.spots.radio", Request, Params, strlen(Params), Return);
+ closesocket(sock);
+}
+
+// ="{\"neighbours\": [{\"node\": \"G7TAJ\",\"port\": \"30\"}]}";
+
+//'POST' \
+// 'https://packetnodes.spots.radio/api/NodeData/GM8BPQ' \
+// -H 'accept: */*' \
+// -H 'Content-Type: application/json' \
+// -d '{
+// "nodeAlias": "BPQ",
+// "location": {"locator": "IO68VL"},
+// "software": {"name": "BPQ32","version": "6.0.24.3"},
+// "contact": "string",
+// "neighbours": [{"node": "G7TAJ","port": "30"}]
+//}'
+
+
+
+
+
diff --git a/FBBRoutines.c b/FBBRoutines.c
index 2fae431..051afe6 100644
--- a/FBBRoutines.c
+++ b/FBBRoutines.c
@@ -472,7 +472,7 @@ ok:
// Check Filters
- if (CheckRejFilters(FBBHeader->From, FBBHeader->To, FBBHeader->ATBBS, FBBHeader->BID, FBBHeader->MsgType))
+ if (CheckRejFilters(FBBHeader->From, FBBHeader->To, FBBHeader->ATBBS, FBBHeader->BID, FBBHeader->MsgType, FBBHeader->Size))
{
memset(FBBHeader, 0, sizeof(struct FBBHeaderLine)); // Clear header
conn->FBBReplyChars[conn->FBBReplyIndex++] = '-';
@@ -604,7 +604,7 @@ ok:
char * To = strtok_s(NULL, seps, &Context);
char * Type = strtok_s(NULL, seps, &Context);
- if (From && To && ATBBS && Type && CheckRejFilters(From, To, ATBBS, NULL, *Type))
+ if (From && To && ATBBS && Type && CheckRejFilters(From, To, ATBBS, NULL, *Type, FBBHeader->Size))
{
memset(FBBHeader, 0, sizeof(struct FBBHeaderLine)); // Clear header
conn->FBBReplyChars[conn->FBBReplyIndex++] = '-';
diff --git a/HanksRT.c b/HanksRT.c
index d78c610..7e8487c 100644
--- a/HanksRT.c
+++ b/HanksRT.c
@@ -75,6 +75,7 @@ char ChatWelcomeMsg[1000];
char Position[81] = "";
char PopupText[260] = "";
int PopupMode = 0;
+int chatPaclen = 236;
char RtKnown[MAX_PATH] = "RTKnown.txt";
char RtUsr[MAX_PATH] = "STUsers.txt";
@@ -97,6 +98,7 @@ int ChatTmr = 0;
BOOL NeedStatus = FALSE;
+
char Verstring[80];
static void node_dec(CHATNODE *node);
@@ -3863,7 +3865,7 @@ int ChatConnected(int Stream)
if (conn->rtcflags == p_linkini)
{
- conn->paclen = 236;
+ conn->paclen = chatPaclen;
// Run first line of connect script
@@ -3883,6 +3885,9 @@ int ChatConnected(int Stream)
if (paclen == 0)
paclen = 256;
+ if (paclen > chatPaclen)
+ paclen = chatPaclen;
+
conn->paclen = paclen;
strlop(callsign, ' '); // Remove trailing spaces
@@ -4163,12 +4168,19 @@ BOOL GetChatConfig(char * ConfigName)
ChatApplNum = GetIntValue(group, "ApplNum");
MaxChatStreams = GetIntValue(group, "MaxStreams");
+ chatPaclen = GetIntValue(group, "chatPaclen");
GetStringValue(group, "OtherChatNodes", OtherNodesList);
GetStringValue(group, "ChatWelcomeMsg", ChatWelcomeMsg);
GetStringValue(group, "MapPosition", Position);
GetStringValue(group, "MapPopup", PopupText);
PopupMode = GetIntValue(group, "PopupMode");
+ if (chatPaclen == 0)
+ chatPaclen = 236;
+
+ if (chatPaclen < 60)
+ chatPaclen = 60;
+
return EXIT_SUCCESS;
}
@@ -4187,6 +4199,7 @@ VOID SaveChatConfigFile(char * ConfigName)
SaveIntValue(group, "ApplNum", ChatApplNum);
SaveIntValue(group, "MaxStreams", MaxChatStreams);
+ SaveIntValue(group, "chatPaclen", chatPaclen);
SaveStringValue(group, "OtherChatNodes", OtherNodesList);
SaveStringValue(group, "ChatWelcomeMsg", ChatWelcomeMsg);
diff --git a/L2Code.c b/L2Code.c
index 1b4d8f7..920c35c 100644
--- a/L2Code.c
+++ b/L2Code.c
@@ -965,6 +965,11 @@ VOID ProcessXIDCommand(struct _LINKTABLE * LINK, struct PORTCONTROL * PORT, MESS
L2SWAPADDRESSES(Buffer); // SWAP ADDRESSES AND SET RESP BITS
+ // We need to save APPLMASK and ALIASPTR so following SABM connects to application
+
+ LINK->APPLMASK = APPLMASK;
+ LINK->ALIASPTR = ALIASPTR;
+
PUT_ON_PORT_Q(PORT, Buffer);
return;
}
@@ -1089,6 +1094,9 @@ VOID L2LINKACTIVE(struct _LINKTABLE * LINK, struct PORTCONTROL * PORT, MESSAGE *
if (LINK->L2STATE == 1) // Sent XID?
{
+ APPLMASK = LINK->APPLMASK;
+ ALIASPTR = LINK->ALIASPTR;
+
L2SABM(LINK, PORT, Buffer, ADJBUFFER, MSGFLAG); // Process the SABM
return;
}
@@ -1351,7 +1359,7 @@ VOID L2SABM(struct _LINKTABLE * LINK, struct PORTCONTROL * PORT, MESSAGE * Buffe
{
Msg->PID = 0xf0;
- memcpy(Msg->L2DATA, APPL->APPLCMD, 12);
+ memcpy(Msg->L2DATA, ALIASPTR, 12);
Msg->L2DATA[12] = 13;
Msg->LENGTH = MSGHDDRLEN + 12 + 2; // 2 for PID and CR
diff --git a/MailNode.ncb b/MailNode.ncb
new file mode 100644
index 0000000..233beff
Binary files /dev/null and b/MailNode.ncb differ
diff --git a/MailNode.vcproj.DESKTOP-MHE5LO8.johnw.user b/MailNode.vcproj.DESKTOP-MHE5LO8.johnw.user
new file mode 100644
index 0000000..f8980b0
--- /dev/null
+++ b/MailNode.vcproj.DESKTOP-MHE5LO8.johnw.user
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/MailNode.vcxproj b/MailNode.vcxproj
index c9fd8a9..d98f512 100644
--- a/MailNode.vcxproj
+++ b/MailNode.vcxproj
@@ -5,24 +5,17 @@
Debug
Win32
-
- Debug
- x64
-
Release
Win32
-
- Release
- x64
-
LinBPQ
{3766AA10-C777-4ED8-A83D-F1452DE9B666}
MailNode
Win32Proj
+ 10.0.17763.0
@@ -31,37 +24,20 @@
NotSet
true
-
- Application
- v141
- NotSet
- true
-
Application
v141
NotSet
-
- Application
- v141
- NotSet
-
-
-
-
-
-
-
<_ProjectFileVersion>15.0.28307.799
@@ -71,17 +47,11 @@
C:\Dev\Msdev2005\Intermed\$(SolutionName)\$(ProjectName)\$(Configuration)\
true
-
- true
-
C:\Dev\Msdev2005\$(SolutionName)\$(ProjectName)\$(Configuration)\
C:\Dev\Msdev2005\Intermed\$(SolutionName)\$(ProjectName)\$(Configuration)\
false
-
- false
-
Disabled
@@ -106,30 +76,6 @@
MachineX86
-
-
- Disabled
- ..\CKernel;..\CommonSource;..\CInclude;%(AdditionalIncludeDirectories)
- WIN32;_DEBUG;_CONSOLE;LINBPQ;%(PreprocessorDefinitions)
- EnableFastChecks
- MultiThreadedDebug
-
-
- Level3
- ProgramDatabase
-
-
- kernel32.lib;WS2_32.Lib;C:\OneDrive\Dev\Source\bpq32\libconfig\x64\Release\libconfig.lib;DbgHelp.lib;setupapi.lib;C:\OneDrive\Dev\Source\miniupnpc-2.2.3\msvc\x64\Debug\miniupnpc.lib;C:\Users\johnw\Downloads\zlib-1.2.11-binaries-x64-release\zlib-1.2.11\binaries\x64\Release\zlib.lib;%(AdditionalDependencies)
- c:\LINBPQ\$(ProjectName).exe
- true
- true
- c:\linbpq\linmail.map
- Console
- 4000000
- 0
- false
-
-
..\CKernel;..\CommonSource;..\CInclude;%(AdditionalIncludeDirectories)
@@ -151,27 +97,6 @@
MachineX86
-
-
- ..\CKernel;..\CommonSource;..\CInclude;%(AdditionalIncludeDirectories)
- WIN32;NDEBUG;_CONSOLE;LINBPQ;_USE_32BIT_TIME_T;%(PreprocessorDefinitions)
- MultiThreaded
-
-
- Level3
- ProgramDatabase
-
-
- kernel32.lib;WS2_32.Lib;..\lib\libconfig.lib;DbgHelp.lib;Setupapi.lib;miniupnpc.lib;zlibstat.lib;%(AdditionalDependencies)
- c:\devprogs\bpq32\LinBPQ.exe
- true
- Console
- 5000000
- 10000000
- true
- true
-
-
@@ -188,12 +113,8 @@
-
-
All
- All
$(IntDir)
- $(IntDir)
diff --git a/MailTCP-DESKTOP-MHE5LO8.c b/MailTCP-DESKTOP-MHE5LO8.c
new file mode 100644
index 0000000..b26f6da
--- /dev/null
+++ b/MailTCP-DESKTOP-MHE5LO8.c
@@ -0,0 +1,4127 @@
+/*
+Copyright 2001-2018 John Wiseman G8BPQ
+
+This file is part of LinBPQ/BPQ32.
+
+LinBPQ/BPQ32 is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+LinBPQ/BPQ32 is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses
+*/
+
+// Mail and Chat Server for BPQ32 Packet Switch
+//
+// TCP access module - POP and SMTP
+
+#include "bpqmail.h"
+
+VOID ReleaseSock(SOCKET sock);
+void Base64EncodeAndSend(SocketConn * sockptr, UCHAR * Msg, int Len);
+
+#define MaxSockets 64
+
+SocketConn * Sockets = NULL;
+
+int CurrentConnections;
+
+int CurrentSockets=0;
+
+#define MAX_PENDING_CONNECTS 4
+
+#define VERSION_MAJOR 2
+#define VERSION_MINOR 0
+
+static SOCKADDR_IN local_sin; /* Local socket - internet style */
+static PSOCKADDR_IN psin;
+
+SOCKET smtpsock, pop3sock;
+
+char szBuff[80];
+
+int SMTPInPort;
+int POP3InPort;
+
+BOOL RemoteEmail; // Set to listen on INADDR_ANY rather than LOCALHOST
+
+BOOL ISP_Gateway_Enabled;
+
+char MyDomain[50]; // Mail domain for BBS<>Internet Mapping
+
+char ISPSMTPName[50];
+char ISPEHLOName[50] = "";
+
+int ISPSMTPPort;
+
+char ISPPOP3Name[50];
+int ISPPOP3Port;
+
+char ISPAccountName[50];
+char ISPAccountPass[50];
+char EncryptedISPAccountPass[100];
+int EncryptedPassLen;
+
+BOOL SMTPAuthNeeded;
+
+BOOL GMailMode = FALSE;
+char GMailName[50];
+
+int POP3Timer=9999; // Run on startup
+int ISPPOP3Interval;
+
+BOOL SMTPMsgCreated=FALSE; // Set to cause SMTP client to send messages to ISP
+BOOL SMTPActive=FALSE; // SO we don't try every 10 secs!
+
+char mycd64[256];
+static const char cb64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static const char cd64[]="|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW$$$$$$XYZ[\\]^_`abcdefghijklmnopq";
+
+char sockTypes[6][12] = {"Undefined", "SMTPServer", "POP3Server", "SMTPClient", "POP3Client", "NNTPServer"};
+
+void decodeblock( unsigned char in[4], unsigned char out[3] );
+VOID FormatTime(char * Time, time_t cTime);
+static int Socket_Accept(SOCKET SocketId);
+
+int SendSock(SocketConn * sockptr, char * msg)
+{
+ int len = (int)strlen(msg), sent;
+ char * newmsg = malloc(len+10);
+
+ WriteLogLine(NULL, '>',msg, len, LOG_TCP);
+
+ strcpy(newmsg, msg);
+
+ strcat(newmsg, "\r\n");
+
+ len+=2;
+
+ if (sockptr->SendBuffer)
+ {
+ // Already queued, so add to end
+
+ if ((sockptr->SendSize + len) > sockptr->SendBufferSize)
+ {
+ sockptr->SendBufferSize += (10000 + len);
+ sockptr->SendBuffer = realloc(sockptr->SendBuffer, sockptr->SendBufferSize);
+ }
+
+ memcpy(&sockptr->SendBuffer[sockptr->SendSize], newmsg, len);
+ sockptr->SendSize += len;
+ free (newmsg);
+ return len;
+ }
+
+ sent = send(sockptr->socket, newmsg, len, 0);
+
+ if (sent < len)
+ {
+ int error, remains;
+
+ // Not all could be sent - queue rest
+
+ if (sent == SOCKET_ERROR)
+ {
+ error = WSAGetLastError();
+ if (error == WSAEWOULDBLOCK)
+ sent=0;
+
+ // What else??
+ }
+
+ remains = len - sent;
+
+ sockptr->SendBufferSize += (10000 + remains);
+ sockptr->SendBuffer = malloc(sockptr->SendBufferSize);
+
+ memcpy(sockptr->SendBuffer, &newmsg[sent], remains);
+
+ sockptr->SendSize = remains;
+ sockptr->SendPtr = 0;
+
+ }
+
+ free (newmsg);
+
+ return sent;
+}
+
+VOID __cdecl sockprintf(SocketConn * sockptr, const char * format, ...)
+{
+ // printf to a socket
+
+ char buff[1000];
+ va_list(arglist);
+
+ va_start(arglist, format);
+ vsprintf(buff, format, arglist);
+
+ SendSock(sockptr, buff);
+}
+
+extern int SMTPMsgs;
+
+fd_set ListenSet;
+SOCKET ListenMax = 0;
+
+extern SOCKET nntpsock;
+
+int NNTP_Read(SocketConn * sockptr, SOCKET sock);
+
+VOID SetupListenSet()
+{
+ // Set up master set of fd's for checking for incoming calls
+
+ fd_set * readfd = &ListenSet;
+ SOCKET sock;
+
+ FD_ZERO(readfd);
+
+ sock = nntpsock;
+ if (sock)
+ {
+ FD_SET(sock, readfd);
+ if (sock > ListenMax)
+ ListenMax = sock;
+ }
+
+ sock = smtpsock;
+ if (sock)
+ {
+ FD_SET(sock, readfd);
+ if (sock > ListenMax)
+ ListenMax = sock;
+ }
+
+ sock = pop3sock;
+
+ if (sock)
+ {
+ FD_SET(sock, readfd);
+ if (sock > ListenMax)
+ ListenMax = sock;
+ }
+}
+
+VOID Socket_Connected(SocketConn * sockptr, int error)
+{
+ SOCKET sock = sockptr->socket;
+
+ if (error)
+ {
+ Logprintf(LOG_TCP, NULL, '|', "Connect Failed");
+
+ if (sockptr->Type == SMTPClient)
+ SMTPActive = FALSE;
+
+ ReleaseSock(sock);
+
+ return;
+ }
+
+ sockptr->State = WaitingForGreeting;
+
+ if (sockptr->Type == NNTPServer)
+ SendSock(sockptr, "200 BPQMail NNTP Server ready");
+
+ else if (sockptr->Type == SMTPServer)
+ SendSock(sockptr, "220 BPQMail SMTP Server ready");
+
+ else if (sockptr->Type == POP3SLAVE)
+ {
+ SendSock(sockptr, "+OK POP3 server ready");
+ sockptr->State = GettingUser;
+ }
+}
+
+VOID TCPFastTimer()
+{
+ // we now poll for incoming connections and data
+
+ fd_set readfd, writefd, exceptfd;
+ struct timeval timeout;
+ int retval;
+ SocketConn * sockptr = Sockets;
+ SOCKET sock;
+ int Active = 0;
+ SOCKET maxsock;
+
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0; // poll
+
+ if (ListenMax)
+ {
+ memcpy(&readfd, &ListenSet, sizeof(fd_set));
+
+ retval = select((int)ListenMax + 1, &readfd, NULL, NULL, &timeout);
+
+ if (retval == -1)
+ {
+ retval = 0;
+ perror("Listen select");
+ }
+
+ if (retval)
+ {
+ sock = pop3sock;
+ if (sock)
+ if (FD_ISSET(sock, &readfd))
+ Socket_Accept(sock);
+
+ sock = smtpsock;
+ if (sock)
+ if (FD_ISSET(sock, &readfd))
+ Socket_Accept(sock);
+
+ sock = nntpsock;
+ if (sock)
+ if (FD_ISSET(sock, &readfd))
+ NNTP_Accept(sock);
+ }
+ }
+
+ // look for data on any active sockets
+
+ maxsock = 0;
+
+ FD_ZERO(&readfd);
+ FD_ZERO(&writefd);
+ FD_ZERO(&exceptfd);
+ sockptr=Sockets;
+
+ while (sockptr)
+ {
+ sockptr->Timeout++;
+
+ if (sockptr->Timeout > 1200) // 2 mins
+ {
+ Logprintf(LOG_TCP, NULL, '|', "Timeout on Socket = %d", sockptr->socket);
+ shutdown(sockptr->socket, 0);
+ closesocket(sockptr->socket);
+ ReleaseSock(sockptr->socket);
+
+ return; // We've messed with chain
+ }
+
+ if (sockptr->State & Connecting)
+ {
+ // look for complete or failed
+
+ FD_SET(sockptr->socket, &writefd);
+ FD_SET(sockptr->socket, &exceptfd);
+ }
+ else
+ FD_SET(sockptr->socket, &readfd);
+
+ Active++;
+
+ if (sockptr->socket > maxsock)
+ maxsock = sockptr->socket;
+
+ sockptr = sockptr->Next;
+ }
+
+ if (Active == 0)
+ return;
+
+ retval = select((int)maxsock + 1, &readfd, &writefd, &exceptfd, &timeout);
+
+ if (retval == -1)
+ {
+ perror("select");
+
+ // we need to do something or the error will recur.
+ // As there are unlikely to be a lot of open tcp connections perhaps
+ // simplest is to close all
+
+ sockptr = Sockets;
+
+ while (sockptr)
+ {
+ Debugprintf("MAILTCP Select Failed Active %s Socket", sockTypes[sockptr->Type]);
+ shutdown(sockptr->socket, 0);
+ closesocket(sockptr->socket);
+ ReleaseSock(sockptr->socket);
+
+ sockptr = Sockets; // We've messed with chain
+ }
+ }
+ else
+ {
+ if (retval)
+ {
+ sockptr = Sockets;
+
+ // see who has data
+
+ while (sockptr)
+ {
+ sock = sockptr->socket;
+
+ if (FD_ISSET(sock, &readfd))
+ {
+ sockptr->Timeout = 0;
+
+ if (sockptr->Type == NNTPServer)
+ {
+ if (NNTP_Read(sockptr, sock) == 0)
+ break; // We've messed with the chain
+ }
+ else
+ {
+ if (DataSocket_Read(sockptr, sock) == 0)
+ break; // We've messed with the chain
+ }
+ }
+ if (FD_ISSET(sockptr->socket, &writefd))
+ Socket_Connected(sockptr, 0);
+
+ if (FD_ISSET(sockptr->socket, &exceptfd))
+ {
+ Socket_Connected(sockptr, 1);
+ return;
+ }
+ sockptr = sockptr->Next;
+ }
+ }
+ }
+}
+
+VOID TCPTimer()
+{
+ POP3Timer+=10;
+
+// Debugprintf("POP3 Debug Timer = %d Interval = %d Port %d Enabled %d",
+// POP3Timer, ISPPOP3Interval, ISPPOP3Port, ISP_Gateway_Enabled);
+
+ if (POP3Timer > ISPPOP3Interval) // 5 mins
+ {
+ POP3Timer=0;
+
+ if ((ISPSMTPPort && ISP_Gateway_Enabled))
+ SendtoISP();
+
+ if (ISPPOP3Port && ISP_Gateway_Enabled)
+ {
+// Debugprintf("Calling POP3 Connect");
+ POP3Connect(ISPPOP3Name, ISPPOP3Port);
+ }
+
+ if (SMTPMsgs && ISPSMTPPort && ISP_Gateway_Enabled)
+ SendtoISP();
+ }
+ else
+ {
+ if (SMTPMsgCreated && ISPSMTPPort && ISP_Gateway_Enabled)
+ SendtoISP();
+ }
+}
+BOOL InitialiseTCP()
+{
+ int Error; // catches return value of WSAStartup
+#ifdef WIN32
+ WORD VersionRequested; // passed to WSAStartup
+ WSADATA WsaData; // receives data from WSAStartup
+#endif
+ int i,j;
+
+
+ for (i=0;i<64; i++)
+ {
+ j=cb64[i];
+ mycd64[j]=i;
+ }
+
+#ifdef WIN32
+
+ VersionRequested = MAKEWORD(VERSION_MAJOR, VERSION_MINOR);
+
+ Error = WSAStartup(VersionRequested, &WsaData);
+
+ if (Error)
+ {
+#ifndef LINBPQ
+ MessageBox(NULL,
+ "Could not find high enough version of WinSock",
+ "BPQMailChat", MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
+#else
+ printf("Could not find high enough version of WinSock\n");
+#endif
+ return FALSE;
+ }
+
+#endif
+
+// Create listening sockets
+
+
+ if (SMTPInPort)
+ smtpsock = CreateListeningSocket(SMTPInPort);
+
+ if (POP3InPort)
+ pop3sock = CreateListeningSocket(POP3InPort);
+
+ if (ISP_Gateway_Enabled)
+ {
+ // See if using GMail
+
+ char * ptr = strchr(ISPAccountName, '@');
+
+ if (ptr)
+ {
+ if (_stricmp(&ptr[1], "gmail.com") == 0 || _stricmp(&ptr[1], "googlemail.com") == 0)
+ {
+ strcpy(GMailName, ISPAccountName);
+ strlop(GMailName, '@');
+ GMailMode = TRUE;
+ SMTPAuthNeeded = TRUE;
+ }
+ }
+ }
+
+ return TRUE;
+
+}
+
+
+SOCKET CreateListeningSocket(int Port)
+{
+ SOCKET sock;
+ unsigned int param = 1;
+
+ sock = socket( AF_INET, SOCK_STREAM, 0);
+
+ if (sock == INVALID_SOCKET)
+ {
+ sprintf(szBuff, "socket() failed error %d", WSAGetLastError());
+#ifdef LINBPQ
+ perror(szBuff);
+#else
+ MessageBox(MainWnd, szBuff, "BPQMailChat", MB_OK);
+#endif
+ return FALSE;
+ }
+
+ setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, (char *)¶m,4);
+
+ psin=&local_sin;
+
+ psin->sin_family = AF_INET;
+ psin->sin_addr.s_addr = htonl(RemoteEmail ? INADDR_ANY : INADDR_LOOPBACK); // Local Host Olny
+
+ psin->sin_port = htons(Port); /* Convert to network ordering */
+
+ if (bind( sock, (struct sockaddr FAR *) &local_sin, sizeof(local_sin)) == SOCKET_ERROR)
+ {
+ sprintf(szBuff, "bind(%d) failed Error %d", Port, WSAGetLastError());
+#ifdef LINBPQ
+ perror(szBuff);
+#else
+ MessageBox(MainWnd, szBuff, "BPQMailChat", MB_OK);
+#endif
+ closesocket( sock );
+ return FALSE;
+ }
+
+ if (listen( sock, MAX_PENDING_CONNECTS ) < 0)
+ {
+ sprintf(szBuff, "listen(%d) failed Error %d", Port, WSAGetLastError());
+#ifdef LINBPQ
+ perror(szBuff);
+#else
+ MessageBox(MainWnd, szBuff, "BPQMailChat", MB_OK);
+#endif
+ closesocket( sock );
+ return FALSE;
+ }
+
+ ioctl(sock, FIONBIO, ¶m);
+ return sock;
+}
+
+static int Socket_Accept(SOCKET SocketId)
+{
+ int addrlen;
+ SocketConn * sockptr;
+ SOCKET sock;
+ unsigned int param = 1;
+
+ addrlen=sizeof(struct sockaddr);
+
+ // Allocate a Socket entry
+
+ sockptr = malloc(sizeof(SocketConn));
+ memset(sockptr, 0, sizeof (SocketConn));
+
+ sockptr->Next = Sockets;
+ Sockets = sockptr;
+
+ sock = accept(SocketId, (struct sockaddr *)&sockptr->sin, &addrlen);
+
+ if (sock == INVALID_SOCKET)
+ {
+ Logprintf(LOG_TCP, NULL, '|', " accept() failed Error %d", WSAGetLastError());
+
+ // get rid of socket record
+
+ Sockets = sockptr->Next;
+ free(sockptr);
+ return FALSE;
+ }
+
+ ioctl(sock, FIONBIO, ¶m);
+
+
+ sockptr->socket = sock;
+
+ if (SocketId == pop3sock)
+ {
+ sockptr->Type = POP3SLAVE;
+ SendSock(sockptr, "+OK POP3 server ready");
+ sockptr->State = GettingUser;
+ Logprintf(LOG_TCP, NULL, '|', "Incoming POP3 Connect Socket = %d", sock);
+ }
+ else
+ {
+ sockptr->Type = SMTPServer;
+ sockptr->State = WaitingForGreeting;
+ SendSock(sockptr, "220 BPQMail SMTP Server ready");
+ Logprintf(LOG_TCP, NULL, '|', "Incoming SMTP Connect Socket = %d", sock);
+ }
+
+ return 0;
+}
+
+
+VOID ReleaseSock(SOCKET sock)
+{
+ // remove and free the socket record
+
+ SocketConn * sockptr, * lastptr;
+
+ sockptr=Sockets;
+ lastptr=NULL;
+
+ while (sockptr)
+ {
+ if (sockptr->socket == sock)
+ {
+ if (lastptr)
+ lastptr->Next=sockptr->Next;
+ else
+ Sockets=sockptr->Next;
+
+ if (sockptr->POP3User)
+ sockptr->POP3User->POP3Locked = FALSE;
+
+ if (sockptr->State == WaitingForGreeting)
+ {
+ Logprintf(LOG_TCP, NULL, '|', "Premature Close on Socket %d", sock);
+
+ if (sockptr->Type == SMTPClient)
+ SMTPActive = FALSE;
+ }
+ else
+ Logprintf(LOG_TCP, NULL, '|', "Socket %d Closed", sock);
+
+
+ free(sockptr);
+ return;
+ }
+ else
+ {
+ lastptr=sockptr;
+ sockptr=sockptr->Next;
+ }
+ }
+}
+
+/*
+int Socket_Data(int sock, int error, int eventcode)
+{
+ SocketConn * sockptr;
+
+ // Find Connection Record
+
+ sockptr=Sockets;
+
+ while (sockptr)
+ {
+ if (sockptr->socket == sock)
+ {
+ switch (eventcode)
+ {
+ case FD_READ:
+
+ return DataSocket_Read(sockptr,sock);
+
+ case FD_WRITE:
+
+ // Either Just connected, or flow contorl cleared
+
+ if (sockptr->SendBuffer)
+ // Data Queued
+ SendFromQueue(sockptr);
+ else
+ {
+ if (sockptr->Type == SMTPServer)
+ SendSock(sockptr, "220 BPQMail SMTP Server ready");
+ else
+ {
+ if (sockptr->Type == POP3SLAVE)
+ {
+ SendSock(sockptr, "+OK POP3 server ready");
+ sockptr->State = GettingUser;
+ }
+ }
+ }
+ return 0;
+
+ case FD_OOB:
+
+ return 0;
+
+ case FD_ACCEPT:
+
+ return 0;
+
+ case FD_CONNECT:
+
+ return 0;
+
+ case FD_CLOSE:
+
+ closesocket(sock);
+ ReleaseSock(sock);
+ return 0;
+ }
+ return 0;
+ }
+ else
+ sockptr=sockptr->Next;
+ }
+
+ return 0;
+}
+*/
+int DataSocket_Read(SocketConn * sockptr, SOCKET sock)
+{
+ int InputLen, MsgLen;
+ char * ptr, * ptr2;
+ char Buffer[2000];
+
+ // May have several messages per packet, or message split over packets
+
+ if (sockptr->InputLen > 1000) // Shouldnt have lines longer than this in text mode
+ {
+ sockptr->InputLen=0;
+ }
+
+ InputLen=recv(sock, &sockptr->TCPBuffer[sockptr->InputLen], 1000, 0);
+
+ if (InputLen <= 0)
+ {
+ int x = WSAGetLastError();
+
+ closesocket(sock);
+ ReleaseSock(sock);
+
+ return 0; // Does this mean closed?
+ }
+
+ sockptr->InputLen += InputLen;
+
+loop:
+
+ ptr = memchr(sockptr->TCPBuffer, '\n', sockptr->InputLen);
+
+ if (ptr) // CR in buffer
+ {
+ ptr2 = &sockptr->TCPBuffer[sockptr->InputLen];
+ ptr++; // Assume LF Follows CR
+
+ if (ptr == ptr2)
+ {
+ // Usual Case - single meg in buffer
+
+ if (sockptr->Type == SMTPServer)
+ ProcessSMTPServerMessage(sockptr, sockptr->TCPBuffer, sockptr->InputLen);
+ else
+ if (sockptr->Type == POP3SLAVE)
+ ProcessPOP3ServerMessage(sockptr, sockptr->TCPBuffer, sockptr->InputLen);
+ else
+ if (sockptr->Type == SMTPClient)
+ ProcessSMTPClientMessage(sockptr, sockptr->TCPBuffer, sockptr->InputLen);
+ else
+ if (sockptr->Type == POP3Client)
+ ProcessPOP3ClientMessage(sockptr, sockptr->TCPBuffer, sockptr->InputLen);
+
+ sockptr->InputLen=0;
+
+ }
+ else
+ {
+ // buffer contains more that 1 message
+
+ MsgLen = sockptr->InputLen - (int)(ptr2-ptr);
+
+ memcpy(Buffer, sockptr->TCPBuffer, MsgLen);
+
+
+ if (sockptr->Type == SMTPServer)
+ ProcessSMTPServerMessage(sockptr, Buffer, MsgLen);
+ else
+ if (sockptr->Type == POP3SLAVE)
+ ProcessPOP3ServerMessage(sockptr, Buffer, MsgLen);
+ else
+ if (sockptr->Type == SMTPClient)
+ ProcessSMTPClientMessage(sockptr, Buffer, MsgLen);
+ else
+ if (sockptr->Type == POP3Client)
+ ProcessPOP3ClientMessage(sockptr, Buffer, MsgLen);
+
+
+ memmove(sockptr->TCPBuffer, ptr, sockptr->InputLen-MsgLen);
+
+ sockptr->InputLen -= MsgLen;
+
+ goto loop;
+
+ }
+ }
+ return TRUE;
+}
+
+char * FindPart(char ** Msg, char * Boundary, int * PartLen)
+{
+ char * ptr = *Msg, * ptr2;
+ char * Msgptr = *Msg;
+ int BLen = (int)strlen(Boundary);
+ char * Part;
+
+ while(*ptr) // Just in case we run off end
+ {
+ ptr2 = strchr(ptr, 10); // Find LF
+
+ if (ptr2 == NULL) return NULL;
+
+ if (*ptr == '-' && *(ptr+1) == '-')
+ {
+ if (memcmp(&ptr[2], Boundary, BLen) == 0)
+ {
+ // Found Boundary
+
+ int Partlen = (int)(ptr - Msgptr);
+ Part = malloc(Partlen + 1);
+ memcpy(Part, Msgptr, Partlen);
+ Part[Partlen] = 0;
+
+ *Msg = ++ptr2;
+
+ *PartLen = Partlen;
+
+ return Part;
+ }
+ }
+
+ ptr = ++ptr2;
+ }
+ return NULL;
+}
+
+
+
+
+
+BOOL CheckforMIME(SocketConn * sockptr, char * Msg, char ** Body, int * MsgLen) // Will reformat message if necessary.
+{
+ int i;
+ char * ptr, * ptr2, * ptr3, * ptr4;
+ char Boundary[1000];
+ BOOL Multipart = FALSE;
+ BOOL ALT = FALSE;
+ int Partlen;
+ char * Save;
+ BOOL Base64 = FALSE;
+ BOOL QuotedP = FALSE;
+
+ char FileName[100][250] = {""};
+ int FileLen[100];
+ char * FileBody[100];
+ char * MallocSave[100];
+ UCHAR * NewMsg;
+
+ int Files = 0;
+
+ ptr = Msg;
+
+ while(*ptr != 13)
+ {
+ ptr2 = strchr(ptr, 10); // Find CR
+
+ while(ptr2[1] == ' ' || ptr2[1] == 9) // Whitespace - continuation line
+ {
+ ptr2 = strchr(&ptr2[1], 10); // Find CR
+ }
+
+// Content-Type: multipart/mixed;
+// boundary="----=_NextPart_000_025B_01CAA004.84449180"
+// 7.2.2 The Multipart/mixed (primary) subtype
+// 7.2.3 The Multipart/alternative subtype
+
+
+ if (_memicmp(ptr, "Content-Type: ", 14) == 0)
+ {
+ char Line[1000] = "";
+ char lcLine[1000] = "";
+
+ char * ptr3;
+
+ memcpy(Line, &ptr[14], ptr2-ptr-14);
+ memcpy(lcLine, &ptr[14], ptr2-ptr-14);
+ _strlwr(lcLine);
+
+ if (_memicmp(Line, "Multipart/", 10) == 0)
+ {
+ Multipart = TRUE;
+
+ if (_memicmp(&Line[10], "alternative", 11) == 0)
+ {
+ ALT = TRUE;
+ }
+
+ ptr3 = strstr(Line, "boundary");
+
+ if (ptr3)
+ {
+ ptr3+=9;
+
+ if ((*ptr3) == '"')
+ ptr3++;
+
+ strcpy(Boundary, ptr3);
+ ptr3 = strchr(Boundary, '"');
+ if (ptr3) *ptr3 = 0;
+ ptr3 = strchr(Boundary, 13); // CR
+ if (ptr3) *ptr3 = 0;
+
+ }
+ else
+ return FALSE; // Can't do anything without a boundary ??
+ }
+
+ }
+
+ else if (_memicmp(ptr, "Content-Transfer-Encoding:", 26) == 0)
+ {
+ if (strstr(&ptr[26], "base64"))
+ Base64 = TRUE;
+ else
+ if (strstr(&ptr[26], "quoted-printable"))
+ QuotedP = TRUE;
+ }
+
+
+ ptr = ptr2;
+ ptr++;
+
+ }
+
+ if (Multipart == FALSE)
+ {
+ // We only have one part, but it could have an odd encoding
+
+ if (Base64)
+ {
+ int i = 0, Len = *MsgLen, NewLen;
+ char * ptr2;
+ char * End;
+
+ ptr = ptr2 = *Body;
+ End = ptr + Len;
+
+ while (ptr < End)
+ {
+ while (*ptr < 33)
+ {ptr++;}
+
+ *ptr2++ = *ptr++;
+ }
+
+ *ptr2 = 0;
+
+ ptr = *Body;
+ Len = (int)(ptr2 - ptr - 1);
+
+ ptr2 = ptr;
+
+ while (Len > 0)
+ {
+ decodeblock(ptr, ptr2);
+ ptr += 4;
+ ptr2 += 3;
+ Len -= 4;
+ }
+
+ NewLen = (int)(ptr2 - *Body);
+
+ if (*(ptr-1) == '=')
+ NewLen--;
+
+ if (*(ptr-2) == '=')
+ NewLen--;
+
+ *MsgLen = NewLen;
+ }
+ else if (QuotedP)
+ {
+ int i = 0, Len = *MsgLen;
+ char * ptr2;
+ char * End;
+
+ ptr = ptr2 =*Body;
+
+ End = ptr + Len;
+
+ while (ptr < End)
+ {
+ if ((*ptr) == '=')
+ {
+ char c = *(++ptr);
+ char d;
+
+ c = c - 48;
+ if (c < 0)
+ {
+ // = CRLF as a soft break
+
+ ptr += 2;
+ continue;
+ }
+
+ if (c > 9)
+ c -= 7;
+ d = *(++ptr);
+ d = d - 48;
+ if (d > 9)
+ d -= 7;
+
+ *(ptr2) = c << 4 | d;
+ ptr2++;
+ ptr++;
+ }
+ else
+ {
+ *ptr2++ = *ptr++;
+ }
+ }
+ *ptr2 = 0;
+
+ *MsgLen = (int)(ptr2 - *Body);
+
+ }
+
+ return FALSE;
+ }
+ // FindPart Returns Next Part of Message, Updates Input Pointer
+ // Skip to first Boundary (over the non MIME Alt Part)
+
+ ptr = FindPart(Body, Boundary, &Partlen);
+
+ if (ptr == NULL)
+ return FALSE; // Couldn't find separator
+
+ free(ptr);
+
+ if (ALT)
+ {
+ // Assume HTML and Plain Text Versions of the same single body.
+
+ ptr = FindPart(Body, Boundary, &Partlen);
+
+ Save = ptr; // For free();
+
+ // Should be the First (Least desireable part, but the bit we want, as we are only interested in plain text)
+
+ // Skip any headers
+
+ while(*ptr != 13)
+ {
+ if (_memicmp(ptr, "Content-Transfer-Encoding:", 26) == 0)
+ {
+ if (strstr(&ptr[26], "base64"))
+ Base64 = TRUE;
+ else
+ if (strstr(&ptr[26], "quoted-printable"))
+ QuotedP = TRUE;
+ }
+
+ ptr2 = strchr(ptr, 10); // Find CR
+
+ while(ptr2[1] == ' ' || ptr2[1] == 9) // Whitespace - continuation line
+ {
+ ptr2 = strchr(&ptr2[1], 10); // Find CR
+ }
+
+ ptr = ++ptr2;
+ }
+
+ ptr += 2; // Skip rerminating line
+
+ // Should now have a plain text body to return;
+
+ // But could be an odd encoding
+
+ if (Base64)
+ {
+ int i = 0, Len = (int)strlen(ptr), NewLen;
+ char * ptr2;
+ char * End;
+ char * Save = ptr;
+
+ ptr2 = ptr;
+ End = ptr + Len;
+
+ while (ptr < End)
+ {
+ while (*ptr < 33)
+ {ptr++;}
+
+ *ptr2++ = *ptr++;
+ }
+
+ *ptr2 = 0;
+
+ ptr = Save;
+ Len = (int)(ptr2 - ptr - 1);
+
+ ptr2 = *Body;
+
+ while (Len > 0)
+ {
+ decodeblock(ptr, ptr2);
+ ptr += 4;
+ ptr2 += 3;
+ Len -= 4;
+ }
+
+ NewLen = (int)(ptr2 - *Body);
+
+ if (*(ptr-1) == '=')
+ NewLen--;
+
+ if (*(ptr-2) == '=')
+ NewLen--;
+
+ *MsgLen = NewLen;
+ }
+ else if (QuotedP)
+ {
+ int i = 0, Len = (int)strlen(ptr);
+ char * ptr2;
+ char * End;
+ char * Save = ptr;
+
+ ptr2 = *Body;
+
+ End = ptr + Len;
+
+ while (ptr < End)
+ {
+ if ((*ptr) == '=')
+ {
+ char c = *(++ptr);
+ char d;
+
+ c = c - 48;
+ if (c < 0)
+ {
+ // = CRLF as a soft break
+
+ ptr += 2;
+ continue;
+ }
+
+ if (c > 9)
+ c -= 7;
+ d = *(++ptr);
+ d = d - 48;
+ if (d > 9)
+ d -= 7;
+
+ *(ptr2) = c << 4 | d;
+ ptr2++;
+ ptr++;
+ }
+ else
+ {
+ *ptr2++ = *ptr++;
+ }
+ }
+ *ptr2 = 0;
+
+ *MsgLen = (int)(ptr2 - *Body);
+ }
+ else
+ {
+ strcpy(*Body, ptr);
+ *MsgLen = (int)strlen(ptr);
+ }
+ free(Save);
+
+ return FALSE;
+ }
+
+ // Assume Multipart/Mixed - Message with attachments
+
+ ptr = FindPart(Body, Boundary, &Partlen);
+
+ if (ptr == NULL)
+ return FALSE; // Couldn't find separator
+
+ while (ptr)
+ {
+ BOOL Base64 = FALSE;
+ BOOL QuotedP = FALSE;
+
+ MallocSave[Files] = ptr; // For free();
+
+ // Should be the First (Least desireable part, but the bit we want, as we are only interested in plain text)
+
+ // Process headers - looking for Content-Disposition: attachment;
+
+ // The first could also be a Content-Type: multipart/alternative; - if so, feed back to mime handler
+
+ while(*ptr != 13)
+ {
+ char lcLine[1000] = "";
+
+ ptr2 = strchr(ptr, 10); // Find CR
+
+ if (ptr2 == 0)
+ return FALSE;
+
+ while(ptr2[1] == ' ' || ptr2[1] == 9) // Whitespace - continuation line
+ {
+ ptr2 = strchr(&ptr2[1], 10); // Find CR
+ }
+
+ memcpy(lcLine, ptr, ptr2-ptr-1);
+ _strlwr(lcLine);
+
+ ptr = lcLine;
+
+ if (_memicmp(ptr, "Content-Type: Multipart/alternative", 30) == 0)
+ {
+ // Feed Back
+ int MsgLen;
+ char * Text = malloc(Partlen+1);
+
+ memcpy(Text, MallocSave[Files], Partlen);
+
+ free(MallocSave[Files]);
+ MallocSave[Files] = Text;
+
+
+ CheckforMIME(sockptr, Text, &Text, &MsgLen);
+
+ FileName[Files][0] = 0;
+ FileBody[Files] = Text;
+
+
+ FileLen[Files++] = MsgLen;
+
+ goto NextPart;
+
+ }
+ else if (_memicmp(ptr, "Content-Disposition: ", 21) == 0)
+ {
+ ptr3 = strstr(&ptr[21], "filename");
+
+ if (ptr3)
+ {
+ ptr3 += 9;
+ if (*ptr3 == '"') ptr3++;
+ ptr4 = strchr(ptr3, '"');
+ if (ptr4) *ptr4 = 0;
+
+ strcpy(FileName[Files], ptr3);
+ }
+ }
+
+ else if (_memicmp(ptr, "Content-Transfer-Encoding:", 26) == 0)
+ {
+ if (strstr(&ptr[26], "base64"))
+ Base64 = TRUE;
+ else
+ if (strstr(&ptr[26], "quoted-printable"))
+ QuotedP = TRUE;
+ }
+
+ ptr = ++ptr2;
+ }
+
+ ptr += 2;
+
+ // Should now have file or plain text. If file is Base64 encoded, decode it.
+
+ FileBody[Files] = ptr;
+ FileLen[Files] = (int)(Partlen - 2 - (ptr - MallocSave[Files]));
+
+ if (Base64)
+ {
+ int i = 0, Len = FileLen[Files], NewLen;
+ char * ptr2 = ptr;
+ char * End;
+
+ End = ptr + FileLen[Files];
+
+ while (ptr < End)
+ {
+ while (*ptr < 33)
+ {ptr++;}
+
+ *ptr2++ = *ptr++;
+ }
+ *ptr2 = 0;
+
+ ptr = FileBody[Files];
+ Len = (int)(ptr2 - ptr - 1);
+
+ ptr2 = ptr;
+
+ while (Len > 0)
+ {
+ decodeblock(ptr, ptr2);
+ ptr += 4;
+ ptr2 += 3;
+ Len -= 4;
+ }
+
+ NewLen = (int)(ptr2 - FileBody[Files]);
+
+ if (*(ptr-1) == '=')
+ NewLen--;
+
+ if (*(ptr-2) == '=')
+ NewLen--;
+
+ FileLen[Files] = NewLen;
+ }
+ else if (QuotedP)
+ {
+ int i = 0, Len = FileLen[Files], NewLen;
+ char * ptr2 = ptr;
+ char * End;
+
+ End = ptr + FileLen[Files];
+
+ while (ptr < End)
+ {
+ if ((*ptr) == '=')
+ {
+ char c = *(++ptr);
+ char d;
+
+ c = c - 48;
+ if (c < 0)
+ {
+ // = CRLF as a soft break
+
+ ptr += 2;
+ continue;
+ }
+
+ if (c > 9)
+ c -= 7;
+ d = *(++ptr);
+ d = d - 48;
+ if (d > 9)
+ d -= 7;
+
+ *(ptr2) = c << 4 | d;
+ ptr2++;
+ ptr++;
+ }
+ else
+ {
+ *ptr2++ = *ptr++;
+ }
+ }
+ *ptr2 = 0;
+
+ NewLen = (int)(ptr2 - FileBody[Files]);
+
+ FileLen[Files] = NewLen;
+ }
+
+ Files++;
+
+ NextPart:
+ ptr = FindPart(Body, Boundary, &Partlen);
+ }
+
+ // Now have all the parts - build a B2 Message. Leave the first part of header for later,
+ // as we may have multiple recipients. Start with the Body: Line.
+
+ // We need to add the first part of header later, so start message part way down buffer.
+ // Make sure buffer is big enough.
+
+ if ((sockptr->MailSize + 2000) > sockptr->MailBufferSize)
+ {
+ sockptr->MailBufferSize += 2000;
+ sockptr->MailBuffer = realloc(sockptr->MailBuffer, sockptr->MailBufferSize);
+
+ if (sockptr->MailBuffer == NULL)
+ {
+ CriticalErrorHandler("Failed to extend Message Buffer");
+ shutdown(sockptr->socket, 0);
+ return FALSE;
+ }
+ }
+
+
+ NewMsg = sockptr->MailBuffer + 1000;
+
+ NewMsg += sprintf(NewMsg, "Body: %d\r\n", FileLen[0]);
+
+ for (i = 1; i < Files; i++)
+ {
+ NewMsg += sprintf(NewMsg, "File: %d %s\r\n", FileLen[i], FileName[i]);
+ }
+
+ NewMsg += sprintf(NewMsg, "\r\n");
+
+ for (i = 0; i < Files; i++)
+ {
+ memcpy(NewMsg, FileBody[i], FileLen[i]);
+ NewMsg += FileLen[i];
+ free(MallocSave[i]);
+ NewMsg += sprintf(NewMsg, "\r\n");
+ }
+
+ *MsgLen = (int)(NewMsg - (sockptr->MailBuffer + 1000));
+ *Body = sockptr->MailBuffer + 1000;
+
+ return TRUE; // B2 Message
+}
+
+
+VOID ProcessSMTPServerMessage(SocketConn * sockptr, char * Buffer, int Len)
+{
+ SOCKET sock;
+ int i;
+ time_t Date = 0;
+
+ sock=sockptr->socket;
+
+ WriteLogLine(NULL, '<',Buffer, Len-2, LOG_TCP);
+
+ if (sockptr->Flags == GETTINGMESSAGE)
+ {
+ if(memcmp(Buffer, ".\r\n", 3) == 0)
+ {
+ char * ptr1, * ptr2;
+ int linelen, MsgLen;
+ char Msgtitle[62];
+ BOOL B2Flag;
+ int ToLen = 0;
+ char * ToString;
+ char * Via;
+
+ // Scan headers for a Subject: or Date: Line (Headers end at blank line)
+
+ ptr1 = sockptr->MailBuffer;
+ Loop:
+ ptr2 = strchr(ptr1, '\r');
+
+ if (ptr2 == NULL)
+ {
+ SendSock(sockptr, "500 Eh");
+ return;
+ }
+
+ linelen = (int)(ptr2 - ptr1);
+
+ if (_memicmp(ptr1, "Subject:", 8) == 0)
+ {
+ if (linelen > 68) linelen = 68;
+ memcpy(Msgtitle, &ptr1[9], linelen-9);
+ Msgtitle[linelen-9]=0;
+ }
+
+ if (_memicmp(ptr1, "Date:", 5) == 0)
+ {
+ struct tm rtime;
+ char * Context;
+ char seps[] = " ,\t\r";
+ char Offset[10] = "";
+ int i, HH, MM;
+ char Copy[500]="";
+
+ // Copy message, so original isn't messed up by strtok
+
+ memcpy(Copy, ptr1, linelen);
+
+ ptr1 = Copy;
+
+ memset(&rtime, 0, sizeof(struct tm));
+
+ // Date: Tue, 9 Jun 2009 20:54:55 +0100
+
+ ptr1 = strtok_s(&ptr1[5], seps, &Context); // Skip Day
+ ptr1 = strtok_s(NULL, seps, &Context); // Day
+
+ rtime.tm_mday = atoi(ptr1);
+
+ ptr1 = strtok_s(NULL, seps, &Context); // Month
+
+ for (i=0; i < 12; i++)
+ {
+ if (strcmp(month[i], ptr1) == 0)
+ {
+ rtime.tm_mon = i;
+ break;
+ }
+ }
+
+ sscanf(Context, "%04d %02d:%02d:%02d%s",
+ &rtime.tm_year, &rtime.tm_hour, &rtime.tm_min, &rtime.tm_sec, Offset);
+
+ rtime.tm_year -= 1900;
+
+ Date = mktime(&rtime) - (time_t)_MYTIMEZONE;
+
+ if (Date == (time_t)-1)
+ Date = 0;
+ else
+ {
+ if ((Offset[0] == '+') || (Offset[0] == '-'))
+ {
+ MM = atoi(&Offset[3]);
+ Offset[3] = 0;
+ HH = atoi(&Offset[1]);
+ MM = MM + (60 * HH);
+
+ if (Offset[0] == '+')
+ Date -= (60*MM);
+ else
+ Date += (60*MM);
+
+ }
+ }
+ }
+
+ ptr1 = ptr2 + 2; // Skip crlf
+
+ if (linelen) // Not Null line
+ {
+ goto Loop;
+ }
+
+ ptr2 = ptr1;
+ ptr1 = sockptr->MailBuffer;
+
+ MsgLen = (int)(sockptr->MailSize - (ptr2 - ptr1));
+
+ // We Just want the from call, not the full address.
+
+ TidyString(sockptr->MailFrom);
+
+ // Examine Message to look for html formatting and attachments.
+
+ B2Flag = CheckforMIME(sockptr, sockptr->MailBuffer, &ptr2, &MsgLen); // Will reformat message if necessary.
+
+ // If any recipients are via RMS, create one message for them, and separate messages for all others
+
+ ToString = zalloc(sockptr->Recipients * 100);
+
+ for (i=0; i < sockptr->Recipients; i++)
+ {
+ char Addr[256]; // Need copy, as we may change it then decide it isn't for RMS
+
+ strcpy(Addr, sockptr->RecpTo[i]);
+ Debugprintf("To Addr %s", Addr);
+
+ TidyString(Addr);
+ Debugprintf("To Addr after Tidy %s", Addr);
+
+ if ((_memicmp (Addr, "RMS:", 4) == 0) |(_memicmp (Addr, "RMS/", 4) == 0))
+ {
+ // Add to B2 Message for RMS
+
+ _strlwr(Addr);
+
+ Via = strlop(&Addr[4], '@');
+
+ if (Via && _stricmp(Via, "winlink.org") == 0)
+ {
+ if (CheckifLocalRMSUser(Addr)) // if local RMS - Leave Here
+ continue;
+
+ ToLen = sprintf(ToString, "%sTo: %s\r\n", ToString, &Addr[4]);
+ *sockptr->RecpTo[i] = 0; // So we dont create individual one later
+ continue;
+ }
+
+ ToLen = sprintf(ToString, "%sTo: %s@%s\r\n", ToString, &Addr[4], Via);
+ *sockptr->RecpTo[i] = 0; // So we dont create individual one later
+ continue;
+ }
+
+ _strupr(Addr);
+ Debugprintf("To Addr after strupr %s", Addr);
+
+ Via = strlop(Addr, '@');
+ Debugprintf("Via %s", Via);
+
+ if (Via && _stricmp(Via, "winlink.org") == 0)
+ {
+ if (CheckifLocalRMSUser(Addr)) // if local RMS - Leave Here
+ continue;
+
+ ToLen = sprintf(ToString, "%sTo: %s\r\n", ToString, Addr);
+ *sockptr->RecpTo[i] = 0; // So we dont create individual one later
+
+ continue;
+ }
+ }
+
+ if (ToLen) // Have some RMS Addresses
+ {
+ char B2Hddr[1000];
+ int B2HddrLen;
+ char DateString[80];
+ char * NewBody;
+ struct tm * tm;
+ struct MsgInfo * Msg;
+ BIDRec * BIDRec;
+
+ Msg = AllocateMsgRecord();
+
+ // Set number here so they remain in sequence
+
+ Msg->number = ++LatestMsg;
+ MsgnotoMsg[Msg->number] = Msg;
+ Msg->length = MsgLen;
+
+ sprintf_s(Msg->bid, sizeof(Msg->bid), "%d_%s", LatestMsg, BBSName);
+
+ Msg->type = 'P';
+ Msg->status = 'N';
+ strcpy(Msg->to, "RMS");
+ strlop(sockptr->MailFrom, '@');
+ if (strlen(sockptr->MailFrom) > 6) sockptr->MailFrom[6]=0;
+ strcpy(Msg->from, sockptr->MailFrom);
+ strcpy(Msg->title, Msgtitle);
+
+ BIDRec = AllocateBIDRecord();
+
+ strcpy(BIDRec->BID, Msg->bid);
+ BIDRec->mode = Msg->type;
+ BIDRec->u.msgno = LOWORD(Msg->number);
+ BIDRec->u.timestamp = LOWORD(time(NULL)/86400);
+
+ Msg->datereceived = Msg->datechanged = Msg->datecreated = time(NULL);
+
+ if (Date)
+ Msg->datecreated = Date;
+
+ tm = gmtime(&Date);
+
+ sprintf(DateString, "%04d/%02d/%02d %02d:%02d",
+ tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min);
+
+ if (B2Flag) // Message has attachments, so Body: line is present
+ {
+ Msg->B2Flags = B2Msg | Attachments;
+
+ B2HddrLen = sprintf(B2Hddr,
+ "MID: %s\r\nDate: %s\r\nType: %s\r\nFrom: %s\r\n%sSubject: %s\r\nMbo: %s\r\n",
+ Msg->bid, DateString, "Private", Msg->from, ToString, Msg->title, BBSName);
+ }
+ else
+ {
+ Msg->B2Flags = B2Msg;
+ B2HddrLen = sprintf(B2Hddr,
+ "MID: %s\r\nDate: %s\r\nType: %s\r\nFrom: %s\r\n%sSubject: %s\r\nMbo: %s\r\nBody: %d\r\n\r\n",
+ Msg->bid, DateString, "Private", Msg->from, ToString, Msg->title, BBSName, Msg->length);
+
+ }
+
+ NewBody = ptr2 - B2HddrLen;
+
+ memcpy(NewBody, B2Hddr, B2HddrLen);
+
+ Msg->length += B2HddrLen;
+
+ free(ToString);
+
+ // Set up forwarding bitmap
+
+ MatchMessagetoBBSList(Msg, 0);
+
+ CreateSMTPMessageFile(NewBody, Msg);
+ }
+
+ for (i=0; i < sockptr->Recipients; i++)
+ {
+ if (*sockptr->RecpTo[i]) // not already sent to RMS?
+ CreateSMTPMessage(sockptr, i, Msgtitle, Date, ptr2, MsgLen, B2Flag);
+ else
+ free(sockptr->RecpTo[i]);
+ }
+
+ free(sockptr->RecpTo);
+ sockptr->RecpTo = NULL;
+ free(sockptr->MailFrom);
+ free(sockptr->MailBuffer);
+
+ sockptr->MailBufferSize=0;
+ sockptr->MailBuffer=0;
+ sockptr->MailSize = 0;
+
+ sockptr->Flags = 0;
+ sockptr->Recipients = 0;
+
+ SendSock(sockptr, "250 Ok");
+ return;
+ }
+
+ if ((sockptr->MailSize + Len) > sockptr->MailBufferSize)
+ {
+ sockptr->MailBufferSize += 10000;
+ sockptr->MailBuffer = realloc(sockptr->MailBuffer, sockptr->MailBufferSize);
+
+ if (sockptr->MailBuffer == NULL)
+ {
+ CriticalErrorHandler("Failed to extend Message Buffer");
+ shutdown(sock, 0);
+ return;
+ }
+ }
+
+ memcpy(&sockptr->MailBuffer[sockptr->MailSize], Buffer, Len);
+ sockptr->MailSize += Len;
+
+ return;
+ }
+
+ if (sockptr->State == GettingUser)
+ {
+ char Out[30];
+
+ Buffer[Len-2]=0;
+
+ decodeblock(Buffer, Out);
+ decodeblock(&Buffer[4], &Out[3]);
+ decodeblock(&Buffer[8], &Out[6]);
+ decodeblock(&Buffer[12], &Out[9]);
+
+ if (strlen(Out) > 10) Out[10] = 0;
+
+ strcpy(sockptr->CallSign, Out);
+
+ sockptr->State = GettingPass;
+ SendSock(sockptr, "334 UGFzc3dvcmQ6");
+ return;
+ }
+
+ if (sockptr->State == GettingPass)
+ {
+ struct UserInfo * user = NULL;
+ char Out[30];
+
+ Buffer[Len-2]=0;
+
+ decodeblock(Buffer, Out);
+ decodeblock(&Buffer[4], &Out[3]);
+ decodeblock(&Buffer[8], &Out[6]);
+ decodeblock(&Buffer[12], &Out[9]);
+ decodeblock(&Buffer[16], &Out[12]);
+ decodeblock(&Buffer[20], &Out[15]);
+
+ user = LookupCall(sockptr->CallSign);
+
+ if (user)
+ {
+ if (strcmp(user->pass, Out) == 0)
+ {
+ sockptr->State = Authenticated;
+ SendSock(sockptr, "235 2.0.0 OK Authenticated"); //535 authorization failed
+ return;
+ }
+ }
+
+ SendSock(sockptr, "535 authorization failed");
+ sockptr->State = 0;
+ return;
+ }
+
+
+
+/*AUTH LOGIN
+
+334 VXNlcm5hbWU6
+a4msl9ux
+334 UGFzc3dvcmQ6
+ZvVx9G1hcg==
+235 2.0.0 OK Authenticated
+*/
+
+
+ if(memcmp(Buffer, "AUTH LOGIN", 10) == 0)
+ {
+ sockptr->State = GettingUser;
+ SendSock(sockptr, "334 VXNlcm5hbWU6");
+ return;
+ }
+
+ if(memcmp(Buffer, "EHLO",4) == 0)
+ {
+ SendSock(sockptr, "250-BPQ Mail Server");
+ SendSock(sockptr, "250 AUTH LOGIN");
+
+ //250-8BITMIME
+
+ return;
+ }
+
+ if(memcmp(Buffer, "AUTH LOGIN", 10) == 0)
+ {
+ sockptr->State = GettingUser;
+ SendSock(sockptr, "334 VXNlcm5hbWU6");
+ return;
+ }
+
+
+ if(memcmp(Buffer, "HELO",4) == 0)
+ {
+ SendSock(sockptr, "250 Ok");
+ return;
+ }
+
+ if(_memicmp(Buffer, "MAIL FROM:", 10) == 0)
+ {
+ if (sockptr->State != Authenticated)
+ {
+ // Accept if from 44/8 and ends in ampr.org
+
+ if (_memicmp(&Buffer[Len - 11], "ampr.org", 8) == 0 &&
+ (sockptr->sin.sin_addr.s_addr & 0xff) == 44)
+ {
+ }
+ else
+ {
+ SendSock(sockptr, "530 Authentication required");
+ return;
+ }
+ }
+
+ sockptr->MailFrom = zalloc(Len);
+ memcpy(sockptr->MailFrom, &Buffer[10], Len-12);
+
+ SendSock(sockptr, "250 Ok");
+
+ return;
+ }
+
+ if(_memicmp(Buffer, "RCPT TO:", 8) == 0)
+ {
+ if (sockptr->State != Authenticated)
+ {
+ // Accept if from 44/8 and ends in ampr.org
+
+
+
+ if (_memicmp(&Buffer[Len - 11], "ampr.org", 8) == 0 &&
+ (sockptr->sin.sin_addr.s_addr & 0xff) == 44)
+ {
+ }
+ else
+ {
+ SendSock(sockptr, "530 Authentication required");
+ return;
+ }
+ }
+
+ sockptr->RecpTo=realloc(sockptr->RecpTo, (sockptr->Recipients+1) * sizeof(void *));
+ sockptr->RecpTo[sockptr->Recipients] = zalloc(Len);
+
+ memcpy(sockptr->RecpTo[sockptr->Recipients++], &Buffer[8], Len-10);
+
+ SendSock(sockptr, "250 Ok");
+ return;
+ }
+
+ if(memcmp(Buffer, "DATA\r\n", 6) == 0)
+ {
+ sockptr->MailBuffer=malloc(10000);
+ sockptr->MailBufferSize=10000;
+
+ if (sockptr->MailBuffer == NULL)
+ {
+ CriticalErrorHandler("Failed to create SMTP Message Buffer");
+ SendSock(sockptr, "250 Failed");
+ shutdown(sock, 0);
+
+ return;
+ }
+
+ sockptr->Flags |= GETTINGMESSAGE;
+
+ SendSock(sockptr, "354 End data with .");
+ return;
+ }
+
+ if(memcmp(Buffer, "QUIT\r\n", 6) == 0)
+ {
+ SendSock(sockptr, "221 OK");
+ Sleep(500);
+ shutdown(sock, 0);
+ return;
+ }
+
+ if(memcmp(Buffer, "RSET\r\n", 6) == 0)
+ {
+ SendSock(sockptr, "250 Ok");
+
+ // This cancelled AUTH which I think is wrong
+ //sockptr->State = 0;
+
+ if (sockptr->State != Authenticated)
+ sockptr->State = 0;
+
+ sockptr->Recipients = 0;
+
+ return;
+ }
+
+ return;
+}
+
+
+int CreateSMTPMessage(SocketConn * sockptr, int i, char * MsgTitle, time_t Date, char * MsgBody, int MsgLen, BOOL B2Flag)
+{
+ struct MsgInfo * Msg;
+ BIDRec * BIDRec;
+ char * To;
+ char * via;
+
+ // Allocate a message Record slot
+
+ Msg = AllocateMsgRecord();
+
+ // Set number here so they remain in sequence
+
+ Msg->number = ++LatestMsg;
+ MsgnotoMsg[Msg->number] = Msg;
+ Msg->length = MsgLen;
+
+ sprintf_s(Msg->bid, sizeof(Msg->bid), "%d_%s", LatestMsg, BBSName);
+
+ Msg->type = 'P';
+ Msg->status = 'N';
+
+ BIDRec = AllocateBIDRecord();
+
+ strcpy(BIDRec->BID, Msg->bid);
+ BIDRec->mode = Msg->type;
+ BIDRec->u.msgno = LOWORD(Msg->number);
+ BIDRec->u.timestamp = LOWORD(time(NULL)/86400);
+
+ Msg->datereceived = Msg->datechanged = Msg->datecreated = time(NULL);
+
+ if (Date)
+ Msg->datecreated = Date;
+
+ To = sockptr->RecpTo[i];
+
+ Debugprintf("To %s", To);
+
+ TidyString(To);
+
+ Debugprintf("To after tidy %s", To);
+
+ if (_memicmp(To, "bull/", 5) == 0)
+ {
+ Msg->type = 'B';
+ memmove(To, &To[5], strlen(&To[4]));
+ }
+
+ if ((_memicmp(To, "nts/", 4) == 0) ||(_memicmp(To, "nts:", 4) == 0) ||
+ (_memicmp(To, "nts.", 4) == 0))
+ {
+ Msg->type = 'T';
+ memmove(To, &To[4], strlen(&To[3]));
+ }
+
+ if (_memicmp(To, "rms:", 4) == 0)
+ {
+ via = _strlwr(strlop(To, ':'));
+ }
+ else if (_memicmp(To, "rms/", 4) == 0)
+ {
+ via = _strlwr(strlop(To, '/'));
+ }
+ else if (_memicmp(To, "rms.", 4) == 0)
+ {
+ via = _strlwr(strlop(To, '.'));
+ }
+ else if (_memicmp(To, "smtp:", 5) == 0)
+ {
+ via = _strlwr(strlop(To, ':'));
+ To[0] = 0;
+ }
+ else if (_memicmp(To, "smtp/", 5) == 0)
+ {
+ via = _strlwr(strlop(To, '/'));
+ To[0] = 0;
+ }
+ else
+ {
+ via = strlop(To, '@');
+ }
+
+ Debugprintf("via %s", via);
+
+ if (via)
+ {
+ int toLen;
+
+ if (strlen(via) > 40) via[40] = 0;
+
+ strcpy(Msg->via, via); // Save before messing with it
+
+ // if ending in AMPR.ORG send via ISP if we have enabled forwarding AMPR
+
+ toLen = (int)strlen(via);
+
+ if (_memicmp(&via[toLen - 8], "ampr.org", 8) == 0)
+ {
+ // if our domain keep here.
+
+ // if not, and SendAMPRDirect set, set as ISP,
+ // else set as RMS
+
+ if (_stricmp(via, AMPRDomain) == 0)
+ {
+ // Our Message- dont forward
+ }
+ else
+ {
+ // AMPR but not us
+
+ if (SendAMPRDirect)
+ {
+ sprintf(Msg->via,"%s@%s", To, via);
+ strcpy(To, "AMPR");
+ }
+ else
+ {
+ sprintf(Msg->via,"%s@%s", To, via);
+ strcpy(To, "RMS");
+ }
+ }
+ }
+ else
+ {
+ strlop(via, '.'); // Get first part of address
+
+ if (_stricmp(via, BBSName) == 0)
+ {
+ // sent via us - clear the name
+
+ Msg->via[0] = 0;
+ }
+ }
+ }
+
+ if (strlen(To) > 6) To[6]=0;
+
+ strcpy(Msg->to, To);
+
+ if (strchr(sockptr->MailFrom, '@'))
+ {
+ char * FromHA = strlop(sockptr->MailFrom, '@');
+ Msg->emailfrom[0] = '@';
+ strcpy(&Msg->emailfrom[1], FromHA);
+ }
+
+ if (strlen(sockptr->MailFrom) > 6) sockptr->MailFrom[6]=0;
+
+ strcpy(Msg->from, sockptr->MailFrom);
+
+ strcpy(Msg->title, MsgTitle);
+
+ if(Msg->to[0] == 0)
+ SMTPMsgCreated=TRUE;
+
+ // If NTS message (TO is numeric and AT is NTSxx or NTSxx.NTS - Outlook won't accept x@y)
+
+ if (isdigits(Msg->to) && memcmp(Msg->via, "NTS", 3) == 0)
+ {
+ if (Msg->via[5] == 0 || strcmp(&Msg->via[5], ".NTS") == 0)
+ {
+ Msg->type = 'T';
+ Msg->via[5] = 0;
+ }
+ }
+
+ Debugprintf("Msg->Via %s", Msg->via);
+
+ if (B2Flag)
+ {
+ char B2Hddr[1000];
+ int B2HddrLen;
+ char B2To[80];
+ char * NewBody;
+ char DateString[80];
+ char * TypeString;
+ struct tm * tm;
+
+ tm = gmtime(&Date);
+
+ sprintf(DateString, "%04d/%02d/%02d %02d:%02d",
+ tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min);
+
+
+ if (strcmp(Msg->to, "RMS") == 0) // Address is in via
+ strcpy(B2To, Msg->via);
+ else
+ if (Msg->via[0])
+ sprintf(B2To, "%s@%s", Msg->to, Msg->via);
+ else
+ strcpy(B2To, Msg->to);
+
+
+ Msg->B2Flags = B2Msg | Attachments;
+
+ if (Msg->type == 'P')
+ TypeString = "Private" ;
+ else if (Msg->type == 'B')
+ TypeString = "Bulletin";
+ else if (Msg->type == 'T')
+ TypeString = "Traffic";
+
+ B2HddrLen = sprintf(B2Hddr,
+ "MID: %s\r\nDate: %s\r\nType: %s\r\nFrom: %s\r\nTo: %s\r\nSubject: %s\r\nMbo: %s\r\n",
+ Msg->bid, DateString, TypeString,
+ Msg->from, B2To, Msg->title, BBSName);
+
+ NewBody = MsgBody - B2HddrLen;
+
+ memcpy(NewBody, B2Hddr, B2HddrLen);
+
+ Msg->length += B2HddrLen;
+
+ free(To);
+
+ // Set up forwarding bitmap
+
+ MatchMessagetoBBSList(Msg, 0);
+
+ if (Msg->type == 'B' && memcmp(Msg->fbbs, zeros, NBMASK) != 0)
+ Msg->status = '$'; // Has forwarding
+
+ return CreateSMTPMessageFile(NewBody, Msg);
+
+ }
+
+ free(To);
+
+ // Set up forwarding bitmap
+
+ MatchMessagetoBBSList(Msg, 0);
+
+ if (Msg->type == 'B' && memcmp( Msg->fbbs, zeros, NBMASK) != 0)
+ Msg->status = '$'; // Has forwarding
+
+ return CreateSMTPMessageFile(MsgBody, Msg);
+
+}
+
+
+BOOL CreateSMTPMessageFile(char * Message, struct MsgInfo * Msg)
+{
+ char MsgFile[250];
+ FILE * hFile;
+ int WriteLen=0;
+ char Mess[255];
+ int len;
+
+ struct UserInfo * ToUser = LookupCall(Msg->to);
+
+ if (ToUser && ToUser->flags & F_HOLDMAIL)
+ {
+ int Length=0;
+ char * MailBuffer = malloc(100);
+ char Title[100];
+
+ Msg->status = 'H';
+
+ Length += sprintf(MailBuffer, "Message %d Held\r\n", Msg->number);
+ sprintf(Title, "Message %d Held - %s", Msg->number, "User has Hold Messages flag set");
+ SendMessageToSYSOP(Title, MailBuffer, Length);
+ }
+
+ sprintf_s(MsgFile, sizeof(MsgFile), "%s/m_%06d.mes", MailDir, Msg->number);
+
+ hFile = fopen(MsgFile, "wb");
+
+ if (hFile)
+ {
+ WriteLen = (int)fwrite(Message, 1, Msg->length, hFile);
+ fclose(hFile);
+ }
+
+ if (WriteLen != Msg->length)
+ {
+ len = sprintf_s(Mess, sizeof(Mess), "Failed to create Message File\r");
+ CriticalErrorHandler(Mess);
+
+ return FALSE;
+ }
+
+ SaveMessageDatabase();
+ SaveBIDDatabase();
+
+ return TRUE;
+}
+
+int TidyString(char * Address)
+{
+ // Cleans up a From: or To: Address
+
+ // May have leading or trailing spaces, or be enclosed by <>, or have a " " part
+
+ // From: "John Wiseman"
+
+ char * ptr1, * ptr2;
+ size_t len;
+
+ _strupr(Address);
+
+ ptr1 = strchr(Address, '<');
+
+ if (ptr1)
+ {
+ ptr1++;
+ ptr2 = strlop(ptr1, '>');
+ len = (int)strlen(ptr1);
+ memmove(Address, ptr1, len);
+ Address[len] = 0;
+
+ // Could have surrounding "" ""
+
+ if (Address[0] == '"')
+ {
+ int len = (int)strlen(Address) - 1;
+
+ if (Address[len] == '"')
+ {
+ Address[len] = 0;
+ memmove(Address, &Address[1], len);
+ return 0;
+ }
+
+ // Thunderbird can put "" round part of address "rms:john.wiseman"@cantab.net
+
+ ptr2 = strchr(&Address[1], '"');
+
+ if (ptr2)
+ {
+ memmove(Address, &Address[1], ptr2 - &Address[1]);
+ memmove(ptr2 - 1, ptr2 + 1, strlen(ptr2 + 1) + 1);
+
+ }
+
+
+ }
+
+ return 0;
+ }
+
+ ptr1 = Address;
+
+ while (*ptr1 == ' ') ptr1++;
+
+ if (*ptr1 == '"')
+ {
+ ptr1++;
+ ptr1=strlop(ptr1, '"');
+ ptr2=strlop(ptr1, ' ');
+ ptr1=ptr2;
+ }
+
+ if (*ptr1 == '<') ptr1++;
+
+ ptr2 = strlop(ptr1, '>');
+ strlop(ptr1, ' ');
+
+ len = strlen(ptr1);
+ memmove(Address, ptr1, len);
+ Address[len] = 0;
+
+ return 0;
+}
+/*
++OK POP3 server ready
+USER john.wiseman
++OK please send PASS command
+PASS gb7bpq
++OK john.wiseman is welcome here
+STAT
++OK 6 115834
+
+UIDL
++OK 6 messages
+1 <4A0DC6E0.5020504@hb9bza.net>
+2
+3 <1085101c9d5d0$09b15420$16f9280a@phx.gbl>
+4
+5
+6 <20090516011401.53DB013804@panix1.panix.com>
+.
+LIST
++OK 6 messages
+1 7167
+2 10160
+3 52898
+4 4746
+5 20218
+6 20645
+.
+
+*/
+
+VOID ProcessPOP3ServerMessage(SocketConn * sockptr, char * Buffer, int Len)
+{
+ SOCKET sock;
+ int i;
+ struct MsgInfo * Msg;
+
+ sock=sockptr->socket;
+
+ WriteLogLine(NULL, '<',Buffer, Len-2, LOG_TCP);
+
+ if(memcmp(Buffer, "CAPA",4) == 0)
+ {
+ SendSock(sockptr, "+OK Capability list follows");
+ SendSock(sockptr, "UIDL");
+ SendSock(sockptr, "TOP");
+ SendSock(sockptr, "EXPIRE 30");
+ SendSock(sockptr, ".");
+ return;
+ }
+
+ if(memcmp(Buffer, "AUTH",4) == 0)
+ {
+ SendSock(sockptr, "-ERR");
+ return;
+ }
+ if (sockptr->State == GettingUser)
+ {
+
+ Buffer[Len-2]=0;
+ if (Len > 15) Buffer[15]=0;
+
+ strcpy(sockptr->CallSign, &Buffer[5]);
+
+ sockptr->State = GettingPass;
+ SendSock(sockptr, "+OK please send PASS command");
+ return;
+ }
+
+ if (sockptr->State == GettingPass)
+ {
+ struct UserInfo * user = NULL;
+
+ Buffer[Len-2]=0;
+ user = LookupCall(sockptr->CallSign);
+
+ if (user)
+ {
+ if (strcmp(user->pass, &Buffer[5]) == 0)
+ {
+ if (user->POP3Locked)
+ {
+ SendSock(sockptr, "-ERR Mailbox Locked");
+ sockptr->State = 0;
+ return;
+ }
+
+ sockptr->State = Authenticated;
+ SendSock(sockptr, "+OK Authenticated");
+
+ sockptr->POP3User = user;
+ user->POP3Locked = TRUE;
+
+ // Get Message List
+
+ for (i=0; i<=NumberofMessages; i++)
+ {
+ Msg = MsgHddrPtr[i];
+
+ if ((_stricmp(Msg->to, sockptr->CallSign) == 0) ||
+ ((_stricmp(Msg->to, "SYSOP") == 0) && (user->flags & F_SYSOP) && (Msg->type == 'P')))
+ {
+ if (Msg->status != 'K' && Msg->status != 'H')
+ {
+ sockptr->POP3Msgs = realloc(sockptr->POP3Msgs, (sockptr->POP3MsgCount+1) * sizeof(void *));
+ sockptr->POP3Msgs[sockptr->POP3MsgCount++] = MsgHddrPtr[i];
+ }
+ }
+ }
+
+ return;
+ }
+ }
+
+ SendSock(sockptr, "-ERR Authentication failed");
+ sockptr->State = 0;
+ return;
+ }
+
+ if (memcmp(Buffer, "QUIT",4) == 0)
+ {
+ SendSock(sockptr, "+OK Finished");
+
+ if (sockptr->POP3User)
+ sockptr->POP3User->POP3Locked = FALSE;
+
+ return;
+ }
+
+ if (memcmp(Buffer, "NOOP",4) == 0)
+ {
+ SendSock(sockptr, "+OK ");
+ return;
+ }
+
+// if (memcmp(Buffer, "LAST",4) == 0)
+// {
+// SendSock(sockptr, "+OK 0");
+// return;
+// }
+
+ if (sockptr->State != Authenticated)
+ {
+ SendSock(sockptr, "-ERR Need Authentication");
+ sockptr->State = 0;
+ return;
+ }
+
+ if (memcmp(Buffer, "STAT",4) == 0)
+ {
+ char reply[40];
+ int i, size=0;
+
+ for (i=0; i< sockptr->POP3MsgCount; i++)
+ {
+ size+=sockptr->POP3Msgs[i]->length;
+ }
+
+ sprintf_s(reply, sizeof(reply), "+OK %d %d", sockptr->POP3MsgCount, size);
+
+ SendSock(sockptr, reply);
+ return;
+ }
+
+ if (memcmp(Buffer, "UIDL",4) == 0)
+ {
+ char reply[40];
+ int i, count=0, size=0;
+ int MsgNo=1;
+
+ SendSock(sockptr, "+OK ");
+
+ for (i=0; i< sockptr->POP3MsgCount; i++)
+ {
+ sprintf_s(reply, sizeof(reply), "%d %s", i+1, sockptr->POP3Msgs[i]->bid);
+ SendSock(sockptr, reply);
+ }
+
+ SendSock(sockptr, ".");
+ return;
+ }
+
+ if (memcmp(Buffer, "LIST", 4) == 0)
+ {
+ char reply[40];
+ int i, count=0, size=0;
+ int MsgNo = atoi(&Buffer[4]);
+
+ if (Buffer[4] == 13) // CR
+ MsgNo = 0;
+
+ Debugprintf("%s %d", Buffer, MsgNo);
+
+ if (MsgNo)
+ {
+ if (MsgNo > sockptr->POP3MsgCount)
+ sprintf(reply, "-ERR no such message, only %d messages in maildrop", sockptr->POP3MsgCount);
+ else
+ sprintf(reply, "+OK %d %d", MsgNo, sockptr->POP3Msgs[MsgNo - 1]->length);
+ SendSock(sockptr, reply);
+ return;
+ }
+
+
+ SendSock(sockptr, "+OK ");
+
+ for (i=0; i< sockptr->POP3MsgCount; i++)
+ {
+ sprintf_s(reply, sizeof(reply), "%d %d", i+1, sockptr->POP3Msgs[i]->length);
+ SendSock(sockptr, reply);
+ }
+
+ SendSock(sockptr, ".");
+ return;
+ }
+
+ if (memcmp(Buffer, "RETR", 4) == 0 || memcmp(Buffer, "TOP", 3) == 0)
+ {
+ char * ptr;
+ char Header[120];
+ int i, count=0, size=0;
+ int MsgNo=1;
+ char * msgbytes;
+ struct MsgInfo * Msg;
+ char B2From[80];
+ struct UserInfo * FromUser;
+ char TimeString[64];
+ BOOL TOP = FALSE;
+ int Len;
+
+ if (memcmp(Buffer, "TOP", 3) == 0)
+ TOP = TRUE;
+
+ ptr=strlop(Buffer, ' '); // Get Number
+
+ i=atoi(ptr);
+
+ if ((i > sockptr->POP3MsgCount) || (i == 0))
+ {
+ SendSock(sockptr, "-ERR no such message");
+ return;
+ }
+
+ Msg = sockptr->POP3Msgs[i-1];
+
+ msgbytes = ReadMessageFile(Msg->number);
+
+ if (msgbytes == NULL)
+ {
+ SendSock(sockptr, "-ERR no such message");
+ return;
+ }
+
+ SendSock(sockptr, "+OK ");
+
+ // Build an RFC822 ish header
+
+//Received: from [69.147.65.148] by n15.bullet.sp1.yahoo.com with NNFMP; 16 May 2009 02:30:47 -0000
+//Received: from [69.147.108.192] by t11.bullet.mail.sp1.yahoo.com with NNFMP; 16 May 2009 02:30:47 -0000
+
+ FormatTime(TimeString, (time_t)Msg->datecreated);
+
+ sprintf_s(Header, sizeof(Header), "Date: %s", TimeString);
+ SendSock(sockptr, Header);
+
+ sprintf_s(Header, sizeof(Header), "To: %s", Msg->to);
+ SendSock(sockptr, Header);
+
+ sprintf_s(Header, sizeof(Header), "Message-ID: %s", Msg->bid);
+ SendSock(sockptr, Header);
+
+ if (_stricmp(Msg->from, "smtp:") == 0)
+ {
+ sprintf_s(Header, sizeof(Header), "From: smtp/%s", Msg->emailfrom);
+ SendSock(sockptr, Header);
+ sprintf_s(Header, sizeof(Header), "Replyto: smtp/%s", Msg->emailfrom);
+ }
+ else
+ {
+ if (_stricmp(Msg->from, "rms:") == 0)
+ {
+ sprintf_s(Header, sizeof(Header), "From: RMS/%s", Msg->emailfrom);
+ SendSock(sockptr, Header);
+ sprintf_s(Header, sizeof(Header), "Replyto: RMS/%s", Msg->emailfrom);
+ }
+ else
+ {
+ // If there is an adddress in Msg->emailfrom use it
+
+ if (Msg->emailfrom[0])
+ {
+ strcpy(B2From, Msg->from);
+ strcat(B2From, Msg->emailfrom);
+ }
+ else
+ {
+ // Packet Address. Mail client will need more than just a call to respond to
+
+ strcpy(B2From, Msg->from);
+
+ if (strcmp(Msg->from, "SMTP:") == 0) // Address is in via
+ strcpy(B2From, Msg->emailfrom);
+ else
+ {
+ FromUser = LookupCall(Msg->from);
+
+ if (FromUser)
+ {
+ if (FromUser->HomeBBS[0])
+ sprintf(B2From, "%s@%s", Msg->from, FromUser->HomeBBS);
+ else
+ sprintf(B2From, "%s@%s", Msg->from, BBSName);
+ }
+ else
+ {
+ WPRecP WP = LookupWP(Msg->from);
+ if (WP)
+ sprintf(B2From, "%s@%s", Msg->from, WP->first_homebbs);
+ }
+ }
+ }
+ sprintf_s(Header, sizeof(Header), "From: %s", B2From);
+ SendSock(sockptr, Header);
+ sprintf_s(Header, sizeof(Header), "Replyto: %s", B2From);
+ }
+ }
+ SendSock(sockptr, Header);
+ sprintf_s(Header, sizeof(Header), "Subject: %s", Msg->title);
+ SendSock(sockptr, Header);
+
+ if ((Msg->B2Flags & Attachments) && TOP == FALSE)
+ {
+ // B2 Message with Attachments. Create a Mime-Encoded Multipart message
+
+ SendMultiPartMessage(sockptr, Msg, msgbytes);
+ return;
+ }
+
+ if (TOP)
+ {
+ // Get first i lines of message
+
+ char * ptr1, * ptr2;
+
+ ptr = strlop(ptr, ' '); // Get Number of lines
+ i = atoi(ptr);
+
+ ptr1 = msgbytes;
+ ptr2 = --ptr1; // Point both to char before message
+
+ while(i--)
+ {
+ ptr2 = strchr(++ptr1, 10);
+
+ if (ptr2 == 0) // No more lines
+ i = 0;
+
+ ptr1 = ptr2;
+ }
+ if (ptr2)
+ *(ptr2 + 1) = 0;
+ }
+
+ // If message has characters above 7F convert to UFT8 if necessary and send as Base64
+
+ Len = (int)strlen(msgbytes);
+
+ if (Is8Bit(msgbytes, Len))
+ {
+ // 8 Bit. Will send as UFT8
+
+ if (WebIsUTF8(msgbytes, Len) == FALSE)
+ {
+ // Must be some other coding
+
+ int code = TrytoGuessCode(msgbytes, Len);
+ UCHAR * UTF = malloc(Len * 3);
+
+ if (code == 437)
+ Len = Convert437toUTF8(msgbytes, Len, UTF);
+ else if (code == 1251)
+ Len = Convert1251toUTF8(msgbytes, Len, UTF);
+ else
+ Len = Convert1252toUTF8(msgbytes, Len, UTF);
+
+ free(msgbytes);
+ msgbytes = UTF;
+ }
+
+ SendSock(sockptr, "Content-Type: text/plain; charset=\"utf-8\"");
+ SendSock(sockptr, "Content-Transfer-Encoding: base64");
+ SendSock(sockptr, "Content-Disposition: inline");
+
+ SendSock(sockptr, ""); // Blank line before body
+
+ Base64EncodeAndSend(sockptr, msgbytes, Len);
+
+ }
+ else
+ {
+ // send as USASCII
+
+ SendSock(sockptr, ""); // Blank line before body
+ SendSock(sockptr, msgbytes);
+ }
+
+ SendSock(sockptr, "");
+ SendSock(sockptr, ".");
+
+ free(msgbytes);
+ return;
+ }
+
+
+ if (memcmp(Buffer, "DELE",4) == 0)
+ {
+ char * ptr;
+ int i;
+ struct MsgInfo * Msg;
+
+ ptr=strlop(Buffer, ' '); // Get Number
+
+ i=atoi(ptr);
+
+ if ((i > sockptr->POP3MsgCount) || (i == 0))
+ {
+ SendSock(sockptr, "-ERR no such message");
+ return;
+ }
+
+ Msg = sockptr->POP3Msgs[i-1];
+
+ FlagAsKilled(Msg, TRUE);
+
+ SendSock(sockptr, "+OK ");
+ return;
+ }
+
+
+ if (memcmp(Buffer, "QUIT",4) == 0)
+ {
+ SendSock(sockptr, "+OK Finished");
+
+ if (sockptr->POP3User)
+ sockptr->POP3User->POP3Locked = FALSE;
+
+ return;
+ }
+
+ SendSock(sockptr, "-ERR Unrecognised Command");
+
+}
+
+
+
+/* jer:
+ * This is the original file, my mods were only to change the name/semantics on the b64decode function
+ * and remove some dependencies.
+ */
+/*
+ LibCGI base64 manipulation functions is extremly based on the work of Bob Tower,
+ from its projec http://base64.sourceforge.net. The functions were a bit modicated.
+ Above is the MIT license from b64.c original code:
+
+LICENCE: Copyright (c) 2001 Bob Trower, Trantor Standard Systems Inc.
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated
+ documentation files (the "Software"), to deal in the
+ Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute,
+ sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so,
+ subject to the following conditions:
+
+ The above copyright notice and this permission notice shall
+ be included in all copies or substantial portions of the
+ Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+ KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
+ OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
+
+*/
+void encodeblock( unsigned char in[3], unsigned char out[4], int len )
+{
+ out[0] = cb64[ in[0] >> 2 ];
+ out[1] = cb64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4) ];
+ out[2] = (unsigned char) (len > 1 ? cb64[ ((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6) ] : '=');
+ out[3] = (unsigned char) (len > 2 ? cb64[ in[2] & 0x3f ] : '=');
+}
+
+void decodeblock( unsigned char in[4], unsigned char out[3])
+{
+ char Block[5];
+
+ Block[0]=mycd64[in[0]];
+ Block[1]=mycd64[in[1]];
+ Block[2]=mycd64[in[2]];
+ Block[3]=mycd64[in[3]];
+
+ out[0] = (unsigned char ) (Block[0] << 2 | Block[1] >> 4);
+ out[1] = (unsigned char ) (Block[1] << 4 | Block[2] >> 2);
+ out[2] = (unsigned char ) (((Block[2] << 6) & 0xc0) | Block[3]);
+}
+
+/**
+* @ingroup libcgi_string
+* @{
+*/
+
+/**
+* Encodes a given tring to its base64 form.
+*
+* @param *str String to convert
+* @return Base64 encoded String
+* @see str_base64_decode
+**/
+char *str_base64_encode(char *str)
+{
+ unsigned int i = 0, j = 0, len = (int)strlen(str);
+ char *tmp = str;
+ char *result = (char *)zalloc((len+1) * sizeof(void *));
+
+ if (!result)
+ return NULL;
+
+ while (len > 2 )
+ {
+ encodeblock(&str[i], &result[j],3);
+ i+=3;
+ j+=4;
+ len -=3;
+ }
+ if (len)
+ {
+ encodeblock(&str[i], &result[j], len);
+ }
+
+ return result;
+}
+
+SocketConn * SMTPConnect(char * Host, int Port, BOOL AMPR, struct MsgInfo * Msg, char * MsgBody)
+{
+ int err;
+ u_long param=1;
+ BOOL bcopt=TRUE;
+
+ SocketConn * sockptr;
+
+ SOCKADDR_IN sinx;
+ SOCKADDR_IN destaddr;
+ int addrlen=sizeof(sinx);
+ struct hostent * HostEnt;
+
+ // Resolve Name if needed
+
+ destaddr.sin_family = AF_INET;
+ destaddr.sin_port = htons(Port);
+
+ destaddr.sin_addr.s_addr = inet_addr(Host);
+
+ if (destaddr.sin_addr.s_addr == INADDR_NONE)
+ {
+ // Resolve name to address
+
+ HostEnt = gethostbyname (Host);
+
+ if (!HostEnt)
+ {
+ Logprintf(LOG_TCP, NULL, '|', "Resolve Failed for SMTP Server %s", Host);
+ SMTPActive = FALSE;
+ return FALSE; // Resolve failed
+ }
+ memcpy(&destaddr.sin_addr.s_addr,HostEnt->h_addr,4);
+ }
+
+// Allocate a Socket entry
+
+ sockptr=malloc(sizeof(SocketConn));
+ memset(sockptr, 0, sizeof (SocketConn));
+
+ sockptr->Next=Sockets;
+ Sockets=sockptr;
+
+ sockptr->socket=socket(AF_INET,SOCK_STREAM,0);
+
+ if (sockptr->socket == INVALID_SOCKET)
+ {
+ return FALSE;
+ }
+
+ sockptr->Type = SMTPClient;
+ sockptr->AMPR = AMPR;
+
+ if (AMPR)
+ strcpy(sockptr->FromDomain, AMPRDomain);
+ else
+ strcpy(sockptr->FromDomain, MyDomain);
+
+ sockptr->SMTPMsg = Msg;
+ sockptr->MailBuffer = MsgBody;
+
+ ioctlsocket (sockptr->socket, FIONBIO, ¶m);
+
+ setsockopt (sockptr->socket, SOL_SOCKET, SO_REUSEADDR, (const char FAR *)&bcopt,4);
+
+ sinx.sin_family = AF_INET;
+ sinx.sin_addr.s_addr = INADDR_ANY;
+ sinx.sin_port = 0;
+
+ if (bind(sockptr->socket, (LPSOCKADDR) &sinx, addrlen) != 0 )
+ {
+ //
+ // Bind Failed
+ //
+
+ return FALSE;
+ }
+
+ if (connect(sockptr->socket,(LPSOCKADDR) &destaddr, sizeof(destaddr)) == 0)
+ {
+ //
+ // Connected successful
+ //
+
+ sockptr->State = WaitingForGreeting;
+
+ return sockptr;
+ }
+ else
+ {
+ err=WSAGetLastError();
+
+ if (err == WSAEWOULDBLOCK || err == 115 || err == 36)
+ {
+ //
+ // Connect in Progress
+ //
+
+ sockptr->State = Connecting;
+ return sockptr;
+ }
+ else
+ {
+ //
+ // Connect failed
+ //
+
+ printf("SMTP Connect failed immediately\n");
+ closesocket(sockptr->socket);
+ ReleaseSock(sockptr->socket);
+ return FALSE;
+
+ return FALSE;
+ }
+ }
+ return FALSE;
+}
+
+int TryHELO = 0; // Not thread safe but taking the chance..
+
+VOID ProcessSMTPClientMessage(SocketConn * sockptr, char * Buffer, int Len)
+{
+ SOCKET sock;
+
+ sock=sockptr->socket;
+
+ WriteLogLine(NULL, '<',Buffer, Len-2, LOG_TCP);
+
+ Buffer[Len] = 0;
+
+ if (sockptr->State == WaitingForGreeting)
+ {
+ if (memcmp(Buffer, "220 ",4) == 0)
+ {
+ TryHELO = 0;
+
+ if (sockptr->AMPR)
+ sockprintf(sockptr, "EHLO %s", AMPRDomain);
+ else if (ISPEHLOName[0])
+ sockprintf(sockptr, "EHLO %s", ISPEHLOName);
+ else
+ sockprintf(sockptr, "EHLO %s", BBSName);
+
+ sockptr->State = WaitingForHELOResponse;
+ }
+ else
+ {
+ SendSock(sockptr, "QUIT");
+ sockptr->State = 0;
+ }
+
+ return;
+ }
+
+ if (sockptr->State == WaitingForHELOResponse)
+ {
+/*
+ if (memcmp(Buffer, "500 ",4) == 0 && TryHELO == 0)
+ {
+ TryHELO = 1;
+
+ if (sockptr->AMPR)
+ sockprintf(sockptr, "HELO %s", AMPRDomain);
+ else if (ISPEHLOName[0])
+ sockprintf(sockptr, "HELO %s", ISPEHLOName);
+ else
+ sockprintf(sockptr, "HELO %s", BBSName);
+
+ return;
+ }
+*/
+ if (memcmp(Buffer, "250-",4) == 0)
+ return;
+
+ if (memcmp(Buffer, "250 ",4) == 0)
+ {
+ if (SMTPAuthNeeded && sockptr->AMPR == FALSE)
+ {
+ sockprintf(sockptr, "AUTH LOGIN");
+ sockptr->State = WaitingForAUTHResponse;
+ }
+ else
+ {
+ sockprintf(sockptr, "MAIL FROM: <%s@%s>", sockptr->SMTPMsg->from, sockptr->FromDomain);
+ sockptr->State = WaitingForFROMResponse;
+ }
+ }
+ else
+ {
+ SendSock(sockptr, "QUIT");
+ sockptr->State = 0;
+ SMTPActive = FALSE;
+
+ }
+
+ return;
+ }
+
+ if (sockptr->State == WaitingForAUTHResponse)
+ {
+ if (memcmp(Buffer, "334 VXN", 7) == 0)
+ {
+ char * Msg = str_base64_encode(ISPAccountName);
+ SendSock(sockptr, Msg);
+ free(Msg);
+ return;
+ }
+ else if (memcmp(Buffer, "334 UGF", 7) == 0)
+ {
+ char * Msg = str_base64_encode(ISPAccountPass);
+ SendSock(sockptr, Msg);
+ free(Msg);
+ return;
+ }
+ else if (memcmp(Buffer, "235 ", 4) == 0)
+ {
+ sockprintf(sockptr, "MAIL FROM: <%s@%s>", sockptr->SMTPMsg->from, sockptr->FromDomain);
+// sockprintf(sockptr, "MAIL FROM: <%s@%s.%s>", sockptr->SMTPMsg->from, BBSName, HRoute);
+ sockptr->State = WaitingForFROMResponse;
+ }
+
+ else
+ {
+ SendSock(sockptr, "QUIT");
+ sockptr->State = 0;
+ SMTPActive = FALSE;
+ }
+
+ return;
+
+ }
+
+
+ if (sockptr->State == WaitingForFROMResponse)
+ {
+ if (memcmp(Buffer, "250 ",4) == 0)
+ {
+ sockprintf(sockptr, "RCPT TO: <%s>", sockptr->SMTPMsg->via);
+ sockptr->State = WaitingForTOResponse;
+ }
+ else
+ {
+ sockptr->SMTPMsg->status = 'H'; // Hold for review
+ SendSock(sockptr, "QUIT");
+ sockptr->State = 0;
+ SMTPActive = FALSE;
+ }
+
+ return;
+ }
+
+ if (sockptr->State == WaitingForTOResponse)
+ {
+ if (memcmp(Buffer, "250 ",4) == 0)
+ {
+ SendSock(sockptr, "DATA");
+ sockptr->State = WaitingForDATAResponse;
+ }
+ else
+ {
+ sockptr->SMTPMsg->status = 'H'; // Hold for review
+ SendSock(sockptr, "QUIT");
+ sockptr->State = 0;
+ SMTPActive = FALSE;
+ }
+
+ return;
+ }
+
+ if (sockptr->State == WaitingForDATAResponse)
+ {
+ int Len;
+ UCHAR * UTF;
+
+ if (memcmp(Buffer, "354 ",4) == 0)
+ {
+ sockprintf(sockptr, "To: %s", sockptr->SMTPMsg->via);
+ sockprintf(sockptr, "From: %s <%s@%s>", sockptr->SMTPMsg->from, sockptr->SMTPMsg->from, sockptr->FromDomain);
+ sockprintf(sockptr, "Sender: %s@%s", sockptr->SMTPMsg->from, sockptr->FromDomain);
+ if (GMailMode && sockptr->AMPR == FALSE)
+ sockprintf(sockptr, "Reply-To: %s+%s@%s", GMailName, sockptr->SMTPMsg->from, sockptr->FromDomain);
+ else
+ sockprintf(sockptr, "Reply-To: %s@%s", sockptr->SMTPMsg->from, sockptr->FromDomain);
+
+ sockprintf(sockptr, "Subject: %s", sockptr->SMTPMsg->title);
+
+ sockptr->State = WaitingForBodyResponse;
+
+ if (sockptr->SMTPMsg->B2Flags & Attachments)
+ {
+ // B2 Message with Attachments. Create a Mime-Encoded Multipart message
+
+ SendMultiPartMessage(sockptr, sockptr->SMTPMsg, sockptr->MailBuffer);
+ return;
+ }
+
+ // If message has characters above 7F convert to UFT8 if necessary and send as Base64
+
+
+ Len = (int)strlen(sockptr->MailBuffer);
+
+ if (Is8Bit(sockptr->MailBuffer, Len))
+ {
+ // 8 Bit. Will send as UFT8
+
+ SendSock(sockptr, "Content-Type: text/plain; charset=\"utf-8\"");
+ SendSock(sockptr, "Content-Transfer-Encoding: base64");
+ SendSock(sockptr, "Content-Disposition: inline");
+
+ SendSock(sockptr, ""); // Blank line before body
+
+ if (WebIsUTF8(sockptr->MailBuffer, Len) == FALSE)
+ {
+ // Must be some other coding
+
+ int code = TrytoGuessCode(sockptr->MailBuffer, Len);
+ UTF = malloc(Len * 3);
+
+ if (code == 437)
+ Len = Convert437toUTF8(sockptr->MailBuffer, Len, UTF);
+ else if (code == 1251)
+ Len = Convert1251toUTF8(sockptr->MailBuffer, Len, UTF);
+ else
+ Len = Convert1252toUTF8(sockptr->MailBuffer, Len, UTF); // Default
+
+ Base64EncodeAndSend(sockptr, UTF, Len);
+ free(UTF);
+ }
+ else
+ Base64EncodeAndSend(sockptr, sockptr->MailBuffer, Len);
+
+ }
+ else
+ {
+ // send as USASCII
+
+ SendSock(sockptr, ""); // Blank line before body
+ SendSock(sockptr, sockptr->MailBuffer);
+ }
+
+ SendSock(sockptr, ".");
+
+ }
+ else
+ {
+ SendSock(sockptr, "QUIT");
+ sockptr->State = 0;
+ SMTPActive = FALSE;
+ }
+
+ return;
+ }
+
+ if (sockptr->State == WaitingForBodyResponse)
+ {
+ struct MsgInfo * Msg = sockptr->SMTPMsg;
+
+ if (memcmp(Buffer, "250 ", 4) == 0)
+ {
+ // if AMPR, clear forwarding bitmap
+
+ if (sockptr->AMPR)
+ {
+ // Mark mail as sent, and look for more
+
+ struct UserInfo * bbs = sockptr->bbs;
+
+ clear_fwd_bit(Msg->fbbs, bbs->BBSNumber);
+ set_fwd_bit(Msg->forw, bbs->BBSNumber);
+
+ // Only mark as forwarded if sent to all BBSs that should have it
+
+ if (memcmp(Msg->fbbs, zeros, NBMASK) == 0)
+ {
+ Msg->status = 'F'; // Mark as forwarded
+ Msg->datechanged=time(NULL);
+ }
+
+ bbs->ForwardingInfo->MsgCount--;
+ bbs->ForwardingInfo->Forwarding = 0;
+
+ // See if any more
+
+ if (bbs->ForwardingInfo->MsgCount)
+ bbs->ForwardingInfo->FwdTimer = bbs->ForwardingInfo->FwdInterval; // Reschdul send
+
+ }
+ else
+ {
+ Msg->status = 'F';
+ SMTPActive = FALSE;
+ SMTPMsgCreated=TRUE; // See if any more
+ }
+ }
+
+ SendSock(sockptr, "QUIT");
+ sockptr->State = 0;
+
+ SMTPActive = FALSE;
+
+ SMTPMsgCreated=TRUE; // See if any more
+
+ return;
+ }
+}
+
+BOOL SendtoAMPR(CIRCUIT * conn)
+{
+ struct MsgInfo * Msg = conn->FwdMsg;
+ SocketConn * sockptr;
+
+ char * Body;
+ int toLen;
+ char * tocopy;
+ char * Host;
+
+ // Make sure message exists
+
+ Body = ReadMessageFile(Msg->number);
+
+ if (Body == NULL)
+ {
+ FlagAsKilled(Msg, TRUE);
+ return FALSE;
+ }
+
+ toLen = (int)strlen(Msg->via);
+
+ tocopy = _strdup(Msg->via);
+
+ Host = strlop(tocopy, '@');
+
+ if (Host == NULL)
+ {
+ Logprintf(LOG_TCP, NULL, '|', "AMPR Forward - Host Name missing from VIA %s for Msg %d", Msg->via, Msg->number);
+ free(tocopy);
+ return FALSE;
+ }
+
+ Logprintf(LOG_TCP, NULL, '|', "Connecting to Server %s to send Msg %d", Host, Msg->number);
+
+ sockptr = SMTPConnect(Host, 25, TRUE, Msg, Body);
+
+ free(tocopy);
+
+ if (sockptr)
+ {
+ sockptr->bbs = conn->UserPointer;
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+BOOL SendtoISP()
+{
+ // Find a message intended for the Internet and send it
+
+ int m = NumberofMessages;
+ char * Body;
+
+ struct MsgInfo * Msg;
+
+ if (SMTPActive)
+ return FALSE;
+
+ do
+ {
+ Msg=MsgHddrPtr[m];
+
+ if ((Msg->status == 'N') && (Msg->to[0] == 0) && (Msg->from[0] != 0))
+ {
+ // Make sure message exists
+
+ Body = ReadMessageFile(Msg->number);
+
+ if (Body == NULL)
+ {
+ FlagAsKilled(Msg, TRUE);
+ return FALSE;
+ }
+
+ Logprintf(LOG_TCP, NULL, '|', "Connecting to Server %s to send Msg %d", ISPSMTPName, Msg->number);
+
+ SMTPMsgCreated=FALSE; // Stop any more attempts
+ SMTPConnect(ISPSMTPName, ISPSMTPPort, FALSE, Msg, Body);
+
+ SMTPActive = TRUE;
+
+ return TRUE;
+ }
+
+ m--;
+
+ } while (m> 0);
+
+ return FALSE;
+
+}
+
+
+BOOL POP3Connect(char * Host, int Port)
+{
+ int err;
+ u_long param=1;
+ BOOL bcopt=TRUE;
+
+ SocketConn * sockptr;
+
+ SOCKADDR_IN sinx;
+ SOCKADDR_IN destaddr;
+ int addrlen=sizeof(sinx);
+ struct hostent * HostEnt;
+
+ Logprintf(LOG_TCP, NULL, '|', "Connecting to POP3 Server %s", Host);
+
+ // Resolve Name if needed
+
+ destaddr.sin_family = AF_INET;
+ destaddr.sin_port = htons(Port);
+
+ destaddr.sin_addr.s_addr = inet_addr(Host);
+
+ if (destaddr.sin_addr.s_addr == INADDR_NONE)
+ {
+ // Resolve name to address
+
+ HostEnt = gethostbyname (Host);
+
+ if (!HostEnt)
+ {
+ Logprintf(LOG_TCP, NULL, '|', "Resolve Failed for POP3 Server %s", Host);
+ return FALSE; // Resolve failed
+ }
+ memcpy(&destaddr.sin_addr.s_addr,HostEnt->h_addr,4);
+ }
+
+// Allocate a Socket entry
+
+ sockptr = malloc(sizeof(SocketConn));
+ memset(sockptr, 0, sizeof (SocketConn));
+
+ sockptr->Next = Sockets;
+ Sockets = sockptr;
+
+ sockptr->socket = socket(AF_INET,SOCK_STREAM,0);
+
+ if (sockptr->socket == INVALID_SOCKET)
+ {
+ return FALSE;
+ }
+
+ sockptr->Type = POP3Client;
+
+ ioctlsocket (sockptr->socket, FIONBIO, ¶m);
+
+ setsockopt (sockptr->socket, SOL_SOCKET, SO_REUSEADDR, (const char FAR *)&bcopt,4);
+
+ sinx.sin_family = AF_INET;
+ sinx.sin_addr.s_addr = INADDR_ANY;
+ sinx.sin_port = 0;
+
+ if (bind(sockptr->socket, (LPSOCKADDR) &sinx, addrlen) != 0 )
+ {
+ //
+ // Bind Failed
+ //
+
+ return FALSE;
+ }
+
+ if (connect(sockptr->socket,(LPSOCKADDR) &destaddr, sizeof(destaddr)) == 0)
+ {
+ //
+ // Connected successful
+ //
+
+ sockptr->State = WaitingForGreeting;
+
+ return TRUE;
+ }
+ else
+ {
+ err=WSAGetLastError();
+
+ if (err == WSAEWOULDBLOCK || err == 115 || err == 36)
+ {
+ //
+ // Connect in Progressing
+ //
+
+ sockptr->State = Connecting;
+ return TRUE;
+ }
+ else
+ {
+ //
+ // Connect failed
+ //
+
+ printf("Connect failed immediately %d\n", err);
+ perror("POP Connect");
+ closesocket(sockptr->socket);
+ ReleaseSock(sockptr->socket);
+ return FALSE;
+ }
+ }
+ return FALSE;
+}
+
+VOID ProcessPOP3ClientMessage(SocketConn * sockptr, char * Buffer, int Len)
+{
+ SOCKET sock;
+ time_t Date;
+ BOOL B2Flag;
+
+ sock=sockptr->socket;
+
+ WriteLogLine(NULL, '<',Buffer, Len-2, LOG_TCP);
+
+ if (sockptr->Flags == GETTINGMESSAGE)
+ {
+ if(memcmp(Buffer, ".\r\n", 3) == 0)
+ {
+ // File Message
+
+ char * ptr1, * ptr2;
+ int linelen, MsgLen;
+ char MsgFrom[62], MsgTo[100], Msgtitle[62];
+
+ // Scan headers for From: To: and Subject: Line (Headers end at blank line)
+
+ ptr1 = sockptr->MailBuffer;
+ Loop:
+ ptr2 = strchr(ptr1, '\r');
+
+ if (ptr2 == NULL)
+ {
+ SendSock(sockptr, "500 Eh");
+ return;
+ }
+
+ linelen = (int)(ptr2 - ptr1);
+
+ // From: "John Wiseman"
+ // To:
+ //
+
+
+ if (_memicmp(ptr1, "From:", 5) == 0)
+ {
+ if (linelen > 65) linelen = 65;
+ memcpy(MsgFrom, &ptr1[5], linelen-5);
+ MsgFrom[linelen-5]=0;
+ }
+ else
+ if (_memicmp(ptr1, "To:", 3) == 0)
+ {
+ if (linelen > 99) linelen = 99;
+ memcpy(MsgTo, &ptr1[4], linelen-4);
+ MsgTo[linelen-4]=0;
+ }
+ else
+ if (_memicmp(ptr1, "Subject:", 8) == 0)
+ {
+ if (linelen > 68) linelen = 68;
+ memcpy(Msgtitle, &ptr1[9], linelen-9);
+ Msgtitle[linelen-9]=0;
+ }
+ else
+ if (_memicmp(ptr1, "Date:", 5) == 0)
+ {
+ struct tm rtime;
+ char * Context;
+ char seps[] = " ,\t\r";
+ char Offset[10] = "";
+ int i, HH, MM;
+ char Copy[500]="";
+
+ // Copy message, so original isn't messed up by strtok
+
+ memcpy(Copy, ptr1, linelen);
+
+ ptr1 = Copy;
+
+ memset(&rtime, 0, sizeof(struct tm));
+
+ // Date: Tue, 9 Jun 2009 20:54:55 +0100
+
+ ptr1 = strtok_s(&ptr1[5], seps, &Context); // Skip Day
+ ptr1 = strtok_s(NULL, seps, &Context); // Day
+
+ rtime.tm_mday = atoi(ptr1);
+
+ ptr1 = strtok_s(NULL, seps, &Context); // Month
+
+ for (i=0; i < 12; i++)
+ {
+ if (strcmp(month[i], ptr1) == 0)
+ {
+ rtime.tm_mon = i;
+ break;
+ }
+ }
+
+ sscanf(Context, "%04d %02d:%02d:%02d%s",
+ &rtime.tm_year, &rtime.tm_hour, &rtime.tm_min, &rtime.tm_sec, Offset);
+
+ rtime.tm_year -= 1900;
+
+ Date = mktime(&rtime) - (time_t)_MYTIMEZONE;
+
+ if (Date == (time_t)-1)
+ Date = 0;
+ else
+ {
+ if ((Offset[0] == '+') || (Offset[0] == '-'))
+ {
+ MM = atoi(&Offset[3]);
+ Offset[3] = 0;
+ HH = atoi(&Offset[1]);
+ MM = MM + (60 * HH);
+
+ if (Offset[0] == '+')
+ Date -= (60*MM);
+ else
+ Date += (60*MM);
+
+
+ }
+ }
+ }
+
+
+ if (linelen) // Not Null line
+ {
+ ptr1 = ptr2 + 2; // Skip crlf
+ goto Loop;
+ }
+
+ ptr1 = sockptr->MailBuffer;
+
+ TidyString(MsgFrom);
+ _strlwr(MsgFrom);
+
+ MsgLen = (int)(sockptr->MailSize - (ptr2 - ptr1));
+
+ B2Flag = CheckforMIME(sockptr, sockptr->MailBuffer, &ptr2, &MsgLen); // Will reformat message if necessary.
+
+ CreatePOP3Message(MsgFrom, MsgTo, Msgtitle, Date, ptr2, MsgLen, B2Flag);
+
+ free(sockptr->MailBuffer);
+ sockptr->MailBufferSize=0;
+ sockptr->MailBuffer=0;
+ sockptr->MailSize = 0;
+
+ sockptr->Flags &= ~GETTINGMESSAGE;
+
+ if (sockptr->POP3MsgCount > sockptr->POP3MsgNum++)
+ {
+ sockprintf(sockptr, "RETR %d", sockptr->POP3MsgNum);
+
+ sockptr->State = WaitingForRETRResponse;
+ }
+ else
+ {
+ sockptr->POP3MsgNum = 1;
+ sockprintf(sockptr, "DELE %d", sockptr->POP3MsgNum);;
+ sockptr->State = WaitingForDELEResponse;
+ }
+
+ return;
+ }
+
+ if ((sockptr->MailSize + Len) > sockptr->MailBufferSize)
+ {
+ sockptr->MailBufferSize += 10000;
+ sockptr->MailBuffer = realloc(sockptr->MailBuffer, sockptr->MailBufferSize);
+
+ if (sockptr->MailBuffer == NULL)
+ {
+ CriticalErrorHandler("Failed to extend Message Buffer");
+ shutdown(sock, 0);
+ return;
+ }
+ }
+
+ memcpy(&sockptr->MailBuffer[sockptr->MailSize], Buffer, Len);
+ sockptr->MailSize += Len;
+
+ return;
+ }
+
+ if (sockptr->State == WaitingForGreeting)
+ {
+ if (memcmp(Buffer, "+OK", 3) == 0)
+ {
+ sockprintf(sockptr, "USER %s", ISPAccountName);
+ sockptr->State = WaitingForUSERResponse;
+ }
+ else
+ {
+ SendSock(sockptr, "QUIT");
+ sockptr->State = 0;
+ }
+
+ return;
+ }
+
+ if (sockptr->State == WaitingForUSERResponse)
+ {
+ if (memcmp(Buffer, "+OK", 3) == 0)
+ {
+ sockprintf(sockptr, "PASS %s", ISPAccountPass);
+ sockptr->State = WaitingForPASSResponse;
+ }
+ else
+ {
+ SendSock(sockptr, "QUIT");
+ sockptr->State = WaitingForQUITResponse;
+ }
+
+ return;
+ }
+
+ if (sockptr->State == WaitingForPASSResponse)
+ {
+ if (memcmp(Buffer, "+OK", 3) == 0)
+ {
+ SendSock(sockptr, "STAT");
+ sockptr->State = WaitingForSTATResponse;
+ }
+ else
+ {
+ shutdown(sock, 0);
+ sockptr->State = 0;
+ }
+
+ return;
+ }
+
+ if (sockptr->State == WaitingForSTATResponse)
+ {
+ if (memcmp(Buffer, "+OK", 3) == 0)
+ {
+ int Msgs = atoi(&Buffer[3]);
+
+ if (Msgs > 0)
+ {
+ sockptr->POP3MsgCount = Msgs;
+ sockptr->POP3MsgNum = 1;
+ SendSock(sockptr, "RETR 1");
+
+ sockptr->State = WaitingForRETRResponse;
+
+ }
+ else
+ {
+ SendSock(sockptr, "QUIT");
+ sockptr->State = WaitingForQUITResponse;
+ }
+ }
+ else
+ {
+ SendSock(sockptr, "QUIT");
+ sockptr->State = WaitingForQUITResponse;
+ }
+
+ return;
+ }
+
+ if (sockptr->State == WaitingForRETRResponse)
+ {
+ if (memcmp(Buffer, "+OK", 3) == 0)
+ {
+ sockptr->MailBuffer=malloc(10000);
+ sockptr->MailBufferSize=10000;
+
+ if (sockptr->MailBuffer == NULL)
+ {
+ CriticalErrorHandler("Failed to create POP3 Message Buffer");
+ SendSock(sockptr, "QUIT");
+ sockptr->State = WaitingForQUITResponse;
+ shutdown(sock, 0);
+
+ return;
+ }
+
+ sockptr->Flags |= GETTINGMESSAGE;
+
+ }
+ else
+ {
+ SendSock(sockptr, "QUIT");
+ sockptr->State = WaitingForQUITResponse;
+ }
+
+ return;
+ }
+ if (sockptr->State == WaitingForDELEResponse)
+ {
+ if (memcmp(Buffer, "+OK", 3) == 0)
+ {
+ if (sockptr->POP3MsgCount > sockptr->POP3MsgNum++)
+ {
+ sockprintf(sockptr, "DELE %d", sockptr->POP3MsgNum);;
+ }
+ else
+ {
+ SendSock(sockptr, "QUIT");
+ sockptr->Flags = WaitingForQUITResponse;
+ }
+ }
+ else
+ {
+ shutdown(sock,0);
+ sockptr->State = 0;
+ }
+ return;
+ }
+
+ if (sockptr->State == WaitingForQUITResponse)
+ {
+ shutdown(sock,0);
+ sockptr->State = 0;
+ return;
+ }
+
+ SendSock(sockptr, "QUIT");
+ shutdown(sock,0);
+ sockptr->State = 0;
+
+}
+
+static char Winlink[] = "WINLINK.ORG";
+
+int CreatePOP3Message(char * From, char * To, char * MsgTitle, time_t Date, char * MsgBody, int MsgLen, BOOL B2Flag)
+{
+ struct MsgInfo * Msg;
+ BIDRec * BIDRec;
+
+ // Allocate a message Record slot
+
+ Msg = AllocateMsgRecord();
+
+ // Set number here so they remain in sequence
+
+ Msg->number = ++LatestMsg;
+ MsgnotoMsg[Msg->number] = Msg;
+ Msg->length = MsgLen;
+
+
+ sprintf_s(Msg->bid, sizeof(Msg->bid), "%d_%s", LatestMsg, BBSName);
+
+ Msg->type = 'P';
+ Msg->status = 'N';
+ Msg->datereceived = Msg->datechanged = Msg->datecreated = time(NULL);
+
+ if (Date)
+ Msg->datecreated = Date;
+
+ BIDRec = AllocateBIDRecord();
+
+ strcpy(BIDRec->BID, Msg->bid);
+ BIDRec->mode = Msg->type;
+ BIDRec->u.msgno = LOWORD(Msg->number);
+ BIDRec->u.timestamp = LOWORD(time(NULL)/86400);
+
+
+ TidyString(To);
+ strlop(To, '@');
+
+ // Could have surrounding "" ""
+
+ if (To[0] == '"')
+ {
+ int len = (int)strlen(To) - 1;
+
+ if (To[len] == '"')
+ {
+ To[len] = 0;
+ memmove(To, &To[1], len);
+ }
+ }
+
+ if (GMailMode)
+ {
+ // + separates our address and the target user
+
+ char * GMailto;
+
+ GMailto = strlop(To,'+');
+
+ if (GMailto)
+ {
+ char * GmailVia = NULL;
+
+ strcpy(To, GMailto);
+ GmailVia = strlop(To, '|');
+
+ if (GmailVia)
+ strcpy(Msg->via, GmailVia);
+ }
+ else
+ {
+ // Someone has sent to the GMAIL account without a +.
+ // This should go to the BBS Call
+
+ strcpy(To, BBSName);
+ }
+ }
+
+ if ((_memicmp(To, "bull/", 5) == 0) || (_memicmp(To, "bull.", 5) == 0)
+ || (_memicmp(To, "bull:", 5) == 0))
+ {
+ Msg->type = 'B';
+ memmove(To, &To[5], strlen(&To[4]));
+ }
+
+ if ((_memicmp(To, "nts/", 4) == 0) || (_memicmp(To, "nts.", 4) == 0)
+ || (_memicmp(To, "nts:", 4) == 0))
+ {
+ Msg->type = 'T';
+ memmove(To, &To[4], strlen(&To[3]));
+ }
+
+ if (Msg->type == 'P' && Msg->via[0] == 0)
+ {
+ // No via - add one from HomeBBS or WP
+
+ struct UserInfo * ToUser = LookupCall(To);
+
+ if (ToUser)
+ {
+ // Local User. If Home BBS is specified, use it
+
+ if (ToUser->flags & F_RMSREDIRECT)
+ {
+ // sent to Winlink
+
+ strcpy(Msg->via, Winlink);
+ }
+ else if (ToUser->HomeBBS[0])
+ strcpy(Msg->via, ToUser->HomeBBS);
+ }
+ else
+ {
+ WPRec * WP = LookupWP(To);
+
+ if (WP)
+ strcpy(Msg->via, WP->first_homebbs);
+ }
+ }
+
+/* if (_memicmp(To, "rms:", 4) == 0)
+ {
+ via = _strlwr(strlop(To, ':'));
+ }
+ else if (_memicmp(To, "rms/", 4) == 0)
+ {
+ via = _strlwr(strlop(To, '/'));
+ }
+ else if (_memicmp(To, "rms.", 4) == 0)
+ {
+ via = _strlwr(strlop(To, '.'));
+ }
+*/
+
+
+ if (strlen(To) > 6) To[6]=0;
+
+ strcpy(Msg->to, To);
+ strcpy(Msg->from, "smtp:");
+ strcpy(Msg->emailfrom, From);
+ strcpy(Msg->title, MsgTitle);
+
+ if(Msg->to[0] == 0)
+ SMTPMsgCreated=TRUE;
+
+ if (B2Flag)
+ {
+ char B2Hddr[1000];
+ int B2HddrLen;
+ char B2To[80];
+ char * NewBody;
+ char DateString[80];
+ struct tm * tm;
+ char Type[16] = "Private";
+
+ // Get Type
+
+ if (Msg->type == 'B')
+ strcpy(Type, "Bulletin");
+ else if (Msg->type == 'T')
+ strcpy(Type, "Traffic");
+
+
+ tm = gmtime(&Date);
+
+ sprintf(DateString, "%04d/%02d/%02d %02d:%02d",
+ tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min);
+
+
+ if (strcmp(Msg->to, "RMS") == 0) // Address is in via
+ strcpy(B2To, Msg->via);
+ else
+ if (Msg->via[0])
+ sprintf(B2To, "%s@%s", Msg->to, Msg->via);
+ else
+ strcpy(B2To, Msg->to);
+
+
+ Msg->B2Flags = B2Msg | Attachments;
+
+ B2HddrLen = sprintf(B2Hddr,
+ "MID: %s\r\nDate: %s\r\nType: %s\r\nFrom: %s\r\nTo: %s\r\nSubject: %s\r\nMbo: %s\r\n",
+ Msg->bid, DateString, Type,
+ Msg->from, B2To, Msg->title, BBSName);
+
+ NewBody = MsgBody - B2HddrLen;
+
+ memcpy(NewBody, B2Hddr, B2HddrLen);
+
+ Msg->length += B2HddrLen;
+
+ // Set up forwarding bitmap
+
+ MatchMessagetoBBSList(Msg, 0);
+
+ return CreateSMTPMessageFile(NewBody, Msg);
+ }
+
+ // Set up forwarding bitmap
+
+ MatchMessagetoBBSList(Msg, 0);
+
+ return CreateSMTPMessageFile(MsgBody, Msg);
+
+}
+
+VOID base64_encode(char *str, char * result, int len)
+{
+ unsigned int i = 0, j = 0;
+ char *tmp = str;
+
+
+ while (len > 2 )
+ {
+ encodeblock(&str[i], &result[j],3);
+ i+=3;
+ j+=4;
+ len -=3;
+ }
+ if (len)
+ {
+ encodeblock(&str[i], &result[j], len);
+ }
+
+ return;
+}
+
+void Base64EncodeAndSend(SocketConn * sockptr, UCHAR * Msg, int Len)
+{
+ char Base64Line[80];
+ int i = Len;
+ int j = 0;
+
+ Base64Line[76] = 13;
+ Base64Line[77] = 10;
+ Base64Line[78] = 0;
+
+ // Need to encode in 57 byte chunks to give 76 char lines.
+
+ while(i > 57)
+ {
+ base64_encode(&Msg[j], Base64Line, 57);
+ SendSock(sockptr, Base64Line);
+
+ j += 57;
+ i -= 57;
+ }
+
+ memset(Base64Line, 0, 79);
+
+ base64_encode(&Msg[j], Base64Line, i);
+ SendSock(sockptr, Base64Line);
+ SendSock(sockptr, "");
+}
+
+VOID SendMultiPartMessage(SocketConn * sockptr, struct MsgInfo * Msg, UCHAR * msgbytes)
+{
+ char * ptr;
+ char Header[120];
+ char Separator[33]="";
+ char FileName[100][250] = {""};
+ int FileLen[100];
+ int Files = 0;
+ int BodyLen;
+ int i;
+
+ CreateOneTimePassword(&Separator[0], "Key", 0);
+ CreateOneTimePassword(&Separator[16], "Key", 1);
+
+ SendSock(sockptr, "MIME-Version: 1.0");
+
+ sprintf_s(Header, sizeof(Header), "Content-Type: multipart/mixed; boundary=\"%s\"", Separator);
+ SendSock(sockptr, Header);
+
+ SendSock(sockptr, ""); // Blank line before body
+
+// Get Part Sizes and Filenames
+
+ ptr = msgbytes;
+
+ while(*ptr != 13)
+ {
+ char * ptr2 = strchr(ptr, 10); // Find CR
+
+ if (memcmp(ptr, "Body: ", 6) == 0)
+ {
+ BodyLen = atoi(&ptr[6]);
+ }
+
+ if (memcmp(ptr, "File: ", 6) == 0)
+ {
+ char * ptr1 = strchr(&ptr[6], ' '); // Find Space
+
+ FileLen[Files] = atoi(&ptr[6]);
+
+ memcpy(FileName[Files++], &ptr1[1], (ptr2-ptr1 - 2));
+ }
+
+ ptr = ptr2;
+ ptr++;
+ }
+
+ ptr += 2; // Over Blank Line
+
+ // Write the none-Mime Part
+
+ SendSock(sockptr, "This is a multi-part message in MIME format.");
+ SendSock(sockptr, "");
+
+ // Write the Body as the first part.
+
+ sprintf_s(Header, sizeof(Header), "--%s", Separator);
+ SendSock(sockptr, Header);
+ SendSock(sockptr, "Content-Type: text/plain");
+ SendSock(sockptr, "");
+
+ ptr[BodyLen] = 0;
+
+ SendSock(sockptr, ptr);
+
+ ptr += BodyLen; // to first file
+ ptr += 2; // Over Blank Line
+
+ // Write Each Attachment
+
+ for (i = 0; i < Files; i++)
+ {
+ sprintf_s(Header, sizeof(Header), "--%s", Separator);
+ SendSock(sockptr, Header);
+// Content-Type: image/png; name="UserParams.png"
+ SendSock(sockptr, "Content-Transfer-Encoding: base64");
+
+ sprintf_s(Header, sizeof(Header), "Content-Disposition: attachment; filename=\"%s\"", FileName[i]);
+ SendSock(sockptr, Header);
+
+ SendSock(sockptr, "");
+
+ // base64 encode and send file
+
+ Base64EncodeAndSend(sockptr, ptr, FileLen[i]);
+
+ ptr += FileLen[i];
+ ptr +=2; // Over separator
+ }
+
+ sprintf_s(Header, sizeof(Header), "--%s--", Separator);
+ SendSock(sockptr, Header);
+
+ SendSock(sockptr, "");
+ SendSock(sockptr, ".");
+
+ free(msgbytes);
+
+ return;
+}
+
+BOOL SendAMPRSMTP(CIRCUIT * conn)
+{
+ struct UserInfo * bbs = conn->UserPointer;
+
+ while (FindMessagestoForward(conn))
+ {
+ if (SendtoAMPR(conn))
+ {
+ bbs->ForwardingInfo->Forwarding = TRUE;
+ return TRUE;
+ }
+ }
+
+ bbs->ForwardingInfo->Forwarding = FALSE;
+ return FALSE;
+}
+
diff --git a/MailTCP.c b/MailTCP.c
index b26f6da..74f2727 100644
--- a/MailTCP.c
+++ b/MailTCP.c
@@ -2207,6 +2207,7 @@ int TidyString(char * Address)
size_t len;
_strupr(Address);
+ Debugprintf(Address);
ptr1 = strchr(Address, '<');
@@ -2260,6 +2261,10 @@ int TidyString(char * Address)
ptr1=ptr2;
}
+ if (ptr1 == 0)
+ return 0;
+
+
if (*ptr1 == '<') ptr1++;
ptr2 = strlop(ptr1, '>');
diff --git a/Versions.h b/Versions.h
index e82c30e..95e4b6d 100644
--- a/Versions.h
+++ b/Versions.h
@@ -10,14 +10,14 @@
#endif
-#define KVers 6,0,24,2
-#define KVerstring "6.0.24.2\0"
+#define KVers 6,0,24,6
+#define KVerstring "6.0.24.6\0"
#ifdef CKernel
#define Vers KVers
#define Verstring KVerstring
-#define Datestring "August 2023"
+#define Datestring "Sepember 2023"
#define VerComments "G8BPQ Packet Switch (C Version)" KVerstring
#define VerCopyright "Copyright © 2001-2023 John Wiseman G8BPQ\0"
#define VerDesc "BPQ32 Switch\0"
diff --git a/asmstrucs.h b/asmstrucs.h
index 29dcb64..e0415d9 100644
--- a/asmstrucs.h
+++ b/asmstrucs.h
@@ -890,6 +890,9 @@ typedef struct _LINKTABLE
UCHAR SESSACTIVE; // SET WHEN WE ARE SURE SESSION IS UP
+ UINT APPLMASK; // Used when XIR processed
+ VOID * ALIASPTR;
+
USHORT KILLTIMER; // TIME TO KILL IDLE LINK
VOID * CIRCUITPOINTER; // POINTER TO L4 CIRCUIT TABLE ENTRY
diff --git a/bpqmail.h b/bpqmail.h
index d910932..a08d00d 100644
--- a/bpqmail.h
+++ b/bpqmail.h
@@ -941,6 +941,23 @@ typedef struct SocketConnectionInfo
} SocketConn;
+// FBB reject.sys like filters
+
+typedef struct FBBFILTER
+{
+ struct FBBFILTER * Next;
+ char Action;
+ char Type;
+ char From[10];
+ char AT[10];
+ char TO[10];
+ char BID[16];
+ int MaxLen;
+
+} FBBFilter;
+
+extern FBBFilter * Filters;
+
typedef struct KEYVALUES
{
char * Key;
@@ -1210,8 +1227,8 @@ BOOL ConnecttoBBS (struct UserInfo * user);
BOOL SetupNewBBS(struct UserInfo * user);
VOID CreateRegBackup();
VOID SaveFilters(HWND hDlg);
-BOOL CheckRejFilters(char * From, char * To, char * ATBBS, char * BID, char Type);
-BOOL CheckHoldFilters(char * From, char * To, char * ATBBS, char * BID);
+BOOL CheckRejFilters(char * From, char * To, char * ATBBS, char * BID, char Type, int Len);
+BOOL CheckHoldFilters(struct MsgInfo * Msg, char * From, char * To, char * ATBBS, char * BID);
BOOL CheckifLocalRMSUser(char * FullTo);
VOID DoWPLookup(ConnectionInfo * conn, struct UserInfo * user, char Type, char *Context);
BOOL wildcardcompare(char * Target, char * Match);
diff --git a/config.c b/config.c
index 6592b51..cd5f6b4 100644
--- a/config.c
+++ b/config.c
@@ -2927,7 +2927,7 @@ BOOL ProcessAPPLDef(char * buf)
Appl = atoi(Param[0]);
- if (Appl < 1 || Appl > 32) return FALSE;
+ if (Appl < 1 || Appl > NumberofAppls) return FALSE;
App = &xxcfg.C_APPL[Appl - 1]; // Recs from zero
diff --git a/templatedefs.c b/templatedefs.c
index 4dba3d7..72f1c8b 100644
--- a/templatedefs.c
+++ b/templatedefs.c
@@ -420,6 +420,7 @@ char * MainConfigtxt()
""
"