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, + ""); + + 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, "
ActionTypeFromTo@BBSBidMax Size
"); + + 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 @@ 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() "" "