diff --git a/BBSHTMLConfig.c b/BBSHTMLConfig.c index 01b05bd..80f2bca 100644 --- a/BBSHTMLConfig.c +++ b/BBSHTMLConfig.c @@ -38,6 +38,7 @@ extern char LTATString[2048]; //static UCHAR BPQDirectory[260]; extern ConnectionInfo Connections[]; + extern int NumberofStreams; extern time_t MaintClock; // Time to run housekeeping @@ -49,6 +50,7 @@ extern int MaxChatStreams; extern char Position[81]; extern char PopupText[251]; extern int PopupMode; +extern int reportMailEvents; #define MaxCMS 10 // Numbr of addresses we can keep - currently 4 are used. @@ -114,6 +116,7 @@ int SendWebMailHeader(char * Reply, char * Key, struct HTTPConnectionInfo * Sess struct UserInfo * FindBBS(char * Name); void ReleaseWebMailStruct(WebMailInfo * WebMail); VOID TidyWelcomeMsg(char ** pPrompt); +int MailAPIProcessHTTPMessage(char * response, char * Method, char * URL, char * request, BOOL LOCAL, char * Param); char UNC[] = ""; char CHKD[] = "checked=checked "; @@ -488,6 +491,13 @@ void ProcessMailHTTPMessage(struct HTTPConnectionInfo * Session, char * Method, GotFirstMessage = 1; return; } + + if (_memicmp(URL, "/Mail/API/", 10) == 0) + { + *RLen = MailAPIProcessHTTPMessage(Reply, Method, URL, input, LOCAL, Context); + return; + } + if (strcmp(Method, "POST") == 0) { @@ -1633,6 +1643,7 @@ VOID ProcessConfUpdate(struct HTTPConnectionInfo * Session, char * MsgPtr, char UserCantKillT = !UserCantKillT; // Reverse Logic GetCheckBox(input, "FWDtoMe=", &ForwardToMe); GetCheckBox(input, "OnlyKnown=", &OnlyKnown); + GetCheckBox(input, "Events=", &reportMailEvents); GetParam(input, "POP3Port=", Temp); POP3InPort = atoi(Temp); @@ -2610,6 +2621,7 @@ VOID SendConfigPage(char * Reply, int * ReplyLen, char * Key) (UserCantKillT) ? UNC : CHKD, // Reverse logic (ForwardToMe) ? CHKD : UNC, (OnlyKnown) ? CHKD : UNC, + (reportMailEvents) ? CHKD : UNC, POP3InPort, SMTPInPort, NNTPInPort, (RemoteEmail) ? CHKD : UNC, AMPRDomain, diff --git a/BBSUtilities.c b/BBSUtilities.c index 1d3c1f2..48f927a 100644 --- a/BBSUtilities.c +++ b/BBSUtilities.c @@ -43,7 +43,7 @@ RECT ConsoleRect; BOOL OpenConsole; BOOL OpenMon; -int reportNewMesageEvents = 0; +int reportMailEvents = 0; FBBFilter * Filters = NULL; @@ -124,6 +124,8 @@ void decodeblock( unsigned char in[4], unsigned char out[3]); int encode_quoted_printable(char *s, char * out, int Len); int32_t Encode(char * in, char * out, int32_t inlen, BOOL B1Protocol, int Compress); int APIENTRY ChangeSessionCallsign(int Stream, unsigned char * AXCall); +void SendMessageReadEvent(char * user, struct MsgInfo * Msg); +void SendNewMessageEvent(char * call, struct MsgInfo * Msg); config_t cfg; config_setting_t * group; @@ -4904,6 +4906,7 @@ sendEOM: Msg->status = 'Y'; Msg->datechanged=time(NULL); SaveMessageDatabase(); + SendMessageReadEvent(user->Call, Msg); } } } @@ -6457,30 +6460,9 @@ nextline: // If Event Notifications enabled report a new message event - if (reportNewMesageEvents) - { - char msg[200]; - - //12345 B 2053 TEST@ALL F6FBB 920325 This is the subject - - struct tm *tm = gmtime((time_t *)&Msg->datecreated); - - sprintf_s(msg, sizeof(msg),"%-6d %c %6d %-13s %-6s %02d%02d%02d %s\r", - Msg->number, Msg->type, Msg->length, Msg->to, - Msg->from, tm->tm_year-100, tm->tm_mon+1, tm->tm_mday, Msg->title); - -#ifdef WIN32 - if (pRunEventProgram) - pRunEventProgram("MailNewMsg.exe", msg); -#else - { - char prog[256]; - sprintf(prog, "%s/%s", BPQDirectory, "MailNewMsg"); - RunEventProgram(prog, msg); - } -#endif - } + user = LookupCall(Msg->to); + SendNewMessageEvent(user->Call, Msg); if (EnableUI) #ifdef LINBPQ @@ -6493,8 +6475,6 @@ nextline: My__except_Routine("SendMsgUI"); #endif - user = LookupCall(Msg->to); - if (user && (user->flags & F_APRSMFOR)) { char APRS[128]; @@ -9576,6 +9556,7 @@ VOID SaveConfig(char * ConfigName) SaveIntValue(group, "EnableUI", EnableUI); SaveIntValue(group, "RefuseBulls", RefuseBulls); SaveIntValue(group, "OnlyKnown", OnlyKnown); + SaveIntValue(group, "reportMailEvents", reportMailEvents); SaveIntValue(group, "SendSYStoSYSOPCall", SendSYStoSYSOPCall); SaveIntValue(group, "SendBBStoSYSOPCall", SendBBStoSYSOPCall); SaveIntValue(group, "DontHoldNewUsers", DontHoldNewUsers); @@ -10098,28 +10079,30 @@ BOOL GetConfig(char * ConfigName) config_destroy(&cfg); return(EXIT_FAILURE); } - +/* #if LIBCONFIG_VER_MINOR > 5 config_set_option(&cfg, CONFIG_OPTION_AUTOCONVERT, 1); #else config_set_auto_convert (&cfg, 1); #endif - +*/ group = config_lookup (&cfg, "main"); if (group == NULL) return EXIT_FAILURE; - SMTPInPort = GetIntValue(group, "SMTPPort"); - POP3InPort = GetIntValue(group, "POP3Port"); - NNTPInPort = GetIntValue(group, "NNTPPort"); - RemoteEmail = GetIntValue(group, "RemoteEmail"); - MaxStreams = GetIntValue(group, "Streams"); - BBSApplNum = GetIntValue(group, "BBSApplNum"); - EnableUI = GetIntValue(group, "EnableUI"); - MailForInterval = GetIntValue(group, "MailForInterval"); - RefuseBulls = GetIntValue(group, "RefuseBulls"); - OnlyKnown = GetIntValue(group, "OnlyKnown"); + SMTPInPort = GetIntValue(group, "SMTPPort"); + POP3InPort = GetIntValue(group, "POP3Port"); + NNTPInPort = GetIntValue(group, "NNTPPort"); + RemoteEmail = GetIntValue(group, "RemoteEmail"); + MaxStreams = GetIntValue(group, "Streams"); + BBSApplNum = GetIntValue(group, "BBSApplNum"); + EnableUI = GetIntValue(group, "EnableUI"); + MailForInterval = GetIntValue(group, "MailForInterval"); + RefuseBulls = GetIntValue(group, "RefuseBulls"); + OnlyKnown = GetIntValue(group, "OnlyKnown"); + reportMailEvents = GetIntValue(group, "reportMailEvents"); + SendSYStoSYSOPCall = GetIntValue(group, "SendSYStoSYSOPCall"); SendBBStoSYSOPCall = GetIntValue(group, "SendBBStoSYSOPCall"); DontHoldNewUsers = GetIntValue(group, "DontHoldNewUsers"); @@ -15793,3 +15776,62 @@ VOID GetPGConfig() NUM_SERVERS = n; fclose(file); } + +void SendMessageReadEvent(char * call, struct MsgInfo * Msg) +{ + if (reportMailEvents) + { + char msg[512]; + + //12345 B 2053 TEST@ALL F6FBB 920325 This is the subject + + struct tm *tm = gmtime((time_t *)&Msg->datecreated); + + sprintf_s(msg, sizeof(msg),"%-6d %c %c %6d %-13s %-6s %02d%02d%02d %s\r", + Msg->number, Msg->type, Msg->status, Msg->length, Msg->to, + Msg->from, tm->tm_year-100, tm->tm_mon+1, tm->tm_mday, Msg->title); + +// sprintf(msg, "%s Read %d\r", user->Call, Msg->number); + +#ifdef WIN32 + if (pRunEventProgram) + pRunEventProgram("MailMsgRead.exe", msg); +#else + { + char prog[256]; + sprintf(prog, "%s/%s", BPQDirectory, "MailMsgRead"); + RunEventProgram(prog, msg); + } +#endif + } +} + +void SendNewMessageEvent(char * call, struct MsgInfo * Msg) +{ + if (reportMailEvents) + { + char msg[512]; + + //12345 B 2053 TEST@ALL F6FBB 920325 This is the subject + + struct tm *tm = gmtime((time_t *)&Msg->datecreated); + + sprintf_s(msg, sizeof(msg),"%-6d %c %c %6d %-13s %-6s %02d%02d%02d %s\r", + Msg->number, Msg->type, Msg->status, Msg->length, Msg->to, + Msg->from, tm->tm_year-100, tm->tm_mon+1, tm->tm_mday, Msg->title); + +#ifdef WIN32 + if (pRunEventProgram) + pRunEventProgram("MailNewMsg.exe", msg); +#else + { + char prog[256]; + sprintf(prog, "%s/%s", BPQDirectory, "MailNewMsg"); + RunEventProgram(prog, msg); + } +#endif + } +} + + + diff --git a/BPQMail.c b/BPQMail.c index bd37641..a4015b1 100644 --- a/BPQMail.c +++ b/BPQMail.c @@ -1123,8 +1123,9 @@ // Add FBB reject.sys style filters (3) // Improve Webmail on 64 bit builds // Fix setting status '$' on Bulls sent via WebMail (22) - - +// Implement New Message and Message Read Events (23) +// Start adding json api (25) +// Fix reading nested directories when loading Standard Templates and other template bugs (25) #include "bpqmail.h" #include "winstdint.h" diff --git a/BPQMail.vcproj b/BPQMail.vcproj index 3c7ef20..81a5df9 100644 --- a/BPQMail.vcproj +++ b/BPQMail.vcproj @@ -316,6 +316,10 @@ RelativePath="..\CommonSource\LzmaLib.c" > + + diff --git a/BPQMail.vcproj.DESKTOP-TGEL8RC.John.user b/BPQMail.vcproj.DESKTOP-TGEL8RC.John.user new file mode 100644 index 0000000..40182c4 --- /dev/null +++ b/BPQMail.vcproj.DESKTOP-TGEL8RC.John.user @@ -0,0 +1,65 @@ + + + + + + + + + + + diff --git a/BPQWinAPP.vcproj.DESKTOP-TGEL8RC.John.user b/BPQWinAPP.vcproj.DESKTOP-TGEL8RC.John.user new file mode 100644 index 0000000..40182c4 --- /dev/null +++ b/BPQWinAPP.vcproj.DESKTOP-TGEL8RC.John.user @@ -0,0 +1,65 @@ + + + + + + + + + + + diff --git a/BPQWinAPP.vcproj.LAPTOP-Q6S4RP5Q.johnw.user b/BPQWinAPP.vcproj.LAPTOP-Q6S4RP5Q.johnw.user new file mode 100644 index 0000000..0cd9a72 --- /dev/null +++ b/BPQWinAPP.vcproj.LAPTOP-Q6S4RP5Q.johnw.user @@ -0,0 +1,65 @@ + + + + + + + + + + + diff --git a/Bpq32.c b/Bpq32.c index f2c5451..e5868dd 100644 --- a/Bpq32.c +++ b/Bpq32.c @@ -1203,6 +1203,9 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses // Improve restart of WinRPR TNC on remote host (21) // Fix some Rigcontrol issues with empty timebands (22) // Fix 64 bit bug in processing INP3 Messages (22) +// First pass at api (24) +// Send OK in response to Rigcontrol CMD (24); + #define CKernel @@ -2065,7 +2068,7 @@ VOID TimerProcX() GetWindowRect(FrameWnd, &FRect); - SaveWindowPos(64); // Rigcontrol + SaveWindowPos(70); // Rigcontrol for (i=0;iPORTCONTROL.PORTPOINTER; } - SaveWindowPos(40); // Rigcontrol + SaveWindowPos(70); // Rigcontrol if (hIPResWnd) diff --git a/CBPQ32.vcproj b/CBPQ32.vcproj index c1c95a2..0648ae6 100644 --- a/CBPQ32.vcproj +++ b/CBPQ32.vcproj @@ -438,6 +438,10 @@ RelativePath="..\CommonSource\MULTIPSK.c" > + + diff --git a/CBPQ32.vcproj.DESKTOP-TGEL8RC.John-notpi4-64.user b/CBPQ32.vcproj.DESKTOP-TGEL8RC.John-notpi4-64.user new file mode 100644 index 0000000..40b9267 --- /dev/null +++ b/CBPQ32.vcproj.DESKTOP-TGEL8RC.John-notpi4-64.user @@ -0,0 +1,65 @@ + + + + + + + + + + + diff --git a/CBPQ32.vcproj.DESKTOP-TGEL8RC.John.user b/CBPQ32.vcproj.DESKTOP-TGEL8RC.John.user new file mode 100644 index 0000000..40b9267 --- /dev/null +++ b/CBPQ32.vcproj.DESKTOP-TGEL8RC.John.user @@ -0,0 +1,65 @@ + + + + + + + + + + + diff --git a/CBPQ32.vcproj.LAPTOP-Q6S4RP5Q.johnw-notpi4-64.user b/CBPQ32.vcproj.LAPTOP-Q6S4RP5Q.johnw-notpi4-64.user new file mode 100644 index 0000000..ddedde2 --- /dev/null +++ b/CBPQ32.vcproj.LAPTOP-Q6S4RP5Q.johnw-notpi4-64.user @@ -0,0 +1,65 @@ + + + + + + + + + + + diff --git a/CBPQ32.vcproj.LAPTOP-Q6S4RP5Q.johnw.user b/CBPQ32.vcproj.LAPTOP-Q6S4RP5Q.johnw.user new file mode 100644 index 0000000..ddedde2 --- /dev/null +++ b/CBPQ32.vcproj.LAPTOP-Q6S4RP5Q.johnw.user @@ -0,0 +1,65 @@ + + + + + + + + + + + diff --git a/CHeaders.h b/CHeaders.h index 0d6886e..caf288b 100644 --- a/CHeaders.h +++ b/CHeaders.h @@ -406,7 +406,7 @@ extern BOOL CloseAllNeeded; extern int CloseOnError; extern char * PortConfig[70]; -extern struct TNCINFO * TNCInfo[70]; // Records are Malloc'd +extern struct TNCINFO * TNCInfo[71]; // Records are Malloc'd #define MaxBPQPortNo 63 // Port 64 reserved for BBS Mon #define MAXBPQPORTS 63 diff --git a/ChatHTMLConfig.c b/ChatHTMLConfig.c index b4d90b6..c4071cf 100644 --- a/ChatHTMLConfig.c +++ b/ChatHTMLConfig.c @@ -67,6 +67,7 @@ extern int MaxChatStreams; extern char Position[81]; extern char PopupText[251]; extern int PopupMode; +extern int reportChatEvents; #include "httpconnectioninfo.h" @@ -323,6 +324,8 @@ VOID SaveChatInfo(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Rep if (chatPaclen < 60) chatPaclen = 60; + GetCheckBox(input, "Events=", &reportChatEvents); + GetParam(input, "nodes=", Nodes); ptr1 = Nodes; @@ -508,7 +511,9 @@ scan: Len = sprintf(Reply, ChatConfigTemplate, OurNode, Key, Key, Key, - ChatApplNum, MaxChatStreams, Nodes, chatPaclen, Position, + ChatApplNum, MaxChatStreams, + (reportChatEvents) ? CHKD : UNC, + Nodes, chatPaclen, Position, (PopupMode) ? UNC : CHKD, (PopupMode) ? CHKD : UNC, Text, ptr2); diff --git a/CommonCode.c b/CommonCode.c index d28cefa..31e4ebc 100644 --- a/CommonCode.c +++ b/CommonCode.c @@ -49,7 +49,7 @@ extern struct CONFIGTABLE xxcfg; #endif -struct TNCINFO * TNCInfo[70]; // Records are Malloc'd +struct TNCINFO * TNCInfo[71]; // Records are Malloc'd extern int ReportTimer; @@ -3516,8 +3516,6 @@ int __sync_lock_test_and_set(int * ptr, int val) #endif // __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ #endif // MACBPQ - - void GetSemaphore(struct SEM * Semaphore, int ID) { // @@ -5232,7 +5230,7 @@ void SendDataToPktMap(char *Msg) // TCP - Mode = Modenames[TNC->Hardware]; + Mode = Modenames[TNC->Hardware - 1]; if (TNC->CONNECTED) Active = 1; diff --git a/FormatHTML.cpp b/FormatHTML.cpp index f27498c..88e306e 100644 --- a/FormatHTML.cpp +++ b/FormatHTML.cpp @@ -1,60 +1,60 @@ -// FormatHTML.cpp : Defines the entry point for the console application. -// -#include - -int main () { - FILE *fp, *fp2; - char str[256]; - char newstr[256]; - char * ptr, * inptr; - - /* opening file for reading */ - fp = fopen("D:/AtomProject/test.html" , "r"); - fp2 = fopen("D:/AtomProject/test.html.c" , "w"); - - if(fp == NULL) { - perror("Error opening file"); - return(-1); - } - - while(fgets (str, 256, fp) != NULL) - { - // Replace any " with \" and add " on front and \r\n" on end - - char c; - ptr = newstr; - inptr = str; - - c = *(inptr++); - - *(ptr++) = '"'; - - while (c && c != 10) - { - if (c == '"') - *(ptr++) = '\\'; - - *(ptr++) = c; - - c = *(inptr++); - } - - - *(ptr++) = '\\'; - *(ptr++) = 'r'; - *(ptr++) = '\\'; - *(ptr++) = 'n'; - *(ptr++) = '"'; - *(ptr++) = 10; - *(ptr++) = 0; - - puts(newstr); - fputs(newstr, fp2); - - } - - fclose(fp); - fclose(fp2); - - return(0); +// FormatHTML.cpp : Defines the entry point for the console application. +// +#include + +int main () { + FILE *fp, *fp2; + char str[256]; + char newstr[256]; + char * ptr, * inptr; + + /* opening file for reading */ + fp = fopen("D:/AtomProject/test.html" , "r"); + fp2 = fopen("D:/AtomProject/test.html.c" , "w"); + + if(fp == NULL) { + perror("Error opening file"); + return(-1); + } + + while(fgets (str, 256, fp) != NULL) + { + // Replace any " with \" and add " on front and \r\n" on end + + char c; + ptr = newstr; + inptr = str; + + c = *(inptr++); + + *(ptr++) = '"'; + + while (c && c != 10) + { + if (c == '"') + *(ptr++) = '\\'; + + *(ptr++) = c; + + c = *(inptr++); + } + + + *(ptr++) = '\\'; + *(ptr++) = 'r'; + *(ptr++) = '\\'; + *(ptr++) = 'n'; + *(ptr++) = '"'; + *(ptr++) = 10; + *(ptr++) = 0; + + puts(newstr); + fputs(newstr, fp2); + + } + + fclose(fp); + fclose(fp2); + + return(0); } \ No newline at end of file diff --git a/FormatHTML.vcproj b/FormatHTML.vcproj index 95563d4..1c3dce1 100644 --- a/FormatHTML.vcproj +++ b/FormatHTML.vcproj @@ -1,219 +1,219 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/HTTPcode.c b/HTTPcode.c index 30cf2bd..049fce3 100644 --- a/HTTPcode.c +++ b/HTTPcode.c @@ -69,6 +69,7 @@ int GetAPRSIcon(unsigned char * _REPLYBUFFER, char * NodeURL); char * GetStandardPage(char * FN, int * Len); BOOL SHA1PasswordHash(char * String, char * Hash); char * byte_base64_encode(char *str, int len); +int APIProcessHTTPMessage(char * response, char * Method, char * URL, char * request, BOOL LOCAL, BOOL COOKIE); extern struct ROUTE * NEIGHBOURS; extern int ROUTE_LEN; @@ -1593,7 +1594,7 @@ int InnerProcessHTTPMessage(struct ConnectionInfo * conn) char * Compressed = 0; char * HostPtr = 0; - char * Context, * Method, * NodeURL, * Key; + char * Context, * Method, * NodeURL = 0, * Key; char _REPLYBUFFER[250000]; char Reply[250000]; @@ -1631,7 +1632,7 @@ int InnerProcessHTTPMessage(struct ConnectionInfo * conn) char Encoding[] = "Content-Encoding: deflate\r\n"; -#ifdef WIN32 +#ifdef WIN32xx struct _EXCEPTION_POINTERS exinfo; strcpy(EXCEPTMSG, "ProcessHTTPMessage"); @@ -1772,6 +1773,43 @@ int InnerProcessHTTPMessage(struct ConnectionInfo * conn) strlop(Mycall, ' '); + // Look for API messages + + if (_memicmp(Context, "/api/", 5) == 0 || _stricmp(Context, "/api") == 0) + { + char * Compressed; + ReplyLen = APIProcessHTTPMessage(_REPLYBUFFER, Method, Context, MsgPtr, LOCAL, COOKIE); + + if (memcmp(_REPLYBUFFER, "HTTP", 4) == 0) + { + // Full Message - just send it + + sendandcheck(sock, _REPLYBUFFER, ReplyLen); + + return 0; + } + + if (allowDeflate) + Compressed = Compressit(_REPLYBUFFER, ReplyLen, &ReplyLen); + else + Compressed = _REPLYBUFFER; + + HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\n" + "Content-Length: %d\r\n" + "Content-Type: application/json\r\n" + "Connection: close\r\n" + "%s\r\n", ReplyLen, Encoding); + + sendandcheck(sock, Header, HeaderLen); + sendandcheck(sock, Compressed, ReplyLen); + + if (allowDeflate) + free (Compressed); + + return 0; + } + + // APRS process internally if (_memicmp(Context, "/APRS/", 6) == 0 || _stricmp(Context, "/APRS") == 0) @@ -1874,7 +1912,8 @@ int InnerProcessHTTPMessage(struct ConnectionInfo * conn) Session = FindSession(Key); - if (Session == NULL) + + if (Session == NULL && _memicmp(Context, "/Mail/API/", 10) != 0) { ReplyLen = sprintf(Reply, MailLostSession, Key); RLen = ReplyLen; @@ -2025,10 +2064,13 @@ Returnit: return 0; } - // Add tail + if (NodeURL && _memicmp(NodeURL, "/mail/api/", 10) != 0) + { + // Add tail - strcpy(&Reply[ReplyLen], Tail); - ReplyLen += strlen(Tail); + strcpy(&Reply[ReplyLen], Tail); + ReplyLen += strlen(Tail); + } // compress if allowed @@ -2037,7 +2079,15 @@ Returnit: else Compressed = Reply; - HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n%s\r\n", ReplyLen, Encoding); + if (NodeURL && _memicmp(NodeURL, "/mail/api/", 10) == 0) + HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\n" + "Content-Length: %d\r\n" + "Content-Type: application/json\r\n" + "Connection: close\r\n" + "%s\r\n", ReplyLen, Encoding); + else + HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n%s\r\n", ReplyLen, Encoding); + sendandcheck(sock, Header, HeaderLen); sendandcheck(sock, Compressed, ReplyLen); @@ -3889,7 +3939,7 @@ SendResp: } return 0; -#ifdef WIN32 +#ifdef WIN32xx } #include "StdExcept.c" } diff --git a/HanksRT.c b/HanksRT.c index cfc6440..3a7d538 100644 --- a/HanksRT.c +++ b/HanksRT.c @@ -77,6 +77,8 @@ char PopupText[260] = ""; int PopupMode = 0; int chatPaclen = 236; +int reportChatEvents = 0; + char RtKnown[MAX_PATH] = "RTKnown.txt"; char RtUsr[MAX_PATH] = "STUsers.txt"; char RtUsrTemp[MAX_PATH] = "STUsers.tmp"; @@ -2079,6 +2081,18 @@ void text_tellu_Joined(USER * user) sprintf(buf, "%s%-6.6s : %s *** Joined Chat, Topic %s", Stamp, user->call, user->name, user->topic->name); + if (reportChatEvents) + { + +#ifdef WIN32 + if (pRunEventProgram) + pRunEventProgram("ChatNewUser.exe", user->call); +#else + sprintf(prog, "%s/%s", BPQDirectory, "ChatNewUser"); + RunEventProgram(prog, user->call); +#endif + } + // Send it to all connected users in the same topic. // Echo to originator if requested. @@ -2109,14 +2123,6 @@ void text_tellu_Joined(USER * user) nputc(circuit, 7); nputc(circuit, 13); - -#ifdef WIN32 - if (pRunEventProgram) - pRunEventProgram("ChatNewUser.exe", user->call); -#else - sprintf(prog, "%s/%s", BPQDirectory, "ChatNewUser"); - RunEventProgram(prog, user->call); -#endif } } // Tell one link circuit about a local user change of topic. @@ -4170,6 +4176,7 @@ BOOL GetChatConfig(char * ConfigName) ChatApplNum = GetIntValue(group, "ApplNum"); MaxChatStreams = GetIntValue(group, "MaxStreams"); + reportChatEvents = GetIntValue(group, "reportChatEvents"); chatPaclen = GetIntValue(group, "chatPaclen"); GetStringValue(group, "OtherChatNodes", OtherNodesList); GetStringValue(group, "ChatWelcomeMsg", ChatWelcomeMsg); @@ -4201,6 +4208,7 @@ VOID SaveChatConfigFile(char * ConfigName) SaveIntValue(group, "ApplNum", ChatApplNum); SaveIntValue(group, "MaxStreams", MaxChatStreams); + SaveIntValue(group, "reportChatEvents", reportChatEvents); SaveIntValue(group, "chatPaclen", chatPaclen); SaveStringValue(group, "OtherChatNodes", OtherNodesList); SaveStringValue(group, "ChatWelcomeMsg", ChatWelcomeMsg); diff --git a/MBLRoutines.c b/MBLRoutines.c index d116893..e7ae622 100644 --- a/MBLRoutines.c +++ b/MBLRoutines.c @@ -23,6 +23,9 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #include "bpqmail.h" +void SendMessageReadEvent(struct UserInfo * user, struct MsgInfo * Msg); + + VOID ProcessMBLLine(CIRCUIT * conn, struct UserInfo * user, UCHAR* Buffer, int len) { Buffer[len] = 0; @@ -86,6 +89,7 @@ VOID ProcessMBLLine(CIRCUIT * conn, struct UserInfo * user, UCHAR* Buffer, int l FBBputs(conn, ">\r"); Msg->status = 'Y'; // Mark as read SaveMessageDatabase(); + SendMessageReadEvent(user->Call, Msg); } else { diff --git a/MailNode.vcproj b/MailNode.vcproj index 4478265..a67f072 100644 --- a/MailNode.vcproj +++ b/MailNode.vcproj @@ -424,6 +424,10 @@ RelativePath="..\CommonSource\LzmaLib.c" > + + @@ -464,6 +468,10 @@ RelativePath="..\CommonSource\NNTPRoutines.c" > + + diff --git a/MailNode.vcproj.DESKTOP-TGEL8RC.John.user b/MailNode.vcproj.DESKTOP-TGEL8RC.John.user new file mode 100644 index 0000000..40182c4 --- /dev/null +++ b/MailNode.vcproj.DESKTOP-TGEL8RC.John.user @@ -0,0 +1,65 @@ + + + + + + + + + + + diff --git a/RigControl.c b/RigControl.c index 0e56d6e..b7e22d1 100644 --- a/RigControl.c +++ b/RigControl.c @@ -1142,7 +1142,6 @@ int Rig_CommandEx(struct RIGPORTINFO * PORT, struct RIGINFO * RIG, TRANSPORTENTR return FALSE; } - // Build a ScanEntry in the buffer FreqPtr = (struct ScanEntry *)buffptr->Data; @@ -1277,8 +1276,6 @@ int Rig_CommandEx(struct RIGPORTINFO * PORT, struct RIGINFO * RIG, TRANSPORTENTR } *(CmdPtr++) = 0xFD; - - *(CmdPtr) = 0; Len = (int)(CmdPtr - (char *)&buffptr[30]); @@ -1325,7 +1322,9 @@ int Rig_CommandEx(struct RIGPORTINFO * PORT, struct RIGINFO * RIG, TRANSPORTENTR FreqPtr[0].Cmd1Len = Len; // for ICOM C_Q_ADD(&RIG->BPQtoRADIO_Q, buffptr); - return TRUE; + + sprintf(Command, "Ok\r"); + return FALSE; } if (_memicmp(FreqString, "Chan", 4) == 0) @@ -2203,7 +2202,7 @@ DllExport BOOL APIENTRY Rig_Init() memset(&RIGTNC, 0, sizeof(struct TNCINFO)); - TNCInfo[40] = TNC; + TNCInfo[70] = TNC; // Get config info @@ -2229,7 +2228,7 @@ DllExport BOOL APIENTRY Rig_Init() #ifndef LINBPQ - TNC->Port = 40; + TNC->Port = 70; CreatePactorWindow(TNC, "RIGCONTROL", "RigControl", 10, PacWndProc, 550, NeedRig * 20 + 60, NULL); hDlg = TNC->hDlg; diff --git a/TelnetV6.c b/TelnetV6.c index ad4c70b..efec041 100644 --- a/TelnetV6.c +++ b/TelnetV6.c @@ -534,6 +534,9 @@ int ProcessLine(char * buf, int Port) else if (_stricmp(param,"HTTPPORT") == 0) TCP->HTTPPort = atoi(value); + else if (_stricmp(param,"APIPORT") == 0) + TCP->APIPort = atoi(value); + else if (_stricmp(param,"SYNCPORT") == 0) TCP->SyncPort = atoi(value); @@ -1646,6 +1649,9 @@ BOOL OpenSockets(struct TNCINFO * TNC) if (TCP->HTTPPort) TCP->HTTPsock = OpenSocket4(TNC, TCP->HTTPPort); + if (TCP->APIPort) + TCP->APIsock = OpenSocket4(TNC, TCP->APIPort); + if (TCP->SyncPort) TCP->Syncsock = OpenSocket4(TNC, TCP->SyncPort); @@ -1755,10 +1761,12 @@ BOOL OpenSockets6(struct TNCINFO * TNC) if (TCP->RelayPort) TCP->Relaysock6 = OpenSocket6(TNC, TCP->RelayPort); - if (TCP->HTTPPort) TCP->HTTPsock6 = OpenSocket6(TNC, TCP->HTTPPort); + if (TCP->APIPort) + TCP->APIsock6 = OpenSocket6(TNC, TCP->APIPort); + if (TCP->SyncPort) TCP->Syncsock6 = OpenSocket6(TNC, TCP->SyncPort); @@ -1818,6 +1826,14 @@ static VOID SetupListenSet(struct TNCINFO * TNC) if (sock > maxsock) maxsock = sock; } + + sock = TCP->APIsock; + if (sock) + { + FD_SET(sock, readfd); + if (sock > maxsock) + maxsock = sock; + } sock = TCP->Syncsock; if (sock) @@ -1886,6 +1902,14 @@ static VOID SetupListenSet(struct TNCINFO * TNC) maxsock = sock; } + sock = TCP->APIsock6; + if (sock) + { + FD_SET(sock, readfd); + if (sock > maxsock) + maxsock = sock; + } + sock = TCP->DRATSsock6; if (sock) @@ -3192,6 +3216,7 @@ int Socket_Accept(struct TNCINFO * TNC, SOCKET SocketId, int Port) TNC->Streams[n].FramesQueued = 0; sockptr->HTTPMode = FALSE; + sockptr->APIMode = FALSE; sockptr->SyncMode = FALSE; sockptr->DRATSMode = FALSE; sockptr->FBBMode = FALSE; @@ -3208,6 +3233,12 @@ int Socket_Accept(struct TNCINFO * TNC, SOCKET SocketId, int Port) if (SocketId == TCP->HTTPsock || SocketId == TCP->HTTPsock6) sockptr->HTTPMode = TRUE; + + if (SocketId == TCP->APIsock || SocketId == TCP->APIsock6) + { + sockptr->HTTPMode = TRUE; // API is a type of HTTP socket + sockptr->APIMode = TRUE; + } else if (SocketId == TCP->Syncsock || SocketId == TCP->Syncsock6) sockptr->SyncMode = TRUE; else if (SocketId == TCP->DRATSsock || SocketId == TCP->DRATSsock6) diff --git a/Versions.h b/Versions.h index 56bfe73..f880e42 100644 --- a/Versions.h +++ b/Versions.h @@ -10,14 +10,14 @@ #endif -#define KVers 6,0,24,22 -#define KVerstring "6.0.24.22\0" +#define KVers 6,0,24,25 +#define KVerstring "6.0.24.25\0" #ifdef CKernel #define Vers KVers #define Verstring KVerstring -#define Datestring "November 2023" +#define Datestring "December 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/WebMail.c b/WebMail.c index f626975..157938b 100644 --- a/WebMail.c +++ b/WebMail.c @@ -76,6 +76,8 @@ VOID SendTemplateSelectScreen(struct HTTPConnectionInfo * Session, char *URLPara BOOL isAMPRMsg(char * Addr); char * doXMLTransparency(char * string); Dll BOOL APIENTRY APISendAPRSMessage(char * Text, char * ToCall); +void SendMessageReadEvent(char * Call, struct MsgInfo * Msg); +void SendNewMessageEvent(char * call, struct MsgInfo * Msg); extern char NodeTail[]; extern char BBSName[10]; @@ -719,26 +721,27 @@ VOID ProcessFormDir(char * FormSet, char * DirName, struct HtmlFormDir *** xxx, { if (entry->d_type == DT_DIR) { - if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) + char Dir[MAX_PATH]; + + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue; - Debugprintf("Recurse %s/%s/%s", FormSet, DirName, entry->d_name); + // Recurse in subdir + + sprintf(Dir, "%s/%s", DirName, entry->d_name); + + ProcessFormDir(FormSet, Dir, &FormDir->Dirs, &FormDir->DirCount); continue; - } - // see if initial html -// if (stristr(entry->d_name, "initial.html")) - { - // Add to list + // Add to list - Form = zalloc(sizeof (struct HtmlForm)); + Form = zalloc(sizeof (struct HtmlForm)); - Form->FileName = _strdup(entry->d_name); + Form->FileName = _strdup(entry->d_name); - FormDir->Forms=realloc(FormDir->Forms, (FormDir->FormCount + 1) * sizeof(void *)); - FormDir->Forms[FormDir->FormCount++] = Form; - } + FormDir->Forms=realloc(FormDir->Forms, (FormDir->FormCount + 1) * sizeof(void *)); + FormDir->Forms[FormDir->FormCount++] = Form; } closedir(dir); #endif @@ -808,22 +811,23 @@ int GetHTMLFormSet(char * FormSet) if (!(dir = opendir(name))) { Debugprintf("cant open forms dir %s %d %d", name, errno, dir); - return 0; } - - while ((entry = readdir(dir)) != NULL) + else { - if (entry->d_type == DT_DIR) + while ((entry = readdir(dir)) != NULL) { - if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) - continue; + if (entry->d_type == DT_DIR) + { + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) + continue; - // Add to Directory List + // Add to Directory List - ProcessFormDir(FormSet, entry->d_name, &HtmlFormDirs, &FormDirCount); - } - } - closedir(dir); + ProcessFormDir(FormSet, entry->d_name, &HtmlFormDirs, &FormDirCount); + } + } + closedir(dir); + } #endif // List for testing @@ -1122,7 +1126,7 @@ int ViewWebMailMessage(struct HTTPConnectionInfo * Session, char * Reply, int Nu Msg->status = 'Y'; Msg->datechanged=time(NULL); SaveMessageDatabase(); - + SendMessageReadEvent(Session->Callsign, Msg); } } } @@ -1190,6 +1194,7 @@ int ViewWebMailMessage(struct HTTPConnectionInfo * Session, char * Reply, int Nu Msg->status = 'Y'; Msg->datechanged=time(NULL); SaveMessageDatabase(); + SendMessageReadEvent(Session->Callsign, Msg); } } } @@ -1303,6 +1308,7 @@ int ViewWebMailMessage(struct HTTPConnectionInfo * Session, char * Reply, int Nu Msg->status = 'Y'; Msg->datechanged=time(NULL); SaveMessageDatabase(); + SendMessageReadEvent(Session->Callsign, Msg); } } } @@ -2776,11 +2782,16 @@ VOID SaveNewMessage(struct HTTPConnectionInfo * Session, char * MsgPtr, char * R if (Msg->status != 'H' && Msg->type == 'B' && memcmp(Msg->fbbs, zeros, NBMASK) != 0) Msg->status = '$'; // Has forwarding + if (EnableUI) SendMsgUI(Msg); user = LookupCall(Msg->to); + // If Event Notifications enabled report a new message event + + SendNewMessageEvent(user->Call, Msg); + if (user && (user->flags & F_APRSMFOR)) { char APRS[128]; @@ -2838,13 +2849,26 @@ char * GetHTMLViewerTemplate(char * FN) { for (l = 0; l < Dir->DirCount; l++) { - for (k = 0; k < Dir->Dirs[l]->FormCount; k++) + struct HtmlFormDir * SDir = Dir->Dirs[l]; + + if (SDir->DirCount) { - if (strcmp(FN, Dir->Dirs[l]->Forms[k]->FileName) == 0) + struct HtmlFormDir * SSDir = SDir->Dirs[0]; + int x = 1; + } + + for (k = 0; k < SDir->FormCount; k++) + { + if (_stricmp(FN, SDir->Forms[k]->FileName) == 0) { - return CheckFile(Dir, Dir->Dirs[l]->Forms[k]->FileName); + return CheckFile(SDir, SDir->Forms[k]->FileName); } } + if (SDir->DirCount) + { + struct HtmlFormDir * SSDir = SDir->Dirs[0]; + int x = 1; + } } } } @@ -3224,7 +3248,7 @@ BOOL ParseXML(WebMailInfo * WebMail, char * XMLOrig) *ptr2++ = 0; - ptr3 = strchr(ptr2, '<'); // end of value string + ptr3 = strstr(ptr2, " + + + + + + + + + + diff --git a/WinRPRHelper.vcproj.DESKTOP-TGEL8RC.John.user b/WinRPRHelper.vcproj.DESKTOP-TGEL8RC.John.user new file mode 100644 index 0000000..40182c4 --- /dev/null +++ b/WinRPRHelper.vcproj.DESKTOP-TGEL8RC.John.user @@ -0,0 +1,65 @@ + + + + + + + + + + + diff --git a/WinmorControl.vcproj.DESKTOP-TGEL8RC.John.user b/WinmorControl.vcproj.DESKTOP-TGEL8RC.John.user new file mode 100644 index 0000000..40182c4 --- /dev/null +++ b/WinmorControl.vcproj.DESKTOP-TGEL8RC.John.user @@ -0,0 +1,65 @@ + + + + + + + + + + + diff --git a/WinmorControl.vcproj.LAPTOP-Q6S4RP5Q.johnw.user b/WinmorControl.vcproj.LAPTOP-Q6S4RP5Q.johnw.user new file mode 100644 index 0000000..0cd9a72 --- /dev/null +++ b/WinmorControl.vcproj.LAPTOP-Q6S4RP5Q.johnw.user @@ -0,0 +1,65 @@ + + + + + + + + + + + diff --git a/bbshtmlconfig.c~ b/bbshtmlconfig.c~ new file mode 100644 index 0000000..33c1048 --- /dev/null +++ b/bbshtmlconfig.c~ @@ -0,0 +1,3161 @@ +/* +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 +*/ + +#define _CRT_SECURE_NO_DEPRECATE + +#include "CHeaders.h" +#include "bpqmail.h" + +#ifdef WIN32 +//#include "C:\Program Files (x86)\GnuWin32\include\iconv.h" +#else +#include +#endif + +extern char NodeTail[]; +extern char BBSName[10]; + +extern char LTFROMString[2048]; +extern char LTTOString[2048]; +extern char LTATString[2048]; + +//static UCHAR BPQDirectory[260]; + +extern ConnectionInfo Connections[]; +extern int NumberofStreams; +extern time_t MaintClock; // Time to run housekeeping + +extern int SMTPMsgs; + +extern int ChatApplNum; +extern int MaxChatStreams; + +extern char Position[81]; +extern char PopupText[251]; +extern int PopupMode; +extern int reportMailEvents; + +#define MaxCMS 10 // Numbr of addresses we can keep - currently 4 are used. + +struct UserInfo * BBSLIST[NBBBS + 1]; + +int MaxBBS = 0; + +#define MAIL +#include "httpconnectioninfo.h" + +struct TCPINFO * TCP; + +VOID ProcessMailSignon(struct TCPINFO * TCP, char * MsgPtr, char * Appl, char * Reply, int * RLen); +static struct HTTPConnectionInfo * FindSession(char * Key); +VOID ProcessUserUpdate(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Rest); +VOID ProcessMsgFwdUpdate(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Rest); +VOID SendConfigPage(char * Reply, int * ReplyLen, char * Key); +VOID ProcessConfUpdate(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Rest); +VOID ProcessUIUpdate(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Rest); +VOID SendUserSelectPage(char * Reply, int * ReplyLen, char * Key); +VOID SendFWDSelectPage(char * Reply, int * ReplyLen, char * Key); +int EncryptPass(char * Pass, char * Encrypt); +VOID ProcessFWDUpdate(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Rest); +VOID SendStatusPage(char * Reply, int * ReplyLen, char * Key); +VOID SendUIPage(char * Reply, int * ReplyLen, char * Key); +VOID GetParam(char * input, char * key, char * value); +BOOL GetConfig(char * ConfigName); +VOID ProcessDisUser(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Rest); +int APIENTRY SessionControl(int stream, int command, int param); +int SendMessageDetails(struct MsgInfo * Msg, char * Reply, char * Key); +VOID ProcessMsgUpdate(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Rest); +VOID ProcessMsgAction(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Rest); +int APIENTRY GetNumberofPorts(); +int APIENTRY GetPortNumber(int portslot); +UCHAR * APIENTRY GetPortDescription(int portslot, char * Desc); +struct PORTCONTROL * APIENTRY GetPortTableEntryFromSlot(int portslot); +VOID SendHouseKeeping(char * Reply, int * ReplyLen, char * Key); +VOID SendWelcomePage(char * Reply, int * ReplyLen, char * Key); +VOID SaveWelcome(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Key); +VOID GetMallocedParam(char * input, char * key, char ** value); +VOID SaveMessageText(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Rest); +VOID SaveHousekeeping(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Key); +VOID SaveWP(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Key); +int SendWPDetails(WPRec * WP, char * Reply, char * Key); +int SendUserDetails(struct HTTPConnectionInfo * Session, char * Reply, char * Key); +int SetupNodeMenu(char * Buff); +VOID SendFwdSelectPage(char * Reply, int * ReplyLen, char * Key); +VOID SendFwdDetails(struct UserInfo * User, char * Reply, int * ReplyLen, char * Key); +VOID SetMultiStringValue(char ** values, char * Multi); +VOID SendFwdMainPage(char * Reply, int * ReplyLen, char * Key); +VOID SaveFwdCommon(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Rest); +VOID SaveFwdDetails(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Rest); +char ** SeparateMultiString(char * MultiString, BOOL NoToUpper); +VOID TidyPrompts(); +char * GetTemplateFromFile(int Version, char * FN); +VOID FormatTime(char * Time, time_t cTime); +struct MsgInfo * GetMsgFromNumber(int msgno); +BOOL CheckUserMsg(struct MsgInfo * Msg, char * Call, BOOL SYSOP); +BOOL OkToKillMessage(BOOL SYSOP, char * Call, struct MsgInfo * Msg); +int MulticastStatusHTML(char * Reply); +void ProcessWebMailMessage(struct HTTPConnectionInfo * Session, char * Key, BOOL LOCAL, char * Method, char * NodeURL, char * input, char * Reply, int * RLen, int InputLen); +int SendWebMailHeader(char * Reply, char * Key, struct HTTPConnectionInfo * Session); +struct UserInfo * FindBBS(char * Name); +void ReleaseWebMailStruct(WebMailInfo * WebMail); +VOID TidyWelcomeMsg(char ** pPrompt); + +char UNC[] = ""; +char CHKD[] = "checked=checked "; +char sel[] = "selected"; + +char Sent[] = "#98FFA0"; +char ToSend[] = "#FFFF00"; +char NotThisOne[] = "#FFFFFF"; + +static char PassError[] = "

Sorry, User or Password is invalid - please try again

"; + +static char BusyError[] = "

Sorry, No sessions available - please try later

"; + +extern char WebMailSignon[]; + +char MailSignon[] = "BPQ32 Mail Server Access" + "

BPQ32 Mail Server %s Access

" + "

Please enter Callsign and Password to access the BBS

" + "
" + "" + "" + "
User
Password
" + "

"; + + +char MailPage[] = "%s's BBS Web Server" + "" + "" + "

BPQ32 BBS %s

" + "

" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "
StatusConfigurationUsersMessagesForwardingWelcome Msgs & PromptsHousekeepingWP UpdateNode Menu
"; + +char RefreshMainPage[] = "" + "" + "" + "%s's BBS Web Server" + "

BPQ32 BBS %s

" + "

" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "
StatusConfigurationUsersMessagesForwardingWelcome Msgs & PromptsHousekeepingWP UpdateNode Menu
"; + +char StatusPage [] = + +"

" +"
User     Callsign   Stream Queue
" +"


"; + +char StatusTail[] = +"Msgs      
" +"Sysop Msgs
" +"Held Msgs 
" +"SMTP Msgs 
"; + + +char UIHddr [] = "
Mailfor Header
" +"           " +"    (use \\r to insert newline in message)

" +"Enable Port           " +"             Path           " +"                   Send: MailFor Headers Empty Mailfor

"; + +char UILine[] = " %s " +" " +"    " +"       
"; + +char UITail[] = "

" +"
"; + +char FWDSelectHddr[] = + "
" + "Max Size to Send   
" + "Max Size to Receive
" + "Warn if no route for P or T
" + "Use Local Time              " + "

" + "Aliases                   Select BBS
" + "  
         " + " 
"; + +char UserSelectHddr[] = + "
" + "Please Select User



" + "" + "
" + " " + "
"; + +char UserUpdateHddr[] = + "

Update User %s

" + "
"; + +char UserUpdateLine[] = ""; + +// +//
+ + +char FWDUpdate[] = +"

Update Forwarding for BBS %s

" +"    " +"TO            " +"AT          " +"TIMES         Connect Script
" +"" +" " +" " +"
" +"" +"

" +"Enable Forwarding  Interval" +"(Secs) Request Reverse" +" Interval (Secs)
" +"Send new messages without waiting for poll timer
" +"BBS HA FBB Max Block
" +"Send Personal Mail Only  " +"Allow Binary     Use B1 " +"Protocol   Use B2 Protocol

" +" " +"

"; + +static char MailDetailPage[] = +"" +"MsgEdit

Message %d

" +"
" +"From  Sent   " +"       " +"Type     
" +"To    " +" Received      " +"Status   
" +"BID   Last Changed  " +"Size 

" +"%s" // Email from Line +" VIA 
" +"Title 

" +" " +" " +"" +"" +//" " +" " +"

" +"Green = Sent, Yellow = Queued" +""; + +char MailDetailTail[] = "
"; + +char Welcome[] = "
" +"Normal User Welcome
" +"
" +"New User Welcome
" +"
" +"Expert User Welcome
" +"
" +"Normal User Prompt
" +"
" +"New User Prompt
" +"
" +"Expert User Prompt
" +"
" +"Signoff
" +"

" +"$U:Callsign of the user  $I:First name of the user $X:Messages for user $x:Unread messages
" +"$L:Number of the latest message $N:Number of active messages. $Z:Last message read by user

" +" "; + +static char MsgEditPage[] = "" +"" +"
" +"

" +"
"; + +static char WPDetail[] = "
" +"
" + +"" +"" +"" +"" +"" +"" +"" +"" +"" +"" +"" +"" +"
Call
Name
Home BBS 1
Home BBS 2
QTH 1
QTH 2
ZIP 1
ZIP 2
Last Seen
Last Modified
Type
Changed
Seen
" +"
" +" " +"
"; + + +static char LostSession[] = "" +"
" +"Sorry, Session had been lost

    " +"
"; + + +char * MsgEditTemplate = NULL; +char * HousekeepingTemplate = NULL; +char * ConfigTemplate = NULL; +char * WPTemplate = NULL; +char * UserListTemplate = NULL; +char * UserDetailTemplate = NULL; +char * FwdTemplate = NULL; +char * FwdDetailTemplate = NULL; +char * WebMailTemplate = NULL; +char * WebMailMsgTemplate = NULL; +char * jsTemplate = NULL; + + +#ifdef LINBPQ +UCHAR * GetBPQDirectory(); +#endif + +static int compare(const void *arg1, const void *arg2) +{ + // Compare Calls. Fortunately call is at start of stuct + + return _stricmp(*(char**)arg1 , *(char**)arg2); +} + +int SendHeader(char * Reply, char * Key) +{ + return sprintf(Reply, MailPage, BBSName, BBSName, Key, Key, Key, Key, Key, Key, Key, Key); +} + + +void ConvertTitletoUTF8(WebMailInfo * WebMail, char * Title, char * UTF8Title, int Len) +{ + if (WebIsUTF8(Title, (int)strlen(Title)) == FALSE) + { + // With Windows it is simple - convert using current codepage + // I think the only reliable way is to convert to unicode and back + + int origlen = (int)strlen(Title) + 1; +#ifdef WIN32 + WCHAR BufferW[128]; + int wlen; + int len = origlen; + + wlen = MultiByteToWideChar(CP_ACP, 0, Title, len, BufferW, origlen * 2); + len = WideCharToMultiByte(CP_UTF8, 0, BufferW, wlen, UTF8Title, origlen * 2, NULL, NULL); +#else + size_t left = Len - 1; + size_t len = origlen; + + iconv_t * icu = WebMail->iconv_toUTF8; + + if (WebMail->iconv_toUTF8 == NULL) + icu = WebMail->iconv_toUTF8 = iconv_open("UTF-8//IGNORE", "CP1252"); + + if (icu == (iconv_t)-1) + { + strcpy(UTF8Title, Title); + WebMail->iconv_toUTF8 = NULL; + return; + } + + char * orig = UTF8Title; + + iconv(icu, NULL, NULL, NULL, NULL); // Reset State Machine + iconv(icu, &Title, &len, (char ** __restrict__)&UTF8Title, &left); + +#endif + } + else + strcpy(UTF8Title, Title); +} + +BOOL GotFirstMessage = 0; + +void ProcessMailHTTPMessage(struct HTTPConnectionInfo * Session, char * Method, char * URL, char * input, char * Reply, int * RLen, int InputLen) +{ + char * Context = 0, * NodeURL; + int ReplyLen; + BOOL LOCAL = FALSE; + char * Key; + char Appl = 'M'; + + if (URL[0] == 0 || Method == NULL) + return; + + if (strstr(input, "Host: 127.0.0.1")) + LOCAL = TRUE; + + if (Session->TNC == (void *)1) // Re-using an address as a flag + LOCAL = TRUE; + + NodeURL = strtok_s(URL, "?", &Context); + + Key = Session->Key; + + if (_memicmp(URL, "/WebMail", 8) == 0) + { + // Pass All Webmail messages to Webmail + + ProcessWebMailMessage(Session, Context, LOCAL, Method, NodeURL, input, Reply, RLen, InputLen); + return; + + } + + // There is a problem if Mail is reloaded without reloading the node + + if (GotFirstMessage == 0) + { + if (_stricmp(NodeURL, "/Mail/Header") == 0 || _stricmp(NodeURL, "/Mail/Lost") == 0) + { + *RLen = SendHeader(Reply, Session->Key); + } + else + { + *RLen = sprintf(Reply, "", Session->Key); + } + + GotFirstMessage = 1; + return; + } + + if (_memicmp(URL, "/Mail/API/", 10) == 0) + { + *RLen = APIProcessHTTPMessage(Reply, Method, URL, input, LOCAL, 0); + return; + } + + + if (strcmp(Method, "POST") == 0) + { + if (_stricmp(NodeURL, "/Mail/Header") == 0) + { + *RLen = SendHeader(Reply, Session->Key); + return; + } + + + if (_stricmp(NodeURL, "/Mail/Config") == 0) + { + NodeURL[strlen(NodeURL)] = ' '; // Undo strtok + ProcessConfUpdate(Session, input, Reply, RLen, Key); + return ; + } + + if (_stricmp(NodeURL, "/Mail/UI") == 0) + { + NodeURL[strlen(NodeURL)] = ' '; // Undo strtok + ProcessUIUpdate(Session, input, Reply, RLen, Key); + return ; + } + if (_stricmp(NodeURL, "/Mail/FwdCommon") == 0) + { + SaveFwdCommon(Session, input, Reply, RLen, Key); + return; + } + + if (_stricmp(NodeURL, "/Mail/DisSession") == 0) + { + ProcessDisUser(Session, input, Reply, RLen, Key); + return ; + } + + if (_stricmp(NodeURL, "/Mail/UserDetails") == 0) + { + char * param = strstr(input, "\r\n\r\n"); // End of headers + + if (param) + { + Session->User = LookupCall(param+4); + if (Session->User) + { + * RLen = SendUserDetails(Session, Reply, Key); + return; + } + } + } + + + if (_stricmp(NodeURL, "/Mail/UserSave") == 0) + { + ProcessUserUpdate(Session, input, Reply, RLen, Key); + return ; + } + + if (_stricmp(NodeURL, "/Mail/MsgDetails") == 0) + { + char * param = strstr(input, "\r\n\r\n"); // End of headers + + if (param) + { + int Msgno = atoi(param + 4); + struct MsgInfo * Msg = FindMessageByNumber(Msgno); + + Session->Msg = Msg; // Save current Message + + * RLen = SendMessageDetails(Msg, Reply, Key); + return; + } + } + + if (_stricmp(NodeURL, "/Mail/MsgSave") == 0) + { + ProcessMsgUpdate(Session, input, Reply, RLen, Key); + return ; + } + + if (_stricmp(NodeURL, "/Mail/EMSave") == 0) + { + // Save Message Text + + SaveMessageText(Session, input, Reply, RLen, Key); + return; + } + + if (_stricmp(NodeURL, "/Mail/MsgAction") == 0) + { + ProcessMsgAction(Session, input, Reply, RLen, Key); + return; + } + + if (_stricmp(NodeURL, "/Mail/MsgFwdUpdate") == 0) + { + ProcessMsgFwdUpdate(Session, input, Reply, RLen, Key); + return; + } + + if (_stricmp(NodeURL, "/Mail/Welcome") == 0) + { + SaveWelcome(Session, input, Reply, RLen, Key); + return; + } + if (_stricmp(NodeURL, "/Mail/HK") == 0) + { + SaveHousekeeping(Session, input, Reply, RLen, Key); + return; + } + if (_stricmp(NodeURL, "/Mail/WPDetails") == 0) + { + char * param = strstr(input, "\r\n\r\n"); // End of headers + + if (param) + { + WPRec * WP = LookupWP(param+4); + Session->WP = WP; // Save current Message + + * RLen = SendWPDetails(WP, Reply, Key); + return; + } + } + if (_stricmp(NodeURL, "/Mail/WPSave") == 0) + { + SaveWP(Session, input, Reply, RLen, Key); + return; + } + + if (_stricmp(NodeURL, "/Mail/MsgInfo.txt") == 0) + { + int n, len = 0; + char * FF = "", *FT = "", *FB = "", *FV = ""; + char * param, * ptr1, *ptr2; + struct MsgInfo * Msg; + char UCto[80]; + char UCfrom[80]; + char UCvia[80]; + char UCbid[80]; + + // Get filter string + + param = strstr(input, "\r\n\r\n"); // End of headers + + + if (param) + { + ptr1 = param + 4; + ptr2 = strchr(ptr1, '|'); + if (ptr2){*(ptr2++) = 0; FF = ptr1; ptr1 = ptr2;} + ptr2 = strchr(ptr1, '|');if (ptr2){*(ptr2++) = 0; FT = ptr1;ptr1 = ptr2;} + ptr2 = strchr(ptr1, '|');if (ptr2){*(ptr2++) = 0; FV = ptr1;ptr1 = ptr2;} + ptr2 = strchr(ptr1, '|');if (ptr2){*(ptr2++) = 0; FB = ptr1;ptr1 = ptr2;} + } + + if (FT[0]) + _strupr(FT); + if (FF[0]) + _strupr(FF); + if (FV[0]) + _strupr(FV); + if (FB[0]) + _strupr(FB); + + for (n = NumberofMessages; n >= 1; n--) + { + Msg = MsgHddrPtr[n]; + + strcpy(UCto, Msg->to); + strcpy(UCfrom, Msg->from); + strcpy(UCvia, Msg->via); + strcpy(UCbid, Msg->bid); + + _strupr(UCto); + _strupr(UCfrom); + _strupr(UCvia); + _strupr(UCbid); + + if ((!FT[0] || strstr(UCto, FT)) && + (!FF[0] || strstr(UCfrom, FF)) && + (!FB[0] || strstr(UCbid, FB)) && + (!FV[0] || strstr(UCvia, FV))) + { + len += sprintf(&Reply[len], "%d|", Msg->number); + } + } + *RLen = len; + return; + } + + if (_stricmp(NodeURL, "/Mail/UserList.txt") == 0) + { + SendUserSelectPage(Reply, RLen, Key); + return; + } + + if (_stricmp(NodeURL, "/Mail/FwdList.txt") == 0) + { + SendFwdSelectPage(Reply, RLen, Key); + return; + } + + if (_stricmp(NodeURL, "/Mail/FwdDetails") == 0) + { + char * param; + + param = strstr(input, "\r\n\r\n"); // End of headers + + if (param) + { + Session->User = LookupCall(param+4); + if (Session->User) + { + SendFwdDetails(Session->User, Reply, RLen, Key); + return; + } + } + } + + if (_stricmp(NodeURL, "/Mail/FWDSave") == 0) + { + SaveFwdDetails(Session, input, Reply, RLen, Key); + return ; + } + + // End of POST section + } + + if (strstr(NodeURL, "webscript.js")) + { + if (jsTemplate) + free(jsTemplate); + + jsTemplate = GetTemplateFromFile(1, "webscript.js"); + + ReplyLen = sprintf(Reply, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\n" + "Cache-Control: max-age=900\r\nContent-Type: text/javascript\r\n\r\n%s", (int)strlen(jsTemplate), jsTemplate); + *RLen = ReplyLen; + return; + } + + + if (_stricmp(NodeURL, "/Mail/Header") == 0) + { + *RLen = SendHeader(Reply, Session->Key); + return; + } + + if (_stricmp(NodeURL, "/Mail/all.html") == 0) + { + *RLen = SendHeader(Reply, Session->Key); + return; + } + + if (_stricmp(NodeURL, "/Mail/Status") == 0 || + _stricmp(NodeURL, "/Mail/DisSession") == 0) // Sent as POST by refresh timer for some reason + { + SendStatusPage(Reply, RLen, Key); + return; + } + + if (_stricmp(NodeURL, "/Mail/Conf") == 0) + { + if (ConfigTemplate) + free(ConfigTemplate); + + ConfigTemplate = GetTemplateFromFile(7, "MainConfig.txt"); + + SendConfigPage(Reply, RLen, Key); + return; + } + + if (_stricmp(NodeURL, "/Mail/FWD") == 0) + { + if (FwdTemplate) + free(FwdTemplate); + + FwdTemplate = GetTemplateFromFile(4, "FwdPage.txt"); + + if (FwdDetailTemplate) + free(FwdDetailTemplate); + + FwdDetailTemplate = GetTemplateFromFile(3, "FwdDetail.txt"); + + SendFwdMainPage(Reply, RLen, Key); + return; + } + if (_stricmp(NodeURL, "/Mail/Wel") == 0) + { + SendWelcomePage(Reply, RLen, Key); + return; + } + + if (_stricmp(NodeURL, "/Mail/Users") == 0) + { + if (UserListTemplate) + free(UserListTemplate); + + UserListTemplate = GetTemplateFromFile(4, "UserPage.txt"); + + if (UserDetailTemplate) + free(UserDetailTemplate); + + UserDetailTemplate = GetTemplateFromFile(4, "UserDetail.txt"); + + *RLen = sprintf(Reply, UserListTemplate, Key, Key, BBSName, + Key, Key, Key, Key, Key, Key, Key, Key); + + return; + } + + if (_stricmp(NodeURL, "/Mail/SaveMessage") == 0) + { + struct MsgInfo * Msg = Session->Msg; + char * MailBuffer; + + int Files = 0; + int BodyLen; + char * ptr; + int WriteLen=0; + char Hddr[1000]; + char FullTo[100]; + + MailBuffer = ReadMessageFile(Msg->number); + BodyLen = Msg->length; + + ptr = MailBuffer; + + if (_stricmp(Msg->to, "RMS") == 0) + sprintf(FullTo, "RMS:%s", Msg->via); + else + if (Msg->to[0] == 0) + sprintf(FullTo, "smtp:%s", Msg->via); + else + strcpy(FullTo, Msg->to); + + sprintf(Hddr, "From: %s%s\r\nTo: %s\r\nType/Status: %c%c\r\nDate/Time: %s\r\nBid: %s\r\nTitle: %s\r\n\r\n", + Msg->from, Msg->emailfrom, FullTo, Msg->type, Msg->status, FormatDateAndTime((time_t)Msg->datecreated, FALSE), Msg->bid, Msg->title); + + if (Msg->B2Flags & B2Msg) + { + // Remove B2 Headers (up to the File: Line) + + char * bptr; + bptr = strstr(ptr, "Body:"); + if (bptr) + { + BodyLen = atoi(bptr + 5); + bptr = strstr(bptr, "\r\n\r\n"); + + if (bptr) + ptr = bptr+4; + } + } + + ptr[BodyLen] = 0; + + sprintf(Reply, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Disposition: attachment; filename=\"SavedMsg%05d.txt\" \r\n\r\n", + (int)(strlen(Hddr) + strlen(ptr)), Msg->number); + strcat(Reply, Hddr); + strcat(Reply, ptr); + + *RLen = (int)strlen(Reply); + + free(MailBuffer); + return; + } + + if (_stricmp(NodeURL, "/Mail/SaveAttachment") == 0) + { + struct MsgInfo * Msg = Session->Msg; + char * MailBuffer; + + int Files = 0, i; + int BodyLen; + char * ptr; + int WriteLen=0; + char FileName[100][MAX_PATH] = {""}; + int FileLen[100]; + char Noatt[] = "Message has no attachments"; + + + MailBuffer = ReadMessageFile(Msg->number); + BodyLen = Msg->length; + + if ((Msg->B2Flags & Attachments) == 0) + { + sprintf(Reply, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\n\r\n%s", + (int)strlen(Noatt), Noatt); + *RLen = (int)strlen(Reply); + + free(MailBuffer); + return; + } + + ptr = MailBuffer; + + while(ptr && *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 += 4; // Over Blank Line and Separator + ptr += BodyLen; // to first file + + if (Files == 0) + { + sprintf(Reply, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\n\r\n%s", + (int)strlen(Noatt), Noatt); + *RLen = (int)strlen(Reply); + free(MailBuffer); + return; + } + + *RLen = 0; + + // For now only handle first + + i = 0; + +// for (i = 0; i < Files; i++) + { + int Len = sprintf(&Reply[*RLen], "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Disposition: attachment; filename=\"%s\" \r\n\r\n", + FileLen[i], FileName[i]); + + memcpy(&Reply[Len + *RLen], ptr, FileLen[i]); + + *RLen += (Len + FileLen[i]); + + ptr += FileLen[i]; + ptr +=2; // Over separator - I don't think there should be one + } + + free(MailBuffer); + return; + } + + + if (_stricmp(NodeURL, "/Mail/Msgs") == 0) + { + struct UserInfo * USER = NULL; + int PageLen; + + if (MsgEditTemplate) + free(MsgEditTemplate); + + MsgEditTemplate = GetTemplateFromFile(2, "MsgPage.txt"); + + // Refresh BBS No to BBS list + + MaxBBS = 0; + + for (USER = BBSChain; USER; USER = USER->BBSNext) + { + int n = USER->BBSNumber; + BBSLIST[n] = USER; + if (n > MaxBBS) + MaxBBS = n; + } + + PageLen = 334 + (MaxBBS / 8) * 24; + + if (MsgEditTemplate) + { + int len =sprintf(Reply, MsgEditTemplate, PageLen, PageLen, PageLen - 97, Key, Key, Key, Key, Key, + BBSName, Key, Key, Key, Key, Key, Key, Key, Key); + *RLen = len; + return; + } + + + + + } + + if (_stricmp(NodeURL, "/Mail/EditM") == 0) + { + // Edit Message + + char * MsgBytes; + + MsgBytes = ReadMessageFile(Session->Msg->number); + + // See if Multipart + +// if (Msg->B2Flags & Attachments) +// EnableWindow(GetDlgItem(hDlg, IDC_SAVEATTACHMENTS), TRUE); + + if (MsgBytes) + { + *RLen = sprintf(Reply, MsgEditPage, Key, MsgBytes); + free (MsgBytes); + } + else + *RLen = sprintf(Reply, MsgEditPage, Key, "Message Not Found"); + + return; + } + + if (_stricmp(NodeURL, "/Mail/HK") == 0) + { + if (HousekeepingTemplate) + free(HousekeepingTemplate); + + HousekeepingTemplate = GetTemplateFromFile(2, "Housekeeping.txt"); + + SendHouseKeeping(Reply, RLen, Key); + return; + } + + if (_stricmp(NodeURL, "/Mail/WP") == 0) + { + if (WPTemplate) + free(WPTemplate); + + WPTemplate = GetTemplateFromFile(1, "WP.txt"); + + if (WPTemplate) + { + int len =sprintf(Reply, WPTemplate, Key, Key, Key, Key, + BBSName, Key, Key, Key, Key, Key, Key, Key, Key); + *RLen = len; + return; + } + + return; + } + + if (_stricmp(NodeURL, "/Mail/WPInfo.txt") == 0) + { + int i = 0, n, len = 0; + WPRec * WP[10000]; + + // Get array of addresses + + for (n = 1; n <= NumberofWPrecs; n++) + { + WP[i++] = WPRecPtr[n]; + if (i > 9999) break; + } + + qsort((void *)WP, i, sizeof(void *), compare); + + for (i=0; i < NumberofWPrecs; i++) + { + len += sprintf(&Reply[len], "%s|", WP[i]->callsign); + } + + *RLen = len; + return; + } + + + ReplyLen = sprintf(Reply, MailSignon, BBSName, BBSName); + *RLen = ReplyLen; + +} + +int SendWPDetails(WPRec * WP, char * Reply, char * Key) +{ + int len = 0; + char D1[80], D2[80]; + + if (WP) + { + strcpy(D1, FormatDateAndTime(WP->last_modif, FALSE)); + strcpy(D2, FormatDateAndTime(WP->last_seen, FALSE)); + + len = sprintf(Reply, WPDetail, Key, WP->callsign, WP->name, + WP->first_homebbs, WP->secnd_homebbs, + WP->first_qth, WP->secnd_qth, + WP->first_zip, WP->secnd_zip, D1, D2, + WP->Type, + WP->changed, + WP->seen); + } + return(len); +} +VOID SaveWP(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Key) +{ + WPRec * WP = Session->WP; + char * input, * ptr1, * ptr2; + int n; + + input = strstr(MsgPtr, "\r\n\r\n"); // End of headers + + if (input) + { + if (strstr(input, "Cancel=Cancel")) + { + *RLen = SendHeader(Reply, Session->Key); + return; + } + + if (strcmp(input + 4, "Delete") == 0) + { + for (n = 1; n <= NumberofWPrecs; n++) + { + if (Session->WP == WPRecPtr[n]) + break; + } + + if (n <= NumberofWPrecs) + { + WP = Session->WP; + + for (n = n; n < NumberofWPrecs; n++) + { + WPRecPtr[n] = WPRecPtr[n+1]; // move down all following entries + } + + NumberofWPrecs--; + + free(WP); + + SaveWPDatabase(); + + Session->WP = WPRecPtr[1]; + } + *RLen = SendWPDetails(Session->WP, Reply, Session->Key); + return; + } + } + if (input && WP) + { + ptr1 = input + 4; + ptr2 = strchr(ptr1, '|');if (ptr2){*(ptr2++) = 0;if (strlen(ptr1) > 12) ptr1[12] = 0;strcpy(WP->name, ptr1);ptr1 = ptr2;} + ptr2 = strchr(ptr1, '|');if (ptr2){*(ptr2++) = 0;if (strlen(ptr1) > 40) ptr1[40] = 0;strcpy(WP->first_homebbs, ptr1);ptr1 = ptr2;} + ptr2 = strchr(ptr1, '|');if (ptr2){*(ptr2++) = 0;if (strlen(ptr1) > 40) ptr1[40] = 0;strcpy(WP->secnd_homebbs, ptr1);ptr1 = ptr2;} + ptr2 = strchr(ptr1, '|');if (ptr2){*(ptr2++) = 0;if (strlen(ptr1) > 30) ptr1[30] = 0;strcpy(WP->first_qth, ptr1);ptr1 = ptr2;} + ptr2 = strchr(ptr1, '|');if (ptr2){*(ptr2++) = 0;if (strlen(ptr1) > 30) ptr1[30] = 0;strcpy(WP->secnd_qth, ptr1);ptr1 = ptr2;} + ptr2 = strchr(ptr1, '|');if (ptr2){*(ptr2++) = 0;if (strlen(ptr1) > 8) ptr1[8] = 0;strcpy(WP->first_zip, ptr1);ptr1 = ptr2;} + ptr2 = strchr(ptr1, '|');if (ptr2){*(ptr2++) = 0;if (strlen(ptr1) > 8) ptr1[8] = 0;strcpy(WP->secnd_zip, ptr1);ptr1 = ptr2;} + + // GetParam(input, "BBSCall=", BBSName); + + +/* + GetDlgItemText(hDlg, IDC_WPNAME, WP->name, 13); + GetDlgItemText(hDlg, IDC_HOMEBBS1, WP->first_homebbs, 41); + GetDlgItemText(hDlg, IDC_HOMEBBS2, WP->first_homebbs, 41); + GetDlgItemText(hDlg, IDC_QTH1, WP->first_qth, 31); + GetDlgItemText(hDlg, IDC_QTH2, WP->secnd_qth, 31); + GetDlgItemText(hDlg, IDC_ZIP1, WP->first_zip, 31); + GetDlgItemText(hDlg, IDC_ZIP2, WP->secnd_zip, 31); + WP->seen = GetDlgItemInt(hDlg, IDC_SEEN, &OK1, FALSE); +*/ + + WP->last_modif = time(NULL); + WP->Type = 'U'; + WP->changed = 1; + + SaveWPDatabase(); + + *RLen = SendWPDetails(WP, Reply, Key); + } +} + + +int SendMessageDetails(struct MsgInfo * Msg, char * Reply, char * Key) +{ + int BBSNo = 1, x, y, len = 0; + char D1[80], D2[80], D3[80]; + struct UserInfo * USER; + int i = 0, n; + struct UserInfo * bbs[NBBBS+2] = {0}; + + if (Msg) + { + char EmailFromLine[256] = ""; + + strcpy(D1, FormatDateAndTime((time_t)Msg->datecreated, FALSE)); + strcpy(D2, FormatDateAndTime((time_t)Msg->datereceived, FALSE)); + strcpy(D3, FormatDateAndTime((time_t)Msg->datechanged, FALSE)); + +// if (Msg->emailfrom[0]) + sprintf(EmailFromLine, "Email From
", Msg->emailfrom); + + len = sprintf(Reply, MailDetailPage, Msg->number, Key, + Msg->from, D1, + (Msg->type == 'B')?sel:"", + (Msg->type == 'P')?sel:"", + (Msg->type == 'T')?sel:"", + Msg->to, D2, + (Msg->status == 'N')?sel:"", + (Msg->status == 'Y')?sel:"", + (Msg->status == 'F')?sel:"", + (Msg->status == 'K')?sel:"", + (Msg->status == 'H')?sel:"", + (Msg->status == 'D')?sel:"", + (Msg->status == '$')?sel:"", + Msg->bid, D3, Msg->length, EmailFromLine, Msg->via, Msg->title, + Key, Msg->number, Key, Key, + (Msg->B2Flags & Attachments)?"":"disabled"); + + // Get a sorted list of BBS records + + for (n = 1; n <= NumberofUsers; n++) + { + USER = UserRecPtr[n]; + + if ((USER->flags & F_BBS)) + if (USER->BBSNumber) + bbs[i++] = USER; + } + + qsort((void *)bbs, i, sizeof(void *), compare ); + + n = 0; + + for (y = 0; y < NBBBS/8; y++) + { + len += sprintf(&Reply[len],""); + for (x= 0; x < 8; x++) + { + char * Colour = NotThisOne; + + if (bbs[n]) + { + if (memcmp(Msg->fbbs, zeros, NBMASK) != 0) + if (check_fwd_bit(Msg->fbbs, bbs[n]->BBSNumber)) + Colour = ToSend; + if (memcmp(Msg->forw, zeros, NBMASK) != 0) + if (check_fwd_bit(Msg->forw, bbs[n]->BBSNumber)) + Colour = Sent; + + len += sprintf(&Reply[len],"%s", + Colour, bbs[n]->BBSNumber, bbs[n]->Call); + } + else + len += sprintf(&Reply[len], " "); + + n++; + } + len += sprintf(&Reply[len],""); + if (n > i) + break; + } + len += sprintf(&Reply[len], "%s", MailDetailTail); + } + return(len); +} + +char ** GetMultiStringInput(char * input, char * key) +{ + char MultiString[16384] = ""; + + GetParam(input, key, MultiString); + + if (MultiString[0] == 0) + return NULL; + + return SeparateMultiString(MultiString, TRUE); +} + +char ** SeparateMultiString(char * MultiString, BOOL NoToUpper) +{ + char * ptr1 = MultiString; + char * ptr2 = NULL; + char * DecodedString; + char ** Value; + int Count = 0; + char c; + char * ptr; + + ptr2 = zalloc(strlen(MultiString) + 1); + DecodedString = ptr2; + + // Input has crlf or lf - replace with | + + while (*ptr1) + { + c = *(ptr1++); + + if (c == 13) + continue; + + if (c == 10) + { + *ptr2++ = '|'; + } + else + *(ptr2++) = c; + } + + // Convert to string array + + Value = zalloc(sizeof(void *)); // always NULL entry on end even if no values + Value[0] = NULL; + + ptr = DecodedString; + + while (ptr && strlen(ptr)) + { + ptr1 = strchr(ptr, '|'); + + if (ptr1) + *(ptr1++) = 0; + + if (strlen(ptr)) + { + Value = realloc(Value, (Count+2) * sizeof(void *)); + if (_memicmp(ptr, "file ", 5) == 0 || NoToUpper) + Value[Count++] = _strdup(ptr); + else + Value[Count++] = _strupr(_strdup(ptr)); + } + ptr = ptr1; + } + + Value[Count] = NULL; + return Value; +} + +VOID GetMallocedParam(char * input, char * key, char ** value) +{ + char Param[32768] = ""; + + GetParam(input, key, Param); + + if (Param[0]) + { + free(*value); + *value = _strdup(Param); + } +} + +VOID GetParam(char * input, char * key, char * value) +{ + char * ptr = strstr(input, key); + char Param[32768]; + char * ptr1, * ptr2; + char c; + + if (ptr) + { + ptr2 = strchr(ptr, '&'); + if (ptr2) *ptr2 = 0; + strcpy(Param, ptr + strlen(key)); + if (ptr2) *ptr2 = '&'; // Restore string + + // Undo any % transparency + + ptr1 = Param; + ptr2 = Param; + + c = *(ptr1++); + + while (c) + { + if (c == '%') + { + int n; + int m = *(ptr1++) - '0'; + if (m > 9) m = m - 7; + n = *(ptr1++) - '0'; + if (n > 9) n = n - 7; + + *(ptr2++) = m * 16 + n; + } + else if (c == '+') + *(ptr2++) = ' '; + else + *(ptr2++) = c; + + c = *(ptr1++); + } + + *(ptr2++) = 0; + + strcpy(value, Param); + } +} + +VOID GetCheckBox(char * input, char * key, int * value) +{ + char * ptr = strstr(input, key); + if (ptr) + *value = 1; + else + *value = 0; +} + + +VOID * GetOverrideFromString(char * input) +{ + char * ptr1; + char * MultiString = NULL; + char * ptr = input; + int Count = 0; + struct Override ** Value; + char * Val; + + Value = zalloc(sizeof(void *)); // always NULL entry on end even if no values + Value[0] = NULL; + + while (ptr && strlen(ptr)) + { + ptr1 = strchr(ptr, 13); + + if (ptr1) + { + *(ptr1) = 0; + ptr1 += 2; + } + Value = realloc(Value, (Count+2) * sizeof(void *)); + Value[Count] = zalloc(sizeof(struct Override)); + Val = strlop(ptr, ','); + if (Val == NULL) + break; + + Value[Count]->Call = _strupr(_strdup(ptr)); + Value[Count++]->Days = atoi(Val); + ptr = ptr1; + } + + Value[Count] = NULL; + return Value; +} + + + + +VOID SaveHousekeeping(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Key) +{ + int ReplyLen = 0; + char * input; + char Temp[80]; + struct tm *tm; + time_t now; + + input = strstr(MsgPtr, "\r\n\r\n"); // End of headers + + if (input) + { + if (strstr(input, "RunNow=")) + { + DoHouseKeeping(FALSE); + SendHouseKeeping(Reply, RLen, Key); + return; + } + if (strstr(input, "Cancel=Cancel")) + { + SendHouseKeeping(Reply, RLen, Key); + return; + } + + GetParam(input, "MTTime=", Temp); + MaintTime = atoi(Temp); + GetParam(input, "MTInt=", Temp); + MaintInterval = atoi(Temp); + GetParam(input, "MAXMSG=", Temp); + MaxMsgno = atoi(Temp); + GetParam(input, "BIDLife=", Temp); + BidLifetime= atoi(Temp); + GetParam(input, "MaxAge=", Temp); + MaxAge = atoi(Temp); + GetParam(input, "LogLife=", Temp); + LogAge = atoi(Temp); + GetParam(input, "UserLife=", Temp); + UserLifetime= atoi(Temp); + + GetCheckBox(input, "Deltobin=", &DeletetoRecycleBin); + GetCheckBox(input, "SendND=", &SendNonDeliveryMsgs); + GetCheckBox(input, "NoMail=", &SuppressMaintEmail); + GetCheckBox(input, "GenTraffic=", &GenerateTrafficReport); + GetCheckBox(input, "OvUnsent=", &OverrideUnsent); + + GetParam(input, "PR=", Temp); + PR = atof(Temp); + GetParam(input, "PUR=", Temp); + PUR = atof(Temp); + GetParam(input, "PF=", Temp); + PF = atof(Temp); + GetParam(input, "PUF=", Temp); + PNF = atof(Temp); + GetParam(input, "BF=", Temp); + BF = atoi(Temp); + GetParam(input, "BUF=", Temp); + BNF = atoi(Temp); + + GetParam(input, "NTSD=", Temp); + NTSD = atoi(Temp); + + GetParam(input, "NTSF=", Temp); + NTSF = atoi(Temp); + + GetParam(input, "NTSU=", Temp); + NTSU = atoi(Temp); + + GetParam(input, "From=", LTFROMString); + LTFROM = GetOverrideFromString(LTFROMString); + + GetParam(input, "To=", LTTOString); + LTTO = GetOverrideFromString(LTTOString); + + GetParam(input, "At=", LTATString); + LTAT = GetOverrideFromString(LTATString); + + SaveConfig(ConfigName); + GetConfig(ConfigName); + + // Calulate time to run Housekeeping + + now = time(NULL); + + tm = gmtime(&now); + + tm->tm_hour = MaintTime / 100; + tm->tm_min = MaintTime % 100; + tm->tm_sec = 0; + +// MaintClock = _mkgmtime(tm); + MaintClock = mktime(tm) - (time_t)_MYTIMEZONE; + + while (MaintClock < now) + MaintClock += MaintInterval * 3600; + + Debugprintf("Maint Clock %d NOW %d Time to HouseKeeping %d", MaintClock, now, MaintClock - now); + } + SendHouseKeeping(Reply, RLen, Key); + return; +} + + + + + + + +VOID SaveWelcome(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Key) +{ + int ReplyLen = 0; + char * input; + + input = strstr(MsgPtr, "\r\n\r\n"); // End of headers + + if (input) + { + if (strstr(input, "Cancel=Cancel")) + { + *RLen = SendHeader(Reply, Session->Key); + return; + } + + GetMallocedParam(input, "NUWelcome=", &WelcomeMsg); + GetMallocedParam(input, "NewWelcome=", &NewWelcomeMsg); + GetMallocedParam(input, "ExWelcome=", &ExpertWelcomeMsg); + + TidyWelcomeMsg(&WelcomeMsg); + TidyWelcomeMsg(&NewWelcomeMsg); + TidyWelcomeMsg(&ExpertWelcomeMsg); + + GetMallocedParam(input, "NUPrompt=", &Prompt); + GetMallocedParam(input, "NewPrompt=", &NewPrompt); + GetMallocedParam(input, "ExPrompt=", &ExpertPrompt); + TidyPrompts(); + + GetParam(input, "Bye=", &SignoffMsg[0]); + if (SignoffMsg[0]) + { + if (SignoffMsg[strlen(SignoffMsg) - 1] == 10) + SignoffMsg[strlen(SignoffMsg) - 1] = 0; + + if (SignoffMsg[strlen(SignoffMsg) - 1] != 13) + strcat(SignoffMsg, "\r"); + } + + if (SignoffMsg[0] == 13) + SignoffMsg[0] = 0; + } + + SendWelcomePage(Reply, RLen, Key); + return; +} + +VOID ProcessConfUpdate(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Key) +{ + int ReplyLen = 0; + char * input; + struct UserInfo * USER = NULL; + char Temp[80]; + + input = strstr(MsgPtr, "\r\n\r\n"); // End of headers + + if (input) + { + if (strstr(input, "Cancel=Cancel")) + { + *RLen = SendHeader(Reply, Session->Key); + return; + } + + if (strstr(input, "ConfigUI=Config+UI")) + { + SendUIPage(Reply, RLen, Key); + return; + } + + GetParam(input, "BBSCall=", BBSName); + _strupr(BBSName); + strlop(BBSName, '-'); + GetParam(input, "SYSOPCall=", SYSOPCall); + _strupr(SYSOPCall); + strlop(SYSOPCall, '-'); + GetParam(input, "HRoute=", HRoute); + _strupr(HRoute); + GetParam(input, "ApplNum=", Temp); + BBSApplNum = atoi(Temp); + GetParam(input, "Streams=", Temp); + MaxStreams = atoi(Temp); + + GetCheckBox(input, "SysToSYSOP=", &SendSYStoSYSOPCall); + GetCheckBox(input, "BBSToSYSOP=", &SendBBStoSYSOPCall); + GetCheckBox(input, "RefuseBulls=", &RefuseBulls); + GetCheckBox(input, "EnUI=", &EnableUI); + + GetParam(input, "UIInterval=", Temp); + MailForInterval = atoi(Temp); + + GetCheckBox(input, "DontHold=", &DontHoldNewUsers); + GetCheckBox(input, "DefaultNoWinlink=", &DefaultNoWINLINK); + GetCheckBox(input, "DontNeedName=", &AllowAnon); + GetCheckBox(input, "DontNeedHomeBBS=", &DontNeedHomeBBS); + GetCheckBox(input, "DontCheckFromCall=", &DontCheckFromCall); + GetCheckBox(input, "UserCantKillT=", &UserCantKillT); + UserCantKillT = !UserCantKillT; // Reverse Logic + GetCheckBox(input, "FWDtoMe=", &ForwardToMe); + GetCheckBox(input, "OnlyKnown=", &OnlyKnown); + GetCheckBox(input, "Events=", &reportMailEvents); + + GetParam(input, "POP3Port=", Temp); + POP3InPort = atoi(Temp); + + GetParam(input, "SMTPPort=", Temp); + SMTPInPort = atoi(Temp); + + GetParam(input, "NNTPPort=", Temp); + NNTPInPort = atoi(Temp); + + GetCheckBox(input, "EnRemote=", &RemoteEmail); + + GetCheckBox(input, "EnISP=", &ISP_Gateway_Enabled); + GetCheckBox(input, "SendAMPR=", &SendAMPRDirect); + + GetParam(input, "AMPRDomain=", AMPRDomain); + + GetParam(input, "ISPDomain=", MyDomain); + GetParam(input, "SMTPServer=", ISPSMTPName); + GetParam(input, "ISPEHLOName=", ISPEHLOName); + + GetParam(input, "ISPSMTPPort=", Temp); + ISPSMTPPort = atoi(Temp); + + GetParam(input, "POP3Server=", ISPPOP3Name); + + GetParam(input, "ISPPOP3Port=", Temp); + ISPPOP3Port = atoi(Temp); + + GetParam(input, "ISPAccount=", ISPAccountName); + + GetParam(input, "ISPPassword=", ISPAccountPass); + EncryptedPassLen = EncryptPass(ISPAccountPass, EncryptedISPAccountPass); + + GetParam(input, "PollInterval=", Temp); + ISPPOP3Interval = atoi(Temp); + + GetCheckBox(input, "ISPAuth=", &SMTPAuthNeeded); + + GetCheckBox(input, "EnWP=", &SendWP); + GetCheckBox(input, "RejWFBulls=", &FilterWPBulls); + + if (strstr(input, "Type=TypeB")) + SendWPType = 0; + + if (strstr(input, "Type=TypeP")) + SendWPType = 1; + + SendWPAddrs = GetMultiStringInput(input, "WPTO="); + + RejFrom = GetMultiStringInput(input, "Rfrom="); + RejTo = GetMultiStringInput(input, "Rto="); + RejAt = GetMultiStringInput(input, "Rat="); + RejBID = GetMultiStringInput(input, "RBID="); + HoldFrom = GetMultiStringInput(input, "Hfrom="); + HoldTo = GetMultiStringInput(input, "Hto="); + 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); + } + + SendConfigPage(Reply, RLen, Key); + return; +} + + + +VOID ProcessUIUpdate(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Key) +{ + int ReplyLen = 0, i; + char * input; + struct UserInfo * USER = NULL; + + input = strstr(MsgPtr, "\r\n\r\n"); // End of headers + + if (input) + { + if (strstr(input, "Cancel=Cancel")) + { + *RLen = SendHeader(Reply, Session->Key); + return; + } + + GetParam(input, "MailFor=", &MailForText[0]); + + for (i = 1; i <= GetNumberofPorts(); i++) + { + char EnKey[10]; + char DigiKey[10]; + char MFKey[12]; + char HDDRKey[12]; + char NullKey[12]; + char Temp[100]; + + sprintf(EnKey, "En%d=", i); + sprintf(DigiKey, "Path%d=", i); + sprintf(MFKey, "SndMF%d=", i); + sprintf(HDDRKey, "SndHDDR%d=", i); + sprintf(NullKey, "SndNull%d=", i); + + GetCheckBox(input, EnKey, &UIEnabled[i]); + GetParam(input, DigiKey, Temp); + if (UIDigi[i]) + free (UIDigi[i]); + UIDigi[i] = _strdup(Temp); + GetCheckBox(input, MFKey, &UIMF[i]); + GetCheckBox(input, HDDRKey, &UIHDDR[i]); + GetCheckBox(input, NullKey, &UINull[i]); + } + + SaveConfig(ConfigName); + GetConfig(ConfigName); + } + + SendUIPage(Reply, RLen, Key); + return; +} + +VOID ProcessDisUser(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Rest) +{ + char * input; + char * ptr; + + input = strstr(MsgPtr, "\r\n\r\n"); // End of headers + + if (input) + { + ptr = strstr(input, "call="); + if (ptr) + { + int Stream = atoi(ptr + 5); + Disconnect(Stream); + } + } + SendStatusPage(Reply, RLen, Rest); +} + + + +VOID SaveFwdCommon(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Rest) +{ + int ReplyLen = 0; + char * input; + struct UserInfo * USER = NULL; + + char Temp[80]; + int Mask = 0; + + input = strstr(MsgPtr, "\r\n\r\n"); // End of headers + + if (input) + { + int n; + GetParam(input, "MaxTX=", Temp); + MaxTXSize = atoi(Temp); + GetParam(input, "MaxRX=", Temp); + MaxRXSize = atoi(Temp); + GetParam(input, "MaxAge=", Temp); + MaxAge = atoi(Temp); + GetCheckBox(input, "WarnNoRoute=", &WarnNoRoute); + GetCheckBox(input, "LocalTime=", &Localtime); + GetCheckBox(input, "SendPtoMultiple=", &SendPtoMultiple); + + // Reinitialise Aliases + + n = 0; + + if (Aliases) + { + while(Aliases[n]) + { + free(Aliases[n]->Dest); + free(Aliases[n]); + n++; + } + + free(Aliases); + Aliases = NULL; + FreeList(AliasText); + } + + AliasText = GetMultiStringInput(input, "Aliases="); + + if (AliasText) + { + n = 0; + + while (AliasText[n]) + { + _strupr(AliasText[n]); + n++; + } + } + SetupFwdAliases(); + } + + SaveConfig(ConfigName); + GetConfig(ConfigName); + + SendFwdMainPage(Reply, RLen, Session->Key); +} + +char * GetNextParam(char ** next) +{ + char * ptr1 = *next; + char * ptr2 = strchr(ptr1, '|'); + if (ptr2) + { + *(ptr2++) = 0; + *next = ptr2; + } + return ptr1; +} + +VOID SaveFwdDetails(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Rest) +{ + int ReplyLen = 0; + char * input; + struct UserInfo * USER = Session->User; + struct BBSForwardingInfo * FWDInfo = USER->ForwardingInfo; + char * ptr1, *ptr2; + + input = strstr(MsgPtr, "\r\n\r\n"); // End of headers + + if (input) + { + if (strstr(input, "StartForward")) + { + StartForwarding(USER->BBSNumber, NULL); + SendFwdDetails(Session->User, Reply, RLen, Session->Key); + return; + } + + if (strstr(input, "CopyForward")) + { + struct UserInfo * OldBBS; + + // Get call to copy from + + ptr2 = input + 4; + ptr1 = GetNextParam(&ptr2); // Call + _strupr(ptr2); + + OldBBS = FindBBS(ptr2); + + if (OldBBS == NULL) + { + + *RLen = sprintf(Reply, "

Copy From BBS %s not found

", ptr2); + return; + } + + // Set current info from OldBBS +// +// SetForwardingPage(hDlg, OldBBS); // moved to separate routine as also called from copy config + + SendFwdDetails(OldBBS, Reply, RLen, Session->Key); + return; + } + // Fwd update + + ptr2 = input + 4; + ptr1 = GetNextParam(&ptr2); // TO + FWDInfo->TOCalls = SeparateMultiString(ptr1, FALSE); + + ptr1 = GetNextParam(&ptr2); // AT + FWDInfo->ATCalls = SeparateMultiString(ptr1, FALSE); + + ptr1 = GetNextParam(&ptr2); // TIMES + FWDInfo->FWDTimes = SeparateMultiString(ptr1, FALSE); + + ptr1 = GetNextParam(&ptr2); // FWD SCRIPT + FWDInfo->ConnectScript = SeparateMultiString(ptr1, TRUE); + + ptr1 = GetNextParam(&ptr2); // HRB + FWDInfo->Haddresses = SeparateMultiString(ptr1, FALSE); + + ptr1 = GetNextParam(&ptr2); // HRP + FWDInfo->HaddressesP = SeparateMultiString(ptr1, FALSE); + + ptr1 = GetNextParam(&ptr2); // BBSHA + if (FWDInfo->BBSHA) + free(FWDInfo->BBSHA); + + FWDInfo->BBSHA = _strdup(_strupr(ptr1)); + + ptr1 = GetNextParam(&ptr2); // EnF + if (strcmp(ptr1, "true") == 0) FWDInfo->Enabled = TRUE; else FWDInfo->Enabled = FALSE; + + ptr1 = GetNextParam(&ptr2); // Interval + FWDInfo->FwdInterval = atoi(ptr1); + + ptr1 = GetNextParam(&ptr2); // EnR + if (strcmp(ptr1, "true") == 0) FWDInfo->ReverseFlag = TRUE; else FWDInfo->ReverseFlag = FALSE; + + ptr1 = GetNextParam(&ptr2); // RInterval + FWDInfo->RevFwdInterval = atoi(ptr1); + + ptr1 = GetNextParam(&ptr2); // No Wait + if (strcmp(ptr1, "true") == 0) FWDInfo->SendNew = TRUE; else FWDInfo->SendNew = FALSE; + + ptr1 = GetNextParam(&ptr2); // Blocked + if (strcmp(ptr1, "true") == 0) FWDInfo->AllowBlocked = TRUE; else FWDInfo->AllowBlocked = FALSE; + + ptr1 = GetNextParam(&ptr2); // FBB Block + FWDInfo->MaxFBBBlockSize = atoi(ptr1); + + ptr1 = GetNextParam(&ptr2); // Personals + if (strcmp(ptr1, "true") == 0) FWDInfo->PersonalOnly = TRUE; else FWDInfo->PersonalOnly = FALSE; + ptr1 = GetNextParam(&ptr2); // Binary + if (strcmp(ptr1, "true") == 0) FWDInfo->AllowCompressed = TRUE; else FWDInfo->AllowCompressed = FALSE; + ptr1 = GetNextParam(&ptr2); // B1 + if (strcmp(ptr1, "true") == 0) FWDInfo->AllowB1 = TRUE; else FWDInfo->AllowB1 = FALSE; + ptr1 = GetNextParam(&ptr2); // B2 + if (strcmp(ptr1, "true") == 0) FWDInfo->AllowB2 = TRUE; else FWDInfo->AllowB2 = FALSE; + ptr1 = GetNextParam(&ptr2); // CTRLZ + if (strcmp(ptr1, "true") == 0) FWDInfo->SendCTRLZ = TRUE; else FWDInfo->SendCTRLZ = FALSE; + ptr1 = GetNextParam(&ptr2); // Connect Timeout + FWDInfo->ConTimeout = atoi(ptr1); + + SaveConfig(ConfigName); + GetConfig(ConfigName); + + ReinitializeFWDStruct(Session->User); + + SendFwdDetails(Session->User, Reply, RLen, Session->Key); + } +} + + + +VOID ProcessUserUpdate(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Rest) +{ + int ReplyLen = 0; + char * input; + struct UserInfo * USER = Session->User; + int SSID, Mask = 0; + char * ptr1, *ptr2; + int skipRMSExUser = 0; + + input = strstr(MsgPtr, "\r\n\r\n"); // End of headers + + if (input) + { + if (strstr(input, "Cancel")) + { + *RLen = SendHeader(Reply, Session->Key); + return; + } + + if (strstr(input, "Delete")) + { + int n; + + for (n = 1; n <= NumberofUsers; n++) + { + if (Session->User == UserRecPtr[n]) + break; + } + + if (n <= NumberofUsers) + { + USER = Session->User; + + for (n = n; n < NumberofUsers; n++) + { + UserRecPtr[n] = UserRecPtr[n+1]; // move down all following entries + } + + NumberofUsers--; + + if (USER->flags & F_BBS) // was a BBS? + DeleteBBS(USER); + + free(USER); + + SaveUserDatabase(); + + Session->User = UserRecPtr[1]; + + SendUserSelectPage(Reply, RLen, Session->Key); + return; + } + } + + if (strstr(input, "Add=")) + { + char * Call; + + Call = input + 8; + strlop(Call, '-'); + + if (strlen(Call) > 6) + Call[6] = 0; + + _strupr(Call); + + if (Call[0] == 0 || LookupCall(Call)) + { + // Null or exists + + SendUserSelectPage(Reply, RLen, Session->Key); + return; + } + + USER = AllocateUserRecord(Call); + USER->Temp = zalloc(sizeof (struct TempUserInfo)); + + SendUserSelectPage(Reply, RLen, Session->Key); + return; + + } + + // User update + + ptr2 = input + 4; + ptr1 = GetNextParam(&ptr2); // BBS + + // If BBS Flag has changed, must set up or delete forwarding info + + if (strcmp(ptr1, "true") == 0) + { + if ((USER->flags & F_BBS) == 0) + { + // New BBS + + if(SetupNewBBS(USER)) + { + USER->flags |= F_BBS; + USER->flags &= ~F_Temp_B2_BBS; // Clear RMS Express User + skipRMSExUser = 1; // Dont read old value + } + else + { + // Failed - too many bbs's defined + + //sprintf(InfoBoxText, "Cannot set user to be a BBS - you already have 80 BBS's defined"); + //DialogBox(hInst, MAKEINTRESOURCE(IDD_USERADDED_BOX), hWnd, InfoDialogProc); + USER->flags &= ~F_BBS; + //CheckDlgButton(hDlg, IDC_BBSFLAG, (user->flags & F_BBS)); + } + } + } + else + { + if (USER->flags & F_BBS) + { + //was a BBS + + USER->flags &= ~F_BBS; + DeleteBBS(USER); + } + } + + ptr1 = GetNextParam(&ptr2); // Permit Email + if (strcmp(ptr1, "true") == 0) USER->flags |= F_EMAIL; else USER->flags &= ~F_EMAIL; + + ptr1 = GetNextParam(&ptr2); // PMS + if (strcmp(ptr1, "true") == 0) USER->flags |= F_PMS; else USER->flags &= ~F_PMS; + + ptr1 = GetNextParam(&ptr2); // RMS EX User + if (strcmp(ptr1, "true") == 0 && !skipRMSExUser) USER->flags |= F_Temp_B2_BBS; else USER->flags &= ~F_Temp_B2_BBS; + ptr1 = GetNextParam(&ptr2); // SYSOP + if (strcmp(ptr1, "true") == 0) USER->flags |= F_SYSOP; else USER->flags &= ~F_SYSOP; + ptr1 = GetNextParam(&ptr2); // PollRMS + if (strcmp(ptr1, "true") == 0) USER->flags |= F_POLLRMS; else USER->flags &= ~F_POLLRMS; + ptr1 = GetNextParam(&ptr2); // Expert + if (strcmp(ptr1, "true") == 0) USER->flags |= F_Expert; else USER->flags &= ~F_Expert; + + ptr1 = GetNextParam(&ptr2); // SSID1 + SSID = atoi(ptr1); + Mask |= (1 << SSID); + ptr1 = GetNextParam(&ptr2); // SSID2 + SSID = atoi(ptr1); + Mask |= (1 << SSID); + ptr1 = GetNextParam(&ptr2); // SSID3 + SSID = atoi(ptr1); + Mask |= (1 << SSID); + ptr1 = GetNextParam(&ptr2); // SSID4 + SSID = atoi(ptr1); + Mask |= (1 << SSID); + Session->User->RMSSSIDBits = Mask; + + ptr1 = GetNextParam(&ptr2); // Excluded + if (strcmp(ptr1, "true") == 0) USER->flags |= F_Excluded; else USER->flags &= ~F_Excluded; + ptr1 = GetNextParam(&ptr2); // Hold + if (strcmp(ptr1, "true") == 0) USER->flags |= F_HOLDMAIL; else USER->flags &= ~F_HOLDMAIL; + ptr1 = GetNextParam(&ptr2); // SYSOP gets LM + if (strcmp(ptr1, "true") == 0) USER->flags |= F_SYSOP_IN_LM; else USER->flags &= ~F_SYSOP_IN_LM; + ptr1 = GetNextParam(&ptr2); // Dont add winlink.org + if (strcmp(ptr1, "true") == 0) USER->flags |= F_NOWINLINK; else USER->flags &= ~F_NOWINLINK; + ptr1 = GetNextParam(&ptr2); // Allow Bulls + if (strcmp(ptr1, "true") == 0) USER->flags &= ~F_NOBULLS; else USER->flags |= F_NOBULLS; // Inverted flag + ptr1 = GetNextParam(&ptr2); // NTS Message Pickup Station + if (strcmp(ptr1, "true") == 0) USER->flags |= F_NTSMPS; else USER->flags &= ~F_NTSMPS; + ptr1 = GetNextParam(&ptr2); // APRS Mail For + if (strcmp(ptr1, "true") == 0) USER->flags |= F_RMSREDIRECT; else USER->flags &= ~F_RMSREDIRECT; + ptr1 = GetNextParam(&ptr2); // Redirect to RMS + + if (strcmp(ptr1, "true") == 0) USER->flags |= F_APRSMFOR; else USER->flags &= ~F_APRSMFOR; + + ptr1 = GetNextParam(&ptr2); // APRS SSID + SSID = atoi(ptr1); + SSID &= 15; + USER->flags &= 0x0fffffff; + USER->flags |= (SSID << 28); + + + ptr1 = GetNextParam(&ptr2); // Last Listed + USER->lastmsg = atoi(ptr1); + ptr1 = GetNextParam(&ptr2); // Name + strcpy(USER->Name, ptr1); + ptr1 = GetNextParam(&ptr2); // Pass + strcpy(USER->pass, ptr1); + ptr1 = GetNextParam(&ptr2); // CMS Pass + if (memcmp("****************", ptr1, strlen(ptr1) != 0)) + { + strcpy(USER->CMSPass, ptr1); + } + + ptr1 = GetNextParam(&ptr2); // QTH + strcpy(USER->Address, ptr1); + ptr1 = GetNextParam(&ptr2); // ZIP + strcpy(USER->ZIP, ptr1); + ptr1 = GetNextParam(&ptr2); // HomeBBS + strcpy(USER->HomeBBS, ptr1); + _strupr(USER->HomeBBS); + + SaveUserDatabase(); + UpdateWPWithUserInfo(USER); + + *RLen = SendUserDetails(Session, Reply, Session->Key); + } +} + +VOID ProcessMsgAction(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Rest) +{ + int ReplyLen = 0; + char * input; + int BBSNumber = 0; + struct MsgInfo * Msg = Session->Msg; + char * ptr1; + + input = strstr(MsgPtr, "\r\n\r\n"); // End of headers + + if (input && Msg) + { + ptr1 = input + 4; + *RLen = SendMessageDetails(Msg, Reply, Session->Key); + } +} + +VOID SaveMessageText(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Rest) +{ + int ReplyLen = 0; + struct MsgInfo * Msg = Session->Msg; + char * ptr, * ptr1, * ptr2, *input; + char c; + int MsgLen, WriteLen; + char MsgFile[256]; + FILE * hFile; + + input = strstr(MsgPtr, "\r\n\r\n"); // End of headers + + if (input) + { + if (strstr(input, "Cancel=Cancel")) + { + *RLen = sprintf(Reply, "%s", ""); + return; + } + + ptr = strstr(input, "&Save="); + + if (ptr) + { + *ptr = 0; + + // Undo any % transparency + + ptr1 = ptr2 = input + 8; + + c = *(ptr1++); + + while (c) + { + if (c == '%') + { + int n; + int m = *(ptr1++) - '0'; + if (m > 9) m = m - 7; + n = *(ptr1++) - '0'; + if (n > 9) n = n - 7; + + *(ptr2++) = m * 16 + n; + } + else if (c == '+') + *(ptr2++) = ' '; + else + *(ptr2++) = c; + + c = *(ptr1++); + } + + *(ptr2++) = 0; + + MsgLen = (int)strlen(input + 8); + + Msg->datechanged = time(NULL); + Msg->length = MsgLen; + + sprintf_s(MsgFile, sizeof(MsgFile), "%s/m_%06d.mes", MailDir, Msg->number); + + hFile = fopen(MsgFile, "wb"); + + if (hFile) + { + WriteLen = (int)fwrite(input + 8, 1, Msg->length, hFile); + fclose(hFile); + } + + if (WriteLen != Msg->length) + { + char Mess[80]; + sprintf_s(Mess, sizeof(Mess), "Failed to create Message File\r"); + CriticalErrorHandler(Mess); + + return; + } + + SaveMessageDatabase(); + + *RLen = sprintf(Reply, "%s", ""); + + } + } + return; + +} + + +VOID ProcessMsgUpdate(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Rest) +{ + int ReplyLen = 0; + char * input; + int BBSNumber = 0; + struct MsgInfo * Msg = Session->Msg; + char * ptr1, * ptr2; + char OldStatus = Msg->status; + + input = strstr(MsgPtr, "\r\n\r\n"); // End of headers + + if (input && Msg) + { + ptr1 = input + 4; + ptr2 = strchr(ptr1, '|'); + if (ptr2) + { + *(ptr2++) = 0; + strcpy(Msg->from, ptr1); + ptr1 = ptr2; + } + ptr2 = strchr(ptr1, '|');if (ptr2){*(ptr2++) = 0;strcpy(Msg->to, ptr1);ptr1 = ptr2;} + ptr2 = strchr(ptr1, '|');if (ptr2){*(ptr2++) = 0;strcpy(Msg->bid, ptr1);ptr1 = ptr2;} + ptr2 = strchr(ptr1, '|');if (ptr2){*(ptr2++) = 0;strcpy(Msg->emailfrom, ptr1);ptr1 = ptr2;} + ptr2 = strchr(ptr1, '|');if (ptr2){*(ptr2++) = 0;strcpy(Msg->via, ptr1);ptr1 = ptr2;} + ptr2 = strchr(ptr1, '|');if (ptr2){*(ptr2++) = 0;strcpy(Msg->title, ptr1);ptr1 = ptr2;} + ptr2 = strchr(ptr1, '|');if (ptr2){*(ptr2++) = 0;Msg->type = *ptr1;ptr1 = ptr2;} + ptr2 = strchr(ptr1, '|');if (ptr2){*(ptr2++) = 0;Msg->status = *ptr1;ptr1 = ptr2;} + + if (Msg->status != OldStatus) + { + // Need to take action if killing message + + if (Msg->status == 'K') + FlagAsKilled(Msg, FALSE); // Clear forwarding bits + } + + Msg->datechanged = time(NULL); + SaveMessageDatabase(); + } + + *RLen = SendMessageDetails(Msg, Reply, Session->Key); +} + + + + +VOID ProcessMsgFwdUpdate(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Rest) +{ + int ReplyLen = 0; + char * input; + int BBSNumber = 0; + struct UserInfo * User; + struct MsgInfo * Msg = Session->Msg; + BOOL toforward, forwarded; + + input = strstr(MsgPtr, "\r\n\r\n"); // End of headers + + if (input && Msg) + { + BBSNumber = atoi(input + 4); + User = BBSLIST[BBSNumber]; + + if (User == NULL) + return; + + toforward = check_fwd_bit(Msg->fbbs, BBSNumber); + forwarded = check_fwd_bit(Msg->forw, BBSNumber); + + if (forwarded) + { + // Changing to not this BBS + + clear_fwd_bit(Msg->forw, BBSNumber); + } + else if (toforward) + { + // Change to Forwarded + + clear_fwd_bit(Msg->fbbs, BBSNumber); + User->ForwardingInfo->MsgCount--; + set_fwd_bit(Msg->forw, BBSNumber); + } + else + { + // Change to to forward + + set_fwd_bit(Msg->fbbs, BBSNumber); + User->ForwardingInfo->MsgCount++; + clear_fwd_bit(Msg->forw, BBSNumber); + if (FirstMessageIndextoForward > Msg->number) + FirstMessageIndextoForward = Msg->number; + + } + *RLen = SendMessageDetails(Msg, Reply, Session->Key); + } + SaveMessageDatabase(); +} + + + + +VOID SetMultiStringValue(char ** values, char * Multi) +{ + char ** Calls; + char * ptr = &Multi[0]; + + *ptr = 0; + + if (values) + { + Calls = values; + + while(Calls[0]) + { + strcpy(ptr, Calls[0]); + ptr += strlen(Calls[0]); + *(ptr++) = '\r'; + *(ptr++) = '\n'; + Calls++; + } + *(ptr) = 0; + } +} + + + +VOID SendFwdDetails(struct UserInfo * User, char * Reply, int * ReplyLen, char * Key) +{ + int Len; + struct BBSForwardingInfo * FWDInfo = User->ForwardingInfo; + char TO[2048] = ""; + char AT[2048] = ""; + char TIMES[2048] = ""; + char FWD[100000] = ""; + char HRB[2048] = ""; + char HRP[2048] = ""; + + SetMultiStringValue(FWDInfo->TOCalls, TO); + SetMultiStringValue(FWDInfo->ATCalls, AT); + SetMultiStringValue(FWDInfo->FWDTimes, TIMES); + SetMultiStringValue(FWDInfo->ConnectScript, FWD); + SetMultiStringValue(FWDInfo->Haddresses, HRB); + SetMultiStringValue(FWDInfo->HaddressesP, HRP); + + if (FwdDetailTemplate == NULL) + FwdDetailTemplate = GetTemplateFromFile(3, "FwdDetail.txt"); + + Len = sprintf(Reply, FwdDetailTemplate, User->Call, + CountMessagestoForward (User), Key, + TO, AT, TIMES , FWD, HRB, HRP, + (FWDInfo->BBSHA) ? FWDInfo->BBSHA : "", + (FWDInfo->Enabled) ? CHKD : UNC, + FWDInfo->FwdInterval, + (FWDInfo->ReverseFlag) ? CHKD : UNC, + FWDInfo->RevFwdInterval, + (FWDInfo->SendNew) ? CHKD : UNC, + (FWDInfo->AllowBlocked) ? CHKD : UNC, + FWDInfo->MaxFBBBlockSize, + (FWDInfo->PersonalOnly) ? CHKD : UNC, + (FWDInfo->AllowCompressed) ? CHKD : UNC, + (FWDInfo->AllowB1) ? CHKD : UNC, + (FWDInfo->AllowB2) ? CHKD : UNC, + (FWDInfo->SendCTRLZ) ? CHKD : UNC, + FWDInfo->ConTimeout); + + *ReplyLen = Len; + +} + +VOID SendConfigPage(char * Reply, int * ReplyLen, char * Key) +{ + int Len, i; + + char HF[2048] = ""; + char HT[2048] = ""; + char HA[2048] = ""; + char HB[2048] = ""; + char RF[2048] = ""; + char RT[2048] = ""; + char RA[2048] = ""; + char RB[2048] = ""; + char WPTO[10000] = ""; + + char FBBFilters[100000] = ""; + + + char * ptr = FBBFilters; + FBBFilter * Filter = Filters; + + SetMultiStringValue(RejFrom, RF); + SetMultiStringValue(RejTo, RT); + SetMultiStringValue(RejAt, RA); + SetMultiStringValue(RejBID, RB); + SetMultiStringValue(HoldFrom, HF); + SetMultiStringValue(HoldTo, HT); + SetMultiStringValue(HoldAt, HA); + 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, + (SendBBStoSYSOPCall) ? CHKD : UNC, + BBSApplNum, MaxStreams, + (SendSYStoSYSOPCall) ? CHKD : UNC, + (RefuseBulls) ? CHKD : UNC, + (EnableUI) ? CHKD : UNC, + MailForInterval, + (DontHoldNewUsers) ? CHKD : UNC, + (DefaultNoWINLINK) ? CHKD : UNC, + (AllowAnon) ? CHKD : UNC, + (DontNeedHomeBBS) ? CHKD : UNC, + (DontCheckFromCall) ? CHKD : UNC, + (UserCantKillT) ? UNC : CHKD, // Reverse logic + (ForwardToMe) ? CHKD : UNC, + (OnlyKnown) ? CHKD : UNC, + (reportMailEvents) ? CHKD : UNC, + POP3InPort, SMTPInPort, NNTPInPort, + (RemoteEmail) ? CHKD : UNC, + AMPRDomain, + (SendAMPRDirect) ? CHKD : UNC, + (ISP_Gateway_Enabled) ? CHKD : UNC, + MyDomain, ISPSMTPName, ISPSMTPPort, ISPEHLOName, ISPPOP3Name, ISPPOP3Port, + ISPAccountName, ISPAccountPass, ISPPOP3Interval, + (SMTPAuthNeeded) ? CHKD : UNC, + (SendWP) ? CHKD : UNC, + (FilterWPBulls) ? CHKD : UNC, + (SendWPType == 0) ? CHKD : UNC, + (SendWPType == 1) ? CHKD : UNC, + WPTO, + RF, RT, RA, RB, HF, HT, HA, HB, FBBFilters); + + *ReplyLen = Len; +} +VOID SendHouseKeeping(char * Reply, int * ReplyLen, char * Key) +{ + char FromList[1000]= "", ToList[1000]= "", AtList[1000] = ""; + char Line[80]; + struct Override ** Call; + + if (LTFROM) + { + Call = LTFROM; + while(Call[0]) + { + sprintf(Line, "%s, %d\r\n", Call[0]->Call, Call[0]->Days); + strcat(FromList, Line); + Call++; + } + } + if (LTTO) + { + Call = LTTO; + while(Call[0]) + { + sprintf(Line, "%s, %d\r\n", Call[0]->Call, Call[0]->Days); + strcat(ToList, Line); + Call++; + } + } + + if (LTAT) + { + Call = LTAT; + while(Call[0]) + { + sprintf(Line, "%s, %d\r\n", Call[0]->Call, Call[0]->Days); + strcat(AtList, Line); + Call++; + } + } + + *ReplyLen = sprintf(Reply, HousekeepingTemplate, + BBSName, Key, Key, Key, Key, Key, Key, Key, Key, Key, + MaintTime, MaintInterval, MaxMsgno, BidLifetime, LogAge, UserLifetime, + (DeletetoRecycleBin) ? CHKD : UNC, + (SendNonDeliveryMsgs) ? CHKD : UNC, + (SuppressMaintEmail) ? CHKD : UNC, + (GenerateTrafficReport) ? CHKD : UNC, + PR, PUR, PF, PNF, BF, BNF, NTSD, NTSF, NTSU, + FromList, ToList, AtList, + (OverrideUnsent) ? CHKD : UNC); + + return; + +} + + +VOID SendWelcomePage(char * Reply, int * ReplyLen, char * Key) +{ + int Len; + + Len = SendHeader(Reply, Key); + + Len += sprintf(&Reply[Len], Welcome, Key, WelcomeMsg, NewWelcomeMsg, ExpertWelcomeMsg, + Prompt, NewPrompt, ExpertPrompt, SignoffMsg); + *ReplyLen = Len; +} + +VOID SendFwdMainPage(char * Reply, int * RLen, char * Key) +{ + char ALIASES[16384]; + + SetMultiStringValue(AliasText, ALIASES); + + *RLen = sprintf(Reply, FwdTemplate, Key, Key, BBSName, + Key, Key, Key, Key, Key, Key, Key, Key, + Key, MaxTXSize, MaxRXSize, MaxAge, + (WarnNoRoute) ? CHKD : UNC, + (Localtime) ? CHKD : UNC, + (SendPtoMultiple) ? CHKD : UNC, + ALIASES); +} + + +char TenSpaces[] = "          "; + +VOID SendUIPage(char * Reply, int * ReplyLen, char * Key) +{ + int Len, i; + + Len = SendHeader(Reply, Key); + Len += sprintf(&Reply[Len], UIHddr, Key, MailForText); + + for (i = 1; i <= GetNumberofPorts(); i++) + { + char PortNo[512]; + char PortDesc[31]; + int n; + + // Only allow UI on ax.25 ports + + struct _EXTPORTDATA * PORTVEC; + + PORTVEC = (struct _EXTPORTDATA * )GetPortTableEntryFromSlot(i); + + if (PORTVEC->PORTCONTROL.PORTTYPE == 16) // EXTERNAL + if (PORTVEC->PORTCONTROL.PROTOCOL == 10) // Pactor/WINMOR + if (PORTVEC->PORTCONTROL.UICAPABLE == 0) + continue; + + + GetPortDescription(i, PortDesc); + n = sprintf(PortNo, "Port %2d %s", GetPortNumber(i), PortDesc); + + while (PortNo[--n] == ' '); + + PortNo[n + 1] = 0; + + while (n++ < 38) + strcat(PortNo, " "); + + Len += sprintf(&Reply[Len], UILine, + (UIEnabled[i])?CHKD:UNC, i, + PortNo, + (UIDigi[i])?UIDigi[i]:"", i, + (UIMF[i])?CHKD:UNC, i, + (UIHDDR[i])?CHKD:UNC, i, + (UINull[i])?CHKD:UNC, i); + } + + Len += sprintf(&Reply[Len], UITail, Key); + + *ReplyLen = Len; +} + +VOID SendStatusPage(char * Reply, int * ReplyLen, char * Key) +{ + int Len; + char msg[1024]; + CIRCUIT * conn; + int i,n, SYSOPMsgs = 0, HeldMsgs = 0; + char Name[80]; + + SMTPMsgs = 0; + + Len = sprintf(Reply, RefreshMainPage, BBSName, BBSName, Key, Key, Key, Key, Key, Key, Key, Key); + + Len += sprintf(&Reply[Len], StatusPage, Key); + + for (n = 0; n < NumberofStreams; n++) + { + conn=&Connections[n]; + + if (!conn->Active) + { + strcpy(msg,"Idle          " + "         " + "         \r\n"); + } + else + { + { + if (conn->UserPointer == 0) + strcpy(msg,"Logging in\r\n"); + else + { + strcpy(Name, conn->UserPointer->Name); + Name[9] = 0; + + i=sprintf_s(msg, sizeof(msg), "%s%s%s%s%2d %5d\r\n", + Name, + &TenSpaces[strlen(Name) * 6], + conn->UserPointer->Call, + &TenSpaces[strlen(conn->UserPointer->Call) * 6], + conn->BPQStream, + conn->OutputQueueLength - conn->OutputGetPointer); + } + } + } + Len += sprintf(&Reply[Len], StatusLine, conn->BPQStream, msg); + } + + n = 0; + + for (i=1; i <= NumberofMessages; i++) + { + if (MsgHddrPtr[i]->status == 'N') + { + if (_stricmp(MsgHddrPtr[i]->to, SYSOPCall) == 0 || _stricmp(MsgHddrPtr[i]->to, "SYSOP") == 0) + SYSOPMsgs++; + else + if (MsgHddrPtr[i]->to[0] == 0) + SMTPMsgs++; + } + else + { + if (MsgHddrPtr[i]->status == 'H') + HeldMsgs++; + } + } + + Len += sprintf(&Reply[Len], StreamEnd, + NumberofMessages, SYSOPMsgs, HeldMsgs, SMTPMsgs); + + // If there are any active multicast transfers, display them. + + Len += MulticastStatusHTML(&Reply[Len]); + + Len += sprintf(&Reply[Len], StatusTail, + NumberofMessages, SYSOPMsgs, HeldMsgs, SMTPMsgs); + + *ReplyLen = Len; +} + +VOID SendFwdSelectPage(char * Reply, int * ReplyLen, char * Key) +{ + struct UserInfo * USER; + int i = 0; + int Len = 0; + + for (USER = BBSChain; USER; USER = USER->BBSNext) + { + Len += sprintf(&Reply[Len], "%s|", USER->Call); + } + + *ReplyLen = Len; +} + +VOID SendUserSelectPage(char * Reply, int * ReplyLen, char * Key) +{ + struct UserInfo * USER; + int i = 0, n; + int Len = 0; + struct UserInfo * users[10000]; + + // Get array of addresses + + for (n = 1; n <= NumberofUsers; n++) + { + users[i++] = UserRecPtr[n]; + if (i > 9999) break; + } + + qsort((void *)users, i, sizeof(void *), compare ); + + for (n = 0; n < NumberofUsers; n++) + { + USER = users[n]; + Len += sprintf(&Reply[Len], "%s|", USER->Call); + } + *ReplyLen = Len; +} + +int SendUserDetails(struct HTTPConnectionInfo * Session, char * Reply, char * Key) +{ + char SSID[16][16] = {""}; + char ASSID[16]; + int i, n, s, Len; + struct UserInfo * User = Session->User; + unsigned int flags = User->flags; + int RMSSSIDBits = Session->User->RMSSSIDBits; + char HiddenPass[20] = ""; + + int ConnectsIn; + int ConnectsOut; + int MsgsReceived; + int MsgsSent; + int MsgsRejectedIn; + int MsgsRejectedOut; + int BytesForwardedIn; + int BytesForwardedOut; +// char MsgsIn[80]; +// char MsgsOut[80]; +// char BytesIn[80]; +// char BytesOut[80]; +// char RejIn[80]; +// char RejOut[80]; + + i = 0; + + ConnectsIn = User->Total.ConnectsIn - User->Last.ConnectsIn; + ConnectsOut = User->Total.ConnectsOut - User->Last.ConnectsOut; + + MsgsReceived = MsgsSent = MsgsRejectedIn = MsgsRejectedOut = BytesForwardedIn = BytesForwardedOut = 0; + + for (n = 0; n < 4; n++) + { + MsgsReceived += User->Total.MsgsReceived[n] - User->Last.MsgsReceived[n]; + MsgsSent += User->Total.MsgsSent[n] - User->Last.MsgsSent[n]; + BytesForwardedIn += User->Total.BytesForwardedIn[n] - User->Last.BytesForwardedIn[n]; + BytesForwardedOut += User->Total.BytesForwardedOut[n] - User->Last.BytesForwardedOut[n]; + MsgsRejectedIn += User->Total.MsgsRejectedIn[n] - User->Last.MsgsRejectedIn[n]; + MsgsRejectedOut += User->Total.MsgsRejectedOut[n] - User->Last.MsgsRejectedOut[n]; + } + + + for (s = 0; s < 16; s++) + { + if (RMSSSIDBits & (1 << s)) + { + if (s) + sprintf(&SSID[i++][0], "%d", s); + else + SSID[i++][0] = 0; + } + } + + memset(HiddenPass, '*', strlen(User->CMSPass)); + + i = (flags >> 28); + sprintf(ASSID, "%d", i); + + if (i == 0) + ASSID[0] = 0; + + if (!UserDetailTemplate) + UserDetailTemplate = GetTemplateFromFile(4, "UserDetail.txt"); + + Len = sprintf(Reply, UserDetailTemplate, Key, User->Call, + (flags & F_BBS)?CHKD:UNC, + (flags & F_EMAIL)?CHKD:UNC, + (flags & F_PMS)?CHKD:UNC, + (flags & F_Temp_B2_BBS)?CHKD:UNC, + (flags & F_SYSOP)?CHKD:UNC, + (flags & F_POLLRMS)?CHKD:UNC, + (flags & F_Expert)?CHKD:UNC, + SSID[0], SSID[1], SSID[2], SSID[3], + (flags & F_Excluded)?CHKD:UNC, + (flags & F_HOLDMAIL)?CHKD:UNC, + (flags & F_SYSOP_IN_LM)?CHKD:UNC, + (flags & F_NOWINLINK)?CHKD:UNC, + (flags & F_NOBULLS)?UNC:CHKD, // Inverted flag + (flags & F_NTSMPS)?CHKD:UNC, + (flags & F_RMSREDIRECT)?CHKD:UNC, + (flags & F_APRSMFOR)?CHKD:UNC, ASSID, + + ConnectsIn, MsgsReceived, MsgsRejectedIn, + ConnectsOut, MsgsSent, MsgsRejectedOut, + BytesForwardedIn, FormatDateAndTime((time_t)User->TimeLastConnected, FALSE), + BytesForwardedOut, User->lastmsg, + User->Name, + User->pass, + HiddenPass, + User->Address, + User->ZIP, + User->HomeBBS); + + return Len; +} + +#ifdef WIN32 + +int ProcessWebmailWebSock(char * MsgPtr, char * OutBuffer); + +static char PipeFileName[] = "\\\\.\\pipe\\BPQMailWebPipe"; + +static DWORD WINAPI InstanceThread(LPVOID lpvParam) + +// This routine is a thread processing function to read from and reply to a client +// via the open pipe connection passed from the main loop. Note this allows +// the main loop to continue executing, potentially creating more threads of +// of this procedure to run concurrently, depending on the number of incoming +// client connections. +{ + DWORD cbBytesRead = 0, cbReplyBytes = 0, cbWritten = 0; + BOOL fSuccess = FALSE; + HANDLE hPipe = NULL; + char Buffer[250000]; + char OutBuffer[250000]; + char * MsgPtr; + int InputLen = 0; + int OutputLen = 0; + struct HTTPConnectionInfo Session; + char URL[100001]; + char * Context, * Method; + int n; + + char * ptr; + + // The thread's parameter is a handle to a pipe object instance. + + hPipe = (HANDLE) lpvParam; + + // First block is the HTTPConnectionInfo record, rest is request + + n = ReadFile(hPipe, &Session, sizeof (struct HTTPConnectionInfo), &n, NULL); + + // Get the data + + fSuccess = ReadFile(hPipe, Buffer, 250000, &InputLen, NULL); + + if (!fSuccess || InputLen == 0) + { + if (GetLastError() == ERROR_BROKEN_PIPE) + Debugprintf("InstanceThread: client disconnected.", GetLastError()); + else + Debugprintf("InstanceThread ReadFile failed, GLE=%d.", GetLastError()); + + return 1; + } + + Buffer[InputLen] = 0; + + MsgPtr = &Buffer[0]; + + if (memcmp(MsgPtr, "WMRefresh", 9) == 0) + { + OutputLen = ProcessWebmailWebSock(MsgPtr, OutBuffer); + } + else + { + strcpy(URL, MsgPtr); + + ptr = strstr(URL, " HTTP"); + + if (ptr) + *ptr = 0; + + Method = strtok_s(URL, " ", &Context); + + ProcessMailHTTPMessage(&Session, Method, Context, MsgPtr, OutBuffer, &OutputLen, InputLen); + } + + WriteFile(hPipe, &Session, sizeof (struct HTTPConnectionInfo), &n, NULL); + WriteFile(hPipe, OutBuffer, OutputLen, &cbWritten, NULL); + + FlushFileBuffers(hPipe); + DisconnectNamedPipe(hPipe); + CloseHandle(hPipe); + + return 1; +} + +static DWORD WINAPI PipeThreadProc(LPVOID lpvParam) +{ + BOOL fConnected = FALSE; + DWORD dwThreadId = 0; + HANDLE hPipe = INVALID_HANDLE_VALUE, hThread = NULL; + +// The main loop creates an instance of the named pipe and +// then waits for a client to connect to it. When the client +// connects, a thread is created to handle communications +// with that client, and this loop is free to wait for the +// next client connect request. It is an infinite loop. + + for (;;) + { + hPipe = CreateNamedPipe( + PipeFileName, // pipe name + PIPE_ACCESS_DUPLEX, // read/write access + PIPE_TYPE_BYTE | // message type pipe + PIPE_WAIT, // blocking mode + PIPE_UNLIMITED_INSTANCES, // max. instances + 4096, // output buffer size + 4096, // input buffer size + 0, // client time-out + NULL); // default security attribute + + if (hPipe == INVALID_HANDLE_VALUE) + { + Debugprintf("CreateNamedPipe failed, GLE=%d.\n", GetLastError()); + return -1; + } + + // Wait for the client to connect; if it succeeds, + // the function returns a nonzero value. If the function + // returns zero, GetLastError returns ERROR_PIPE_CONNECTED. + + fConnected = ConnectNamedPipe(hPipe, NULL) ? + TRUE : (GetLastError() == ERROR_PIPE_CONNECTED); + + if (fConnected) + { + // Create a thread for this client. + + hThread = CreateThread( + NULL, // no security attribute + 0, // default stack size + InstanceThread, // thread proc + (LPVOID) hPipe, // thread parameter + 0, // not suspended + &dwThreadId); // returns thread ID + + if (hThread == NULL) + { + Debugprintf("CreateThread failed, GLE=%d.\n", GetLastError()); + return -1; + } + else CloseHandle(hThread); + } + else + // The client could not connect, so close the pipe. + CloseHandle(hPipe); + } + + return 0; +} + +BOOL CreatePipeThread() +{ + DWORD ThreadId; + CreateThread(NULL, 0, PipeThreadProc, 0, 0, &ThreadId); + return TRUE; +} + +#endif + +char *month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; +char *dat[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; + +VOID FormatTime(char * Time, time_t cTime) +{ + struct tm * TM; + TM = gmtime(&cTime); + + sprintf(Time, "%s, %02d %s %3d %02d:%02d:%02d GMT", dat[TM->tm_wday], TM->tm_mday, month[TM->tm_mon], + TM->tm_year + 1900, TM->tm_hour, TM->tm_min, TM->tm_sec); +} + + + + + + + diff --git a/mailapi.c b/mailapi.c new file mode 100644 index 0000000..b60ec77 --- /dev/null +++ b/mailapi.c @@ -0,0 +1,196 @@ +// basic JASON API to BPQ Node + +// Authentication is via Telnet USER records. + + +#define _CRT_SECURE_NO_DEPRECATE +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers + +//#include +#include "CHeaders.h" +#include +#include "bpqmail.h" + + +// Constants +#define TOKEN_SIZE 32 // Length of the authentication token +#define TOKEN_EXPIRATION 7200 // Token expiration time in seconds (2 hours) + +// Token data structure +typedef struct MailToken { + char token[TOKEN_SIZE + 1]; + time_t expiration_time; + struct UserInfo * User; + char Call[10]; + struct MailToken* next; +} MailToken; + +static MailToken * token_list = NULL; + +static int verify_token(const char* token); +static void remove_expired_tokens(); +static int request_token(char * response); +static void add_token_to_list(MailToken* token); +static MailToken * find_token(const char* token); + +static MailToken * generate_token() +{ + // Generate a random authentication token + int i; + + MailToken * token = malloc(sizeof(MailToken)); + + srand(time(NULL)); + + for (i = 0; i < TOKEN_SIZE; i++) + { + token->token[i] = 'A' + rand() % 26; // Random uppercase alphabet character + } + token->token[TOKEN_SIZE] = '\0'; // Null-terminate the token + token->expiration_time = time(NULL) + TOKEN_EXPIRATION; // Set token expiration time + add_token_to_list(token); + return token; +} + +// Function to add the token to the token_list +static void add_token_to_list(MailToken * token) +{ + if (token_list == NULL) + { + token_list = token; + token->next = NULL; + } + else + { + MailToken * current = token_list; + + while (current->next != NULL) + current = current->next; + + current->next = token; + token->next = NULL; + } +} + +static int verify_token(const char* token) +{ + // Find the token in the token list + MailToken * existing_token = find_token(token); + + if (existing_token != NULL) + { + // Check if the token has expired + time_t current_time = time(NULL); + if (current_time > existing_token->expiration_time) + { + // Token has expired, remove it from the token list + remove_expired_tokens(); + return 0; + } + // Token is valid + return 1; + } + + // Token doesn't exist in the token list + return 0; +} + +static void remove_expired_tokens() +{ + time_t current_time = time(NULL); + MailToken* current_token = token_list; + MailToken* prev_token = NULL; + MailToken* next_token; + + while (current_token != NULL) + { + if (current_time > current_token->expiration_time) + { + // Token has expired, remove it from the token list + if (prev_token == NULL) + { + token_list = current_token->next; + } else { + prev_token->next = current_token->next; + } + next_token = current_token->next; + free(current_token); + current_token = next_token; + } else { + prev_token = current_token; + current_token = current_token->next; + } + } +} + +static MailToken * find_token(const char* token) +{ + MailToken * current_token = token_list; + while (current_token != NULL) + { + if (strcmp(current_token->token, token) == 0) + { + return current_token; + } + current_token = current_token->next; + } + return NULL; +} + +static int send_http_response(char * response, const char* msg) +{ + return sprintf(response, "HTTP/1.1 %s\r\nContent-Length: 0\r\nConnection: close\r\n\r\n", msg); +} + + +int MailAPIProcessHTTPMessage(char * response, char * Method, char * URL, char * request, BOOL LOCAL, char *Params) +{ + char * pass = strlop(Params, '&'); + int Flags = 0; + MailToken * Token; + + + // Check if the request is for token generation + + if (strcmp(Method, "GET") != 0) + return send_http_response(response, "403 (Bad Method)"); + + if (_stricmp(URL, "/mail/api/login") == 0) + { + // user is in Params and Password in pass + + struct UserInfo * User; + char Msg[256]; + int n; + + User = LookupCall(Params); + + if (User) + { + // Check Password + + if (pass[0] == 0 || strcmp(User->pass, pass) != 0 || User->flags & F_Excluded) + return send_http_response(response, "403 (Login Failed)"); + + n=sprintf_s(Msg, sizeof(Msg), "API Connect from %s", _strupr(Params)); + WriteLogLine(NULL, '|',Msg, n, LOG_BBS); + + Token = generate_token(); + add_token_to_list(Token); + + Token->User = User; + + strcpy(Token->Call, Params); + + // Return Token + + sprintf(response, "{\"access_token\":\"%s\", \"expires_in\":%d, \"scope\":\"create\"}\r\n", + Token->token, TOKEN_EXPIRATION); + + return strlen(response); + + } + } + + return 0; +} diff --git a/makefile b/makefile index 184cfbf..0bd8491 100644 --- a/makefile +++ b/makefile @@ -13,7 +13,7 @@ OBJS = pngwtran.o pngrtran.o pngset.o pngrio.o pngwio.o pngtrans.o pngrutil.o pn MailCommands.o MailDataDefs.o LinBPQ.o MailRouting.o MailTCP.o MBLRoutines.o md5.o Moncode.o \ NNTPRoutines.o RigControl.o TelnetV6.o WINMOR.o TNCCode.o UZ7HODrv.o WPRoutines.o \ SCSTrackeMulti.o SCSPactor.o SCSTracker.o HanksRT.o UIRoutines.o AGWAPI.o AGWMoncode.o \ - DRATS.o FreeDATA.o base64.o Events.o + DRATS.o FreeDATA.o base64.o Events.o nodeapi.o mailapi.o # Configuration: diff --git a/nodeapi.c b/nodeapi.c new file mode 100644 index 0000000..8a5a814 --- /dev/null +++ b/nodeapi.c @@ -0,0 +1,633 @@ +// basic JASON API to BPQ Node + +// Authentication is via Telnet USER records. + + +#define _CRT_SECURE_NO_DEPRECATE + +#include "CHeaders.h" +#include +#include "tncinfo.h" +#include "asmstrucs.h" +#include "kiss.h" + +// Constants +#define TOKEN_SIZE 32 // Length of the authentication token +#define TOKEN_EXPIRATION 7200 // Token expiration time in seconds (2 hours) + +// Token data structure +typedef struct Token { + char token[TOKEN_SIZE + 1]; + time_t expiration_time; + struct Token* next; +} Token; + + +// Function prototypes +void handle_request(SOCKET client_socket, char * request, char * response); +int verify_token(const char* token); +void remove_expired_tokens(); +char* fetch_data(const char* endpoint); +int request_token(char * response); +int send_http_response(char * response, const char* msg); +int create_json_response(char * response, char* access_token, int expires_in, char* scope); +void add_token_to_list(Token* token); + +Token* find_token(const char* token); +Token* generate_token(); + +int sendPortList(char * response, char * token,int Flags); +int sendNodeList(char * response, char * token,int Flags); +int sendUserList(char * response, char * token,int Flags); +int sendInfo(char * response, char * token, int Flags); + +DllExport struct PORTCONTROL * APIENTRY GetPortTableEntryFromSlot(int portslot); + +// Token list +Token* token_list = NULL; + +int xx() +{ + while (1) + { + // Remove expired tokens + remove_expired_tokens(); + + // Handle the client request + // handle_request(); + } + return 0; +} + +int APIProcessHTTPMessage(char * response, char * Method, char * URL, char * request, BOOL LOCAL, BOOL COOKIE) +{ + const char * auth_header = "Authorization: Bearer "; + char * token_begin = strstr(request, auth_header); + char token[TOKEN_SIZE + 1]= ""; + char * param = strlop(URL, '?'); + int Flags = 0; + + if (param && strlen(param) == TOKEN_SIZE) + { + // assume auth token + + strcpy(token, param); + } + + remove_expired_tokens(); // Tidy up + + // Check if the request is for token generation + + if (strcmp(Method, "GET") != 0) + return send_http_response(response, "403 (Bad Method)"); + + if (_stricmp(URL, "/api/request_token") == 0) + return request_token(response); + + if (token[0] == 0) + { + // Extract the token from the request (assuming it's present in the request headers) + if (token_begin == NULL) + { + Debugprintf("Invalid request: No authentication token provided.\n"); + return send_http_response(response, "403 (Forbidden)"); + } + token_begin += strlen(auth_header); // Move to the beginning of the token + strncpy(token, token_begin, TOKEN_SIZE); + token[TOKEN_SIZE] = '\0'; // Null-terminate the token + } + + // Verify the token + if (!verify_token(token)) + { + Debugprintf("Invalid authentication token.\n"); + return send_http_response(response, "401 Unauthorized"); + } + + // Determine the requested API endpoint + + if (_stricmp(URL, "/api/getports") == 0) + return sendPortList(response, token, Flags); + else if (_stricmp(URL, "/api/getnodes") == 0) + return sendNodeList(response, token, Flags); + else if (_stricmp(URL, "/api/getusers") == 0) + return sendUserList(response, token, Flags); + else if (_stricmp(URL, "/api/getinfo") == 0) + return sendInfo(response, token, Flags); + + return send_http_response(response, "401 Invalid API Call"); + +} + +int request_token(char * response) +{ + Token * token = generate_token(); + int expires_in = 3600; + char scope[] = "create"; + + printf("Token generated: %s\n", token->token); + + sprintf(response, "{\"access_token\":\"%s\", \"expires_in\":%d, \"scope\":\"create\"}\r\n", + token->token, expires_in); + + return strlen(response); +} + +Token * generate_token() +{ + // Generate a random authentication token + int i; + + Token * token = malloc(sizeof(Token)); + for (i = 0; i < TOKEN_SIZE; i++) + { + token->token[i] = 'A' + rand() % 26; // Random uppercase alphabet character + } + token->token[TOKEN_SIZE] = '\0'; // Null-terminate the token + token->expiration_time = time(NULL) + TOKEN_EXPIRATION; // Set token expiration time + add_token_to_list(token); + return token; +} + +// Function to add the token to the token_list +void add_token_to_list(Token* token) +{ + if (token_list == NULL) + { + token_list = token; + token->next = NULL; + } + else + { + Token* current = token_list; + + while (current->next != NULL) + current = current->next; + + current->next = token; + token->next = NULL; + } +} + +int verify_token(const char* token) +{ + // Find the token in the token list + Token * existing_token = find_token(token); + + if (existing_token != NULL) + { + // Check if the token has expired + time_t current_time = time(NULL); + if (current_time > existing_token->expiration_time) + { + // Token has expired, remove it from the token list + remove_expired_tokens(); + return 0; + } + // Token is valid + return 1; + } + + // Token doesn't exist in the token list + return 0; +} + +void remove_expired_tokens() +{ + time_t current_time = time(NULL); + Token* current_token = token_list; + Token* prev_token = NULL; + Token* next_token; + + while (current_token != NULL) + { + if (current_time > current_token->expiration_time) + { + // Token has expired, remove it from the token list + if (prev_token == NULL) + { + token_list = current_token->next; + } else { + prev_token->next = current_token->next; + } + next_token = current_token->next; + free(current_token); + current_token = next_token; + } else { + prev_token = current_token; + current_token = current_token->next; + } + } +} + +Token * find_token(const char* token) +{ + Token* current_token = token_list; + while (current_token != NULL) + { + if (strcmp(current_token->token, token) == 0) + { + return current_token; + } + current_token = current_token->next; + } + return NULL; +} + +int send_http_response(char * response, const char* msg) +{ + return sprintf(response, "HTTP/1.1 %s\r\nContent-Length: 0\r\nConnection: close\r\n\r\n", msg); +} + +/* +{ +"access_token":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3", +"expires_in":3600, +"scope":"create" +} +*/ + +/* +{"ports":[ +{"ID":"My Port", "Driver":"KISS", "Number":2, "State":"Active"), +{ ...}, +{...} +]} +*/ + +extern int MasterPort[MAXBPQPORTS+1]; // Pointer to first BPQ port for a specific MPSK or UZ7HO host + +int sendPortList(char * response, char * token, int Flags) +{ + char * Array = 0; + int ArrayLen = 0; + int ArrayPtr = 0; + + struct _EXTPORTDATA * ExtPort; + struct PORTCONTROL * Port; + struct PORTCONTROL * SAVEPORT; + int PortNo; + + int count; + char DLL[20]; + char Status[32]="Unknown"; + char ID[33]; + char * ptr; + + ArrayPtr += sprintf(&response[ArrayPtr], "{\"ports\":[\r\n"); + + for (count = 1; count <= NUMBEROFPORTS; count++) + { + Port = GetPortTableEntryFromSlot(count); + ExtPort = (struct _EXTPORTDATA *)Port; + PortNo = Port->PORTNUMBER; + + if (Port->PORTTYPE == 0x10) + { + strcpy(DLL, ExtPort->PORT_DLL_NAME); + strlop(DLL, '.'); + strlop(DLL, ' '); + } + else if (Port->PORTTYPE == 0) + strcpy(DLL, "ASYNC"); + + else if (Port->PORTTYPE == 22) + strcpy(DLL, "I2C"); + + else if (Port->PORTTYPE == 14) + strcpy(DLL, "INTERNAL"); + + else if (Port->PORTTYPE > 0 && Port->PORTTYPE < 14) + strcpy(DLL, "HDLC"); + + + if (Port->PortStopped) + { + strcpy(Status, "Stopped"); + + } + else + { + if (Port->PORTTYPE == 0) + { + struct KISSINFO * KISS = (struct KISSINFO *)Port; + NPASYINFO KPort; + + SAVEPORT = Port; + + if (KISS->FIRSTPORT && KISS->FIRSTPORT != KISS) + { + // Not first port on device + + Port = (struct PORTCONTROL *)KISS->FIRSTPORT; + KPort = KISSInfo[PortNo]; + } + + KPort = KISSInfo[PortNo]; + + if (KPort) + { + // KISS like - see if connected + + if (Port->PORTIPADDR.s_addr || Port->KISSSLAVE) + { + // KISS over UDP or TCP + + if (Port->KISSTCP) + { + if (KPort->Connected) + strcpy(Status, "Open "); + else + if (Port->KISSSLAVE) + strcpy(Status, "Listen"); + else + strcpy(Status, "Closed"); + } + else + strcpy(Status, "UDP"); + } + else + if (KPort->idComDev) // Serial port Open + strcpy(Status, "Open "); + else + strcpy(Status, "Closed"); + + + Port = SAVEPORT; + } + } + + if (Port->PORTTYPE == 14) // Loopback + strcpy(Status, "Open "); + + else if (Port->PORTTYPE == 16) // External + { + if (Port->PROTOCOL == 10) // 'HF' Port + { + struct TNCINFO * TNC = TNCInfo[PortNo]; + + if (TNC) + { + switch (TNC->Hardware) // Hardware Type + { + case H_SCS: + case H_KAM: + case H_AEA: + case H_HAL: + case H_TRK: + case H_SERIAL: + + // Serial + + if (TNC->hDevice) + strcpy(Status, "Open "); + else + strcpy(Status, "Closed"); + + break; + + case H_UZ7HO: + + if (TNCInfo[MasterPort[PortNo]]->CONNECTED) + strcpy(Status, "Open "); + else + strcpy(Status, "Closed"); + + break; + + case H_WINMOR: + case H_V4: + + case H_MPSK: + case H_FLDIGI: + case H_UIARQ: + case H_ARDOP: + case H_VARA: + case H_KISSHF: + case H_WINRPR: + case H_FREEDATA: + + // TCP + + if (TNC->CONNECTED) + { + if (TNC->Streams[0].Attached) + strcpy(Status, "In Use"); + else + strcpy(Status, "Open "); + } + else + strcpy(Status, "Closed"); + + break; + + case H_TELNET: + + strcpy(Status, "Open "); + } + } + } + else + { + // External but not HF - AXIP, BPQETHER VKISS, ?? + + struct _EXTPORTDATA * EXTPORT = (struct _EXTPORTDATA *)Port; + + strcpy(Status, "Open "); + } + } + } + + strlop(Status, ' '); + strcpy(ID, Port->PORTDESCRIPTION); + ptr = &ID[29]; + while (*(ptr) == ' ') + { + *(ptr--) = 0; + } + + ArrayPtr += sprintf(&response[ArrayPtr], " {\"ID\":\"%s\", \"Driver\":\"%s\", \"Number\":%d,\"State\":\"%s\"},\r\n", + ID, DLL, Port->PORTNUMBER, Status); + } + + ArrayPtr -= 3; // remove trailing comma + ArrayPtr += sprintf(&response[ArrayPtr], "\r\n]}\r\n"); + + return ArrayPtr; +} + +/* +{"Nodes":[ +{"Call":"xx", "Alias":"xx", "Nbour1 ":"xx", "Quality":192), +{ ...}, +{...} +]} +*/ + +extern int MaxNodes; +extern struct DEST_LIST * DESTS; // NODE LIST +extern int DEST_LIST_LEN; + + +int sendNodeList(char * response, char * token, int Flags) +{ + int ArrayPtr = 0; + + int count, len, i; + char Normcall[10], Portcall[10]; + char Alias[7]; + struct DEST_LIST * Dests = DESTS ; + // struct ROUTE * Routes; + + Dests = DESTS; + MaxNodes = MAXDESTS; + + ArrayPtr += sprintf(&response[ArrayPtr], "{\"nodes\":[\r\n"); + + Dests-=1; + + for (count = 0; count < MaxNodes; count++) + { + Dests+=1; + + if (Dests->DEST_CALL[0] == 0) + continue; + + len = ConvFromAX25(Dests->DEST_CALL, Normcall); + Normcall[len] = 0; + + memcpy(Alias, Dests->DEST_ALIAS, 6); + + Alias[6]=0; + + for (i=0;i<6;i++) + { + if (Alias[i] == ' ') + Alias[i] = 0; + } + + + ArrayPtr += sprintf(&response[ArrayPtr], " {\"Call\":\"%s\", \"Alias\":\"%s\", \"Routes\":[", Normcall, Alias); + + + // Add an array with up to 6 objects (3 NR + 3 INP3 Neighbours + + if (Dests->NRROUTE[0].ROUT_NEIGHBOUR != 0 && Dests->NRROUTE[0].ROUT_NEIGHBOUR->INP3Node == 0) + { + len = ConvFromAX25(Dests->NRROUTE[0].ROUT_NEIGHBOUR->NEIGHBOUR_CALL,Portcall); + Portcall[len] = 0; + + ArrayPtr += sprintf(&response[ArrayPtr], "{\"Call\":\"%s\", \"Port\":%d, \"Quality\":%d},", + Portcall, Dests->NRROUTE[0].ROUT_NEIGHBOUR->NEIGHBOUR_PORT, Dests->NRROUTE[0].ROUT_QUALITY); + + + // if (Dests->NRROUTE[0].ROUT_OBSCOUNT > 127) + // { + // len=sprintf(&line[cursor],"! "); + // cursor+=len; + // } + + + if (Dests->NRROUTE[1].ROUT_NEIGHBOUR != 0 && Dests->NRROUTE[1].ROUT_NEIGHBOUR->INP3Node == 0) + { + len=ConvFromAX25(Dests->NRROUTE[1].ROUT_NEIGHBOUR->NEIGHBOUR_CALL,Portcall); + Portcall[len]=0; + + + + ArrayPtr += sprintf(&response[ArrayPtr], " {\"Call\":\"%s\", \"Port\":%d, \"Quality\":%d},", + Portcall, Dests->NRROUTE[1].ROUT_NEIGHBOUR->NEIGHBOUR_PORT, Dests->NRROUTE[1].ROUT_QUALITY); + //if (Dests->NRROUTE[1].ROUT_OBSCOUNT > 127) + //{ + //len=sprintf(&line[cursor],"! "); + //cursor+=len; + //} + + } + + if (Dests->NRROUTE[2].ROUT_NEIGHBOUR != 0 && Dests->NRROUTE[2].ROUT_NEIGHBOUR->INP3Node == 0) + { + len=ConvFromAX25(Dests->NRROUTE[2].ROUT_NEIGHBOUR->NEIGHBOUR_CALL,Portcall); + Portcall[len]=0; + + + ArrayPtr += sprintf(&response[ArrayPtr], " {\"Call\":\"%s\", \"Port\":%d, \"Quality\":%d},", + Portcall, Dests->NRROUTE[1].ROUT_NEIGHBOUR->NEIGHBOUR_PORT, Dests->NRROUTE[1].ROUT_QUALITY); + + //if (Dests->NRROUTE[2].ROUT_OBSCOUNT > 127) + //{ + //len=sprintf(&line[cursor],"! "); + //cursor+=len; + + } + ArrayPtr -= 1; // remove comma + } + + ArrayPtr += sprintf(&response[ArrayPtr], "]},\r\n"); + } + + ArrayPtr -= 3; // remove comma + ArrayPtr += sprintf(&response[ArrayPtr], "\r\n]}"); + + return ArrayPtr; +} + + +int sendUserList(char * response, char * token, int Flags) +{ + int ArrayPtr = 0; + int n = MAXCIRCUITS; + TRANSPORTENTRY * L4 = L4TABLE; + TRANSPORTENTRY * Partner; + int MaxLinks = MAXLINKS; + char State[12] = "", Type[12] = "Uplink"; + char LHS[50] = "", MID[10] = "", RHS[50] = ""; + char Line[100]; + char Normcall[10]; + int len; + + ArrayPtr += sprintf(&response[ArrayPtr], "{\"users\":[\r\n"); + + while (n--) + { + if (L4->L4USER[0]) + { + RHS[0] = MID[0] = 0; + + len = ConvFromAX25(L4->L4USER, Normcall); + Normcall[len] = 0; + + ArrayPtr += sprintf(&response[ArrayPtr], " {\"Call\", \"%s\"},\r\n", Normcall); + L4++; + } + } + + if (ArrayPtr == 12) //empty list + { + ArrayPtr -=2; + ArrayPtr += sprintf(&response[ArrayPtr], "]}\r\n"); + } + else + { + ArrayPtr -= 3; // remove trailing comma + ArrayPtr += sprintf(&response[ArrayPtr], "\r\n]}\r\n"); + } + return ArrayPtr; +} + +extern char MYALIASLOPPED[]; +extern char TextVerstring[]; +extern char LOCATOR[]; + +int sendInfo(char * response, char * token, int Flags) +{ + char call[10]; + + memcpy(call, MYNODECALL, 10); + strlop(call, ' '); + + sprintf(response, "{\"info\":{\"NodeCall\":\"%s\", \"Alias\":\"%s\", \"Locator\":\"%s\", \"Version\":\"%s\"}}\r\n", + call, MYALIASLOPPED, LOCATOR, TextVerstring); + + return strlen(response); +} diff --git a/telnetserver.h b/telnetserver.h index 77da27c..48f87d0 100644 --- a/telnetserver.h +++ b/telnetserver.h @@ -36,7 +36,8 @@ struct ConnectionInfo BOOL RelayMode; // Pure TCP for RMS Relay Emulation forwarding BOOL DRATSMode; // HTML Terminal Emulator BOOL SyncMode; // RMS Relay Sync - BOOL HTTPMode; // DRATS Reflector Emulator + BOOL HTTPMode; // HTTP Server + BOOL APIMode; // REST API Server BOOL TriMode; // Trimode emulation BOOL TriModeConnected; // Set when remote session is connected - now send data to DataSock SOCKET TriModeDataSock; // Data Socket diff --git a/templatedefs.c b/templatedefs.c index 72f1c8b..dbd7485 100644 --- a/templatedefs.c +++ b/templatedefs.c @@ -478,7 +478,9 @@ char * MainConfigtxt() " Dont Check From Call
\r\n" " Allow users to kill T messages
\r\n" " Forward Messages to BBS Call
\r\n" - " Don't allow unknown users

\r\n" + " Don't allow unknown users
\r\n" + " Enable Event Reporting

\r\n" + " POP3 Port   \r\n" "SMTP Port NTPPort   Enable Remote Access
\r\n" " AMPR Address Send AMPR Mail to AMPR host\r\n" @@ -515,7 +517,7 @@ char * MainConfigtxt() " FBB reject.sys type filters (all fields must match, wildcards allowed)\r\n" "

" "
%s
" - "
" + "
" " " "
" "\r\n" @@ -1428,7 +1430,7 @@ char * ChatConfigtxt() "
Chat Configuration
\r\n" "
\r\n" + "style=\"align: center; border: 2px solid ; overflow: auto; text-align: center; position: relative; top: 10px; height: 650px; width: 700px; left: 96.5px;\">\r\n" "
\r\n" "

 Chat Server Params

\r\n" @@ -1437,6 +1439,8 @@ char * ChatConfigtxt() "Streams    \r\n" "  
\r\n" " 
\r\n" + " Enable Event Reporting

\r\n" + "
The Nodes to link to box defines which other Chat Nodes should be connected to, or from which " "connections may be accepted. The format is ALIAS:CALL, eg BPQCHT:G8BPQ-4. If the node is not directly " "connectable (ie is not in your NODES table) you can add a connect script. This consists of a series of commands " @@ -1460,7 +1464,7 @@ char * ChatConfigtxt() "
\r\n" "
\r\n" "\r\n" - "
\r\n" + "
\r\n" " \r\n" " \r\n" " \r\n" diff --git a/tncinfo.h b/tncinfo.h index 2d6ad93..9b9cb54 100644 --- a/tncinfo.h +++ b/tncinfo.h @@ -110,6 +110,7 @@ struct TCPINFO int FBBPort[100]; int RelayPort; int HTTPPort; + int APIPort; int TriModePort; int SyncPort; int DRATSPort; @@ -159,6 +160,7 @@ struct TCPINFO SOCKET FBBsock[100]; SOCKET Relaysock; SOCKET HTTPsock; + SOCKET APIsock; SOCKET TriModeSock; SOCKET TriModeDataSock; SOCKET Syncsock; @@ -169,6 +171,7 @@ struct TCPINFO SOCKET FBBsock6[100]; SOCKET Relaysock6; SOCKET HTTPsock6; + SOCKET APIsock6; SOCKET Syncsock6; SOCKET DRATSsock6; diff --git a/upnp.c.bak b/upnp.c.bak new file mode 100644 index 0000000..cdc68a4 --- /dev/null +++ b/upnp.c.bak @@ -0,0 +1,187 @@ +// Includes code from MiniUPnPc, used subject to the following conditions: + +/* + +MiniUPnPc +Copyright (c) 2005-2020, Thomas BERNARD +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +*/ + +#define MINIUPNP_STATICLIB + +#include +#ifdef _WIN32 +#include "upnpcommands.h" +#include "miniupnpc.h" +#include "upnperrors.h" +#include +#else +#include +#include +#include +#include +#endif + +int AddMap(char * controlURL, char * eport, char * iport, char * proto); +int DeleteMap(char * controlURL, char * eport, char * iport, char * proto); + +void Consoleprintf(const char * format, ...); + +struct UPNP +{ + struct UPNP * Next; + char * Protocol; + char * LANport; + char * WANPort; +}; + +extern struct UPNP * UPNPConfig; + +char * controlURL = 0; +char * servicetype = 0; +char iaddr[] = "IP"; +char * inClient = NULL; +#ifdef LINBPQ +char desc[] = "LinBPQ "; +#else +char desc[] = "BPQ32 "; +#endif +char * remoteHost = NULL; +char * leaseDuration = NULL; + +struct UPNPDev * devlist = 0; +char lanaddr[64] = "unset"; /* my ip address on the LAN */ +struct UPNPUrls urls; +struct IGDdatas data; + +int i; +const char * rootdescurl = 0; +const char * multicastif = 0; +const char * minissdpdpath = 0; +int localport = UPNP_LOCAL_PORT_ANY; +int retcode = 0; +int error = 0; +int ipv6 = 0; +int ignore = 0; +unsigned char ttl = 2; + + +int upnpInit() +{ + struct UPNP * Config = UPNPConfig; + int i; +#ifdef WIN32 + WSADATA wsaData; + int nResult = WSAStartup(MAKEWORD(2,2), &wsaData); + if(nResult != NO_ERROR) + { + fprintf(stderr, "WSAStartup() failed.\n"); + return -1; + } +#endif + + while (Config) + { + if (devlist == NULL) + { + devlist = upnpDiscover(2000, multicastif, minissdpdpath, localport, ipv6, ttl, &error); + + if (devlist == NULL) + { + Consoleprintf("Failed to find a UPNP device"); + return 0; + } + + i = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr)); + } + + AddMap(devlist->descURL, Config->LANport, Config->WANPort, Config->Protocol); + Config = Config->Next; + } + + return 0; +} + +int upnpClose() +{ + struct UPNP * Config = UPNPConfig; + int i; + + while (Config) + { + if (devlist == NULL) + { + devlist = upnpDiscover(2000, multicastif, minissdpdpath, localport, ipv6, ttl, &error); + + if (devlist == NULL) + { + Consoleprintf("Failed to find a UPNP device"); + return 0; + } + + i = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr)); + } + + DeleteMap(devlist->descURL, Config->LANport, Config->WANPort, Config->Protocol); + Config = Config->Next; + } + + return 0; +} + +int AddMap(char * controlURL, char * eport, char * iport, char * proto) +{ + int r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, + eport, iport, lanaddr, desc, + proto, remoteHost, leaseDuration); + + if (r != UPNPCOMMAND_SUCCESS) + { + Consoleprintf("UPNP AddPortMapping(%s, %s, %s) failed with code %d (%s)", eport, iport, lanaddr, r, strupnperror(r)); + return -2; + } + Consoleprintf("UPNP AddPortMapping(%s, %s, %s) Succeeded", eport, iport, lanaddr, r); + return 0; +} + +int DeleteMap(char * controlURL, char * eport, char * iport, char * proto) +{ + int r = UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, eport, proto, remoteHost); + + if(r != UPNPCOMMAND_SUCCESS) + { + Consoleprintf("UPNP DeletePortMapping(%s, %s, %s) failed with code %d (%s)", eport, iport, lanaddr, r, strupnperror(r)); + return -2; + } + Consoleprintf("UPNP DeletePortMapping(%s, %s, %s) Succeeded", eport, iport, lanaddr, r); + + return 0; +} + + + +