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/BPQWinAPP.vcproj.NOTTSDESKTOP.John.user b/BPQWinAPP.vcproj.NOTTSDESKTOP.John.user new file mode 100644 index 0000000..fa82c00 --- /dev/null +++ b/BPQWinAPP.vcproj.NOTTSDESKTOP.John.user @@ -0,0 +1,65 @@ + + + + + + + + + + + diff --git a/Bpq32.c b/Bpq32.c index f2c5451..bc76ca0 100644 --- a/Bpq32.c +++ b/Bpq32.c @@ -1086,7 +1086,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses // Add ? and * wildcards to NODES command (74) // Add Port RADIO config parameter (74) -// Version 6.0.24.1 August 2023 +// Version 6.0.24.1 August 2024 // Apply NODES command wildcard to alias as well a call (2) // Add STOPPORT/STARTPORT to VARA Driver (2) @@ -1203,6 +1203,11 @@ 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) +// Disable CTS check in WriteComBlock (26) +// Improvments to reporting to M0LTE Map (26) +// IPGateway fix from github user isavitsky (27) #define CKernel @@ -2065,7 +2070,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.NOTTSDESKTOP.John.user b/CBPQ32.vcproj.NOTTSDESKTOP.John.user new file mode 100644 index 0000000..f4ba73a --- /dev/null +++ b/CBPQ32.vcproj.NOTTSDESKTOP.John.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..abcbee1 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; @@ -917,9 +917,8 @@ BOOL ProcessIncommingConnectEx(struct TNCINFO * TNC, char * Call, int Stream, BO PMSGWITHLEN buffptr; int Totallen = 0; UCHAR * ptr; - struct PORTCONTROL * PORT = TNC->PortRecord; + struct PORTCONTROL * PORT = (struct PORTCONTROL *)TNC->PortRecord; - // Stop Scanner if (Stream == 0 || TNC->Hardware == H_UZ7HO) @@ -2365,8 +2364,8 @@ BOOL WriteCOMBlock(HANDLE fd, char * Block, int BytesToWrite) Err = GetCommModemStatus(fd, &Mask); - if ((Mask & MS_CTS_ON) == 0) // trap com0com other end not open - return TRUE; +// if ((Mask & MS_CTS_ON) == 0) // trap com0com other end not open +// return TRUE; fWriteStat = WriteFile(fd, Block, BytesToWrite, &BytesWritten, NULL ); @@ -3682,7 +3681,7 @@ VOID OpenReportingSockets() { // Enable Node Map Reports - ReportTimer = 600; + ReportTimer = 60; ReportSocket = socket(AF_INET,SOCK_DGRAM,0); @@ -4877,7 +4876,7 @@ static char HeaderTemplate[] = "POST %s HTTP/1.1\r\n" "Content-Type: application/json\r\n" "Host: %s:%d\r\n" "Content-Length: %d\r\n" - //r\nUser-Agent: BPQ32(G8BPQ)\r\n" + "User-Agent: %s%s\r\n" // "Expect: 100-continue\r\n" "\r\n"; @@ -4891,7 +4890,11 @@ VOID SendWebRequest(SOCKET sock, char * Host, char * Request, char * Params, int char * ptr, * ptr1; int Sent; - sprintf(Header, HeaderTemplate, Request, Host, 80, Len, Params); +#ifdef LINBPQ + sprintf(Header, HeaderTemplate, Request, Host, 80, Len, "linbpq/", VersionString, Params); +#else + sprintf(Header, HeaderTemplate, Request, Host, 80, Len, "bpq32/", VersionString, Params); +#endif Sent = send(sock, Header, (int)strlen(Header), 0); Sent = send(sock, Params, (int)strlen(Params), 0); @@ -4986,17 +4989,81 @@ VOID SendWebRequest(SOCKET sock, char * Host, char * Request, char * Params, int extern char MYALIASLOPPED[10]; extern int MasterPort[MAXBPQPORTS+1]; + +// G7TAJ // +/* + {"mheard": [ + { + "Callsign": "GB7CIP-7", + "Port": "VHF", + "Packets": 70369, + "LastHeard": "2024-12-29 20:26:32" + }, +*/ + +void BuildPortMH(char * MHJSON, struct PORTCONTROL * PORT) +{ + struct tm * TM; + static char MHTIME[50]; + time_t szClock; + MHSTRUC * MH = PORT->PORTMHEARD; + int count = MHENTRIES; + char Normcall[20]; + int len; + char * ptr; + char mhstr[400]; + + if (MH == NULL) + return; + + while (count--) + { + if (MH->MHCALL[0] == 0) + break; + + len = ConvFromAX25(MH->MHCALL, Normcall); + Normcall[len] = 0; + + ptr = &MH->MHCALL[6]; // End of Address bit + + if ((*ptr & 1) == 0) + { + // at least one digi - which we are not going to include + MH++; + continue; + } + + Normcall[len++] = 0; + + //format TIME + + szClock = MH->MHTIME; + TM = gmtime(&szClock); + sprintf(MHTIME, "%d-%d-%d %02d:%02d:%02d", + TM->tm_year+1900, TM->tm_mon + 1, TM->tm_mday, TM->tm_hour, TM->tm_min, TM->tm_sec); + + sprintf(mhstr, "{\"callSign\": \"%s\", \"port\": \"%d\", \"packets\": %d, \"lastHeard\": \"%s\" },\r\n" , + Normcall, PORT->PORTNUMBER, MH->MHCOUNT, MHTIME); + + strcat( MHJSON, mhstr ); + + MH++; + } +} + + void SendDataToPktMap(char *Msg) { SOCKET sock; char Return[256]; char Request[64]; char Params[50000]; + struct PORTCONTROL * PORT = PORTTABLE; struct PORTCONTROL * SAVEPORT; struct ROUTE * Routes = NEIGHBOURS; int MaxRoutes = MAXNEIGHBOURS; - + int PortNo; int Active; uint64_t Freq; @@ -5012,10 +5079,19 @@ void SendDataToPktMap(char *Msg) int Port = 0; char Normcall[10]; char Copy[20]; + char ID[33]; char * ptr = Params; - printf("Sending to new map\n"); +// G7TAJ // + char MHJSON[50000]; + char * mhptr; + char * b4Routesptr; + + MHJSON[0]=0; +// G7TAJ // + +// printf("Sending to new map\n"); sprintf(Request, "/api/NodeData/%s", MYNODECALL); @@ -5058,6 +5134,11 @@ void SendDataToPktMap(char *Msg) #endif ptr += sprintf(ptr, "\"source\": \"ReportedByNode\",\r\n"); +// G7TAJ // + sprintf(MHJSON, ",\"mheard\": ["); +// G7TAJ // + + //Ports ptr += sprintf(ptr, "\"ports\": ["); @@ -5232,7 +5313,7 @@ void SendDataToPktMap(char *Msg) // TCP - Mode = Modenames[TNC->Hardware]; + Mode = Modenames[TNC->Hardware - 1]; if (TNC->CONNECTED) Active = 1; @@ -5258,14 +5339,27 @@ void SendDataToPktMap(char *Msg) if (Active) { + char * ptr2 = &ID[29]; + strcpy(ID, PORT->PORTDESCRIPTION); + while (*(ptr2) == ' ' && ptr2 != ID) + *(ptr2--) = 0; + ptr += sprintf(ptr, "{\"id\": \"%d\",\"linkType\": \"%s\"," "\"freq\": \"%lld\",\"mode\": \"%s\",\"modulation\": \"%s\"," "\"baud\": \"%d\",\"bitrate\": \"%d\",\"usage\": \"%s\",\"comment\": \"%s\"},\r\n", PortNo, Type, Freq, Mode, Modulation, - Baud, Bitrate, "Access", PORT->PORTDESCRIPTION); + Baud, Bitrate, "Access", ID); + +// G7TAJ // + // make MH list to be added later + BuildPortMH(MHJSON, PORT); + +// G7TAJ // + + } - + PORT = PORT->PORTPOINTER; } @@ -5274,6 +5368,10 @@ void SendDataToPktMap(char *Msg) // Neighbours +// G7TAJ // + b4Routesptr = ptr-3; +// G7TAJ // + ptr += sprintf(ptr, "\"neighbours\": [\r\n"); while (MaxRoutes--) @@ -5284,7 +5382,7 @@ void SendDataToPktMap(char *Msg) ConvFromAX25(Routes->NEIGHBOUR_CALL, Normcall); strlop(Normcall, ' '); - ptr += sprintf(ptr, + ptr += sprintf(ptr, "{\"node\": \"%s\", \"port\": \"%d\", \"quality\": \"%d\"},\r\n", Normcall, Routes->NEIGHBOUR_PORT, Routes->NEIGHBOUR_QUAL); } @@ -5292,8 +5390,30 @@ void SendDataToPktMap(char *Msg) Routes++; } - ptr -= 3; - ptr += sprintf(ptr, "]}"); +// G7TAJ // + + // if !strstr quality, then there are none, so remove neighbours portion + if ( strstr(Params, "quality") == NULL ) { + ptr = b4Routesptr; + } else { + ptr -= 3; + ptr += sprintf(ptr, "]"); + } + + if ( strlen(MHJSON) > 15 ) { + mhptr = MHJSON + strlen(MHJSON); + mhptr -= 3; + sprintf(mhptr, "]\r\n"); + ptr += sprintf(ptr, "\r\n%s", MHJSON); + + } + + ptr += sprintf(ptr, "}"); + + + +// G7TAJ // + /* { 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/GetVersion.h b/GetVersion.h index c239ae1..d830bef 100644 --- a/GetVersion.h +++ b/GetVersion.h @@ -11,13 +11,14 @@ void GetVersionInfo(char * File) char isDebug[40]=""; #ifdef SPECIALVERSION + strcat(isDebug, " "); strcat(isDebug, SPECIALVERSION); #endif #ifdef _DEBUG - strcat(isDebug, "Debug Build "); + strcat(isDebug, " Debug Build"); #endif - sprintf(VersionString,"%d.%d.%d.%d %s", Ver[0], Ver[1], Ver[2], Ver[3], isDebug); + sprintf(VersionString,"%d.%d.%d.%d%s", Ver[0], Ver[1], Ver[2], Ver[3], isDebug); sprintf(TextVerstring,"V%d.%d.%d.%d", Ver[0], Ver[1], Ver[2], Ver[3]); 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/IPCode.c b/IPCode.c index efc4d91..7958b73 100644 --- a/IPCode.c +++ b/IPCode.c @@ -4539,6 +4539,50 @@ void OpenTAP() return; } + // Fix from github user isavitsky + + /* + * After some research I found that on most of my + * systems, including Raspberry Pi IV, a slight delay + * is needed before considering the TAP device + * up and running. Otherwise the interface structures + * do not initialise properly and later in the code + * around the line 4700 when we initialise our ARP + * structure: + * + * memcpy(Arp->HWADDR, xbuffer.ifr_hwaddr.sa_data, 6); + * + * the MAC address is getting filled in with random + * value which makes the communication via our TAP + * device using the configured IPADDR virtually + * impossible. + * + */ + + Debugprintf("Waiting for the TAP to become UP and RUNNING"); + + for (int i=10; i>0; i--) + { + Sleep(10); + + if ((err = ioctl(sockfd, SIOCGIFFLAGS, &ifr)) < 0) + { + perror("SIOCGIFFLAGS"); + return; + } + + if((ifr.ifr_flags & IFF_UP) && (ifr.ifr_flags & IFF_RUNNING)) + { + Debugprintf("TAP is UP and RUNNING"); + break; + } + else if (i == 1) + { + Debugprintf("TAP is still not UP and RUNNING"); + return; + } + } + printf("TAP brought up\n"); // Set MTU to 256 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/NNTPRoutines.c b/NNTPRoutines.c index 2875a06..16b6478 100644 --- a/NNTPRoutines.c +++ b/NNTPRoutines.c @@ -41,6 +41,87 @@ char *day[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; VOID ReleaseNNTPSock(SOCKET sock); +int NNTPSendSock(SocketConn * sockptr, char * msg) +{ + int len = (int)strlen(msg); + char * newmsg = malloc(len+10); + + WriteLogLine(NULL, '>',msg, len, LOG_TCP); + + strcpy(newmsg, msg); + + strcat(newmsg, "\r\n"); + + len+=2; + + // Attempt to fix Thunderbird - Queue all and send at end + + if ((sockptr->SendSize + len) > sockptr->SendBufferSize) + { + sockptr->SendBufferSize += (10000 + len); + sockptr->SendBuffer = realloc(sockptr->SendBuffer, sockptr->SendBufferSize); + } + + memcpy(&sockptr->SendBuffer[sockptr->SendSize], newmsg, len); + sockptr->SendSize += len; + free (newmsg); + return len; +} + +void NNTPFlush(SocketConn * sockptr) +{ + int sent; + + sent = send(sockptr->socket, sockptr->SendBuffer, sockptr->SendSize, 0); + + if (sent < sockptr->SendSize) + { + int error, remains; + + // Not all could be sent - queue rest + + if (sent == SOCKET_ERROR) + { + error = WSAGetLastError(); + if (error == WSAEWOULDBLOCK) + sent=0; + + // What else?? + } + + remains = sockptr->SendSize - sent; + + sockptr->SendBufferSize += (10000 + remains); + sockptr->SendBuffer = malloc(sockptr->SendBufferSize); + + memmove(sockptr->SendBuffer, &sockptr->SendBuffer[sent], remains); + + sockptr->SendSize = remains; + sockptr->SendPtr = 0; + + return; + } + + free(sockptr->SendBuffer); + sockptr->SendBuffer = NULL; + sockptr->SendSize = 0; + sockptr->SendBufferSize = 0; + return; +} + +VOID __cdecl NNTPsockprintf(SocketConn * sockptr, const char * format, ...) +{ + // printf to a socket + + char buff[1000]; + va_list(arglist); + + va_start(arglist, format); + vsprintf(buff, format, arglist); + + NNTPSendSock(sockptr, buff); +} + struct NNTPRec * LookupNNTP(char * Group) { struct NNTPRec * ptr = FirstNNTPRec; @@ -304,7 +385,7 @@ VOID ProcessNNTPServerMessage(SocketConn * sockptr, char * Buffer, int Len) if (ptr2 == NULL) { - SendSock(sockptr, "500 Eh"); + NNTPSendSock(sockptr, "500 Eh"); return; } @@ -428,7 +509,7 @@ VOID ProcessNNTPServerMessage(SocketConn * sockptr, char * Buffer, int Len) sockptr->Flags &= ~GETTINGMESSAGE; - SendSock(sockptr, "240 OK"); + NNTPSendSock(sockptr, "240 OK"); return; } @@ -459,13 +540,13 @@ VOID ProcessNNTPServerMessage(SocketConn * sockptr, char * Buffer, int Len) if (Len > 22) Buffer[22]=0; strcpy(sockptr->CallSign, &Buffer[14]); sockptr->State = GettingPass; - sockprintf(sockptr, "381 More authentication information required"); + NNTPsockprintf(sockptr, "381 More authentication information required"); return; } if (sockptr->State == GettingUser) { - sockprintf(sockptr, "480 Authentication required"); + NNTPsockprintf(sockptr, "480 Authentication required"); return; } @@ -481,19 +562,19 @@ VOID ProcessNNTPServerMessage(SocketConn * sockptr, char * Buffer, int Len) { if (strcmp(user->pass, &Buffer[14]) == 0) { - sockprintf(sockptr, "281 Authentication accepted"); + NNTPsockprintf(sockptr, "281 Authentication accepted"); sockptr->State = Authenticated; sockptr->POP3User = user; return; } } - SendSock(sockptr, "482 Authentication rejected"); + NNTPSendSock(sockptr, "482 Authentication rejected"); sockptr->State = GettingUser; return; } - sockprintf(sockptr, "480 Authentication required"); + NNTPsockprintf(sockptr, "480 Authentication required"); return; } @@ -506,7 +587,7 @@ VOID ProcessNNTPServerMessage(SocketConn * sockptr, char * Buffer, int Len) { if (_stricmp(REC->NewsGroup, &Buffer[6]) == 0) { - sockprintf(sockptr, "211 %d %d %d %s", REC->Count, REC->FirstMsg, REC->LastMsg, REC->NewsGroup); + NNTPsockprintf(sockptr, "211 %d %d %d %s", REC->Count, REC->FirstMsg, REC->LastMsg, REC->NewsGroup); sockptr->NNTPNum = 0; sockptr->NNTPGroup = REC; return; @@ -514,7 +595,7 @@ VOID ProcessNNTPServerMessage(SocketConn * sockptr, char * Buffer, int Len) REC =REC->Next; } - sockprintf(sockptr, "411 no such news group"); + NNTPsockprintf(sockptr, "411 no such news group"); return; } @@ -528,7 +609,7 @@ VOID ProcessNNTPServerMessage(SocketConn * sockptr, char * Buffer, int Len) if (REC == NULL && Buffer[10] == 0) { - sockprintf(sockptr, "412 No Group Selected"); + NNTPsockprintf(sockptr, "412 No Group Selected"); return; } @@ -543,7 +624,7 @@ VOID ProcessNNTPServerMessage(SocketConn * sockptr, char * Buffer, int Len) { GotGroup: - sockprintf(sockptr, "211 Article Numbers Follows"); + NNTPsockprintf(sockptr, "211 Article Numbers Follows"); sockptr->NNTPNum = 0; sockptr->NNTPGroup = REC; @@ -557,22 +638,22 @@ VOID ProcessNNTPServerMessage(SocketConn * sockptr, char * Buffer, int Len) sprintf(FullGroup, "%s.%s", Msg->to, Msg->via ); if (_stricmp(FullGroup, REC->NewsGroup) == 0) { - sockprintf(sockptr, "%d", MsgNo); + NNTPsockprintf(sockptr, "%d", MsgNo); } } } - SendSock(sockptr,"."); + NNTPSendSock(sockptr,"."); return; } REC = REC->Next; } - sockprintf(sockptr, "411 no such news group"); + NNTPsockprintf(sockptr, "411 no such news group"); return; } if(_memicmp(Buffer, "MODE READER", 11) == 0) { - SendSock(sockptr, "200 Hello"); + NNTPSendSock(sockptr, "200 Hello"); return; } @@ -580,15 +661,15 @@ VOID ProcessNNTPServerMessage(SocketConn * sockptr, char * Buffer, int Len) { struct NNTPRec * REC = FirstNNTPRec; - SendSock(sockptr, "215 list of newsgroups follows"); + NNTPSendSock(sockptr, "215 list of newsgroups follows"); while (REC) { - sockprintf(sockptr, "%s %d %d y", REC->NewsGroup, REC->LastMsg, REC->FirstMsg); + NNTPsockprintf(sockptr, "%s %d %d y", REC->NewsGroup, REC->LastMsg, REC->FirstMsg); REC = REC->Next; } - SendSock(sockptr,"."); + NNTPSendSock(sockptr,"."); return; } @@ -615,16 +696,16 @@ VOID ProcessNNTPServerMessage(SocketConn * sockptr, char * Buffer, int Len) else Time = mktime(&rtime); - SendSock(sockptr, "231 list of new newsgroups follows"); + NNTPSendSock(sockptr, "231 list of new newsgroups follows"); while(REC) { if (REC->DateCreated > Time) - sockprintf(sockptr, "%s %d %d y", REC->NewsGroup, REC->LastMsg, REC->FirstMsg); + NNTPsockprintf(sockptr, "%s %d %d y", REC->NewsGroup, REC->LastMsg, REC->FirstMsg); REC = REC->Next; } - SendSock(sockptr,"."); + NNTPSendSock(sockptr,"."); return; } @@ -636,7 +717,7 @@ VOID ProcessNNTPServerMessage(SocketConn * sockptr, char * Buffer, int Len) if (REC == NULL) { - SendSock(sockptr,"412 no newsgroup has been selected"); + NNTPSendSock(sockptr,"412 no newsgroup has been selected"); return; } @@ -646,7 +727,7 @@ VOID ProcessNNTPServerMessage(SocketConn * sockptr, char * Buffer, int Len) if (MsgNo == 0) { - SendSock(sockptr,"420 no current article has been selected"); + NNTPSendSock(sockptr,"420 no current article has been selected"); return; } } @@ -659,20 +740,20 @@ VOID ProcessNNTPServerMessage(SocketConn * sockptr, char * Buffer, int Len) if (Msg) { - sockprintf(sockptr, "221 %d <%s>", MsgNo, Msg->bid); + NNTPsockprintf(sockptr, "221 %d <%s>", MsgNo, Msg->bid); - sockprintf(sockptr, "From: %s", Msg->from); - sockprintf(sockptr, "Date: %s", FormatNNTPDateAndTime((time_t)Msg->datecreated)); - sockprintf(sockptr, "Newsgroups: %s.s", Msg->to, Msg->via); - sockprintf(sockptr, "Subject: %s", Msg->title); - sockprintf(sockptr, "Message-ID: <%s>", Msg->bid); - sockprintf(sockptr, "Path: %s", BBSName); + NNTPsockprintf(sockptr, "From: %s", Msg->from); + NNTPsockprintf(sockptr, "Date: %s", FormatNNTPDateAndTime((time_t)Msg->datecreated)); + NNTPsockprintf(sockptr, "Newsgroups: %s.s", Msg->to, Msg->via); + NNTPsockprintf(sockptr, "Subject: %s", Msg->title); + NNTPsockprintf(sockptr, "Message-ID: <%s>", Msg->bid); + NNTPsockprintf(sockptr, "Path: %s", BBSName); - SendSock(sockptr,"."); + NNTPSendSock(sockptr,"."); return; } - SendSock(sockptr,"423 No such article in this newsgroup"); + NNTPSendSock(sockptr,"423 No such article in this newsgroup"); return; } @@ -686,7 +767,7 @@ VOID ProcessNNTPServerMessage(SocketConn * sockptr, char * Buffer, int Len) if (REC == NULL) { - SendSock(sockptr,"412 no newsgroup has been selected"); + NNTPSendSock(sockptr,"412 no newsgroup has been selected"); return; } @@ -696,7 +777,7 @@ VOID ProcessNNTPServerMessage(SocketConn * sockptr, char * Buffer, int Len) if (MsgNo == 0) { - SendSock(sockptr,"420 no current article has been selected"); + NNTPSendSock(sockptr,"420 no current article has been selected"); return; } } @@ -709,25 +790,25 @@ VOID ProcessNNTPServerMessage(SocketConn * sockptr, char * Buffer, int Len) if (Msg) { - sockprintf(sockptr, "220 %d <%s>", MsgNo, Msg->bid); + NNTPsockprintf(sockptr, "220 %d <%s>", MsgNo, Msg->bid); msgbytes = ReadMessageFile(Msg->number); Path = GetPathFromHeaders(msgbytes); - sockprintf(sockptr, "From: %s", Msg->from); - sockprintf(sockptr, "Date: %s", FormatNNTPDateAndTime((time_t)Msg->datecreated)); - sockprintf(sockptr, "Newsgroups: %s.%s", Msg->to, Msg->via); - sockprintf(sockptr, "Subject: %s", Msg->title); - sockprintf(sockptr, "Message-ID: <%s>", Msg->bid); - sockprintf(sockptr, "Path: %s", &Path[1]); + NNTPsockprintf(sockptr, "From: %s", Msg->from); + NNTPsockprintf(sockptr, "Date: %s", FormatNNTPDateAndTime((time_t)Msg->datecreated)); + NNTPsockprintf(sockptr, "Newsgroups: %s.%s", Msg->to, Msg->via); + NNTPsockprintf(sockptr, "Subject: %s", Msg->title); + NNTPsockprintf(sockptr, "Message-ID: <%s>", Msg->bid); + NNTPsockprintf(sockptr, "Path: %s", &Path[1]); - SendSock(sockptr,""); + NNTPSendSock(sockptr,""); - SendSock(sockptr,msgbytes); - SendSock(sockptr,""); + NNTPSendSock(sockptr,msgbytes); + NNTPSendSock(sockptr,""); - SendSock(sockptr,"."); + NNTPSendSock(sockptr,"."); free(msgbytes); free(Path); @@ -735,7 +816,7 @@ VOID ProcessNNTPServerMessage(SocketConn * sockptr, char * Buffer, int Len) return; } - SendSock(sockptr,"423 No such article in this newsgroup"); + NNTPSendSock(sockptr,"423 No such article in this newsgroup"); return; } @@ -749,7 +830,7 @@ VOID ProcessNNTPServerMessage(SocketConn * sockptr, char * Buffer, int Len) if (REC == NULL) { - SendSock(sockptr,"412 no newsgroup has been selected"); + NNTPSendSock(sockptr,"412 no newsgroup has been selected"); return; } @@ -759,7 +840,7 @@ VOID ProcessNNTPServerMessage(SocketConn * sockptr, char * Buffer, int Len) if (MsgNo == 0) { - SendSock(sockptr,"420 no current article has been selected"); + NNTPSendSock(sockptr,"420 no current article has been selected"); return; } } @@ -772,15 +853,15 @@ VOID ProcessNNTPServerMessage(SocketConn * sockptr, char * Buffer, int Len) if (Msg) { - sockprintf(sockptr, "222 %d <%s>", MsgNo, Msg->bid); + NNTPsockprintf(sockptr, "222 %d <%s>", MsgNo, Msg->bid); msgbytes = ReadMessageFile(Msg->number); Path = GetPathFromHeaders(msgbytes); - SendSock(sockptr,msgbytes); - SendSock(sockptr,""); + NNTPSendSock(sockptr,msgbytes); + NNTPSendSock(sockptr,""); - SendSock(sockptr,"."); + NNTPSendSock(sockptr,"."); free(msgbytes); free(Path); @@ -788,7 +869,7 @@ VOID ProcessNNTPServerMessage(SocketConn * sockptr, char * Buffer, int Len) return; } - SendSock(sockptr,"423 No such article in this newsgroup"); + NNTPSendSock(sockptr,"423 No such article in this newsgroup"); return; } @@ -801,7 +882,7 @@ VOID ProcessNNTPServerMessage(SocketConn * sockptr, char * Buffer, int Len) if (REC == NULL) { - SendSock(sockptr,"412 no newsgroup has been selected"); + NNTPSendSock(sockptr,"412 no newsgroup has been selected"); return; } @@ -821,7 +902,7 @@ VOID ProcessNNTPServerMessage(SocketConn * sockptr, char * Buffer, int Len) if (MsgStart == 0) { - SendSock(sockptr,"420 no current article has been selected"); + NNTPSendSock(sockptr,"420 no current article has been selected"); return; } } @@ -830,7 +911,7 @@ VOID ProcessNNTPServerMessage(SocketConn * sockptr, char * Buffer, int Len) sockptr->NNTPNum = MsgEnd; } - sockprintf(sockptr, "221 "); + NNTPsockprintf(sockptr, "221 "); for (MsgNo = MsgStart; MsgNo <= MsgEnd; MsgNo++) { @@ -843,20 +924,20 @@ VOID ProcessNNTPServerMessage(SocketConn * sockptr, char * Buffer, int Len) if (_stricmp(FullGroup, REC->NewsGroup) == 0) { if (_stricmp(Header, "subject") == 0) - sockprintf(sockptr, "%d Subject: %s", MsgNo, Msg->title); + NNTPsockprintf(sockptr, "%d Subject: %s", MsgNo, Msg->title); else if (_stricmp(Header, "from") == 0) - sockprintf(sockptr, "%d From: %s", MsgNo, Msg->from); + NNTPsockprintf(sockptr, "%d From: %s", MsgNo, Msg->from); else if (_stricmp(Header, "date") == 0) - sockprintf(sockptr, "%d Date: %s", MsgNo, FormatNNTPDateAndTime((time_t)Msg->datecreated)); + NNTPsockprintf(sockptr, "%d Date: %s", MsgNo, FormatNNTPDateAndTime((time_t)Msg->datecreated)); else if (_stricmp(Header, "message-id") == 0) - sockprintf(sockptr, "%d Message-ID: <%s>", MsgNo, Msg->bid); + NNTPsockprintf(sockptr, "%d Message-ID: <%s>", MsgNo, Msg->bid); else if (_stricmp(Header, "lines") == 0) - sockprintf(sockptr, "%d Lines: %d", MsgNo, Msg->length); + NNTPsockprintf(sockptr, "%d Lines: %d", MsgNo, Msg->length); } } } - SendSock(sockptr,"."); + NNTPSendSock(sockptr,"."); return; } @@ -869,7 +950,7 @@ VOID ProcessNNTPServerMessage(SocketConn * sockptr, char * Buffer, int Len) if (REC == NULL) { - SendSock(sockptr,"412 no newsgroup has been selected"); + NNTPSendSock(sockptr,"412 no newsgroup has been selected"); return; } @@ -887,7 +968,7 @@ VOID ProcessNNTPServerMessage(SocketConn * sockptr, char * Buffer, int Len) if (MsgStart == 0) { - SendSock(sockptr,"420 no current article has been selected"); + NNTPSendSock(sockptr,"420 no current article has been selected"); return; } } @@ -896,7 +977,7 @@ VOID ProcessNNTPServerMessage(SocketConn * sockptr, char * Buffer, int Len) sockptr->NNTPNum = MsgEnd; } - sockprintf(sockptr, "224 "); + NNTPsockprintf(sockptr, "224 "); for (MsgNo = MsgStart; MsgNo <= MsgEnd; MsgNo++) { @@ -909,14 +990,14 @@ VOID ProcessNNTPServerMessage(SocketConn * sockptr, char * Buffer, int Len) if (_stricmp(FullGroup, REC->NewsGroup) == 0) { // subject, author, date, message-id, references, byte count, and line count. - sockprintf(sockptr, "%d\t%s\t%s\t%s\t%s\t%s\t%d\t%d", + NNTPsockprintf(sockptr, "%d\t%s\t%s\t%s\t%s\t%s\t%d\t%d", MsgNo, Msg->title, Msg->from, FormatNNTPDateAndTime((time_t)Msg->datecreated), Msg->bid, "", Msg->length, Msg->length); } } } - SendSock(sockptr,"."); + NNTPSendSock(sockptr,"."); return; } @@ -932,7 +1013,7 @@ VOID ProcessNNTPServerMessage(SocketConn * sockptr, char * Buffer, int Len) { if (sockptr->State != Authenticated) { - sockprintf(sockptr, "480 Authentication required"); + NNTPsockprintf(sockptr, "480 Authentication required"); return; } @@ -942,7 +1023,7 @@ VOID ProcessNNTPServerMessage(SocketConn * sockptr, char * Buffer, int Len) if (sockptr->MailBuffer == NULL) { CriticalErrorHandler("Failed to create POP3 Message Buffer"); - SendSock(sockptr, "QUIT"); + NNTPSendSock(sockptr, "QUIT"); sockptr->State = WaitingForQUITResponse; shutdown(sock, 0); @@ -951,7 +1032,7 @@ VOID ProcessNNTPServerMessage(SocketConn * sockptr, char * Buffer, int Len) sockptr->Flags |= GETTINGMESSAGE; - SendSock(sockptr, "340 OK"); + NNTPSendSock(sockptr, "340 OK"); return; } @@ -959,7 +1040,7 @@ VOID ProcessNNTPServerMessage(SocketConn * sockptr, char * Buffer, int Len) if(_memicmp(Buffer, "QUIT", 4) == 0) { - SendSock(sockptr, "205 OK"); + NNTPSendSock(sockptr, "205 OK"); Sleep(500); shutdown(sock, 0); return; @@ -967,7 +1048,7 @@ VOID ProcessNNTPServerMessage(SocketConn * sockptr, char * Buffer, int Len) /* if(memcmp(Buffer, "RSET\r\n", 6) == 0) { - SendSock(sockptr, "250 Ok"); + NNTPSendSock(sockptr, "250 Ok"); sockptr->State = 0; sockptr->Recipients; return; @@ -991,15 +1072,15 @@ VOID ProcessNNTPServerMessage(SocketConn * sockptr, char * Buffer, int Len) sprintf_s(Date, sizeof(Date), "111 %04d%02d%02d%02d%02d%02d", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); - SendSock(sockptr, Date); + NNTPSendSock(sockptr, Date); } else - SendSock(sockptr, "500 command not recognized"); + NNTPSendSock(sockptr, "500 command not recognized"); return; } - SendSock(sockptr, "500 command not recognized"); + NNTPSendSock(sockptr, "500 command not recognized"); return; } @@ -1068,6 +1149,9 @@ loop: } } + + NNTPFlush(sockptr); + return 0; } @@ -1110,9 +1194,11 @@ int NNTP_Accept(SOCKET SocketId) sockptr->socket = sock; sockptr->State = 0; - SendSock(sockptr, "200 BPQMail NNTP Server ready"); + NNTPSendSock(sockptr, "200 BPQMail NNTP Server ready"); Logprintf(LOG_TCP, NULL, '|', "Incoming NNTP Connect Socket = %d", sock); + NNTPFlush(sockptr); + return 0; } /* @@ -1144,7 +1230,7 @@ int NNTP_Data(int sock, int error, int eventcode) SendFromQueue(sockptr); else { - SendSock(sockptr, "200 BPQMail NNTP Server ready"); + NNTPSendSock(sockptr, "200 BPQMail NNTP Server ready"); // sockptr->State = GettingUser; } 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..d86948c 100644 --- a/Versions.h +++ b/Versions.h @@ -10,16 +10,16 @@ #endif -#define KVers 6,0,24,22 -#define KVerstring "6.0.24.22\0" +#define KVers 6,0,24,27 +#define KVerstring "6.0.24.27\0" #ifdef CKernel #define Vers KVers #define Verstring KVerstring -#define Datestring "November 2023" +#define Datestring "January 2024" #define VerComments "G8BPQ Packet Switch (C Version)" KVerstring -#define VerCopyright "Copyright © 2001-2023 John Wiseman G8BPQ\0" +#define VerCopyright "Copyright © 2001-2024 John Wiseman G8BPQ\0" #define VerDesc "BPQ32 Switch\0" #define VerProduct "BPQ32" @@ -30,7 +30,7 @@ #define Vers 1,0,16,2 #define Verstring "1.0.16.2\0" #define VerComments "Internet Terminal for G8BPQ Packet Switch\0" -#define VerCopyright "Copyright © 2011-2023 John Wiseman G8BPQ\0" +#define VerCopyright "Copyright © 2011-2024 John Wiseman G8BPQ\0" #define VerDesc "Simple TCP Terminal Program for G8BPQ Switch\0" #define VerProduct "BPQTermTCP" @@ -41,7 +41,7 @@ #define Vers 2,2,5,2 #define Verstring "2.2.5.2\0" #define VerComments "Simple Terminal for G8BPQ Packet Switch\0" -#define VerCopyright "Copyright © 1999-2023 John Wiseman G8BPQ\0" +#define VerCopyright "Copyright © 1999-2024 John Wiseman G8BPQ\0" #define VerDesc "Simple Terminal Program for G8BPQ Switch\0" #define VerProduct "BPQTerminal" @@ -52,7 +52,7 @@ #define Vers 2,2,0,3 #define Verstring "2.2.0.3\0" #define VerComments "MDI Terminal for G8BPQ Packet Switch\0" -#define VerCopyright "Copyright © 1999-2023 John Wiseman G8BPQ\0" +#define VerCopyright "Copyright © 1999-2024 John Wiseman G8BPQ\0" #define VerDesc "MDI Terminal Program for G8BPQ Switch\0" #endif @@ -62,7 +62,7 @@ #define Vers KVers #define Verstring KVerstring #define VerComments "Mail server for G8BPQ Packet Switch\0" -#define VerCopyright "Copyright © 2009-2023 John Wiseman G8BPQ\0" +#define VerCopyright "Copyright © 2009-2024 John Wiseman G8BPQ\0" #define VerDesc "Mail server for G8BPQ's 32 Bit Switch\0" #define VerProduct "BPQMail" @@ -97,7 +97,7 @@ #define Vers 0,1,0,0 #define Verstring "0.1.0.0\0" #define VerComments "Password Generation Utility for G8BPQ Packet Switch\0" -#define VerCopyright "Copyright © 2011-2023 John Wiseman G8BPQ\0" +#define VerCopyright "Copyright © 2011-2024 John Wiseman G8BPQ\0" #define VerDesc "Password Generation Utility for G8BPQ Switch\0" #endif @@ -107,7 +107,7 @@ #define Vers KVers #define Verstring KVerstring #define VerComments "APRS Client for G8BPQ Switch\0" -#define VerCopyright "Copyright © 2012-2023 John Wiseman G8BPQ\0" +#define VerCopyright "Copyright © 2012-2024 John Wiseman G8BPQ\0" #define VerDesc "APRS Client for G8BPQ Switch\0" #define VerProduct "BPQAPRS" @@ -118,7 +118,7 @@ #define Vers KVers #define Verstring KVerstring #define VerComments "Chat server for G8BPQ Packet Switch\0" -#define VerCopyright "Copyright © 2009-2023 John Wiseman G8BPQ\0" +#define VerCopyright "Copyright © 2009-2024 John Wiseman G8BPQ\0" #define VerDesc "Chat server for G8BPQ's 32 Bit Switch\0" #define VerProduct "BPQChat" 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/WinmorControl.vcproj.NOTTSDESKTOP.John.user b/WinmorControl.vcproj.NOTTSDESKTOP.John.user new file mode 100644 index 0000000..fa82c00 --- /dev/null +++ b/WinmorControl.vcproj.NOTTSDESKTOP.John.user @@ -0,0 +1,65 @@ + + + + + + + + + + + diff --git a/debian/changelog b/debian/changelog index 3f7c7df..ad29ff9 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,7 +1,24 @@ +linbpq (6.0.24.27-1~bpo11+1) bullseye; urgency=medium + + * Rebuild for bullseye. + + -- Dave Hibberd Tue, 16 Jan 2024 20:55:26 +0000 + +linbpq (6.0.24.27-1) unstable; urgency=medium + + * New Upstream Release + + -- Dave Hibberd Tue, 16 Jan 2024 20:51:43 +0000 + +linbpq (6.0.24.25-1) unstable; urgency=medium + + * New Upstream Release + + -- Dave Hibberd Thu, 28 Dec 2023 10:44:47 +0000 + linbpq (6.0.24.22-2~bpo11+1) bullseye; urgency=medium * Rebuild for bullseye. - * -- Dave Hibberd Sat, 16 Dec 2023 14:42:25 +0000 diff --git a/debian/preinst b/debian/preinst index 4dae0eb..c0e122c 100644 --- a/debian/preinst +++ b/debian/preinst @@ -10,3 +10,5 @@ if [ -L $confile ]; then cp $node $confile mv $node $node.bak fi + +#DEBHELPER# 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; +} + + + +