diff --git a/250mS@1000Hz.wav b/250mS@1000Hz.wav new file mode 100644 index 0000000..0079795 Binary files /dev/null and b/250mS@1000Hz.wav differ diff --git a/250mS@600Hz.wav b/250mS@600Hz.wav new file mode 100644 index 0000000..3480a76 Binary files /dev/null and b/250mS@600Hz.wav differ diff --git a/APRSCode.c b/APRSCode.c index 67ab0c2..70327d5 100644 --- a/APRSCode.c +++ b/APRSCode.c @@ -103,6 +103,7 @@ void SaveAPRSMessage(struct APRSMESSAGE * ptr); void ClearSavedMessages(); void GetSavedAPRSMessages(); static VOID GPSDConnect(void * unused); +int CanPortDigi(int Port); extern int SemHeldByAPI; extern int APRSMONDECODE(); @@ -664,9 +665,10 @@ Dll BOOL APIENTRY Init_APRS() memset(&CrossPortMap[0][0], 0, sizeof(CrossPortMap)); memset(&APRSBridgeMap[0][0], 0, sizeof(APRSBridgeMap)); - for (i = 1; i <= 32; i++) + for (i = 1; i <= MaxBPQPortNo; i++) { - CrossPortMap[i][i] = TRUE; // Set Defaults - Same Port + if (CanPortDigi(i)) + CrossPortMap[i][i] = TRUE; // Set Defaults - Same Port CrossPortMap[i][0] = TRUE; // and APRS-IS } @@ -1945,7 +1947,7 @@ static int APRSProcessLine(char * buf) { SendTo = atoi(ptr); // this gives zero for IS - if (SendTo > 32) + if (SendTo > MaxBPQPortNo) return FALSE; Object->PortMap[SendTo] = TRUE; @@ -2175,6 +2177,12 @@ static int APRSProcessLine(char * buf) if (GetPortTableEntryFromPortNum(Port) == NULL) return FALSE; + // Check that port can digi (SCS Pactor can't set digi'd bit in calls) + + if (CanPortDigi(Port) == 0) + return FALSE; + + CrossPortMap[Port][Port] = FALSE; // Cancel Default mapping CrossPortMap[Port][0] = FALSE; // Cancel Default APRSIS @@ -2218,7 +2226,7 @@ static int APRSProcessLine(char * buf) { DigiTo = atoi(ptr); // this gives zero for IS - if (DigiTo > 32) + if (DigiTo > MaxBPQPortNo) return FALSE; APRSBridgeMap[Port][DigiTo] = TRUE; @@ -5238,6 +5246,7 @@ int DecodeAPRSPayload(char * Payload, struct STATIONRECORD * Station) DecodeLocationString(Payload + 18, Object); Object->TimeLastUpdated = time(NULL); + Object->LastPort = Station->LastPort; Station->Object = Object; return 0; @@ -8168,6 +8177,8 @@ VOID APRSCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * else Bufferptr = Cmdprintf(Session, Bufferptr, "but not connected\r"); } + + SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); return; } @@ -8844,7 +8855,7 @@ int GetAPRSPageInfo(char * Buffer, double N, double S, double W, double E, int a if (lastLat != ptr->Lat) Len += sprintf(&Buffer[Len],"%.4f,%.4f,\r\n|", ptr->Lat, ptr->Lon); //Add current position to end of track else - Len += sprintf(&Buffer[Len],"\r\n|", ptr->Lat, ptr->Lon); + Len += sprintf(&Buffer[Len],"\r\n|"); } } } diff --git a/APRSStdPages-HPLaptop.c b/APRSStdPages-HPLaptop.c deleted file mode 100644 index 7cb38e1..0000000 --- a/APRSStdPages-HPLaptop.c +++ /dev/null @@ -1,3719 +0,0 @@ - -#include -#include - -#ifndef WIN32 - -#define _stricmp stricmp -#define _strdup strdup - -int stricmp(const unsigned char * pStr1, const unsigned char *pStr2); - -#endif - -unsigned char aisblue_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, - 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x22, - 0x02, 0x03, 0x00, 0x00, 0x00, 0xcd, 0x06, 0x7a, 0x10, 0x00, 0x00, 0x00, - 0x09, 0x50, 0x4c, 0x54, 0x45, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xff, 0x23, 0xde, 0xb7, 0xa6, 0x00, 0x00, 0x00, 0x01, 0x74, 0x52, - 0x4e, 0x53, 0x00, 0x40, 0xe6, 0xd8, 0x66, 0x00, 0x00, 0x00, 0x01, 0x62, - 0x4b, 0x47, 0x44, 0x00, 0x88, 0x05, 0x1d, 0x48, 0x00, 0x00, 0x00, 0x09, - 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13, - 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, - 0x45, 0x07, 0xe6, 0x01, 0x09, 0x0a, 0x35, 0x03, 0x7a, 0x0e, 0x22, 0xdf, - 0x00, 0x00, 0x00, 0x53, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, 0x60, - 0x80, 0x01, 0x16, 0x3c, 0x94, 0x28, 0x84, 0x92, 0x44, 0xa1, 0x22, 0x1d, - 0xc0, 0x54, 0x16, 0x16, 0x8a, 0x31, 0x2b, 0x00, 0x4c, 0xad, 0x9a, 0x80, - 0x49, 0xb1, 0xae, 0x9a, 0x02, 0xa2, 0xd8, 0x56, 0x2d, 0x41, 0xa6, 0x96, - 0x21, 0xf3, 0xc4, 0x56, 0x2d, 0x05, 0x51, 0x52, 0xab, 0x56, 0x12, 0xa2, - 0xa2, 0x56, 0xad, 0x04, 0x59, 0x98, 0xb5, 0x6a, 0x15, 0x06, 0xc5, 0x08, - 0xa4, 0x02, 0x40, 0xb6, 0xae, 0x02, 0xd9, 0xcb, 0x18, 0x1a, 0x1a, 0x1a, - 0xc0, 0x00, 0x00, 0xd1, 0xed, 0x24, 0x45, 0x35, 0x85, 0xab, 0x6c, 0x00, - 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; -unsigned int aisblue_png_len = 227; -unsigned char aisgreen_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, - 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x22, - 0x02, 0x03, 0x00, 0x00, 0x00, 0xcd, 0x06, 0x7a, 0x10, 0x00, 0x00, 0x00, - 0x0c, 0x50, 0x4c, 0x54, 0x45, 0x61, 0x62, 0x6c, 0x00, 0x00, 0x00, 0x00, - 0xff, 0x00, 0x13, 0xfe, 0x00, 0x1b, 0x46, 0xca, 0x60, 0x00, 0x00, 0x00, - 0x01, 0x74, 0x52, 0x4e, 0x53, 0x00, 0x40, 0xe6, 0xd8, 0x66, 0x00, 0x00, - 0x00, 0x01, 0x62, 0x4b, 0x47, 0x44, 0x00, 0x88, 0x05, 0x1d, 0x48, 0x00, - 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, 0x13, 0x00, - 0x00, 0x0b, 0x13, 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00, 0x07, - 0x74, 0x49, 0x4d, 0x45, 0x07, 0xe6, 0x01, 0x09, 0x0a, 0x35, 0x11, 0x89, - 0xb7, 0x53, 0x97, 0x00, 0x00, 0x00, 0x53, 0x49, 0x44, 0x41, 0x54, 0x08, - 0xd7, 0x63, 0x60, 0x80, 0x01, 0x16, 0x3c, 0x94, 0x28, 0x84, 0x92, 0x44, - 0xa1, 0x22, 0x1d, 0xc0, 0x54, 0x16, 0x16, 0x8a, 0x31, 0x2b, 0x00, 0x4c, - 0xad, 0x9a, 0x80, 0x49, 0xb1, 0xae, 0x9a, 0x02, 0xa2, 0xd8, 0x56, 0x2d, - 0x41, 0xa6, 0x96, 0x21, 0xf3, 0xc4, 0x56, 0x2f, 0x05, 0x51, 0x52, 0xab, - 0x56, 0x12, 0xa2, 0xa2, 0x56, 0xad, 0x04, 0x59, 0x98, 0xb5, 0x6a, 0x15, - 0x06, 0xc5, 0x08, 0xa4, 0x02, 0x40, 0xb6, 0xae, 0x02, 0xd9, 0xcb, 0x18, - 0x1a, 0x1a, 0x1a, 0xc0, 0x00, 0x00, 0xd2, 0x45, 0x24, 0x46, 0xf4, 0x40, - 0x4e, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, - 0x60, 0x82 -}; -unsigned int aisgreen_png_len = 230; -unsigned char yellowplane_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, - 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x27, - 0x08, 0x03, 0x00, 0x00, 0x00, 0xbb, 0x7d, 0xa1, 0x07, 0x00, 0x00, 0x02, - 0xf7, 0x50, 0x4c, 0x54, 0x45, 0x00, 0x00, 0x00, 0x38, 0x44, 0x47, 0x44, - 0x45, 0x46, 0x3b, 0x4c, 0x51, 0x42, 0x4b, 0x4e, 0x3f, 0x4d, 0x51, 0x43, - 0x4e, 0x51, 0x44, 0x4e, 0x51, 0x44, 0x51, 0x54, 0x4b, 0x50, 0x52, 0x42, - 0x54, 0x5a, 0x43, 0x54, 0x5a, 0x4c, 0x52, 0x53, 0x48, 0x53, 0x56, 0x4a, - 0x53, 0x56, 0x4d, 0x53, 0x55, 0x46, 0x57, 0x5c, 0x4b, 0x56, 0x59, 0x4a, - 0x58, 0x5c, 0x4b, 0x58, 0x5b, 0x4f, 0x58, 0x5b, 0x4d, 0x59, 0x5c, 0x4e, - 0x59, 0x5d, 0x53, 0x58, 0x59, 0x50, 0x59, 0x5c, 0x49, 0x5b, 0x5f, 0x4e, - 0x5b, 0x5e, 0x4e, 0x5c, 0x60, 0x52, 0x5b, 0x5e, 0x49, 0x5e, 0x65, 0x4c, - 0x5e, 0x63, 0x52, 0x5d, 0x60, 0x55, 0x5d, 0x5f, 0x53, 0x5e, 0x61, 0x55, - 0x5f, 0x62, 0x53, 0x60, 0x64, 0x54, 0x60, 0x63, 0x54, 0x61, 0x65, 0x55, - 0x61, 0x64, 0x57, 0x61, 0x64, 0x5c, 0x60, 0x60, 0x58, 0x61, 0x64, 0x5a, - 0x61, 0x63, 0x52, 0x63, 0x69, 0x57, 0x62, 0x66, 0x5c, 0x61, 0x63, 0x56, - 0x63, 0x67, 0x5d, 0x62, 0x63, 0x59, 0x63, 0x66, 0x56, 0x64, 0x68, 0x5c, - 0x63, 0x66, 0x5c, 0x64, 0x67, 0x61, 0x65, 0x67, 0x63, 0x65, 0x65, 0x5d, - 0x67, 0x6a, 0x61, 0x66, 0x68, 0x5b, 0x68, 0x6c, 0x63, 0x66, 0x67, 0x5c, - 0x68, 0x6c, 0x59, 0x69, 0x6d, 0x61, 0x67, 0x69, 0x59, 0x69, 0x6f, 0x5e, - 0x68, 0x6b, 0x61, 0x69, 0x6b, 0x61, 0x6a, 0x6d, 0x5a, 0x6c, 0x71, 0x63, - 0x6a, 0x6b, 0x64, 0x6a, 0x6c, 0x66, 0x68, 0x7e, 0x5d, 0x6c, 0x70, 0x66, - 0x6a, 0x6b, 0x65, 0x6b, 0x6d, 0x5b, 0x6f, 0x74, 0x5c, 0x70, 0x75, 0x68, - 0x6d, 0x6e, 0x64, 0x6e, 0x71, 0x5e, 0x70, 0x75, 0x62, 0x6f, 0x73, 0x67, - 0x6e, 0x70, 0x69, 0x6e, 0x6f, 0x69, 0x6e, 0x70, 0x66, 0x6f, 0x72, 0x66, - 0x71, 0x75, 0x6b, 0x70, 0x71, 0x67, 0x71, 0x74, 0x6e, 0x70, 0x70, 0x62, - 0x74, 0x7a, 0x66, 0x74, 0x78, 0x70, 0x72, 0x72, 0x6d, 0x73, 0x75, 0x66, - 0x75, 0x7a, 0x68, 0x75, 0x79, 0x71, 0x73, 0x74, 0x72, 0x74, 0x75, 0x72, - 0x76, 0x77, 0x6c, 0x78, 0x7b, 0x72, 0x77, 0x78, 0x72, 0x77, 0x79, 0x73, - 0x78, 0x79, 0x72, 0x79, 0x7b, 0x72, 0x7b, 0x7e, 0x78, 0x7a, 0x7a, 0x77, - 0x7b, 0x7d, 0x74, 0x7c, 0x7e, 0x75, 0x7c, 0x7e, 0x76, 0x7d, 0x80, 0x77, - 0x7e, 0x80, 0x77, 0x80, 0x82, 0x7c, 0x7f, 0x7f, 0x72, 0x82, 0x87, 0x76, - 0x81, 0x85, 0x7b, 0x80, 0x81, 0x76, 0x83, 0x87, 0x7e, 0x85, 0x87, 0x83, - 0x84, 0x85, 0x7d, 0x87, 0x89, 0x7b, 0x88, 0x8c, 0x7b, 0x89, 0x8e, 0x7e, - 0x8a, 0x8d, 0x7f, 0x8b, 0x8e, 0x88, 0x8b, 0x8b, 0x89, 0x8b, 0x8c, 0x8b, - 0x8c, 0x8c, 0x88, 0x8e, 0x91, 0x85, 0x8f, 0x93, 0x8c, 0x8e, 0x8f, 0x8d, - 0x8f, 0x8f, 0x87, 0x91, 0x94, 0x88, 0x93, 0x97, 0x91, 0x94, 0x96, 0x93, - 0x94, 0x95, 0x8d, 0x96, 0x9a, 0x8d, 0x97, 0x9a, 0x90, 0x97, 0x99, 0x95, - 0x96, 0x96, 0x91, 0x98, 0x9b, 0x94, 0x98, 0x99, 0x91, 0x99, 0x9b, 0x96, - 0x97, 0xa4, 0x93, 0x99, 0x9b, 0x91, 0x9a, 0x9c, 0x98, 0x99, 0x99, 0x93, - 0x9b, 0x9d, 0x97, 0x9c, 0x9d, 0x93, 0x9d, 0xa1, 0x95, 0x9d, 0x9f, 0x96, - 0x9d, 0xa0, 0x98, 0xa0, 0xa3, 0x9d, 0x9f, 0xa0, 0x97, 0xa1, 0xa5, 0xa1, - 0xa1, 0xa1, 0x99, 0xa3, 0xa7, 0x9b, 0xa3, 0xa5, 0xa4, 0xa5, 0xa5, 0x9d, - 0xa7, 0xa9, 0xa6, 0xa8, 0xa8, 0xa2, 0xa9, 0xac, 0xa2, 0xab, 0xad, 0xaa, - 0xab, 0xab, 0xa6, 0xad, 0xb0, 0xa5, 0xaf, 0xb2, 0xab, 0xb3, 0xb6, 0xaf, - 0xb2, 0xb4, 0xae, 0xb5, 0xb8, 0xb4, 0xb4, 0xb4, 0xb0, 0xb6, 0xb8, 0xb1, - 0xb7, 0xba, 0xb2, 0xb7, 0xb9, 0xb4, 0xb7, 0xb9, 0xb2, 0xb8, 0xb9, 0xb2, - 0xb8, 0xba, 0xb3, 0xb8, 0xb9, 0xb3, 0xbb, 0xbe, 0xb4, 0xbb, 0xbd, 0xb5, - 0xbb, 0xbd, 0xb6, 0xbb, 0xbc, 0xb7, 0xbc, 0xbf, 0xb8, 0xbd, 0xbe, 0xbd, - 0xbe, 0xbf, 0xbc, 0xbf, 0xc0, 0xbc, 0xc1, 0xc2, 0xbd, 0xc1, 0xc2, 0xbb, - 0xc2, 0xc5, 0xc2, 0xc2, 0xc2, 0xc3, 0xc3, 0xc3, 0xbe, 0xc5, 0xc7, 0xc2, - 0xc4, 0xc5, 0xc3, 0xc4, 0xc4, 0xc2, 0xc6, 0xc7, 0xc4, 0xc6, 0xc7, 0xc3, - 0xc7, 0xc8, 0xc3, 0xc7, 0xc9, 0xc3, 0xc8, 0xca, 0xc4, 0xc9, 0xcb, 0xc6, - 0xca, 0xcb, 0xc6, 0xcc, 0xce, 0xca, 0xcd, 0xce, 0xca, 0xce, 0xd0, 0xcb, - 0xce, 0xcf, 0xca, 0xcf, 0xd1, 0xcb, 0xcf, 0xd0, 0xcb, 0xd0, 0xd2, 0xcd, - 0xd0, 0xd1, 0xcf, 0xd1, 0xd2, 0xd0, 0xd1, 0xd1, 0xce, 0xd2, 0xd3, 0xd0, - 0xd2, 0xd3, 0xd0, 0xd3, 0xd4, 0xd2, 0xd4, 0xd5, 0xd4, 0xd5, 0xd8, 0xd2, - 0xd6, 0xd8, 0xd2, 0xd7, 0xd8, 0xd4, 0xd7, 0xd8, 0xd3, 0xd8, 0xd9, 0xd7, - 0xd7, 0xdd, 0xd6, 0xd8, 0xd9, 0xd6, 0xd8, 0xda, 0xd7, 0xd8, 0xd8, 0xd7, - 0xda, 0xdb, 0xd8, 0xdb, 0xdd, 0xd7, 0xdc, 0xde, 0xd9, 0xdc, 0xdd, 0xda, - 0xdc, 0xdc, 0xdb, 0xdd, 0xdd, 0xdb, 0xdd, 0xde, 0xdc, 0xdf, 0xe0, 0xdd, - 0xdf, 0xe0, 0xdd, 0xe0, 0xe0, 0xde, 0xe1, 0xe2, 0xe0, 0xe1, 0xe2, 0xe0, - 0xe2, 0xe2, 0xe1, 0xe3, 0xe3, 0xe1, 0xe3, 0xe4, 0xe2, 0xe3, 0xe3, 0xe1, - 0xe6, 0xe7, 0xe5, 0xe7, 0xe7, 0xe6, 0xe7, 0xe7, 0xe6, 0xe7, 0xe8, 0xe6, - 0xe8, 0xe9, 0xe7, 0xe8, 0xe9, 0xe4, 0xe9, 0xeb, 0xe6, 0xe9, 0xea, 0xe7, - 0xe9, 0xea, 0xe8, 0xe9, 0xea, 0xe6, 0xea, 0xeb, 0xe9, 0xeb, 0xec, 0xe8, - 0xec, 0xed, 0xea, 0xec, 0xed, 0xeb, 0xec, 0xed, 0xeb, 0xed, 0xed, 0xec, - 0xed, 0xee, 0xec, 0xef, 0xf1, 0xff, 0xff, 0x00, 0x0f, 0x9e, 0xcb, 0x48, - 0x00, 0x00, 0x00, 0x01, 0x74, 0x52, 0x4e, 0x53, 0x00, 0x40, 0xe6, 0xd8, - 0x66, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0e, - 0xc4, 0x00, 0x00, 0x0e, 0xc4, 0x01, 0x95, 0x2b, 0x0e, 0x1b, 0x00, 0x00, - 0x00, 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xe6, 0x01, 0x09, 0x0a, 0x37, - 0x0f, 0x41, 0x8e, 0x0c, 0x76, 0x00, 0x00, 0x01, 0xda, 0x49, 0x44, 0x41, - 0x54, 0x38, 0xcb, 0x63, 0x60, 0x20, 0x1b, 0xdc, 0x7a, 0x49, 0x94, 0xb2, - 0x0e, 0x67, 0xf5, 0x43, 0x44, 0x28, 0xdb, 0x14, 0xf7, 0xe7, 0xcf, 0x44, - 0xc2, 0xca, 0xde, 0x86, 0x14, 0xfd, 0xf9, 0x23, 0x7c, 0x90, 0xa0, 0xba, - 0x59, 0xd2, 0x7f, 0x80, 0x60, 0x29, 0x41, 0x75, 0x1b, 0xed, 0x41, 0xea, - 0x7a, 0x08, 0xaa, 0x5b, 0xe9, 0x07, 0x52, 0x17, 0x4e, 0x50, 0xdd, 0xea, - 0x60, 0x90, 0x3a, 0xd7, 0xc7, 0x84, 0xd4, 0x4d, 0x76, 0x06, 0xa9, 0xb3, - 0xb8, 0x4b, 0x48, 0xdd, 0x8a, 0x00, 0x90, 0xba, 0xa0, 0xe3, 0x78, 0x15, - 0xbd, 0x38, 0xb7, 0x25, 0xca, 0x1c, 0xa4, 0x4e, 0xa8, 0xa4, 0xbe, 0xf9, - 0x19, 0x4e, 0x65, 0xf7, 0x1d, 0xcd, 0x0c, 0x18, 0x35, 0x40, 0xea, 0x58, - 0x24, 0x9c, 0x04, 0xf3, 0x70, 0xaa, 0x3b, 0xa5, 0x35, 0xbb, 0x8a, 0x29, - 0x14, 0xa4, 0xce, 0x34, 0x62, 0x49, 0x53, 0xe0, 0x1b, 0x5c, 0xea, 0x76, - 0x59, 0xde, 0xfc, 0x83, 0x00, 0x46, 0xf7, 0x70, 0x28, 0xfb, 0x55, 0x20, - 0xbe, 0x1d, 0x49, 0x1d, 0x7b, 0xcd, 0x25, 0xec, 0xea, 0xe6, 0x08, 0xa4, - 0xee, 0x40, 0x52, 0xf7, 0x47, 0x21, 0x6c, 0x1b, 0x16, 0x55, 0x97, 0x36, - 0x8b, 0xc5, 0xee, 0xfe, 0x83, 0x02, 0xfc, 0x53, 0xa6, 0x9f, 0x44, 0x57, - 0x76, 0xdd, 0xd6, 0xa6, 0xed, 0xcc, 0x1f, 0x34, 0x90, 0x23, 0xe3, 0xb1, - 0xe0, 0x27, 0xb2, 0xaa, 0xcf, 0xab, 0x32, 0xdc, 0xe6, 0xfd, 0xc1, 0x04, - 0xd3, 0xf4, 0xe5, 0xf6, 0xbf, 0x43, 0x28, 0x7b, 0xd8, 0xcd, 0xfa, 0x07, - 0x07, 0xa8, 0x48, 0x6c, 0x38, 0x0c, 0x53, 0xb6, 0x2c, 0x1a, 0x22, 0x56, - 0x69, 0x2f, 0x22, 0xcd, 0xc1, 0x09, 0x62, 0xf1, 0x33, 0x67, 0x27, 0x4b, - 0x79, 0xd5, 0xf5, 0x02, 0x99, 0x53, 0x4c, 0xaa, 0x5f, 0x43, 0x94, 0x3d, - 0xd2, 0x86, 0x28, 0x73, 0xcf, 0x9a, 0x71, 0xe2, 0x68, 0x2e, 0x1f, 0x88, - 0xa9, 0x58, 0xfa, 0xe4, 0xc7, 0xfa, 0x49, 0x8d, 0x3a, 0x36, 0x20, 0x8e, - 0xe6, 0x3a, 0xa8, 0x79, 0x49, 0x20, 0x9e, 0x43, 0xf1, 0x9e, 0x4f, 0x40, - 0xf6, 0x8d, 0x48, 0x10, 0xc7, 0xe0, 0x08, 0x58, 0xe2, 0x74, 0xb9, 0x35, - 0x90, 0xc3, 0xb6, 0x15, 0xa2, 0xec, 0xae, 0xdd, 0x1f, 0x1e, 0xbd, 0x96, - 0x63, 0x10, 0xce, 0x15, 0x63, 0x90, 0x3a, 0x95, 0xe5, 0x50, 0x23, 0x76, - 0x1e, 0x6a, 0xfd, 0x53, 0x08, 0x65, 0x7f, 0x9d, 0xe0, 0xb9, 0xef, 0x01, - 0xcc, 0xad, 0x27, 0x44, 0x41, 0xea, 0x94, 0xe6, 0x23, 0x3c, 0x79, 0xe0, - 0x21, 0x9c, 0x79, 0x15, 0x21, 0xfa, 0x54, 0x15, 0xa4, 0x4e, 0x79, 0x2e, - 0xc1, 0x84, 0x9f, 0x09, 0x52, 0x67, 0x75, 0x9e, 0x90, 0xb2, 0xdb, 0xf1, - 0x20, 0x75, 0xdc, 0x8b, 0x09, 0x28, 0xfb, 0xbe, 0xd0, 0x0e, 0xa4, 0x4e, - 0xbe, 0x8c, 0x40, 0x06, 0x99, 0x6a, 0x98, 0x00, 0x52, 0x57, 0xcb, 0xeb, - 0xb3, 0x06, 0x9f, 0xb2, 0xad, 0x92, 0x31, 0x90, 0x30, 0x9f, 0xa9, 0x2b, - 0x7b, 0x16, 0xb7, 0xb2, 0xe7, 0xde, 0x69, 0xf0, 0x88, 0xcd, 0xef, 0xff, - 0x81, 0x53, 0x5d, 0x3b, 0x72, 0x0a, 0xe0, 0xda, 0x86, 0x53, 0xdd, 0x22, - 0x94, 0xa4, 0xf2, 0x11, 0xa7, 0xba, 0xbd, 0x6a, 0xe9, 0x7d, 0x6b, 0x2f, - 0x76, 0xb9, 0x6c, 0xf8, 0x70, 0xb9, 0xd3, 0xf7, 0x02, 0x1e, 0x7f, 0xbc, - 0xff, 0xf2, 0x0d, 0x48, 0x5e, 0x63, 0xf8, 0xcd, 0xf0, 0xea, 0x0e, 0x03, - 0x4d, 0x01, 0x00, 0x38, 0x16, 0x7f, 0x3f, 0xdc, 0xdc, 0x55, 0xf3, 0x00, - 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; -unsigned int yellowplane_png_len = 1355; - -unsigned char greenplane_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, - 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x27, - 0x08, 0x03, 0x00, 0x00, 0x00, 0xbb, 0x7d, 0xa1, 0x07, 0x00, 0x00, 0x02, - 0xf7, 0x50, 0x4c, 0x54, 0x45, 0x00, 0x00, 0x00, 0x38, 0x44, 0x47, 0x44, - 0x45, 0x46, 0x3b, 0x4c, 0x51, 0x42, 0x4b, 0x4e, 0x3f, 0x4d, 0x51, 0x43, - 0x4e, 0x51, 0x44, 0x4e, 0x51, 0x44, 0x51, 0x54, 0x4b, 0x50, 0x52, 0x42, - 0x54, 0x5a, 0x43, 0x54, 0x5a, 0x4c, 0x52, 0x53, 0x48, 0x53, 0x56, 0x4a, - 0x53, 0x56, 0x4d, 0x53, 0x55, 0x46, 0x57, 0x5c, 0x4b, 0x56, 0x59, 0x4a, - 0x58, 0x5c, 0x4b, 0x58, 0x5b, 0x4f, 0x58, 0x5b, 0x4d, 0x59, 0x5c, 0x4e, - 0x59, 0x5d, 0x53, 0x58, 0x59, 0x50, 0x59, 0x5c, 0x49, 0x5b, 0x5f, 0x4e, - 0x5b, 0x5e, 0x4e, 0x5c, 0x60, 0x52, 0x5b, 0x5e, 0x49, 0x5e, 0x65, 0x4c, - 0x5e, 0x63, 0x52, 0x5d, 0x60, 0x55, 0x5d, 0x5f, 0x53, 0x5e, 0x61, 0x55, - 0x5f, 0x62, 0x53, 0x60, 0x64, 0x54, 0x60, 0x63, 0x54, 0x61, 0x65, 0x55, - 0x61, 0x64, 0x57, 0x61, 0x64, 0x5c, 0x60, 0x60, 0x58, 0x61, 0x64, 0x5a, - 0x61, 0x63, 0x52, 0x63, 0x69, 0x57, 0x62, 0x66, 0x5c, 0x61, 0x63, 0x56, - 0x63, 0x67, 0x5d, 0x62, 0x63, 0x59, 0x63, 0x66, 0x56, 0x64, 0x68, 0x5c, - 0x63, 0x66, 0x5c, 0x64, 0x67, 0x61, 0x65, 0x67, 0x63, 0x65, 0x65, 0x5d, - 0x67, 0x6a, 0x61, 0x66, 0x68, 0x5b, 0x68, 0x6c, 0x63, 0x66, 0x67, 0x5c, - 0x68, 0x6c, 0x59, 0x69, 0x6d, 0x61, 0x67, 0x69, 0x59, 0x69, 0x6f, 0x5e, - 0x68, 0x6b, 0x61, 0x69, 0x6b, 0x61, 0x6a, 0x6d, 0x5a, 0x6c, 0x71, 0x63, - 0x6a, 0x6b, 0x64, 0x6a, 0x6c, 0x66, 0x68, 0x7e, 0x5d, 0x6c, 0x70, 0x66, - 0x6a, 0x6b, 0x65, 0x6b, 0x6d, 0x5b, 0x6f, 0x74, 0x5c, 0x70, 0x75, 0x68, - 0x6d, 0x6e, 0x64, 0x6e, 0x71, 0x5e, 0x70, 0x75, 0x62, 0x6f, 0x73, 0x67, - 0x6e, 0x70, 0x69, 0x6e, 0x6f, 0x69, 0x6e, 0x70, 0x66, 0x6f, 0x72, 0x66, - 0x71, 0x75, 0x6b, 0x70, 0x71, 0x67, 0x71, 0x74, 0x6e, 0x70, 0x70, 0x62, - 0x74, 0x7a, 0x66, 0x74, 0x78, 0x70, 0x72, 0x72, 0x6d, 0x73, 0x75, 0x66, - 0x75, 0x7a, 0x68, 0x75, 0x79, 0x71, 0x73, 0x74, 0x72, 0x74, 0x75, 0x72, - 0x76, 0x77, 0x6c, 0x78, 0x7b, 0x72, 0x77, 0x78, 0x72, 0x77, 0x79, 0x73, - 0x78, 0x79, 0x72, 0x79, 0x7b, 0x72, 0x7b, 0x7e, 0x78, 0x7a, 0x7a, 0x77, - 0x7b, 0x7d, 0x74, 0x7c, 0x7e, 0x75, 0x7c, 0x7e, 0x76, 0x7d, 0x80, 0x77, - 0x7e, 0x80, 0x77, 0x80, 0x82, 0x7c, 0x7f, 0x7f, 0x72, 0x82, 0x87, 0x76, - 0x81, 0x85, 0x7b, 0x80, 0x81, 0x76, 0x83, 0x87, 0x7e, 0x85, 0x87, 0x83, - 0x84, 0x85, 0x7d, 0x87, 0x89, 0x7b, 0x88, 0x8c, 0x7b, 0x89, 0x8e, 0x7e, - 0x8a, 0x8d, 0x7f, 0x8b, 0x8e, 0x88, 0x8b, 0x8b, 0x89, 0x8b, 0x8c, 0x8b, - 0x8c, 0x8c, 0x88, 0x8e, 0x91, 0x85, 0x8f, 0x93, 0x8c, 0x8e, 0x8f, 0x8d, - 0x8f, 0x8f, 0x87, 0x91, 0x94, 0x88, 0x93, 0x97, 0x91, 0x94, 0x96, 0x93, - 0x94, 0x95, 0x8d, 0x96, 0x9a, 0x8d, 0x97, 0x9a, 0x90, 0x97, 0x99, 0x95, - 0x96, 0x96, 0x91, 0x98, 0x9b, 0x94, 0x98, 0x99, 0x91, 0x99, 0x9b, 0x96, - 0x97, 0xa4, 0x93, 0x99, 0x9b, 0x91, 0x9a, 0x9c, 0x98, 0x99, 0x99, 0x93, - 0x9b, 0x9d, 0x97, 0x9c, 0x9d, 0x93, 0x9d, 0xa1, 0x95, 0x9d, 0x9f, 0x96, - 0x9d, 0xa0, 0x98, 0xa0, 0xa3, 0x9d, 0x9f, 0xa0, 0x97, 0xa1, 0xa5, 0xa1, - 0xa1, 0xa1, 0x99, 0xa3, 0xa7, 0x9b, 0xa3, 0xa5, 0xa4, 0xa5, 0xa5, 0x9d, - 0xa7, 0xa9, 0xa6, 0xa8, 0xa8, 0xa2, 0xa9, 0xac, 0xa2, 0xab, 0xad, 0xaa, - 0xab, 0xab, 0xa6, 0xad, 0xb0, 0xa5, 0xaf, 0xb2, 0xab, 0xb3, 0xb6, 0xaf, - 0xb2, 0xb4, 0xae, 0xb5, 0xb8, 0xb4, 0xb4, 0xb4, 0xb0, 0xb6, 0xb8, 0xb1, - 0xb7, 0xba, 0xb2, 0xb7, 0xb9, 0xb4, 0xb7, 0xb9, 0xb2, 0xb8, 0xb9, 0xb2, - 0xb8, 0xba, 0x00, 0xff, 0x00, 0xb3, 0xb8, 0xb9, 0xb3, 0xbb, 0xbe, 0xb4, - 0xbb, 0xbd, 0xb5, 0xbb, 0xbd, 0xb6, 0xbb, 0xbc, 0xb7, 0xbc, 0xbf, 0xb8, - 0xbd, 0xbe, 0xbd, 0xbe, 0xbf, 0xbc, 0xbf, 0xc0, 0xbc, 0xc1, 0xc2, 0xbd, - 0xc1, 0xc2, 0xbb, 0xc2, 0xc5, 0xc2, 0xc2, 0xc2, 0xc3, 0xc3, 0xc3, 0xbe, - 0xc5, 0xc7, 0xc2, 0xc4, 0xc5, 0xc3, 0xc4, 0xc4, 0xc2, 0xc6, 0xc7, 0xc4, - 0xc6, 0xc7, 0xc3, 0xc7, 0xc8, 0xc3, 0xc7, 0xc9, 0xc3, 0xc8, 0xca, 0xc4, - 0xc9, 0xcb, 0xc6, 0xca, 0xcb, 0xc6, 0xcc, 0xce, 0xca, 0xcd, 0xce, 0xca, - 0xce, 0xd0, 0xcb, 0xce, 0xcf, 0xca, 0xcf, 0xd1, 0xcb, 0xcf, 0xd0, 0xcb, - 0xd0, 0xd2, 0xcd, 0xd0, 0xd1, 0xcf, 0xd1, 0xd2, 0xd0, 0xd1, 0xd1, 0xce, - 0xd2, 0xd3, 0xd0, 0xd2, 0xd3, 0xd0, 0xd3, 0xd4, 0xd2, 0xd4, 0xd5, 0xd4, - 0xd5, 0xd8, 0xd2, 0xd6, 0xd8, 0xd2, 0xd7, 0xd8, 0xd4, 0xd7, 0xd8, 0xd3, - 0xd8, 0xd9, 0xd7, 0xd7, 0xdd, 0xd6, 0xd8, 0xd9, 0xd6, 0xd8, 0xda, 0xd7, - 0xd8, 0xd8, 0xd7, 0xda, 0xdb, 0xd8, 0xdb, 0xdd, 0xd7, 0xdc, 0xde, 0xd9, - 0xdc, 0xdd, 0xda, 0xdc, 0xdc, 0xdb, 0xdd, 0xdd, 0xdb, 0xdd, 0xde, 0xdc, - 0xdf, 0xe0, 0xdd, 0xdf, 0xe0, 0xdd, 0xe0, 0xe0, 0xde, 0xe1, 0xe2, 0xe0, - 0xe1, 0xe2, 0xe0, 0xe2, 0xe2, 0xe1, 0xe3, 0xe3, 0xe1, 0xe3, 0xe4, 0xe2, - 0xe3, 0xe3, 0xe1, 0xe6, 0xe7, 0xe5, 0xe7, 0xe7, 0xe6, 0xe7, 0xe7, 0xe6, - 0xe7, 0xe8, 0xe6, 0xe8, 0xe9, 0xe7, 0xe8, 0xe9, 0xe4, 0xe9, 0xeb, 0xe6, - 0xe9, 0xea, 0xe7, 0xe9, 0xea, 0xe8, 0xe9, 0xea, 0xe6, 0xea, 0xeb, 0xe9, - 0xeb, 0xec, 0xe8, 0xec, 0xed, 0xea, 0xec, 0xed, 0xeb, 0xec, 0xed, 0xeb, - 0xed, 0xed, 0xec, 0xed, 0xee, 0xec, 0xef, 0xf1, 0xbe, 0x3f, 0x0a, 0xac, - 0x00, 0x00, 0x00, 0x01, 0x74, 0x52, 0x4e, 0x53, 0x00, 0x40, 0xe6, 0xd8, - 0x66, 0x00, 0x00, 0x00, 0x01, 0x62, 0x4b, 0x47, 0x44, 0x00, 0x88, 0x05, - 0x1d, 0x48, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, - 0x0e, 0xc4, 0x00, 0x00, 0x0e, 0xc4, 0x01, 0x95, 0x2b, 0x0e, 0x1b, 0x00, - 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xe6, 0x01, 0x09, 0x0a, - 0x36, 0x22, 0x1d, 0x4a, 0x61, 0x42, 0x00, 0x00, 0x01, 0xda, 0x49, 0x44, - 0x41, 0x54, 0x38, 0xcb, 0x63, 0x60, 0x20, 0x1b, 0xdc, 0x7e, 0x45, 0x94, - 0xb2, 0x0e, 0x67, 0xf5, 0xc3, 0x44, 0x28, 0xdb, 0x1c, 0xb7, 0x7a, 0xf5, - 0x44, 0xc2, 0xca, 0xde, 0x85, 0x14, 0xad, 0x5e, 0x2d, 0x7c, 0x88, 0xa0, - 0xba, 0x59, 0xd2, 0xab, 0x81, 0x60, 0x29, 0x41, 0x75, 0x9b, 0xec, 0x41, - 0xea, 0x7a, 0x08, 0xaa, 0x5b, 0xe9, 0x07, 0x52, 0x17, 0x4e, 0x50, 0xdd, - 0x9a, 0x60, 0x90, 0x3a, 0xd7, 0x27, 0x84, 0xd4, 0x4d, 0x76, 0x06, 0xa9, - 0xb3, 0xb8, 0x47, 0x48, 0xdd, 0x8a, 0x00, 0x90, 0xba, 0xa0, 0x13, 0x78, - 0x15, 0xbd, 0x3c, 0xbf, 0x35, 0xca, 0x1c, 0xa4, 0x4e, 0xa8, 0xa4, 0xbe, - 0xf9, 0x39, 0x4e, 0x65, 0x0f, 0x1c, 0xcd, 0x0c, 0x18, 0x35, 0x40, 0xea, - 0x58, 0x24, 0x9c, 0x04, 0xf3, 0x70, 0xaa, 0x3b, 0xad, 0x35, 0xbb, 0x8a, - 0x29, 0x14, 0xa4, 0xce, 0x34, 0x62, 0x49, 0x53, 0xe0, 0x5b, 0x5c, 0xea, - 0x76, 0x5b, 0xde, 0x5a, 0x8d, 0x00, 0x46, 0xf7, 0x71, 0x28, 0xfb, 0x5d, - 0x20, 0xbe, 0x03, 0x49, 0x1d, 0x7b, 0xcd, 0x65, 0xec, 0xea, 0xe6, 0x08, - 0xa4, 0xee, 0x44, 0x52, 0xb7, 0x5a, 0x21, 0x6c, 0x3b, 0x16, 0x55, 0x97, - 0xb7, 0x88, 0xc5, 0xee, 0x59, 0x8d, 0x02, 0xfc, 0x53, 0xa6, 0x9f, 0x42, - 0x57, 0x76, 0xc3, 0xd6, 0xa6, 0xed, 0xec, 0x6a, 0x34, 0x90, 0x23, 0xe3, - 0xb1, 0xe0, 0x17, 0xb2, 0xaa, 0x2f, 0xab, 0x32, 0xdc, 0xe6, 0xad, 0xc6, - 0x04, 0xd3, 0xf4, 0xe5, 0x0e, 0xbc, 0x47, 0x28, 0x7b, 0xd4, 0xcd, 0xba, - 0x1a, 0x07, 0xa8, 0x48, 0x6c, 0x38, 0x02, 0x53, 0xb6, 0x2c, 0x1a, 0x22, - 0x56, 0x69, 0x2f, 0x22, 0xcd, 0xc1, 0x09, 0x62, 0xf1, 0x33, 0x67, 0x27, - 0x4b, 0x79, 0xd5, 0xf5, 0x02, 0x99, 0x53, 0x4c, 0xaa, 0xdf, 0x40, 0x94, - 0x3d, 0xd6, 0x86, 0x28, 0x73, 0xcf, 0x9a, 0x71, 0xf2, 0x58, 0x2e, 0x1f, - 0x88, 0xa9, 0x58, 0xfa, 0xf4, 0xe7, 0x86, 0x49, 0x8d, 0x3a, 0x36, 0x20, - 0x8e, 0xe6, 0x7a, 0xa8, 0x79, 0x49, 0x20, 0x9e, 0x43, 0xf1, 0xde, 0xcf, - 0x40, 0xf6, 0xcd, 0x48, 0x10, 0xc7, 0xe0, 0x28, 0x58, 0xe2, 0x4c, 0xb9, - 0x35, 0x90, 0xc3, 0xb6, 0x0d, 0xa2, 0xec, 0x9e, 0xdd, 0x6a, 0x1e, 0xbd, - 0x96, 0xe3, 0x10, 0xce, 0x55, 0x63, 0x90, 0x3a, 0x95, 0xe5, 0x50, 0x23, - 0x76, 0x1d, 0x6e, 0x5d, 0x5d, 0x08, 0x65, 0x7f, 0x9b, 0xe0, 0xb9, 0xff, - 0x21, 0xcc, 0xad, 0x27, 0x45, 0x41, 0xea, 0x94, 0xe6, 0x23, 0x3c, 0x79, - 0xf0, 0x11, 0x9c, 0x79, 0x0d, 0x21, 0xfa, 0x4c, 0x15, 0xa4, 0x4e, 0x79, - 0x2e, 0xc1, 0x84, 0x9f, 0x09, 0x52, 0x67, 0x75, 0x81, 0x90, 0xb2, 0x3b, - 0xf1, 0x20, 0x75, 0xdc, 0x8b, 0x09, 0x28, 0xfb, 0xb1, 0xd0, 0x0e, 0xa4, - 0x4e, 0xbe, 0x8c, 0x40, 0x06, 0x99, 0x6a, 0x98, 0x00, 0x52, 0x57, 0xcb, - 0xeb, 0xb3, 0x16, 0x9f, 0xb2, 0x6d, 0x92, 0x31, 0x90, 0x30, 0x9f, 0xa9, - 0x2b, 0x7b, 0x0e, 0xb7, 0xb2, 0x17, 0xde, 0x69, 0xf0, 0x88, 0xcd, 0xef, - 0xff, 0x89, 0x53, 0x5d, 0x3b, 0x72, 0x0a, 0xe0, 0xda, 0x8e, 0x53, 0xdd, - 0x22, 0x94, 0xa4, 0xf2, 0x09, 0xa7, 0xba, 0x7d, 0x6a, 0xe9, 0x7d, 0xeb, - 0x2e, 0x75, 0xb9, 0x6c, 0xfc, 0x78, 0xa5, 0xd3, 0xf7, 0x22, 0x1e, 0x7f, - 0x7c, 0xf8, 0xfa, 0x1d, 0x48, 0x5e, 0x67, 0xf8, 0xc3, 0xf0, 0xfa, 0x2e, - 0x03, 0x4d, 0x01, 0x00, 0xfc, 0xea, 0x2e, 0xea, 0xf1, 0xce, 0x06, 0x98, - 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; -unsigned int greenplane_png_len = 1368; -unsigned char aisred_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, - 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x22, - 0x02, 0x03, 0x00, 0x00, 0x00, 0xcd, 0x06, 0x7a, 0x10, 0x00, 0x00, 0x00, - 0x09, 0x50, 0x4c, 0x54, 0x45, 0x00, 0x00, 0xec, 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xf9, 0xfb, 0x11, 0x4e, 0x00, 0x00, 0x00, 0x01, 0x74, 0x52, - 0x4e, 0x53, 0x00, 0x40, 0xe6, 0xd8, 0x66, 0x00, 0x00, 0x00, 0x01, 0x62, - 0x4b, 0x47, 0x44, 0x00, 0x88, 0x05, 0x1d, 0x48, 0x00, 0x00, 0x00, 0x09, - 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13, - 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, - 0x45, 0x07, 0xe6, 0x01, 0x09, 0x0a, 0x35, 0x30, 0xc5, 0xde, 0x43, 0xc9, - 0x00, 0x00, 0x00, 0x53, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, 0x60, - 0x80, 0x01, 0x16, 0x3c, 0x94, 0x28, 0x84, 0x92, 0x44, 0xa1, 0x22, 0x1d, - 0xc0, 0x54, 0x16, 0x16, 0x8a, 0x31, 0x2b, 0x00, 0x4c, 0xad, 0x9a, 0x80, - 0x49, 0xb1, 0xae, 0x9a, 0x02, 0xa2, 0xd8, 0x56, 0x2d, 0x41, 0xa6, 0x96, - 0x21, 0xf3, 0xc4, 0x56, 0x2d, 0x05, 0x51, 0x52, 0xab, 0x56, 0x12, 0xa2, - 0xa2, 0x56, 0xad, 0x04, 0x59, 0x98, 0xb5, 0x6a, 0x15, 0x06, 0xc5, 0x08, - 0xa4, 0x02, 0x40, 0xb6, 0xae, 0x02, 0xd9, 0xcb, 0x18, 0x1a, 0x1a, 0x1a, - 0xc0, 0x00, 0x00, 0xd1, 0xed, 0x24, 0x45, 0x35, 0x85, 0xab, 0x6c, 0x00, - 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; -unsigned int aisred_png_len = 227; -unsigned char aistrans_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, - 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x22, - 0x01, 0x03, 0x00, 0x00, 0x00, 0x8a, 0xa6, 0x00, 0xc0, 0x00, 0x00, 0x00, - 0x06, 0x50, 0x4c, 0x54, 0x45, 0x6f, 0x72, 0x74, 0x00, 0x00, 0x00, 0x3b, - 0x8a, 0x80, 0x24, 0x00, 0x00, 0x00, 0x01, 0x74, 0x52, 0x4e, 0x53, 0x00, - 0x40, 0xe6, 0xd8, 0x66, 0x00, 0x00, 0x00, 0x01, 0x62, 0x4b, 0x47, 0x44, - 0x00, 0x88, 0x05, 0x1d, 0x48, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, - 0x73, 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13, 0x01, 0x00, 0x9a, - 0x9c, 0x18, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xe6, - 0x01, 0x09, 0x0a, 0x36, 0x08, 0xc6, 0xf1, 0xa8, 0x94, 0x00, 0x00, 0x00, - 0x43, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, 0x60, 0x00, 0x01, 0x05, - 0x34, 0x5c, 0x00, 0xc4, 0x01, 0x50, 0x7c, 0x03, 0x88, 0x3b, 0x10, 0x98, - 0xb1, 0x07, 0x88, 0x59, 0x10, 0x98, 0x99, 0x8d, 0x81, 0x81, 0x89, 0x09, - 0x8a, 0x95, 0x20, 0x34, 0x1b, 0x33, 0x03, 0x03, 0x0b, 0x23, 0x26, 0xe6, - 0x61, 0x6c, 0x60, 0xe0, 0x60, 0x40, 0x60, 0x09, 0x86, 0x03, 0x0c, 0x02, - 0x0c, 0x0e, 0x0c, 0xf2, 0xff, 0x0f, 0x00, 0x00, 0x1c, 0xa6, 0x0a, 0x23, - 0x27, 0x5d, 0x69, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, - 0xae, 0x42, 0x60, 0x82 -}; -unsigned int aistrans_png_len = 208; -unsigned char plane_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, - 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x27, - 0x08, 0x03, 0x00, 0x00, 0x00, 0xbb, 0x7d, 0xa1, 0x07, 0x00, 0x00, 0x03, - 0x00, 0x50, 0x4c, 0x54, 0x45, 0x00, 0x00, 0x00, 0x19, 0x1b, 0x27, 0x2c, - 0x30, 0x41, 0x37, 0x44, 0x49, 0x42, 0x46, 0x48, 0x39, 0x4c, 0x51, 0x41, - 0x4b, 0x4c, 0x40, 0x4d, 0x53, 0x43, 0x4c, 0x58, 0x44, 0x4e, 0x4f, 0x44, - 0x51, 0x56, 0x4c, 0x50, 0x52, 0x4d, 0x51, 0x53, 0x41, 0x55, 0x59, 0x4e, - 0x52, 0x54, 0x49, 0x54, 0x54, 0x4f, 0x53, 0x55, 0x4b, 0x56, 0x57, 0x44, - 0x58, 0x5c, 0x45, 0x59, 0x5e, 0x4b, 0x58, 0x5e, 0x53, 0x57, 0x5a, 0x4f, - 0x59, 0x5a, 0x47, 0x5b, 0x60, 0x4e, 0x5c, 0x61, 0x56, 0x5a, 0x5c, 0x47, - 0x5e, 0x68, 0x4a, 0x5e, 0x62, 0x52, 0x5c, 0x5d, 0x58, 0x5c, 0x5e, 0x53, - 0x5e, 0x5e, 0x54, 0x5f, 0x5f, 0x5a, 0x5e, 0x60, 0x53, 0x60, 0x66, 0x55, - 0x60, 0x60, 0x56, 0x60, 0x61, 0x57, 0x61, 0x62, 0x5c, 0x60, 0x62, 0x50, - 0x64, 0x68, 0x5d, 0x61, 0x63, 0x56, 0x63, 0x69, 0x5e, 0x62, 0x64, 0x59, - 0x64, 0x64, 0x5f, 0x63, 0x65, 0x61, 0x65, 0x67, 0x5c, 0x67, 0x68, 0x63, - 0x66, 0x63, 0x62, 0x66, 0x68, 0x5b, 0x68, 0x6e, 0x55, 0x6a, 0x6e, 0x5d, - 0x68, 0x69, 0x62, 0x67, 0x69, 0x5e, 0x69, 0x6a, 0x5f, 0x6a, 0x6b, 0x64, - 0x68, 0x7c, 0x5e, 0x6b, 0x71, 0x58, 0x6d, 0x71, 0x66, 0x6a, 0x6c, 0x67, - 0x6b, 0x6e, 0x68, 0x6c, 0x6f, 0x63, 0x6e, 0x6f, 0x6d, 0x6b, 0x6f, 0x5c, - 0x70, 0x75, 0x69, 0x6d, 0x70, 0x62, 0x6f, 0x75, 0x65, 0x70, 0x71, 0x6b, - 0x6f, 0x71, 0x64, 0x71, 0x77, 0x66, 0x71, 0x72, 0x6e, 0x70, 0x6d, 0x60, - 0x74, 0x79, 0x6e, 0x72, 0x75, 0x70, 0x72, 0x6f, 0x67, 0x75, 0x7b, 0x6f, - 0x73, 0x76, 0x70, 0x74, 0x77, 0x71, 0x75, 0x78, 0x6d, 0x78, 0x78, 0x73, - 0x77, 0x79, 0x74, 0x78, 0x7b, 0x78, 0x7a, 0x77, 0x71, 0x7c, 0x7d, 0x77, - 0x7b, 0x7e, 0x78, 0x7c, 0x7f, 0x79, 0x7d, 0x80, 0x7c, 0x7e, 0x7b, 0x7b, - 0x7f, 0x82, 0x75, 0x81, 0x81, 0x74, 0x82, 0x88, 0x7c, 0x81, 0x83, 0x75, - 0x83, 0x89, 0x7e, 0x82, 0x85, 0x7f, 0x83, 0x86, 0x80, 0x84, 0x87, 0x83, - 0x85, 0x82, 0x7a, 0x88, 0x8e, 0x7c, 0x88, 0x88, 0x7b, 0x89, 0x8f, 0x83, - 0x87, 0x8a, 0x85, 0x87, 0x84, 0x7e, 0x8a, 0x8a, 0x7f, 0x8b, 0x8b, 0x87, - 0x89, 0x86, 0x86, 0x8a, 0x8c, 0x87, 0x8b, 0x8e, 0x89, 0x8b, 0x88, 0x8a, - 0x8c, 0x89, 0x89, 0x8d, 0x90, 0x84, 0x90, 0x91, 0x8c, 0x8f, 0x8c, 0x8b, - 0x8f, 0x91, 0x8e, 0x90, 0x8d, 0x86, 0x92, 0x93, 0x85, 0x93, 0x99, 0x8e, - 0x92, 0x95, 0x90, 0x92, 0x8f, 0x91, 0x93, 0x90, 0x90, 0x94, 0x97, 0x8b, - 0x97, 0x98, 0x92, 0x96, 0x99, 0x94, 0x96, 0x93, 0x93, 0x98, 0x9a, 0x95, - 0x97, 0xa6, 0x8f, 0x9a, 0x9b, 0x94, 0x99, 0x9b, 0x97, 0x99, 0x96, 0x95, - 0x9a, 0x9c, 0x97, 0x9b, 0x9e, 0x91, 0x9d, 0x9d, 0x99, 0x9c, 0x98, 0x93, - 0x9e, 0x9f, 0x98, 0x9d, 0x9f, 0x9b, 0x9e, 0x9a, 0x9b, 0x9f, 0xa2, 0x96, - 0xa1, 0xa2, 0x9d, 0xa0, 0x9d, 0x9c, 0xa1, 0xa3, 0x9e, 0xa1, 0x9e, 0x9d, - 0xa2, 0xa4, 0x98, 0xa4, 0xa4, 0xa0, 0xa2, 0x9f, 0xa1, 0xa3, 0xa0, 0xa3, - 0xa5, 0xa2, 0x9c, 0xa8, 0xa8, 0xa4, 0xa6, 0xa3, 0xa5, 0xa7, 0xa4, 0xa4, - 0xa8, 0xab, 0xa6, 0xa8, 0xa5, 0xa0, 0xac, 0xad, 0xa9, 0xab, 0xa8, 0xa8, - 0xac, 0xaf, 0xa3, 0xaf, 0xb0, 0xad, 0xaf, 0xac, 0xac, 0xb1, 0xb3, 0xaf, - 0xb2, 0xae, 0xae, 0xb3, 0xb5, 0xb0, 0xb3, 0xaf, 0xb1, 0xb4, 0xb0, 0xb0, - 0xb5, 0xb7, 0xb2, 0xb5, 0xb2, 0xb1, 0xb6, 0xb8, 0xb2, 0xb7, 0xba, 0xb4, - 0xb7, 0xb3, 0xb4, 0xb8, 0xbb, 0xb6, 0xb8, 0xb5, 0xb6, 0xba, 0xbd, 0xb8, - 0xba, 0xb7, 0xb7, 0xbb, 0xbe, 0xb9, 0xbb, 0xb8, 0xb8, 0xbc, 0xbf, 0xbb, - 0xbd, 0xba, 0xba, 0xbf, 0xc1, 0xbd, 0xbf, 0xbc, 0xbc, 0xc1, 0xc3, 0xbd, - 0xc2, 0xc4, 0xbf, 0xc2, 0xbe, 0xc0, 0xc3, 0xbf, 0xbf, 0xc4, 0xc6, 0xc1, - 0xc4, 0xc1, 0xc3, 0xc5, 0xc2, 0xc1, 0xc6, 0xc8, 0xc4, 0xc6, 0xc3, 0xc5, - 0xc7, 0xc4, 0xc3, 0xc8, 0xca, 0xc5, 0xc9, 0xcc, 0xc7, 0xc9, 0xc6, 0xc6, - 0xca, 0xcd, 0xc9, 0xcb, 0xc8, 0xc7, 0xcc, 0xce, 0xca, 0xcc, 0xc9, 0xc9, - 0xce, 0xd0, 0xcb, 0xce, 0xca, 0xca, 0xcf, 0xd1, 0xcb, 0xd0, 0xd2, 0xcd, - 0xd0, 0xcc, 0xcc, 0xd1, 0xd4, 0xce, 0xd1, 0xce, 0xcd, 0xd2, 0xd5, 0xd0, - 0xd2, 0xcf, 0xcf, 0xd3, 0xd6, 0xd1, 0xd3, 0xd0, 0xd0, 0xd4, 0xd7, 0xd3, - 0xd6, 0xd2, 0xd2, 0xd6, 0xd9, 0xd5, 0xd7, 0xd4, 0xd3, 0xd8, 0xda, 0xda, - 0xd7, 0xdb, 0xd4, 0xd9, 0xdb, 0xd6, 0xd9, 0xd5, 0xd5, 0xda, 0xdc, 0xd7, - 0xda, 0xd6, 0xd6, 0xdb, 0xde, 0xd8, 0xdb, 0xd7, 0xd7, 0xdc, 0xdf, 0xd9, - 0xdc, 0xd9, 0xd8, 0xdd, 0xe0, 0xdb, 0xdd, 0xda, 0xdc, 0xde, 0xdb, 0xdb, - 0xe0, 0xe2, 0xde, 0xe0, 0xdd, 0xdf, 0xe1, 0xde, 0xdd, 0xe2, 0xe4, 0xe0, - 0xe3, 0xdf, 0xdf, 0xe4, 0xe6, 0xe1, 0xe4, 0xe0, 0xe2, 0xe5, 0xe1, 0xe1, - 0xe6, 0xe9, 0xe3, 0xe6, 0xe2, 0xe5, 0xe7, 0xe4, 0xe3, 0xe8, 0xeb, 0xe5, - 0xe9, 0xec, 0xe7, 0xe9, 0xe6, 0xe6, 0xea, 0xed, 0xe8, 0xea, 0xe7, 0xe7, - 0xec, 0xee, 0xe8, 0xed, 0xef, 0xea, 0xed, 0xe9, 0xe9, 0xee, 0xf0, 0xeb, - 0xee, 0xea, 0xea, 0xef, 0xf2, 0xed, 0xf0, 0xed, 0xec, 0xf1, 0xf4, 0xef, - 0xf1, 0xee, 0xf0, 0xf2, 0xef, 0xf1, 0xf3, 0xf0, 0xf2, 0xf4, 0xf1, 0xf3, - 0xf6, 0xf2, 0xf4, 0xf7, 0xf3, 0xf5, 0xf8, 0xf4, 0xf6, 0xf9, 0xf6, 0xf8, - 0xfa, 0xf7, 0xf9, 0xfb, 0xf8, 0xfa, 0xfc, 0xf9, 0xfb, 0xfd, 0xfa, 0xfc, - 0xff, 0xfb, 0xff, 0xff, 0xff, 0x17, 0x03, 0x0e, 0x9e, 0x00, 0x00, 0x00, - 0x01, 0x74, 0x52, 0x4e, 0x53, 0x00, 0x40, 0xe6, 0xd8, 0x66, 0x00, 0x00, - 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0e, 0xc4, 0x00, 0x00, - 0x0e, 0xc4, 0x01, 0x95, 0x2b, 0x0e, 0x1b, 0x00, 0x00, 0x00, 0x07, 0x74, - 0x49, 0x4d, 0x45, 0x07, 0xe6, 0x01, 0x09, 0x0a, 0x36, 0x3b, 0x79, 0x21, - 0xc9, 0x82, 0x00, 0x00, 0x02, 0x78, 0x49, 0x44, 0x41, 0x54, 0x38, 0xcb, - 0x63, 0x60, 0x20, 0x1b, 0x5c, 0x7c, 0x40, 0x94, 0xb2, 0x4a, 0x4b, 0x95, - 0x5d, 0x44, 0x28, 0x5b, 0xed, 0xd7, 0x13, 0xdc, 0x44, 0x58, 0xd9, 0x33, - 0x97, 0xd8, 0x3b, 0xd3, 0x44, 0x76, 0x10, 0x54, 0xd7, 0x2f, 0x31, 0xe9, - 0xd7, 0x21, 0xd5, 0x05, 0x04, 0xd5, 0xad, 0x34, 0x5d, 0xf2, 0xed, 0x90, - 0x7e, 0x35, 0x41, 0x75, 0x8b, 0xed, 0xb7, 0xfe, 0x38, 0xe3, 0xe4, 0x49, - 0x58, 0x9d, 0xd3, 0xce, 0xdf, 0x57, 0x22, 0xcd, 0x6f, 0x11, 0x52, 0xd7, - 0x6a, 0xb9, 0xf3, 0xf7, 0x83, 0x18, 0x83, 0x8b, 0x84, 0xd4, 0x2d, 0xb0, - 0xdf, 0xfb, 0xe3, 0x71, 0xba, 0xf3, 0x01, 0xbc, 0x8a, 0xee, 0x1f, 0x5f, - 0xeb, 0xa9, 0xbf, 0xf3, 0xd7, 0x83, 0x34, 0x91, 0xf8, 0x82, 0xb2, 0x7b, - 0x38, 0x95, 0xdd, 0xb0, 0xd0, 0xd5, 0x62, 0x56, 0xdd, 0xf6, 0xfb, 0x71, - 0x16, 0x9b, 0x98, 0x25, 0x7f, 0x04, 0x4e, 0x75, 0x07, 0x55, 0x27, 0x67, - 0xb1, 0xb8, 0x5e, 0xf8, 0xfd, 0x65, 0x89, 0x9e, 0xc7, 0xdc, 0x52, 0xc7, - 0x27, 0xb8, 0xd4, 0x6d, 0x34, 0xbe, 0xf0, 0xbc, 0x77, 0xf3, 0xe7, 0x7f, - 0x7f, 0x1f, 0xae, 0xd9, 0x76, 0x63, 0xae, 0xf6, 0x15, 0x1c, 0xca, 0xde, - 0x46, 0x89, 0x6e, 0xf8, 0xfa, 0xee, 0xfb, 0xdf, 0x7f, 0xff, 0xfe, 0xfd, - 0xf8, 0xfa, 0x79, 0x02, 0x67, 0xce, 0x69, 0xec, 0xea, 0x26, 0x09, 0x05, - 0x6c, 0xfe, 0xf5, 0x0f, 0x0a, 0xbe, 0x6d, 0x8d, 0x95, 0x73, 0x5b, 0x87, - 0x45, 0xd5, 0xe9, 0xd5, 0x22, 0xde, 0x9b, 0x3f, 0xfd, 0x83, 0x83, 0xaf, - 0xfb, 0x7b, 0xec, 0x03, 0xbb, 0x0f, 0xa2, 0x2b, 0x3b, 0x6f, 0x60, 0x5c, - 0x71, 0xec, 0x0b, 0x50, 0x1e, 0x64, 0x2d, 0x98, 0xf8, 0xf3, 0x78, 0x55, - 0x98, 0x8c, 0xdd, 0xf4, 0x77, 0x28, 0xa9, 0x69, 0x71, 0x90, 0xe5, 0xd4, - 0x07, 0x7f, 0xfe, 0xfc, 0x7e, 0xf3, 0xf8, 0xf9, 0x37, 0xa0, 0x59, 0x0f, - 0x6f, 0xbf, 0xfc, 0xfa, 0xfb, 0xc7, 0xe7, 0x9d, 0x3d, 0x9a, 0xd2, 0x5b, - 0x9e, 0x21, 0x94, 0xdd, 0xaa, 0x61, 0xcf, 0xdb, 0xfc, 0xf2, 0xcb, 0x93, - 0xcd, 0xb3, 0xea, 0x8a, 0x4b, 0x4f, 0xfd, 0xfe, 0xbc, 0x2d, 0x33, 0x29, - 0xbd, 0xa5, 0x77, 0xff, 0xbb, 0xcf, 0x67, 0x96, 0x66, 0xf8, 0x15, 0xee, - 0x81, 0xc7, 0x95, 0xa7, 0x7d, 0xe6, 0x89, 0xdb, 0x87, 0x96, 0x64, 0x98, - 0x8a, 0x49, 0x70, 0x71, 0xcf, 0xf8, 0xfa, 0xbd, 0x57, 0x80, 0x35, 0xdc, - 0x5f, 0xc2, 0x3a, 0xbf, 0x76, 0xe7, 0xcd, 0x25, 0x1d, 0x3a, 0xd9, 0xd0, - 0x80, 0xbc, 0xa5, 0x26, 0x39, 0x75, 0xfd, 0x8a, 0x09, 0x0a, 0x96, 0x21, - 0x5d, 0x07, 0xf6, 0x45, 0xf0, 0x2f, 0xf9, 0xfc, 0x65, 0xa2, 0x7c, 0xe2, - 0xdd, 0xd7, 0xcb, 0x9b, 0x4b, 0x35, 0x8c, 0xd3, 0x7a, 0xfa, 0xf2, 0x55, - 0x96, 0x42, 0xcd, 0xf3, 0x8f, 0xeb, 0x29, 0xe2, 0x31, 0x4d, 0x00, 0xbb, - 0xe4, 0xbc, 0xfb, 0xac, 0xcf, 0x5f, 0xfa, 0xb4, 0xf6, 0x41, 0x22, 0x28, - 0xd5, 0xd0, 0xc4, 0x52, 0x96, 0x73, 0x2d, 0x34, 0x1f, 0x1a, 0xa9, 0xf3, - 0x69, 0x94, 0x41, 0x64, 0x18, 0xce, 0x6a, 0xcd, 0xfc, 0xfa, 0x69, 0x82, - 0x12, 0x2c, 0xe1, 0x6f, 0xdc, 0x55, 0x2e, 0x1c, 0x0b, 0x65, 0xbf, 0x6a, - 0xb0, 0xdb, 0x72, 0x1d, 0xe6, 0xd6, 0x03, 0x62, 0x93, 0x3e, 0x7d, 0xed, - 0x51, 0x9a, 0x86, 0xf0, 0xe4, 0x76, 0x44, 0x9a, 0x3d, 0x8b, 0x10, 0xbd, - 0xab, 0xd8, 0xf1, 0xfc, 0xd7, 0x44, 0xc5, 0x29, 0x04, 0x13, 0x7e, 0x70, - 0xf2, 0xed, 0x4f, 0x8d, 0x06, 0xc7, 0x09, 0x16, 0x1a, 0xbe, 0x21, 0x57, - 0xbe, 0x94, 0xf0, 0xce, 0x23, 0xa0, 0xec, 0xf5, 0x6c, 0xa3, 0xe8, 0x8b, - 0x5f, 0xeb, 0xe5, 0x52, 0x08, 0x64, 0x90, 0x36, 0x0d, 0xbf, 0x65, 0x9f, - 0xfe, 0x5d, 0xca, 0xe3, 0xb7, 0x5b, 0x8a, 0x4f, 0xd9, 0x5a, 0x71, 0xaf, - 0x25, 0x1f, 0xff, 0xfd, 0xfe, 0x72, 0x6a, 0x82, 0xba, 0x14, 0x1e, 0x27, - 0x3e, 0xb0, 0x09, 0x3a, 0xf1, 0xe9, 0xce, 0xde, 0x8d, 0x87, 0x5e, 0x9e, - 0x5a, 0x1d, 0xd9, 0xfc, 0x1a, 0x77, 0x91, 0x26, 0xd7, 0xb7, 0x6b, 0x4e, - 0xba, 0xad, 0x8e, 0x75, 0xde, 0x8c, 0xb9, 0xa1, 0xbc, 0xeb, 0x70, 0xaa, - 0x9b, 0x2d, 0x1b, 0xed, 0xcf, 0xcf, 0xc1, 0xc4, 0xa8, 0x3d, 0xcd, 0xc7, - 0x4a, 0x20, 0xe6, 0x19, 0x4e, 0x75, 0x5b, 0x94, 0x03, 0x1b, 0x96, 0x9e, - 0xac, 0x32, 0x5b, 0xf9, 0xec, 0x74, 0xb5, 0xc3, 0x49, 0x7c, 0xa5, 0xdf, - 0x8b, 0x57, 0x40, 0xf2, 0x1c, 0xc3, 0x5b, 0x86, 0xfb, 0x17, 0x19, 0x68, - 0x0a, 0x00, 0x52, 0xa4, 0x31, 0x22, 0xfa, 0xbb, 0x4c, 0x44, 0x00, 0x00, - 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; -unsigned int plane_png_len = 1522; -unsigned char helicopter_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, - 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x1f, - 0x04, 0x03, 0x00, 0x00, 0x00, 0xed, 0x80, 0x0b, 0x0a, 0x00, 0x00, 0x00, - 0x15, 0x50, 0x4c, 0x54, 0x45, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xf0, - 0xf8, 0xff, 0xff, 0x00, 0x00, 0xff, 0x20, 0x20, 0x20, 0x20, 0x20, 0xff, - 0xff, 0xff, 0x96, 0xba, 0xb8, 0x46, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, - 0x59, 0x73, 0x00, 0x00, 0x0b, 0x12, 0x00, 0x00, 0x0b, 0x12, 0x01, 0xd2, - 0xdd, 0x7e, 0xfc, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, - 0xe6, 0x01, 0x09, 0x0a, 0x36, 0x2f, 0x63, 0xfb, 0x1d, 0xff, 0x00, 0x00, - 0x00, 0x70, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x9d, 0xd1, 0xc1, 0x0d, - 0x80, 0x20, 0x0c, 0x05, 0x50, 0x2e, 0xde, 0x6d, 0x52, 0x16, 0x20, 0x6e, - 0x00, 0x0b, 0x54, 0x3a, 0x80, 0x3d, 0xb8, 0xff, 0x2a, 0x62, 0x89, 0x26, - 0x68, 0x7b, 0xd0, 0x7f, 0x21, 0x7d, 0x49, 0x39, 0xfc, 0x06, 0x18, 0x33, - 0x87, 0x3f, 0x10, 0xf7, 0x3b, 0x62, 0x83, 0x26, 0xca, 0xe3, 0x0f, 0x0f, - 0x90, 0x3c, 0x40, 0x66, 0xd2, 0xc7, 0x81, 0x36, 0xd6, 0xc2, 0xa4, 0x6a, - 0x02, 0x72, 0xcd, 0x39, 0x17, 0xd6, 0x35, 0x0b, 0xfa, 0x7c, 0x0a, 0x81, - 0x0d, 0x97, 0x14, 0x02, 0x0f, 0xba, 0xf4, 0x0d, 0x07, 0x00, 0xd7, 0x94, - 0x16, 0x02, 0x1f, 0x5a, 0x89, 0xdb, 0xa4, 0x05, 0x7a, 0xa0, 0x24, 0x43, - 0x85, 0x2f, 0xf8, 0x74, 0xca, 0x03, 0x65, 0xe5, 0x3e, 0xf8, 0xf3, 0x53, - 0x78, 0x63, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, - 0x60, 0x82 -}; -unsigned int helicopter_png_len = 242; -unsigned char aisnavaid_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, - 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x15, - 0x01, 0x03, 0x00, 0x00, 0x00, 0x93, 0xd9, 0x37, 0xd5, 0x00, 0x00, 0x00, - 0x06, 0x50, 0x4c, 0x54, 0x45, 0x63, 0x65, 0x6c, 0x00, 0x00, 0x00, 0x0b, - 0x25, 0x74, 0xbd, 0x00, 0x00, 0x00, 0x01, 0x74, 0x52, 0x4e, 0x53, 0x00, - 0x40, 0xe6, 0xd8, 0x66, 0x00, 0x00, 0x00, 0x01, 0x62, 0x4b, 0x47, 0x44, - 0x00, 0x88, 0x05, 0x1d, 0x48, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, - 0x73, 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13, 0x01, 0x00, 0x9a, - 0x9c, 0x18, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xe6, - 0x01, 0x09, 0x0a, 0x22, 0x0e, 0x01, 0x3c, 0xda, 0xf4, 0x00, 0x00, 0x00, - 0x16, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, 0xf8, 0xff, 0xff, 0x07, - 0x03, 0x0c, 0x3f, 0x28, 0xb0, 0xc0, 0x8a, 0x49, 0x54, 0x03, 0x00, 0x6b, - 0xd8, 0x2d, 0x07, 0x1f, 0xad, 0xa8, 0xbc, 0x00, 0x00, 0x00, 0x00, 0x49, - 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; -unsigned int aisnavaid_png_len = 163; - -unsigned char aiswhite_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, - 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x22, - 0x02, 0x03, 0x00, 0x00, 0x00, 0xcd, 0x06, 0x7a, 0x10, 0x00, 0x00, 0x00, - 0x09, 0x50, 0x4c, 0x54, 0x45, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0x38, 0x24, 0x6b, 0x47, 0x00, 0x00, 0x00, 0x01, 0x74, 0x52, - 0x4e, 0x53, 0x00, 0x40, 0xe6, 0xd8, 0x66, 0x00, 0x00, 0x00, 0x01, 0x62, - 0x4b, 0x47, 0x44, 0x00, 0x88, 0x05, 0x1d, 0x48, 0x00, 0x00, 0x00, 0x09, - 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13, - 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, - 0x45, 0x07, 0xe6, 0x01, 0x09, 0x0a, 0x36, 0x16, 0x3c, 0xfe, 0x95, 0xf7, - 0x00, 0x00, 0x00, 0x53, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, 0x60, - 0x80, 0x01, 0x16, 0x3c, 0x94, 0x28, 0x84, 0x92, 0x44, 0xa1, 0x22, 0x1d, - 0xc0, 0x54, 0x16, 0x16, 0x8a, 0x31, 0x2b, 0x00, 0x4c, 0xad, 0x9a, 0x80, - 0x49, 0xb1, 0xae, 0x9a, 0x02, 0xa2, 0xd8, 0x56, 0x2d, 0x41, 0xa6, 0x96, - 0x21, 0xf3, 0xc4, 0x56, 0x2d, 0x05, 0x51, 0x52, 0xab, 0x56, 0x12, 0xa2, - 0xa2, 0x56, 0xad, 0x04, 0x59, 0x98, 0xb5, 0x6a, 0x15, 0x06, 0xc5, 0x08, - 0xa4, 0x02, 0x40, 0xb6, 0xae, 0x02, 0xd9, 0xcb, 0x18, 0x1a, 0x1a, 0x1a, - 0xc0, 0x00, 0x00, 0xd1, 0xed, 0x24, 0x45, 0x35, 0x85, 0xab, 0x6c, 0x00, - 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; -unsigned int aiswhite_png_len = 227; -char * get_info_call() -{ - char Msg[] = - "" - "" - "" - "" - "" - "\r\n" - " \r\n" - "\r\n" - "##MY_CALLSIGN##'s BPQ32 Web Server\r\n" - "\r\n" - - "\r\n" - - "\r\n" - "\r\n" - "\r\n" - "\r\n" - "\r\n" - "Home\r\n" - "All Stations\r\n" - "RF Stations\r\n" - "All WX Stations\r\n" - "RF WX Stations\r\n" - "All Mobile Stations\r\n" - "RF Mobile Stations\r\n" - "All Objects\r\n" - "RF Objects\r\n" - "Information\r\n" - "Node Pages\r\n" - "\r\n" - "\r\n" - - "\r\n" - "

##MY_CALLSIGN##'s BPQ32 APRS Web Server

\r\n" - - "

(This page will automatically refresh every five minutes)

\r\n" - - "

Information about\r\n" - "##CALLSIGN##
\r\n" - "Click the callsign to look it up on qrz.com
\r\n" - "Location: ##LOCATION##
\r\n" - "The bearing from ##MY_CALLSIGN## to ##CALLSIGN## is\r\n" - "##BEARING## degrees, the distance is ##DISTANCE## ##MILES_KM##

\r\n" - - "\r\n" - "\r\n" - "\r\n" - "\r\n" - "
Last posit: ##FRAME_HEADER##
##FRAME_INFO##
\r\n" - - "

Status: ##STATUS_TEXT##
\r\n" - "Last heard ##LAST_HEARD## ago

\r\n" - - "

" - - "\r\n" - "\r\n" - "\r\n"; - - return _strdup(Msg);; -} - -char * get_infomobile_call() -{ - char Msg[] = - "" - "" - "" - "" - "" - "\r\n" - " \r\n" - "\r\n" - "##MY_CALLSIGN##'s BPQ32 Web Server\r\n" - "\r\n" - - "\r\n" - - "\r\n" - "\r\n" - "\r\n" - "\r\n" - "\r\n" - "Home\r\n" - "All Stations\r\n" - "RF Stations\r\n" - "All WX Stations\r\n" - "RF WX Stations\r\n" - "All Mobile Stations\r\n" - "RF Mobile Stations\r\n" - "All Objects\r\n" - "RF Objects\r\n" - "Information\r\n" - "Node Pages\r\n" - "\r\n" - "\r\n" - - "\r\n" - "

##MY_CALLSIGN##'s BPQ32 APRS Web Server

\r\n" - - "

(This page will automatically refresh every five minutes)

\r\n" - - "

Information about\r\n" - "##CALLSIGN##
\r\n" - "Click the callsign to look it up on qrz.com
\r\n" - "Location: ##LOCATION##
\r\n" - "The bearing from ##MY_CALLSIGN## to ##CALLSIGN## is\r\n" - "##BEARING## degrees, the distance is ##DISTANCE## ##MILES_KM##

\r\n" - - "\r\n" - "\r\n" - "\r\n" - "\r\n" - "
Last posit: ##FRAME_HEADER##
##FRAME_INFO##
\r\n" - - "

Course ##COURSE## degrees, speed ##SPEED_MPH##mph
" - "Status: ##STATUS_TEXT##
" - - "Last heard ##LAST_HEARD## ago

\r\n" - - "

" - - "\r\n" - "\r\n" - "\r\n"; - - return _strdup(Msg);; -} - -char * get_infoobj_call() -{ - char Msg[] = - "" - "" - "" - "" - "" - "\r\n" - " \r\n" - "\r\n" - "##MY_CALLSIGN##'s BPQ32 Web Server\r\n" - "\r\n" - - "\r\n" - - "\r\n" - "\r\n" - "\r\n" - "\r\n" - "\r\n" - "Home\r\n" - "All Stations\r\n" - "RF Stations\r\n" - "All WX Stations\r\n" - "RF WX Stations\r\n" - "All Mobile Stations\r\n" - "RF Mobile Stations\r\n" - "All Objects\r\n" - "RF Objects\r\n" - "Information\r\n" - "Node Pages\r\n" - "\r\n" - "\r\n" - - "\r\n" - "

##MY_CALLSIGN##'s BPQ32 APRS Web Server

\r\n" - - "

(This page will automatically refresh every five minutes)

\r\n" - - "

Information about Object ##CALLSIGN##

" - - "Location: ##LOCATION##
\r\n" - - "The bearing from ##MY_CALLSIGN## to ##CALLSIGN## is\r\n" - "##BEARING## degrees, the distance is ##DISTANCE## ##MILES_KM##

\r\n" - - "\r\n" - "\r\n" - "\r\n" - "\r\n" - "
Last posit: ##FRAME_HEADER##
##FRAME_INFO##
\r\n" - - "

Last Report: ##LASTPACKET##
" - - "Last heard ##LAST_HEARD## ago

\r\n" - - "

" - - "\r\n" - "\r\n" - "\r\n"; - - return _strdup(Msg);; -} - - -char * get_infowx_call() -{ - char Msg[] = - "" - "" - "" - "" - "" - "\r\n" - " \r\n" - "\r\n" - "##MY_CALLSIGN##'s BPQ32 Web Server\r\n" - "\r\n" - - "\r\n" - - "\r\n" - "\r\n" - "\r\n" - "\r\n" - "\r\n" - "Home\r\n" - "All Stations\r\n" - "RF Stations\r\n" - "All WX Stations\r\n" - "RF WX Stations\r\n" - "All Mobile Stations\r\n" - "RF Mobile Stations\r\n" - "All Objects\r\n" - "RF Objects\r\n" - "Information\r\n" - "Node Pages\r\n" - "\r\n" - "\r\n" - - "\r\n" - "

##MY_CALLSIGN##'s BPQ32 APRS Web Server

\r\n" - - "

(This page will automatically refresh every five minutes)

\r\n" - - "

Information about\r\n" - "##CALLSIGN##
\r\n" - "Click the callsign to look it up on qrz.com
\r\n" - "Location: ##LOCATION##
\r\n" - "The bearing from ##MY_CALLSIGN## to ##CALLSIGN## is\r\n" - "##BEARING## degrees, the distance is ##DISTANCE## ##MILES_KM##

\r\n" - - "\r\n" - "\r\n" - "\r\n" - "\r\n" - "
Last posit: ##FRAME_HEADER##
##FRAME_INFO##
\r\n" - - "

Status: ##STATUS_TEXT##
\r\n" - "Last heard ##LAST_HEARD## ago

\r\n" - - "

Weather Data

\r\n" - "\r\n" - "\r\n" - "\r\n" - "\r\n" - "\r\n" - "\r\n" - "\r\n" - "\r\n" - "\r\n" - "\r\n" - "\r\n" - "
MeasurementImperial
Wind speed##WIND_SPEED_MPH## mph
Wind gust##WIND_GUST_MPH## mph
Wind direction##WIND_DIRECTION## deg
Temperature##TEMPERATURE_F##F
Pressure##PRESSURE_HPA## hPa/mb
Humidity##HUMIDITY##%
Rain last hour##RAIN_HOUR_IN##\"
Rain today##RAIN_TODAY_IN##\"
Rain last 24 hours##RAIN_24_IN##\"
\r\n" - - "

" - - "\r\n" - "\r\n" - "\r\n"; - - return _strdup(Msg);; -} - - -char * get_all() -{ - char Msg[] = - "" - "" - "" - "" - "" - "\r\n" - " \r\n" - "\r\n" - "##MY_CALLSIGN##'s BPQ32 Web Server\r\n" - "\r\n" - - "\r\n" - - "\r\n" - "\r\n" - "\r\n" - "\r\n" - "\r\n" - "Home\r\n" - "All Stations\r\n" - "RF Stations\r\n" - "All WX Stations\r\n" - "RF WX Stations\r\n" - "All Mobile Stations\r\n" - "RF Mobile Stations\r\n" - "All Objects\r\n" - "RF Objects\r\n" - "Information\r\n" - "Node Pages\r\n" - "\r\n" - "\r\n" - - "\r\n" - "

##MY_CALLSIGN##'s BPQ32 APRS Web Server

\r\n" - - "

All Stations

\r\n" - - "

(This page will automatically refresh every five minutes)

\r\n" - - "

The following is a list of all the stations heard in the past ##EXPIRE_TIME## minutes,
both on RF and on the internet.

" - "

There are ##TABLE_COUNT## callsigns in the list,
click a callsign to get an information page for that station.

" - - "" - "##STATION_TABLE##
\r\n" - "\r\n" - "\r\n"; - - return _strdup(Msg);; -} - -char * get_mobileall() -{ - char Msg[] = - "" - "" - "" - "" - "" - "\r\n" - " \r\n" - "\r\n" - "##MY_CALLSIGN##'s BPQ32 Web Server\r\n" - "\r\n" - - "\r\n" - - "\r\n" - "\r\n" - "\r\n" - "\r\n" - "\r\n" - "Home\r\n" - "All Stations\r\n" - "RF Stations\r\n" - "All WX Stations\r\n" - "RF WX Stations\r\n" - "All Mobile Stations\r\n" - "RF Mobile Stations\r\n" - "All Objects\r\n" - "RF Objects\r\n" - "Information\r\n" - "Node Pages\r\n" - "\r\n" - "\r\n" - - "\r\n" - "

##MY_CALLSIGN##'s BPQ32 APRS Web Server

\r\n" - - "

All Mobile Stations

\r\n" - - "

(This page will automatically refresh every five minutes)

\r\n" - - "

The following is a list of all the mobile stations heard in the past ##EXPIRE_TIME## minutes,
both on RF and on the internet.

" - "

There are ##TABLE_COUNT## callsigns in the list,
click a callsign to get an information page for that station.

" - - "" - "##STATION_TABLE##
\r\n" - "\r\n" - "\r\n"; - - return _strdup(Msg);; -} - -char * get_obj() -{ - char Msg[] = - "" - "" - "" - "" - "" - "\r\n" - " \r\n" - "\r\n" - "##MY_CALLSIGN##'s BPQ32 Web Server\r\n" - "\r\n" - - "\r\n" - - "\r\n" - "\r\n" - "\r\n" - "\r\n" - "\r\n" - "Home\r\n" - "All Stations\r\n" - "RF Stations\r\n" - "All WX Stations\r\n" - "RF WX Stations\r\n" - "All Mobile Stations\r\n" - "RF Mobile Stations\r\n" - "All Objects\r\n" - "RF Objects\r\n" - "Information\r\n" - "Node Pages\r\n" - "\r\n" - "\r\n" - - "\r\n" - "

##MY_CALLSIGN##'s BPQ32 APRS Web Server

\r\n" - - "

All Objects

\r\n" - - "

(This page will automatically refresh every five minutes)

\r\n" - - "

The following is a list of all the objects heard in the past ##EXPIRE_TIME## minutes,
both on RF and on the internet.

" - "

There are ##TABLE_COUNT## callsigns in the list,
click a callsign to get an information page for that station.

" - - "" - "##STATION_TABLE##
\r\n" - "\r\n" - "\r\n"; - - return _strdup(Msg);; -} - - -char * get_noinfo() -{ - char Msg[] = - "" - "" - "" - "" - "" - "\r\n" - " \r\n" - "\r\n" - "##MY_CALLSIGN##'s BPQ32 Web Server\r\n" - "\r\n" - - "\r\n" - - "\r\n" - "\r\n" - "\r\n" - "\r\n" - "\r\n" - "Home\r\n" - "All Stations\r\n" - "RF Stations\r\n" - "All WX Stations\r\n" - "RF WX Stations\r\n" - "All Mobile Stations\r\n" - "RF Mobile Stations\r\n" - "All Objects\r\n" - "RF Objects\r\n" - "Information\r\n" - "Node Pages\r\n" - "\r\n" - "\r\n" - - "\r\n" - "

##MY_CALLSIGN##'s BPQ32 APRS Web Server

\r\n" - "

No information is available for ##CALLSIGN##

\r\n" - "\r\n"; - - return _strdup(Msg);; -} - -char * get_wxall() -{ - char Msg[] = - "" - "" - "" - "" - "" - "\r\n" - " \r\n" - "\r\n" - "##MY_CALLSIGN##'s BPQ32 Web Server\r\n" - "\r\n" - - "\r\n" - - "\r\n" - "\r\n" - "\r\n" - "\r\n" - "\r\n" - "Home\r\n" - "All Stations\r\n" - "RF Stations\r\n" - "All WX Stations\r\n" - "RF WX Stations\r\n" - "All Mobile Stations\r\n" - "RF Mobile Stations\r\n" - "All Objects\r\n" - "RF Objects\r\n" - "Information\r\n" - "Node Pages\r\n" - "\r\n" - "\r\n" - - "\r\n" - "

##MY_CALLSIGN##'s BPQ32 APRS Web Server

\r\n" - - "

All WX Stations

\r\n" - - "

(This page will automatically refresh every five minutes)

\r\n" - - "

The following is a list of all the WX stations heard in the past ##EXPIRE_TIME## minutes,
both on RF and on the internet.

" - "

There are ##TABLE_COUNT## callsigns in the list,
click a callsign to get an information page for that station.

" - - "" - "##STATION_TABLE##
\r\n" - "\r\n" - "\r\n"; - - return _strdup(Msg);; -} - -char * get_info() -{ - char Msg[] = - "" - "" - "" - "" - "##MY_CALLSIGN##'s BPQ32 Web Server\r\n" - "\r\n" - - "\r\n" - - "\r\n" - "\r\n" - "\r\n" - "\r\n" - "\r\n" - "Home\r\n" - "All Stations\r\n" - "RF Stations\r\n" - "All WX Stations\r\n" - "RF WX Stations\r\n" - "All Mobile Stations\r\n" - "RF Mobile Stations\r\n" - "All Objects\r\n" - "RF Objects\r\n" - "Information\r\n" - "Node Pages\r\n" - "\r\n" - "\r\n" - - "\r\n" - "

##MY_CALLSIGN##'s BPQ32 APRS Web Server

\r\n" - - "

Information

\r\n" - - "\r\n" - "
\r\n" - "

BPQ-WebServer is a simple plug-in web server for BPQ32. It will dynamically serve a selection of pages created from the data in BPQ32. The pages currently available are -

\r\n" - - "
    " - "
  • index.html - return to the home page
  • \r\n" - "
  • all.html - a list of all the stations heard
  • \r\n" - "
  • allrf.html - a list of all stations heard on RF
  • \r\n" - "
  • mobilesall.html - a list of all mobiles stations heard
  • \r\n" - "
  • mobilesrf.html - a list of all the mobile stations heard on RF
  • \r\n" - "
  • wxall.html - a list of all WX stations heard
  • \r\n" - "
  • wxrf.html - a list of all the WX stations heard on RF
  • \r\n" - "
  • obj.html - a list of all objects heard
  • \r\n" - "
  • objrf.html - a list of all objects heard on RF
  • \r\n" - "
" - - "

The dynamic pages use templates, so the user can make them as pretty or as simple as he wishes, including using graphics.

" - - "

Besides serving dynamic pages, BPQ-WebServer can also serve other pages that you may wish to make available. For example, this page is made available simply by putting it in BPQ-WebServer's HTML folder, and adding a link to it to the other pages.

" - "
\r\n"; - - return _strdup(Msg);; -} - -char * get_allrf() -{ - char Msg[] = - "" - "" - "" - "" - "" - "\r\n" - " \r\n" - "\r\n" - "##MY_CALLSIGN##'s BPQ32 Web Server\r\n" - "\r\n" - - "\r\n" - - "\r\n" - "\r\n" - "\r\n" - "\r\n" - "\r\n" - "Home\r\n" - "All Stations\r\n" - "RF Stations\r\n" - "All WX Stations\r\n" - "RF WX Stations\r\n" - "All Mobile Stations\r\n" - "RF Mobile Stations\r\n" - "All Objects\r\n" - "RF Objects\r\n" - "Information\r\n" - "Node Pages\r\n" - "\r\n" - "\r\n" - - "\r\n" - "

##MY_CALLSIGN##'s BPQ32 APRS Web Server

\r\n" - - "

RF Stations

\r\n" - - "

(This page will automatically refresh every five minutes)

\r\n" - - "

The following is a list of all the stations heard on RF in the past ##EXPIRE_TIME## minutes.

" - - "

'*' after a callsign means that it was heard via a digi

" - - "" - "" - "" - "" - "
The list only includes callsigns heard on RF, direct or via digipeaters.
It does not include callsigns heard on the internet,
or heard as third-party RF traffic via IGATEs.
" - - "

There are ##TABLE_COUNT## callsigns in the list,
click a callsign to get an information page for that station.

" - - "\r\n" - "\r\n" - "\r\n" - "##STATION_TABLE##
CallsignSymbolLocation##MILES_KM##BearingLast heard
\r\n" - - "\r\n" - "\r\n"; - - return _strdup(Msg);; -} - -char * get_mobilesrf() -{ - char Msg[] = - "" - "" - "" - "" - "" - "\r\n" - " \r\n" - "\r\n" - "##MY_CALLSIGN##'s BPQ32 Web Server\r\n" - "\r\n" - - "\r\n" - - "\r\n" - "\r\n" - "\r\n" - "\r\n" - "\r\n" - "Home\r\n" - "All Stations\r\n" - "RF Stations\r\n" - "All WX Stations\r\n" - "RF WX Stations\r\n" - "All Mobile Stations\r\n" - "RF Mobile Stations\r\n" - "All Objects\r\n" - "RF Objects\r\n" - "Information\r\n" - "Node Pages\r\n" - "\r\n" - "\r\n" - - "\r\n" - "

##MY_CALLSIGN##'s BPQ32 APRS Web Server

\r\n" - - "

Mobile RF Stations

\r\n" - - "

(This page will automatically refresh every five minutes)

\r\n" - - "

The following is a list of all the mobile stations heard on RF in the past ##EXPIRE_TIME## minutes.

" - - "

'*' after a callsign means that it was heard via a digi

" - - // "" - // "" - // "" - // "" - // "
The list only includes callsigns heard on RF, direct or via digipeaters.
It does not include callsigns heard on the internet,
or heard as third-party RF traffic via IGATEs.
" - - "

There are ##TABLE_COUNT## callsigns in the list,
click a callsign to get an information page for that station.

" - - "\r\n" - "\r\n" - "\r\n" - "##STATION_TABLE##
CallsignSymbolLocation##MILES_KM##BearingLast heard
\r\n" - - "\r\n" - "\r\n"; - - return _strdup(Msg);; -} - -char * get_objrf() -{ - char Msg[] = - "" - "" - "" - "" - "" - "\r\n" - " \r\n" - "\r\n" - "##MY_CALLSIGN##'s BPQ32 Web Server\r\n" - "\r\n" - - "\r\n" - - "\r\n" - "\r\n" - "\r\n" - "\r\n" - "\r\n" - "Home\r\n" - "All Stations\r\n" - "RF Stations\r\n" - "All WX Stations\r\n" - "RF WX Stations\r\n" - "All Mobile Stations\r\n" - "RF Mobile Stations\r\n" - "All Objects\r\n" - "RF Objects\r\n" - "Information\r\n" - "Node Pages\r\n" - "\r\n" - "\r\n" - - "\r\n" - "

##MY_CALLSIGN##'s BPQ32 APRS Web Server

\r\n" - - "

RF Objects

\r\n" - - "

(This page will automatically refresh every five minutes)

\r\n" - - "

The following is a list of all the objects heard on RF in the past ##EXPIRE_TIME## minutes.

" - - "

'*' after a callsign means that it was heard via a digi

" - - // "" - // "" - // "" - // "" - // "
The list only includes callsigns heard on RF, direct or via digipeaters.
It does not include callsigns heard on the internet,
or heard as third-party RF traffic via IGATEs.
" - - "

There are ##TABLE_COUNT## callsigns in the list,
click a callsign to get an information page for that station.

" - - "\r\n" - "\r\n" - "\r\n" - "##STATION_TABLE##
CallsignSymbolLocation##MILES_KM##BearingLast heard
\r\n" - - "\r\n" - "\r\n"; - - return _strdup(Msg);; -} - -char * get_wxrf() -{ - char Msg[] = - "" - "" - "" - "" - "" - "\r\n" - " \r\n" - "\r\n" - "##MY_CALLSIGN##'s BPQ32 Web Server\r\n" - "\r\n" - - "\r\n" - - "\r\n" - "\r\n" - "\r\n" - "\r\n" - "\r\n" - "Home\r\n" - "All Stations\r\n" - "RF Stations\r\n" - "All WX Stations\r\n" - "RF WX Stations\r\n" - "All Mobile Stations\r\n" - "RF Mobile Stations\r\n" - "All Objects\r\n" - "RF Objects\r\n" - "Information\r\n" - "Node Pages\r\n" - "\r\n" - "\r\n" - - "\r\n" - "

##MY_CALLSIGN##'s BPQ32 APRS Web Server

\r\n" - - "

RF WX Stations

\r\n" - - "

(This page will automatically refresh every five minutes)

\r\n" - - "

The following is a list of all the WX stations heard on RF in the past ##EXPIRE_TIME## minutes.

" - - "

'*' after a callsign means that it was heard via a digi

" - - // "" - // "" - // "" - // "" - // "
The list only includes callsigns heard on RF, direct or via digipeaters.
It does not include callsigns heard on the internet,
or heard as third-party RF traffic via IGATEs.
" - - "

There are ##TABLE_COUNT## callsigns in the list,
click a callsign to get an information page for that station.

" - - "\r\n" - "\r\n" - "\r\n" - "##STATION_TABLE##
CallsignSymbolLocation##MILES_KM##BearingLast heard
\r\n" - - "\r\n" - "\r\n"; - - return _strdup(Msg);; -} - -char * get_favicon(int * Len) -{ - unsigned char * ptr; - - unsigned char Msg[] = - { - 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x20, 0x20, 0x10, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xE8, 0x02, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x28, 0x00, - 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x01, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, - 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, - 0x80, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x80, 0x00, 0xC0, 0xC0, - 0xC0, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, - 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, - 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, - 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, - 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, - 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, - 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xB0, 0x00, 0x00, 0x0B, 0xBB, 0xBB, 0xBB, - 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0x00, 0xBB, 0x00, - 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, - 0xB0, 0x0B, 0xB0, 0x00, 0x0B, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, - 0xBB, 0xBB, 0xBB, 0xBB, 0xB0, 0x0B, 0xBB, 0xB0, 0x0B, 0xBB, 0xBB, 0xBB, - 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xB0, 0x0B, 0xBB, 0xB0, - 0x0B, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, - 0xB0, 0x0B, 0xBB, 0xB0, 0x0B, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, - 0xBB, 0xBB, 0xBB, 0xBB, 0xB0, 0x0B, 0xBB, 0xB0, 0x0B, 0xBB, 0xBB, 0xBB, - 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xB0, 0x0B, 0xBB, 0xB0, - 0x0B, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0x00, 0xBB, 0xBB, 0xBB, - 0xBB, 0x00, 0xBB, 0x00, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, - 0x00, 0xBB, 0xBB, 0xBB, 0xBB, 0xB0, 0x00, 0x0B, 0xBB, 0xBB, 0xBB, 0xBB, - 0xBB, 0xBB, 0xBB, 0xBB, 0x00, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, - 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0x00, 0xBB, 0xBB, 0xBB, - 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, - 0x00, 0x00, 0x00, 0x0B, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, - 0xBB, 0xBB, 0xBB, 0xBB, 0x00, 0xBB, 0xBB, 0x00, 0xBB, 0xBB, 0xBB, 0xBB, - 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0x00, 0xBB, 0xBB, 0x00, - 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, - 0x00, 0xBB, 0xBB, 0x00, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0x00, - 0x00, 0x00, 0x0B, 0xBB, 0x00, 0xBB, 0xBB, 0x00, 0xBB, 0xBB, 0xBB, 0xBB, - 0xBB, 0xBB, 0xBB, 0x00, 0xBB, 0xBB, 0x00, 0xBB, 0x00, 0x00, 0x00, 0x0B, - 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0x00, 0xBB, 0xBB, 0x00, 0xBB, - 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0x00, - 0xBB, 0xBB, 0x00, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, - 0xBB, 0xBB, 0xBB, 0x00, 0xBB, 0xBB, 0x00, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, - 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0x00, 0x00, 0x00, 0x0B, 0xBB, - 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0x00, - 0xBB, 0xBB, 0x00, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, - 0xBB, 0xBB, 0xBB, 0x00, 0xBB, 0xBB, 0x00, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, - 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0x00, 0xBB, 0xBB, 0x00, 0xBB, - 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0x00, - 0x00, 0x00, 0x0B, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, - 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, - 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, - 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, - 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, - 0xBB, 0xBB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }; - -#define favicon_LENGTH 0x000002FE - - ptr = malloc(favicon_LENGTH); - memcpy(ptr, Msg, favicon_LENGTH); - - return ptr; -} - -static unsigned char Clouds[] = -{ - 0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00, 0x01, - 0x02, 0x01, 0x00, 0x48, 0x00, 0x48, 0x00, 0x00, 0xFF, 0xE1, 0x08, 0x03, - 0x45, 0x78, 0x69, 0x66, 0x00, 0x00, 0x4D, 0x4D, 0x00, 0x2A, 0x00, 0x00, - 0x00, 0x08, 0x00, 0x07, 0x01, 0x12, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x00, 0x01, 0x1A, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x62, 0x01, 0x1B, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x6A, 0x01, 0x28, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x02, 0x00, 0x00, 0x01, 0x31, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, - 0x00, 0x00, 0x00, 0x72, 0x01, 0x32, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, - 0x00, 0x00, 0x00, 0x86, 0x87, 0x69, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x9C, 0x00, 0x00, 0x00, 0xC8, 0x00, 0x00, 0x00, 0x48, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, - 0x41, 0x64, 0x6F, 0x62, 0x65, 0x20, 0x50, 0x68, 0x6F, 0x74, 0x6F, 0x73, - 0x68, 0x6F, 0x70, 0x20, 0x37, 0x2E, 0x30, 0x00, 0x32, 0x30, 0x31, 0x32, - 0x3A, 0x30, 0x35, 0x3A, 0x33, 0x30, 0x20, 0x31, 0x32, 0x3A, 0x33, 0x38, - 0x3A, 0x31, 0x32, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA0, 0x01, 0x00, 0x03, - 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x00, 0xA0, 0x02, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0xF4, 0xA0, 0x03, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0xF4, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x06, 0x00, 0x00, 0x01, 0x1A, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x01, 0x16, 0x01, 0x1B, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x01, 0x1E, 0x01, 0x28, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x02, 0x00, 0x00, 0x02, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x01, 0x26, 0x02, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x06, 0xD5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, - 0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00, 0x01, - 0x02, 0x01, 0x00, 0x48, 0x00, 0x48, 0x00, 0x00, 0xFF, 0xED, 0x00, 0x0C, - 0x41, 0x64, 0x6F, 0x62, 0x65, 0x5F, 0x43, 0x4D, 0x00, 0x02, 0xFF, 0xEE, - 0x00, 0x0E, 0x41, 0x64, 0x6F, 0x62, 0x65, 0x00, 0x64, 0x80, 0x00, 0x00, - 0x00, 0x01, 0xFF, 0xDB, 0x00, 0x84, 0x00, 0x0C, 0x08, 0x08, 0x08, 0x09, - 0x08, 0x0C, 0x09, 0x09, 0x0C, 0x11, 0x0B, 0x0A, 0x0B, 0x11, 0x15, 0x0F, - 0x0C, 0x0C, 0x0F, 0x15, 0x18, 0x13, 0x13, 0x15, 0x13, 0x13, 0x18, 0x11, - 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x11, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, - 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, - 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x01, - 0x0D, 0x0B, 0x0B, 0x0D, 0x0E, 0x0D, 0x10, 0x0E, 0x0E, 0x10, 0x14, 0x0E, - 0x0E, 0x0E, 0x14, 0x14, 0x0E, 0x0E, 0x0E, 0x0E, 0x14, 0x11, 0x0C, 0x0C, - 0x0C, 0x0C, 0x0C, 0x11, 0x11, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x11, - 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, - 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, - 0x0C, 0x0C, 0x0C, 0x0C, 0xFF, 0xC0, 0x00, 0x11, 0x08, 0x00, 0x80, 0x00, - 0x80, 0x03, 0x01, 0x22, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xFF, - 0xDD, 0x00, 0x04, 0x00, 0x08, 0xFF, 0xC4, 0x01, 0x3F, 0x00, 0x00, 0x01, - 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x03, 0x00, 0x01, 0x02, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, - 0x0A, 0x0B, 0x01, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x03, 0x04, - 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x10, 0x00, 0x01, 0x04, 0x01, - 0x03, 0x02, 0x04, 0x02, 0x05, 0x07, 0x06, 0x08, 0x05, 0x03, 0x0C, 0x33, - 0x01, 0x00, 0x02, 0x11, 0x03, 0x04, 0x21, 0x12, 0x31, 0x05, 0x41, 0x51, - 0x61, 0x13, 0x22, 0x71, 0x81, 0x32, 0x06, 0x14, 0x91, 0xA1, 0xB1, 0x42, - 0x23, 0x24, 0x15, 0x52, 0xC1, 0x62, 0x33, 0x34, 0x72, 0x82, 0xD1, 0x43, - 0x07, 0x25, 0x92, 0x53, 0xF0, 0xE1, 0xF1, 0x63, 0x73, 0x35, 0x16, 0xA2, - 0xB2, 0x83, 0x26, 0x44, 0x93, 0x54, 0x64, 0x45, 0xC2, 0xA3, 0x74, 0x36, - 0x17, 0xD2, 0x55, 0xE2, 0x65, 0xF2, 0xB3, 0x84, 0xC3, 0xD3, 0x75, 0xE3, - 0xF3, 0x46, 0x27, 0x94, 0xA4, 0x85, 0xB4, 0x95, 0xC4, 0xD4, 0xE4, 0xF4, - 0xA5, 0xB5, 0xC5, 0xD5, 0xE5, 0xF5, 0x56, 0x66, 0x76, 0x86, 0x96, 0xA6, - 0xB6, 0xC6, 0xD6, 0xE6, 0xF6, 0x37, 0x47, 0x57, 0x67, 0x77, 0x87, 0x97, - 0xA7, 0xB7, 0xC7, 0xD7, 0xE7, 0xF7, 0x11, 0x00, 0x02, 0x02, 0x01, 0x02, - 0x04, 0x04, 0x03, 0x04, 0x05, 0x06, 0x07, 0x07, 0x06, 0x05, 0x35, 0x01, - 0x00, 0x02, 0x11, 0x03, 0x21, 0x31, 0x12, 0x04, 0x41, 0x51, 0x61, 0x71, - 0x22, 0x13, 0x05, 0x32, 0x81, 0x91, 0x14, 0xA1, 0xB1, 0x42, 0x23, 0xC1, - 0x52, 0xD1, 0xF0, 0x33, 0x24, 0x62, 0xE1, 0x72, 0x82, 0x92, 0x43, 0x53, - 0x15, 0x63, 0x73, 0x34, 0xF1, 0x25, 0x06, 0x16, 0xA2, 0xB2, 0x83, 0x07, - 0x26, 0x35, 0xC2, 0xD2, 0x44, 0x93, 0x54, 0xA3, 0x17, 0x64, 0x45, 0x55, - 0x36, 0x74, 0x65, 0xE2, 0xF2, 0xB3, 0x84, 0xC3, 0xD3, 0x75, 0xE3, 0xF3, - 0x46, 0x94, 0xA4, 0x85, 0xB4, 0x95, 0xC4, 0xD4, 0xE4, 0xF4, 0xA5, 0xB5, - 0xC5, 0xD5, 0xE5, 0xF5, 0x56, 0x66, 0x76, 0x86, 0x96, 0xA6, 0xB6, 0xC6, - 0xD6, 0xE6, 0xF6, 0x27, 0x37, 0x47, 0x57, 0x67, 0x77, 0x87, 0x97, 0xA7, - 0xB7, 0xC7, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, - 0x11, 0x00, 0x3F, 0x00, 0xF4, 0x22, 0x09, 0x44, 0xAC, 0x18, 0xD1, 0x40, - 0x14, 0x7A, 0x84, 0x85, 0x29, 0x61, 0x0C, 0x60, 0xF8, 0x28, 0xB8, 0x4A, - 0xB0, 0x5A, 0x10, 0x8B, 0x7D, 0xDE, 0x09, 0x02, 0x92, 0x1A, 0xEE, 0x08, - 0x64, 0x42, 0xB2, 0xF0, 0x10, 0x6C, 0x6C, 0x09, 0x1A, 0xA2, 0x0A, 0xD2, - 0x1A, 0xEE, 0x74, 0x21, 0xEE, 0x51, 0xB9, 0xE4, 0x18, 0x00, 0x94, 0x22, - 0xF7, 0x07, 0x42, 0x78, 0x0B, 0x09, 0x4F, 0x29, 0xA5, 0x44, 0x6E, 0x70, - 0xD0, 0x29, 0x32, 0xB7, 0x1E, 0x78, 0x49, 0x4A, 0xE5, 0x49, 0xA0, 0xA9, - 0x06, 0x34, 0x09, 0xF0, 0x4C, 0xDE, 0x50, 0x4D, 0x32, 0x68, 0x46, 0x63, - 0x47, 0x7D, 0x14, 0x1A, 0xE8, 0x10, 0x8A, 0xD3, 0x25, 0x02, 0x90, 0xCB, - 0x60, 0x09, 0xE5, 0x46, 0x4F, 0x8A, 0x52, 0x7B, 0xA0, 0x9B, 0x7F, 0xFF, - 0xD0, 0xF4, 0x26, 0xB4, 0xF7, 0x56, 0x2B, 0x8F, 0x04, 0x1D, 0xE0, 0xF0, - 0x21, 0x15, 0xA6, 0x02, 0x98, 0xB0, 0x84, 0xC3, 0x85, 0x02, 0x07, 0x25, - 0x20, 0xFD, 0x14, 0x6C, 0x70, 0x23, 0x44, 0xDA, 0x4A, 0x2B, 0x1D, 0xAA, - 0x03, 0xAC, 0x04, 0xC1, 0x45, 0xB1, 0x84, 0x83, 0xE0, 0xAA, 0xB9, 0xAE, - 0x13, 0xF9, 0x53, 0x82, 0xD2, 0x56, 0x24, 0xB9, 0xDA, 0x08, 0x08, 0xAD, - 0xC6, 0x6C, 0x4B, 0xBE, 0xF5, 0x0A, 0xD8, 0x49, 0x93, 0xC0, 0xE0, 0x23, - 0x4F, 0xB7, 0x50, 0x89, 0x40, 0x44, 0xF0, 0xD6, 0x98, 0x89, 0xF3, 0x50, - 0xB2, 0xC0, 0xC0, 0x48, 0x10, 0xA5, 0x6B, 0xD8, 0xC3, 0x3A, 0x94, 0x17, - 0x58, 0xCB, 0x3E, 0x7D, 0x91, 0x08, 0x25, 0x1F, 0xAE, 0x1C, 0x76, 0xEB, - 0x25, 0x11, 0xB3, 0xA4, 0x4A, 0x42, 0x80, 0x06, 0xE5, 0x30, 0xD8, 0x8D, - 0x11, 0x40, 0xBE, 0xA9, 0x2B, 0x73, 0x46, 0x84, 0x4C, 0xA2, 0xFB, 0x47, - 0x65, 0x0A, 0xF9, 0x82, 0x34, 0x45, 0x21, 0xA1, 0x34, 0xAE, 0x0C, 0x80, - 0xDD, 0xC0, 0x48, 0x80, 0x07, 0x1A, 0xA8, 0xB2, 0xC6, 0x8E, 0xFA, 0x29, - 0x7A, 0x80, 0xA0, 0x97, 0xFF, 0xD1, 0xF4, 0x1A, 0xCC, 0x8D, 0x51, 0x37, - 0x82, 0x15, 0x2A, 0xAE, 0x9E, 0x55, 0x86, 0x49, 0x20, 0x8E, 0x14, 0xE4, - 0x35, 0xC1, 0x6C, 0x86, 0xCB, 0x7C, 0xD0, 0x5C, 0xE8, 0x3A, 0xA2, 0x87, - 0x10, 0x39, 0x55, 0xAD, 0x81, 0x24, 0x94, 0x02, 0x4B, 0x37, 0x5B, 0xB4, - 0x6B, 0xAC, 0xA1, 0xB5, 0xBB, 0xFE, 0x03, 0x55, 0x16, 0x89, 0x1A, 0xF7, - 0xE1, 0x11, 0xB0, 0xC6, 0xA2, 0x8B, 0x58, 0x80, 0x38, 0xF6, 0xA8, 0x97, - 0x1D, 0xB3, 0xBA, 0x0F, 0x82, 0x4E, 0xD7, 0xC8, 0x1E, 0xC9, 0xBD, 0x22, - 0x62, 0x52, 0x55, 0xA2, 0xB2, 0xB9, 0x1A, 0x19, 0x43, 0x2C, 0xF2, 0xD5, - 0x5D, 0x35, 0xD7, 0xB7, 0x68, 0x10, 0x50, 0x36, 0x41, 0x23, 0xF1, 0x4E, - 0x05, 0x04, 0x2E, 0xC7, 0x43, 0x7C, 0xD2, 0x0E, 0x6C, 0x68, 0xA0, 0x46, - 0xC9, 0xF1, 0x48, 0x81, 0x00, 0xFD, 0xE9, 0x52, 0x2D, 0x6F, 0x59, 0xD3, - 0x00, 0xC2, 0x9F, 0xAA, 0xF8, 0xFA, 0x48, 0x24, 0x7B, 0x92, 0x6D, 0x80, - 0x18, 0x76, 0x90, 0x95, 0x22, 0xD9, 0xFA, 0x86, 0x79, 0xD4, 0x27, 0x6B, - 0xDC, 0x4F, 0x2A, 0xBB, 0xAD, 0x6C, 0x94, 0x99, 0x76, 0xB2, 0x8D, 0x2A, - 0xDF, 0xFF, 0xD2, 0xED, 0x68, 0x68, 0x8F, 0x35, 0x66, 0xB7, 0x96, 0x13, - 0xAE, 0x8A, 0xB3, 0x76, 0x31, 0x93, 0x30, 0x67, 0x84, 0xDE, 0xA8, 0x2E, - 0xD4, 0xAB, 0x24, 0x5B, 0x50, 0x1A, 0x6F, 0x7A, 0xA1, 0xDD, 0xE5, 0x02, - 0xE7, 0x01, 0xA3, 0x8F, 0xC9, 0x53, 0xB3, 0x20, 0xB5, 0xE4, 0xB7, 0x8F, - 0x04, 0x3F, 0x5D, 0xD6, 0x76, 0x44, 0x41, 0x46, 0x6D, 0xC6, 0xD9, 0xAE, - 0x9C, 0x22, 0x87, 0xB7, 0xBF, 0x2A, 0xA3, 0x09, 0xDB, 0x10, 0x3F, 0x8A, - 0x98, 0x7B, 0x82, 0x44, 0x28, 0x49, 0xB6, 0x4B, 0x42, 0x94, 0x83, 0x0A, - 0xA8, 0xB0, 0x11, 0x12, 0x65, 0x19, 0x91, 0x09, 0xB4, 0xB8, 0x16, 0x76, - 0x4F, 0xE6, 0xEA, 0x7B, 0x21, 0x7B, 0x86, 0xAE, 0xD3, 0xE2, 0xA7, 0xEA, - 0x11, 0x12, 0x9A, 0xDB, 0x18, 0x5B, 0xA9, 0x94, 0x94, 0x85, 0xF1, 0x3E, - 0xEE, 0xE8, 0x86, 0xB9, 0x60, 0x11, 0x03, 0xC5, 0x0C, 0x34, 0x1D, 0x47, - 0x6E, 0xC5, 0x11, 0xB6, 0xB8, 0x0D, 0x46, 0x83, 0x84, 0x4A, 0x02, 0x27, - 0x8F, 0x4C, 0x6B, 0xCA, 0xA9, 0x6D, 0x85, 0xDF, 0x04, 0x7B, 0x8E, 0xF3, - 0xA6, 0x84, 0x94, 0xDE, 0x80, 0x03, 0xDC, 0x7E, 0x49, 0xC1, 0x69, 0xD5, - 0xA2, 0x5E, 0x67, 0x5F, 0xBD, 0x16, 0xA0, 0x4E, 0xBF, 0x72, 0xB4, 0xCC, - 0x6A, 0xCB, 0x74, 0x4E, 0x68, 0xD9, 0x03, 0x90, 0x8F, 0x10, 0x5B, 0xC2, - 0x5F, 0xFF, 0xD3, 0xEA, 0xCD, 0xA7, 0xE8, 0x84, 0xDB, 0xFC, 0x79, 0x4F, - 0xE9, 0x38, 0xA7, 0xF4, 0x65, 0x5C, 0xD1, 0xA1, 0xAA, 0x33, 0xA9, 0x48, - 0x13, 0xD9, 0x17, 0xD1, 0x69, 0xD4, 0x9D, 0x14, 0x0E, 0x86, 0x3C, 0x38, - 0x45, 0x54, 0xB7, 0xA8, 0x41, 0xD3, 0x94, 0x41, 0x69, 0xEE, 0x50, 0x5C, - 0xD2, 0x99, 0xAC, 0x74, 0xF9, 0x25, 0xA2, 0xAC, 0xB6, 0x1B, 0x71, 0x07, - 0x8F, 0x9A, 0x28, 0xB1, 0xC6, 0x35, 0x55, 0x64, 0x8E, 0x79, 0x44, 0x63, - 0x87, 0x32, 0x81, 0x09, 0x05, 0x3B, 0x9C, 0xE3, 0xAC, 0xA6, 0x13, 0x3A, - 0x73, 0xE2, 0xA2, 0x1C, 0x0F, 0x74, 0x4A, 0xE0, 0x90, 0x0F, 0x74, 0x17, - 0x32, 0x60, 0x23, 0xCD, 0x4C, 0x26, 0x88, 0x30, 0x91, 0x29, 0xA9, 0x46, - 0xE6, 0x80, 0xE9, 0x8E, 0x39, 0x51, 0x71, 0xDD, 0xA7, 0x08, 0xA5, 0x30, - 0x69, 0x3C, 0x04, 0x6D, 0x0C, 0x01, 0xD9, 0xC7, 0x3E, 0x2A, 0x0F, 0x79, - 0x8E, 0x54, 0x9E, 0xD2, 0x0A, 0x0B, 0xDA, 0x4A, 0x21, 0x05, 0xFF, 0xD4, - 0xEC, 0xC3, 0x44, 0x6A, 0x96, 0xE0, 0x3C, 0xD5, 0x6F, 0xB4, 0x87, 0x1D, - 0x24, 0xA2, 0x56, 0x4B, 0xCC, 0x42, 0xB7, 0x4D, 0x3B, 0x1D, 0x12, 0x68, - 0x75, 0xF0, 0x50, 0x73, 0x9B, 0xD8, 0x29, 0xBD, 0x9B, 0x47, 0x28, 0x71, - 0xDD, 0x20, 0xA2, 0xC6, 0x0F, 0x60, 0x9F, 0x67, 0x92, 0x93, 0x66, 0x51, - 0x01, 0x8E, 0x44, 0xA5, 0x6A, 0xA4, 0x05, 0x93, 0xCA, 0x67, 0x6D, 0x6A, - 0x23, 0xCE, 0xBA, 0x28, 0x47, 0xF2, 0x44, 0xA2, 0x82, 0x15, 0x59, 0x9F, - 0x29, 0xF1, 0x56, 0x2B, 0x60, 0xE4, 0x99, 0xF2, 0x55, 0xB7, 0x86, 0xC4, - 0x85, 0x2F, 0xB4, 0xBF, 0x81, 0xF8, 0xA0, 0x6D, 0x40, 0x80, 0xDB, 0x0E, - 0x05, 0x22, 0x55, 0x56, 0xD9, 0xAC, 0xCA, 0x28, 0xB0, 0x21, 0x4B, 0xAD, - 0x28, 0x1B, 0xB8, 0x45, 0xAD, 0xA5, 0xBC, 0xF7, 0x55, 0x3E, 0xD0, 0x1A, - 0xA4, 0xCC, 0xC6, 0x9D, 0x0F, 0x28, 0x10, 0x54, 0x08, 0x4D, 0x68, 0x07, - 0x8D, 0x4A, 0x09, 0x69, 0xF0, 0x4E, 0xEB, 0xC7, 0x68, 0x3E, 0x68, 0x67, - 0x29, 0xAD, 0x69, 0x9F, 0x92, 0x20, 0x15, 0x12, 0x1F, 0xFF, 0xD5, 0xEB, - 0x46, 0x33, 0x87, 0x01, 0x3F, 0xA7, 0x6B, 0x75, 0x06, 0x07, 0xE2, 0xAD, - 0x8D, 0xC3, 0x8E, 0xE9, 0xB6, 0x13, 0xCA, 0xB5, 0xC4, 0xD4, 0xE1, 0x0D, - 0x33, 0xEA, 0x18, 0x92, 0xA5, 0xC0, 0x8E, 0xEA, 0xDF, 0xA2, 0xD3, 0xD9, - 0x2F, 0x48, 0x01, 0xC2, 0x5C, 0x4A, 0xE1, 0x2D, 0x51, 0x1F, 0x34, 0xE6, - 0xC0, 0x02, 0x31, 0xAC, 0x14, 0x3B, 0x18, 0x47, 0x01, 0x2B, 0x0A, 0xA2, - 0x87, 0x79, 0x9D, 0x54, 0x1D, 0x6F, 0x75, 0x37, 0x53, 0x61, 0xD6, 0x14, - 0x0D, 0x64, 0x09, 0x21, 0x3B, 0x45, 0xA6, 0xD1, 0xBD, 0xFB, 0xB5, 0x01, - 0x38, 0x32, 0x3F, 0x82, 0x44, 0x38, 0xE8, 0x02, 0x23, 0x2B, 0x9F, 0x2F, - 0x8A, 0x56, 0x8A, 0x60, 0x1D, 0x1A, 0xA4, 0x6D, 0x8F, 0x8A, 0x28, 0xA9, - 0xDD, 0xB5, 0x1F, 0x82, 0x4E, 0xA8, 0x1D, 0x74, 0x94, 0xAC, 0x2A, 0x8A, - 0x22, 0xF9, 0x52, 0x68, 0xF2, 0x92, 0xA4, 0x6B, 0x20, 0x79, 0xF9, 0x26, - 0x1B, 0x87, 0x23, 0x44, 0xAD, 0x34, 0xC1, 0xAC, 0x71, 0x76, 0xB2, 0x8A, - 0x71, 0x89, 0xD7, 0x52, 0x54, 0x98, 0x78, 0x85, 0x65, 0x80, 0xC2, 0x06, - 0x49, 0x11, 0x0F, 0xFF, 0xD6, 0xEF, 0x9A, 0xDF, 0x15, 0x20, 0xDF, 0x24, - 0xFC, 0x15, 0x36, 0x89, 0x53, 0x5B, 0x05, 0x30, 0xDA, 0xA2, 0x5A, 0x8E, - 0x5A, 0xA0, 0x5A, 0x95, 0xA6, 0x90, 0x96, 0xC2, 0x81, 0x00, 0xA2, 0xB8, - 0x28, 0x22, 0xB5, 0x19, 0x60, 0x88, 0x84, 0x27, 0xD6, 0x22, 0x00, 0xE1, - 0x58, 0x25, 0x0C, 0xA2, 0x10, 0x40, 0x43, 0xB1, 0xA7, 0xE9, 0x69, 0x0A, - 0x62, 0xB1, 0x13, 0x32, 0x12, 0x21, 0x38, 0x24, 0x70, 0x8D, 0xA2, 0x91, - 0x19, 0x07, 0x44, 0xA1, 0xDF, 0xEC, 0x44, 0x30, 0x90, 0x84, 0xAD, 0x54, - 0xC1, 0xAD, 0x77, 0x8A, 0x23, 0x6B, 0x61, 0x3E, 0xED, 0x54, 0x80, 0x08, - 0x83, 0x6F, 0x64, 0x09, 0x48, 0x0C, 0x05, 0x4D, 0xEC, 0x11, 0x03, 0x23, - 0x84, 0xED, 0x08, 0x80, 0x21, 0x69, 0x01, 0xFF, 0xD9, 0xFF, 0xED, 0x0C, - 0x98, 0x50, 0x68, 0x6F, 0x74, 0x6F, 0x73, 0x68, 0x6F, 0x70, 0x20, 0x33, - 0x2E, 0x30, 0x00, 0x38, 0x42, 0x49, 0x4D, 0x04, 0x25, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x42, 0x49, 0x4D, 0x03, - 0xED, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x48, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x38, - 0x42, 0x49, 0x4D, 0x04, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x80, 0x00, - 0x00, 0x38, 0x42, 0x49, 0x4D, 0x04, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x1E, 0x38, 0x42, 0x49, 0x4D, 0x04, 0x19, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1E, 0x38, 0x42, 0x49, - 0x4D, 0x03, 0xF3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x38, 0x42, 0x49, 0x4D, 0x04, - 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x38, 0x42, 0x49, - 0x4D, 0x27, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x38, 0x42, 0x49, 0x4D, 0x03, - 0xF5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x2F, 0x66, 0x66, 0x00, - 0x01, 0x00, 0x6C, 0x66, 0x66, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x2F, 0x66, 0x66, 0x00, 0x01, 0x00, 0xA1, 0x99, 0x9A, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x32, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x5A, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x35, 0x00, 0x00, 0x00, 0x01, 0x00, 0x2D, 0x00, 0x00, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x38, 0x42, 0x49, 0x4D, 0x03, - 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xE8, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, - 0xE8, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x03, 0xE8, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xE8, 0x00, 0x00, 0x38, - 0x42, 0x49, 0x4D, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, - 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x02, 0x40, 0x00, - 0x00, 0x00, 0x00, 0x38, 0x42, 0x49, 0x4D, 0x04, 0x1E, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x38, 0x42, 0x49, 0x4D, 0x04, - 0x1A, 0x00, 0x00, 0x00, 0x00, 0x03, 0x41, 0x00, 0x00, 0x00, 0x06, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xF4, 0x00, - 0x00, 0x01, 0xF4, 0x00, 0x00, 0x00, 0x06, 0x00, 0x63, 0x00, 0x6C, 0x00, - 0x6F, 0x00, 0x75, 0x00, 0x64, 0x00, 0x73, 0x00, 0x00, 0x00, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xF4, 0x00, 0x00, 0x01, 0xF4, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6E, 0x75, - 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x62, 0x6F, - 0x75, 0x6E, 0x64, 0x73, 0x4F, 0x62, 0x6A, 0x63, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x63, 0x74, 0x31, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x54, 0x6F, 0x70, 0x20, 0x6C, 0x6F, - 0x6E, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4C, 0x65, - 0x66, 0x74, 0x6C, 0x6F, 0x6E, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x42, 0x74, 0x6F, 0x6D, 0x6C, 0x6F, 0x6E, 0x67, 0x00, 0x00, - 0x01, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x52, 0x67, 0x68, 0x74, 0x6C, 0x6F, - 0x6E, 0x67, 0x00, 0x00, 0x01, 0xF4, 0x00, 0x00, 0x00, 0x06, 0x73, 0x6C, - 0x69, 0x63, 0x65, 0x73, 0x56, 0x6C, 0x4C, 0x73, 0x00, 0x00, 0x00, 0x01, - 0x4F, 0x62, 0x6A, 0x63, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x05, 0x73, 0x6C, 0x69, 0x63, 0x65, 0x00, 0x00, 0x00, 0x12, 0x00, - 0x00, 0x00, 0x07, 0x73, 0x6C, 0x69, 0x63, 0x65, 0x49, 0x44, 0x6C, 0x6F, - 0x6E, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x67, 0x72, - 0x6F, 0x75, 0x70, 0x49, 0x44, 0x6C, 0x6F, 0x6E, 0x67, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x06, 0x6F, 0x72, 0x69, 0x67, 0x69, 0x6E, 0x65, - 0x6E, 0x75, 0x6D, 0x00, 0x00, 0x00, 0x0C, 0x45, 0x53, 0x6C, 0x69, 0x63, - 0x65, 0x4F, 0x72, 0x69, 0x67, 0x69, 0x6E, 0x00, 0x00, 0x00, 0x0D, 0x61, - 0x75, 0x74, 0x6F, 0x47, 0x65, 0x6E, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, - 0x00, 0x00, 0x00, 0x00, 0x54, 0x79, 0x70, 0x65, 0x65, 0x6E, 0x75, 0x6D, - 0x00, 0x00, 0x00, 0x0A, 0x45, 0x53, 0x6C, 0x69, 0x63, 0x65, 0x54, 0x79, - 0x70, 0x65, 0x00, 0x00, 0x00, 0x00, 0x49, 0x6D, 0x67, 0x20, 0x00, 0x00, - 0x00, 0x06, 0x62, 0x6F, 0x75, 0x6E, 0x64, 0x73, 0x4F, 0x62, 0x6A, 0x63, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x63, - 0x74, 0x31, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x54, 0x6F, - 0x70, 0x20, 0x6C, 0x6F, 0x6E, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x4C, 0x65, 0x66, 0x74, 0x6C, 0x6F, 0x6E, 0x67, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x74, 0x6F, 0x6D, 0x6C, 0x6F, - 0x6E, 0x67, 0x00, 0x00, 0x01, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x52, 0x67, - 0x68, 0x74, 0x6C, 0x6F, 0x6E, 0x67, 0x00, 0x00, 0x01, 0xF4, 0x00, 0x00, - 0x00, 0x03, 0x75, 0x72, 0x6C, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6E, 0x75, 0x6C, 0x6C, 0x54, - 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x4D, 0x73, 0x67, 0x65, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x61, 0x6C, 0x74, 0x54, 0x61, - 0x67, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x0E, 0x63, 0x65, 0x6C, 0x6C, 0x54, 0x65, 0x78, 0x74, 0x49, - 0x73, 0x48, 0x54, 0x4D, 0x4C, 0x62, 0x6F, 0x6F, 0x6C, 0x01, 0x00, 0x00, - 0x00, 0x08, 0x63, 0x65, 0x6C, 0x6C, 0x54, 0x65, 0x78, 0x74, 0x54, 0x45, - 0x58, 0x54, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, - 0x68, 0x6F, 0x72, 0x7A, 0x41, 0x6C, 0x69, 0x67, 0x6E, 0x65, 0x6E, 0x75, - 0x6D, 0x00, 0x00, 0x00, 0x0F, 0x45, 0x53, 0x6C, 0x69, 0x63, 0x65, 0x48, - 0x6F, 0x72, 0x7A, 0x41, 0x6C, 0x69, 0x67, 0x6E, 0x00, 0x00, 0x00, 0x07, - 0x64, 0x65, 0x66, 0x61, 0x75, 0x6C, 0x74, 0x00, 0x00, 0x00, 0x09, 0x76, - 0x65, 0x72, 0x74, 0x41, 0x6C, 0x69, 0x67, 0x6E, 0x65, 0x6E, 0x75, 0x6D, - 0x00, 0x00, 0x00, 0x0F, 0x45, 0x53, 0x6C, 0x69, 0x63, 0x65, 0x56, 0x65, - 0x72, 0x74, 0x41, 0x6C, 0x69, 0x67, 0x6E, 0x00, 0x00, 0x00, 0x07, 0x64, - 0x65, 0x66, 0x61, 0x75, 0x6C, 0x74, 0x00, 0x00, 0x00, 0x0B, 0x62, 0x67, - 0x43, 0x6F, 0x6C, 0x6F, 0x72, 0x54, 0x79, 0x70, 0x65, 0x65, 0x6E, 0x75, - 0x6D, 0x00, 0x00, 0x00, 0x11, 0x45, 0x53, 0x6C, 0x69, 0x63, 0x65, 0x42, - 0x47, 0x43, 0x6F, 0x6C, 0x6F, 0x72, 0x54, 0x79, 0x70, 0x65, 0x00, 0x00, - 0x00, 0x00, 0x4E, 0x6F, 0x6E, 0x65, 0x00, 0x00, 0x00, 0x09, 0x74, 0x6F, - 0x70, 0x4F, 0x75, 0x74, 0x73, 0x65, 0x74, 0x6C, 0x6F, 0x6E, 0x67, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x6C, 0x65, 0x66, 0x74, 0x4F, - 0x75, 0x74, 0x73, 0x65, 0x74, 0x6C, 0x6F, 0x6E, 0x67, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0C, 0x62, 0x6F, 0x74, 0x74, 0x6F, 0x6D, 0x4F, - 0x75, 0x74, 0x73, 0x65, 0x74, 0x6C, 0x6F, 0x6E, 0x67, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0B, 0x72, 0x69, 0x67, 0x68, 0x74, 0x4F, 0x75, - 0x74, 0x73, 0x65, 0x74, 0x6C, 0x6F, 0x6E, 0x67, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x38, 0x42, 0x49, 0x4D, 0x04, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x01, 0x00, 0x38, 0x42, 0x49, 0x4D, 0x04, 0x14, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x38, 0x42, 0x49, 0x4D, 0x04, - 0x0C, 0x00, 0x00, 0x00, 0x00, 0x06, 0xF1, 0x00, 0x00, 0x00, 0x01, 0x00, - 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, - 0x00, 0xC0, 0x00, 0x00, 0x00, 0x06, 0xD5, 0x00, 0x18, 0x00, 0x01, 0xFF, - 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00, 0x01, 0x02, - 0x01, 0x00, 0x48, 0x00, 0x48, 0x00, 0x00, 0xFF, 0xED, 0x00, 0x0C, 0x41, - 0x64, 0x6F, 0x62, 0x65, 0x5F, 0x43, 0x4D, 0x00, 0x02, 0xFF, 0xEE, 0x00, - 0x0E, 0x41, 0x64, 0x6F, 0x62, 0x65, 0x00, 0x64, 0x80, 0x00, 0x00, 0x00, - 0x01, 0xFF, 0xDB, 0x00, 0x84, 0x00, 0x0C, 0x08, 0x08, 0x08, 0x09, 0x08, - 0x0C, 0x09, 0x09, 0x0C, 0x11, 0x0B, 0x0A, 0x0B, 0x11, 0x15, 0x0F, 0x0C, - 0x0C, 0x0F, 0x15, 0x18, 0x13, 0x13, 0x15, 0x13, 0x13, 0x18, 0x11, 0x0C, - 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x11, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, - 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, - 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x01, 0x0D, - 0x0B, 0x0B, 0x0D, 0x0E, 0x0D, 0x10, 0x0E, 0x0E, 0x10, 0x14, 0x0E, 0x0E, - 0x0E, 0x14, 0x14, 0x0E, 0x0E, 0x0E, 0x0E, 0x14, 0x11, 0x0C, 0x0C, 0x0C, - 0x0C, 0x0C, 0x11, 0x11, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x11, 0x0C, - 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, - 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, - 0x0C, 0x0C, 0x0C, 0xFF, 0xC0, 0x00, 0x11, 0x08, 0x00, 0x80, 0x00, 0x80, - 0x03, 0x01, 0x22, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xFF, 0xDD, - 0x00, 0x04, 0x00, 0x08, 0xFF, 0xC4, 0x01, 0x3F, 0x00, 0x00, 0x01, 0x05, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x03, 0x00, 0x01, 0x02, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, - 0x0B, 0x01, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x03, 0x04, 0x05, - 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x10, 0x00, 0x01, 0x04, 0x01, 0x03, - 0x02, 0x04, 0x02, 0x05, 0x07, 0x06, 0x08, 0x05, 0x03, 0x0C, 0x33, 0x01, - 0x00, 0x02, 0x11, 0x03, 0x04, 0x21, 0x12, 0x31, 0x05, 0x41, 0x51, 0x61, - 0x13, 0x22, 0x71, 0x81, 0x32, 0x06, 0x14, 0x91, 0xA1, 0xB1, 0x42, 0x23, - 0x24, 0x15, 0x52, 0xC1, 0x62, 0x33, 0x34, 0x72, 0x82, 0xD1, 0x43, 0x07, - 0x25, 0x92, 0x53, 0xF0, 0xE1, 0xF1, 0x63, 0x73, 0x35, 0x16, 0xA2, 0xB2, - 0x83, 0x26, 0x44, 0x93, 0x54, 0x64, 0x45, 0xC2, 0xA3, 0x74, 0x36, 0x17, - 0xD2, 0x55, 0xE2, 0x65, 0xF2, 0xB3, 0x84, 0xC3, 0xD3, 0x75, 0xE3, 0xF3, - 0x46, 0x27, 0x94, 0xA4, 0x85, 0xB4, 0x95, 0xC4, 0xD4, 0xE4, 0xF4, 0xA5, - 0xB5, 0xC5, 0xD5, 0xE5, 0xF5, 0x56, 0x66, 0x76, 0x86, 0x96, 0xA6, 0xB6, - 0xC6, 0xD6, 0xE6, 0xF6, 0x37, 0x47, 0x57, 0x67, 0x77, 0x87, 0x97, 0xA7, - 0xB7, 0xC7, 0xD7, 0xE7, 0xF7, 0x11, 0x00, 0x02, 0x02, 0x01, 0x02, 0x04, - 0x04, 0x03, 0x04, 0x05, 0x06, 0x07, 0x07, 0x06, 0x05, 0x35, 0x01, 0x00, - 0x02, 0x11, 0x03, 0x21, 0x31, 0x12, 0x04, 0x41, 0x51, 0x61, 0x71, 0x22, - 0x13, 0x05, 0x32, 0x81, 0x91, 0x14, 0xA1, 0xB1, 0x42, 0x23, 0xC1, 0x52, - 0xD1, 0xF0, 0x33, 0x24, 0x62, 0xE1, 0x72, 0x82, 0x92, 0x43, 0x53, 0x15, - 0x63, 0x73, 0x34, 0xF1, 0x25, 0x06, 0x16, 0xA2, 0xB2, 0x83, 0x07, 0x26, - 0x35, 0xC2, 0xD2, 0x44, 0x93, 0x54, 0xA3, 0x17, 0x64, 0x45, 0x55, 0x36, - 0x74, 0x65, 0xE2, 0xF2, 0xB3, 0x84, 0xC3, 0xD3, 0x75, 0xE3, 0xF3, 0x46, - 0x94, 0xA4, 0x85, 0xB4, 0x95, 0xC4, 0xD4, 0xE4, 0xF4, 0xA5, 0xB5, 0xC5, - 0xD5, 0xE5, 0xF5, 0x56, 0x66, 0x76, 0x86, 0x96, 0xA6, 0xB6, 0xC6, 0xD6, - 0xE6, 0xF6, 0x27, 0x37, 0x47, 0x57, 0x67, 0x77, 0x87, 0x97, 0xA7, 0xB7, - 0xC7, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, - 0x00, 0x3F, 0x00, 0xF4, 0x22, 0x09, 0x44, 0xAC, 0x18, 0xD1, 0x40, 0x14, - 0x7A, 0x84, 0x85, 0x29, 0x61, 0x0C, 0x60, 0xF8, 0x28, 0xB8, 0x4A, 0xB0, - 0x5A, 0x10, 0x8B, 0x7D, 0xDE, 0x09, 0x02, 0x92, 0x1A, 0xEE, 0x08, 0x64, - 0x42, 0xB2, 0xF0, 0x10, 0x6C, 0x6C, 0x09, 0x1A, 0xA2, 0x0A, 0xD2, 0x1A, - 0xEE, 0x74, 0x21, 0xEE, 0x51, 0xB9, 0xE4, 0x18, 0x00, 0x94, 0x22, 0xF7, - 0x07, 0x42, 0x78, 0x0B, 0x09, 0x4F, 0x29, 0xA5, 0x44, 0x6E, 0x70, 0xD0, - 0x29, 0x32, 0xB7, 0x1E, 0x78, 0x49, 0x4A, 0xE5, 0x49, 0xA0, 0xA9, 0x06, - 0x34, 0x09, 0xF0, 0x4C, 0xDE, 0x50, 0x4D, 0x32, 0x68, 0x46, 0x63, 0x47, - 0x7D, 0x14, 0x1A, 0xE8, 0x10, 0x8A, 0xD3, 0x25, 0x02, 0x90, 0xCB, 0x60, - 0x09, 0xE5, 0x46, 0x4F, 0x8A, 0x52, 0x7B, 0xA0, 0x9B, 0x7F, 0xFF, 0xD0, - 0xF4, 0x26, 0xB4, 0xF7, 0x56, 0x2B, 0x8F, 0x04, 0x1D, 0xE0, 0xF0, 0x21, - 0x15, 0xA6, 0x02, 0x98, 0xB0, 0x84, 0xC3, 0x85, 0x02, 0x07, 0x25, 0x20, - 0xFD, 0x14, 0x6C, 0x70, 0x23, 0x44, 0xDA, 0x4A, 0x2B, 0x1D, 0xAA, 0x03, - 0xAC, 0x04, 0xC1, 0x45, 0xB1, 0x84, 0x83, 0xE0, 0xAA, 0xB9, 0xAE, 0x13, - 0xF9, 0x53, 0x82, 0xD2, 0x56, 0x24, 0xB9, 0xDA, 0x08, 0x08, 0xAD, 0xC6, - 0x6C, 0x4B, 0xBE, 0xF5, 0x0A, 0xD8, 0x49, 0x93, 0xC0, 0xE0, 0x23, 0x4F, - 0xB7, 0x50, 0x89, 0x40, 0x44, 0xF0, 0xD6, 0x98, 0x89, 0xF3, 0x50, 0xB2, - 0xC0, 0xC0, 0x48, 0x10, 0xA5, 0x6B, 0xD8, 0xC3, 0x3A, 0x94, 0x17, 0x58, - 0xCB, 0x3E, 0x7D, 0x91, 0x08, 0x25, 0x1F, 0xAE, 0x1C, 0x76, 0xEB, 0x25, - 0x11, 0xB3, 0xA4, 0x4A, 0x42, 0x80, 0x06, 0xE5, 0x30, 0xD8, 0x8D, 0x11, - 0x40, 0xBE, 0xA9, 0x2B, 0x73, 0x46, 0x84, 0x4C, 0xA2, 0xFB, 0x47, 0x65, - 0x0A, 0xF9, 0x82, 0x34, 0x45, 0x21, 0xA1, 0x34, 0xAE, 0x0C, 0x80, 0xDD, - 0xC0, 0x48, 0x80, 0x07, 0x1A, 0xA8, 0xB2, 0xC6, 0x8E, 0xFA, 0x29, 0x7A, - 0x80, 0xA0, 0x97, 0xFF, 0xD1, 0xF4, 0x1A, 0xCC, 0x8D, 0x51, 0x37, 0x82, - 0x15, 0x2A, 0xAE, 0x9E, 0x55, 0x86, 0x49, 0x20, 0x8E, 0x14, 0xE4, 0x35, - 0xC1, 0x6C, 0x86, 0xCB, 0x7C, 0xD0, 0x5C, 0xE8, 0x3A, 0xA2, 0x87, 0x10, - 0x39, 0x55, 0xAD, 0x81, 0x24, 0x94, 0x02, 0x4B, 0x37, 0x5B, 0xB4, 0x6B, - 0xAC, 0xA1, 0xB5, 0xBB, 0xFE, 0x03, 0x55, 0x16, 0x89, 0x1A, 0xF7, 0xE1, - 0x11, 0xB0, 0xC6, 0xA2, 0x8B, 0x58, 0x80, 0x38, 0xF6, 0xA8, 0x97, 0x1D, - 0xB3, 0xBA, 0x0F, 0x82, 0x4E, 0xD7, 0xC8, 0x1E, 0xC9, 0xBD, 0x22, 0x62, - 0x52, 0x55, 0xA2, 0xB2, 0xB9, 0x1A, 0x19, 0x43, 0x2C, 0xF2, 0xD5, 0x5D, - 0x35, 0xD7, 0xB7, 0x68, 0x10, 0x50, 0x36, 0x41, 0x23, 0xF1, 0x4E, 0x05, - 0x04, 0x2E, 0xC7, 0x43, 0x7C, 0xD2, 0x0E, 0x6C, 0x68, 0xA0, 0x46, 0xC9, - 0xF1, 0x48, 0x81, 0x00, 0xFD, 0xE9, 0x52, 0x2D, 0x6F, 0x59, 0xD3, 0x00, - 0xC2, 0x9F, 0xAA, 0xF8, 0xFA, 0x48, 0x24, 0x7B, 0x92, 0x6D, 0x80, 0x18, - 0x76, 0x90, 0x95, 0x22, 0xD9, 0xFA, 0x86, 0x79, 0xD4, 0x27, 0x6B, 0xDC, - 0x4F, 0x2A, 0xBB, 0xAD, 0x6C, 0x94, 0x99, 0x76, 0xB2, 0x8D, 0x2A, 0xDF, - 0xFF, 0xD2, 0xED, 0x68, 0x68, 0x8F, 0x35, 0x66, 0xB7, 0x96, 0x13, 0xAE, - 0x8A, 0xB3, 0x76, 0x31, 0x93, 0x30, 0x67, 0x84, 0xDE, 0xA8, 0x2E, 0xD4, - 0xAB, 0x24, 0x5B, 0x50, 0x1A, 0x6F, 0x7A, 0xA1, 0xDD, 0xE5, 0x02, 0xE7, - 0x01, 0xA3, 0x8F, 0xC9, 0x53, 0xB3, 0x20, 0xB5, 0xE4, 0xB7, 0x8F, 0x04, - 0x3F, 0x5D, 0xD6, 0x76, 0x44, 0x41, 0x46, 0x6D, 0xC6, 0xD9, 0xAE, 0x9C, - 0x22, 0x87, 0xB7, 0xBF, 0x2A, 0xA3, 0x09, 0xDB, 0x10, 0x3F, 0x8A, 0x98, - 0x7B, 0x82, 0x44, 0x28, 0x49, 0xB6, 0x4B, 0x42, 0x94, 0x83, 0x0A, 0xA8, - 0xB0, 0x11, 0x12, 0x65, 0x19, 0x91, 0x09, 0xB4, 0xB8, 0x16, 0x76, 0x4F, - 0xE6, 0xEA, 0x7B, 0x21, 0x7B, 0x86, 0xAE, 0xD3, 0xE2, 0xA7, 0xEA, 0x11, - 0x12, 0x9A, 0xDB, 0x18, 0x5B, 0xA9, 0x94, 0x94, 0x85, 0xF1, 0x3E, 0xEE, - 0xE8, 0x86, 0xB9, 0x60, 0x11, 0x03, 0xC5, 0x0C, 0x34, 0x1D, 0x47, 0x6E, - 0xC5, 0x11, 0xB6, 0xB8, 0x0D, 0x46, 0x83, 0x84, 0x4A, 0x02, 0x27, 0x8F, - 0x4C, 0x6B, 0xCA, 0xA9, 0x6D, 0x85, 0xDF, 0x04, 0x7B, 0x8E, 0xF3, 0xA6, - 0x84, 0x94, 0xDE, 0x80, 0x03, 0xDC, 0x7E, 0x49, 0xC1, 0x69, 0xD5, 0xA2, - 0x5E, 0x67, 0x5F, 0xBD, 0x16, 0xA0, 0x4E, 0xBF, 0x72, 0xB4, 0xCC, 0x6A, - 0xCB, 0x74, 0x4E, 0x68, 0xD9, 0x03, 0x90, 0x8F, 0x10, 0x5B, 0xC2, 0x5F, - 0xFF, 0xD3, 0xEA, 0xCD, 0xA7, 0xE8, 0x84, 0xDB, 0xFC, 0x79, 0x4F, 0xE9, - 0x38, 0xA7, 0xF4, 0x65, 0x5C, 0xD1, 0xA1, 0xAA, 0x33, 0xA9, 0x48, 0x13, - 0xD9, 0x17, 0xD1, 0x69, 0xD4, 0x9D, 0x14, 0x0E, 0x86, 0x3C, 0x38, 0x45, - 0x54, 0xB7, 0xA8, 0x41, 0xD3, 0x94, 0x41, 0x69, 0xEE, 0x50, 0x5C, 0xD2, - 0x99, 0xAC, 0x74, 0xF9, 0x25, 0xA2, 0xAC, 0xB6, 0x1B, 0x71, 0x07, 0x8F, - 0x9A, 0x28, 0xB1, 0xC6, 0x35, 0x55, 0x64, 0x8E, 0x79, 0x44, 0x63, 0x87, - 0x32, 0x81, 0x09, 0x05, 0x3B, 0x9C, 0xE3, 0xAC, 0xA6, 0x13, 0x3A, 0x73, - 0xE2, 0xA2, 0x1C, 0x0F, 0x74, 0x4A, 0xE0, 0x90, 0x0F, 0x74, 0x17, 0x32, - 0x60, 0x23, 0xCD, 0x4C, 0x26, 0x88, 0x30, 0x91, 0x29, 0xA9, 0x46, 0xE6, - 0x80, 0xE9, 0x8E, 0x39, 0x51, 0x71, 0xDD, 0xA7, 0x08, 0xA5, 0x30, 0x69, - 0x3C, 0x04, 0x6D, 0x0C, 0x01, 0xD9, 0xC7, 0x3E, 0x2A, 0x0F, 0x79, 0x8E, - 0x54, 0x9E, 0xD2, 0x0A, 0x0B, 0xDA, 0x4A, 0x21, 0x05, 0xFF, 0xD4, 0xEC, - 0xC3, 0x44, 0x6A, 0x96, 0xE0, 0x3C, 0xD5, 0x6F, 0xB4, 0x87, 0x1D, 0x24, - 0xA2, 0x56, 0x4B, 0xCC, 0x42, 0xB7, 0x4D, 0x3B, 0x1D, 0x12, 0x68, 0x75, - 0xF0, 0x50, 0x73, 0x9B, 0xD8, 0x29, 0xBD, 0x9B, 0x47, 0x28, 0x71, 0xDD, - 0x20, 0xA2, 0xC6, 0x0F, 0x60, 0x9F, 0x67, 0x92, 0x93, 0x66, 0x51, 0x01, - 0x8E, 0x44, 0xA5, 0x6A, 0xA4, 0x05, 0x93, 0xCA, 0x67, 0x6D, 0x6A, 0x23, - 0xCE, 0xBA, 0x28, 0x47, 0xF2, 0x44, 0xA2, 0x82, 0x15, 0x59, 0x9F, 0x29, - 0xF1, 0x56, 0x2B, 0x60, 0xE4, 0x99, 0xF2, 0x55, 0xB7, 0x86, 0xC4, 0x85, - 0x2F, 0xB4, 0xBF, 0x81, 0xF8, 0xA0, 0x6D, 0x40, 0x80, 0xDB, 0x0E, 0x05, - 0x22, 0x55, 0x56, 0xD9, 0xAC, 0xCA, 0x28, 0xB0, 0x21, 0x4B, 0xAD, 0x28, - 0x1B, 0xB8, 0x45, 0xAD, 0xA5, 0xBC, 0xF7, 0x55, 0x3E, 0xD0, 0x1A, 0xA4, - 0xCC, 0xC6, 0x9D, 0x0F, 0x28, 0x10, 0x54, 0x08, 0x4D, 0x68, 0x07, 0x8D, - 0x4A, 0x09, 0x69, 0xF0, 0x4E, 0xEB, 0xC7, 0x68, 0x3E, 0x68, 0x67, 0x29, - 0xAD, 0x69, 0x9F, 0x92, 0x20, 0x15, 0x12, 0x1F, 0xFF, 0xD5, 0xEB, 0x46, - 0x33, 0x87, 0x01, 0x3F, 0xA7, 0x6B, 0x75, 0x06, 0x07, 0xE2, 0xAD, 0x8D, - 0xC3, 0x8E, 0xE9, 0xB6, 0x13, 0xCA, 0xB5, 0xC4, 0xD4, 0xE1, 0x0D, 0x33, - 0xEA, 0x18, 0x92, 0xA5, 0xC0, 0x8E, 0xEA, 0xDF, 0xA2, 0xD3, 0xD9, 0x2F, - 0x48, 0x01, 0xC2, 0x5C, 0x4A, 0xE1, 0x2D, 0x51, 0x1F, 0x34, 0xE6, 0xC0, - 0x02, 0x31, 0xAC, 0x14, 0x3B, 0x18, 0x47, 0x01, 0x2B, 0x0A, 0xA2, 0x87, - 0x79, 0x9D, 0x54, 0x1D, 0x6F, 0x75, 0x37, 0x53, 0x61, 0xD6, 0x14, 0x0D, - 0x64, 0x09, 0x21, 0x3B, 0x45, 0xA6, 0xD1, 0xBD, 0xFB, 0xB5, 0x01, 0x38, - 0x32, 0x3F, 0x82, 0x44, 0x38, 0xE8, 0x02, 0x23, 0x2B, 0x9F, 0x2F, 0x8A, - 0x56, 0x8A, 0x60, 0x1D, 0x1A, 0xA4, 0x6D, 0x8F, 0x8A, 0x28, 0xA9, 0xDD, - 0xB5, 0x1F, 0x82, 0x4E, 0xA8, 0x1D, 0x74, 0x94, 0xAC, 0x2A, 0x8A, 0x22, - 0xF9, 0x52, 0x68, 0xF2, 0x92, 0xA4, 0x6B, 0x20, 0x79, 0xF9, 0x26, 0x1B, - 0x87, 0x23, 0x44, 0xAD, 0x34, 0xC1, 0xAC, 0x71, 0x76, 0xB2, 0x8A, 0x71, - 0x89, 0xD7, 0x52, 0x54, 0x98, 0x78, 0x85, 0x65, 0x80, 0xC2, 0x06, 0x49, - 0x11, 0x0F, 0xFF, 0xD6, 0xEF, 0x9A, 0xDF, 0x15, 0x20, 0xDF, 0x24, 0xFC, - 0x15, 0x36, 0x89, 0x53, 0x5B, 0x05, 0x30, 0xDA, 0xA2, 0x5A, 0x8E, 0x5A, - 0xA0, 0x5A, 0x95, 0xA6, 0x90, 0x96, 0xC2, 0x81, 0x00, 0xA2, 0xB8, 0x28, - 0x22, 0xB5, 0x19, 0x60, 0x88, 0x84, 0x27, 0xD6, 0x22, 0x00, 0xE1, 0x58, - 0x25, 0x0C, 0xA2, 0x10, 0x40, 0x43, 0xB1, 0xA7, 0xE9, 0x69, 0x0A, 0x62, - 0xB1, 0x13, 0x32, 0x12, 0x21, 0x38, 0x24, 0x70, 0x8D, 0xA2, 0x91, 0x19, - 0x07, 0x44, 0xA1, 0xDF, 0xEC, 0x44, 0x30, 0x90, 0x84, 0xAD, 0x54, 0xC1, - 0xAD, 0x77, 0x8A, 0x23, 0x6B, 0x61, 0x3E, 0xED, 0x54, 0x80, 0x08, 0x83, - 0x6F, 0x64, 0x09, 0x48, 0x0C, 0x05, 0x4D, 0xEC, 0x11, 0x03, 0x23, 0x84, - 0xED, 0x08, 0x80, 0x21, 0x69, 0x01, 0xFF, 0xD9, 0x00, 0x38, 0x42, 0x49, - 0x4D, 0x04, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, - 0x01, 0x01, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x41, 0x00, 0x64, 0x00, 0x6F, - 0x00, 0x62, 0x00, 0x65, 0x00, 0x20, 0x00, 0x50, 0x00, 0x68, 0x00, 0x6F, - 0x00, 0x74, 0x00, 0x6F, 0x00, 0x73, 0x00, 0x68, 0x00, 0x6F, 0x00, 0x70, - 0x00, 0x00, 0x00, 0x13, 0x00, 0x41, 0x00, 0x64, 0x00, 0x6F, 0x00, 0x62, - 0x00, 0x65, 0x00, 0x20, 0x00, 0x50, 0x00, 0x68, 0x00, 0x6F, 0x00, 0x74, - 0x00, 0x6F, 0x00, 0x73, 0x00, 0x68, 0x00, 0x6F, 0x00, 0x70, 0x00, 0x20, - 0x00, 0x37, 0x00, 0x2E, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x38, - 0x42, 0x49, 0x4D, 0x04, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0xFF, 0xE1, 0x12, 0x48, 0x68, - 0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F, 0x6E, 0x73, 0x2E, 0x61, 0x64, 0x6F, - 0x62, 0x65, 0x2E, 0x63, 0x6F, 0x6D, 0x2F, 0x78, 0x61, 0x70, 0x2F, 0x31, - 0x2E, 0x30, 0x2F, 0x00, 0x3C, 0x3F, 0x78, 0x70, 0x61, 0x63, 0x6B, 0x65, - 0x74, 0x20, 0x62, 0x65, 0x67, 0x69, 0x6E, 0x3D, 0x27, 0xEF, 0xBB, 0xBF, - 0x27, 0x20, 0x69, 0x64, 0x3D, 0x27, 0x57, 0x35, 0x4D, 0x30, 0x4D, 0x70, - 0x43, 0x65, 0x68, 0x69, 0x48, 0x7A, 0x72, 0x65, 0x53, 0x7A, 0x4E, 0x54, - 0x63, 0x7A, 0x6B, 0x63, 0x39, 0x64, 0x27, 0x3F, 0x3E, 0x0A, 0x3C, 0x3F, - 0x61, 0x64, 0x6F, 0x62, 0x65, 0x2D, 0x78, 0x61, 0x70, 0x2D, 0x66, 0x69, - 0x6C, 0x74, 0x65, 0x72, 0x73, 0x20, 0x65, 0x73, 0x63, 0x3D, 0x22, 0x43, - 0x52, 0x22, 0x3F, 0x3E, 0x0A, 0x3C, 0x78, 0x3A, 0x78, 0x61, 0x70, 0x6D, - 0x65, 0x74, 0x61, 0x20, 0x78, 0x6D, 0x6C, 0x6E, 0x73, 0x3A, 0x78, 0x3D, - 0x27, 0x61, 0x64, 0x6F, 0x62, 0x65, 0x3A, 0x6E, 0x73, 0x3A, 0x6D, 0x65, - 0x74, 0x61, 0x2F, 0x27, 0x20, 0x78, 0x3A, 0x78, 0x61, 0x70, 0x74, 0x6B, - 0x3D, 0x27, 0x58, 0x4D, 0x50, 0x20, 0x74, 0x6F, 0x6F, 0x6C, 0x6B, 0x69, - 0x74, 0x20, 0x32, 0x2E, 0x38, 0x2E, 0x32, 0x2D, 0x33, 0x33, 0x2C, 0x20, - 0x66, 0x72, 0x61, 0x6D, 0x65, 0x77, 0x6F, 0x72, 0x6B, 0x20, 0x31, 0x2E, - 0x35, 0x27, 0x3E, 0x0A, 0x3C, 0x72, 0x64, 0x66, 0x3A, 0x52, 0x44, 0x46, - 0x20, 0x78, 0x6D, 0x6C, 0x6E, 0x73, 0x3A, 0x72, 0x64, 0x66, 0x3D, 0x27, - 0x68, 0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F, 0x77, 0x77, 0x77, 0x2E, 0x77, - 0x33, 0x2E, 0x6F, 0x72, 0x67, 0x2F, 0x31, 0x39, 0x39, 0x39, 0x2F, 0x30, - 0x32, 0x2F, 0x32, 0x32, 0x2D, 0x72, 0x64, 0x66, 0x2D, 0x73, 0x79, 0x6E, - 0x74, 0x61, 0x78, 0x2D, 0x6E, 0x73, 0x23, 0x27, 0x20, 0x78, 0x6D, 0x6C, - 0x6E, 0x73, 0x3A, 0x69, 0x58, 0x3D, 0x27, 0x68, 0x74, 0x74, 0x70, 0x3A, - 0x2F, 0x2F, 0x6E, 0x73, 0x2E, 0x61, 0x64, 0x6F, 0x62, 0x65, 0x2E, 0x63, - 0x6F, 0x6D, 0x2F, 0x69, 0x58, 0x2F, 0x31, 0x2E, 0x30, 0x2F, 0x27, 0x3E, - 0x0A, 0x0A, 0x20, 0x3C, 0x72, 0x64, 0x66, 0x3A, 0x44, 0x65, 0x73, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x61, 0x62, 0x6F, 0x75, - 0x74, 0x3D, 0x27, 0x75, 0x75, 0x69, 0x64, 0x3A, 0x65, 0x35, 0x35, 0x35, - 0x61, 0x39, 0x65, 0x35, 0x2D, 0x61, 0x61, 0x38, 0x65, 0x2D, 0x31, 0x31, - 0x65, 0x31, 0x2D, 0x62, 0x30, 0x62, 0x33, 0x2D, 0x65, 0x62, 0x31, 0x39, - 0x32, 0x32, 0x62, 0x38, 0x35, 0x34, 0x30, 0x35, 0x27, 0x0A, 0x20, 0x20, - 0x78, 0x6D, 0x6C, 0x6E, 0x73, 0x3A, 0x78, 0x61, 0x70, 0x4D, 0x4D, 0x3D, - 0x27, 0x68, 0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F, 0x6E, 0x73, 0x2E, 0x61, - 0x64, 0x6F, 0x62, 0x65, 0x2E, 0x63, 0x6F, 0x6D, 0x2F, 0x78, 0x61, 0x70, - 0x2F, 0x31, 0x2E, 0x30, 0x2F, 0x6D, 0x6D, 0x2F, 0x27, 0x3E, 0x0A, 0x20, - 0x20, 0x3C, 0x78, 0x61, 0x70, 0x4D, 0x4D, 0x3A, 0x44, 0x6F, 0x63, 0x75, - 0x6D, 0x65, 0x6E, 0x74, 0x49, 0x44, 0x3E, 0x61, 0x64, 0x6F, 0x62, 0x65, - 0x3A, 0x64, 0x6F, 0x63, 0x69, 0x64, 0x3A, 0x70, 0x68, 0x6F, 0x74, 0x6F, - 0x73, 0x68, 0x6F, 0x70, 0x3A, 0x65, 0x35, 0x35, 0x35, 0x61, 0x39, 0x65, - 0x31, 0x2D, 0x61, 0x61, 0x38, 0x65, 0x2D, 0x31, 0x31, 0x65, 0x31, 0x2D, - 0x62, 0x30, 0x62, 0x33, 0x2D, 0x65, 0x62, 0x31, 0x39, 0x32, 0x32, 0x62, - 0x38, 0x35, 0x34, 0x30, 0x35, 0x3C, 0x2F, 0x78, 0x61, 0x70, 0x4D, 0x4D, - 0x3A, 0x44, 0x6F, 0x63, 0x75, 0x6D, 0x65, 0x6E, 0x74, 0x49, 0x44, 0x3E, - 0x0A, 0x20, 0x3C, 0x2F, 0x72, 0x64, 0x66, 0x3A, 0x44, 0x65, 0x73, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x3E, 0x0A, 0x0A, 0x3C, 0x2F, - 0x72, 0x64, 0x66, 0x3A, 0x52, 0x44, 0x46, 0x3E, 0x0A, 0x3C, 0x2F, 0x78, - 0x3A, 0x78, 0x61, 0x70, 0x6D, 0x65, 0x74, 0x61, 0x3E, 0x0A, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0A, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0A, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0A, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0A, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0A, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0A, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0A, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0A, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0A, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0A, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0A, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0A, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0A, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0A, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0A, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0A, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x0A, 0x3C, 0x3F, 0x78, 0x70, 0x61, 0x63, 0x6B, 0x65, 0x74, 0x20, - 0x65, 0x6E, 0x64, 0x3D, 0x27, 0x77, 0x27, 0x3F, 0x3E, 0xFF, 0xEE, 0x00, - 0x0E, 0x41, 0x64, 0x6F, 0x62, 0x65, 0x00, 0x64, 0x80, 0x00, 0x00, 0x00, - 0x01, 0xFF, 0xDB, 0x00, 0x84, 0x00, 0x0C, 0x08, 0x08, 0x08, 0x09, 0x08, - 0x0C, 0x09, 0x09, 0x0C, 0x11, 0x0B, 0x0A, 0x0B, 0x11, 0x15, 0x0F, 0x0C, - 0x0C, 0x0F, 0x15, 0x18, 0x13, 0x13, 0x15, 0x13, 0x13, 0x18, 0x11, 0x0C, - 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x11, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, - 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, - 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x01, 0x0D, - 0x0B, 0x0B, 0x0D, 0x0E, 0x0D, 0x10, 0x0E, 0x0E, 0x10, 0x14, 0x0E, 0x0E, - 0x0E, 0x14, 0x14, 0x0E, 0x0E, 0x0E, 0x0E, 0x14, 0x11, 0x0C, 0x0C, 0x0C, - 0x0C, 0x0C, 0x11, 0x11, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x11, 0x0C, - 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, - 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, - 0x0C, 0x0C, 0x0C, 0xFF, 0xC0, 0x00, 0x11, 0x08, 0x01, 0xF4, 0x01, 0xF4, - 0x03, 0x01, 0x22, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xFF, 0xDD, - 0x00, 0x04, 0x00, 0x20, 0xFF, 0xC4, 0x01, 0x3F, 0x00, 0x00, 0x01, 0x05, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x03, 0x00, 0x01, 0x02, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, - 0x0B, 0x01, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x03, 0x04, 0x05, - 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x10, 0x00, 0x01, 0x04, 0x01, 0x03, - 0x02, 0x04, 0x02, 0x05, 0x07, 0x06, 0x08, 0x05, 0x03, 0x0C, 0x33, 0x01, - 0x00, 0x02, 0x11, 0x03, 0x04, 0x21, 0x12, 0x31, 0x05, 0x41, 0x51, 0x61, - 0x13, 0x22, 0x71, 0x81, 0x32, 0x06, 0x14, 0x91, 0xA1, 0xB1, 0x42, 0x23, - 0x24, 0x15, 0x52, 0xC1, 0x62, 0x33, 0x34, 0x72, 0x82, 0xD1, 0x43, 0x07, - 0x25, 0x92, 0x53, 0xF0, 0xE1, 0xF1, 0x63, 0x73, 0x35, 0x16, 0xA2, 0xB2, - 0x83, 0x26, 0x44, 0x93, 0x54, 0x64, 0x45, 0xC2, 0xA3, 0x74, 0x36, 0x17, - 0xD2, 0x55, 0xE2, 0x65, 0xF2, 0xB3, 0x84, 0xC3, 0xD3, 0x75, 0xE3, 0xF3, - 0x46, 0x27, 0x94, 0xA4, 0x85, 0xB4, 0x95, 0xC4, 0xD4, 0xE4, 0xF4, 0xA5, - 0xB5, 0xC5, 0xD5, 0xE5, 0xF5, 0x56, 0x66, 0x76, 0x86, 0x96, 0xA6, 0xB6, - 0xC6, 0xD6, 0xE6, 0xF6, 0x37, 0x47, 0x57, 0x67, 0x77, 0x87, 0x97, 0xA7, - 0xB7, 0xC7, 0xD7, 0xE7, 0xF7, 0x11, 0x00, 0x02, 0x02, 0x01, 0x02, 0x04, - 0x04, 0x03, 0x04, 0x05, 0x06, 0x07, 0x07, 0x06, 0x05, 0x35, 0x01, 0x00, - 0x02, 0x11, 0x03, 0x21, 0x31, 0x12, 0x04, 0x41, 0x51, 0x61, 0x71, 0x22, - 0x13, 0x05, 0x32, 0x81, 0x91, 0x14, 0xA1, 0xB1, 0x42, 0x23, 0xC1, 0x52, - 0xD1, 0xF0, 0x33, 0x24, 0x62, 0xE1, 0x72, 0x82, 0x92, 0x43, 0x53, 0x15, - 0x63, 0x73, 0x34, 0xF1, 0x25, 0x06, 0x16, 0xA2, 0xB2, 0x83, 0x07, 0x26, - 0x35, 0xC2, 0xD2, 0x44, 0x93, 0x54, 0xA3, 0x17, 0x64, 0x45, 0x55, 0x36, - 0x74, 0x65, 0xE2, 0xF2, 0xB3, 0x84, 0xC3, 0xD3, 0x75, 0xE3, 0xF3, 0x46, - 0x94, 0xA4, 0x85, 0xB4, 0x95, 0xC4, 0xD4, 0xE4, 0xF4, 0xA5, 0xB5, 0xC5, - 0xD5, 0xE5, 0xF5, 0x56, 0x66, 0x76, 0x86, 0x96, 0xA6, 0xB6, 0xC6, 0xD6, - 0xE6, 0xF6, 0x27, 0x37, 0x47, 0x57, 0x67, 0x77, 0x87, 0x97, 0xA7, 0xB7, - 0xC7, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, - 0x00, 0x3F, 0x00, 0xF4, 0x24, 0xC9, 0xD3, 0x15, 0x33, 0x02, 0xC5, 0x20, - 0x98, 0xA7, 0x09, 0x29, 0x90, 0x53, 0x0A, 0x01, 0x4C, 0x24, 0x96, 0x61, - 0x24, 0xC9, 0xD0, 0x4A, 0x92, 0x49, 0x24, 0x94, 0xA4, 0xD0, 0x9D, 0x24, - 0x94, 0xB2, 0x89, 0x52, 0x2A, 0x25, 0x24, 0x2C, 0x53, 0x27, 0x29, 0x8A, - 0x2A, 0x59, 0x44, 0xA9, 0x14, 0xC5, 0x24, 0x31, 0x2A, 0x25, 0x49, 0x32, - 0x28, 0x62, 0x92, 0x74, 0xC9, 0x29, 0x64, 0x92, 0x4C, 0x52, 0x52, 0xC5, - 0x32, 0x72, 0x98, 0xA2, 0x85, 0x93, 0x14, 0x89, 0x4C, 0x4A, 0x4A, 0x5D, - 0x34, 0xA6, 0x49, 0x24, 0x2F, 0x29, 0x4A, 0x69, 0x49, 0x15, 0x29, 0x24, - 0x92, 0x49, 0x4B, 0x24, 0x92, 0x49, 0x29, 0x49, 0x24, 0x92, 0x4A, 0x52, - 0x49, 0x24, 0x92, 0x94, 0x99, 0x24, 0x92, 0x52, 0x92, 0x49, 0x3A, 0x4A, - 0x5D, 0x38, 0x4C, 0x13, 0xA4, 0xA5, 0x27, 0x4C, 0x9C, 0x20, 0x95, 0xD3, - 0xA6, 0x09, 0xD2, 0x52, 0xE9, 0x24, 0x14, 0xA1, 0x25, 0x28, 0x05, 0x28, - 0x48, 0x05, 0x20, 0xD4, 0x12, 0xB4, 0x25, 0x0A, 0x61, 0xA5, 0x3E, 0xD4, - 0x13, 0x4C, 0x00, 0x52, 0x4A, 0x13, 0x80, 0x92, 0x94, 0x02, 0x78, 0x49, - 0x24, 0x92, 0xA4, 0x92, 0x49, 0x25, 0x2C, 0x92, 0x7E, 0xE9, 0x24, 0xA7, - 0xFF, 0xD0, 0xF4, 0x24, 0x88, 0x4A, 0x12, 0x85, 0x33, 0x0B, 0x18, 0x4E, - 0x02, 0x78, 0x4E, 0x92, 0x95, 0x0A, 0x4D, 0x09, 0x94, 0xDA, 0x82, 0x97, - 0x84, 0xA1, 0x48, 0x27, 0x84, 0x92, 0xC1, 0x25, 0x22, 0x13, 0x24, 0xA5, - 0x93, 0x29, 0x42, 0x45, 0x25, 0x31, 0x4C, 0xA4, 0x99, 0x24, 0x31, 0x84, - 0xC4, 0x29, 0x24, 0x42, 0x4A, 0x60, 0x42, 0x89, 0x0A, 0x70, 0x98, 0x84, - 0x50, 0xC0, 0x85, 0x12, 0x11, 0x08, 0x51, 0x29, 0x29, 0x81, 0x4C, 0xA4, - 0x53, 0x22, 0x86, 0x29, 0x8A, 0x91, 0x51, 0x29, 0x29, 0x89, 0x51, 0x25, - 0x39, 0x51, 0x25, 0x14, 0x28, 0x94, 0xD2, 0x98, 0x94, 0xD2, 0x8A, 0x17, - 0x94, 0xA5, 0x46, 0x53, 0xA4, 0x85, 0xD2, 0x4D, 0x29, 0x24, 0xA5, 0xD2, - 0x4C, 0x94, 0xA4, 0x95, 0xD2, 0x4D, 0x29, 0x4A, 0x4A, 0x5D, 0x32, 0x49, - 0x12, 0x92, 0x95, 0x29, 0x26, 0x4A, 0x52, 0x52, 0xE9, 0x24, 0x9D, 0x25, - 0x29, 0x28, 0x4E, 0x13, 0xA0, 0xA5, 0x04, 0x92, 0x52, 0x09, 0x25, 0x68, - 0x4E, 0x94, 0x27, 0xDA, 0x92, 0x94, 0x13, 0xA5, 0xB4, 0xA7, 0x0D, 0x29, - 0x29, 0x41, 0x48, 0x24, 0x1A, 0x9F, 0x6A, 0x09, 0x5C, 0x15, 0x36, 0xA8, - 0x06, 0x95, 0x2D, 0x40, 0x41, 0x21, 0x20, 0x21, 0x3E, 0x8A, 0x0D, 0x53, - 0x49, 0x2B, 0x10, 0xA2, 0xA4, 0x98, 0xA4, 0xA5, 0x4A, 0x64, 0x92, 0x49, - 0x0A, 0x49, 0x24, 0x92, 0x52, 0x92, 0x49, 0x24, 0x94, 0xFF, 0x00, 0xFF, - 0xD1, 0xF4, 0x24, 0xEA, 0x29, 0xC2, 0x99, 0x81, 0x92, 0x50, 0x94, 0x84, - 0x92, 0x4A, 0xE0, 0x22, 0x00, 0x86, 0x11, 0x1A, 0x50, 0x2A, 0x0C, 0x80, - 0x4F, 0x09, 0xC2, 0x94, 0x04, 0x12, 0xC2, 0x12, 0x85, 0x32, 0xD4, 0xD0, - 0x95, 0xA5, 0x86, 0xD4, 0x88, 0x52, 0x84, 0x92, 0x42, 0x32, 0x21, 0x45, - 0x11, 0xCA, 0x05, 0x15, 0x2C, 0x9F, 0x94, 0x80, 0x4F, 0x10, 0x92, 0x98, - 0x90, 0xA2, 0x42, 0x99, 0xE5, 0x31, 0x09, 0x21, 0x19, 0x0A, 0x24, 0x22, - 0x15, 0x12, 0x25, 0x15, 0x23, 0x51, 0x44, 0x2D, 0x51, 0x20, 0x84, 0x51, - 0x4C, 0x0A, 0x89, 0x52, 0x2A, 0x05, 0x24, 0x31, 0x28, 0x6E, 0x2A, 0x6E, - 0x42, 0x71, 0x44, 0x2D, 0x2A, 0x94, 0xC4, 0xA6, 0x95, 0x12, 0x8A, 0x19, - 0x4A, 0x79, 0x43, 0x94, 0xB7, 0x22, 0xA4, 0x92, 0x90, 0x2A, 0x1B, 0x93, - 0x82, 0x92, 0x99, 0xA4, 0x9A, 0x52, 0x94, 0x14, 0xBA, 0x69, 0x4C, 0x4A, - 0x69, 0x49, 0x4C, 0xE5, 0x28, 0x25, 0x44, 0x4A, 0x23, 0x02, 0x49, 0x63, - 0x05, 0x38, 0x0A, 0x65, 0xA1, 0x20, 0x12, 0xB5, 0x53, 0x18, 0x29, 0xC0, - 0x28, 0x81, 0xA9, 0xC8, 0x08, 0x5A, 0x69, 0x84, 0x42, 0x8A, 0x21, 0x1A, - 0x28, 0x10, 0x92, 0x94, 0x14, 0x82, 0x82, 0x90, 0x49, 0x4C, 0x82, 0x70, - 0x52, 0x09, 0xD2, 0x53, 0x30, 0x9E, 0x14, 0x01, 0x85, 0x2D, 0xC8, 0x25, - 0x74, 0xE1, 0x44, 0x15, 0x24, 0x92, 0xBC, 0xA4, 0x13, 0x27, 0x08, 0x29, - 0x96, 0x81, 0x2D, 0xC5, 0x32, 0x64, 0x94, 0xCB, 0x72, 0x45, 0xC1, 0x45, - 0x24, 0x95, 0x6C, 0xA5, 0x31, 0x29, 0xA5, 0x32, 0x4A, 0x5E, 0x53, 0xCA, - 0x64, 0x92, 0x52, 0xF2, 0x92, 0x49, 0x24, 0xA7, 0xFF, 0xD2, 0xF4, 0x10, - 0x9F, 0x44, 0xC9, 0xD4, 0xCC, 0x0B, 0xA7, 0x05, 0x45, 0x3A, 0x4A, 0x66, - 0x35, 0x44, 0x6B, 0x50, 0x9A, 0x8A, 0xD2, 0x50, 0x29, 0x09, 0x00, 0x52, - 0x50, 0x05, 0x48, 0x14, 0x0A, 0x57, 0x48, 0x94, 0xD2, 0x92, 0x09, 0x51, - 0x51, 0x2A, 0x69, 0x8A, 0x4A, 0x46, 0xE5, 0x15, 0x22, 0xA2, 0x9C, 0x85, - 0x04, 0xE5, 0x32, 0x49, 0x29, 0x68, 0x4C, 0x53, 0xA8, 0x94, 0x94, 0xC4, - 0xA4, 0x92, 0x74, 0x50, 0xC6, 0x54, 0x5C, 0x25, 0x48, 0x84, 0xC4, 0xA4, - 0xA4, 0x2E, 0x69, 0x43, 0x76, 0x88, 0xEE, 0xE1, 0x09, 0xC1, 0x10, 0xB4, - 0xA1, 0x79, 0x41, 0x71, 0x56, 0x0B, 0x25, 0x09, 0xD5, 0xA7, 0x05, 0xA5, - 0x0C, 0x95, 0x30, 0xA5, 0xE9, 0x78, 0x27, 0xD8, 0x95, 0xA2, 0x91, 0x38, - 0x1E, 0xC8, 0x7A, 0xCA, 0x3B, 0x99, 0xE0, 0xA1, 0xB0, 0xA2, 0x82, 0x18, - 0x82, 0xA4, 0x13, 0xB6, 0xB5, 0x31, 0x5A, 0x49, 0xA6, 0x20, 0x15, 0x2D, - 0xA5, 0x48, 0x30, 0x85, 0x30, 0xD0, 0x82, 0x69, 0x16, 0xC4, 0xE1, 0xA8, - 0xBB, 0x53, 0x6D, 0x4A, 0xD5, 0x4C, 0x43, 0x41, 0x52, 0x0D, 0x85, 0x26, - 0x85, 0x20, 0x02, 0x16, 0x96, 0x30, 0x9C, 0x00, 0xA4, 0x40, 0x4C, 0x52, - 0x52, 0xE2, 0x13, 0x14, 0xA5, 0x31, 0x28, 0x29, 0x44, 0xA8, 0x92, 0x98, - 0xB9, 0x34, 0x94, 0x54, 0xB8, 0x52, 0xF8, 0x28, 0xEA, 0x53, 0x8D, 0x12, - 0x53, 0x24, 0xF2, 0x98, 0x14, 0x81, 0x49, 0x4B, 0x82, 0xA4, 0xA2, 0x9C, - 0x20, 0x96, 0x40, 0xA9, 0x4A, 0x8A, 0x49, 0x29, 0x98, 0x52, 0x10, 0xA0, - 0x14, 0x81, 0x41, 0x2C, 0xE0, 0x28, 0x94, 0xFA, 0x26, 0x49, 0x4B, 0x24, - 0x9D, 0x24, 0x94, 0xB2, 0x65, 0x28, 0x4C, 0x8A, 0x14, 0x92, 0x78, 0x4D, - 0x09, 0x29, 0x49, 0x25, 0xA2, 0x49, 0x29, 0xFF, 0xD3, 0xF4, 0x09, 0x48, - 0x14, 0xC9, 0xC0, 0x53, 0xB5, 0xD7, 0x95, 0x21, 0xAA, 0x88, 0x53, 0x01, - 0x04, 0xB2, 0x01, 0x4C, 0x4A, 0x88, 0x85, 0x36, 0xA0, 0x96, 0x40, 0x14, - 0x82, 0x79, 0x4E, 0x82, 0x54, 0x13, 0xA6, 0x09, 0xD0, 0x4A, 0x93, 0x14, - 0xE9, 0x92, 0x53, 0x17, 0x28, 0xA9, 0x9D, 0x53, 0x42, 0x28, 0x63, 0x09, - 0x29, 0x42, 0x62, 0x8A, 0x98, 0x15, 0x12, 0xA4, 0x54, 0x0A, 0x48, 0x50, - 0x48, 0xA6, 0x9D, 0x14, 0x0B, 0x91, 0x53, 0x22, 0x54, 0x09, 0x48, 0x94, - 0xD2, 0x92, 0x16, 0x82, 0x98, 0xB4, 0x29, 0x4A, 0x8B, 0x9C, 0x11, 0x53, - 0x12, 0x04, 0x21, 0x18, 0x95, 0x37, 0xB8, 0x42, 0x14, 0xF7, 0x44, 0x2D, - 0x2C, 0xE0, 0x28, 0x9D, 0x52, 0x12, 0x54, 0xDA, 0xD4, 0x94, 0xC0, 0x34, - 0xA7, 0x35, 0xA2, 0x86, 0x29, 0x86, 0x4A, 0x16, 0x9A, 0x6B, 0x0A, 0xE1, - 0x4D, 0xAD, 0x47, 0x35, 0xC2, 0x6D, 0xA9, 0x5A, 0xA9, 0x1F, 0xA6, 0x0A, - 0x6D, 0x84, 0x22, 0xBB, 0x45, 0x02, 0xE0, 0x92, 0x98, 0xC2, 0x7D, 0xA9, - 0xE5, 0x38, 0x84, 0x94, 0xC2, 0x0A, 0x92, 0x4E, 0x50, 0x2E, 0x80, 0x92, - 0x19, 0x39, 0xC0, 0x04, 0x32, 0xE5, 0x17, 0x3D, 0x36, 0xE4, 0x69, 0x56, - 0xCE, 0x53, 0x12, 0xA3, 0xB9, 0x44, 0x90, 0x8A, 0x2D, 0x72, 0x52, 0x92, - 0x9A, 0x25, 0x38, 0x09, 0x29, 0x70, 0xE2, 0x13, 0x87, 0x25, 0xB4, 0x26, - 0x49, 0x4C, 0xC1, 0x52, 0x0A, 0x0D, 0x53, 0x08, 0x25, 0x9B, 0x42, 0x9E, - 0xD5, 0x06, 0x14, 0x50, 0xE0, 0x82, 0x43, 0x12, 0xC4, 0xB6, 0xA2, 0x03, - 0x29, 0x42, 0x09, 0xA6, 0x00, 0x27, 0x88, 0x52, 0xD1, 0x32, 0x4A, 0x5C, - 0x29, 0x6D, 0x51, 0x05, 0x4C, 0x1D, 0x12, 0x53, 0x12, 0x13, 0x15, 0x22, - 0x52, 0x84, 0x94, 0xC1, 0x3E, 0xD4, 0xF0, 0xA4, 0x21, 0x25, 0x31, 0x84, - 0xC4, 0x22, 0x40, 0x50, 0x29, 0x29, 0x8F, 0x74, 0x92, 0xEE, 0x92, 0x28, - 0x7F, 0xFF, 0xD4, 0xF4, 0x18, 0x94, 0xFB, 0x54, 0x83, 0x52, 0x2A, 0x66, - 0x0A, 0x58, 0x05, 0x24, 0xC1, 0x48, 0x24, 0xA5, 0xC2, 0x94, 0xA8, 0xA9, - 0x35, 0x04, 0xAE, 0x25, 0x48, 0x25, 0x01, 0x24, 0x92, 0xCA, 0x53, 0x85, - 0x1D, 0x14, 0x82, 0x05, 0x4B, 0xA8, 0x95, 0x24, 0xD0, 0x82, 0x58, 0xA6, - 0x52, 0x21, 0x32, 0x28, 0x59, 0x45, 0xC5, 0x39, 0x2A, 0x04, 0xA2, 0xA6, - 0x2E, 0x2A, 0x04, 0xA9, 0x15, 0x02, 0x8A, 0x16, 0x95, 0x12, 0x53, 0x98, - 0x51, 0x25, 0x24, 0x30, 0x25, 0x2D, 0xC9, 0x9C, 0x54, 0x51, 0x43, 0x30, - 0xF2, 0xA2, 0xE7, 0xA6, 0xEC, 0x98, 0xA2, 0x86, 0x26, 0x4A, 0x40, 0x15, - 0x20, 0x97, 0x09, 0x29, 0x70, 0x11, 0x58, 0xD5, 0x06, 0x19, 0x46, 0x10, - 0x81, 0x48, 0x5C, 0x31, 0x48, 0x02, 0x12, 0x0E, 0x4E, 0x5C, 0x10, 0x5C, - 0xB1, 0x1E, 0x29, 0x88, 0x09, 0x17, 0x28, 0x12, 0x52, 0x43, 0x17, 0x84, - 0x2E, 0xE8, 0x84, 0xA8, 0x10, 0x88, 0x41, 0x5B, 0x72, 0x7D, 0xC5, 0x46, - 0x14, 0xA0, 0x22, 0x86, 0x25, 0xCA, 0x2E, 0x70, 0x53, 0x20, 0x21, 0x3C, - 0x88, 0x49, 0x05, 0x13, 0xDC, 0x86, 0x5E, 0xE5, 0x23, 0x2A, 0x24, 0x27, - 0x2D, 0x56, 0xF4, 0xFB, 0xE4, 0xA8, 0x10, 0x53, 0xB4, 0x19, 0x49, 0x49, - 0xDA, 0x4C, 0x29, 0x02, 0xA0, 0xD4, 0x46, 0xE8, 0x82, 0xE0, 0xAD, 0xC7, - 0x84, 0xE0, 0x27, 0x89, 0xE1, 0x38, 0x49, 0x4A, 0x01, 0x38, 0x49, 0x21, - 0x28, 0x25, 0x90, 0x4E, 0x0A, 0x68, 0x29, 0xC0, 0x49, 0x49, 0x1A, 0x4A, - 0x91, 0x25, 0x45, 0xAA, 0x52, 0x82, 0x56, 0xDC, 0x9E, 0x54, 0x53, 0x80, - 0x92, 0x97, 0x95, 0x20, 0x54, 0x42, 0x98, 0x84, 0x12, 0xB8, 0x52, 0x01, - 0x33, 0x54, 0xF4, 0x84, 0x92, 0xC2, 0x0A, 0x68, 0x2A, 0x64, 0xA6, 0x84, - 0x94, 0xC4, 0xCA, 0x89, 0x95, 0x32, 0x13, 0x6D, 0x49, 0x0C, 0x35, 0x49, - 0x4B, 0x6A, 0x49, 0x2A, 0x9F, 0xFF, 0xD5, 0xF4, 0x60, 0x12, 0xDA, 0x12, - 0xDC, 0x9B, 0x72, 0x99, 0x85, 0x47, 0x44, 0xA5, 0x31, 0x29, 0x82, 0x48, - 0x66, 0x35, 0x44, 0x6A, 0x1B, 0x54, 0xC2, 0x09, 0x67, 0x29, 0x4A, 0x8A, - 0x52, 0x92, 0x59, 0x05, 0x20, 0x54, 0x42, 0x52, 0x82, 0x99, 0xCA, 0x69, - 0x51, 0x25, 0x29, 0x4A, 0x94, 0xC9, 0x45, 0xC9, 0xE5, 0x33, 0x92, 0x53, - 0x02, 0x54, 0x0A, 0x91, 0x4C, 0x8A, 0x18, 0x94, 0x37, 0x29, 0x95, 0x12, - 0x35, 0x45, 0x08, 0xDD, 0xC2, 0x19, 0x25, 0x19, 0xCD, 0x42, 0x70, 0x45, - 0x05, 0x84, 0xA5, 0xC2, 0x63, 0x29, 0x6B, 0x08, 0xA1, 0x44, 0x84, 0xDC, - 0xEA, 0x9A, 0x13, 0xA4, 0xA5, 0xB5, 0x09, 0xF5, 0x29, 0x19, 0x52, 0x63, - 0x67, 0x54, 0x94, 0xCA, 0xB6, 0x9E, 0x51, 0x44, 0x26, 0x1A, 0x04, 0xDB, - 0xA5, 0x04, 0xA4, 0x1C, 0x68, 0x9E, 0x09, 0x0A, 0x2D, 0x30, 0x96, 0xE2, - 0x82, 0x54, 0x41, 0x50, 0x32, 0xA5, 0xBB, 0x54, 0xFB, 0x41, 0x49, 0x48, - 0x88, 0x3D, 0x93, 0x06, 0xF8, 0xA2, 0x3B, 0x40, 0xA0, 0x4A, 0x28, 0x5F, - 0x68, 0x4C, 0x40, 0x0A, 0x32, 0x91, 0x72, 0x4A, 0x62, 0xE5, 0x02, 0x25, - 0x49, 0xCA, 0x28, 0xAD, 0x28, 0xDC, 0x02, 0x8C, 0x22, 0x91, 0x29, 0xBD, - 0x39, 0x45, 0x14, 0x8F, 0x64, 0xA4, 0x1A, 0x8C, 0x18, 0x91, 0x6A, 0x56, - 0xAA, 0x60, 0x1A, 0xA6, 0x02, 0x70, 0x13, 0x80, 0x92, 0x54, 0x04, 0x25, - 0x09, 0xCA, 0x64, 0x12, 0xC9, 0xA1, 0x11, 0xA0, 0x28, 0x37, 0x44, 0xF2, - 0x52, 0x53, 0x38, 0x0A, 0x41, 0xA8, 0x61, 0x11, 0xA5, 0x04, 0xAF, 0xB5, - 0x2D, 0xAA, 0x4D, 0x0A, 0x44, 0x20, 0x96, 0x00, 0x25, 0x0A, 0x6A, 0x25, - 0x25, 0x31, 0x21, 0x38, 0x4E, 0x92, 0x4A, 0x64, 0xD5, 0x30, 0x86, 0x0A, - 0x98, 0x29, 0x29, 0x74, 0x93, 0x12, 0x9B, 0x72, 0x49, 0x64, 0x99, 0x2D, - 0xC9, 0x89, 0x49, 0x4A, 0x84, 0x92, 0x94, 0x92, 0x43, 0xFF, 0xD6, 0xF4, - 0x1D, 0xC9, 0xE5, 0x44, 0xC2, 0x75, 0x3B, 0x5D, 0x79, 0x52, 0x01, 0x40, - 0x29, 0x04, 0x12, 0x90, 0x29, 0x05, 0x16, 0xA7, 0xD5, 0x04, 0xAF, 0x29, - 0x4A, 0x8A, 0x52, 0x92, 0x99, 0x02, 0x9E, 0x54, 0x41, 0x49, 0x25, 0x32, - 0x4A, 0x54, 0x65, 0x22, 0x52, 0x53, 0x3D, 0xCA, 0x24, 0xA8, 0x92, 0x9B, - 0x72, 0x54, 0xAB, 0x5E, 0x53, 0x26, 0x94, 0xE8, 0xA9, 0x44, 0x26, 0xDA, - 0x9E, 0x52, 0x25, 0x25, 0x31, 0x23, 0x44, 0x37, 0x34, 0x22, 0xF6, 0x42, - 0x78, 0x84, 0x90, 0x50, 0xB9, 0xA9, 0x80, 0x21, 0x12, 0x67, 0xB2, 0x73, - 0xF4, 0x74, 0x46, 0xD1, 0x48, 0x5D, 0xA7, 0x29, 0xB9, 0x0A, 0x4E, 0x32, - 0x91, 0x6E, 0x82, 0x11, 0x42, 0xC0, 0x4F, 0x6E, 0x11, 0x18, 0x21, 0x30, - 0x02, 0x25, 0x4C, 0x44, 0x20, 0x95, 0x41, 0x51, 0x1F, 0x49, 0x14, 0x44, - 0x6A, 0x91, 0x0D, 0x41, 0x34, 0xB0, 0x88, 0xD1, 0x47, 0x50, 0x53, 0x81, - 0x1C, 0x27, 0x29, 0x29, 0x62, 0x53, 0x6F, 0x01, 0x28, 0x51, 0x73, 0x80, - 0x45, 0x0A, 0x7B, 0xA5, 0x57, 0x71, 0x32, 0xA6, 0x4A, 0x83, 0xA0, 0xA2, - 0x10, 0x58, 0x7A, 0x84, 0x26, 0x0F, 0x32, 0x99, 0xDC, 0xA6, 0x82, 0x78, - 0x45, 0x6D, 0xA4, 0xF5, 0x12, 0xDE, 0x10, 0xA0, 0x85, 0x20, 0x95, 0x2A, - 0xD2, 0xB4, 0xCA, 0x20, 0x08, 0x0C, 0x3A, 0xA3, 0x02, 0x91, 0x48, 0x65, - 0x09, 0x88, 0x53, 0x6C, 0x14, 0xE5, 0x92, 0x82, 0x50, 0x93, 0xAA, 0x70, - 0x14, 0x8D, 0x71, 0xAA, 0x5A, 0x24, 0xA5, 0x94, 0x60, 0xA2, 0x42, 0x68, - 0x49, 0x4B, 0x34, 0x15, 0x28, 0x48, 0x0D, 0x54, 0xB4, 0x49, 0x4B, 0x34, - 0x22, 0x00, 0xA2, 0x21, 0x48, 0x10, 0x82, 0x43, 0x36, 0xA9, 0x97, 0x04, - 0x30, 0x42, 0x79, 0x94, 0x12, 0xBC, 0xA8, 0x92, 0x9E, 0x53, 0x14, 0x94, - 0xC7, 0x74, 0x24, 0x5E, 0x53, 0x39, 0x42, 0x75, 0x45, 0x09, 0x1A, 0xE5, - 0x20, 0xF4, 0x12, 0xE4, 0xB7, 0x25, 0x4A, 0xB4, 0xDB, 0xA5, 0x29, 0x43, - 0x0E, 0x4F, 0xBD, 0x2A, 0x55, 0xA4, 0x94, 0xA5, 0x0F, 0x78, 0x4B, 0x70, - 0x49, 0x56, 0x93, 0x71, 0x49, 0x43, 0x70, 0x49, 0x25, 0x3F, 0xFF, 0xD7, - 0xEF, 0x9A, 0x88, 0x10, 0x5A, 0x51, 0x01, 0x53, 0x96, 0xB8, 0x66, 0x21, - 0x38, 0x4C, 0x9C, 0x20, 0x96, 0x63, 0x84, 0xE0, 0xA1, 0xEE, 0x52, 0x05, - 0x24, 0xA8, 0xA4, 0x98, 0x94, 0x92, 0x43, 0x20, 0xA4, 0x02, 0x66, 0xA9, - 0x84, 0x12, 0xC6, 0x14, 0x5C, 0x88, 0x50, 0xDC, 0x92, 0x98, 0x95, 0x14, - 0x89, 0x4D, 0x28, 0xA1, 0x94, 0xA5, 0x2A, 0x32, 0x94, 0xA4, 0xA6, 0x52, - 0x94, 0xA8, 0xA4, 0x4A, 0x4A, 0x67, 0x28, 0x4F, 0xE7, 0x54, 0x8B, 0xA1, - 0x45, 0xCE, 0x25, 0x25, 0x5A, 0xA5, 0x24, 0xC1, 0x2E, 0x51, 0x42, 0xC1, - 0xB3, 0xAA, 0x90, 0xAE, 0x75, 0x4E, 0x01, 0x52, 0x69, 0x09, 0x29, 0x89, - 0x61, 0xE1, 0x37, 0x05, 0x49, 0xC5, 0x30, 0x49, 0x2B, 0x13, 0x01, 0x29, - 0x48, 0xB4, 0x95, 0x12, 0x08, 0x49, 0x0C, 0xF7, 0x42, 0x89, 0x77, 0x82, - 0x60, 0x09, 0x4E, 0x6B, 0x29, 0x29, 0x8E, 0xF3, 0x08, 0x66, 0x49, 0xD5, - 0x4C, 0x88, 0xD1, 0x3E, 0xD0, 0x42, 0x28, 0x44, 0x65, 0x41, 0xC0, 0xA3, - 0x16, 0xE8, 0xA0, 0x44, 0xE8, 0x92, 0x0B, 0x5E, 0x25, 0x4C, 0x08, 0x4E, - 0x5A, 0x25, 0x2E, 0xE8, 0xA1, 0x50, 0x98, 0x80, 0xA7, 0x1A, 0x26, 0x21, - 0x25, 0x31, 0x68, 0x84, 0x46, 0x92, 0x86, 0x7C, 0x94, 0xDB, 0x21, 0x24, - 0x84, 0xC0, 0xE8, 0xA6, 0x0A, 0x1B, 0x22, 0x75, 0x53, 0x25, 0x04, 0xA8, - 0x92, 0x74, 0x51, 0x80, 0x91, 0x29, 0x83, 0x92, 0x53, 0x20, 0x14, 0xA0, - 0x42, 0x8C, 0xA5, 0x29, 0x29, 0x62, 0x96, 0xE0, 0x13, 0x39, 0xC8, 0x72, - 0x51, 0x45, 0xA5, 0x2E, 0x4D, 0xBD, 0x0C, 0x98, 0x4D, 0x32, 0x95, 0x2A, - 0xD2, 0x7A, 0xA5, 0x48, 0x5A, 0x84, 0x9C, 0x25, 0x4A, 0xB4, 0x9E, 0xA9, - 0x4B, 0xD5, 0x50, 0x48, 0xA5, 0x4A, 0xB6, 0x46, 0xC4, 0xDB, 0x94, 0x0A, - 0x64, 0xA9, 0x56, 0xCC, 0x94, 0xD2, 0x53, 0x4A, 0x52, 0x92, 0x99, 0x6F, - 0x29, 0xB7, 0x15, 0x19, 0x4D, 0x32, 0x92, 0x2D, 0x9E, 0xE2, 0xA4, 0x1C, - 0x54, 0x02, 0x90, 0x49, 0x36, 0xCE, 0x74, 0x49, 0x46, 0x74, 0x49, 0x04, - 0xBF, 0xFF, 0xD0, 0xEE, 0xDA, 0x88, 0x10, 0xC1, 0x53, 0x05, 0x58, 0x6B, - 0x33, 0x05, 0x3C, 0xA8, 0x82, 0x94, 0xA0, 0x96, 0x52, 0x9C, 0x15, 0x09, - 0x4A, 0x52, 0x55, 0xB3, 0x94, 0xE0, 0xA1, 0xCA, 0x93, 0x42, 0x4A, 0x4C, - 0xD5, 0x30, 0x14, 0x18, 0x54, 0xC1, 0x4D, 0x2B, 0x94, 0x42, 0x83, 0x82, - 0x20, 0x51, 0x74, 0x24, 0xA4, 0x04, 0x28, 0x95, 0x27, 0x94, 0x2D, 0xC9, - 0xCB, 0x4B, 0x29, 0x48, 0x15, 0x09, 0x4B, 0x74, 0x24, 0xA4, 0xB2, 0xA0, - 0xE2, 0xA3, 0xBE, 0x52, 0x71, 0x94, 0xA9, 0x56, 0xB1, 0x71, 0x51, 0x94, - 0xD0, 0x65, 0x39, 0x28, 0xA1, 0x98, 0x3A, 0x29, 0x35, 0xB2, 0x14, 0x1A, - 0x8A, 0xDD, 0x10, 0x29, 0x0C, 0x83, 0x40, 0x0A, 0x24, 0x29, 0x82, 0x3B, - 0xA8, 0xBB, 0x94, 0x12, 0xB4, 0x28, 0xE8, 0x91, 0x72, 0x89, 0xE5, 0x14, - 0x32, 0x04, 0x05, 0x07, 0x9D, 0x52, 0x71, 0x51, 0x99, 0x4A, 0x91, 0x6C, - 0xDA, 0xEF, 0x15, 0x22, 0xFD, 0x10, 0x8A, 0x89, 0x72, 0x34, 0xAB, 0x66, - 0xE2, 0x0A, 0x40, 0x00, 0x84, 0x5C, 0x65, 0x3B, 0x49, 0x4A, 0x95, 0x69, - 0x49, 0x04, 0x28, 0x6D, 0x4E, 0x13, 0xED, 0x29, 0x29, 0x0B, 0x80, 0xEC, - 0x9B, 0x6A, 0x9B, 0x80, 0x09, 0xA5, 0x14, 0x2C, 0x98, 0xF9, 0x29, 0x25, - 0x09, 0x21, 0x18, 0x06, 0x54, 0xC0, 0x4E, 0x02, 0x53, 0x09, 0x29, 0x93, - 0x74, 0x53, 0x90, 0x50, 0x83, 0x94, 0x81, 0x42, 0x93, 0x6B, 0xB9, 0x46, - 0x40, 0x49, 0xDA, 0xA8, 0xC2, 0x2A, 0x48, 0x1C, 0x0A, 0x45, 0x0D, 0x3C, - 0x94, 0x95, 0x6A, 0x72, 0x8C, 0xA7, 0x95, 0x12, 0x92, 0x16, 0x71, 0x4C, - 0x0A, 0x63, 0xCA, 0x78, 0x45, 0x0C, 0x81, 0x52, 0x0A, 0x01, 0x48, 0x24, - 0x96, 0x52, 0x91, 0x4C, 0x9C, 0x20, 0xA5, 0xB5, 0x51, 0x28, 0x88, 0x6F, - 0xE5, 0x25, 0x2C, 0x0A, 0x97, 0x65, 0x0E, 0x13, 0xCA, 0x2A, 0x5D, 0x20, - 0x9A, 0x52, 0x94, 0x94, 0xC8, 0x15, 0x20, 0x50, 0xE4, 0xCA, 0x9B, 0x4A, - 0x4A, 0x66, 0x92, 0x7E, 0xC9, 0x20, 0x97, 0xFF, 0xD1, 0xEE, 0x03, 0x94, - 0x83, 0x90, 0x03, 0x94, 0xC3, 0x95, 0x9A, 0x6A, 0x02, 0x9C, 0x15, 0x20, - 0x84, 0xD2, 0xA6, 0x1C, 0x82, 0xE6, 0x49, 0xA5, 0x2E, 0x52, 0x84, 0x94, - 0xC9, 0xA5, 0x11, 0xA5, 0x09, 0xA1, 0x15, 0x81, 0x02, 0x90, 0xC8, 0x15, - 0x30, 0x54, 0x21, 0x3E, 0xA1, 0x05, 0xCC, 0xCB, 0xA0, 0x28, 0x39, 0xC9, - 0x6A, 0x98, 0x8D, 0x12, 0x52, 0x27, 0x21, 0x98, 0x45, 0x70, 0x95, 0x02, - 0xCD, 0x51, 0x5A, 0x58, 0xC4, 0x85, 0x12, 0xA6, 0x44, 0x21, 0xB9, 0x10, - 0x85, 0x82, 0x9B, 0x44, 0xA1, 0xB6, 0x65, 0x10, 0x24, 0xA5, 0xCB, 0x61, - 0x46, 0x24, 0xA9, 0x1E, 0x13, 0x00, 0x92, 0x97, 0x68, 0xF1, 0x46, 0x6C, - 0x14, 0x36, 0x89, 0x53, 0x80, 0x10, 0x5C, 0x19, 0x18, 0x0A, 0x24, 0x4F, - 0x09, 0x89, 0x4C, 0x5E, 0x21, 0x05, 0x5A, 0xCE, 0x30, 0xA0, 0x5C, 0x53, - 0xF2, 0xA2, 0x9C, 0xB5, 0x6F, 0x8A, 0x8F, 0x74, 0x43, 0x0A, 0x1C, 0xA4, - 0xA5, 0xFB, 0x28, 0x16, 0xA2, 0x80, 0x13, 0x16, 0xCA, 0x4A, 0x46, 0x1A, - 0x49, 0x45, 0x15, 0x24, 0xD6, 0xC2, 0x33, 0x48, 0x29, 0x12, 0xA0, 0x18, - 0x8A, 0xCA, 0x45, 0x88, 0xA0, 0x84, 0xC5, 0x0B, 0x5D, 0x4D, 0x67, 0xB5, - 0x08, 0x85, 0x65, 0xE2, 0x4A, 0x13, 0x9B, 0x08, 0x82, 0xB4, 0x84, 0x60, - 0x27, 0x00, 0xA4, 0xA4, 0x11, 0x43, 0x12, 0x21, 0x44, 0xA2, 0x6D, 0x94, - 0xC5, 0xA9, 0x29, 0x80, 0x10, 0xA4, 0x13, 0x42, 0x49, 0x21, 0x79, 0x09, - 0x93, 0x6A, 0xA4, 0xD1, 0xE2, 0x92, 0x56, 0xDA, 0x98, 0x84, 0x4D, 0x14, - 0x1D, 0x29, 0x28, 0xAD, 0x09, 0x88, 0x09, 0xF5, 0x4C, 0xED, 0x02, 0x48, - 0x62, 0x40, 0x4A, 0x14, 0x75, 0x52, 0x01, 0x14, 0x2B, 0xB2, 0x70, 0x53, - 0x14, 0xD2, 0x92, 0x52, 0x4A, 0x90, 0x84, 0x20, 0x51, 0x1A, 0x82, 0x82, - 0xEE, 0x43, 0x71, 0x52, 0x79, 0x43, 0x73, 0xD2, 0x0A, 0x2B, 0xCC, 0xA6, - 0x85, 0x02, 0xEF, 0x05, 0x20, 0xF0, 0x8A, 0x14, 0x4C, 0x26, 0xDC, 0x99, - 0xC5, 0x46, 0x51, 0xA5, 0x5A, 0x50, 0x42, 0x93, 0x4A, 0x0B, 0x4A, 0x90, - 0x30, 0x85, 0x2A, 0xD3, 0xEE, 0xD1, 0x24, 0x3D, 0xC1, 0x24, 0xA9, 0x36, - 0xFF, 0x00, 0xFF, 0xD2, 0xEB, 0xC1, 0x45, 0x08, 0x2D, 0x44, 0x0A, 0xD9, - 0x69, 0x84, 0x8D, 0x72, 0x98, 0x28, 0x60, 0x29, 0x84, 0xD4, 0x84, 0x8D, - 0x72, 0x20, 0x84, 0x10, 0x11, 0x18, 0x25, 0x02, 0xB8, 0x24, 0x01, 0x4C, - 0x04, 0x9A, 0xD4, 0xE4, 0x26, 0xAE, 0x0B, 0xA7, 0x27, 0x44, 0xC1, 0x22, - 0x42, 0x49, 0x50, 0x72, 0x62, 0x54, 0x49, 0x51, 0x94, 0x91, 0x6B, 0xA6, - 0x2E, 0x09, 0x89, 0x1E, 0x2A, 0x2E, 0xF1, 0x45, 0x16, 0xC5, 0xCE, 0x01, - 0x08, 0x9D, 0x53, 0xB8, 0xCA, 0x84, 0x90, 0x9C, 0x02, 0xD2, 0x52, 0x35, - 0x4F, 0x44, 0x30, 0x54, 0xA6, 0x50, 0x4B, 0x25, 0x28, 0x0A, 0x21, 0x3C, - 0xA4, 0xA6, 0x61, 0x31, 0x25, 0x46, 0x61, 0x29, 0x41, 0x36, 0xB9, 0x2A, - 0x30, 0x94, 0xA4, 0x25, 0x14, 0x28, 0x02, 0x91, 0x01, 0x3A, 0x62, 0x0A, - 0x4A, 0x59, 0x38, 0x6A, 0x60, 0x35, 0x44, 0x68, 0x09, 0x29, 0x6D, 0xA9, - 0x6D, 0x53, 0x51, 0x28, 0x25, 0x41, 0xA9, 0xD2, 0x09, 0xD2, 0x52, 0xC4, - 0x94, 0x83, 0x8A, 0x45, 0x45, 0x25, 0x32, 0x9D, 0x54, 0x1F, 0xC2, 0x74, - 0x8A, 0x48, 0x43, 0x09, 0xE1, 0x48, 0xC4, 0xA5, 0xCA, 0x2A, 0x58, 0x6A, - 0x91, 0x09, 0xE2, 0x13, 0x3C, 0xA4, 0xA6, 0x05, 0x46, 0x42, 0x91, 0x43, - 0x74, 0xA2, 0xB4, 0xAE, 0x4A, 0x76, 0xA8, 0x29, 0xB5, 0x25, 0x32, 0x94, - 0xC5, 0x3C, 0x26, 0x76, 0x89, 0x25, 0x64, 0xC6, 0x0A, 0x69, 0x4C, 0x8A, - 0x15, 0x09, 0xC0, 0x4A, 0x12, 0x49, 0x4B, 0x11, 0xD9, 0x41, 0xC2, 0x11, - 0x44, 0x26, 0x70, 0x05, 0x25, 0x22, 0x69, 0xD7, 0x55, 0x2D, 0xEA, 0x2E, - 0xE5, 0x40, 0xB9, 0x1A, 0x45, 0xB3, 0x2F, 0x25, 0x44, 0x95, 0x02, 0xE5, - 0x12, 0xE2, 0x95, 0x22, 0xD9, 0x94, 0x83, 0x90, 0xCB, 0xBB, 0x26, 0xDC, - 0x8D, 0x22, 0xD9, 0xB9, 0xDA, 0xE8, 0x90, 0x72, 0x82, 0x53, 0x08, 0xA2, - 0xD2, 0x87, 0x27, 0x94, 0x30, 0x54, 0x82, 0x09, 0xB4, 0x92, 0x92, 0x82, - 0x49, 0x2A, 0xDF, 0xFF, 0xD3, 0xEB, 0x9A, 0x11, 0x58, 0x14, 0x1B, 0x08, - 0xAD, 0x56, 0x8B, 0x4C, 0x32, 0x01, 0x4B, 0xB2, 0x68, 0x53, 0x6B, 0x74, - 0xD5, 0x05, 0xC1, 0x6D, 0x54, 0xD8, 0x60, 0xA8, 0xB8, 0x24, 0x01, 0x41, - 0x29, 0xDB, 0x62, 0x9E, 0xF4, 0x01, 0x3D, 0xD4, 0xC6, 0xA8, 0x52, 0x6D, - 0x26, 0xE0, 0x94, 0x94, 0x30, 0x42, 0x96, 0xE0, 0x38, 0x49, 0x36, 0xB2, - 0x62, 0x0A, 0x5B, 0xF5, 0x48, 0xBA, 0x42, 0x48, 0x60, 0x65, 0x44, 0xEE, - 0x53, 0x95, 0x12, 0x51, 0x42, 0x32, 0x13, 0x10, 0x93, 0x8A, 0x62, 0x74, - 0x45, 0x0A, 0x94, 0xA6, 0x14, 0x4B, 0x92, 0xDC, 0x92, 0x2D, 0x28, 0x72, - 0x79, 0x43, 0x69, 0x52, 0x05, 0x2A, 0x4D, 0xA4, 0x02, 0x53, 0xC2, 0x83, - 0x5C, 0xA7, 0xB9, 0x04, 0xAF, 0x01, 0x3C, 0x28, 0x87, 0x29, 0xC8, 0x84, - 0x14, 0xB7, 0x29, 0x14, 0xF2, 0xA2, 0x4A, 0x49, 0x5E, 0x13, 0xB5, 0x46, - 0x53, 0x82, 0x92, 0x19, 0x15, 0x12, 0xA5, 0xCA, 0x68, 0x49, 0x2A, 0x49, - 0x3A, 0x74, 0x94, 0xC0, 0xA6, 0x52, 0x72, 0x81, 0x45, 0x0B, 0x17, 0x28, - 0x97, 0x26, 0x71, 0x51, 0x25, 0x2A, 0x45, 0xB2, 0x05, 0x38, 0x50, 0x68, - 0x25, 0x48, 0x22, 0xA6, 0x52, 0x14, 0x0A, 0x91, 0x0A, 0x25, 0x25, 0x31, - 0x25, 0x47, 0x95, 0x3D, 0x23, 0x54, 0xD0, 0x3B, 0x24, 0x86, 0x30, 0xA6, - 0xC6, 0xA4, 0x14, 0x80, 0x29, 0x24, 0x32, 0xDA, 0x21, 0x41, 0xCD, 0x95, - 0x36, 0x92, 0x98, 0xF2, 0x82, 0x5A, 0xE5, 0xA4, 0x27, 0x1A, 0x1D, 0x51, - 0x8B, 0x74, 0x43, 0x2D, 0xD5, 0x1B, 0x5B, 0x4A, 0xD3, 0x94, 0xDA, 0x29, - 0x46, 0xD0, 0xA1, 0x29, 0x29, 0x72, 0x44, 0x28, 0x13, 0x09, 0x38, 0xA1, - 0x39, 0xC6, 0x51, 0x01, 0x04, 0xA9, 0xE4, 0x21, 0x94, 0x89, 0x51, 0x94, - 0xE5, 0xA4, 0xA8, 0xA8, 0x97, 0x29, 0x1E, 0x10, 0x89, 0x44, 0x21, 0x79, - 0x94, 0xE8, 0x61, 0xCA, 0x5B, 0x91, 0xA4, 0x32, 0x05, 0x29, 0x4C, 0x0A, - 0x48, 0x29, 0x9B, 0x51, 0x02, 0x1B, 0x25, 0x15, 0x02, 0x90, 0xAE, 0xC9, - 0x25, 0x26, 0x12, 0x49, 0x2F, 0xFF, 0xD4, 0xEC, 0x5B, 0x0A, 0x6C, 0xE5, - 0x04, 0x13, 0xCA, 0x2B, 0x78, 0x56, 0x8B, 0x4D, 0x30, 0x2A, 0x60, 0xA1, - 0x84, 0xED, 0x3E, 0x28, 0x2E, 0x64, 0xE3, 0x29, 0x4A, 0x62, 0x3C, 0x14, - 0x4B, 0x88, 0x49, 0x49, 0x03, 0x93, 0xEE, 0x84, 0x1D, 0xDA, 0xA4, 0x49, - 0x4A, 0x95, 0x69, 0x0B, 0xF5, 0x52, 0x6B, 0x87, 0x28, 0x0E, 0x72, 0x61, - 0x62, 0x54, 0xAB, 0x6C, 0xC8, 0x2A, 0x4D, 0x21, 0x00, 0x3D, 0x3E, 0xF8, - 0x08, 0x52, 0x6D, 0x33, 0xA3, 0x94, 0x17, 0xB8, 0x04, 0xCE, 0xB4, 0xA1, - 0x3D, 0xC4, 0xA2, 0x02, 0x09, 0x51, 0x7A, 0x62, 0xF4, 0x3D, 0xCA, 0x24, - 0xCA, 0x75, 0x2C, 0xB4, 0xBB, 0xA5, 0x38, 0x50, 0x68, 0x2A, 0x44, 0x14, - 0x92, 0xC8, 0x15, 0x30, 0x50, 0x81, 0x52, 0x05, 0x05, 0x24, 0x94, 0xE0, - 0xA8, 0x02, 0x9C, 0x14, 0x13, 0x6C, 0xC1, 0x44, 0x69, 0xD1, 0x09, 0x3C, - 0xA5, 0x49, 0xB4, 0xA4, 0x85, 0x12, 0xA2, 0x0A, 0x72, 0x50, 0x4A, 0xA5, - 0x38, 0x2A, 0x12, 0x90, 0x72, 0x34, 0x8B, 0x4C, 0x1C, 0x9B, 0x72, 0x80, - 0x29, 0xD0, 0x4D, 0xB3, 0x0E, 0x52, 0x94, 0x36, 0x85, 0x20, 0x50, 0x52, - 0xE5, 0x40, 0xA2, 0x26, 0x84, 0x94, 0x88, 0xD7, 0x29, 0x7A, 0x68, 0xD2, - 0x13, 0xE8, 0x8D, 0xAA, 0x90, 0x06, 0x42, 0x5A, 0x22, 0x90, 0x86, 0xF6, - 0xF8, 0x24, 0xA6, 0x24, 0xA8, 0x98, 0x2A, 0x2E, 0x4C, 0x1C, 0x42, 0x2B, - 0x6D, 0x93, 0xB8, 0x43, 0x2E, 0x85, 0x27, 0x19, 0x51, 0x21, 0x15, 0x15, - 0x35, 0xC4, 0x95, 0x66, 0xBE, 0x15, 0x76, 0x84, 0x7A, 0xA4, 0x20, 0x52, - 0x19, 0x96, 0xA8, 0x96, 0xED, 0xE5, 0x1B, 0x70, 0x08, 0x64, 0x97, 0x26, - 0xAE, 0x63, 0x1B, 0x93, 0x6D, 0x85, 0x30, 0x08, 0x3A, 0xA1, 0xD8, 0xE2, - 0x25, 0x14, 0x23, 0xB3, 0x94, 0x27, 0x10, 0x02, 0x91, 0x71, 0x28, 0x6F, - 0x4E, 0x0B, 0x09, 0x46, 0xF7, 0x6A, 0xA0, 0x49, 0xE5, 0x4C, 0x85, 0x10, - 0x13, 0x96, 0xB1, 0x25, 0x44, 0x8E, 0xE8, 0xA5, 0xA0, 0x26, 0x20, 0x94, - 0x95, 0x48, 0xA4, 0xA8, 0x22, 0x3B, 0x42, 0x96, 0xDD, 0xC3, 0x44, 0x50, - 0x84, 0xB6, 0x38, 0x4B, 0x58, 0x46, 0xD8, 0x78, 0x4F, 0xB5, 0xBB, 0x7C, - 0xD2, 0xB5, 0x52, 0x1D, 0x54, 0xD8, 0x27, 0x44, 0xFE, 0x9A, 0x9B, 0x18, - 0x67, 0x54, 0x89, 0x55, 0x2E, 0x1A, 0x42, 0x94, 0x29, 0xE8, 0x98, 0x93, - 0x28, 0x5A, 0xEA, 0x5F, 0x6E, 0x89, 0x26, 0x97, 0x24, 0x82, 0x9F, 0xFF, - 0xD5, 0xEC, 0x83, 0x77, 0x71, 0xA2, 0x9B, 0x1B, 0xA2, 0x61, 0xCC, 0x84, - 0x66, 0x01, 0xB5, 0x5A, 0x2D, 0x40, 0x11, 0xEA, 0x0A, 0x70, 0x7C, 0x14, - 0xDC, 0x04, 0x4F, 0x74, 0x2D, 0xC3, 0x80, 0x82, 0x97, 0xDE, 0x5B, 0xCA, - 0x8B, 0x9C, 0x49, 0xF2, 0x4F, 0xA1, 0xE5, 0x41, 0xCE, 0x00, 0xA2, 0x86, - 0x6D, 0xD7, 0x95, 0x28, 0x50, 0x04, 0x15, 0x30, 0x44, 0x24, 0x96, 0x2F, - 0x28, 0x45, 0xD0, 0xA4, 0xF7, 0x4A, 0x0B, 0x89, 0x44, 0x2D, 0x25, 0x2B, - 0x6C, 0x4E, 0x6D, 0x0A, 0xB6, 0xE2, 0x13, 0x7A, 0x84, 0x23, 0x48, 0xE2, - 0x6C, 0x17, 0x26, 0xDE, 0xAB, 0x9B, 0x49, 0xE5, 0x36, 0xE4, 0xA9, 0x5C, - 0x49, 0xCB, 0x82, 0x8C, 0xEA, 0xA1, 0xB9, 0x38, 0x49, 0x16, 0x9D, 0x8E, - 0x08, 0x9B, 0x82, 0xAE, 0x14, 0xDB, 0x28, 0x10, 0xB8, 0x14, 0x9A, 0x14, - 0x81, 0x50, 0xD5, 0x3C, 0xA4, 0xA6, 0x60, 0xA7, 0x94, 0x39, 0x4E, 0x0A, - 0x49, 0x49, 0xB9, 0x20, 0x50, 0xE5, 0x48, 0x14, 0x14, 0x94, 0x25, 0xAA, - 0x80, 0x2A, 0x5B, 0x90, 0x4A, 0xC4, 0x14, 0xED, 0x6F, 0x9A, 0x53, 0x29, - 0xC2, 0x4A, 0x64, 0x02, 0x9C, 0x28, 0x29, 0x83, 0x28, 0x25, 0x74, 0xDB, - 0xA1, 0x2D, 0x53, 0x77, 0x49, 0x2C, 0xC3, 0x92, 0x2E, 0x51, 0xDD, 0xA2, - 0x89, 0x72, 0x54, 0xAB, 0x48, 0x35, 0x2A, 0x53, 0x08, 0x2D, 0x72, 0x20, - 0x74, 0xA4, 0xA5, 0xCE, 0xA1, 0x40, 0x95, 0x30, 0x54, 0x1F, 0x11, 0x28, - 0x05, 0x23, 0x70, 0xEE, 0x86, 0x42, 0x99, 0x2A, 0x33, 0x29, 0xCB, 0x4B, - 0x18, 0x29, 0x44, 0x15, 0x38, 0x4C, 0xE6, 0xA2, 0xA5, 0x08, 0x44, 0x6B, - 0xC0, 0x90, 0x85, 0x09, 0x4C, 0x21, 0x4A, 0x05, 0x36, 0xE0, 0x88, 0x1C, - 0x15, 0x5D, 0xC5, 0x4D, 0xA5, 0x22, 0x12, 0x0A, 0x77, 0x38, 0x76, 0x41, - 0xB2, 0x0F, 0x74, 0xC5, 0xE5, 0x0C, 0xBB, 0x54, 0x80, 0x51, 0x2B, 0x3B, - 0xCB, 0xEF, 0x41, 0x79, 0x32, 0x8A, 0x78, 0x41, 0x70, 0x32, 0x9C, 0x16, - 0x16, 0x32, 0x65, 0x48, 0xC9, 0x09, 0x35, 0xA8, 0x81, 0xBE, 0x48, 0xA8, - 0x23, 0x0D, 0x31, 0xAA, 0x5B, 0x62, 0x04, 0x23, 0x86, 0xA7, 0x2D, 0x1F, - 0x34, 0x2D, 0x34, 0xD6, 0x75, 0x40, 0xF6, 0x4E, 0xDA, 0xA0, 0xEA, 0x8A, - 0xEE, 0x53, 0xB4, 0x18, 0x94, 0xAD, 0x14, 0xC0, 0xD6, 0x99, 0xD5, 0x77, - 0x89, 0x47, 0x00, 0x42, 0x72, 0xD3, 0xC1, 0x28, 0x5A, 0x69, 0xAB, 0xB3, - 0x58, 0x4E, 0x18, 0x40, 0x56, 0x3D, 0x30, 0x9B, 0x66, 0x88, 0xDA, 0xA9, - 0x0E, 0x91, 0xE6, 0xA5, 0x09, 0xCB, 0x61, 0x3B, 0x48, 0x8D, 0x52, 0x53, - 0x18, 0xD2, 0x23, 0x54, 0x94, 0xF4, 0x49, 0x05, 0x3F, 0xFF, 0xD6, 0xED, - 0x41, 0x0A, 0x5B, 0xFC, 0x10, 0x37, 0x6B, 0xE6, 0x9C, 0x38, 0xC2, 0xB5, - 0x4D, 0x3B, 0x66, 0xF7, 0x94, 0x30, 0xED, 0x53, 0xB9, 0xC2, 0x10, 0xC1, - 0xD5, 0x10, 0x10, 0x4B, 0x32, 0x4A, 0x89, 0x24, 0xA7, 0x26, 0x54, 0x51, - 0x43, 0x36, 0xBA, 0x13, 0x97, 0x21, 0x02, 0x9E, 0x52, 0xA5, 0x5A, 0xEE, - 0x72, 0x19, 0x76, 0xA9, 0xC9, 0x43, 0x29, 0x20, 0x95, 0x12, 0xA2, 0x4A, - 0x92, 0x68, 0x45, 0x0C, 0x21, 0x48, 0x04, 0xF0, 0xA4, 0x20, 0x23, 0x6A, - 0x5C, 0x30, 0xA9, 0x06, 0xA4, 0x1C, 0x53, 0xEE, 0x09, 0xA9, 0x64, 0xD1, - 0xE2, 0xA6, 0x21, 0x08, 0xBD, 0x20, 0xE8, 0x49, 0x36, 0x9A, 0x25, 0x34, - 0x28, 0x0B, 0x0F, 0x75, 0x20, 0xF0, 0x82, 0x6D, 0x96, 0xD2, 0x42, 0x68, - 0x52, 0x0F, 0x85, 0x12, 0xE0, 0x52, 0x52, 0x93, 0xA8, 0xCA, 0x79, 0x49, - 0x4C, 0x81, 0x4F, 0x2A, 0x20, 0xA7, 0x00, 0xA0, 0x96, 0x60, 0x92, 0xA4, - 0x09, 0x0A, 0x21, 0x4B, 0x44, 0x92, 0xC8, 0x12, 0x54, 0x9A, 0xE8, 0x43, - 0x05, 0x22, 0xE0, 0x82, 0xAD, 0x3C, 0xC8, 0x51, 0x3A, 0xA1, 0x8B, 0x14, - 0xB7, 0x21, 0x49, 0xB5, 0xCE, 0x8A, 0x24, 0x84, 0xC6, 0xC0, 0xA0, 0xE7, - 0xA3, 0x48, 0x25, 0x90, 0x76, 0xAA, 0x61, 0xD0, 0x83, 0x23, 0x94, 0xC5, - 0xE8, 0xD2, 0xAD, 0x39, 0x79, 0x50, 0x2E, 0x28, 0x7B, 0xCA, 0x40, 0x99, - 0xD5, 0x2A, 0x55, 0xB2, 0x2E, 0x4D, 0xF0, 0x48, 0x90, 0x9A, 0x42, 0x48, - 0x66, 0x09, 0x52, 0xEC, 0x86, 0x0A, 0x23, 0x50, 0x48, 0x58, 0xC4, 0x28, - 0xC2, 0x24, 0x04, 0xC9, 0x29, 0x88, 0x6E, 0xAA, 0x70, 0x98, 0x1D, 0x54, - 0xB4, 0x49, 0x41, 0x19, 0x25, 0x0E, 0x61, 0x15, 0xC1, 0x08, 0x84, 0x42, - 0x0A, 0xC5, 0xCA, 0x1A, 0x12, 0x9D, 0xC0, 0xA7, 0x6B, 0x51, 0x43, 0x26, - 0x80, 0x88, 0x1A, 0x14, 0x40, 0x52, 0xEC, 0x82, 0x42, 0xC7, 0x45, 0x1D, - 0xC9, 0xDC, 0x86, 0x52, 0x52, 0xE5, 0xC9, 0xDA, 0x44, 0xA8, 0x04, 0xFC, - 0x22, 0x84, 0xC2, 0x09, 0xF2, 0x53, 0x20, 0x46, 0x88, 0x2D, 0x28, 0x93, - 0xA1, 0x09, 0xAB, 0x97, 0x01, 0x3A, 0x8E, 0xE0, 0x02, 0x6D, 0xE9, 0x2A, - 0xD4, 0xE6, 0xA8, 0x6D, 0xD7, 0xC2, 0x14, 0x8D, 0x8A, 0x25, 0xC1, 0x14, - 0x2A, 0x04, 0xCA, 0x4A, 0x3B, 0xF5, 0x84, 0x92, 0x55, 0xBF, 0xFF, 0xD7, - 0xEB, 0xA6, 0x12, 0xDE, 0xA0, 0x5C, 0xA2, 0x4A, 0xB9, 0x4D, 0x1B, 0x66, - 0x4A, 0x8C, 0xA8, 0xEE, 0x4D, 0x24, 0xA3, 0x48, 0xB4, 0x9B, 0x92, 0x25, - 0x40, 0x12, 0x9E, 0x52, 0x53, 0x29, 0x4D, 0x29, 0xA5, 0x29, 0x49, 0x4A, - 0x29, 0x92, 0x29, 0x24, 0xA5, 0x24, 0x92, 0x49, 0x29, 0x49, 0x92, 0x29, - 0x24, 0xA5, 0xD3, 0xA8, 0xA7, 0x49, 0x4B, 0xA4, 0x9A, 0x52, 0x94, 0x94, - 0xBC, 0xA9, 0x07, 0x21, 0x92, 0x90, 0x25, 0x25, 0x5A, 0x69, 0x4E, 0x0A, - 0x10, 0x25, 0x4E, 0x50, 0x4D, 0xB3, 0x05, 0x29, 0x50, 0x94, 0x89, 0x49, - 0x56, 0xCF, 0x74, 0x29, 0x36, 0xC4, 0x09, 0x4E, 0x0A, 0x54, 0xAB, 0x6C, - 0x6F, 0x94, 0xB7, 0x94, 0x10, 0xE5, 0x20, 0x50, 0xA4, 0xDA, 0x5D, 0xE5, - 0x34, 0xA8, 0xCA, 0x79, 0x49, 0x4B, 0x82, 0x65, 0x4A, 0x4A, 0x80, 0x52, - 0x41, 0x2B, 0x19, 0x4C, 0xA4, 0x98, 0xA4, 0xA6, 0x29, 0xC2, 0x49, 0xA1, - 0x14, 0x32, 0x81, 0xE2, 0x91, 0xF0, 0x51, 0x4A, 0x12, 0x52, 0xE9, 0x00, - 0x52, 0x01, 0x4C, 0x04, 0x92, 0xA0, 0xA6, 0x14, 0x42, 0x70, 0x82, 0x99, - 0xA6, 0x4C, 0x9D, 0x04, 0xA8, 0x27, 0x4C, 0xA4, 0x12, 0x53, 0x12, 0x0A, - 0x81, 0x08, 0xA6, 0x21, 0x40, 0xA4, 0xA4, 0x4E, 0x09, 0x82, 0x99, 0x0A, - 0x31, 0xAA, 0x28, 0x66, 0x08, 0x48, 0x90, 0x54, 0x7B, 0x68, 0xA2, 0x4E, - 0xA9, 0x29, 0x99, 0x28, 0x66, 0x0F, 0x09, 0xF5, 0x29, 0x35, 0xBA, 0xA2, - 0xA6, 0x20, 0x42, 0x90, 0x6E, 0xA9, 0xF6, 0xA7, 0x02, 0x35, 0x49, 0x4B, - 0xB4, 0x01, 0xAA, 0x45, 0xDA, 0x28, 0x92, 0x12, 0x88, 0x12, 0x82, 0x94, - 0x5C, 0x90, 0x04, 0xEA, 0x99, 0x3E, 0xE8, 0x45, 0x4B, 0x3B, 0x45, 0x02, - 0x54, 0xDC, 0x54, 0x1D, 0xC2, 0x48, 0x2C, 0x65, 0x25, 0x19, 0x49, 0x14, - 0x5B, 0xFF, 0xD0, 0xEA, 0x25, 0x31, 0x94, 0xE9, 0x95, 0xD7, 0x3D, 0x88, - 0x52, 0x10, 0x98, 0x27, 0x49, 0x4B, 0xA6, 0x25, 0x24, 0x88, 0x49, 0x4A, - 0x94, 0xE0, 0xA8, 0xC2, 0x74, 0x94, 0xB9, 0x4C, 0x9D, 0x34, 0xA4, 0x95, - 0x24, 0x94, 0xA4, 0x92, 0x16, 0x4E, 0xA4, 0x04, 0xA4, 0x52, 0x4A, 0xC0, - 0x24, 0x42, 0x70, 0x91, 0x49, 0x4C, 0x13, 0x4A, 0x72, 0x99, 0x14, 0x29, - 0x48, 0x28, 0x25, 0x30, 0x92, 0x92, 0x82, 0x12, 0x94, 0x30, 0x52, 0xDC, - 0x85, 0x2A, 0xD2, 0x4A, 0x52, 0xA0, 0x0A, 0x98, 0x29, 0x25, 0x6D, 0x53, - 0xC2, 0x49, 0x24, 0xA6, 0x41, 0x48, 0x28, 0x05, 0x29, 0x41, 0x21, 0x98, - 0x2A, 0x41, 0x0E, 0x54, 0x81, 0x41, 0x2C, 0xD3, 0xCA, 0x8C, 0xA7, 0x49, - 0x4B, 0xA4, 0x53, 0x4A, 0x52, 0x82, 0x54, 0x92, 0x49, 0x22, 0xA5, 0x27, - 0x01, 0x24, 0xE1, 0x05, 0x2E, 0x02, 0x78, 0x48, 0x27, 0x09, 0x29, 0x50, - 0x9E, 0x12, 0x4E, 0x82, 0x54, 0x92, 0x74, 0x92, 0x52, 0xC9, 0xD3, 0x24, - 0x92, 0x97, 0x51, 0x21, 0x3A, 0x62, 0x92, 0x96, 0x2D, 0x4C, 0x42, 0x94, - 0x26, 0x45, 0x08, 0xCC, 0x84, 0xA1, 0x4C, 0xA8, 0xC2, 0x4A, 0x58, 0x18, - 0x4E, 0x94, 0x27, 0x84, 0x94, 0xAE, 0x12, 0x24, 0x26, 0x29, 0x8A, 0x4A, - 0x62, 0x60, 0x14, 0xE5, 0xC9, 0x26, 0x28, 0xA1, 0x69, 0x48, 0x19, 0x49, - 0x34, 0xA4, 0xA5, 0x38, 0xE8, 0xA1, 0x29, 0x12, 0xA0, 0x4E, 0xA8, 0x80, - 0x82, 0x57, 0x9D, 0x52, 0x51, 0x92, 0x92, 0x28, 0x7F, 0xFF, 0xD1, 0xEA, - 0x08, 0x48, 0x05, 0x38, 0x4D, 0x0A, 0xEB, 0x41, 0x84, 0x27, 0x85, 0x28, - 0x4E, 0x18, 0x52, 0x55, 0x31, 0x00, 0x24, 0x42, 0x28, 0x68, 0xF9, 0xA6, - 0x2D, 0x42, 0xD5, 0x48, 0xB6, 0x9F, 0x04, 0xE1, 0x88, 0xA1, 0xA9, 0xF6, - 0xA5, 0x69, 0xA4, 0x5B, 0x02, 0x62, 0xC2, 0x8C, 0x1B, 0xAA, 0x7D, 0xA0, - 0xA5, 0x6A, 0xA4, 0x02, 0xA9, 0x52, 0xF4, 0xA3, 0x94, 0x70, 0x00, 0x51, - 0x72, 0x56, 0xAA, 0x47, 0x11, 0xC2, 0x81, 0xD5, 0x49, 0xCA, 0x29, 0x20, - 0xA8, 0x24, 0x52, 0x48, 0xA2, 0xA6, 0x05, 0x32, 0x9C, 0x14, 0xC4, 0x24, - 0x86, 0x2A, 0x30, 0xA7, 0x09, 0x8A, 0x2A, 0x63, 0xC2, 0x61, 0xCA, 0x91, - 0x09, 0xC3, 0x52, 0x52, 0xE1, 0x38, 0x48, 0x35, 0x39, 0x08, 0x29, 0x70, - 0x52, 0x4D, 0x05, 0x2D, 0x52, 0x4A, 0xEA, 0x41, 0x41, 0x38, 0x29, 0x29, - 0x9A, 0x90, 0x51, 0x69, 0x52, 0x08, 0x25, 0x90, 0x49, 0x32, 0x79, 0x41, - 0x2B, 0xA7, 0x4C, 0x0A, 0x79, 0x49, 0x4A, 0x84, 0xA1, 0x34, 0xA7, 0x05, - 0x24, 0xAE, 0x14, 0x80, 0x4D, 0x29, 0xC2, 0x0A, 0x66, 0x02, 0x50, 0xA4, - 0xD4, 0xEE, 0x08, 0x25, 0x82, 0x70, 0x53, 0x24, 0x92, 0x99, 0x24, 0x99, - 0x24, 0x94, 0xA4, 0xC9, 0x14, 0xC9, 0x29, 0x74, 0x93, 0x05, 0x24, 0x94, - 0xB1, 0x4C, 0x9D, 0x32, 0x2A, 0x59, 0x28, 0x49, 0x24, 0x90, 0xA4, 0xC9, - 0xD2, 0x49, 0x4B, 0x15, 0x12, 0x14, 0x93, 0x10, 0x92, 0x98, 0x26, 0x2A, - 0x64, 0x26, 0x84, 0x54, 0xC5, 0x44, 0xA9, 0xC2, 0x89, 0x09, 0x21, 0x19, - 0x51, 0x21, 0x13, 0x6A, 0x68, 0x45, 0x14, 0xC2, 0x12, 0x52, 0x84, 0x91, - 0x45, 0x3F, 0xFF, 0xD2, 0xEB, 0xA1, 0x48, 0x34, 0x42, 0x50, 0x9C, 0x2B, - 0x76, 0xD2, 0x63, 0x0D, 0x09, 0xE5, 0x22, 0xD4, 0x82, 0x4A, 0x50, 0x09, - 0x42, 0x98, 0x88, 0x48, 0x42, 0x56, 0xAA, 0x62, 0x02, 0x44, 0x29, 0x81, - 0x29, 0xF6, 0xA1, 0x69, 0xA4, 0x62, 0x52, 0x06, 0x14, 0xA0, 0x28, 0x91, - 0x1C, 0x24, 0xA5, 0x12, 0xA2, 0x52, 0x24, 0xCA, 0x70, 0x09, 0x45, 0x0C, - 0x1C, 0x02, 0x81, 0x08, 0xA5, 0xA9, 0x06, 0x23, 0x6A, 0xA4, 0x30, 0x53, - 0xC2, 0x2C, 0x05, 0x03, 0x09, 0x5A, 0x29, 0x8C, 0x26, 0x21, 0x49, 0x24, - 0x94, 0xC6, 0x13, 0x6D, 0x53, 0x49, 0x2B, 0x45, 0x30, 0xDA, 0x9C, 0x05, - 0x28, 0x4A, 0x12, 0x55, 0x2D, 0x09, 0xE1, 0x20, 0x92, 0x49, 0x58, 0x84, - 0xCA, 0x44, 0x28, 0x90, 0x92, 0x16, 0x4E, 0xA2, 0x9C, 0x04, 0x54, 0xC8, - 0x15, 0x2D, 0xCA, 0x21, 0x24, 0x12, 0xCB, 0x72, 0x6D, 0xC9, 0x8A, 0x52, - 0x92, 0x19, 0x87, 0x29, 0x02, 0x86, 0x0A, 0x90, 0x29, 0x25, 0x94, 0xA9, - 0x05, 0x10, 0x92, 0x09, 0x66, 0x9C, 0x39, 0x40, 0x14, 0xE0, 0xC9, 0x49, - 0x49, 0xD8, 0xE5, 0x32, 0x84, 0xD4, 0x40, 0x0A, 0x69, 0x5C, 0x16, 0x29, - 0x24, 0x44, 0x24, 0x92, 0x94, 0x92, 0x50, 0x92, 0x49, 0x59, 0x34, 0x29, - 0x42, 0x64, 0x90, 0xA8, 0x49, 0x24, 0x92, 0x52, 0x93, 0x27, 0x49, 0x25, - 0x2D, 0x09, 0x27, 0x49, 0x25, 0x28, 0x09, 0x52, 0xD8, 0x9D, 0x81, 0x11, - 0x0B, 0x48, 0x08, 0xBD, 0x35, 0x12, 0xC4, 0x78, 0x43, 0x72, 0x56, 0xAA, - 0x42, 0x5A, 0x98, 0x84, 0x42, 0x14, 0x0A, 0x28, 0xA6, 0x24, 0x28, 0x90, - 0xA6, 0x98, 0x84, 0x50, 0xC0, 0x85, 0x12, 0x11, 0x21, 0x34, 0x22, 0x86, - 0x10, 0x92, 0x9C, 0x24, 0x92, 0xA9, 0xFF, 0xD3, 0xEC, 0x53, 0xB5, 0x25, - 0x20, 0xD5, 0x69, 0xA6, 0xA8, 0x05, 0x2D, 0x89, 0xE2, 0x12, 0x98, 0x49, - 0x2B, 0x6D, 0x84, 0xB4, 0x4A, 0x74, 0x4C, 0x4C, 0x24, 0xA6, 0x40, 0xA4, - 0x4A, 0x81, 0x72, 0x6D, 0xC9, 0x29, 0x92, 0x64, 0xD2, 0x9C, 0x10, 0x92, - 0x15, 0x09, 0x27, 0x91, 0xD9, 0x31, 0x29, 0x29, 0x7D, 0xAA, 0x26, 0x42, - 0x45, 0xE4, 0x28, 0x97, 0x92, 0x92, 0x94, 0x75, 0x51, 0x20, 0x26, 0x25, - 0x34, 0x94, 0x50, 0xBA, 0x62, 0x94, 0x14, 0xA1, 0x14, 0x2C, 0xA4, 0x13, - 0x42, 0x70, 0x12, 0x52, 0xE0, 0x25, 0x09, 0x27, 0x41, 0x2B, 0x42, 0x65, - 0x24, 0xA1, 0x25, 0x30, 0x84, 0x8B, 0x54, 0xE1, 0x32, 0x2A, 0xA6, 0x01, - 0x8A, 0x41, 0x8A, 0x41, 0x29, 0x4A, 0xD5, 0x4C, 0x4B, 0x53, 0x42, 0x91, - 0x4D, 0xB9, 0x24, 0x31, 0x21, 0x32, 0x44, 0xA6, 0x94, 0x90, 0xC8, 0x29, - 0x88, 0x50, 0x12, 0x78, 0x52, 0x00, 0xA4, 0x90, 0xCA, 0x53, 0xCA, 0x4D, - 0x68, 0x8D, 0x54, 0x83, 0x42, 0x09, 0xA5, 0x80, 0x44, 0x63, 0x0A, 0x76, - 0x88, 0x44, 0x05, 0x02, 0x52, 0x02, 0x80, 0x4F, 0x2A, 0x25, 0xCA, 0x32, - 0x82, 0x52, 0x13, 0x29, 0x94, 0x41, 0x4F, 0x29, 0x25, 0x74, 0x92, 0x4D, - 0x29, 0x29, 0x72, 0x99, 0x32, 0x49, 0x21, 0x49, 0x4A, 0x69, 0x4A, 0x52, - 0x52, 0xE9, 0x15, 0x20, 0x13, 0xC0, 0x49, 0x54, 0xC1, 0x48, 0x04, 0xF0, - 0x9F, 0x69, 0xEC, 0x92, 0x69, 0x41, 0x4D, 0xA9, 0x9A, 0x13, 0x80, 0x82, - 0x57, 0x3C, 0x28, 0x10, 0x89, 0x09, 0x89, 0x08, 0x29, 0x11, 0x6A, 0x19, - 0x84, 0x67, 0x4A, 0x11, 0x09, 0xC1, 0x05, 0x82, 0x62, 0xA5, 0xB4, 0xA8, - 0xC2, 0x28, 0x59, 0x24, 0xF0, 0x94, 0x14, 0x90, 0xB2, 0x49, 0xE1, 0x24, - 0x94, 0xFF, 0x00, 0xFF, 0xD4, 0xEC, 0xD3, 0xEE, 0x51, 0x71, 0x0A, 0x3B, - 0x95, 0xA6, 0xA2, 0x49, 0x51, 0x73, 0x94, 0x65, 0x34, 0xA5, 0x48, 0xB6, - 0x5B, 0x93, 0xB8, 0xCA, 0x1C, 0xA9, 0x07, 0x24, 0xA5, 0x42, 0x49, 0x12, - 0x9B, 0x59, 0x45, 0x4B, 0xEA, 0x92, 0x53, 0x1A, 0x26, 0x28, 0x29, 0x94, - 0xA6, 0x2A, 0x29, 0x4A, 0x4A, 0x51, 0x4C, 0x91, 0x29, 0xA5, 0x14, 0x29, - 0x20, 0x0A, 0x49, 0xE4, 0x22, 0xA5, 0x04, 0xE9, 0x93, 0xA0, 0xA5, 0x42, - 0x96, 0xD4, 0x82, 0x70, 0x82, 0x56, 0xDA, 0x96, 0xD5, 0x24, 0xF0, 0x52, - 0x55, 0x30, 0x84, 0xB6, 0xA2, 0x06, 0x94, 0xCE, 0x05, 0x2B, 0x55, 0x30, - 0xDA, 0x13, 0x42, 0x72, 0x9A, 0x52, 0x52, 0xD0, 0x98, 0x94, 0xE9, 0x88, - 0x45, 0x0C, 0x4B, 0x82, 0x81, 0x72, 0x99, 0x62, 0x60, 0xCD, 0x75, 0x45, - 0x06, 0xD8, 0x4C, 0xF0, 0x90, 0x61, 0x94, 0x5D, 0x80, 0x26, 0xD1, 0x2B, - 0x45, 0x2D, 0x04, 0x27, 0xDC, 0x53, 0x81, 0x29, 0xF6, 0xC2, 0x49, 0x53, - 0x49, 0xEE, 0x8A, 0xD5, 0x06, 0x80, 0xA7, 0xB8, 0x04, 0x0A, 0x43, 0x31, - 0x2A, 0x4A, 0x2D, 0x7A, 0x94, 0xCA, 0x6A, 0xE5, 0x1F, 0x35, 0x02, 0x61, - 0x3B, 0x8F, 0x9A, 0x13, 0x88, 0x05, 0x10, 0x82, 0xCF, 0x72, 0x90, 0x72, - 0x00, 0x2A, 0x61, 0xC9, 0x52, 0xAD, 0x34, 0xA5, 0x28, 0x60, 0xA7, 0x94, - 0x12, 0xCA, 0x52, 0x94, 0xC9, 0xD2, 0x52, 0xD0, 0x9C, 0x24, 0x92, 0x4A, - 0x5C, 0x15, 0x31, 0x08, 0x63, 0x94, 0x49, 0xD1, 0x24, 0x86, 0x41, 0x4D, - 0xA0, 0x20, 0xEE, 0x0A, 0x4D, 0x72, 0x09, 0x09, 0x0F, 0x29, 0x4A, 0x8C, - 0xCA, 0x79, 0x41, 0x4B, 0x92, 0x86, 0x65, 0x48, 0x94, 0xDA, 0x22, 0xA6, - 0x24, 0xA6, 0x2A, 0x44, 0x05, 0x14, 0x90, 0xB2, 0x8E, 0xC9, 0x4E, 0x4C, - 0x26, 0x0F, 0x45, 0x4A, 0xDA, 0x02, 0x73, 0x09, 0xC1, 0x4C, 0x52, 0x53, - 0x0E, 0xFC, 0x24, 0x9E, 0x44, 0xA4, 0x92, 0x1F, 0xFF, 0xD5, 0xEB, 0x8B, - 0xB5, 0x4C, 0x5C, 0x10, 0x4D, 0x89, 0x7A, 0x81, 0x5C, 0xA6, 0x8D, 0xA6, - 0xDC, 0x13, 0x6E, 0x41, 0xDE, 0x13, 0x87, 0x25, 0x4A, 0xB4, 0xB3, 0x29, - 0x03, 0xAA, 0x80, 0x72, 0x94, 0x94, 0x93, 0x69, 0x01, 0x95, 0x30, 0xA0, - 0xD9, 0x44, 0x03, 0x54, 0xD2, 0x95, 0xB6, 0x84, 0xE5, 0xA2, 0x14, 0xC3, - 0x53, 0x38, 0x14, 0x93, 0x48, 0x88, 0x51, 0x32, 0xA6, 0xE2, 0xA1, 0x25, - 0x14, 0x2D, 0x09, 0xA1, 0x49, 0x24, 0x90, 0xC6, 0x12, 0x52, 0x84, 0xD0, - 0x92, 0x94, 0x92, 0x49, 0xD2, 0x52, 0xE1, 0x38, 0x4C, 0x14, 0xE1, 0x04, - 0xAC, 0xA4, 0x1C, 0xA3, 0x09, 0x88, 0x29, 0x29, 0x30, 0x72, 0x89, 0xD5, - 0x40, 0x27, 0xDC, 0x61, 0x2A, 0x4D, 0xAC, 0xE0, 0x50, 0xD4, 0x89, 0x51, - 0x21, 0x14, 0x15, 0x12, 0x98, 0x3B, 0x54, 0x93, 0x42, 0x48, 0x65, 0x25, - 0x29, 0x0A, 0x24, 0x25, 0x09, 0x29, 0x96, 0xE0, 0xA2, 0x4C, 0xA6, 0x84, - 0xA1, 0x14, 0x32, 0x07, 0x44, 0x89, 0x50, 0xE1, 0x22, 0xE2, 0x92, 0xAD, - 0x9B, 0x5C, 0x9C, 0xBA, 0x50, 0xC3, 0x92, 0x2F, 0x09, 0x2A, 0xD2, 0x6E, - 0x29, 0x7A, 0x87, 0xC5, 0x0B, 0x7A, 0x60, 0x65, 0x2A, 0x55, 0xA4, 0x2F, - 0x25, 0x29, 0x51, 0x0A, 0x40, 0x68, 0x92, 0x99, 0x02, 0xA6, 0x10, 0x82, - 0x90, 0x28, 0x25, 0x28, 0x29, 0x4A, 0x80, 0x29, 0xC3, 0x90, 0x4B, 0x39, - 0x4F, 0x2A, 0x12, 0x94, 0xA4, 0xA6, 0x72, 0x9E, 0x50, 0xE5, 0x36, 0xE4, - 0x95, 0x69, 0x66, 0x12, 0x0F, 0x42, 0xDC, 0x53, 0x17, 0x25, 0x4A, 0xB4, - 0xA5, 0xFA, 0xA7, 0x0F, 0xF1, 0x55, 0xF7, 0xC1, 0x4B, 0xD5, 0x08, 0xD2, - 0xAD, 0xB4, 0x1E, 0xA5, 0xBD, 0x55, 0x6D, 0xA1, 0x4C, 0x58, 0x10, 0xA4, - 0xF1, 0x36, 0x37, 0x26, 0xDC, 0x84, 0x2C, 0x52, 0x2E, 0x04, 0x21, 0x49, - 0xB5, 0xDC, 0xF8, 0x4D, 0xBE, 0x50, 0xDC, 0xE2, 0x9A, 0x7C, 0x51, 0xA4, - 0x5B, 0x32, 0x65, 0x32, 0x81, 0x78, 0x0A, 0x2E, 0xB2, 0x78, 0x4A, 0x91, - 0x69, 0xC3, 0x82, 0x77, 0x3F, 0x45, 0x5C, 0x3D, 0x27, 0x5B, 0x09, 0x52, - 0xAD, 0x9E, 0xED, 0x52, 0x55, 0xFD, 0x5D, 0x52, 0x46, 0x91, 0xC4, 0xFF, - 0x00, 0xFF, 0xD6, 0xE8, 0x35, 0x52, 0x82, 0xA4, 0x1A, 0xA5, 0xB6, 0x15, - 0xDB, 0x73, 0xE9, 0x88, 0x0A, 0x40, 0x29, 0x00, 0x13, 0xC0, 0x4A, 0xD3, - 0x4B, 0x00, 0xA6, 0xD0, 0x98, 0x27, 0x0E, 0x01, 0x04, 0xA7, 0xAC, 0x0E, - 0xE8, 0x82, 0x15, 0x60, 0xF8, 0x4B, 0xD5, 0x84, 0xDA, 0x5D, 0x6D, 0xA2, - 0xE0, 0xA2, 0xE7, 0x20, 0x8B, 0x27, 0x95, 0x17, 0x58, 0x95, 0x26, 0xD9, - 0xB9, 0xC1, 0x46, 0x50, 0xF7, 0xEA, 0x9C, 0x39, 0x1A, 0x5B, 0x6C, 0xD2, - 0x4D, 0x29, 0xC2, 0x49, 0x5E, 0x13, 0x27, 0x4C, 0x92, 0x96, 0x4E, 0x92, - 0x50, 0x92, 0x17, 0x05, 0x48, 0x15, 0x10, 0x9C, 0x20, 0x96, 0x69, 0x68, - 0xA3, 0x29, 0xD2, 0x4A, 0x88, 0x4C, 0x94, 0xA6, 0x2E, 0x49, 0x0A, 0x85, - 0x12, 0x96, 0xE4, 0xB7, 0x22, 0xA5, 0x42, 0x50, 0x94, 0xA4, 0x92, 0x95, - 0x0A, 0x3A, 0x27, 0x24, 0x26, 0x90, 0x92, 0x14, 0x91, 0x4B, 0x44, 0x8C, - 0x24, 0xA6, 0x25, 0x0D, 0xC7, 0xC1, 0x4D, 0xCA, 0x05, 0x15, 0xA5, 0x69, - 0x4A, 0x0A, 0x62, 0x9C, 0x14, 0x54, 0xBC, 0x14, 0x80, 0x84, 0xF3, 0x09, - 0x72, 0x92, 0x95, 0x29, 0xF7, 0x15, 0x12, 0x13, 0x80, 0x92, 0x99, 0x02, - 0xA4, 0x10, 0xD4, 0x9A, 0x82, 0x43, 0x30, 0x53, 0x82, 0xA2, 0x9A, 0x52, - 0x4A, 0x49, 0x4C, 0x1C, 0xA3, 0x29, 0xA6, 0x10, 0x55, 0xA5, 0x2A, 0x24, - 0xA8, 0xEE, 0x4B, 0x70, 0x49, 0x4B, 0xEE, 0x51, 0x2E, 0x29, 0x12, 0x14, - 0x09, 0x45, 0x05, 0x72, 0xE5, 0x12, 0x53, 0xCA, 0x6E, 0xE9, 0x21, 0x40, - 0x90, 0x54, 0xDA, 0xE2, 0xA3, 0xB7, 0x45, 0x26, 0x88, 0x49, 0x4C, 0xC3, - 0x93, 0xEF, 0x3E, 0x28, 0x4E, 0x74, 0x28, 0x1B, 0x09, 0xE1, 0x2A, 0x4D, - 0xB6, 0x0B, 0xC7, 0x8A, 0x6D, 0xE3, 0xB2, 0xAF, 0x2E, 0x3C, 0xA9, 0x00, - 0x52, 0xA4, 0x5A, 0x57, 0x3A, 0x54, 0x0A, 0x61, 0x29, 0x14, 0x94, 0xAD, - 0xCA, 0x0E, 0x24, 0xA7, 0x2A, 0x3A, 0xA2, 0x86, 0x3E, 0xE9, 0x49, 0x4D, - 0x24, 0x6D, 0x54, 0xFF, 0x00, 0xFF, 0xD7, 0xEA, 0x76, 0x27, 0xD8, 0x8A, - 0x18, 0xA5, 0xB3, 0x45, 0x6E, 0xDA, 0x54, 0x80, 0x35, 0x3C, 0x22, 0x6C, - 0x4B, 0x6A, 0x56, 0xAA, 0x44, 0x42, 0x81, 0x06, 0x55, 0x80, 0xC9, 0x48, - 0xD4, 0x07, 0x64, 0xAD, 0x54, 0x80, 0x07, 0x14, 0xFB, 0x61, 0x17, 0x6C, - 0x28, 0xBA, 0x51, 0xB5, 0x53, 0x0E, 0xC9, 0xB5, 0x52, 0x2C, 0x29, 0xC3, - 0x60, 0x24, 0x8A, 0x47, 0x05, 0x4C, 0x04, 0xA3, 0x55, 0x20, 0x92, 0xA9, - 0x93, 0x53, 0xA6, 0x09, 0x1D, 0x10, 0x5C, 0xA2, 0xA3, 0x25, 0x24, 0xE9, - 0x21, 0x70, 0x9E, 0x13, 0x04, 0xF2, 0x92, 0x57, 0x49, 0x34, 0xA5, 0x28, - 0x29, 0x92, 0x52, 0xA1, 0xB9, 0x2D, 0xC9, 0x52, 0x99, 0x12, 0xA0, 0xE2, - 0x98, 0x95, 0x12, 0x51, 0xA4, 0x12, 0xBC, 0xA5, 0xB9, 0x42, 0x4A, 0x70, - 0x8A, 0x2D, 0x98, 0x29, 0xC9, 0x51, 0x4C, 0x4A, 0x49, 0x51, 0x70, 0x4D, - 0xB9, 0x46, 0x53, 0x4A, 0x48, 0xB6, 0x5B, 0xD3, 0xEE, 0x42, 0x25, 0x29, - 0xD1, 0x14, 0x5B, 0x32, 0x65, 0x44, 0x94, 0xC4, 0x94, 0xDA, 0xA4, 0xA5, - 0x12, 0x9D, 0xAE, 0x95, 0x02, 0x13, 0xB5, 0x24, 0x24, 0x29, 0x00, 0x9B, - 0x54, 0xFA, 0xC2, 0x49, 0x52, 0x79, 0x51, 0x82, 0x90, 0x09, 0x29, 0x79, - 0x52, 0x06, 0x14, 0x53, 0xA4, 0xA5, 0xF7, 0x25, 0x2A, 0x25, 0xC9, 0x20, - 0xA6, 0x41, 0xD0, 0x9C, 0xBC, 0x76, 0x43, 0x77, 0x0A, 0x32, 0x95, 0x2A, - 0xD2, 0x6E, 0x4E, 0x20, 0xA1, 0x84, 0xB7, 0x24, 0xAB, 0x48, 0x48, 0x09, - 0xB4, 0x2A, 0x32, 0x94, 0xA4, 0xA6, 0x49, 0x0F, 0x34, 0xC1, 0x49, 0x24, - 0xAE, 0x9E, 0x54, 0x64, 0xA4, 0x64, 0xA4, 0xA5, 0x39, 0xBD, 0xD0, 0xC8, - 0x85, 0x32, 0x0A, 0x6D, 0xA5, 0x24, 0x10, 0xC4, 0x29, 0xB5, 0x20, 0xD5, - 0x36, 0x35, 0x25, 0x00, 0xB6, 0xD4, 0xE1, 0x88, 0x80, 0x29, 0x86, 0xA1, - 0x6B, 0xA9, 0x07, 0xA4, 0x9F, 0xD3, 0x01, 0x1A, 0x13, 0x16, 0xCA, 0x56, - 0xAA, 0x43, 0xB4, 0x4A, 0x48, 0x9B, 0x12, 0x4A, 0xD5, 0x4F, 0xFF, 0xD0, - 0xED, 0x8B, 0x52, 0x0C, 0x48, 0xA7, 0x69, 0x56, 0x5A, 0xAB, 0x8A, 0xD2, - 0x35, 0x85, 0x30, 0xE4, 0xCE, 0x72, 0x09, 0x47, 0xB4, 0x04, 0xA1, 0x39, - 0x29, 0xB7, 0x14, 0x50, 0xC1, 0xC0, 0x28, 0x96, 0xA2, 0x19, 0x29, 0x6D, - 0x29, 0x5A, 0x29, 0x09, 0x61, 0x4B, 0x69, 0xEE, 0x8D, 0xB1, 0x36, 0xC4, - 0x6D, 0x54, 0x84, 0xB5, 0x3C, 0x04, 0x5D, 0x85, 0x37, 0xA6, 0x95, 0xAA, - 0x91, 0x41, 0x4B, 0x69, 0x46, 0x0C, 0x4F, 0xB5, 0x2B, 0x55, 0x21, 0xDA, - 0x52, 0xDA, 0x8D, 0xB5, 0x2D, 0xA9, 0x5A, 0xA9, 0x0E, 0xD4, 0xD0, 0x51, - 0x8B, 0x53, 0x40, 0x4A, 0xD5, 0x48, 0xA0, 0xA5, 0x05, 0x13, 0x6A, 0x50, - 0x95, 0xA2, 0x91, 0x42, 0x62, 0x11, 0x4B, 0x53, 0x10, 0x8D, 0xAA, 0x91, - 0x96, 0xA6, 0xDA, 0xA6, 0x54, 0x4A, 0x48, 0x62, 0x42, 0x8C, 0xA9, 0x39, - 0x40, 0x84, 0x50, 0x57, 0xDC, 0x9A, 0x54, 0x53, 0xF0, 0x92, 0x14, 0x99, - 0x4B, 0x94, 0xD0, 0x92, 0x98, 0x99, 0x4D, 0x05, 0x4A, 0x14, 0xA1, 0x1B, - 0x53, 0x00, 0xDF, 0x14, 0xA0, 0xA9, 0x42, 0x45, 0x2B, 0x53, 0x08, 0x4A, - 0x13, 0x92, 0x13, 0x84, 0x94, 0xC7, 0x50, 0xA4, 0x25, 0x38, 0x0A, 0x40, - 0x04, 0x95, 0x4B, 0x76, 0x4C, 0xA4, 0x79, 0x4D, 0xDD, 0x05, 0x2B, 0x6A, - 0x7D, 0xBA, 0x25, 0xB8, 0xA7, 0x0E, 0x49, 0x28, 0xF6, 0x92, 0x54, 0xB6, - 0xE8, 0x88, 0x1A, 0x0A, 0x62, 0xD0, 0x95, 0xAA, 0x90, 0xBA, 0x41, 0x4D, - 0x05, 0x14, 0xB5, 0x47, 0x6A, 0x36, 0x8A, 0x61, 0x05, 0x48, 0x35, 0x48, - 0x35, 0x3C, 0x21, 0x6A, 0xA6, 0x10, 0x52, 0xDA, 0x89, 0xB5, 0x23, 0x09, - 0x5A, 0x69, 0x88, 0x10, 0x9C, 0x04, 0x8A, 0x70, 0xE4, 0x94, 0xA8, 0x52, - 0x01, 0x30, 0x29, 0xD0, 0x4A, 0x93, 0x42, 0x74, 0xE1, 0x25, 0x28, 0x35, - 0x38, 0x09, 0xC0, 0x4E, 0x02, 0x16, 0x95, 0xDA, 0x11, 0x00, 0x4C, 0x14, - 0x82, 0x09, 0x5B, 0x6A, 0x70, 0xD9, 0x4E, 0x13, 0xA4, 0x9A, 0x5B, 0xD3, - 0x09, 0x27, 0x49, 0x25, 0x3F, 0xFF, 0xD1, 0xED, 0xE1, 0x34, 0x29, 0xC2, - 0x50, 0xAC, 0x35, 0x98, 0xA6, 0x32, 0xA5, 0x09, 0x6D, 0x94, 0x94, 0xC5, - 0x3C, 0x27, 0x0D, 0x4F, 0x09, 0x29, 0x68, 0x4F, 0x09, 0xE1, 0x3C, 0x24, - 0xA6, 0x30, 0x94, 0x29, 0x42, 0x78, 0x41, 0x2C, 0x21, 0x28, 0x53, 0x84, - 0xA1, 0x25, 0x30, 0x84, 0xA1, 0x4E, 0x13, 0x42, 0x4A, 0x63, 0x09, 0x88, - 0x53, 0x85, 0x12, 0x8A, 0x18, 0x90, 0x9A, 0x14, 0x92, 0x84, 0x94, 0xC2, - 0x12, 0x85, 0x38, 0x4C, 0x42, 0x36, 0x8A, 0x60, 0x42, 0x81, 0x45, 0x20, - 0xA8, 0x16, 0xA4, 0x82, 0x89, 0xC5, 0x40, 0xCA, 0x29, 0x6A, 0x8E, 0xD4, - 0xE4, 0x23, 0x32, 0xA0, 0x8E, 0x6B, 0x94, 0xBD, 0x24, 0xAD, 0x14, 0x82, - 0x13, 0xC2, 0x21, 0xA8, 0xA5, 0xB0, 0x84, 0x6D, 0x54, 0xC1, 0x25, 0x2D, - 0xA5, 0x2D, 0xA5, 0x05, 0x53, 0x08, 0x4C, 0x53, 0xB9, 0x44, 0x82, 0x8A, - 0x16, 0x94, 0xC4, 0xA7, 0xD5, 0x30, 0xD4, 0xA4, 0x85, 0xBB, 0xA9, 0xB4, - 0x26, 0xD8, 0xA4, 0x02, 0x49, 0x01, 0x96, 0x89, 0xC0, 0x94, 0xC1, 0x15, - 0xA0, 0x42, 0x09, 0x46, 0x5A, 0x9A, 0x11, 0x88, 0x09, 0xA0, 0x25, 0x6A, - 0xA4, 0x50, 0x9C, 0x22, 0x16, 0xA4, 0x18, 0x95, 0xAA, 0x98, 0x04, 0xFA, - 0x22, 0x6C, 0x01, 0x2D, 0xA0, 0xA5, 0x69, 0xA4, 0x70, 0x91, 0x03, 0xB2, - 0x9E, 0xC0, 0x13, 0x7B, 0x52, 0xB5, 0x52, 0x38, 0x29, 0x00, 0x42, 0x9C, - 0x6A, 0x9C, 0x35, 0x2B, 0x55, 0x30, 0x84, 0xC4, 0x22, 0x90, 0x02, 0x83, - 0x92, 0x53, 0x08, 0x4D, 0x21, 0x3C, 0x4A, 0x6D, 0x85, 0x14, 0x2E, 0x0A, - 0x70, 0xE4, 0xC1, 0xA9, 0xE1, 0x05, 0x32, 0x04, 0x27, 0x0A, 0x09, 0xC2, - 0x49, 0x66, 0x9C, 0x28, 0xA9, 0x09, 0x41, 0x4C, 0x81, 0x52, 0x0A, 0x20, - 0x29, 0x80, 0x82, 0x59, 0x04, 0xE9, 0x00, 0x9D, 0x05, 0xCB, 0x24, 0xA4, - 0x92, 0x4A, 0x7F, 0xFF, 0xD2, 0xEE, 0xA1, 0x3C, 0x24, 0x9D, 0x4E, 0xD7, - 0x63, 0x09, 0xE1, 0x4A, 0x12, 0xDA, 0x92, 0x96, 0x84, 0xA1, 0x4A, 0x02, - 0x50, 0x92, 0x96, 0x84, 0xA1, 0x4A, 0x12, 0x49, 0x4B, 0x42, 0x50, 0xA4, - 0x99, 0x25, 0x2D, 0x09, 0x42, 0x74, 0x92, 0x4A, 0xD0, 0x9A, 0x13, 0xA6, - 0x29, 0x21, 0x64, 0xC4, 0x27, 0x4C, 0x92, 0x96, 0x84, 0xA1, 0x3C, 0x24, - 0x92, 0x96, 0x84, 0xA1, 0x3A, 0x49, 0x29, 0x89, 0x0A, 0x24, 0x29, 0xA4, - 0x8A, 0x11, 0x16, 0xA8, 0x46, 0xA8, 0xC4, 0x26, 0x2D, 0x4A, 0xD1, 0x4C, - 0x02, 0x4A, 0x61, 0xA9, 0x10, 0x8D, 0xAA, 0x98, 0x18, 0x43, 0x25, 0x14, - 0xB1, 0x0C, 0xB7, 0x54, 0x90, 0x56, 0x4C, 0xE5, 0x3D, 0xAA, 0x2E, 0x6A, - 0x2A, 0xA4, 0x25, 0xA2, 0x53, 0x86, 0x4A, 0x91, 0x69, 0x4E, 0xD0, 0x51, - 0xB4, 0x52, 0x33, 0x5A, 0x6D, 0xA0, 0x23, 0x98, 0x50, 0x2D, 0x4A, 0xD5, - 0x4C, 0x04, 0x15, 0x20, 0xC0, 0x9F, 0x6A, 0x90, 0x1A, 0x21, 0x6A, 0xA6, - 0x21, 0x9D, 0xD4, 0xA0, 0x24, 0x02, 0x78, 0x29, 0x25, 0x6D, 0x52, 0x82, - 0xA7, 0xAA, 0x89, 0x3E, 0x29, 0x29, 0x40, 0x88, 0xD5, 0x48, 0x42, 0x82, - 0x40, 0x84, 0x94, 0xCD, 0xDC, 0x28, 0x14, 0xF3, 0x29, 0x8A, 0x4A, 0x5C, - 0x04, 0xC5, 0xA5, 0x2D, 0xC9, 0xC3, 0xA5, 0x25, 0x2C, 0x34, 0x52, 0x05, - 0x44, 0xA6, 0x0E, 0x01, 0x25, 0x33, 0x21, 0x47, 0x68, 0x4E, 0x5C, 0x90, - 0x72, 0x4A, 0x5B, 0x60, 0x4C, 0x5A, 0xA6, 0x0A, 0x72, 0x92, 0x90, 0xED, - 0x48, 0xB6, 0x78, 0x46, 0x00, 0x14, 0xB6, 0x78, 0x25, 0x6A, 0xA4, 0x3B, - 0x4A, 0x70, 0xD4, 0x6F, 0x4C, 0xA7, 0x15, 0xC2, 0x56, 0xAA, 0x42, 0x02, - 0x90, 0x08, 0x9B, 0x12, 0xD8, 0x85, 0xAA, 0x96, 0x01, 0x4C, 0x26, 0x01, - 0x4F, 0x6A, 0x45, 0x21, 0x70, 0x9E, 0x12, 0x01, 0x3A, 0x09, 0x5A, 0x12, - 0x4E, 0x92, 0x4A, 0x7F, 0xFF, 0xD3, 0xEF, 0x13, 0x84, 0xF0, 0x94, 0x29, - 0xDA, 0xEB, 0xA4, 0x92, 0x78, 0x41, 0x2C, 0x75, 0x4E, 0x14, 0xA1, 0x28, - 0x49, 0x4B, 0x42, 0x50, 0xA5, 0x09, 0x42, 0x4A, 0x62, 0x92, 0x94, 0x25, - 0x09, 0x29, 0x8C, 0x25, 0x0A, 0x50, 0x9A, 0x12, 0x53, 0x14, 0xD0, 0xA7, - 0x09, 0xA1, 0x25, 0x31, 0x84, 0xA1, 0x3C, 0x24, 0x8A, 0x98, 0x90, 0x99, - 0x48, 0xA6, 0x21, 0x24, 0x31, 0x49, 0x3A, 0x64, 0x94, 0xA8, 0x4A, 0x12, - 0x49, 0x25, 0x2D, 0x09, 0xA1, 0x3A, 0x49, 0x29, 0x68, 0x29, 0x27, 0x49, - 0x25, 0x31, 0x2A, 0x24, 0x05, 0x22, 0x98, 0xA2, 0x86, 0x30, 0x14, 0x0A, - 0x99, 0x09, 0xA1, 0x24, 0x23, 0xD5, 0x38, 0x4E, 0x5A, 0x98, 0x84, 0x50, - 0xA4, 0xE1, 0xA1, 0x47, 0x55, 0x20, 0xE4, 0x94, 0xAD, 0x81, 0x3E, 0xC4, - 0xDB, 0x94, 0x83, 0xA7, 0x94, 0x92, 0xAD, 0xA0, 0x25, 0xB4, 0x29, 0x88, - 0x29, 0x10, 0x85, 0xAA, 0x98, 0x91, 0xA2, 0x19, 0x6E, 0xA8, 0x84, 0x21, - 0x94, 0x42, 0x8B, 0x12, 0x9A, 0x13, 0x94, 0xD0, 0x8A, 0x15, 0xAA, 0x7D, - 0x53, 0x80, 0x9D, 0x05, 0x31, 0xDA, 0x98, 0x68, 0xA6, 0x94, 0x24, 0xA6, - 0x04, 0xCA, 0x50, 0xA7, 0x09, 0x42, 0x4A, 0xA6, 0x29, 0xE0, 0x29, 0x6D, - 0x4A, 0x12, 0x55, 0x28, 0x37, 0xC1, 0x39, 0x6A, 0x76, 0x88, 0x52, 0x29, - 0x26, 0x98, 0xB5, 0xA8, 0xCD, 0x68, 0x50, 0x10, 0x14, 0xA5, 0x02, 0x95, - 0xC8, 0x01, 0x31, 0x12, 0x90, 0xD5, 0x3A, 0x0A, 0x5A, 0x13, 0x16, 0xA9, - 0x29, 0x00, 0x8A, 0x98, 0x06, 0xA9, 0x84, 0xB6, 0xA7, 0x01, 0x04, 0xAC, - 0x92, 0x94, 0x25, 0x09, 0x29, 0x8A, 0x4A, 0x50, 0x92, 0x4A, 0x7F, 0xFF, - 0xD4, 0xF4, 0x08, 0x4A, 0x13, 0xA4, 0xA6, 0x60, 0x52, 0x74, 0xC9, 0xD2, - 0x52, 0x93, 0xA4, 0x92, 0x49, 0x52, 0x49, 0x27, 0x49, 0x4B, 0x25, 0x09, - 0xD2, 0x49, 0x4B, 0x24, 0x9E, 0x12, 0x84, 0x94, 0xC5, 0x32, 0x92, 0x64, - 0x94, 0xC5, 0x24, 0xF0, 0x98, 0xA4, 0x85, 0x8A, 0x64, 0xE5, 0x32, 0x4A, - 0x58, 0xA6, 0x4E, 0x98, 0xA2, 0x85, 0x92, 0x4E, 0x92, 0x4A, 0x5A, 0x12, - 0x4E, 0x99, 0x25, 0x29, 0x28, 0x49, 0x24, 0x94, 0xB1, 0x0A, 0x24, 0x29, - 0x14, 0xC9, 0x29, 0x89, 0x09, 0x93, 0x94, 0xC5, 0x14, 0x2C, 0x42, 0x62, - 0x13, 0xA4, 0x92, 0x98, 0x42, 0x50, 0x14, 0x8A, 0x8A, 0x28, 0x5A, 0x13, - 0x84, 0x93, 0x84, 0x94, 0xCC, 0x29, 0x21, 0x82, 0x53, 0xCA, 0x09, 0x5C, - 0x85, 0x02, 0x14, 0xE5, 0x44, 0xA4, 0xA6, 0x10, 0x94, 0x29, 0x27, 0x80, - 0x8A, 0x18, 0x42, 0x74, 0xF0, 0x94, 0x24, 0xA5, 0xA1, 0x3A, 0x74, 0x90, - 0x52, 0xD0, 0x9C, 0x04, 0xE9, 0x42, 0x49, 0x54, 0x25, 0x09, 0xE1, 0x3C, - 0x24, 0xA6, 0x30, 0x9C, 0x05, 0x28, 0x09, 0xE1, 0x25, 0x2D, 0x09, 0xE1, - 0x3C, 0x27, 0x84, 0x12, 0xC6, 0x13, 0xC4, 0x27, 0x80, 0x92, 0x4A, 0x50, - 0x52, 0x10, 0x99, 0x3A, 0x4A, 0x5D, 0x3A, 0x41, 0x3A, 0x09, 0x54, 0x25, - 0x09, 0x27, 0x49, 0x4B, 0x42, 0x49, 0xE1, 0x24, 0x94, 0xFF, 0x00, 0xFF, - 0xD5, 0xF4, 0x14, 0x93, 0x95, 0x12, 0xA6, 0x60, 0x5D, 0x3A, 0x8C, 0xA7, - 0x49, 0x4C, 0x93, 0xA8, 0x85, 0x20, 0x92, 0x54, 0x9E, 0x13, 0xC2, 0x74, - 0x14, 0xB4, 0x25, 0x09, 0xE1, 0x24, 0x94, 0xC5, 0x22, 0x9D, 0x24, 0x94, - 0xC5, 0x34, 0x29, 0x42, 0x68, 0x45, 0x4C, 0x61, 0x31, 0x52, 0x29, 0x8A, - 0x4A, 0x62, 0x98, 0xA9, 0x14, 0xC5, 0x24, 0x30, 0x4C, 0xA4, 0x54, 0x4A, - 0x28, 0x52, 0x49, 0x26, 0x49, 0x4B, 0xA6, 0x49, 0x24, 0x94, 0xA4, 0x92, - 0x4D, 0x29, 0x29, 0x4A, 0x25, 0x39, 0x4C, 0x92, 0x16, 0x29, 0x92, 0x49, - 0x15, 0x2C, 0x92, 0x49, 0x24, 0xA5, 0x93, 0x42, 0x92, 0x64, 0x94, 0xB2, - 0x49, 0x14, 0x92, 0x42, 0xE9, 0x26, 0x4E, 0x92, 0x94, 0x92, 0x49, 0x24, - 0x95, 0x92, 0x49, 0x24, 0x90, 0xA4, 0xE9, 0x92, 0x45, 0x4B, 0xA7, 0x4C, - 0x92, 0x0A, 0x5D, 0x3A, 0x64, 0xE9, 0x25, 0x70, 0x9D, 0x32, 0x74, 0x94, - 0xB8, 0x53, 0xD1, 0x0C, 0x29, 0x02, 0x82, 0x59, 0x82, 0x12, 0x30, 0xA0, - 0x13, 0xA4, 0xA5, 0xD2, 0x49, 0x24, 0x94, 0xA0, 0x9D, 0x20, 0xA4, 0x92, - 0x94, 0x13, 0x84, 0xA1, 0x3C, 0x20, 0x95, 0x24, 0x94, 0x27, 0x49, 0x4B, - 0x24, 0x9D, 0x24, 0x92, 0xFF, 0x00, 0xFF, 0xD6, 0xF4, 0x24, 0xC5, 0x7C, - 0xD2, 0x92, 0x99, 0x81, 0xFA, 0x55, 0x20, 0xBE, 0x6A, 0x49, 0x25, 0x3F, - 0x4B, 0x85, 0x31, 0x0B, 0xE6, 0x54, 0x92, 0x4B, 0xF4, 0xE0, 0x4E, 0xBE, - 0x62, 0x49, 0x04, 0xBF, 0x4E, 0xA4, 0xBE, 0x62, 0x49, 0x25, 0x3F, 0x4E, - 0x24, 0xBE, 0x63, 0x49, 0x24, 0x3F, 0x4D, 0xA6, 0x2B, 0xE6, 0x54, 0x92, - 0x53, 0xF4, 0xC9, 0x4C, 0x57, 0xCC, 0xE9, 0x22, 0xA7, 0xE9, 0x62, 0x98, - 0xAF, 0x9A, 0x92, 0x49, 0x0F, 0xD2, 0x65, 0x31, 0x5F, 0x36, 0xA4, 0x8A, - 0x1F, 0xA4, 0x12, 0x5F, 0x37, 0xA4, 0x92, 0x9F, 0xA4, 0x0A, 0x45, 0x7C, - 0xDE, 0x92, 0x4A, 0x7E, 0x8F, 0x4C, 0xBE, 0x71, 0x49, 0x24, 0x3F, 0x46, - 0x94, 0xC5, 0x7C, 0xE6, 0x92, 0x2A, 0x7E, 0x8B, 0x49, 0x7C, 0xE8, 0x92, - 0x4A, 0x7E, 0x8A, 0x4E, 0xBE, 0x74, 0x49, 0x25, 0x3F, 0x45, 0x26, 0x5F, - 0x3B, 0x24, 0x92, 0x1F, 0xA2, 0x53, 0x2F, 0x9D, 0xD2, 0x49, 0x4F, 0xD1, - 0x09, 0xD7, 0xCE, 0xC9, 0x22, 0xA7, 0xE8, 0x94, 0x97, 0xCE, 0xC9, 0x20, - 0x97, 0xE8, 0x84, 0x97, 0xCE, 0xE9, 0x24, 0x87, 0xE8, 0x84, 0x97, 0xCE, - 0xE9, 0x22, 0xA7, 0xE8, 0x94, 0xEB, 0xE7, 0x54, 0x90, 0x53, 0xF4, 0x52, - 0x75, 0xF3, 0xA2, 0x49, 0x25, 0xFA, 0x31, 0x3A, 0xF9, 0xC9, 0x24, 0x94, - 0xFD, 0x1C, 0x90, 0x5F, 0x38, 0xA4, 0x92, 0x9F, 0xA3, 0xC2, 0x92, 0xF9, - 0xB9, 0x24, 0x12, 0xFD, 0x22, 0x9D, 0x7C, 0xDA, 0x92, 0x4A, 0x7E, 0x93, - 0x0A, 0x41, 0x7C, 0xD4, 0x92, 0x09, 0x7E, 0x96, 0x4E, 0xBE, 0x68, 0x49, - 0x25, 0x3F, 0x4B, 0xA4, 0xBE, 0x68, 0x49, 0x24, 0xBF, 0x4B, 0xA4, 0xBE, - 0x68, 0x49, 0x25, 0x3F, 0xFF, 0xD9, -}; - -#define IMAGE_LENGTH 0x000049F2 - -char * get_clouds(int * Len) -{ - unsigned char * ptr; - - ptr = malloc(IMAGE_LENGTH); - memcpy(ptr, Clouds, IMAGE_LENGTH); - *Len = IMAGE_LENGTH; - - return ptr; -} - -char * get_ais_blue(int * Len) -{ - unsigned char * ptr; - - ptr = malloc(aisblue_png_len); - memcpy(ptr, aisblue_png, aisblue_png_len); - *Len = IMAGE_LENGTH; - - return ptr; -} - -char * get_ais_navaid(int * Len) -{ - unsigned char * ptr; - - ptr = malloc(aisnavaid_png_len); - memcpy(ptr, aisnavaid_png, aisnavaid_png_len); - *Len = aisnavaid_png_len; - - return ptr; -} - -char * get_ais_green(int * Len) -{ - unsigned char * ptr; - - ptr = malloc(aisgreen_png_len); - memcpy(ptr, aisgreen_png, aisgreen_png_len); - *Len = aisgreen_png_len; - - return ptr; -} - -char * get_ais_red(int * Len) -{ - unsigned char * ptr; - - ptr = malloc(aisred_png_len); - memcpy(ptr, aisred_png, aisred_png_len); - *Len = aisred_png_len; - - return ptr; -} - -char * get_ais_white(int * Len) -{ - unsigned char * ptr; - - ptr = malloc(aiswhite_png_len); - memcpy(ptr, aiswhite_png, aiswhite_png_len); - *Len = aiswhite_png_len; - - return ptr; -} - -char * get_ais_trans(int * Len) -{ - unsigned char * ptr; - - ptr = malloc(aistrans_png_len); - memcpy(ptr, aistrans_png, aistrans_png_len); - *Len = aistrans_png_len; - - return ptr; -} - - -char * get_greenplane(int * Len) -{ - unsigned char * ptr; - - ptr = malloc(greenplane_png_len); - memcpy(ptr, greenplane_png, greenplane_png_len); - *Len = greenplane_png_len; - - return ptr; -} - -char * get_yellowplane(int * Len) -{ - unsigned char * ptr; - - ptr = malloc(yellowplane_png_len); - memcpy(ptr, yellowplane_png, yellowplane_png_len); - *Len = yellowplane_png_len; - - return ptr; -} - -char * get_helicopter(int * Len) -{ - unsigned char * ptr; - - ptr = malloc(helicopter_png_len); - memcpy(ptr, helicopter_png, helicopter_png_len); - *Len = helicopter_png_len; - - return ptr; -} - - -char * get_plane(int * Len) -{ - unsigned char * ptr; - - ptr = malloc(plane_png_len); - memcpy(ptr, plane_png, plane_png_len); - *Len = plane_png_len; - - return ptr; -} - - - - -char * get_aprs() -{ - char Msg[] = - -"\n" -"\n" -"\n" -"\n" -"\n" -"\n" -"G8BPQ APRS Display\n" -"\n" - -"\n" -"\n" - - -//"\n" -//"\n" -"\n" -"\n" -"\n" -"\n" -" \n" -"\n" -"\n" -"\n" -"\n" -"\n" -"
\n" -"\n" -""; - - - return _strdup(Msg);; -} - - -char * get_rotatedMarker() -{ - char Msg[] = - -"(function() {\n" -" // save these original methods before they are overwritten\n" -" var proto_initIcon = L.Marker.prototype._initIcon;\n" -" var proto_setPos = L.Marker.prototype._setPos;\n" -"\n" -" var oldIE = (L.DomUtil.TRANSFORM === 'msTransform');\n" -"\n" -" L.Marker.addInitHook(function () {\n" -" var iconOptions = this.options.icon && this.options.icon.options;\n" -" var iconAnchor = iconOptions && this.options.icon.options.iconAnchor;\n" -" if (iconAnchor) {\n" -" iconAnchor = (iconAnchor[0] + 'px ' + iconAnchor[1] + 'px');\n" -" }\n" -" this.options.rotationOrigin = this.options.rotationOrigin || iconAnchor || 'center bottom' ;\n" -" this.options.rotationAngle = this.options.rotationAngle || 0;\n" -"\n" -" // Ensure marker keeps rotated during dragging\n" -" this.on('drag', function(e) { e.target._applyRotation(); });\n" -" });\n" -"\n" -" L.Marker.include({\n" -" _initIcon: function() {\n" -" proto_initIcon.call(this);\n" -" },\n" -"\n" -" _setPos: function (pos) {\n" -" proto_setPos.call(this, pos);\n" -" this._applyRotation();\n" -" },\n" -"\n" -" _applyRotation: function () {\n" -" if(this.options.rotationAngle) {\n" -" this._icon.style[L.DomUtil.TRANSFORM+'Origin'] = this.options.rotationOrigin;\n" -"\n" -" if(oldIE) {\n" -" // for IE 9, use the 2D rotation\n" -" this._icon.style[L.DomUtil.TRANSFORM] = 'rotate(' + this.options.rotationAngle + 'deg)';\n" -" } else {\n" -" // for modern browsers, prefer the 3D accelerated version\n" -" this._icon.style[L.DomUtil.TRANSFORM] += ' rotateZ(' + this.options.rotationAngle + 'deg)';\n" -" }\n" -" }\n" -" },\n" -"\n" -" setRotationAngle: function(angle) {\n" -" this.options.rotationAngle = angle;\n" -" this.update();\n" -" return this;\n" -" },\n" -"\n" -" setRotationOrigin: function(origin) {\n" -" this.options.rotationOrigin = origin;\n" -" this.update();\n" -" return this;\n" -" }\n" -" });\n" -"})();"; - - - return _strdup(Msg);; -} - - - -char * GetStandardPage(char * FN, int * Len) -{ - if (_stricmp(FN, "aprs.html") == 0) - return get_aprs(); - - if (_stricmp(FN, "leaflet.rotatedMarker.js") == 0) - return get_rotatedMarker(); - - if (_stricmp(FN, "info_call.html") == 0) - return get_info_call(); - - if (_stricmp(FN, "infomobile_call.html") == 0) - return get_infomobile_call(); - - if (_stricmp(FN, "infoobj_call.html") == 0) - return get_infoobj_call(); - - if (_stricmp(FN, "infowx_call.html") == 0) - return get_infowx_call(); - - if (_stricmp(FN, "all.html") == 0) - return get_all(); - - if (_stricmp(FN, "allrf.html") == 0) - return get_allrf(); - - if (_stricmp(FN, "wxall.html") == 0) - return get_wxall(); - - if (_stricmp(FN, "wxrf.html") == 0) - return get_wxrf(); - - if (_stricmp(FN, "obj.html") == 0) - return get_obj(); - - if (_stricmp(FN, "objrf.html") == 0) - return get_objrf(); - - if (_stricmp(FN, "mobilesall.html") == 0) - return get_mobileall(); - - if (_stricmp(FN, "mobilesrf.html") == 0) - return get_mobilesrf(); - - if (_stricmp(FN, "info.html") == 0) - return get_info(); - - if (_stricmp(FN, "noinfo.html") == 0) - return get_noinfo(); - - if (_stricmp(FN, "favicion.ico") == 0) - return get_favicon(Len); - - if (_stricmp(FN, "Images/clouds.jpg") == 0) - return get_clouds(Len); - - if (_stricmp(FN, "aisnavaid.png") == 0) - return get_ais_navaid(Len); - - if (_stricmp(FN, "aisgreen.png") == 0) - return get_ais_green(Len); - - if (_stricmp(FN, "aisblue.png") == 0) - return get_ais_blue(Len); - - if (_stricmp(FN, "aisred.png") == 0) - return get_ais_red(Len); - - if (_stricmp(FN, "aistrans.png") == 0) - return get_ais_trans(Len); - - if (_stricmp(FN, "aiswhite.png") == 0) - return get_ais_white(Len); - - if (_stricmp(FN, "greenplane.png") == 0) - return get_greenplane(Len); - - if (_stricmp(FN, "yellowplane.png") == 0) - return get_yellowplane(Len); - - if (_stricmp(FN, "plane.png") == 0) - return get_plane(Len); - - if (_stricmp(FN, "helicopter.png") == 0) - return get_helicopter(Len); - - return 0; -} - diff --git a/BBSHTMLConfig.c b/BBSHTMLConfig.c index f965f27..01b05bd 100644 --- a/BBSHTMLConfig.c +++ b/BBSHTMLConfig.c @@ -398,7 +398,7 @@ int SendHeader(char * Reply, char * Key) } -void ConvertTitletoUTF8(char * Title, char * UTF8Title) +void ConvertTitletoUTF8(WebMailInfo * WebMail, char * Title, char * UTF8Title, int Len) { if (WebIsUTF8(Title, (int)strlen(Title)) == FALSE) { @@ -414,15 +414,26 @@ void ConvertTitletoUTF8(char * Title, char * UTF8Title) wlen = MultiByteToWideChar(CP_ACP, 0, Title, len, BufferW, origlen * 2); len = WideCharToMultiByte(CP_UTF8, 0, BufferW, wlen, UTF8Title, origlen * 2, NULL, NULL); #else - int left = 2 * strlen(Title); - int len = origlen; - iconv_t * icu = NULL; - - if (icu == NULL) - icu = iconv_open("UTF-8", "CP1252"); + 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 @@ -1681,6 +1692,85 @@ VOID ProcessConfUpdate(struct HTTPConnectionInfo * Session, char * MsgPtr, char HoldAt = GetMultiStringInput(input, "Hat="); HoldBID = GetMultiStringInput(input, "HBID="); + // Look for fbb style filters + + input = strstr(input, "&Action="); + + // delete old list + + while(Filters && Filters->Next) + { + FBBFilter * next = Filters->Next; + free(Filters); + Filters = next; + } + + free(Filters); + Filters = NULL; + + while (input) + { + // extract and validate before saving + + FBBFilter Filter; + FBBFilter * PFilter; + + memset(&Filter, 0, sizeof(FBBFilter)); + + Filter.Action = toupper(input[8]); + + input = strstr(input, "&Type="); + + if (Filter.Action == 'H' || Filter.Action == 'R') + { + Filter.Type = toupper(input[6]); + input = strstr(input, "&From="); + memcpy(Filter.From, &input[6], 10); + input = strstr(input, "&TO="); + strlop(Filter.From, '&'); + _strupr(Filter.From); + memcpy(Filter.TO, &input[4], 10); + input = strstr(input, "&AT="); + strlop(Filter.TO, '&'); + _strupr(Filter.TO); + memcpy(Filter.AT, &input[4], 10); + input = strstr(input, "&BID="); + strlop(Filter.AT, '&'); + _strupr(Filter.AT); + memcpy(Filter.BID, &input[5], 10); + input = strstr(input, "&MaxLen="); + strlop(Filter.BID, '&'); + _strupr(Filter.BID); + Filter.MaxLen = atoi(&input[8]); + + if (Filter.Type == '&') Filter.Type = '*'; + if (Filter.From[0] == 0) strcpy(Filter.From, "*"); + if (Filter.TO[0] == 0) strcpy(Filter.TO, "*"); + if (Filter.AT[0] == 0) strcpy(Filter.AT, "*"); + if (Filter.BID[0] == 0) strcpy(Filter.BID, "*"); + + // add to list + + PFilter = zalloc(sizeof(FBBFilter)); + + memcpy(PFilter, &Filter, sizeof(FBBFilter)); + + if (Filters == 0) + Filters = PFilter; + else + { + FBBFilter * p = Filters; + + while (p->Next) + p = p->Next; + + p->Next = PFilter; + } + } + + input = strstr(input, "&Action="); + } + SaveConfig(ConfigName); GetConfig(ConfigName); } @@ -2437,7 +2527,7 @@ VOID SendFwdDetails(struct UserInfo * User, char * Reply, int * ReplyLen, char * VOID SendConfigPage(char * Reply, int * ReplyLen, char * Key) { - int Len; + int Len, i; char HF[2048] = ""; char HT[2048] = ""; @@ -2449,6 +2539,12 @@ VOID SendConfigPage(char * Reply, int * ReplyLen, char * Key) char RB[2048] = ""; char WPTO[10000] = ""; + char FBBFilters[100000] = ""; + + + char * ptr = FBBFilters; + FBBFilter * Filter = Filters; + SetMultiStringValue(RejFrom, RF); SetMultiStringValue(RejTo, RT); SetMultiStringValue(RejAt, RA); @@ -2459,7 +2555,44 @@ VOID SendConfigPage(char * Reply, int * ReplyLen, char * Key) SetMultiStringValue(HoldBID, HB); SetMultiStringValue(SendWPAddrs, WPTO); + // set up FB style fiters + ptr += sprintf(ptr, + ""); + + while(Filter) + { + ptr += sprintf(ptr, "" + "" + "" + "" + "" + "" + "" + "", + Filter->Action, Filter->Type, Filter->From, Filter->TO, Filter->AT, Filter->BID, Filter->MaxLen); + + Filter = Filter->Next; + } + + // Add a few blank entries for input + + for (i = 0; i < 5; i++) + { + ptr += sprintf(ptr, "" + "" + "" + "" + "" + "" + "" + "", ' ', ' ', "", "", "", "", 0); + } + + ptr += sprintf(ptr, "
ActionTypeFromTo@BBSBidMax Size
"); + + Debugprintf("%d", strlen(FBBFilters)); + Len = sprintf(Reply, ConfigTemplate, BBSName, Key, Key, Key, Key, Key, Key, Key, Key, Key, BBSName, SYSOPCall, HRoute, @@ -2490,7 +2623,7 @@ VOID SendConfigPage(char * Reply, int * ReplyLen, char * Key) (SendWPType == 0) ? CHKD : UNC, (SendWPType == 1) ? CHKD : UNC, WPTO, - RF, RT, RA, RB, HF, HT, HA, HB); + RF, RT, RA, RB, HF, HT, HA, HB, FBBFilters); *ReplyLen = Len; } diff --git a/BBSUtilities.c b/BBSUtilities.c index 413a121..1d3c1f2 100644 --- a/BBSUtilities.c +++ b/BBSUtilities.c @@ -45,6 +45,7 @@ BOOL OpenMon; int reportNewMesageEvents = 0; +FBBFilter * Filters = NULL; extern struct ConsoleInfo BBSConsole; @@ -2078,10 +2079,37 @@ int CountConnectionsOnPort(int CheckPort) return Count; } +/* +REJECT.SYS (\FBB\SYSTEM). -BOOL CheckRejFilters(char * From, char * To, char * ATBBS, char * BID, char Type) + This file is in SYSTEM-directory. With this file it is possible to reject or +hold certain types or sizes of messages. + +The first letter of each valid line specifies the action : + +R = Reject : The message will not be received. +H = Hold : The message will be received but held until the sysop reviews. +L = Local Hold : Only messages created on this BBS will be held. + + # File for rejecting messages. They are rejected with N-BID: + # + # Type, from, @BBS, to, BID, maximum size: + # + # * and ? can be used as wildcards (as in MS-DOS) + # + R B TOTO ALL TATA * 0 + R B * * VENTE * 0 + R B * VENTE * * 0 + H * P1RAT * * * 0 + L B * * * * 0 + */ + + +BOOL CheckRejFilters(char * From, char * To, char * ATBBS, char * BID, char Type, int Len) { char ** Calls; + FBBFilter * p = Filters; + char ToCopy[256]; if (Type == 'B' && FilterWPBulls && _stricmp(To, "WP") == 0) return TRUE; @@ -2145,6 +2173,43 @@ BOOL CheckRejFilters(char * From, char * To, char * ATBBS, char * BID, char Type Calls++; } } + + // check fbb reject.sys type filters + + strcpy(ToCopy, To); + _strupr(ToCopy); + + while (p) + { + if (p->Action != 'R') + goto Continue; + + if (p->Type != Type && p->Type != '*') + goto Continue; + + if (wildcardcompare(From, p->From) == 0) + goto Continue; + + if (wildcardcompare(ToCopy, p->TO) == 0) + goto Continue; + + if (ATBBS) + if (wildcardcompare(ATBBS, p->AT) == 0) + goto Continue; + + if (BID) + if (wildcardcompare(BID, p->BID) == 0) + goto Continue; + + if (p->MaxLen && Len < p->MaxLen) + goto Continue; + + return TRUE; // Hold + +Continue: + p = p->Next; + } + return FALSE; // Ok to accept } @@ -2175,9 +2240,12 @@ BOOL CheckValidCall(char * From) return FALSE; } -BOOL CheckHoldFilters(char * From, char * To, char * ATBBS, char * BID) +BOOL wildcardcompare(char * Target, char * Match); + +BOOL CheckHoldFilters(struct MsgInfo * Msg, char * From, char * To, char * ATBBS, char * BID) { char ** Calls; + FBBFilter * p = Filters; if (HoldFrom && From) { @@ -2238,6 +2306,38 @@ BOOL CheckHoldFilters(char * From, char * To, char * ATBBS, char * BID) Calls++; } } + + // check fbb reject.sys type filters + + while (p) + { + if (p->Action != 'H') + goto Continue; + + if (p->Type != Msg->type && p->Type != '*') + goto Continue; + + if (wildcardcompare(Msg->from, p->From) == 0) + goto Continue; + + if (wildcardcompare(Msg->to, p->TO) == 0) + goto Continue; + + if (wildcardcompare(Msg->via, p->AT) == 0) + goto Continue; + + if (wildcardcompare(Msg->bid, p->BID) == 0) + goto Continue; + + if (p->MaxLen && Msg->length < p->MaxLen) + goto Continue; + + return TRUE; // Hold + +Continue: + p = p->Next; + } + return FALSE; // Ok to accept } @@ -5361,7 +5461,7 @@ BOOL CreateMessage(CIRCUIT * conn, char * From, char * ToCall, char * ATBBS, cha } else { - if (CheckRejFilters(From, ToCall, ATBBS, BID, MsgType)) + if (CheckRejFilters(From, ToCall, ATBBS, BID, MsgType, 0)) { if ((conn->BBSFlags & BBS)) { @@ -6169,7 +6269,7 @@ nextline: HoldReason = "Bad word in title or body"; } - if (CheckHoldFilters(Msg->from, Msg->to, Msg->via, Msg->bid)) + if (CheckHoldFilters(Msg, Msg->from, Msg->to, Msg->via, Msg->bid)) { Msg->status = 'H'; HoldReason = "Matched Hold Filters"; @@ -9441,6 +9541,9 @@ VOID SaveConfig(char * ConfigName) char Size[80]; struct BBSForwardingInfo DummyForwardingInfo; char Line[1024]; + char FBBString[8192]= ""; + FBBFilter * p = Filters; + char * ptr = FBBString; if (configSaved == 0) { @@ -9566,6 +9669,18 @@ VOID SaveConfig(char * ConfigName) SaveMultiStringValue(group, "HoldAt", HoldAt); SaveMultiStringValue(group, "HoldBID", HoldBID); + // Save FBB Filters + + while (p) + { + ptr += sprintf(ptr, "%c|%c|%s|%s|%s|%s|%d|", + p->Action, p->Type, p->From, p->TO, p->AT, p->BID, p->MaxLen); + + p = p->Next; + } + + SaveStringValue(group, "FBBFilters", FBBString); + SaveIntValue(group, "SendWP", SendWP); SaveIntValue(group, "SendWPType", SendWPType); SaveIntValue(group, "FilterWPBulls", FilterWPBulls); @@ -9964,7 +10079,8 @@ BOOL GetConfig(char * ConfigName) char Size[80]; config_setting_t *setting; const char * ptr; - + char FBBString[8192]= ""; + FBBFilter f; config_init(&cfg); /* Read the file. If there is an error, report it and exit. */ @@ -10161,6 +10277,89 @@ BOOL GetConfig(char * ConfigName) HoldAt = GetMultiStringValue(group, "HoldAt"); HoldBID = GetMultiStringValue(group, "HoldBID"); + // Get FBB Filters + + GetStringValue(group, "FBBFilters", FBBString); + + ptr = FBBString; + + // delete old list + + while(Filters && Filters->Next) + { + FBBFilter * next = Filters->Next; + free(Filters); + Filters = next; + } + + free(Filters); + Filters = NULL; + + while (ptr && ptr[0]) + { + FBBFilter * PFilter; + + f.Action = ptr[0]; + f.Type = ptr[2]; + ptr = &ptr[4]; + + memcpy(f.From, ptr, 10); + strlop(f.From, '|'); + ptr = strlop(ptr, '|'); + + memcpy(f.TO, ptr, 10); + strlop(f.TO, '|'); + ptr = strlop(ptr, '|'); + + memcpy(f.AT, ptr, 10); + strlop(f.AT, '|'); + ptr = strlop(ptr, '|'); + + memcpy(f.BID, ptr, 10); + strlop(f.BID, '|'); + ptr = strlop(ptr, '|'); + + f.MaxLen = atoi(ptr); + + // add to list + + f.Next = 0; + + PFilter = zalloc(sizeof(FBBFilter)); + + memcpy(PFilter, &f, sizeof(FBBFilter)); + + if (Filters == 0) + Filters = PFilter; + else + { + FBBFilter * p = Filters; + + while (p->Next) + p = p->Next; + + p->Next = PFilter; + } + + ptr = strlop(ptr, '|'); + } + + + + + +//f.Action, f.Type, f.From, f.TO, f.AT, f.BID, &f.MaxLen); + +/* while (p) + { + ptr += sprintf(ptr, "%c|%c|%s|%s|%s|%s|%d|", + p->Action, p->Type, p->From, p->TO, p->AT, p->BID, p->MaxLen); + + p = p->Next; + } + +*/ + // Send WP Params SendWP = GetIntValue(group, "SendWP"); diff --git a/BBSUtilities.c.bak b/BBSUtilities.c.bak deleted file mode 100644 index c5c7e48..0000000 --- a/BBSUtilities.c.bak +++ /dev/null @@ -1,14926 +0,0 @@ -/* -Copyright 2001-2018 John Wiseman G8BPQ - -This file is part of LinBPQ/BPQ32. - -LinBPQ/BPQ32 is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -LinBPQ/BPQ32 is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses -*/ - -// Mail and Chat Server for BPQ32 Packet Switch -// -// Utility Routines - -#include "bpqmail.h" -#ifdef WIN32 -#include "Winspool.h" -#else -#include -#endif - - -BOOL Bells; -BOOL FlashOnBell; // Flash instead of Beep -BOOL StripLF; - -BOOL WarnWrap; -BOOL FlashOnConnect; -BOOL WrapInput; -BOOL CloseWindowOnBye; - -RECT ConsoleRect; - -BOOL OpenConsole; -BOOL OpenMon; - -int reportNewMesageEvents = 0; - - -extern struct ConsoleInfo BBSConsole; - -extern char LOC[7]; - -//#define BBSIDLETIME 120 -//#define USERIDLETIME 300 - - -#define BBSIDLETIME 900 -#define USERIDLETIME 900 - -#ifdef LINBPQ -extern BPQVECSTRUC ** BPQHOSTVECPTR; -UCHAR * GetLogDirectory(); -DllExport int APIENTRY SessionStateNoAck(int stream, int * state); -int RefreshWebMailIndex(); -#else -__declspec(dllimport) BPQVECSTRUC ** BPQHOSTVECPTR; -typedef char * (WINAPI FAR *FARPROCZ)(); -typedef int (WINAPI FAR *FARPROCX)(); -FARPROCZ pGetLOC; -FARPROCX pRefreshWebMailIndex; - -#endif - -Dll BOOL APIENTRY APISendAPRSMessage(char * Text, char * ToCall); -VOID APIENTRY md5 (char *arg, unsigned char * checksum); -int APIENTRY GetRaw(int stream, char * msg, int * len, int * count); -void GetSemaphore(struct SEM * Semaphore, int ID); -void FreeSemaphore(struct SEM * Semaphore); -int EncryptPass(char * Pass, char * Encrypt); -VOID DecryptPass(char * Encrypt, unsigned char * Pass, unsigned int len); -void DeletetoRecycle(char * FN); -VOID DoImportCmd(CIRCUIT * conn, struct UserInfo * user, char * Arg1, char * Context); -VOID DoExportCmd(CIRCUIT * conn, struct UserInfo * user, char * Arg1, char * Context); -VOID TidyPrompts(); -char * ReadMessageFileEx(struct MsgInfo * MsgRec); -char * APIENTRY GetBPQDirectory(); -BOOL SendARQMail(CIRCUIT * conn); -int APIENTRY ChangeSessionIdletime(int Stream, int idletime); -int APIENTRY GetApplNum(int Stream); -VOID FormatTime(char * Time, time_t cTime); -BOOL CheckifPacket(char * Via); -char * APIENTRY GetVersionString(); -void ListFiles(ConnectionInfo * conn, struct UserInfo * user, char * filename); -void ReadBBSFile(ConnectionInfo * conn, struct UserInfo * user, char * filename); -int GetCMSHash(char * Challenge, char * Password); -BOOL SendAMPRSMTP(CIRCUIT * conn); -VOID ProcessMCASTLine(ConnectionInfo * conn, struct UserInfo * user, char * Buffer, int MsgLen); -VOID MCastTimer(); -VOID MCastConTimer(ConnectionInfo * conn); -int FindFreeBBSNumber(); -VOID DoSetMsgNo(CIRCUIT * conn, struct UserInfo * user, char * Arg1, char * Context); -BOOL ProcessYAPPMessage(CIRCUIT * conn); -void YAPPSendFile(ConnectionInfo * conn, struct UserInfo * user, char * filename); -void YAPPSendData(ConnectionInfo * conn); -VOID CheckBBSNumber(int i); -struct UserInfo * FindAMPR(); -VOID SaveInt64Value(config_setting_t * group, char * name, long long value); -VOID SaveIntValue(config_setting_t * group, char * name, int value); -VOID SaveStringValue(config_setting_t * group, char * name, char * value); -char *stristr (char *ch1, char *ch2); -BOOL CheckforMessagetoServer(struct MsgInfo * Msg); -void DoHousekeepingCmd(CIRCUIT * conn, struct UserInfo * user, char * Arg1, char * Context); -BOOL CheckUserMsg(struct MsgInfo * Msg, char * Call, BOOL SYSOP, BOOL IncludeKilled); -void ListCategories(ConnectionInfo * conn); -void RebuildNNTPList(); -long long GetInt64Value(config_setting_t * group, char * name); -void ProcessSyncModeMessage(CIRCUIT * conn, struct UserInfo * user, char* Buffer, int len); -int ReformatSyncMessage(CIRCUIT * conn); -char * initMultipartUnpack(char ** Input); -char * FormatSYNCMessage(CIRCUIT * conn, struct MsgInfo * Msg); -int decode_quoted_printable(char *ptr, int len); -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); - -config_t cfg; -config_setting_t * group; - -extern ULONG BBSApplMask; - -//static int SEMCLASHES = 0; - -char SecureMsg[80] = ""; // CMS Secure Signon Response - -int NumberofStreams; - -extern char VersionStringWithBuild[50]; - -#define MaxSockets 64 - -extern struct SEM OutputSEM; - -extern ConnectionInfo Connections[MaxSockets+1]; - -extern struct UserInfo ** UserRecPtr; -extern int NumberofUsers; - -extern struct UserInfo * BBSChain; // Chain of users that are BBSes - -extern struct MsgInfo ** MsgHddrPtr; -extern int NumberofMessages; - -extern int FirstMessageIndextoForward; // Lowest Message wirh a forward bit set - limits search - -extern char UserDatabaseName[MAX_PATH]; -extern char UserDatabasePath[MAX_PATH]; - -extern char MsgDatabasePath[MAX_PATH]; -extern char MsgDatabaseName[MAX_PATH]; - -extern char BIDDatabasePath[MAX_PATH]; -extern char BIDDatabaseName[MAX_PATH]; - -extern char WPDatabasePath[MAX_PATH]; -extern char WPDatabaseName[MAX_PATH]; - -extern char BadWordsPath[MAX_PATH]; -extern char BadWordsName[MAX_PATH]; - -extern char BaseDir[MAX_PATH]; -extern char BaseDirRaw[MAX_PATH]; // As set in registry - may contain %NAME% -extern char ProperBaseDir[MAX_PATH]; // BPQ Directory/BPQMailChat - - -extern char MailDir[MAX_PATH]; - -extern BIDRec ** BIDRecPtr; -extern int NumberofBIDs; - -extern BIDRec ** TempBIDRecPtr; -extern int NumberofTempBIDs; - -extern WPRec ** WPRecPtr; -extern int NumberofWPrecs; - -extern char ** BadWords; -extern int NumberofBadWords; -extern char * BadFile; - -extern int LatestMsg; -extern struct SEM MsgNoSemaphore; // For locking updates to LatestMsg -extern int HighestBBSNumber; - -extern int MaxMsgno; -extern int BidLifetime; -extern int MaxAge; -extern int MaintInterval; -extern int MaintTime; - -extern int ProgramErrors; - -extern BOOL MonBBS; -extern BOOL MonCHAT; -extern BOOL MonTCP; - -BOOL SendNewUserMessage = TRUE; -BOOL AllowAnon = FALSE; -BOOL UserCantKillT = FALSE; - -typedef int (WINAPI FAR *FARPROCX)(); -FARPROCX pRunEventProgram; - -int RunEventProgram(char * Program, char * Param); - - -extern BOOL EventsEnabled; - -#define BPQHOSTSTREAMS 64 - -// Although externally streams are numbered 1 to 64, internally offsets are 0 - 63 - -extern BPQVECSTRUC BPQHOSTVECTOR[BPQHOSTSTREAMS + 5]; - -#ifdef LINBPQ -extern BPQVECSTRUC ** BPQHOSTVECPTR; -extern char WL2KModes [54][18]; -#else -__declspec(dllimport) BPQVECSTRUC ** BPQHOSTVECPTR; - - -char WL2KModes [54][18] = { - "Packet 1200", "Packet 2400", "Packet 4800", "Packet 9600", "Packet 19200", "Packet 38400", "High Speed Packet", "", "", "", "", - "", "Pactor 1", "", "", "Pactor 2", "", "Pactor 3", "", "", "Pactor 4", // 10 - 20 - "Winmor 500", "Winmor 1600", "", "", "", "", "", "", "", // 21 - 29 - "Robust Packet", "", "", "", "", "", "", "", "", "", // 30 - 39 - "ARDOP 200", "ARDOP 500", "ARDOP 1000", "ARDOP 2000", "ARDOP 2000 FM", "", "", "", "", "", // 40 - 49 - "VARA", "VARA FM", "VARA FM WIDE", "VARA 500"}; -#endif - - - - - -FILE * LogHandle[4] = {NULL, NULL, NULL, NULL}; - -time_t LastLogTime[4] = {0, 0, 0, 0}; - -char FilesNames[4][100] = {"", "", "", ""}; - -char * Logs[4] = {"BBS", "CHAT", "TCP", "DEBUG"}; - - -BOOL OpenLogfile(int Flags) -{ - UCHAR FN[MAX_PATH]; - time_t LT; - struct tm * tm; - - LT = time(NULL); - tm = gmtime(<); - - sprintf(FN,"%s/logs/log_%02d%02d%02d_%s.txt", GetLogDirectory(), tm->tm_year-100, tm->tm_mon+1, tm->tm_mday, Logs[Flags]); - - LogHandle[Flags] = fopen(FN, "ab"); - -#ifndef WIN32 - - if (strcmp(FN, &FilesNames[Flags][0])) - { - UCHAR SYMLINK[MAX_PATH]; - - sprintf(SYMLINK,"%s/logLatest_%s.txt", GetBPQDirectory(), Logs[Flags]); - unlink(SYMLINK); - strcpy(&FilesNames[Flags][0], FN); - symlink(FN, SYMLINK); - } - -#endif - - return (LogHandle[Flags] != NULL); -} - -typedef int (WINAPI FAR *FARPROCX)(); - -extern FARPROCX pDllBPQTRACE; - -struct SEM LogSEM = {0, 0}; - -void WriteLogLine(CIRCUIT * conn, int Flag, char * Msg, int MsgLen, int Flags) -{ - char CRLF[2] = {0x0d,0x0a}; - struct tm * tm; - char Stamp[20]; - time_t LT; -// struct _EXCEPTION_POINTERS exinfo; - - // Write to Node BPQTRACE system - - if ((Flags == LOG_BBS || Flags == LOG_DEBUG_X) && MsgLen < 250) - { - MESSAGE Monframe; - memset(&Monframe, 0, sizeof(Monframe)); - - Monframe.PORT = 64; - Monframe.LENGTH = 12 + MsgLen; - Monframe.DEST[0] = 1; // Plain Text Monitor - - memcpy(&Monframe.DEST[1], Msg, MsgLen); - Monframe.DEST[1 + MsgLen] = 0; - - time(&Monframe.Timestamp); -#ifdef LINBPQ - GetSemaphore(&Semaphore, 88); - BPQTRACE(&Monframe, FALSE); - FreeSemaphore(&Semaphore); -#else - if (pDllBPQTRACE) - pDllBPQTRACE(&Monframe, FALSE); -#endif - } -#ifndef LINBPQ - __try - { -#endif - - - -#ifndef LINBPQ - - if (hMonitor) - { - if (Flags == LOG_TCP && MonTCP) - { - WritetoMonitorWindow((char *)&Flag, 1); - WritetoMonitorWindow(Msg, MsgLen); - WritetoMonitorWindow(CRLF , 1); - } - else if (Flags == LOG_CHAT && MonCHAT) - { - WritetoMonitorWindow((char *)&Flag, 1); - - if (conn && conn->Callsign[0]) - { - char call[20]; - sprintf(call, "%s ", conn->Callsign); - WritetoMonitorWindow(call, 10); - } - else - WritetoMonitorWindow(" ", 10); - - WritetoMonitorWindow(Msg, MsgLen); - if (Msg[MsgLen-1] != '\r') - WritetoMonitorWindow(CRLF , 1); - } - else if (Flags == LOG_BBS && MonBBS) - { - WritetoMonitorWindow((char *)&Flag, 1); - if (conn && conn->Callsign[0]) - { - char call[20]; - sprintf(call, "%s ", conn->Callsign); - WritetoMonitorWindow(call, 10); - } - else - WritetoMonitorWindow(" ", 10); - - WritetoMonitorWindow(Msg, MsgLen); - WritetoMonitorWindow(CRLF , 1); - } - else if (Flags == LOG_DEBUG_X) - { - WritetoMonitorWindow((char *)&Flag, 1); - WritetoMonitorWindow(Msg, MsgLen); - WritetoMonitorWindow(CRLF , 1); - } - } -#endif - - if (Flags == LOG_TCP && !LogTCP) - return; - if (Flags == LOG_BBS && !LogBBS) - return; - if (Flags == LOG_CHAT && !LogCHAT) - return; - - GetSemaphore(&LogSEM, 0); - - if (LogHandle[Flags] == NULL) - OpenLogfile(Flags); - - if (LogHandle[Flags] == NULL) - { - FreeSemaphore(&LogSEM); - return; - } - LT = time(NULL); - tm = gmtime(<); - - sprintf(Stamp,"%02d%02d%02d %02d:%02d:%02d %c", - tm->tm_year-100, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, Flag); - - fwrite(Stamp, 1, strlen(Stamp), LogHandle[Flags]); - - if (conn && conn->Callsign[0]) - { - char call[20]; - sprintf(call, "%s ", conn->Callsign); - fwrite(call, 1, 10, LogHandle[Flags]); - } - else - fwrite(" ", 1, 10, LogHandle[Flags]); - - fwrite(Msg, 1, MsgLen, LogHandle[Flags]); - - if (Flags == LOG_CHAT && Msg[MsgLen-1] == '\r') - fwrite(&CRLF[1], 1, 1, LogHandle[Flags]); - else - fwrite(CRLF, 1, 2, LogHandle[Flags]); - - // Don't close/reopen logs every time - -// if ((LT - LastLogTime[Flags]) > 60) - { - LastLogTime[Flags] = LT; - fclose(LogHandle[Flags]); - LogHandle[Flags] = NULL; - } - FreeSemaphore(&LogSEM); - -#ifndef LINBPQ - } - __except(EXCEPTION_EXECUTE_HANDLER) - { - } -#endif -} - -int CriticalErrorHandler(char * error) -{ - Debugprintf("Critical Error %s", error); - ProgramErrors = 25; - CheckProgramErrors(); // Force close - return 0; -} - -BOOL CheckForTooManyErrors(ConnectionInfo * conn) -{ - conn->ErrorCount++; - - if (conn->ErrorCount > 4) - { - BBSputs(conn, "Too many errors - closing\r"); - conn->CloseAfterFlush = 20; - return TRUE; - } - return FALSE; -} - - - - - -VOID __cdecl Debugprintf(const char * format, ...) -{ - char Mess[16384]; - va_list(arglist); - int Len; - - va_start(arglist, format); - Len = vsprintf(Mess, format, arglist); -#ifndef LINBPQ - WriteLogLine(NULL, '!',Mess, Len, LOG_DEBUG_X); -#endif - // #ifdef _DEBUG - strcat(Mess, "\r\n"); - OutputDebugString(Mess); - -// #endif - return; -} - -VOID __cdecl Logprintf(int LogMode, CIRCUIT * conn, int InOut, const char * format, ...) -{ - char Mess[1000]; - va_list(arglist);int Len; - - va_start(arglist, format); - Len = vsprintf(Mess, format, arglist); - WriteLogLine(conn, InOut, Mess, Len, LogMode); - - return; -} - -struct MsgInfo * GetMsgFromNumber(int msgno) -{ - if (msgno < 1 || msgno > 999999) - return NULL; - - return MsgnotoMsg[msgno]; -} - -struct UserInfo * AllocateUserRecord(char * Call) -{ - struct UserInfo * User = zalloc(sizeof (struct UserInfo)); - - strcpy(User->Call, Call); - User->Length = sizeof (struct UserInfo); - - GetSemaphore(&AllocSemaphore, 0); - - UserRecPtr=realloc(UserRecPtr,(++NumberofUsers+1) * sizeof(void *)); - UserRecPtr[NumberofUsers]= User; - - FreeSemaphore(&AllocSemaphore); - - return User; -} - -struct MsgInfo * AllocateMsgRecord() -{ - struct MsgInfo * Msg = zalloc(sizeof (struct MsgInfo)); - - GetSemaphore(&AllocSemaphore, 0); - - MsgHddrPtr=realloc(MsgHddrPtr,(++NumberofMessages+1) * sizeof(void *)); - MsgHddrPtr[NumberofMessages] = Msg; - - FreeSemaphore(&AllocSemaphore); - - return Msg; -} - -BIDRec * AllocateBIDRecord() -{ - BIDRec * BID = zalloc(sizeof (BIDRec)); - - GetSemaphore(&AllocSemaphore, 0); - - BIDRecPtr = realloc(BIDRecPtr,(++NumberofBIDs+1) * sizeof(void *)); - BIDRecPtr[NumberofBIDs] = BID; - - FreeSemaphore(&AllocSemaphore); - - return BID; -} - -BIDRec * AllocateTempBIDRecord() -{ - BIDRec * BID = zalloc(sizeof (BIDRec)); - - GetSemaphore(&AllocSemaphore, 0); - - TempBIDRecPtr=realloc(TempBIDRecPtr,(++NumberofTempBIDs+1) * sizeof(void *)); - TempBIDRecPtr[NumberofTempBIDs] = BID; - - FreeSemaphore(&AllocSemaphore); - - return BID; -} - -struct UserInfo * LookupCall(char * Call) -{ - struct UserInfo * ptr = NULL; - int i; - - for (i=1; i <= NumberofUsers; i++) - { - ptr = UserRecPtr[i]; - - if (_stricmp(ptr->Call, Call) == 0) return ptr; - - } - - return NULL; -} - -int GetNetInt(char * Line) -{ - char temp[1024]; - char * ptr = strlop(Line, ','); - int n = atoi(Line); - if (ptr == NULL) - Line[0] = 0; - else - { - strcpy(temp, ptr); - strcpy(Line, temp); - } - return n; -} - -VOID GetUserDatabase() -{ - struct UserInfo UserRec; - - FILE * Handle; - size_t ReadLen; - struct UserInfo * user; - time_t UserLimit = time(NULL) - (UserLifetime * 86400); // Oldest user to keep - int i; - - // See if user config is in main config - - group = config_lookup (&cfg, "BBSUsers"); - - if (group) - { - // We have User config in the main config file. so use that - - int index = 0; - char * stats; - struct MsgStats * Stats; - char * ptr, * ptr2; - - config_setting_t * entry = config_setting_get_elem (group, index++); - - // Initialise a new File - - UserRecPtr = malloc(sizeof(void *)); - UserRecPtr[0] = malloc(sizeof (struct UserInfo)); - memset(UserRecPtr[0], 0, sizeof (struct UserInfo)); - UserRecPtr[0]->Length = sizeof (struct UserInfo); - - NumberofUsers = 0; - - while (entry) - { - char call[16]; - - // entry->name is call, will have * in front if a call stating woth number - - if (entry->name[0] == '*') - strcpy(call, &entry->name[1]); - else - strcpy(call, entry->name); - - user = AllocateUserRecord(call); - - ptr = entry->value.sval; - - ptr2 = strlop(ptr, '^'); - if (ptr) strcpy(user->Name, ptr); - ptr = ptr2; - - ptr2 = strlop(ptr, '^'); - if (ptr) strcpy(user->Address, ptr); - ptr = ptr2; - - ptr2 = strlop(ptr, '^'); - if (ptr) strcpy(user->HomeBBS, ptr); - ptr = ptr2; - - ptr2 = strlop(ptr, '^'); - if (ptr) strcpy(user->QRA, ptr); - ptr = ptr2; - - ptr2 = strlop(ptr, '^'); - if (ptr) strcpy(user->pass, ptr); - ptr = ptr2; - - ptr2 = strlop(ptr, '^'); - if (ptr) strcpy(user->ZIP, ptr); - ptr = ptr2; - - ptr2 = strlop(ptr, '^'); - if (ptr) strcpy(user->CMSPass, ptr); - ptr = ptr2; - - ptr2 = strlop(ptr, '^'); - if (ptr) user->lastmsg = atoi(ptr); - ptr = ptr2; - - ptr2 = strlop(ptr, '^'); - if (ptr) user->flags = atoi(ptr); - ptr = ptr2; - - ptr2 = strlop(ptr, '^'); - if (ptr) user->PageLen = atoi(ptr); - ptr = ptr2; - - ptr2 = strlop(ptr, '^'); - if (ptr) user->BBSNumber = atoi(ptr); - ptr = ptr2; - - ptr2 = strlop(ptr, '^'); - if (ptr) user->RMSSSIDBits = atoi(ptr); - ptr = ptr2; - - ptr2 = strlop(ptr, '^'); - if (ptr) user->WebSeqNo = atoi(ptr); - ptr = ptr2; - - ptr2 = strlop(ptr, '^'); - if (ptr) user->TimeLastConnected = atol(ptr); - ptr = ptr2; - - ptr2 = strlop(ptr, '^'); - if (ptr) Stats = &user->Total; - stats = ptr; - - if (Stats == NULL) - { - NumberofUsers--; - free(user); - entry = config_setting_get_elem (group, index++); - continue; - } - - Stats->ConnectsIn = GetNetInt(stats); - Stats->ConnectsOut = GetNetInt(stats); - Stats->MsgsReceived[0] = GetNetInt(stats); - Stats->MsgsReceived[1] = GetNetInt(stats); - Stats->MsgsReceived[2] = GetNetInt(stats); - Stats->MsgsReceived[3] = GetNetInt(stats); - Stats->MsgsSent[0] = GetNetInt(stats); - Stats->MsgsSent[1] = GetNetInt(stats); - Stats->MsgsSent[2] = GetNetInt(stats); - Stats->MsgsSent[3] = GetNetInt(stats); - Stats->MsgsRejectedIn[0] = GetNetInt(stats); - Stats->MsgsRejectedIn[1] = GetNetInt(stats); - Stats->MsgsRejectedIn[2] = GetNetInt(stats); - Stats->MsgsRejectedIn[3] = GetNetInt(stats); - Stats->MsgsRejectedOut[0] = GetNetInt(stats); - Stats->MsgsRejectedOut[1] = GetNetInt(stats); - Stats->MsgsRejectedOut[2] = GetNetInt(stats); - Stats->MsgsRejectedOut[3] = GetNetInt(stats); - Stats->BytesForwardedIn[0] = GetNetInt(stats); - Stats->BytesForwardedIn[1] = GetNetInt(stats); - Stats->BytesForwardedIn[2] = GetNetInt(stats); - Stats->BytesForwardedIn[3] = GetNetInt(stats); - Stats->BytesForwardedOut[0] = GetNetInt(stats); - Stats->BytesForwardedOut[1] = GetNetInt(stats); - Stats->BytesForwardedOut[2] = GetNetInt(stats); - Stats->BytesForwardedOut[3] = GetNetInt(stats); - - Stats = &user->Last; - stats = ptr2; - - if (Stats == NULL) - { - NumberofUsers--; - free(user); - entry = config_setting_get_elem (group, index++); - continue; - } - - Stats->ConnectsIn = GetNetInt(stats); - Stats->ConnectsOut = GetNetInt(stats); - Stats->MsgsReceived[0] = GetNetInt(stats); - Stats->MsgsReceived[1] = GetNetInt(stats); - Stats->MsgsReceived[2] = GetNetInt(stats); - Stats->MsgsReceived[3] = GetNetInt(stats); - Stats->MsgsSent[0] = GetNetInt(stats); - Stats->MsgsSent[1] = GetNetInt(stats); - Stats->MsgsSent[2] = GetNetInt(stats); - Stats->MsgsSent[3] = GetNetInt(stats); - Stats->MsgsRejectedIn[0] = GetNetInt(stats); - Stats->MsgsRejectedIn[1] = GetNetInt(stats); - Stats->MsgsRejectedIn[2] = GetNetInt(stats); - Stats->MsgsRejectedIn[3] = GetNetInt(stats); - Stats->MsgsRejectedOut[0] = GetNetInt(stats); - Stats->MsgsRejectedOut[1] = GetNetInt(stats); - Stats->MsgsRejectedOut[2] = GetNetInt(stats); - Stats->MsgsRejectedOut[3] = GetNetInt(stats); - Stats->BytesForwardedIn[0] = GetNetInt(stats); - Stats->BytesForwardedIn[1] = GetNetInt(stats); - Stats->BytesForwardedIn[2] = GetNetInt(stats); - Stats->BytesForwardedIn[3] = GetNetInt(stats); - Stats->BytesForwardedOut[0] = GetNetInt(stats); - Stats->BytesForwardedOut[1] = GetNetInt(stats); - Stats->BytesForwardedOut[2] = GetNetInt(stats); - Stats->BytesForwardedOut[3] = GetNetInt(stats); - - - if ((user->flags & F_BBS) == 0) // Not BBS - Check Age - { - if (UserLifetime && user->TimeLastConnected) // Dont delete manually added Users that havent yet connected - { - if (user->TimeLastConnected < UserLimit) - { - // Too Old - ignore - - NumberofUsers--; - free(user); - entry = config_setting_get_elem (group, index++); - continue; - } - } - } - user->Temp = zalloc(sizeof (struct TempUserInfo)); - - if (user->lastmsg < 0 || user->lastmsg > LatestMsg) - user->lastmsg = LatestMsg; - - - entry = config_setting_get_elem (group, index++); - } - } - else - { - Handle = fopen(UserDatabasePath, "rb"); - - if (Handle == NULL) - { - // Initialise a new File - - UserRecPtr=malloc(sizeof(void *)); - UserRecPtr[0]= malloc(sizeof (struct UserInfo)); - memset(UserRecPtr[0], 0, sizeof (struct UserInfo)); - UserRecPtr[0]->Length = sizeof (struct UserInfo); - - NumberofUsers = 0; - - return; - } - - - // Get First Record - - ReadLen = fread(&UserRec, 1, (int)sizeof (UserRec), Handle); - - if (ReadLen == 0) - { - // Duff file - - memset(&UserRec, 0, sizeof (struct UserInfo)); - UserRec.Length = sizeof (struct UserInfo); - } - else - { - // See if format has changed - - if (UserRec.Length == 0) - { - // Old format without a Length field - - struct OldUserInfo * OldRec = (struct OldUserInfo *)&UserRec; - int Users = OldRec->ConnectsIn; // User Count in control record - char Backup1[MAX_PATH]; - - // Create a backup in case reversion is needed and Reposition to first User record - - fclose(Handle); - - strcpy(Backup1, UserDatabasePath); - strcat(Backup1, ".oldformat"); - - CopyFile(UserDatabasePath, Backup1, FALSE); // Copy to .bak - - Handle = fopen(UserDatabasePath, "rb"); - - ReadLen = fread(&UserRec, 1, (int)sizeof (struct OldUserInfo), Handle); // Skip Control Record - - // Set up control record - - UserRecPtr=malloc(sizeof(void *)); - UserRecPtr[0]= malloc(sizeof (struct UserInfo)); - memcpy(UserRecPtr[0], &UserRec, sizeof (UserRec)); - UserRecPtr[0]->Length = sizeof (UserRec); - - NumberofUsers = 0; - -OldNext: - - ReadLen = fread(&UserRec, 1, (int)sizeof (struct OldUserInfo), Handle); - - if (ReadLen > 0) - { - if (OldRec->Call[0] < '0') - goto OldNext; // Blank record - - user = AllocateUserRecord(OldRec->Call); - user->Temp = zalloc(sizeof (struct TempUserInfo)); - - // Copy info from Old record - - user->lastmsg = OldRec->lastmsg; - user->Total.ConnectsIn = OldRec->ConnectsIn; - user->TimeLastConnected = OldRec->TimeLastConnected; - user->flags = OldRec->flags; - user->PageLen = OldRec->PageLen; - user->BBSNumber = OldRec->BBSNumber; - memcpy(user->Name, OldRec->Name, 18); - memcpy(user->Address, OldRec->Address, 61); - user->Total.MsgsReceived[0] = OldRec->MsgsReceived; - user->Total.MsgsSent[0] = OldRec->MsgsSent; - user->Total.MsgsRejectedIn[0] = OldRec->MsgsRejectedIn; // Messages we reject - user->Total.MsgsRejectedOut[0] = OldRec->MsgsRejectedOut; // Messages Rejectd by other end - user->Total.BytesForwardedIn[0] = OldRec->BytesForwardedIn; - user->Total.BytesForwardedOut[0] = OldRec->BytesForwardedOut; - user->Total.ConnectsOut = OldRec->ConnectsOut; // Forwarding Connects Out - user->RMSSSIDBits = OldRec->RMSSSIDBits; // SSID's to poll in RMS - memcpy(user->HomeBBS, OldRec->HomeBBS, 41); - memcpy(user->QRA, OldRec->QRA, 7); - memcpy(user->pass, OldRec->pass, 13); - memcpy(user->ZIP, OldRec->ZIP, 9); - - // Read any forwarding info, even if not a BBS. - // This allows a BBS to be temporarily set as a - // normal user without loosing forwarding info - - SetupForwardingStruct(user); - - if (user->flags & F_BBS) - { - // Defined as BBS - allocate and initialise forwarding structure - - // Add to BBS Chain; - - user->BBSNext = BBSChain; - BBSChain = user; - - // Save Highest BBS Number - - if (user->BBSNumber > HighestBBSNumber) HighestBBSNumber = user->BBSNumber; - } - goto OldNext; - } - - SortBBSChain(); - fclose(Handle); - - return; - } - } - - // Set up control record - - UserRecPtr=malloc(sizeof(void *)); - UserRecPtr[0]= malloc(sizeof (struct UserInfo)); - memcpy(UserRecPtr[0], &UserRec, sizeof (UserRec)); - UserRecPtr[0]->Length = sizeof (UserRec); - - NumberofUsers = 0; - -Next: - - ReadLen = fread(&UserRec, 1, (int)sizeof (UserRec), Handle); - - if (ReadLen > 0) - { - if (UserRec.Call[0] < '0') - goto Next; // Blank record - - if (UserRec.TimeLastConnected == 0) - UserRec.TimeLastConnected = UserRec.xTimeLastConnected; - - if ((UserRec.flags & F_BBS) == 0) // Not BBS - Check Age - if (UserLifetime) // if limit set - if (UserRec.TimeLastConnected) // Dont delete manually added Users that havent yet connected - if (UserRec.TimeLastConnected < UserLimit) - goto Next; // Too Old - ignore - - user = AllocateUserRecord(UserRec.Call); - memcpy(user, &UserRec, sizeof (UserRec)); - user->Temp = zalloc(sizeof (struct TempUserInfo)); - - user->ForwardingInfo = NULL; // In case left behind on crash - user->BBSNext = NULL; - user->POP3Locked = FALSE; - - if (user->lastmsg < 0 || user->lastmsg > LatestMsg) - user->lastmsg = LatestMsg; - - goto Next; - } - fclose(Handle); - } - - // Setting up BBS struct has been moved until all user record - // have been read so we can fix corrupt BBSNUmber - - for (i=1; i <= NumberofUsers; i++) - { - user = UserRecPtr[i]; - - // Read any forwarding info, even if not a BBS. - // This allows a BBS to be temporarily set as a - // normal user without loosing forwarding info - - SetupForwardingStruct(user); - - if (user->flags & F_BBS) - { - // Add to BBS Chain; - - if (user->BBSNumber == NBBBS) // Fix corrupt records - { - user->BBSNumber = FindFreeBBSNumber(); - if (user->BBSNumber == 0) - user->BBSNumber = NBBBS; // cant really do much else - } - - user->BBSNext = BBSChain; - BBSChain = user; - -// Logprintf(LOG_BBS, NULL, '?', "BBS %s BBSNumber %d", user->Call, user->BBSNumber); - - // Save Highest BBS Number - - if (user->BBSNumber > HighestBBSNumber) - HighestBBSNumber = user->BBSNumber; - } - } - - // Check for dulicate BBS numbers - - for (i=1; i <= NumberofUsers; i++) - { - user = UserRecPtr[i]; - - if (user->flags & F_BBS) - { - if (user->BBSNumber == 0) - user->BBSNumber = FindFreeBBSNumber(); - - CheckBBSNumber(user->BBSNumber); - } - } - - SortBBSChain(); -} - -VOID CopyUserDatabase() -{ - return; // User config now in main config file -/* - char Backup1[MAX_PATH]; - char Backup2[MAX_PATH]; - - // Keep 4 Generations - - strcpy(Backup2, UserDatabasePath); - strcat(Backup2, ".bak.3"); - - strcpy(Backup1, UserDatabasePath); - strcat(Backup1, ".bak.2"); - - DeleteFile(Backup2); // Remove old .bak.3 - MoveFile(Backup1, Backup2); // Move .bak.2 to .bak.3 - - strcpy(Backup2, UserDatabasePath); - strcat(Backup2, ".bak.1"); - - MoveFile(Backup2, Backup1); // Move .bak.1 to .bak.2 - - strcpy(Backup1, UserDatabasePath); - strcat(Backup1, ".bak"); - - MoveFile(Backup1, Backup2); //Move .bak to .bak.1 - - CopyFile(UserDatabasePath, Backup1, FALSE); // Copy to .bak -*/ -} - -VOID CopyConfigFile(char * ConfigName) -{ - char Backup1[MAX_PATH]; - char Backup2[MAX_PATH]; - - // Keep 4 Generations - - strcpy(Backup2, ConfigName); - strcat(Backup2, ".bak.3"); - - strcpy(Backup1, ConfigName); - strcat(Backup1, ".bak.2"); - - DeleteFile(Backup2); // Remove old .bak.3 - MoveFile(Backup1, Backup2); // Move .bak.2 to .bak.3 - - strcpy(Backup2, ConfigName); - strcat(Backup2, ".bak.1"); - - MoveFile(Backup2, Backup1); // Move .bak.1 to .bak.2 - - strcpy(Backup1, ConfigName); - strcat(Backup1, ".bak"); - - MoveFile(Backup1, Backup2); // Move .bak to .bak.1 - - CopyFile(ConfigName, Backup1, FALSE); // Copy to .bak -} - - - -VOID SaveUserDatabase() -{ - SaveConfig(ConfigName); // User config is now in main config file - GetConfig(ConfigName); - -/* - FILE * Handle; - size_t WriteLen; - int i; - - Handle = fopen(UserDatabasePath, "wb"); - - UserRecPtr[0]->Total.ConnectsIn = NumberofUsers; - - for (i=0; i <= NumberofUsers; i++) - { - WriteLen = fwrite(UserRecPtr[i], 1, (int)sizeof (struct UserInfo), Handle); - } - - fclose(Handle); -*/ - return; -} - -VOID GetMessageDatabase() -{ - struct MsgInfo MsgRec; - FILE * Handle; - size_t ReadLen; - struct MsgInfo * Msg; - char * MsgBytes; - int FileRecsize = sizeof(struct MsgInfo); // May be changed if reformating - BOOL Reformatting = FALSE; - char HEX[3] = ""; - int n; - - // See if Message Database is in main config - - group = config_lookup (&cfg, "MSGS"); - -// group = 0; - - if (group) - { - // We have User config in the main config file. so use that - - int index = 0; - char * ptr, * ptr2; - config_setting_t * entry = config_setting_get_elem (group, index++); - - // Initialise a new File - - MsgHddrPtr=malloc(sizeof(void *)); - MsgHddrPtr[0]= zalloc(sizeof (MsgRec)); - NumberofMessages = 0; - MsgHddrPtr[0]->status = 2; - - if (entry) - { - // First Record has current message number - - ptr = entry->value.sval; - ptr2 = strlop(ptr, '|'); - ptr2 = strlop(ptr2, '|'); - if (ptr2) - LatestMsg = atoi(ptr2); - } - - entry = config_setting_get_elem (group, index++); - - while (entry) - { - // entry->name is MsgNo with 'R' in front - - ptr = entry->value.sval; - ptr2 = strlop(ptr, '|'); - - memset(&MsgRec, 0, sizeof(struct MsgInfo)); - - MsgRec.number = atoi(&entry->name[1]); - MsgRec.type = ptr[0]; - - ptr = ptr2; - - if (ptr == NULL) - { - entry = config_setting_get_elem (group, index++); - continue; - } - - ptr2 = strlop(ptr, '|'); - MsgRec.status = ptr[0]; - - ptr = ptr2; - ptr2 = strlop(ptr, '|'); - if (ptr) MsgRec.length = atoi(ptr); - - ptr = ptr2; - ptr2 = strlop(ptr, '|'); - if (ptr) MsgRec.datereceived = atol(ptr); - - ptr = ptr2; - ptr2 = strlop(ptr, '|'); - if (ptr) strcpy(MsgRec.bbsfrom, ptr); - - ptr = ptr2; - ptr2 = strlop(ptr, '|'); - if (ptr) strcpy(MsgRec.via, ptr); - - ptr = ptr2; - ptr2 = strlop(ptr, '|'); - if (ptr) strcpy(MsgRec.from, ptr); - - ptr = ptr2; - ptr2 = strlop(ptr, '|'); - if (ptr) strcpy(MsgRec.to, ptr); - - ptr = ptr2; - ptr2 = strlop(ptr, '|'); - if (ptr) strcpy(MsgRec.bid, ptr); - - ptr = ptr2; - ptr2 = strlop(ptr, '|'); - if (ptr) MsgRec.B2Flags = atoi(ptr); - - ptr = ptr2; - ptr2 = strlop(ptr, '|'); - if (ptr) MsgRec.datecreated = atol(ptr); - - ptr = ptr2; - ptr2 = strlop(ptr, '|'); - if (ptr) MsgRec.datechanged = atol(ptr); - - ptr = ptr2; - if (ptr) ptr2 = strlop(ptr, '|'); - - if (ptr == NULL) - { - entry = config_setting_get_elem (group, index++); - continue; - } - - if (ptr[0]) - { - char String[50] = "00000000000000000000"; - String[20] = 0; - memcpy(String, ptr, strlen(ptr)); - for (n = 0; n < NBMASK; n++) - { - memcpy(HEX, &String[n * 2], 2); - MsgRec.fbbs[n] = (UCHAR)strtol(HEX, 0, 16); - } - } - - ptr = ptr2; - ptr2 = strlop(ptr, '|'); - - if (ptr == NULL) - { - entry = config_setting_get_elem (group, index++); - continue; - } - - if (ptr[0]) - { - char String[50] = "00000000000000000000"; - String[20] = 0; - memcpy(String, ptr, strlen(ptr)); - for (n = 0; n < NBMASK; n++) - { - memcpy(HEX, &String[n * 2], 2); - MsgRec.forw[n] = (UCHAR)strtol(HEX, 0, 16); - } - } - - ptr = ptr2; - ptr2 = strlop(ptr, '|'); - if (ptr) strcpy(MsgRec.emailfrom, ptr); - - ptr = ptr2; - ptr2 = strlop(ptr, '|'); - if (ptr) MsgRec.UTF8 = atoi(ptr); - - ptr = ptr2; - - if (ptr) - { - strcpy(MsgRec.title, ptr); - - MsgBytes = ReadMessageFileEx(&MsgRec); - - if (MsgBytes) - { - free(MsgBytes); - Msg = AllocateMsgRecord(); - memcpy(Msg, &MsgRec, sizeof (MsgRec)); - - MsgnotoMsg[Msg->number] = Msg; - - // Fix Corrupted NTS Messages - - if (Msg->type == 'N') - Msg->type = 'T'; - - // Look for corrupt FROM address (ending in @) - - strlop(Msg->from, '@'); - - BuildNNTPList(Msg); // Build NNTP Groups list - - // If any forward bits are set, increment count on corresponding BBS record. - - if (memcmp(Msg->fbbs, zeros, NBMASK) != 0) - { - if (FirstMessageIndextoForward == 0) - FirstMessageIndextoForward = NumberofMessages; // limit search - } - } - } - entry = config_setting_get_elem (group, index++); - } - - if (FirstMessageIndextoForward == 0) - FirstMessageIndextoForward = NumberofMessages; // limit search - - return; - } - - Handle = fopen(MsgDatabasePath, "rb"); - - if (Handle == NULL) - { - // Initialise a new File - - MsgHddrPtr=malloc(sizeof(void *)); - MsgHddrPtr[0]= zalloc(sizeof (MsgRec)); - NumberofMessages = 0; - MsgHddrPtr[0]->status = 2; - - return; - } - - // Get First Record - - ReadLen = fread(&MsgRec, 1, FileRecsize, Handle); - - if (ReadLen == 0) - { - // Duff file - - memset(&MsgRec, 0, sizeof (MsgRec)); - MsgRec.status = 2; - } - - // Set up control record - - MsgHddrPtr=malloc(sizeof(void *)); - MsgHddrPtr[0]= malloc(sizeof (MsgRec)); - memcpy(MsgHddrPtr[0], &MsgRec, sizeof (MsgRec)); - - LatestMsg=MsgHddrPtr[0]->length; - - NumberofMessages = 0; - - if (MsgRec.status == 1) // Used as file format version - // 0 = original, 1 = Extra email from addr, 2 = More BBS's. - { - char Backup1[MAX_PATH]; - - // Create a backup in case reversion is needed and Reposition to first User record - - fclose(Handle); - - strcpy(Backup1, MsgDatabasePath); - strcat(Backup1, ".oldformat"); - - CopyFile(MsgDatabasePath, Backup1, FALSE); // Copy to .oldformat - - Handle = fopen(MsgDatabasePath, "rb"); - - FileRecsize = sizeof(struct OldMsgInfo); - - ReadLen = fread(&MsgRec, 1, FileRecsize, Handle); - - MsgHddrPtr[0]->status = 2; - } - -Next: - - ReadLen = fread(&MsgRec, 1, FileRecsize, Handle); - - if (ReadLen > 0) - { - // Validate Header - - if (FileRecsize == sizeof(struct MsgInfo)) - { - if (MsgRec.type == 0 || MsgRec.number == 0) - goto Next; - - MsgBytes = ReadMessageFileEx(&MsgRec); - - if (MsgBytes) - { - // MsgRec.length = strlen(MsgBytes); - free(MsgBytes); - } - else - goto Next; - - Msg = AllocateMsgRecord(); - - memcpy(Msg, &MsgRec, +sizeof (MsgRec)); - } - else - { - // Resizing - record from file is an OldRecInfo - - struct OldMsgInfo * OldMessage = (struct OldMsgInfo *) &MsgRec; - - if (OldMessage->type == 0) - goto Next; - - if (OldMessage->number > 99999 || OldMessage->number < 1) - goto Next; - - Msg = AllocateMsgRecord(); - - - Msg->B2Flags = OldMessage->B2Flags; - memcpy(Msg->bbsfrom, OldMessage->bbsfrom, 7); - memcpy(Msg->bid, OldMessage->bid, 13); - Msg->datechanged = OldMessage->datechanged; - Msg->datecreated = OldMessage->datecreated; - Msg->datereceived = OldMessage->datereceived; - memcpy(Msg->emailfrom, OldMessage->emailfrom, 41); - memcpy(Msg->fbbs , OldMessage->fbbs, 10); - memcpy(Msg->forw , OldMessage->forw, 10); - memcpy(Msg->from, OldMessage->from, 7); - Msg->length = OldMessage->length; - Msg->nntpnum = OldMessage->nntpnum; - Msg->number = OldMessage->number; - Msg->status = OldMessage->status; - memcpy(Msg->title, OldMessage->title, 61); - memcpy(Msg->to, OldMessage->to, 7); - Msg->type = OldMessage->type; - memcpy(Msg->via, OldMessage->via, 41); - } - - MsgnotoMsg[Msg->number] = Msg; - - // Fix Corrupted NTS Messages - - if (Msg->type == 'N') - Msg->type = 'T'; - - // Look for corrupt FROM address (ending in @) - - strlop(Msg->from, '@'); - - // Move Dates if first run with new format - - if (Msg->datecreated == 0) - Msg->datecreated = Msg->xdatecreated; - - if (Msg->datereceived == 0) - Msg->datereceived = Msg->xdatereceived; - - if (Msg->datechanged == 0) - Msg->datechanged = Msg->xdatechanged; - - BuildNNTPList(Msg); // Build NNTP Groups list - - Msg->Locked = 0; // In case left locked - Msg->Defered = 0; // In case left set. - - // If any forward bits are set, increment count on corresponding BBS record. - - if (memcmp(Msg->fbbs, zeros, NBMASK) != 0) - { - if (FirstMessageIndextoForward == 0) - FirstMessageIndextoForward = NumberofMessages; // limit search - } - - goto Next; - } - - if (FirstMessageIndextoForward == 0) - FirstMessageIndextoForward = NumberofMessages; // limit search - - fclose(Handle); -} - -VOID CopyMessageDatabase() -{ - char Backup1[MAX_PATH]; - char Backup2[MAX_PATH]; - -// return; - - // Keep 4 Generations - - strcpy(Backup2, MsgDatabasePath); - strcat(Backup2, ".bak.3"); - - strcpy(Backup1, MsgDatabasePath); - strcat(Backup1, ".bak.2"); - - DeleteFile(Backup2); // Remove old .bak.3 - MoveFile(Backup1, Backup2); // Move .bak.2 to .bak.3 - - strcpy(Backup2, MsgDatabasePath); - strcat(Backup2, ".bak.1"); - - MoveFile(Backup2, Backup1); // Move .bak.1 to .bak.2 - - strcpy(Backup1, MsgDatabasePath); - strcat(Backup1, ".bak"); - - MoveFile(Backup1, Backup2); //Move .bak to .bak.1 - - strcpy(Backup2, MsgDatabasePath); - strcat(Backup2, ".bak"); - - CopyFile(MsgDatabasePath, Backup2, FALSE); // Copy to .bak - -} - -VOID SaveMessageDatabase() -{ - FILE * Handle; - size_t WriteLen; - int i; - char Key[16]; - struct MsgInfo *Msg; -// char CfgName[MAX_PATH]; - char HEXString1[64]; - char HEXString2[64]; - int n; -// char * CfgBuffer; - char Cfg[1024]; -// int CfgLen = 0; -// FILE * hFile; - -// SaveConfig(ConfigName); // Message Headers now in main config -// return; - -#ifdef LINBPQ - RefreshWebMailIndex(); -#else - if (pRefreshWebMailIndex) - pRefreshWebMailIndex(); -#endif - - Handle = fopen(MsgDatabasePath, "wb"); - - if (Handle == NULL) - { - CriticalErrorHandler("Failed to open message database"); - return; - } - - MsgHddrPtr[0]->status = 2; - MsgHddrPtr[0]->number = NumberofMessages; - MsgHddrPtr[0]->length = LatestMsg; - - for (i=0; i <= NumberofMessages; i++) - { - WriteLen = fwrite(MsgHddrPtr[i], 1, sizeof (struct MsgInfo), Handle); - - if (WriteLen != sizeof(struct MsgInfo)) - { - CriticalErrorHandler("Failed to write message database record"); - return; - } - } - - if (fclose(Handle) != 0) - CriticalErrorHandler("Failed to close message database"); - - for (i = 1; i <= NumberofMessages; i++) - { - Msg = MsgHddrPtr[i]; - - for (n = 0; n < NBMASK; n++) - sprintf(&HEXString1[n * 2], "%02X", Msg->fbbs[n]); - - n = 39; - while (n >=0 && HEXString1[n] == '0') - HEXString1[n--] = 0; - - for (n = 0; n < NBMASK; n++) - sprintf(&HEXString2[n * 2], "%02X", Msg->forw[n]); - - n = 39; - while (n >= 0 && HEXString2[n] == '0') - HEXString2[n--] = 0; - - sprintf(Key, "R%d:\r\n", i); - - n = sprintf(Cfg, "%c|%c|%d|%d|%lld|%s|%s|%s|%s|%s|%d|%lld|%lld|%s|%s|%s|%d|%s", Msg->type, Msg->status, - Msg->number, Msg->length, Msg->datereceived, &Msg->bbsfrom[0], &Msg->via[0], &Msg->from[0], - &Msg->to[0], &Msg->bid[0], Msg->B2Flags, Msg->datecreated, Msg->datechanged, HEXString1, HEXString2, - &Msg->emailfrom[0], Msg->UTF8, &Msg->title[0]); - } - - return; -} - -VOID GetBIDDatabase() -{ - BIDRec BIDRec; - FILE * Handle; - size_t ReadLen; - BIDRecP BID; - int index = 0; - char * ptr, * ptr2; - - // If BID info is in main config file, use it - - group = config_lookup (&cfg, "BIDS"); - - if (group) - { - config_setting_t * entry = config_setting_get_elem (group, index++); - - BIDRecPtr=malloc(sizeof(void *)); - BIDRecPtr[0]= malloc(sizeof (BIDRec)); - memset(BIDRecPtr[0], 0, sizeof (BIDRec)); - NumberofBIDs = 0; - - while (entry) - { - // entry->name is Bid with 'R' in front - - ptr = entry->value.sval; - ptr2 = strlop(ptr, '|'); - - if (ptr && ptr2) - { - BID = AllocateBIDRecord(); - strcpy(BID->BID, &entry->name[1]); - BID->mode = atoi(ptr); - BID->u.timestamp = atoi(ptr2); - - if (BID->u.timestamp == 0) - BID->u.timestamp = LOWORD(time(NULL)/86400); - - } - entry = config_setting_get_elem (group, index++); - } - return; - } - - Handle = fopen(BIDDatabasePath, "rb"); - - if (Handle == NULL) - { - // Initialise a new File - - BIDRecPtr=malloc(sizeof(void *)); - BIDRecPtr[0]= malloc(sizeof (BIDRec)); - memset(BIDRecPtr[0], 0, sizeof (BIDRec)); - NumberofBIDs = 0; - - return; - } - - - // Get First Record - - ReadLen = fread(&BIDRec, 1, sizeof (BIDRec), Handle); - - if (ReadLen == 0) - { - // Duff file - - memset(&BIDRec, 0, sizeof (BIDRec)); - } - - // Set up control record - - BIDRecPtr = malloc(sizeof(void *)); - BIDRecPtr[0] = malloc(sizeof (BIDRec)); - memcpy(BIDRecPtr[0], &BIDRec, sizeof (BIDRec)); - - NumberofBIDs = 0; - -Next: - - ReadLen = fread(&BIDRec, 1, sizeof (BIDRec), Handle); - - if (ReadLen > 0) - { - BID = AllocateBIDRecord(); - memcpy(BID, &BIDRec, sizeof (BIDRec)); - - if (BID->u.timestamp == 0) - BID->u.timestamp = LOWORD(time(NULL)/86400); - - goto Next; - } - - fclose(Handle); -} - -VOID CopyBIDDatabase() -{ - char Backup[MAX_PATH]; - -// return; - - - strcpy(Backup, BIDDatabasePath); - strcat(Backup, ".bak"); - - CopyFile(BIDDatabasePath, Backup, FALSE); -} - -VOID SaveBIDDatabase() -{ - FILE * Handle; - size_t WriteLen; - int i; - -// return; // Bids are now in main config and are saved when message is saved - - Handle = fopen(BIDDatabasePath, "wb"); - - BIDRecPtr[0]->u.msgno = NumberofBIDs; // First Record has file size - - for (i=0; i <= NumberofBIDs; i++) - { - WriteLen = fwrite(BIDRecPtr[i], 1, sizeof (BIDRec), Handle); - } - - fclose(Handle); - - return; -} - -BIDRec * LookupBID(char * BID) -{ - BIDRec * ptr = NULL; - int i; - - for (i=1; i <= NumberofBIDs; i++) - { - ptr = BIDRecPtr[i]; - - if (_stricmp(ptr->BID, BID) == 0) - return ptr; - } - - return NULL; -} - -BIDRec * LookupTempBID(char * BID) -{ - BIDRec * ptr = NULL; - int i; - - for (i=1; i <= NumberofTempBIDs; i++) - { - ptr = TempBIDRecPtr[i]; - - if (_stricmp(ptr->BID, BID) == 0) return ptr; - } - - return NULL; -} - -VOID RemoveTempBIDS(CIRCUIT * conn) -{ - // Remove any Temp BID records for conn. Called when connection closes - Msgs will be complete or failed - - if (NumberofTempBIDs == 0) - return; - else - { - BIDRec * ptr = NULL; - BIDRec ** NewTempBIDRecPtr = zalloc((NumberofTempBIDs+1) * sizeof(void *)); - int i = 0, n; - - GetSemaphore(&AllocSemaphore, 0); - - for (n = 1; n <= NumberofTempBIDs; n++) - { - ptr = TempBIDRecPtr[n]; - - if (ptr) - { - if (ptr->u.conn == conn) - // Remove this entry - free(ptr); - else - NewTempBIDRecPtr[++i] = ptr; - } - } - - NumberofTempBIDs = i; - - free(TempBIDRecPtr); - - TempBIDRecPtr = NewTempBIDRecPtr; - FreeSemaphore(&AllocSemaphore); - } - -} - -VOID GetBadWordFile() -{ - FILE * Handle; - DWORD FileSize; - char * ptr1, * ptr2; - struct stat STAT; - - if (stat(BadWordsPath, &STAT) == -1) - return; - - FileSize = STAT.st_size; - - Handle = fopen(BadWordsPath, "rb"); - - if (Handle == NULL) - return; - - // Release old info in case a re-read - - if (BadWords) free(BadWords); - if (BadFile) free(BadFile); - - BadWords = NULL; - BadFile = NULL; - NumberofBadWords = 0; - - BadFile = malloc(FileSize+1); - - fread(BadFile, 1, FileSize, Handle); - - fclose(Handle); - - BadFile[FileSize]=0; - - _strlwr(BadFile); // Compares are case-insensitive - - ptr1 = BadFile; - - while (ptr1) - { - if (*ptr1 == '\n') ptr1++; - - ptr2 = strtok_s(NULL, "\r\n", &ptr1); - if (ptr2) - { - if (*ptr2 != '#') - { - BadWords = realloc(BadWords,(++NumberofBadWords+1) * sizeof(void *)); - BadWords[NumberofBadWords] = ptr2; - } - } - else - break; - } -} - -BOOL CheckBadWord(char * Word, char * Msg) -{ - char * ptr1 = Msg, * ptr2; - size_t len = strlen(Word); - - while (*ptr1) // Stop at end - { - ptr2 = strstr(ptr1, Word); - - if (ptr2 == NULL) - return FALSE; // OK - - // Only bad if it ia not part of a longer word - - if ((ptr2 == Msg) || !(isalpha(*(ptr2 - 1)))) // No alpha before - if (!(isalpha(*(ptr2 + len)))) // No alpha after - return TRUE; // Bad word - - // Keep searching - - ptr1 = ptr2 + len; - } - - return FALSE; // OK -} - -BOOL CheckBadWords(char * Msg) -{ - char * dupMsg = _strlwr(_strdup(Msg)); - int i; - - for (i = 1; i <= NumberofBadWords; i++) - { - if (CheckBadWord(BadWords[i], dupMsg)) - { - free(dupMsg); - return TRUE; // Bad - } - } - - free(dupMsg); - return FALSE; // OK - -} - -VOID SendWelcomeMsg(int Stream, ConnectionInfo * conn, struct UserInfo * user) -{ - if (user->flags & F_Expert) - ExpandAndSendMessage(conn, ExpertWelcomeMsg, LOG_BBS); - else if (conn->NewUser) - ExpandAndSendMessage(conn, NewWelcomeMsg, LOG_BBS); - else - ExpandAndSendMessage(conn, WelcomeMsg, LOG_BBS); - - if (user->HomeBBS[0] == 0 && !DontNeedHomeBBS) - BBSputs(conn, "Please enter your Home BBS using the Home command.\rYou may also enter your QTH and ZIP/Postcode using qth and zip commands.\r"); - -// if (user->flags & F_Temp_B2_BBS) -// nodeprintf(conn, "%s CMS >\r", BBSName); -// else - SendPrompt(conn, user); -} - -VOID SendPrompt(ConnectionInfo * conn, struct UserInfo * user) -{ - if (user->Temp->ListSuspended) - return; // Dont send prompt if pausing a listing - - if (user->flags & F_Expert) - ExpandAndSendMessage(conn, ExpertPrompt, LOG_BBS); - else if (conn->NewUser) - ExpandAndSendMessage(conn, NewPrompt, LOG_BBS); - else - ExpandAndSendMessage(conn, Prompt, LOG_BBS); - -// if (user->flags & F_Expert) -// nodeprintf(conn, "%s\r", ExpertPrompt); -// else if (conn->NewUser) -// nodeprintf(conn, "%s\r", NewPrompt); -// else -// nodeprintf(conn, "%s\r", Prompt); -} - - - -VOID * _zalloc(size_t len) -{ - // ?? malloc and clear - - void * ptr; - - ptr=malloc(len); - memset(ptr, 0, len); - - return ptr; -} - -BOOL isAMPRMsg(char * Addr) -{ - // See if message is addressed to ampr.org and is either - // for us or we have SendAMPRDirect (ie don't need RMS or SMTP to send it) - - size_t toLen = strlen(Addr); - - if (_memicmp(&Addr[toLen - 8], "ampr.org", 8) == 0) - { - // message is for ampr.org - - char toCall[48]; - char * via; - - strcpy(toCall, _strupr(Addr)); - - via = strlop(toCall, '@'); - - if (_stricmp(via, AMPRDomain) == 0) - { - // message is for us. - - return TRUE; - } - - if (SendAMPRDirect) - { - // We want to send ampr mail direct to host. Queue to BBS AMPR - - if (FindAMPR()) - { - // We have bbs AMPR - - return TRUE; - } - } - } - return FALSE; -} - -struct UserInfo * FindAMPR() -{ - struct UserInfo * bbs; - - for (bbs = BBSChain; bbs; bbs = bbs->BBSNext) - { - if (strcmp(bbs->Call, "AMPR") == 0) - return bbs; - } - - return NULL; -} - -struct UserInfo * FindRMS() -{ - struct UserInfo * bbs; - - for (bbs = BBSChain; bbs; bbs = bbs->BBSNext) - { - if (strcmp(bbs->Call, "RMS") == 0) - return bbs; - } - - return NULL; -} - -struct UserInfo * FindBBS(char * Name) -{ - struct UserInfo * bbs; - - for (bbs = BBSChain; bbs; bbs = bbs->BBSNext) - { - if (strcmp(bbs->Call, Name) == 0) - return bbs; - } - - return NULL; -} - -int CountConnectionsOnPort(int CheckPort) -{ - int n, Count = 0; - CIRCUIT * conn; - int port, sesstype, paclen, maxframe, l4window; - char callsign[11]; - - for (n = 0; n < NumberofStreams; n++) - { - conn = &Connections[n]; - - if (conn->Active) - { - GetConnectionInfo(conn->BPQStream, callsign, &port, &sesstype, &paclen, &maxframe, &l4window); - if (port == CheckPort) - Count++; - } - } - - return Count; -} - - -BOOL CheckRejFilters(char * From, char * To, char * ATBBS, char * BID, char Type) -{ - char ** Calls; - - if (Type == 'B' && FilterWPBulls && _stricmp(To, "WP") == 0) - return TRUE; - - if (RejFrom && From) - { - Calls = RejFrom; - - while(Calls[0]) - { - if (_stricmp(Calls[0], From) == 0) - return TRUE; - - Calls++; - } - } - - if (RejTo && To) - { - Calls = RejTo; - - while(Calls[0]) - { - if (_stricmp(Calls[0], To) == 0) - return TRUE; - - Calls++; - } - } - - if (RejAt && ATBBS) - { - Calls = RejAt; - - while(Calls[0]) - { - if (_stricmp(Calls[0], ATBBS) == 0) - return TRUE; - - Calls++; - } - } - - if (RejBID && BID) - { - Calls = RejBID; - - while(Calls[0]) - { - if (Calls[0][0] == '*') - { - if (stristr(BID, &Calls[0][1])) - return TRUE; - } - else - { - if (_stricmp(BID, Calls[0]) == 0) - return TRUE; - } - - Calls++; - } - } - return FALSE; // Ok to accept -} - -BOOL CheckValidCall(char * From) -{ - unsigned int i; - - if (DontCheckFromCall) - return TRUE; - - if (strcmp(From, "SYSOP") == 0 || strcmp(From, "SYSTEM") == 0 || - strcmp(From, "IMPORT") == 0 || strcmp(From, "SMTP:") == 0 || strcmp(From, "RMS:") == 0) - return TRUE; - - for (i = 1; i < strlen(From); i++) // skip first which may also be digit - { - if (isdigit(From[i])) - { - // Has a digit. Check Last is not digit - - if (isalpha(From[strlen(From) - 1])) - return TRUE; - } - } - - // No digit, return false - - return FALSE; -} - -BOOL CheckHoldFilters(char * From, char * To, char * ATBBS, char * BID) -{ - char ** Calls; - - if (HoldFrom && From) - { - Calls = HoldFrom; - - while(Calls[0]) - { - if (_stricmp(Calls[0], From) == 0) - return TRUE; - - Calls++; - } - } - - if (HoldTo && To) - { - Calls = HoldTo; - - while(Calls[0]) - { - if (_stricmp(Calls[0], To) == 0) - return TRUE; - - Calls++; - } - } - - if (HoldAt && ATBBS) - { - Calls = HoldAt; - - while(Calls[0]) - { - if (_stricmp(Calls[0], ATBBS) == 0) - return TRUE; - - Calls++; - } - } - - if (HoldBID && BID) - { - Calls = HoldBID; - - while(Calls[0]) - { - if (Calls[0][0] == '*') - { - if (stristr(BID, &Calls[0][1])) - return TRUE; - } - else - { - if (_stricmp(BID, Calls[0]) == 0) - return TRUE; - } - - Calls++; - } - } - return FALSE; // Ok to accept -} - -BOOL CheckifLocalRMSUser(char * FullTo) -{ - struct UserInfo * user = LookupCall(FullTo); - - if (user) - if (user->flags & F_POLLRMS) - return TRUE; - - return FALSE; - -} - - - -int check_fwd_bit(char *mask, int bbsnumber) -{ - if (bbsnumber) - return (mask[(bbsnumber - 1) / 8] & (1 << ((bbsnumber - 1) % 8))); - else - return 0; -} - - -void set_fwd_bit(char *mask, int bbsnumber) -{ - if (bbsnumber) - mask[(bbsnumber - 1) / 8] |= (1 << ((bbsnumber - 1) % 8)); -} - - -void clear_fwd_bit (char *mask, int bbsnumber) -{ - if (bbsnumber) - mask[(bbsnumber - 1) / 8] &= (~(1 << ((bbsnumber - 1) % 8))); -} - -VOID BBSputs(CIRCUIT * conn, char * buf) -{ - // Sends to user and logs - - WriteLogLine(conn, '>',buf, (int)strlen(buf) -1, LOG_BBS); - - QueueMsg(conn, buf, (int)strlen(buf)); -} - -VOID __cdecl nodeprintf(ConnectionInfo * conn, const char * format, ...) -{ - char Mess[1000]; - int len; - va_list(arglist); - - - va_start(arglist, format); - len = vsprintf(Mess, format, arglist); - - QueueMsg(conn, Mess, len); - - WriteLogLine(conn, '>',Mess, len-1, LOG_BBS); - - return; -} - -// nodeprintfEx add a LF if NEEFLF is set - -VOID __cdecl nodeprintfEx(ConnectionInfo * conn, const char * format, ...) -{ - char Mess[1000]; - int len; - va_list(arglist); - - - va_start(arglist, format); - len = vsprintf(Mess, format, arglist); - - QueueMsg(conn, Mess, len); - - WriteLogLine(conn, '>',Mess, len-1, LOG_BBS); - - if (conn->BBSFlags & NEEDLF) - QueueMsg(conn, "\r", 1); - - return; -} - - -int compare( const void *arg1, const void *arg2 ); - -VOID SortBBSChain() -{ - struct UserInfo * user; - struct UserInfo * users[161]; - int i = 0, n; - - // Get array of addresses - - for (user = BBSChain; user; user = user->BBSNext) - { - users[i++] = user; - if (i > 160) break; - } - - qsort((void *)users, i, sizeof(void *), compare ); - - BBSChain = NULL; - - // Rechain (backwards, as entries ate put on front of chain) - - for (n = i-1; n >= 0; n--) - { - users[n]->BBSNext = BBSChain; - BBSChain = users[n]; - } -} - -int compare(const void *arg1, const void *arg2) -{ - // Compare Calls. Fortunately call is at start of stuct - - return _stricmp(*(char**)arg1 , *(char**)arg2); -} - -int CountMessagesTo(struct UserInfo * user, int * Unread) -{ - int i, Msgs = 0; - UCHAR * Call = user->Call; - - *Unread = 0; - - for (i = NumberofMessages; i > 0; i--) - { - if (MsgHddrPtr[i]->status == 'K') - continue; - - if (_stricmp(MsgHddrPtr[i]->to, Call) == 0) - { - Msgs++; - if (MsgHddrPtr[i]->status == 'N') - *Unread = *Unread + 1; - } - } - return(Msgs); -} - - - -// Custimised message handling routines. -/* - Variables - a subset of those used by FBB - - $C : Number of the next message. - $I : First name of the connected user. - $L : Number of the latest message. - $N : Number of active messages - $U : Callsign of the connected user. - $W : Inserts a carriage return. - $Z : Last message read by the user (L command). - %X : Number of messages for the user. - %x : Number of new messages for the user. -*/ - -VOID ExpandAndSendMessage(CIRCUIT * conn, char * Msg, int LOG) -{ - char NewMessage[10000]; - char * OldP = Msg; - char * NewP = NewMessage; - char * ptr, * pptr; - size_t len; - char Dollar[] = "$"; - char CR[] = "\r"; - char num[20]; - int Msgs = 0, Unread = 0; - - ptr = strchr(OldP, '$'); - - while (ptr) - { - len = ptr - OldP; // Chars before $ - memcpy(NewP, OldP, len); - NewP += len; - - switch (*++ptr) - { - case 'I': // First name of the connected user. - - pptr = conn->UserPointer->Name; - break; - - case 'L': // Number of the latest message. - - sprintf(num, "%d", LatestMsg); - pptr = num; - break; - - case 'N': // Number of active messages. - - sprintf(num, "%d", NumberofMessages); - pptr = num; - break; - - case 'U': // Callsign of the connected user. - - pptr = conn->UserPointer->Call; - break; - - case 'W': // Inserts a carriage return. - - pptr = CR; - break; - - case 'Z': // Last message read by the user (L command). - - sprintf(num, "%d", conn->UserPointer->lastmsg); - pptr = num; - break; - - case 'X': // Number of messages for the user. - - Msgs = CountMessagesTo(conn->UserPointer, &Unread); - sprintf(num, "%d", Msgs); - pptr = num; - break; - - case 'x': // Number of new messages for the user. - - Msgs = CountMessagesTo(conn->UserPointer, &Unread); - sprintf(num, "%d", Unread); - pptr = num; - break; - - case 'F': // Number of new messages to forward to this BBS. - - Msgs = CountMessagestoForward(conn->UserPointer); - sprintf(num, "%d", Msgs); - pptr = num; - break; - - default: - - pptr = Dollar; // Just Copy $ - } - - len = strlen(pptr); - memcpy(NewP, pptr, len); - NewP += len; - - OldP = ++ptr; - ptr = strchr(OldP, '$'); - } - - strcpy(NewP, OldP); - - len = RemoveLF(NewMessage, (int)strlen(NewMessage)); - - WriteLogLine(conn, '>', NewMessage, (int)len, LOG); - QueueMsg(conn, NewMessage, (int)len); -} - -BOOL isdigits(char * string) -{ - // Returns TRUE id sting is decimal digits - - size_t i, n = strlen(string); - - for (i = 0; i < n; i++) - { - if (isdigit(string[i]) == FALSE) return FALSE; - } - return TRUE; -} - -BOOL wildcardcompare(char * Target, char * Match) -{ - // Do a compare with string *string string* *string* - - // Strings should all be UC - - char Pattern[100]; - char * firststar; - - strcpy(Pattern, Match); - firststar = strchr(Pattern,'*'); - - if (firststar) - { - size_t Len = strlen(Pattern); - - if (Pattern[0] == '*' && Pattern[Len - 1] == '*') // * at start and end - { - Pattern[Len - 1] = 0; - return !(strstr(Target, &Pattern[1]) == NULL); - } - if (Pattern[0] == '*') // * at start - { - // Compare the last len - 1 chars of Target - - size_t Targlen = strlen(Target); - size_t Comparelen = Targlen - (Len - 1); - - if (Len == 1) // Just * - return TRUE; - - if (Comparelen < 0) // Too Short - return FALSE; - - return (memcmp(&Target[Comparelen], &Pattern[1], Len - 1) == 0); - } - - // Must be * at end - compare first Len-1 char - - return (memcmp(Target, Pattern, Len - 1) == 0); - } - - // No WildCards - straight strcmp - return (strcmp(Target, Pattern) == 0); -} - -#ifndef LINBPQ - -PrintMessage(HDC hDC, struct MsgInfo * Msg); - -PrintMessages(HWND hDlg, int Count, int * Indexes) -{ - int i, CurrentMsgIndex; - char MsgnoText[10]; - int Msgno; - struct MsgInfo * Msg; - int Len = MAX_PATH; - BOOL hResult; - PRINTDLG pdx = {0}; - HDC hDC; - -// CHOOSEFONT cf; - LOGFONT lf; - HFONT hFont; - - - // Initialize the PRINTDLG structure. - - pdx.lStructSize = sizeof(PRINTDLG); - pdx.hwndOwner = hWnd; - pdx.hDevMode = NULL; - pdx.hDevNames = NULL; - pdx.hDC = NULL; - pdx.Flags = PD_RETURNDC | PD_COLLATE; - pdx.nMinPage = 1; - pdx.nMaxPage = 1000; - pdx.nCopies = 1; - pdx.hInstance = 0; - pdx.lpPrintTemplateName = NULL; - - // Invoke the Print property sheet. - - hResult = PrintDlg(&pdx); - - memset(&lf, 0, sizeof(LOGFONT)); - - /* - - // Initialize members of the CHOOSEFONT structure. - - cf.lStructSize = sizeof(CHOOSEFONT); - cf.hwndOwner = (HWND)NULL; - cf.hDC = pdx.hDC; - cf.lpLogFont = &lf; - cf.iPointSize = 0; - cf.Flags = CF_PRINTERFONTS | CF_FIXEDPITCHONLY; - cf.rgbColors = RGB(0,0,0); - cf.lCustData = 0L; - cf.lpfnHook = (LPCFHOOKPROC)NULL; - cf.lpTemplateName = (LPSTR)NULL; - cf.hInstance = (HINSTANCE) NULL; - cf.lpszStyle = (LPSTR)NULL; - cf.nFontType = PRINTER_FONTTYPE; - cf.nSizeMin = 0; - cf.nSizeMax = 0; - - // Display the CHOOSEFONT common-dialog box. - - ChooseFont(&cf); - - // Create a logical font based on the user's - // selection and return a handle identifying - // that font. -*/ - - lf.lfHeight = -56; - lf.lfWeight = 600; - lf.lfOutPrecision = 3; - lf.lfClipPrecision = 2; - lf.lfQuality = 1; - lf.lfPitchAndFamily = '1'; - strcpy (lf.lfFaceName, "Courier New"); - - hFont = CreateFontIndirect(&lf); - - if (hResult) - { - // User clicked the Print button, so use the DC and other information returned in the - // PRINTDLG structure to print the document. - - DOCINFO pdi; - - pdi.cbSize = sizeof(DOCINFO); - pdi.lpszDocName = "BBS Message Print"; - pdi.lpszOutput = NULL; - pdi.lpszDatatype = "RAW"; - pdi.fwType = 0; - - hDC = pdx.hDC; - - SelectObject(hDC, hFont); - - StartDoc(hDC, &pdi); - StartPage(hDC); - - for (i = 0; i < Count; i++) - { - SendDlgItemMessage(hDlg, 0, LB_GETTEXT, Indexes[i], (LPARAM)(LPCTSTR)&MsgnoText); - - Msgno = atoi(MsgnoText); - - for (CurrentMsgIndex = 1; CurrentMsgIndex <= NumberofMessages; CurrentMsgIndex++) - { - Msg = MsgHddrPtr[CurrentMsgIndex]; - - if (Msg->number == Msgno) - { - PrintMessage(hDC, Msg); - break; - } - } - } - - EndDoc(hDC); - } - - if (pdx.hDevMode != NULL) - GlobalFree(pdx.hDevMode); - if (pdx.hDevNames != NULL) - GlobalFree(pdx.hDevNames); - - if (pdx.hDC != NULL) - DeleteDC(pdx.hDC); - - return 0; -} - -PrintMessage(HDC hDC, struct MsgInfo * Msg) -{ - int Len = MAX_PATH; - char * MsgBytes; - char * Save; - int Msglen; - - StartPage(hDC); - - Save = MsgBytes = ReadMessageFile(Msg->number); - - Msglen = Msg->length; - - if (MsgBytes) - { - char Hddr[1000]; - char FullTo[100]; - int HRes, VRes; - char * ptr1, * ptr2; - int LineLen; - - RECT Rect; - - 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 * ptr; - ptr = strstr(MsgBytes, "Body:"); - if (ptr) - { - Msglen = atoi(ptr + 5); - ptr = strstr(ptr, "\r\n\r\n"); - } - if (ptr) - MsgBytes = ptr + 4; - } - - HRes = GetDeviceCaps(hDC, HORZRES) - 50; - VRes = GetDeviceCaps(hDC, VERTRES) - 50; - - Rect.top = 50; - Rect.left = 50; - Rect.right = HRes; - Rect.bottom = VRes; - - DrawText(hDC, Hddr, strlen(Hddr), &Rect, DT_CALCRECT | DT_WORDBREAK); - DrawText(hDC, Hddr, strlen(Hddr), &Rect, DT_WORDBREAK); - - // process message a line at a time. When page is full, output a page break - - ptr1 = MsgBytes; - ptr2 = ptr1; - - while (Msglen-- > 0) - { - if (*ptr1++ == '\r') - { - // Output this line - - // First check if it will fit - - Rect.top = Rect.bottom; - Rect.right = HRes; - Rect.bottom = VRes; - - LineLen = ptr1 - ptr2 - 1; - - if (LineLen == 0) // Blank line - Rect.bottom = Rect.top + 40; - else - DrawText(hDC, ptr2, ptr1 - ptr2 - 1, &Rect, DT_CALCRECT | DT_WORDBREAK); - - if (Rect.bottom >= VRes) - { - EndPage(hDC); - StartPage(hDC); - - Rect.top = 50; - Rect.bottom = VRes; - if (LineLen == 0) // Blank line - Rect.bottom = Rect.top + 40; - else - DrawText(hDC, ptr2, ptr1 - ptr2 - 1, &Rect, DT_CALCRECT | DT_WORDBREAK); - } - - if (LineLen == 0) // Blank line - Rect.bottom = Rect.top + 40; - else - DrawText(hDC, ptr2, ptr1 - ptr2 - 1, &Rect, DT_WORDBREAK); - - if (*(ptr1) == '\n') - { - ptr1++; - Msglen--; - } - - ptr2 = ptr1; - } - } - - free(Save); - - EndPage(hDC); - - } - return 0; -} - -#endif - - -int ImportMessages(CIRCUIT * conn, char * FN, BOOL Nopopup) -{ - char FileName[MAX_PATH] = "Messages.in"; - int Files = 0; - int WriteLen=0; - FILE *in; - CIRCUIT dummyconn; - struct UserInfo User; - int Index = 0; - - char Buffer[100000]; - char *buf = Buffer; - - if (FN[0]) // Name supplled - strcpy(FileName, FN); - - else - { -#ifndef LINBPQ - OPENFILENAME Ofn; - - memset(&Ofn, 0, sizeof(Ofn)); - - Ofn.lStructSize = sizeof(OPENFILENAME); - Ofn.hInstance = hInst; - Ofn.hwndOwner = MainWnd; - Ofn.lpstrFilter = NULL; - Ofn.lpstrFile= FileName; - Ofn.nMaxFile = sizeof(FileName)/ sizeof(*FileName); - Ofn.lpstrFileTitle = NULL; - Ofn.nMaxFileTitle = 0; - Ofn.lpstrInitialDir = BaseDir; - Ofn.Flags = OFN_SHOWHELP | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST; - Ofn.lpstrTitle = NULL;//; - - if (!GetOpenFileName(&Ofn)) - return 0; -#endif - } - - in = fopen(FileName, "rb"); - - if (!(in)) - { - char msg[500]; - sprintf_s(msg, sizeof(msg), "Failed to open %s", FileName); - if (conn) - nodeprintf(conn, "%s\r", msg); -#ifdef WIN32 - else - if (Nopopup == FALSE) - MessageBox(NULL, msg, "BPQMailChat", MB_OK); -#endif - return 0; - } - - memset(&dummyconn, 0, sizeof(CIRCUIT)); - memset(&User, 0, sizeof(struct UserInfo)); - - if (conn == 0) - { - conn = &dummyconn; - - dummyconn.UserPointer = &User; // Was SYSOPCall, but I think that is wrong. - strcpy(User.Call, "IMPORT"); - User.flags |= F_EMAIL; - dummyconn.sysop = TRUE; - dummyconn.BBSFlags = BBS; - - strcpy(dummyconn.Callsign, "IMPORT"); - } - - while(fgets(Buffer, 99999, in)) - { - // First line should start SP/SB ?ST? - - char * From = NULL; - char * BID = NULL; - char * ATBBS = NULL; - char seps[] = " \t\r"; - struct MsgInfo * Msg; - char To[100]= ""; - int msglen; - char * Context; - char * Arg1, * Cmd; - -NextMessage: - - From = NULL; - BID = NULL; - ATBBS = NULL; - To[0]= 0; - - Sleep(100); - - strlop(Buffer, 10); - strlop(Buffer, 13); // Remove cr and/or lf - - if (Buffer[0] == 0) //Blank Line - continue; - - WriteLogLine(conn, '>', Buffer, (int)strlen(Buffer), LOG_BBS); - - if (dummyconn.sysop == 0) - { - nodeprintf(conn, "%s\r", Buffer); - Flush(conn); - } - - Cmd = strtok_s(Buffer, seps, &Context); - - if (Cmd == NULL) - { - fclose(in); - return Files; - } - - Arg1 = strtok_s(NULL, seps, &Context); - - if (Arg1 == NULL) - { - if (dummyconn.sysop) - Debugprintf("Bad Import Line %s", Buffer); - else - nodeprintf(conn, "Bad Import Line %s\r", Buffer); - - fclose(in); - return Files; - } - - strcpy(To, Arg1); - - if (DecodeSendParams(conn, Context, &From, To, &ATBBS, &BID)) - { - if (CreateMessage(conn, From, To, ATBBS, toupper(Cmd[1]), BID, NULL)) - { - Msg = conn->TempMsg; - - // SP is Ok, read message; - - ClearQueue(conn); - - fgets(Buffer, 99999, in); - strlop(Buffer, 10); - strlop(Buffer, 13); // Remove cr and/or lf - if (strlen(Buffer) > 60) - Buffer[60] = 0; - - strcpy(Msg->title, Buffer); - - // Read the lines - - conn->Flags |= GETTINGMESSAGE; - - Buffer[0] = 0; - - fgets(Buffer, 99999, in); - - while ((conn->Flags & GETTINGMESSAGE) && Buffer[0]) - { - strlop(Buffer, 10); - strlop(Buffer, 13); // Remove cr and/or lf - msglen = (int)strlen(Buffer); - Buffer[msglen++] = 13; - ProcessMsgLine(conn, conn->UserPointer,Buffer, msglen); - - Buffer[0] = 0; - fgets(Buffer, 99999, in); - } - - // Message completed (or off end of file) - - Files ++; - - ClearQueue(conn); - - if (Buffer[0]) - goto NextMessage; // We have read the SP/SB line; - else - { - fclose(in); - return Files; - } - } - else - { - // Create failed - - Flush(conn); - } - } - - // Search for next message - - Buffer[0] = 0; - fgets(Buffer, 99999, in); - - while (Buffer[0]) - { - strlop(Buffer, 10); - strlop(Buffer, 13); // Remove cr and/or lf - - if (_stricmp(Buffer, "/EX") == 0) - { - // Found end - - Buffer[0] = 0; - fgets(Buffer, 99999, in); - - if (dummyconn.sysop) - ClearQueue(conn); - else - Flush(conn); - - if (Buffer[0]) - goto NextMessage; // We have read the SP/SB line; - } - - Buffer[0] = 0; - fgets(Buffer, 99999, in); - } - } - - fclose(in); - - if (dummyconn.sysop) - ClearQueue(conn); - else - Flush(conn); - - return Files; -} -char * ReadMessageFileEx(struct MsgInfo * MsgRec) -{ - // Sets Message Size from File Size - - int msgno = MsgRec->number; - int FileSize; - char MsgFile[MAX_PATH]; - FILE * hFile; - char * MsgBytes; - struct stat STAT; - - sprintf_s(MsgFile, sizeof(MsgFile), "%s/m_%06d.mes", MailDir, msgno); - - if (stat(MsgFile, &STAT) == -1) - return NULL; - - FileSize = STAT.st_size; - - hFile = fopen(MsgFile, "rb"); - - if (hFile == NULL) - return NULL; - - MsgBytes=malloc(FileSize+1); - - fread(MsgBytes, 1, FileSize, hFile); - - fclose(hFile); - - MsgBytes[FileSize]=0; - MsgRec->length = FileSize; - - return MsgBytes; -} - -char * ReadMessageFile(int msgno) -{ - int FileSize; - char MsgFile[MAX_PATH]; - FILE * hFile; - char * MsgBytes; - struct stat STAT; - - sprintf_s(MsgFile, sizeof(MsgFile), "%s/m_%06d.mes", MailDir, msgno); - - if (stat(MsgFile, &STAT) == -1) - return NULL; - - FileSize = STAT.st_size; - - hFile = fopen(MsgFile, "rb"); - - if (hFile == NULL) - return NULL; - - MsgBytes = malloc(FileSize + 100); // A bit of space for alias substitution on B2 - - fread(MsgBytes, 1, FileSize, hFile); - - fclose(hFile); - - MsgBytes[FileSize]=0; - - return MsgBytes; -} - - -int QueueMsg(ConnectionInfo * conn, char * msg, int len) -{ - // Add Message to queue for this connection - - // UCHAR * OutputQueue; // Messages to user - // int OutputQueueLength; // Total Malloc'ed size. Also Put Pointer for next Message - // int OutputGetPointer; // Next byte to send. When Getpointer = Quele Length all is sent - free the buffer and start again. - - // Create or extend buffer - - GetSemaphore(&OutputSEM, 0); - - conn->OutputQueue=realloc(conn->OutputQueue, conn->OutputQueueLength + len); - - if (conn->OutputQueue == NULL) - { - // relloc failed - should never happen, but clean up - - CriticalErrorHandler("realloc failed to expand output queue"); - FreeSemaphore(&OutputSEM); - return 0; - } - - memcpy(&conn->OutputQueue[conn->OutputQueueLength], msg, len); - conn->OutputQueueLength += len; - FreeSemaphore(&OutputSEM); - - return len; -} - -void TrytoSend() -{ - // call Flush on any connected streams with queued data - - ConnectionInfo * conn; - struct ConsoleInfo * Cons; - - int n; - - for (n = 0; n < NumberofStreams; n++) - { - conn = &Connections[n]; - - if (conn->Active == TRUE) - { - Flush(conn); - - // if an FLARQ mail has been sent see if queues have cleared - - if (conn->BBSFlags & YAPPTX) - { - YAPPSendData(conn); - } - else if (conn->OutputQueue == NULL && (conn->BBSFlags & ARQMAILACK)) - { - int n = TXCount(conn->BPQStream); // All Sent and Acked? - - if (n == 0) - { - struct MsgInfo * Msg = conn->FwdMsg; - - conn->ARQClearCount--; - - if (conn->ARQClearCount <= 0) - { - Logprintf(LOG_BBS, conn, '>', "ARQ Send Complete"); - - // Mark mail as sent, and look for more - - clear_fwd_bit(Msg->fbbs, conn->UserPointer->BBSNumber); - set_fwd_bit(Msg->forw, conn->UserPointer->BBSNumber); - - // Only mark as forwarded if sent to all BBSs that should have it - - if (memcmp(Msg->fbbs, zeros, NBMASK) == 0) - { - Msg->status = 'F'; // Mark as forwarded - Msg->datechanged=time(NULL); - } - - conn->BBSFlags &= ~ARQMAILACK; - conn->UserPointer->ForwardingInfo->MsgCount--; - - SaveMessageDatabase(); - SendARQMail(conn); // See if any more - close if not - } - } - else - conn->ARQClearCount = 10; - } - } - } -#ifndef LINBPQ - for (Cons = ConsHeader[0]; Cons; Cons = Cons->next) - { - if (Cons->Console) - Flush(Cons->Console); - } -#endif -} - - -void Flush(CIRCUIT * conn) -{ - int tosend, len, sent; - - // Try to send data to user. May be stopped by user paging or node flow control - - // UCHAR * OutputQueue; // Messages to user - // int OutputQueueLength; // Total Malloc'ed size. Also Put Pointer for next Message - // int OutputGetPointer; // Next byte to send. When Getpointer = Quele Length all is sent - free the buffer and start again. - - // BOOL Paging; // Set if user wants paging - // int LinesSent; // Count when paging - // int PageLen; // Lines per page - - - if (conn->OutputQueue == NULL) - { - // Nothing to send. If Close after Flush is set, disconnect - - if (conn->CloseAfterFlush) - { - conn->CloseAfterFlush--; - - if (conn->CloseAfterFlush) - return; - - Disconnect(conn->BPQStream); - conn->ErrorCount = 0; - } - - return; // Nothing to send - } - tosend = conn->OutputQueueLength - conn->OutputGetPointer; - - sent=0; - - while (tosend > 0) - { - if (TXCount(conn->BPQStream) > 15) - return; // Busy - - if (conn->BBSFlags & SYSOPCHAT) // Suspend queued output while sysop chatting - return; - - if (conn->Paging && (conn->LinesSent >= conn->PageLen)) - return; - - if (tosend <= conn->paclen) - len=tosend; - else - len=conn->paclen; - - GetSemaphore(&OutputSEM, 0); - - if (conn->Paging) - { - // look for CR chars in message to send. Increment LinesSent, and stop if at limit - - UCHAR * ptr1 = &conn->OutputQueue[conn->OutputGetPointer]; - UCHAR * ptr2; - int lenleft = len; - - ptr2 = memchr(ptr1, 0x0d, len); - - while (ptr2) - { - conn->LinesSent++; - ptr2++; - lenleft = len - (int)(ptr2 - ptr1); - - if (conn->LinesSent >= conn->PageLen) - { - len = (int)(ptr2 - &conn->OutputQueue[conn->OutputGetPointer]); - - SendUnbuffered(conn->BPQStream, &conn->OutputQueue[conn->OutputGetPointer], len); - conn->OutputGetPointer+=len; - tosend-=len; - SendUnbuffered(conn->BPQStream, "bort, Continue..>", 25); - FreeSemaphore(&OutputSEM); - return; - - } - ptr2 = memchr(ptr2, 0x0d, lenleft); - } - } - - SendUnbuffered(conn->BPQStream, &conn->OutputQueue[conn->OutputGetPointer], len); - - conn->OutputGetPointer+=len; - - FreeSemaphore(&OutputSEM); - - tosend-=len; - sent++; - - if (sent > 15) - return; - } - - // All Sent. Free buffers and reset pointers - - conn->LinesSent = 0; - - ClearQueue(conn); -} - -VOID ClearQueue(ConnectionInfo * conn) -{ - if (conn->OutputQueue == NULL) - return; - - GetSemaphore(&OutputSEM, 0); - - free(conn->OutputQueue); - - conn->OutputQueue=NULL; - conn->OutputGetPointer=0; - conn->OutputQueueLength=0; - - FreeSemaphore(&OutputSEM); -} - - - -VOID FlagAsKilled(struct MsgInfo * Msg, BOOL SaveDB) -{ - struct UserInfo * user; - - Msg->status='K'; - Msg->datechanged=time(NULL); - - // Remove any forwarding references - - if (memcmp(Msg->fbbs, zeros, NBMASK) != 0) - { - for (user = BBSChain; user; user = user->BBSNext) - { - if (check_fwd_bit(Msg->fbbs, user->BBSNumber)) - { - user->ForwardingInfo->MsgCount--; - clear_fwd_bit(Msg->fbbs, user->BBSNumber); - } - } - } - if (SaveDB) - SaveMessageDatabase(); - RebuildNNTPList(); -} - -void DoDeliveredCommand(CIRCUIT * conn, struct UserInfo * user, char * Cmd, char * Arg1, char * Context) -{ - int msgno=-1; - struct MsgInfo * Msg; - - while (Arg1) - { - msgno = atoi(Arg1); - - if (msgno > 100000) - { - BBSputs(conn, "Message Number too high\r"); - return; - } - - Msg = GetMsgFromNumber(msgno); - - if (Msg == NULL) - { - nodeprintf(conn, "Message %d not found\r", msgno); - goto Next; - } - - if (Msg->type != 'T') - { - nodeprintf(conn, "Message %d not an NTS Message\r", msgno); - goto Next; - } - - if (Msg->status == 'N') - nodeprintf(conn, "Warning - Message has status N\r"); - - Msg->status = 'D'; - Msg->datechanged=time(NULL); - SaveMessageDatabase(); - - nodeprintf(conn, "Message #%d Flagged as Delivered\r", msgno); - Next: - Arg1 = strtok_s(NULL, " \r", &Context); - } - - return; -} - -void DoUnholdCommand(CIRCUIT * conn, struct UserInfo * user, char * Cmd, char * Arg1, char * Context) -{ - int msgno=-1; - int i; - struct MsgInfo * Msg; - - // Param is either ALL or a list of numbers - - if (Arg1 == NULL) - { - nodeprintf(conn, "No message number\r"); - return; - } - - if (_stricmp(Arg1, "ALL") == 0) - { - for (i=NumberofMessages; i>0; i--) - { - Msg = MsgHddrPtr[i]; - - if (Msg->status == 'H') - { - if (Msg->type == 'B' && memcmp(Msg->fbbs, zeros, NBMASK) != 0) - Msg->status = '$'; // Has forwarding - else - Msg->status = 'N'; - - nodeprintf(conn, "Message #%d Unheld\r", Msg->number); - } - } - return; - } - - while (Arg1) - { - msgno = atoi(Arg1); - Msg = GetMsgFromNumber(msgno); - - if (Msg) - { - if (Msg->status == 'H') - { - if (Msg->type == 'B' && memcmp(Msg->fbbs, zeros, NBMASK) != 0) - Msg->status = '$'; // Has forwarding - else - Msg->status = 'N'; - - nodeprintf(conn, "Message #%d Unheld\r", msgno); - } - else - { - nodeprintf(conn, "Message #%d was not held\r", msgno); - } - } - else - nodeprintf(conn, "Message #%d not found\r", msgno); - - Arg1 = strtok_s(NULL, " \r", &Context); - } - - return; -} - -void DoKillCommand(CIRCUIT * conn, struct UserInfo * user, char * Cmd, char * Arg1, char * Context) -{ - int msgno=-1; - int i; - struct MsgInfo * Msg; - - switch (toupper(Cmd[1])) - { - - case 0: // Just K - - while (Arg1) - { - msgno = atoi(Arg1); - KillMessage(conn, user, msgno); - - Arg1 = strtok_s(NULL, " \r", &Context); - } - - SaveMessageDatabase(); - return; - - case 'M': // Kill Mine - - for (i=NumberofMessages; i>0; i--) - { - Msg = MsgHddrPtr[i]; - - if ((_stricmp(Msg->to, user->Call) == 0) || (conn->sysop && _stricmp(Msg->to, "SYSOP") == 0 && user->flags & F_SYSOP_IN_LM)) - { - if (Msg->type == 'P' && Msg->status == 'Y') - { - FlagAsKilled(Msg, FALSE); - nodeprintf(conn, "Message #%d Killed\r", Msg->number); - } - } - } - - SaveMessageDatabase(); - return; - - case 'H': // Kill Held - - if (conn->sysop) - { - for (i=NumberofMessages; i>0; i--) - { - Msg = MsgHddrPtr[i]; - - if (Msg->status == 'H') - { - FlagAsKilled(Msg, FALSE); - nodeprintf(conn, "Message #%d Killed\r", Msg->number); - } - } - } - SaveMessageDatabase(); - return; - - case '>': // K> - Kill to - - if (conn->sysop) - { - if (Arg1) - if (KillMessagesTo(conn, user, Arg1) == 0) - BBSputs(conn, "No Messages found\r"); - - return; - } - - case '<': - - if (conn->sysop) - { - if (Arg1) - if (KillMessagesFrom(conn, user, Arg1) == 0); - BBSputs(conn, "No Messages found\r"); - - return; - } - } - - nodeprintf(conn, "*** Error: Invalid Kill option %c\r", Cmd[1]); - - return; - -} - -int KillMessagesTo(ConnectionInfo * conn, struct UserInfo * user, char * Call) -{ - int i, Msgs = 0; - struct MsgInfo * Msg; - - for (i=NumberofMessages; i>0; i--) - { - Msg = MsgHddrPtr[i]; - if (Msg->status != 'K' && _stricmp(Msg->to, Call) == 0) - { - Msgs++; - KillMessage(conn, user, MsgHddrPtr[i]->number); - } - } - - SaveMessageDatabase(); - return(Msgs); -} - -int KillMessagesFrom(ConnectionInfo * conn, struct UserInfo * user, char * Call) -{ - int i, Msgs = 0; - struct MsgInfo * Msg; - - - for (i=NumberofMessages; i>0; i--) - { - Msg = MsgHddrPtr[i]; - if (Msg->status != 'K' && _stricmp(Msg->from, Call) == 0) - { - Msgs++; - KillMessage(conn, user, MsgHddrPtr[i]->number); - } - } - - SaveMessageDatabase(); - return(Msgs); -} - -BOOL OkToKillMessage(BOOL SYSOP, char * Call, struct MsgInfo * Msg) -{ - if (SYSOP || (Msg->type == 'T' && UserCantKillT == FALSE)) - return TRUE; - - if (Msg->type == 'P') - if ((_stricmp(Msg->to, Call) == 0) || (_stricmp(Msg->from, Call) == 0)) - return TRUE; - - if (Msg->type == 'B') - if (_stricmp(Msg->from, Call) == 0) - return TRUE; - - return FALSE; -} - -void KillMessage(ConnectionInfo * conn, struct UserInfo * user, int msgno) -{ - struct MsgInfo * Msg; - - Msg = GetMsgFromNumber(msgno); - - if (Msg == NULL || Msg->status == 'K') - { - nodeprintf(conn, "Message %d not found\r", msgno); - return; - } - - if (OkToKillMessage(conn->sysop, user->Call, Msg)) - { - FlagAsKilled(Msg, FALSE); - nodeprintf(conn, "Message #%d Killed\r", msgno); - } - else - nodeprintf(conn, "Not your message\r"); -} - - -BOOL ListMessage(struct MsgInfo * Msg, ConnectionInfo * conn, struct TempUserInfo * Temp) -{ - char FullFrom[80]; - char FullTo[80]; - - strcpy(FullFrom, Msg->from); - - if ((_stricmp(Msg->from, "RMS:") == 0) || (_stricmp(Msg->from, "SMTP:") == 0) || - Temp->SendFullFrom || (_stricmp(Msg->emailfrom, "@winlink.org") == 0)) - strcat(FullFrom, Msg->emailfrom); - - if (_stricmp(Msg->to, "RMS") == 0) - { - sprintf(FullTo, "RMS:%s", Msg->via); - nodeprintf(conn, "%-6d %s %c%c %5d %-7s %-6s %-s\r", - Msg->number, FormatDateAndTime((time_t)Msg->datecreated, TRUE), Msg->type, Msg->status, Msg->length, FullTo, FullFrom, Msg->title); - } - else - - if (Msg->to[0] == 0 && Msg->via[0] != 0) - { - sprintf(FullTo, "smtp:%s", Msg->via); - nodeprintf(conn, "%-6d %s %c%c %5d %-7s %-6s %-s\r", - Msg->number, FormatDateAndTime((time_t)Msg->datecreated, TRUE), Msg->type, Msg->status, Msg->length, FullTo, FullFrom, Msg->title); - } - - else - if (Msg->via[0] != 0) - { - char Via[80]; - strcpy(Via, Msg->via); - strlop(Via, '.'); // Only show first part of via - nodeprintf(conn, "%-6d %s %c%c %5d %-7s@%-6s %-6s %-s\r", - Msg->number, FormatDateAndTime((time_t)Msg->datecreated, TRUE), Msg->type, Msg->status, Msg->length, Msg->to, Via, FullFrom, Msg->title); - } - else - nodeprintf(conn, "%-6d %s %c%c %5d %-7s %-6s %-s\r", - Msg->number, FormatDateAndTime((time_t)Msg->datecreated, TRUE), Msg->type, Msg->status, Msg->length, Msg->to, FullFrom, Msg->title); - - // if paging, stop two before page lengh. This lets us send the continue prompt, save status - // and exit without triggering the system paging code. We can then read a message then resume listing - - if (Temp->ListActive && conn->Paging) - { - Temp->LinesSent++; - - if ((Temp->LinesSent + 1) >= conn->PageLen) - { - nodeprintf(conn, "bort, , = Continue..>"); - Temp->LastListedInPagedMode = Msg->number; - Temp->ListSuspended = TRUE; - return TRUE; - } - } - - return FALSE; -} - -void DoListCommand(ConnectionInfo * conn, struct UserInfo * user, char * Cmd, char * Arg1, BOOL Resuming, char * Context) -{ - struct TempUserInfo * Temp = user->Temp; - struct MsgInfo * Msg; - - // Allow compound selection, eg LTN or LFP - - // types P N T - // Options LL LR L< L> L@ LM LC (L* used internally for just L, ie List New - // Status N Y H F K D - - // Allowing options in any order complicates paging. May be best to parse options once and restore if paging. - - Temp->ListActive = TRUE; - Temp->LinesSent = 0; - - if (Resuming) - { - // Entered after a paging pause. Selection fields are already set up - - // We have reentered list command after a pause. The next message to list is in Temp->LastListedInPagedMode - -// Start = Temp->LastListedInPagedMode; - Temp->ListSuspended = FALSE; - } - else - { - Temp->ListRangeEnd = LatestMsg; - Temp->ListRangeStart = 1; - Temp->LLCount = 0; - Temp->SendFullFrom = 0; - Temp->ListType = 0; - Temp->ListStatus = 0; - Temp->ListSelector = 0; - Temp->UpdateLatest = 0; - Temp->LastListParams[0] = 0; - Temp->IncludeKilled = 1; // SYSOP include Killed except LM - - //Analyse L params. - - _strupr(Cmd); - - if (strcmp(Cmd, "LC") == 0) // List Bull Categories - { - ListCategories(conn); - return; - } - - // if command is just L or LR start from last listed - - if (Arg1 == NULL) - { - if (strcmp(Cmd, "L") == 0 || strcmp(Cmd, "LR") == 0) - { - if (LatestMsg == conn->lastmsg) - { - BBSputs(conn, "No New Messages\r"); - return; - } - - Temp->UpdateLatest = 1; - Temp->ListRangeStart = conn->lastmsg; - } - } - - if (strchr(Cmd, 'V')) // Verbose - Temp->SendFullFrom = 'V'; - - if (strchr(Cmd, 'R')) - Temp->ListDirn = 'R'; - else - Temp->ListDirn = '*'; // Default newest first - - Cmd++; // skip L - - if (strchr(Cmd, 'T')) - Temp->ListType = 'T'; - else if (strchr(Cmd, 'P')) - Temp->ListType = 'P'; - else if (strchr(Cmd, 'B')) - Temp->ListType = 'B'; - - if (strchr(Cmd, 'N')) - Temp->ListStatus = 'N'; - else if (strchr(Cmd, 'Y')) - Temp->ListStatus = 'Y'; - else if (strchr(Cmd, 'F')) - Temp->ListStatus = 'F'; - else if (strchr(Cmd, '$')) - Temp->ListStatus = '$'; - else if (strchr(Cmd, 'H')) - Temp->ListStatus = 'H'; - else if (strchr(Cmd, 'K')) - Temp->ListStatus = 'K'; - else if (strchr(Cmd, 'D')) - Temp->ListStatus = 'D'; - - // H or K only by Sysop - - switch (Temp->ListStatus) - { - case 'K': - case 'H': // List Status - - if (conn->sysop) - break; - - BBSputs(conn, "LH or LK can only be used by SYSOP\r"); - return; - } - - if (strchr(Cmd, '<')) - Temp->ListSelector = '<'; - else if (strchr(Cmd, '>')) - Temp->ListSelector = '>'; - else if (strchr(Cmd, '@')) - Temp->ListSelector = '@'; - else if (strchr(Cmd, 'M')) - { - Temp->ListSelector = 'M'; - Temp->IncludeKilled = FALSE; - } - - // Param could be single number, number range or call - - if (Arg1) - { - if (strchr(Cmd, 'L')) // List Last - { - // Param is number - - if (Arg1) - Temp->LLCount = atoi(Arg1); - } - else - { - // Range nnn-nnn or single value or callsign - - char * Arg2, * Arg3, * Range; - char seps[] = " \t\r"; - UINT From=LatestMsg, To=0; - - Arg2 = strtok_s(NULL, seps, &Context); - Arg3 = strtok_s(NULL, seps, &Context); - - if (Temp->ListSelector && Temp->ListSelector != 'M') - { - // < > or @ - first param is callsign - - strcpy(Temp->LastListParams, Arg1); - - // Just possible number range - - Arg1 = Arg2; - Arg2 = Arg3; - Arg3 = strtok_s(NULL, seps, &Context); - } - - if (Arg1) - { - Range = strchr(Arg1, '-'); - - // A number could be a Numeric Bull Dest (eg 44) - // I think this can only resaonably be > - - if (isdigits(Arg1)) - To = From = atoi(Arg1); - - if (Arg2) - From = atoi(Arg2); - else - { - if (Range) - { - Arg3 = strlop(Arg1, '-'); - - To = atoi(Arg1); - - if (Arg3 && Arg3[0]) - From = atoi(Arg3); - else - From = LatestMsg; - } - } - if (From > 100000 || To > 100000) - { - BBSputs(conn, "Message Number too high\r"); - return; - } - Temp->ListRangeStart = To; - Temp->ListRangeEnd = From; - } - } - } - } - - // Run through all messages (either forwards or backwards) and list any that match all selection criteria - - while (1) - { - if (Temp->ListDirn == 'R') - Msg = GetMsgFromNumber(Temp->ListRangeStart); - else - Msg = GetMsgFromNumber(Temp->ListRangeEnd); - - - if (Msg && CheckUserMsg(Msg, user->Call, conn->sysop, Temp->IncludeKilled)) // Check if user is allowed to list this message - { - // Check filters - - if (Temp->ListStatus && Temp->ListStatus != Msg->status) - goto skip; - - if (Temp->ListType && Temp->ListType != Msg->type) - goto skip; - - if (Temp->ListSelector == '<') - if (_stricmp(Msg->from, Temp->LastListParams) != 0) - goto skip; - - if (Temp->ListSelector == '>') - if (_stricmp(Msg->to, Temp->LastListParams) != 0) - goto skip; - - if (Temp->ListSelector == '@') - if (_memicmp(Msg->via, Temp->LastListParams, strlen(Temp->LastListParams)) != 0 && - (_stricmp(Temp->LastListParams, "SMTP:") != 0 || Msg->to[0] != 0)) - goto skip; - - if (Temp->ListSelector == 'M') - if (_stricmp(Msg->to, user->Call) != 0 && - (_stricmp(Msg->to, "SYSOP") != 0 || ((user->flags & F_SYSOP_IN_LM) == 0))) - - goto skip; - - if (ListMessage(Msg, conn, Temp)) - { - if (Temp->ListDirn == 'R') - Temp->ListRangeStart++; - else - Temp->ListRangeEnd--; - - return; // Hit page limit - } - - if (Temp->LLCount) - { - Temp->LLCount--; - if (Temp->LLCount == 0) - return; // LL count reached - } -skip:; - } - - if (Temp->ListRangeStart == Temp->ListRangeEnd) - { - // if using L or LR (list new) update last listed field - - if (Temp->UpdateLatest) - conn->lastmsg = LatestMsg; - - return; - } - - if (Temp->ListDirn == 'R') - Temp->ListRangeStart++; - else - Temp->ListRangeEnd--; - - if (Temp->ListRangeStart > 100000 || Temp->ListRangeEnd < 0) // Loop protection! - return; - - } - -/* - - switch (Cmd[0]) - { - - case '*': // Just L - case 'R': // LR = List Reverse - - if (Arg1) - { - // Range nnn-nnn or single value - - char * Arg2, * Arg3; - char * Context; - char seps[] = " -\t\r"; - UINT From=LatestMsg, To=0; - char * Range = strchr(Arg1, '-'); - - Arg2 = strtok_s(Arg1, seps, &Context); - Arg3 = strtok_s(NULL, seps, &Context); - - if (Arg2) - To = From = atoi(Arg2); - - if (Arg3) - From = atoi(Arg3); - else - if (Range) - From = LatestMsg; - - if (From > 100000 || To > 100000) - { - BBSputs(conn, "Message Number too high\r"); - return; - } - - if (Cmd[1] == 'R') - { - if (Start) - To = Start + 1; - - ListMessagesInRangeForwards(conn, user, user->Call, From, To, Temp->SendFullFrom); - } - else - { - if (Start) - From = Start - 1; - - ListMessagesInRange(conn, user, user->Call, From, To, Temp->SendFullFrom); - } - } - else - - if (LatestMsg == conn->lastmsg) - BBSputs(conn, "No New Messages\r"); - else if (Cmd[1] == 'R') - ListMessagesInRangeForwards(conn, user, user->Call, LatestMsg, conn->lastmsg + 1, SendFullFrom); - else - ListMessagesInRange(conn, user, user->Call, LatestMsg, conn->lastmsg + 1, SendFullFrom); - - conn->lastmsg = LatestMsg; - - return; - - - case 'L': // List Last - - if (Arg1) - { - int i = atoi(Arg1); - int m = NumberofMessages; - - if (Resuming) - i = Temp->LLCount; - else - Temp->LLCount = i; - - for (; i>0 && m != 0; i--) - { - m = GetUserMsg(m, user->Call, conn->sysop); - - if (m > 0) - { - if (Start && MsgHddrPtr[m]->number >= Start) - { - m--; - i++; - continue; - } - - Temp->LLCount--; - - if (ListMessage(MsgHddrPtr[m], conn, SendFullFrom)) - return; // Hit page limit - m--; - } - } - } - return; - - case 'M': // LM - List Mine - - if (ListMessagesTo(conn, user, user->Call, SendFullFrom, Start) == 0) - BBSputs(conn, "No Messages found\r"); - return; - - case '>': // L> - List to - - if (Arg1) - if (ListMessagesTo(conn, user, Arg1, SendFullFrom, Start) == 0) - BBSputs(conn, "No Messages found\r"); - - - return; - - case '<': - - if (Arg1) - if (ListMessagesFrom(conn, user, Arg1, SendFullFrom, Start) == 0) - BBSputs(conn, "No Messages found\r"); - - return; - - case '@': - - if (Arg1) - if (ListMessagesAT(conn, user, Arg1, SendFullFrom, Start) == 0) - BBSputs(conn, "No Messages found\r"); - - return; - - case 'N': - case 'Y': - case 'F': - case '$': - case 'D': // Delivered NTS Traffic can be listed by anyone - { - int m = NumberofMessages; - - while (m > 0) - { - m = GetUserMsg(m, user->Call, conn->sysop); - - if (m > 0) - { - if (Start && MsgHddrPtr[m]->number >= Start) - { - m--; - continue; - } - - if (Temp->ListType) - { - if (MsgHddrPtr[m]->status == Cmd[1] && MsgHddrPtr[m]->type == Temp->ListType) - if (ListMessage(MsgHddrPtr[m], conn, SendFullFrom)) - return; // Hit page limit - } - else - { - if (MsgHddrPtr[m]->status == toupper(Cmd[1])) - if (ListMessage(MsgHddrPtr[m], conn, SendFullFrom)) - return; // Hit page limit - } - m--; - } - } - } - return; - - case 'K': - case 'H': // List Status - - if (conn->sysop) - { - int i, Msgs = Start; - - for (i=NumberofMessages; i>0; i--) - { - if (Start && MsgHddrPtr[i]->number >= Start) - continue; - - if (MsgHddrPtr[i]->status == toupper(Cmd[1])) - { - Msgs++; - if (ListMessage(MsgHddrPtr[i], conn, SendFullFrom)) - return; // Hit page limit - - } - } - - if (Msgs == 0) - BBSputs(conn, "No Messages found\r"); - } - else - BBSputs(conn, "LH or LK can only be used by SYSOP\r"); - - return; - - case 'C': - { - struct NNTPRec * ptr = FirstNNTPRec; - char Cat[100]; - char NextCat[100]; - int Line = 0; - int Count; - - while (ptr) - { - // if the next name is the same, combine counts - - strcpy(Cat, ptr->NewsGroup); - strlop(Cat, '.'); - Count = ptr->Count; - Catloop: - if (ptr->Next) - { - strcpy(NextCat, ptr->Next->NewsGroup); - strlop(NextCat, '.'); - if (strcmp(Cat, NextCat) == 0) - { - ptr = ptr->Next; - Count += ptr->Count; - goto Catloop; - } - } - - nodeprintf(conn, "%-6s %-3d", Cat, Count); - Line += 10; - if (Line > 80) - { - Line = 0; - nodeprintf(conn, "\r"); - } - - ptr = ptr->Next; - } - - if (Line) - nodeprintf(conn, "\r\r"); - else - nodeprintf(conn, "\r"); - - return; - } - } - - // Could be P B or T if specified without a status - - switch (Temp->ListType) - { - case 'P': - case 'B': - case 'T': // NTS Traffic can be listed by anyone - { - int m = NumberofMessages; - - while (m > 0) - { - m = GetUserMsg(m, user->Call, conn->sysop); - - if (m > 0) - { - if (Start && MsgHddrPtr[m]->number >= Start) - { - m--; - continue; - } - - if (MsgHddrPtr[m]->type == Temp->ListType) - if (ListMessage(MsgHddrPtr[m], conn, SendFullFrom)) - return; // Hit page limit - m--; - } - } - - return; - } - } - -*/ - nodeprintf(conn, "*** Error: Invalid List option %c\r", Cmd[1]); - -} - -void ListCategories(ConnectionInfo * conn) -{ - // list bull categories - struct NNTPRec * ptr = FirstNNTPRec; - char Cat[100]; - char NextCat[100]; - int Line = 0; - int Count; - - while (ptr) - { - // if the next name is the same, combine counts - - strcpy(Cat, ptr->NewsGroup); - strlop(Cat, '.'); - Count = ptr->Count; -Catloop: - if (ptr->Next) - { - strcpy(NextCat, ptr->Next->NewsGroup); - strlop(NextCat, '.'); - if (strcmp(Cat, NextCat) == 0) - { - ptr = ptr->Next; - Count += ptr->Count; - goto Catloop; - } - } - - nodeprintf(conn, "%-6s %-3d", Cat, Count); - Line += 10; - if (Line > 80) - { - Line = 0; - nodeprintf(conn, "\r"); - } - - ptr = ptr->Next; - } - - if (Line) - nodeprintf(conn, "\r\r"); - else - nodeprintf(conn, "\r"); - - return; -} - -/* -int ListMessagesTo(ConnectionInfo * conn, struct UserInfo * user, char * Call, BOOL SendFullFrom, int Start) -{ - int i, Msgs = Start; - - for (i=NumberofMessages; i>0; i--) - { - if (MsgHddrPtr[i]->status == 'K') - continue; - - if (Start && MsgHddrPtr[i]->number >= Start) - continue; - - if ((_stricmp(MsgHddrPtr[i]->to, Call) == 0) || - ((conn->sysop) && _stricmp(Call, SYSOPCall) == 0 && - _stricmp(MsgHddrPtr[i]->to, "SYSOP") == 0 && (user->flags & F_SYSOP_IN_LM))) - { - Msgs++; - if (ListMessage(MsgHddrPtr[i], conn, Temp->SendFullFrom)) - break; // Hit page limit - } - } - - return(Msgs); -} - -int ListMessagesFrom(ConnectionInfo * conn, struct UserInfo * user, char * Call, BOOL SendFullFrom, int Start) -{ - int i, Msgs = 0; - - for (i=NumberofMessages; i>0; i--) - { - if (MsgHddrPtr[i]->status == 'K') - continue; - - if (Start && MsgHddrPtr[i]->number >= Start) - continue; - - if (_stricmp(MsgHddrPtr[i]->from, Call) == 0) - { - Msgs++; - if (ListMessage(MsgHddrPtr[i], conn, Temp->SendFullFrom)) - return Msgs; // Hit page limit - - } - } - - return(Msgs); -} - -int ListMessagesAT(ConnectionInfo * conn, struct UserInfo * user, char * Call, BOOL SendFullFrom,int Start) -{ - int i, Msgs = 0; - - for (i=NumberofMessages; i>0; i--) - { - if (MsgHddrPtr[i]->status == 'K') - continue; - - if (Start && MsgHddrPtr[i]->number >= Start) - continue; - - if (_memicmp(MsgHddrPtr[i]->via, Call, strlen(Call)) == 0 || - (_stricmp(Call, "SMTP:") == 0 && MsgHddrPtr[i]->to[0] == 0)) - { - Msgs++; - if (ListMessage(MsgHddrPtr[i], conn, Temp->SendFullFrom)) - break; // Hit page limit - } - } - - return(Msgs); -} -*/ -int GetUserMsg(int m, char * Call, BOOL SYSOP) -{ - struct MsgInfo * Msg; - - // Get Next (usually backwards) message which should be shown to this user - // ie Not Deleted, and not Private unless to or from Call - - do - { - Msg=MsgHddrPtr[m]; - - if (SYSOP) return m; // Sysop can list or read anything - - if (Msg->status != 'K') - { - - if (Msg->status != 'H') - { - if (Msg->type == 'B' || Msg->type == 'T') return m; - - if (Msg->type == 'P') - { - if ((_stricmp(Msg->to, Call) == 0) || (_stricmp(Msg->from, Call) == 0)) - return m; - } - } - } - - m--; - - } while (m> 0); - - return 0; -} - - -BOOL CheckUserMsg(struct MsgInfo * Msg, char * Call, BOOL SYSOP, BOOL IncludeKilled) -{ - // Return TRUE if user is allowed to read message - - if (Msg->status == 'K' && IncludeKilled == 0) - return FALSE; - - if (SYSOP) - return TRUE; // Sysop can list or read anything - - if ((Msg->status != 'K') && (Msg->status != 'H')) - { - if (Msg->type == 'B' || Msg->type == 'T') return TRUE; - - if (Msg->type == 'P') - { - if ((_stricmp(Msg->to, Call) == 0) || (_stricmp(Msg->from, Call) == 0)) - return TRUE; - } - } - - return FALSE; -} -/* -int GetUserMsgForwards(int m, char * Call, BOOL SYSOP) -{ - struct MsgInfo * Msg; - - // Get Next (usually backwards) message which should be shown to this user - // ie Not Deleted, and not Private unless to or from Call - - do - { - Msg=MsgHddrPtr[m]; - - if (Msg->status != 'K') - { - if (SYSOP) return m; // Sysop can list or read anything - - if (Msg->status != 'H') - { - if (Msg->type == 'B' || Msg->type == 'T') return m; - - if (Msg->type == 'P') - { - if ((_stricmp(Msg->to, Call) == 0) || (_stricmp(Msg->from, Call) == 0)) - return m; - } - } - } - - m++; - - } while (m <= NumberofMessages); - - return 0; - -} - - -void ListMessagesInRange(ConnectionInfo * conn, struct UserInfo * user, char * Call, int Start, int End, BOOL SendFullFrom) -{ - int m; - struct MsgInfo * Msg; - - for (m = Start; m >= End; m--) - { - Msg = GetMsgFromNumber(m); - - if (Msg && CheckUserMsg(Msg, user->Call, conn->sysop)) - if (ListMessage(Msg, conn, Temp->SendFullFrom)) - return; // Hit page limit - - } -} - - -void ListMessagesInRangeForwards(ConnectionInfo * conn, struct UserInfo * user, char * Call, int End, int Start, BOOL SendFullFrom) -{ - int m; - struct MsgInfo * Msg; - - for (m = Start; m <= End; m++) - { - Msg = GetMsgFromNumber(m); - - if (Msg && CheckUserMsg(Msg, user->Call, conn->sysop)) - if (ListMessage(Msg, conn, Temp->SendFullFrom)) - return; // Hit page limit - } -} -*/ - -void DoReadCommand(CIRCUIT * conn, struct UserInfo * user, char * Cmd, char * Arg1, char * Context) -{ - int msgno=-1; - int i; - struct MsgInfo * Msg; - - - switch (toupper(Cmd[1])) - { - case 0: // Just R - - while (Arg1) - { - msgno = atoi(Arg1); - if (msgno > 100000) - { - BBSputs(conn, "Message Number too high\r"); - return; - } - - ReadMessage(conn, user, msgno); - Arg1 = strtok_s(NULL, " \r", &Context); - } - - return; - - case 'M': // Read Mine (Unread Messages) - - if (toupper(Cmd[2]) == 'R') - { - for (i = 1; i <= NumberofMessages; i++) - { - Msg = MsgHddrPtr[i]; - - if ((_stricmp(Msg->to, user->Call) == 0) || (conn->sysop && _stricmp(Msg->to, "SYSOP") == 0 && user->flags & F_SYSOP_IN_LM)) - if (Msg->status == 'N') - ReadMessage(conn, user, Msg->number); - } - } - else - { - for (i = NumberofMessages; i > 0; i--) - { - Msg = MsgHddrPtr[i]; - - if ((_stricmp(Msg->to, user->Call) == 0) || (conn->sysop && _stricmp(Msg->to, "SYSOP") == 0 && user->flags & F_SYSOP_IN_LM)) - if (Msg->status == 'N') - ReadMessage(conn, user, Msg->number); - } - } - - return; - } - - nodeprintf(conn, "*** Error: Invalid Read option %c\r", Cmd[1]); - - return; -} - -int RemoveLF(char * Message, int len) -{ - // Remove lf chars and nulls - - char * ptr1, * ptr2; - - ptr1 = ptr2 = Message; - - while (len-- > 0) - { - while (*ptr1 == 0 && len) - { - ptr1++; - len--; - } - - *ptr2 = *ptr1; - - if (*ptr1 == '\r') - if (*(ptr1+1) == '\n') - { - ptr1++; - len--; - } - ptr1++; - ptr2++; - } - - return (int)(ptr2 - Message); -} - - - -int RemoveNulls(char * Message, int len) -{ - // Remove nulls - - char * ptr1, * ptr2; - - ptr1 = ptr2 = Message; - - while (len-- > 0) - { - while (*ptr1 == 0 && len) - { - ptr1++; - len--; - } - - *ptr2 = *ptr1; - - ptr1++; - ptr2++; - } - - return (int)(ptr2 - Message); -} - -void ReadMessage(ConnectionInfo * conn, struct UserInfo * user, int msgno) -{ - struct MsgInfo * Msg; - char * MsgBytes, * Save; - char FullTo[100]; - int Index = 0; - - Msg = GetMsgFromNumber(msgno); - - if (Msg == NULL) - { - nodeprintf(conn, "Message %d not found\r", msgno); - return; - } - - if (!CheckUserMsg(Msg, user->Call, conn->sysop, TRUE)) - { - nodeprintf(conn, "Message %d not for you\r", msgno); - return; - } - - 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); - - - nodeprintf(conn, "From: %s%s\rTo: %s\rType/Status: %c%c\rDate/Time: %s\rBid: %s\rTitle: %s\r\r", - Msg->from, Msg->emailfrom, FullTo, Msg->type, Msg->status, FormatDateAndTime((time_t)Msg->datecreated, FALSE), Msg->bid, Msg->title); - - MsgBytes = Save = ReadMessageFile(msgno); - - if (Msg->type == 'P') - Index = PMSG; - else if (Msg->type == 'B') - Index = BMSG; - else if (Msg->type == 'T') - Index = TMSG; - - if (MsgBytes) - { - int Length = Msg->length; - - if (Msg->B2Flags & B2Msg) - { - char * ptr; - - // if message has attachments, display them if plain text - - if (Msg->B2Flags & Attachments) - { - char * FileName[100]; - int FileLen[100]; - int Files = 0; - int BodyLen, NewLen; - int i; - char *ptr2; - char Msg[512]; - int Len; - - ptr = MsgBytes; - - Len = sprintf(Msg, "Message has Attachments\r\r"); - QueueMsg(conn, Msg, Len); - - while(*ptr != 13) - { - 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]); - - FileName[Files++] = &ptr1[1]; - *(ptr2 - 1) = 0; - } - - ptr = ptr2; - ptr++; - } - - ptr += 2; // Over Blank Line and Separator - - NewLen = RemoveLF(ptr, BodyLen); - - QueueMsg(conn, ptr, NewLen); // Display Body - - ptr += BodyLen + 2; // to first file - - for (i = 0; i < Files; i++) - { - char Msg[512]; - int Len, n; - char * p = ptr; - char c; - - // Check if message is probably binary - - int BinCount = 0; - - NewLen = RemoveLF(ptr, FileLen[i]); // Removes LF agter CR but not on its own - - for (n = 0; n < NewLen; n++) - { - c = *p; - - if (c == 10) - *p = 13; - - if (c==0 || (c & 128)) - BinCount++; - - p++; - - } - - if (BinCount > NewLen/10) - { - // File is probably Binary - - Len = sprintf(Msg, "\rAttachment %s is a binary file\r", FileName[i]); - QueueMsg(conn, Msg, Len); - } - else - { - Len = sprintf(Msg, "\rAttachment %s\r\r", FileName[i]); - QueueMsg(conn, Msg, Len); - - user->Total.MsgsSent[Index] ++; - user->Total.BytesForwardedOut[Index] += NewLen; - - QueueMsg(conn, ptr, NewLen); - } - - ptr += FileLen[i]; - ptr +=2; // Over separator - } - goto sendEOM; - } - - // Remove B2 Headers (up to the File: Line) - - ptr = strstr(MsgBytes, "Body:"); - - if (ptr) - { - MsgBytes = ptr; - Length = (int)strlen(ptr); - } - } - - // Remove lf chars - - Length = RemoveLF(MsgBytes, Length); - - user->Total.MsgsSent[Index] ++; - user->Total.BytesForwardedOut[Index] += Length; - - QueueMsg(conn, MsgBytes, Length); - -sendEOM: - - free(Save); - - nodeprintf(conn, "\r\r[End of Message #%d from %s%s]\r", msgno, Msg->from, Msg->emailfrom); - - if ((_stricmp(Msg->to, user->Call) == 0) || ((conn->sysop) && (_stricmp(Msg->to, "SYSOP") == 0))) - { - if ((Msg->status != 'K') && (Msg->status != 'H') && (Msg->status != 'F') && (Msg->status != 'D')) - { - if (Msg->status != 'Y') - { - Msg->status = 'Y'; - Msg->datechanged=time(NULL); - SaveMessageDatabase(); - } - } - } - } - else - { - nodeprintf(conn, "File for Message %d not found\r", msgno); - } -} - struct MsgInfo * FindMessage(char * Call, int msgno, BOOL sysop) - { - int m=NumberofMessages; - - struct MsgInfo * Msg; - - do - { - m = GetUserMsg(m, Call, sysop); - - if (m == 0) - return NULL; - - Msg=MsgHddrPtr[m]; - - if (Msg->number == msgno) - return Msg; - - m--; - - } while (m> 0); - - return NULL; - -} - - -char * ReadInfoFile(char * File) -{ - int FileSize; - char MsgFile[MAX_PATH]; - FILE * hFile; - char * MsgBytes; - struct stat STAT; - char * ptr1 = 0, * ptr2; - - sprintf_s(MsgFile, sizeof(MsgFile), "%s/%s", BaseDir, File); - - if (stat(MsgFile, &STAT) == -1) - return NULL; - - FileSize = STAT.st_size; - - hFile = fopen(MsgFile, "rb"); - - if (hFile == NULL) - return NULL; - - MsgBytes=malloc(FileSize+1); - - fread(MsgBytes, 1, FileSize, hFile); - - fclose(hFile); - - MsgBytes[FileSize] = 0; - - ptr1 = MsgBytes; - - // Replace LF or CRLF with CR - - // First remove cr from crlf - - while(ptr2 = strstr(ptr1, "\r\n")) - { - memmove(ptr2, ptr2 + 1, strlen(ptr2)); - } - - // Now replace lf with cr - - ptr1 = MsgBytes; - - while (*ptr1) - { - if (*ptr1 == '\n') - *(ptr1) = '\r'; - - ptr1++; - } - - return MsgBytes; -} - -char * FormatDateAndTime(time_t Datim, BOOL DateOnly) -{ - struct tm *tm; - static char Date[]="xx-xxx hh:mmZ"; - - tm = gmtime(&Datim); - - if (tm) - sprintf_s(Date, sizeof(Date), "%02d-%3s %02d:%02dZ", - tm->tm_mday, month[tm->tm_mon], tm->tm_hour, tm->tm_min); - - if (DateOnly) - { - Date[6]=0; - return Date; - } - - return Date; -} - -BOOL DecodeSendParams(CIRCUIT * conn, char * Context, char ** From, char * To, char ** ATBBS, char ** BID); - - -BOOL DoSendCommand(CIRCUIT * conn, struct UserInfo * user, char * Cmd, char * Arg1, char * Context) -{ - // SB WANT @ ALLCAN < N6ZFJ $4567_N0ARY - - char * From = NULL; - char * BID = NULL; - char * ATBBS = NULL; - char seps[] = " \t\r"; - struct MsgInfo * OldMsg; - char OldTitle[62]; - char NewTitle[62]; - char To[100]= ""; - int msgno; - - if (Cmd[1] == 0) Cmd[1] ='P'; // Just S means SP - - switch (toupper(Cmd[1])) - { - case 'B': - - if (RefuseBulls) - { - nodeprintf(conn, "*** Error: This system doesn't allow sending Bulls\r"); - return FALSE; - } - - if (user->flags & F_NOBULLS) - { - nodeprintf(conn, "*** Error: You are not allowed to send Bulls\r"); - return FALSE; - } - - - case 'P': - case 'T': - - if (Arg1 == NULL) - { - nodeprintf(conn, "*** Error: The 'TO' callsign is missing\r"); - return FALSE; - } - - strcpy(To, Arg1); - - if (!DecodeSendParams(conn, Context, &From, To, &ATBBS, &BID)) - return FALSE; - - return CreateMessage(conn, From, To, ATBBS, toupper(Cmd[1]), BID, NULL); - - case 'R': - - if (Arg1 == NULL) - { - nodeprintf(conn, "*** Error: Message Number is missing\r"); - return FALSE; - } - - msgno = atoi(Arg1); - - if (msgno > 100000) - { - BBSputs(conn, "Message Number too high\r"); - return FALSE; - } - - OldMsg = FindMessage(user->Call, msgno, conn->sysop); - - if (OldMsg == NULL) - { - nodeprintf(conn, "Message %d not found\r", msgno); - return FALSE; - } - - Arg1=&OldMsg->from[0]; - - strcpy(To, Arg1); - - if (_stricmp(Arg1, "SMTP:") == 0 || _stricmp(Arg1, "RMS:") == 0 || OldMsg->emailfrom) - { - // SMTP message. Need to get the real sender from the message - - sprintf(To, "%s%s", Arg1, OldMsg->emailfrom); - } - - if (!DecodeSendParams(conn, "", &From, To, &ATBBS, &BID)) - return FALSE; - - strcpy(OldTitle, OldMsg->title); - - if (strlen(OldTitle) > 57) OldTitle[57] = 0; - - strcpy(NewTitle, "Re:"); - strcat(NewTitle, OldTitle); - - return CreateMessage(conn, From, To, ATBBS, 'P', BID, NewTitle); - - return TRUE; - - case 'C': - - if (Arg1 == NULL) - { - nodeprintf(conn, "*** Error: Message Number is missing\r"); - return FALSE; - } - - msgno = atoi(Arg1); - - if (msgno > 100000) - { - BBSputs(conn, "Message Number too high\r"); - return FALSE; - } - - Arg1 = strtok_s(NULL, seps, &Context); - - if (Arg1 == NULL) - { - nodeprintf(conn, "*** Error: The 'TO' callsign is missing\r"); - return FALSE; - } - - strcpy(To, Arg1); - - if (!DecodeSendParams(conn, Context, &From, To, &ATBBS, &BID)) - return FALSE; - - OldMsg = FindMessage(user->Call, msgno, conn->sysop); - - if (OldMsg == NULL) - { - nodeprintf(conn, "Message %d not found\r", msgno); - return FALSE; - } - - strcpy(OldTitle, OldMsg->title); - - if (strlen(OldTitle) > 56) OldTitle[56] = 0; - - strcpy(NewTitle, "Fwd:"); - strcat(NewTitle, OldTitle); - - conn->CopyBuffer = ReadMessageFile(msgno); - - return CreateMessage(conn, From, To, ATBBS, 'P', BID, NewTitle); - } - - - nodeprintf(conn, "*** Error: Invalid Send option %c\r", Cmd[1]); - - return FALSE; -} - -char * CheckToAddress(CIRCUIT * conn, char * Addr) -{ - // Check one element of Multiple Address - - if (conn == NULL || !(conn->BBSFlags & BBS)) - { - // if a normal user, check that TO and/or AT are known and warn if not. - - if (_stricmp(Addr, "SYSOP") == 0) - { - return _strdup(Addr); - } - - if (SendBBStoSYSOPCall) - if (_stricmp(Addr, BBSName) == 0) - return _strdup(SYSOPCall); - - - if (strchr(Addr, '@') == 0) - { - // No routing, if not a user and not known to forwarding or WP warn - - struct UserInfo * ToUser = LookupCall(Addr); - - if (ToUser) - { - // Local User. If Home BBS is specified, use it - - if (ToUser->HomeBBS[0]) - { - char * NewAddr = malloc(250); - if (conn) - nodeprintf(conn, "Address %s - @%s added from HomeBBS\r", Addr, ToUser->HomeBBS); - sprintf(NewAddr, "%s@%s", Addr, ToUser->HomeBBS); - return NewAddr; - } - } - else - { - WPRecP WP = LookupWP(Addr); - - if (WP) - { - char * NewAddr = malloc(250); - - if (conn) - nodeprintf(conn, "Address %s - @%s added from WP\r", Addr, WP->first_homebbs); - sprintf(NewAddr, "%s@%s", Addr, WP->first_homebbs); - return NewAddr; - } - } - } - } - - // Check SMTP and RMS Addresses - - if ((_memicmp(Addr, "rms:", 4) == 0) || (_memicmp(Addr, "rms/", 4) == 0)) - { - Addr[3] = ':'; // Replace RMS/ with RMS: - - if (conn && !FindRMS()) - { - nodeprintf(conn, "*** Error - Forwarding via RMS is not configured on this BBS\r"); - return FALSE; - } - } - else if ((_memicmp(Addr, "smtp:", 5) == 0) || (_memicmp(Addr, "smtp/", 5) == 0)) - { - Addr[4] = ':'; // Replace smpt/ with smtp: - - if (ISP_Gateway_Enabled) - { - if (conn && (conn->UserPointer->flags & F_EMAIL) == 0) - { - nodeprintf(conn, "*** Error - You need to ask the SYSOP to allow you to use Internet Mail\r"); - return FALSE; - } - } - else - { - if (conn) - nodeprintf(conn, "*** Error - Sending mail to smtp addresses is disabled\r"); - return FALSE; - } - } - - return _strdup(Addr); -} - - -char Winlink[] = "WINLINK.ORG"; - -BOOL DecodeSendParams(CIRCUIT * conn, char * Context, char ** From, char *To, char ** ATBBS, char ** BID) -{ - char * ptr; - char seps[] = " \t\r"; - WPRecP WP; - char * ToCopy = _strdup(To); - int Len; - - conn->ToCount = 0; - - // SB WANT @ ALLCAN < N6ZFJ $4567_N0ARY - - // Having trailing ; will mess up parsing multiple addresses, so remove. - - while (To[strlen(To) - 1] == ';') - To[strlen(To) - 1] = 0; - - if (strchr(Context, ';') || strchr(To, ';')) - { - // Multiple Addresses - put address list back together - - char * p; - - To[strlen(To)] = ' '; - Context = To; - - while (p = strchr(Context, ';')) - { - // Multiple Addressees - - To = strtok_s(NULL, ";", &Context); - Len = (int)strlen(To); - conn->To = realloc(conn->To, (conn->ToCount+1) * sizeof(void *)); - if (conn->To[conn->ToCount] = CheckToAddress(conn, To)) - conn->ToCount++; - } - - To = strtok_s(NULL, seps, &Context); - - Len = (int)strlen(To); - conn->To=realloc(conn->To, (conn->ToCount+1) * sizeof(void *)); - if (conn->To[conn->ToCount] = CheckToAddress(conn, To)) - conn->ToCount++; - } - else - { - // Single Call - - // accept CALL!CALL for source routed message - - if (strchr(To, '@') == 0 && strchr(To, '!')) // Bang route without @ - { - char * bang = strchr(To, '!'); - - memmove(bang + 1, bang, strlen(bang)); // Move !call down one - - *ATBBS = strlop(To, '!');; - } - - // Accept call@call (without spaces) - but check for smtp addresses - - if (_memicmp(To, "smtp:", 5) != 0 && _memicmp(To, "rms:", 4) != 0 && _memicmp(To, "rms/", 4) != 0) - { - ptr = strchr(To, '@'); - - if (ptr) - { - // If looks like a valid email address, treat as such - - int tolen; - *ATBBS = strlop(To, '@'); - - strlop(To, '-'); // Cant have SSID on BBS Name - - tolen = (int)strlen(To); - - if (tolen > 6 || !CheckifPacket(*ATBBS)) - { - // Probably Email address. Add smtp: or rms: - - if (FindRMS() || strchr(*ATBBS, '!')) // have RMS or source route - sprintf(To, "rms:%s", ToCopy); - else if (ISP_Gateway_Enabled) - sprintf(To, "smtp:%s", ToCopy); - else if (isAMPRMsg(ToCopy)) - sprintf(To, "rms:%s", ToCopy); - - } - } - } - } - - free(ToCopy); - - // Look for Optional fields; - - ptr = strtok_s(NULL, seps, &Context); - - while (ptr) - { - if (strcmp(ptr, "@") == 0) - { - *ATBBS = _strupr(strtok_s(NULL, seps, &Context)); - } - else if(strcmp(ptr, "<") == 0) - { - *From = strtok_s(NULL, seps, &Context); - } - else if (ptr[0] == '$') - *BID = &ptr[1]; - else - { - nodeprintf(conn, "*** Error: Invalid Format\r"); - return FALSE; - } - ptr = strtok_s(NULL, seps, &Context); - } - - // Only allow < from a BBS - - if (*From) - { - if (!(conn->BBSFlags & BBS)) - { - nodeprintf(conn, "*** < can only be used by a BBS\r"); - return FALSE; - } - } - - if (!*From) - *From = conn->UserPointer->Call; - - if (!(conn->BBSFlags & BBS)) - { - // if a normal user, check that TO and/or AT are known and warn if not. - - if (_stricmp(To, "SYSOP") == 0) - { - conn->LocalMsg = TRUE; - return TRUE; - } - - if (!*ATBBS && conn->ToCount == 0) - { - // No routing, if not a user and not known to forwarding or WP warn - - struct UserInfo * ToUser = LookupCall(To); - - if (ToUser) - { - // Local User. If Home BBS is specified, use it - - if (ToUser->flags & F_RMSREDIRECT) - { - // sent to Winlink - - *ATBBS = Winlink; - nodeprintf(conn, "Redirecting to winlink.org\r", *ATBBS); - } - else if (ToUser->HomeBBS[0]) - { - *ATBBS = ToUser->HomeBBS; - nodeprintf(conn, "Address @%s added from HomeBBS\r", *ATBBS); - } - else - { - conn->LocalMsg = TRUE; - } - } - else - { - conn->LocalMsg = FALSE; - WP = LookupWP(To); - - if (WP) - { - *ATBBS = WP->first_homebbs; - nodeprintf(conn, "Address @%s added from WP\r", *ATBBS); - } - } - } - } - return TRUE; -} - -BOOL CreateMessage(CIRCUIT * conn, char * From, char * ToCall, char * ATBBS, char MsgType, char * BID, char * Title) -{ - struct MsgInfo * Msg, * TestMsg; - char * via = NULL; - char * FromHA; - - // Create a temp msg header entry - - if (conn->ToCount) - { - } - else - { - if (CheckRejFilters(From, ToCall, ATBBS, BID, MsgType)) - { - if ((conn->BBSFlags & BBS)) - { - nodeprintf(conn, "NO - REJECTED\r"); - if (conn->BBSFlags & OUTWARDCONNECT) - nodeprintf(conn, "F>\r"); // if Outward connect must be reverse forward - else - nodeprintf(conn, ">\r"); - } - else - nodeprintf(conn, "*** Error - Message Filters prevent sending this message\r"); - - return FALSE; - } - } - - Msg = malloc(sizeof (struct MsgInfo)); - - if (Msg == 0) - { - CriticalErrorHandler("malloc failed for new message header"); - return FALSE; - } - - memset(Msg, 0, sizeof (struct MsgInfo)); - - conn->TempMsg = Msg; - - Msg->type = MsgType; - - if (conn->UserPointer->flags & F_HOLDMAIL) - Msg->status = 'H'; - else - Msg->status = 'N'; - - Msg->datereceived = Msg->datechanged = Msg->datecreated = time(NULL); - - if (BID) - { - BIDRec * TempBID; - - // If P Message, dont immediately reject on a Duplicate BID. Check if we still have the message - // If we do, reject it. If not, accept it again. (do we need some loop protection ???) - - TempBID = LookupBID(BID); - - if (TempBID) - { - if (MsgType == 'B') - { - // Duplicate bid - - if ((conn->BBSFlags & BBS)) - { - nodeprintf(conn, "NO - BID\r"); - if (conn->BBSFlags & OUTWARDCONNECT) - nodeprintf(conn, "F>\r"); // if Outward connect must be reverse forward - else - nodeprintf(conn, ">\r"); - } - else - nodeprintf(conn, "*** Error- Duplicate BID\r"); - - return FALSE; - } - - TestMsg = GetMsgFromNumber(TempBID->u.msgno); - - // if the same TO we will assume the same message - - if (TestMsg && strcmp(TestMsg->to, ToCall) == 0) - { - // We have this message. If we have already forwarded it, we should accept it again - - if ((TestMsg->status == 'N') || (TestMsg->status == 'Y')|| (TestMsg->status == 'H')) - { - // Duplicate bid - - if ((conn->BBSFlags & BBS)) - { - nodeprintf(conn, "NO - BID\r"); - if (conn->BBSFlags & OUTWARDCONNECT) - nodeprintf(conn, "F>\r"); // if Outward connect must be reverse forward - else - nodeprintf(conn, ">\r"); - } - else - nodeprintf(conn, "*** Error- Duplicate BID\r"); - - return FALSE; - } - } - } - - if (strlen(BID) > 12) BID[12] = 0; - strcpy(Msg->bid, BID); - - // Save BID in temp list in case we are offered it again before completion - - TempBID = AllocateTempBIDRecord(); - strcpy(TempBID->BID, BID); - TempBID->u.conn = conn; - - } - - if (conn->ToCount) - { - } - else - { - if (_memicmp(ToCall, "rms:", 4) == 0) - { - if (!FindRMS()) - { - nodeprintf(conn, "*** Error - Forwarding via RMS is not configured on this BBS\r"); - return FALSE; - } - - via=strlop(ToCall, ':'); - _strupr(ToCall); - } - else if (_memicmp(ToCall, "rms/", 4) == 0) - { - if (!FindRMS()) - { - nodeprintf(conn, "*** Error - Forwarding via RMS is not configured on this BBS\r"); - return FALSE; - } - - via=strlop(ToCall, '/'); - _strupr(ToCall); - } - else if (_memicmp(ToCall, "smtp:", 5) == 0) - { - if (ISP_Gateway_Enabled) - { - if ((conn->UserPointer->flags & F_EMAIL) == 0) - { - nodeprintf(conn, "*** Error - You need to ask the SYSOP to allow you to use Internet Mail\r"); - return FALSE; - } - via=strlop(ToCall, ':'); - ToCall[0] = 0; - } - else - { - nodeprintf(conn, "*** Error - Sending mail to smtp addresses is disabled\r"); - return FALSE; - } - } - else - { - _strupr(ToCall); - if (ATBBS) - via=_strupr(ATBBS); - } - - strlop(ToCall, '-'); // Remove any (illegal) ssid - if (strlen(ToCall) > 6) ToCall[6] = 0; - - strcpy(Msg->to, ToCall); - - if (SendBBStoSYSOPCall) - if (_stricmp(ToCall, BBSName) == 0) - strcpy(Msg->to, SYSOPCall); - - if (via) - { - if (strlen(via) > 40) via[40] = 0; - - strcpy(Msg->via, via); - } - - } // End of Multiple Dests - - // Look for HA in From (even if we shouldn't be getting it!) - - FromHA = strlop(From, '@'); - - - strlop(From, '-'); // Remove any (illegal) ssid - if (strlen(From) > 6) From[6] = 0; - strcpy(Msg->from, From); - - if (FromHA) - { - if (strlen(FromHA) > 39) FromHA[39] = 0; - Msg->emailfrom[0] = '@'; - strcpy(&Msg->emailfrom[1], _strupr(FromHA)); - } - - if (Title) // Only used by SR and SC - { - strcpy(Msg->title, Title); - conn->Flags |= GETTINGMESSAGE; - - // Create initial buffer of 10K. Expand if needed later - - conn->MailBuffer=malloc(10000); - conn->MailBufferSize=10000; - - nodeprintf(conn, "Enter Message Text (end with /ex or ctrl/z)\r"); - return TRUE; - } - - if (conn->BBSFlags & FLARQMODE) - return TRUE; - - if (!(conn->BBSFlags & FBBCompressed)) - conn->Flags |= GETTINGTITLE; - - if (!(conn->BBSFlags & BBS)) - nodeprintf(conn, "Enter Title (only):\r"); - else - if (!(conn->BBSFlags & FBBForwarding)) - nodeprintf(conn, "OK\r"); - - return TRUE; -} - -VOID ProcessMsgTitle(ConnectionInfo * conn, struct UserInfo * user, char* Buffer, int msglen) -{ - - conn->Flags &= ~GETTINGTITLE; - - if (msglen == 1) - { - nodeprintf(conn, "*** Message Cancelled\r"); - SendPrompt(conn, user); - return; - } - - if (msglen > 60) msglen = 60; - - Buffer[msglen-1] = 0; - - strcpy(conn->TempMsg->title, Buffer); - - // Create initial buffer of 10K. Expand if needed later - - conn->MailBuffer=malloc(10000); - conn->MailBufferSize=10000; - - if (conn->MailBuffer == NULL) - { - nodeprintf(conn, "Failed to create Message Buffer\r"); - return; - } - - conn->Flags |= GETTINGMESSAGE; - - if (!conn->BBSFlags & BBS) - nodeprintf(conn, "Enter Message Text (end with /ex or ctrl/z)\r"); - -} - -VOID ProcessMsgLine(CIRCUIT * conn, struct UserInfo * user, char* Buffer, int msglen) -{ - char * ptr2 = NULL; - - if (((msglen < 3) && (Buffer[0] == 0x1a)) || ((msglen == 4) && (_memicmp(Buffer, "/ex", 3) == 0))) - { - int Index = 0; - - if (conn->TempMsg->type == 'P') - Index = PMSG; - else if (conn->TempMsg->type == 'B') - Index = BMSG; - else if (conn->TempMsg->type == 'T') - Index = TMSG; - - conn->Flags &= ~GETTINGMESSAGE; - - user->Total.MsgsReceived[Index]++; - user->Total.BytesForwardedIn[Index] += conn->TempMsg->length; - - if (conn->ToCount) - { - // Multiple recipients - - struct MsgInfo * Msg = conn->TempMsg; - int i; - struct MsgInfo * SaveMsg = Msg; - char * SaveBody = conn->MailBuffer; - int SaveMsgLen = Msg->length; - BOOL SentToRMS = FALSE; - int ToLen = 0; - char * ToString = zalloc(conn->ToCount * 100); - - // If no BID provided, allocate one - - if (Msg->bid[0] == 0) - sprintf_s(Msg->bid, sizeof(Msg->bid), "%d_%s", LatestMsg + 1, BBSName); - - for (i = 0; i < conn->ToCount; i++) - { - char * Addr = conn->To[i]; - char * Via; - - if (_memicmp (Addr, "SMTP:", 5) == 0) - { - // For Email - - conn->TempMsg = Msg = malloc(sizeof(struct MsgInfo)); - memcpy(Msg, SaveMsg, sizeof(struct MsgInfo)); - - conn->MailBuffer = malloc(SaveMsgLen + 10); - memcpy(conn->MailBuffer, SaveBody, SaveMsgLen); - - Msg->to[0] = 0; - strcpy(Msg->via, &Addr[5]); - - CreateMessageFromBuffer(conn); - continue; - } - - if (_memicmp (Addr, "RMS:", 4) == 0) - { - // Add to B2 Message for RMS - - Addr+=4; - - Via = strlop(Addr, '@'); - - if (Via && _stricmp(Via, "winlink.org") == 0) - { - if (CheckifLocalRMSUser(Addr)) - { - // Local RMS - Leave Here - - Via = 0; // Drop Through - goto PktMsg; - } - else - { - ToLen = sprintf(ToString, "%sTo: %s\r\n", ToString, Addr); - continue; - } - } - - ToLen = sprintf(ToString, "%sTo: %s@%s\r\n", ToString, Addr, Via); - continue; - } - - _strupr(Addr); - - Via = strlop(Addr, '@'); - - if (Via && _stricmp(Via, "winlink.org") == 0) - { - if (CheckifLocalRMSUser(Addr)) - { - // Local RMS - Leave Here - - Via = 0; // Drop Through - } - else - { - ToLen = sprintf(ToString, "%sTo: %s\r\n", ToString, Addr); - - // Add to B2 Message for RMS - - continue; - } - } - - PktMsg: - - conn->LocalMsg = FALSE; - - // Normal BBS Message - - if (_stricmp(Addr, "SYSOP") == 0) - conn->LocalMsg = TRUE; - else - { - struct UserInfo * ToUser = LookupCall(Addr); - - if (ToUser) - conn->LocalMsg = TRUE; - } - - conn->TempMsg = Msg = malloc(sizeof(struct MsgInfo)); - memcpy(Msg, SaveMsg, sizeof(struct MsgInfo)); - - conn->MailBuffer = malloc(SaveMsgLen + 10); - memcpy(conn->MailBuffer, SaveBody, SaveMsgLen); - - strcpy(Msg->to, Addr); - - if (Via) - { - Msg->bid[0] = 0; // if we are forwarding it, we must change BID to be safe - strcpy(Msg->via, Via); - } - - CreateMessageFromBuffer(conn); - } - - if (ToLen) - { - char * B2Hddr = zalloc(ToLen + 1000); - int B2HddrLen; - char DateString[80]; - struct tm * tm; - time_t Date = time(NULL); - char Type[16] = "Private"; - - // Get Type - - if (conn->TempMsg->type == 'B') - strcpy(Type, "Bulletin"); - else if (conn->TempMsg->type == 'T') - strcpy(Type, "Traffic"); - - tm = gmtime(&Date); - - sprintf(DateString, "%04d/%02d/%02d %02d:%02d", - tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min); - - conn->TempMsg = Msg = malloc(sizeof(struct MsgInfo)); - memcpy(Msg, SaveMsg, sizeof(struct MsgInfo)); - - conn->MailBuffer = malloc(SaveMsgLen + 1000 + ToLen); - - Msg->B2Flags = B2Msg; - - B2HddrLen = sprintf(B2Hddr, - "MID: %s\r\nDate: %s\r\nType: %s\r\nFrom: %s\r\n%sSubject: %s\r\nMbo: %s\r\nBody: %d\r\n\r\n", - SaveMsg->bid, DateString, Type, - SaveMsg->from, ToString, SaveMsg->title, BBSName, SaveMsgLen); - - memcpy(conn->MailBuffer, B2Hddr, B2HddrLen); - memcpy(&conn->MailBuffer[B2HddrLen], SaveBody, SaveMsgLen); - - Msg->length += B2HddrLen; - - strcpy(Msg->to, "RMS"); - - CreateMessageFromBuffer(conn); - - free(B2Hddr); - } - - free(SaveMsg); - free(SaveBody); - conn->MailBuffer = NULL; - conn->MailBufferSize=0; - - if (!(conn->BBSFlags & BBS)) - SendPrompt(conn, conn->UserPointer); - else - if (!(conn->BBSFlags & FBBForwarding)) - { - if (conn->BBSFlags & OUTWARDCONNECT) - BBSputs(conn, "F>\r"); // if Outward connect must be reverse forward - else - BBSputs(conn, ">\r"); - } - - /* - // From a client - Create one copy with all RMS recipients, and another for each packet recipient - - // Merge all RMS To: lines - - ToLen = 0; - ToString[0] = 0; - - for (i = 0; i < Recipients; i++) - { - if (LocalMsg[i]) - continue; // For a local RMS user - - if (_stricmp(Via[i], "WINLINK.ORG") == 0 || _memicmp (&HddrTo[i][4], "SMTP:", 5) == 0 || - _stricmp(RecpTo[i], "RMS") == 0) - { - ToLen += strlen(HddrTo[i]); - strcat(ToString, HddrTo[i]); - } - } - - if (ToLen) - { - conn->TempMsg = Msg = malloc(sizeof(struct MsgInfo)); - memcpy(Msg, SaveMsg, sizeof(struct MsgInfo)); - - conn->MailBuffer = malloc(SaveMsgLen + 1000); - memcpy(conn->MailBuffer, SaveBody, SaveMsgLen); - - - memmove(&conn->MailBuffer[B2To + ToLen], &conn->MailBuffer[B2To], count); - memcpy(&conn->MailBuffer[B2To], ToString, ToLen); - - conn->TempMsg->length += ToLen; - - strcpy(Msg->to, "RMS"); - strcpy(Msg->via, "winlink.org"); - - // Must Change the BID - - Msg->bid[0] = 0; - - CreateMessageFromBuffer(conn); - } - - } - - free(ToString); - - for (i = 0; i < Recipients; i++) - { - // Only Process Non - RMS Dests or local RMS Users - - if (LocalMsg[i] == 0) - if (_stricmp (Via[i], "WINLINK.ORG") == 0 || - _memicmp (&HddrTo[i][4], "SMTP:", 5) == 0 || - _stricmp(RecpTo[i], "RMS") == 0) - continue; - - conn->TempMsg = Msg = malloc(sizeof(struct MsgInfo)); - memcpy(Msg, SaveMsg, sizeof(struct MsgInfo)); - - conn->MailBuffer = malloc(SaveMsgLen + 1000); - memcpy(conn->MailBuffer, SaveBody, SaveMsgLen); - - // Add our To: - - ToLen = strlen(HddrTo[i]); - - if (_memicmp(HddrTo[i], "CC", 2) == 0) // Replace CC: with TO: - memcpy(HddrTo[i], "To", 2); - - memmove(&conn->MailBuffer[B2To + ToLen], &conn->MailBuffer[B2To], count); - memcpy(&conn->MailBuffer[B2To], HddrTo[i], ToLen); - - conn->TempMsg->length += ToLen; - - strcpy(Msg->to, RecpTo[i]); - strcpy(Msg->via, Via[i]); - - Msg->bid[0] = 0; - - CreateMessageFromBuffer(conn); - } - } // End not from RMS - - free(SaveMsg); - free(SaveBody); - conn->MailBuffer = NULL; - conn->MailBufferSize=0; - - SetupNextFBBMessage(conn); - return; - - } My__except_Routine("Process Multiple Destinations"); - - BBSputs(conn, "*** Program Error Processing Multiple Destinations\r"); - Flush(conn); - conn->CloseAfterFlush = 20; // 2 Secs - - return; -*/ - - conn->ToCount = 0; - - return; - } - - - CreateMessageFromBuffer(conn); - return; - - } - - Buffer[msglen++] = 0x0a; - - if ((conn->TempMsg->length + msglen) > conn->MailBufferSize) - { - conn->MailBufferSize += 10000; - conn->MailBuffer = realloc(conn->MailBuffer, conn->MailBufferSize); - - if (conn->MailBuffer == NULL) - { - nodeprintf(conn, "Failed to extend Message Buffer\r"); - - conn->Flags &= ~GETTINGMESSAGE; - return; - } - } - - memcpy(&conn->MailBuffer[conn->TempMsg->length], Buffer, msglen); - - conn->TempMsg->length += msglen; -} - -VOID CreateMessageFromBuffer(CIRCUIT * conn) -{ - struct MsgInfo * Msg; - BIDRec * BIDRec; - char * ptr1, * ptr2 = NULL; - char * ptr3, * ptr4; - int FWDCount = 0; - char OldMess[] = "\r\n\r\nOriginal Message:\r\n\r\n"; - time_t Age; - int OurCount; - char * HoldReason = "User has Hold Messages flag set"; - struct UserInfo * user; - - -#ifndef LINBPQ - struct _EXCEPTION_POINTERS exinfo; -#endif - - // If doing SC, Append Old Message - - if (conn->CopyBuffer) - { - if ((conn->TempMsg->length + (int) strlen(conn->CopyBuffer) + 80 )> conn->MailBufferSize) - { - conn->MailBufferSize += (int)strlen(conn->CopyBuffer) + 80; - conn->MailBuffer = realloc(conn->MailBuffer, conn->MailBufferSize); - - if (conn->MailBuffer == NULL) - { - nodeprintf(conn, "Failed to extend Message Buffer\r"); - - conn->Flags &= ~GETTINGMESSAGE; - return; - } - } - - memcpy(&conn->MailBuffer[conn->TempMsg->length], OldMess, strlen(OldMess)); - - conn->TempMsg->length += (int)strlen(OldMess); - - memcpy(&conn->MailBuffer[conn->TempMsg->length], conn->CopyBuffer, strlen(conn->CopyBuffer)); - - conn->TempMsg->length += (int)strlen(conn->CopyBuffer); - - free(conn->CopyBuffer); - conn->CopyBuffer = NULL; - } - - // Allocate a message Record slot - - Msg = AllocateMsgRecord(); - memcpy(Msg, conn->TempMsg, sizeof(struct MsgInfo)); - - free(conn->TempMsg); - - // Set number here so they remain in sequence - - GetSemaphore(&MsgNoSemaphore, 0); - Msg->number = ++LatestMsg; - FreeSemaphore(&MsgNoSemaphore); - MsgnotoMsg[Msg->number] = Msg; - - if (Msg->status == 0) - Msg->status = 'N'; - - // Create BID if non supplied - - if (Msg->bid[0] == 0) - sprintf_s(Msg->bid, sizeof(Msg->bid), "%d_%s", LatestMsg, BBSName); - - // if message body had R: lines, get date created from last (not very accurate, but best we can do) - - // Also check if we have had message before to detect loops - - ptr1 = conn->MailBuffer; - OurCount = 0; - - // If it is a B2 Message, Must Skip B2 Header - - if (Msg->B2Flags & B2Msg) - { - ptr1 = strstr(ptr1, "\r\n\r\n"); - if (ptr1) - ptr1 += 4; - else - ptr1 = conn->MailBuffer; - } - -nextline: - - if (memcmp(ptr1, "R:", 2) == 0) - { - // Is if ours? - - // BPQ RLINE Format R:090920/1041Z 6542@N4JOA.#WPBFL.FL.USA.NOAM BPQ1.0.2 - - ptr3 = strchr(ptr1, '@'); - ptr4 = strchr(ptr1, '.'); - - if (ptr3 && ptr4 && (ptr4 > ptr3)) - { - if (memcmp(ptr3+1, BBSName, ptr4-ptr3-1) == 0) - OurCount++; - } - - GetWPBBSInfo(ptr1); // Create WP /I record from R: Line - - // see if another - - ptr2 = ptr1; // save - ptr1 = strchr(ptr1, '\r'); - if (ptr1 == 0) - { - Debugprintf("Corrupt Message %s from %s - truncated within R: line", Msg->bid, Msg->from); - return; - } - ptr1++; - if (*ptr1 == '\n') ptr1++; - - goto nextline; - } - - // ptr2 points to last R: line (if any) - - if (ptr2) - { - struct tm rtime; - time_t result; - - memset(&rtime, 0, sizeof(struct tm)); - - if (ptr2[10] == '/') - { - // Dodgy 4 char year - - sscanf(&ptr2[2], "%04d%02d%02d/%02d%02d", - &rtime.tm_year, &rtime.tm_mon, &rtime.tm_mday, &rtime.tm_hour, &rtime.tm_min); - rtime.tm_year -= 1900; - rtime.tm_mon--; - } - else if (ptr2[8] == '/') - { - sscanf(&ptr2[2], "%02d%02d%02d/%02d%02d", - &rtime.tm_year, &rtime.tm_mon, &rtime.tm_mday, &rtime.tm_hour, &rtime.tm_min); - - if (rtime.tm_year < 90) - rtime.tm_year += 100; // Range 1990-2089 - rtime.tm_mon--; - } - - // Otherwise leave date as zero, which should be rejected - - // result = _mkgmtime(&rtime); - - if ((result = mktime(&rtime)) != (time_t)-1 ) - { - result -= (time_t)_MYTIMEZONE; - - Msg->datecreated = result; - Age = (time(NULL) - result)/86400; - - if ( Age < -7) - { - Msg->status = 'H'; - HoldReason = "Suspect Date Sent"; - } - else if (Age > BidLifetime || Age > MaxAge) - { - Msg->status = 'H'; - HoldReason = "Message too old"; - - } - else - GetWPInfoFromRLine(Msg->from, ptr2, result); - } - else - { - // Can't decode R: Datestamp - - Msg->status = 'H'; - HoldReason = "Corrupt R: Line - can't determine age"; - } - - if (OurCount > 1) - { - // Message is looping - - Msg->status = 'H'; - HoldReason = "Message may be looping"; - - } - } - - if (strcmp(Msg->to, "WP") == 0) - { - // If Reject WP Bulls is set, Kill message here. - // It should only get here if B2 - otherwise it should be - // rejected earlier - - if (Msg->type == 'B' && FilterWPBulls) - Msg->status = 'K'; - - } - - conn->MailBuffer[Msg->length] = 0; - - if (CheckBadWords(Msg->title) || CheckBadWords(conn->MailBuffer)) - { - Msg->status = 'H'; - HoldReason = "Bad word in title or body"; - } - - if (CheckHoldFilters(Msg->from, Msg->to, Msg->via, Msg->bid)) - { - Msg->status = 'H'; - HoldReason = "Matched Hold Filters"; - } - - if (CheckValidCall(Msg->from) == 0) - { - Msg->status = 'H'; - HoldReason = "Probable Invalid From Call"; - } - - // Process any WP Messages - - if (strcmp(Msg->to, "WP") == 0) - { - if (Msg->status == 'N') - { - ProcessWPMsg(conn->MailBuffer, Msg->length, ptr2); - - if (Msg->type == 'P') // Kill any processed private WP messages. - { - char VIA[80]; - - strcpy(VIA, Msg->via); - strlop(VIA, '.'); - - if (strcmp(VIA, BBSName) == 0) - Msg->status = 'K'; - } - } - } - - CreateMessageFile(conn, Msg); - - BIDRec = AllocateBIDRecord(); - - strcpy(BIDRec->BID, Msg->bid); - BIDRec->mode = Msg->type; - BIDRec->u.msgno = LOWORD(Msg->number); - BIDRec->u.timestamp = LOWORD(time(NULL)/86400); - - if (Msg->length > MaxTXSize) - { - Msg->status = 'H'; - HoldReason = "Message too long"; - - if (!(conn->BBSFlags & BBS)) - nodeprintf(conn, "*** Warning Message length exceeds sysop-defined maximum of %d - Message will be held\r", MaxTXSize); - } - - // Check for message to internal server - - if (Msg->via[0] == 0 - || _stricmp(Msg->via, BBSName) == 0 // our BBS a - || _stricmp(Msg->via, AMPRDomain) == 0) // our AMPR Address - { - if (CheckforMessagetoServer(Msg)) - { - // Flag as killed and send prompt - - FlagAsKilled(Msg, TRUE); - - if (!(conn->BBSFlags & BBS)) - { - nodeprintf(conn, "Message %d to Server Processed and Killed.\r", Msg->number); - SendPrompt(conn, conn->UserPointer); - } - return; // no need to process further - } - } - - if (Msg->to[0]) - FWDCount = MatchMessagetoBBSList(Msg, conn); - else - { - // If addressed @winlink.org, and to a local user, Keep here. - - char * Call; - char * AT; - - // smtp or rms - don't warn no route - - FWDCount = 1; - - Call = _strupr(_strdup(Msg->via)); - AT = strlop(Call, '@'); - - if (AT && _stricmp(AT, "WINLINK.ORG") == 0) - { - struct UserInfo * user = LookupCall(Call); - - if (user) - { - if (user->flags & F_POLLRMS) - { - Logprintf(LOG_BBS, conn, '?', "SMTP Message @ winlink.org, but local RMS user - leave here"); - strcpy(Msg->to, Call); - strcpy(Msg->via, AT); - if (user->flags & F_BBS) // User is a BBS, so set FWD bit so he can get it - set_fwd_bit(Msg->fbbs, user->BBSNumber); - - } - } - } - free(Call); - } - - // Warn SYSOP if P or T forwarded in, and has nowhere to go - - if ((conn->BBSFlags & BBS) && Msg->type != 'B' && FWDCount == 0 && WarnNoRoute && - strcmp(Msg->to, "SYSOP") && strcmp(Msg->to, "WP")) - { - if (Msg->via[0]) - { - if (_stricmp(Msg->via, BBSName)) // Not for our BBS a - if (_stricmp(Msg->via, AMPRDomain)) // Not for our AMPR Address - SendWarningToSYSOP(Msg); - } - else - { - // No via - is it for a local user? - - if (LookupCall(Msg->to) == 0) - SendWarningToSYSOP(Msg); - } - } - - if ((conn->BBSFlags & SYNCMODE) == 0) - { - if (!(conn->BBSFlags & BBS)) - { - nodeprintf(conn, "Message: %d Bid: %s Size: %d\r", Msg->number, Msg->bid, Msg->length); - - if (Msg->via[0]) - { - if (_stricmp(Msg->via, BBSName)) // Not for our BBS a - if (_stricmp(Msg->via, AMPRDomain)) // Not for our AMPR Address - - if (FWDCount == 0 && Msg->to[0] != 0) // unless smtp msg - nodeprintf(conn, "@BBS specified, but no forwarding info is available - msg may not be delivered\r"); - } - else - { - if (FWDCount == 0 && conn->LocalMsg == 0 && Msg->type != 'B') - // Not Local and no forward route - nodeprintf(conn, "Message is not for a local user, and no forwarding info is available - msg may not be delivered\r"); - } - if (conn->ToCount == 0) - SendPrompt(conn, conn->UserPointer); - } - else - { - if (!(conn->BBSFlags & FBBForwarding)) - { - if (conn->ToCount == 0) - if (conn->BBSFlags & OUTWARDCONNECT) - nodeprintf(conn, "F>\r"); // if Outward connect must be reverse forward - else - nodeprintf(conn, ">\r"); - } - } - } - - if(Msg->to[0] == 0) - SMTPMsgCreated=TRUE; - - if (Msg->status != 'H' && Msg->type == 'B' && memcmp(Msg->fbbs, zeros, NBMASK) != 0) - Msg->status = '$'; // Has forwarding - - if (Msg->status == 'H') - { - int Length=0; - char * MailBuffer = malloc(100); - char Title[100]; - - Length += sprintf(MailBuffer, "Message %d Held\r\n", Msg->number); - sprintf(Title, "Message %d Held - %s", Msg->number, HoldReason); - SendMessageToSYSOP(Title, MailBuffer, Length); - } - - BuildNNTPList(Msg); // Build NNTP Groups list - - SaveMessageDatabase(); - SaveBIDDatabase(); - - // 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 - } - - - if (EnableUI) -#ifdef LINBPQ - SendMsgUI(Msg); -#else - __try - { - SendMsgUI(Msg); - } - My__except_Routine("SendMsgUI"); -#endif - - user = LookupCall(Msg->to); - - if (user && (user->flags & F_APRSMFOR)) - { - char APRS[128]; - char Call[16]; - int SSID = user->flags >> 28; - - if (SSID) - sprintf(Call, "%s-%d", Msg->to, SSID); - else - strcpy(Call, Msg->to); - - sprintf(APRS, "New BBS Message %s From %s", Msg->title, Msg->from); - APISendAPRSMessage(APRS, Call); - } - - return; -} - -VOID CreateMessageFile(ConnectionInfo * conn, struct MsgInfo * Msg) -{ - char MsgFile[MAX_PATH]; - FILE * hFile; - size_t WriteLen=0; - char Mess[255]; - int len; - BOOL AutoImport = FALSE; - - sprintf_s(MsgFile, sizeof(MsgFile), "%s/m_%06d.mes", MailDir, Msg->number); - - // If title is "Batched messages for AutoImport from BBS xxxxxx and first line is S? and it is - // for this BBS, Import file and set message as Killed. May need to strip B2 Header and R: lines - - if (strcmp(Msg->to, BBSName) == 0 && strstr(Msg->title, "Batched messages for AutoImport from BBS ")) - { - UCHAR * ptr = conn->MailBuffer; - - // If it is a B2 Message, Must Skip B2 Header - - if (Msg->B2Flags & B2Msg) - { - ptr = strstr(ptr, "\r\n\r\n"); - if (ptr) - ptr += 4; - else - ptr = conn->MailBuffer; - } - - if (memcmp(ptr, "R:", 2) == 0) - { - ptr = strstr(ptr, "\r\n\r\n"); //And remove R: Lines - if (ptr) - ptr += 4; - } - - if (*(ptr) == 'S' && ptr[2] == ' ') - { - int HeaderLen = (int)(ptr - conn->MailBuffer); - Msg->length -= HeaderLen; - memmove(conn->MailBuffer, ptr, Msg->length); - Msg->status = 'K'; - AutoImport = TRUE; - } - } - - hFile = fopen(MsgFile, "wb"); - - if (hFile) - { - WriteLen = fwrite(conn->MailBuffer, 1, Msg->length, hFile); - fclose(hFile); - } - - if (AutoImport) - ImportMessages(NULL, MsgFile, TRUE); - - free(conn->MailBuffer); - conn->MailBufferSize=0; - conn->MailBuffer=0; - - if (WriteLen != Msg->length) - { - len = sprintf_s(Mess, sizeof(Mess), "Failed to create Message File\r"); - QueueMsg(conn, Mess, len); - Debugprintf(Mess); - } - return; -} - - - - -VOID SendUnbuffered(int stream, char * msg, int len) -{ -#ifndef LINBPQ - if (stream < 0) - WritetoConsoleWindow(stream, msg, len); - else -#endif - SendMsg(stream, msg, len); -} - -BOOL FindMessagestoForwardLoop(CIRCUIT * conn, char Type, int MaxLen); - -BOOL FindMessagestoForward (CIRCUIT * conn) -{ - struct UserInfo * user = conn->UserPointer; - -#ifndef LINBPQ - - struct _EXCEPTION_POINTERS exinfo; - - __try { -#endif - - // This is a hack so Winpack or WLE users can use forwarding - // protocols to get their messages without being defined as a BBS - - // !!IMPORTANT Getting this wrong can see message repeatedly proposed !! - // !! Anything sent using this must be killed if sent or rejected. - - // I'm not sure about this. I think I only need the PacLinkCalls - // if from RMS Express, and it always sends an FW; line - // Ah, no. What about WinPack ?? - // If from RMS Express must have Temp_B2 or BBS set or SID will - // be rejected. So maybe just Temp_B2 && BBS = 0?? - // No, someone may have Temp_B2 set and not be using WLE ?? So what ?? - - if ((user->flags & F_Temp_B2_BBS) && ((user->flags & F_BBS) == 0) || conn->RMSExpress || conn->PAT) - { - if (conn->PacLinkCalls == NULL) - { - // create a list with just the user call - - char * ptr1; - - conn->PacLinkCalls = zalloc(30); - - ptr1 = (char *)conn->PacLinkCalls; - ptr1 += 16; // Must be room for a null pointer on end (64 bit bug) - strcpy(ptr1, user->Call); - - conn->PacLinkCalls[0] = ptr1; - } - } - - if (conn->SendT && FindMessagestoForwardLoop(conn, 'T', conn->MaxTLen)) - { - conn->LastForwardType = 'T'; - return TRUE; - } - - if (conn->LastForwardType == 'T') - conn->NextMessagetoForward = FirstMessageIndextoForward; - - if (conn->SendP && FindMessagestoForwardLoop(conn, 'P', conn->MaxPLen)) - { - conn->LastForwardType = 'P'; - return TRUE; - } - - if (conn->LastForwardType == 'P') - conn->NextMessagetoForward = FirstMessageIndextoForward; - - if (conn->SendB && FindMessagestoForwardLoop(conn, 'B', conn->MaxBLen)) - { - conn->LastForwardType = 'B'; - return TRUE; - } - - conn->LastForwardType = 0; - return FALSE; -#ifndef LINBPQ - } My__except_Routine("FindMessagestoForward"); -#endif - return FALSE; - -} - - -BOOL FindMessagestoForwardLoop(CIRCUIT * conn, char Type, int MaxLen) -{ - // See if any messages are queued for this BBS - - int m; - struct MsgInfo * Msg; - struct UserInfo * user = conn->UserPointer; - struct FBBHeaderLine * FBBHeader; - BOOL Found = FALSE; - char RLine[100]; - int TotalSize = 0; - time_t NOW = time(NULL); - -// Debugprintf("FMTF entered Call %s Type %c Maxlen %d NextMsg = %d BBSNo = %d", -// conn->Callsign, Type, MaxLen, conn->NextMessagetoForward, user->BBSNumber); - - if (conn->PacLinkCalls || (conn->UserPointer->flags & F_NTSMPS)) // Looking for all messages, so reset - conn->NextMessagetoForward = 1; - - conn->FBBIndex = 0; - - for (m = conn->NextMessagetoForward; m <= NumberofMessages; m++) - { - Msg=MsgHddrPtr[m]; - - // If an NTS MPS, see if anything matches - - if (Type == 'T' && (conn->UserPointer->flags & F_NTSMPS)) - { - struct BBSForwardingInfo * ForwardingInfo = conn->UserPointer->ForwardingInfo; - int depth; - - if (Msg->type == 'T' && Msg->status == 'N' && Msg->length <= MaxLen && ForwardingInfo) - { - depth = CheckBBSToForNTS(Msg, ForwardingInfo); - - if (depth > -1 && Msg->Locked == 0) - goto Forwardit; - - depth = CheckBBSAtList(Msg, ForwardingInfo, Msg->via); - - if (depth && Msg->Locked == 0) - goto Forwardit; - - depth = CheckBBSATListWildCarded(Msg, ForwardingInfo, Msg->via); - - if (depth > -1 && Msg->Locked == 0) - goto Forwardit; - } - } - - // If forwarding to Paclink or RMS Express, look for any message matching the - // requested call list with status 'N' (maybe should also be 'P' ??) - - if (conn->PacLinkCalls) - { - int index = 1; - - char * Call = conn->PacLinkCalls[0]; - - while (Call) - { - if (Msg->type == Type && Msg->status == 'N') - { -// Debugprintf("Comparing RMS Call %s %s", Msg->to, Call); - if (_stricmp(Msg->to, Call) == 0) - if (Msg->status == 'N' && Msg->type == Type && Msg->length <= MaxLen) - goto Forwardit; - else - Debugprintf("Call Match but Wrong Type/Len %c %d", Msg->type, Msg->length); - } - Call = conn->PacLinkCalls[index++]; - } -// continue; - } - - if (Msg->type == Type && Msg->length <= MaxLen && (Msg->status != 'H') - && (Msg->status != 'D') && Msg->type && check_fwd_bit(Msg->fbbs, user->BBSNumber)) - { - // Message to be sent - do a consistancy check (State, etc) - - Forwardit: - - if (Msg->Defered > 0) // = response received - { - Msg->Defered--; - Debugprintf("Message %d deferred", Msg->number); - continue; - } - - if ((Msg->from[0] == 0) || (Msg->to[0] == 0)) - { - int Length=0; - char * MailBuffer = malloc(100); - char Title[100]; - - Length += sprintf(MailBuffer, "Message %d Held\r\n", Msg->number); - sprintf(Title, "Message %d Held - %s", Msg->number, "Missing From: or To: field"); - SendMessageToSYSOP(Title, MailBuffer, Length); - - Msg->status = 'H'; - continue; - } - - conn->NextMessagetoForward = m + 1; // So we don't offer again if defered - - Msg->Locked = 1; // So other MPS can't pick it up - - // if FBB forwarding add to list, eise save pointer - - if (conn->BBSFlags & FBBForwarding) - { - struct tm *tm; - time_t temp; - - FBBHeader = &conn->FBBHeaders[conn->FBBIndex++]; - - FBBHeader->FwdMsg = Msg; - FBBHeader->MsgType = Msg->type; - FBBHeader->Size = Msg->length; - TotalSize += Msg->length; - strcpy(FBBHeader->From, Msg->from); - strcpy(FBBHeader->To, Msg->to); - strcpy(FBBHeader->ATBBS, Msg->via); - strcpy(FBBHeader->BID, Msg->bid); - - // Set up R:Line, so se can add its length to the sise - - memcpy(&temp, &Msg->datereceived, sizeof(time_t)); - tm = gmtime(&temp); - - FBBHeader->Size += sprintf_s(RLine, sizeof(RLine),"R:%02d%02d%02d/%02d%02dZ %d@%s.%s %s\r\n", - tm->tm_year-100, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, - Msg->number, BBSName, HRoute, RlineVer); - - // If using B2 forwarding we need the message size and Compressed size for FC proposal - - if (conn->BBSFlags & FBBB2Mode) - { - if (CreateB2Message(conn, FBBHeader, RLine) == FALSE) - { - char * MailBuffer = malloc(100); - char Title[100]; - int Length; - - // Corrupt B2 Message - - Debugprintf("Corrupt B2 Message found - Message %d will be held", Msg->number); - Msg->status = 'H'; - SaveMessageDatabase(); - - conn->FBBIndex--; - TotalSize -= Msg->length; - memset(&conn->FBBHeaders[conn->FBBIndex], 0, sizeof(struct FBBHeaderLine)); - - Length = sprintf(MailBuffer, "Message %d Held\r\n", Msg->number); - sprintf(Title, "Message %d Held - %s", Msg->number, "Corrupt B2 Message"); - SendMessageToSYSOP(Title, MailBuffer, Length); - - continue; - } - } - - if (conn->FBBIndex == 5 || TotalSize > user->ForwardingInfo->MaxFBBBlockSize) - return TRUE; // Got max number or too big - - Found = TRUE; // Remember we have some - } - else - { - conn->FwdMsg = Msg; - return TRUE; - } - } - } - - return Found; -} - -BOOL SeeifMessagestoForward (int BBSNumber, CIRCUIT * conn) -{ - // See if any messages are queued for this BBS - - // if Conn is not NULL, also check Msg Type - - int m; - struct MsgInfo * Msg; - - for (m = FirstMessageIndextoForward; m <= NumberofMessages; m++) - { - Msg=MsgHddrPtr[m]; - - if ((Msg->status != 'H') && (Msg->status != 'D') && Msg->type && check_fwd_bit(Msg->fbbs, BBSNumber)) - { - if (conn) - { - char Type = Msg->type; - - if ((conn->SendB && Type == 'B') || (conn->SendP && Type == 'P') || (conn->SendT && Type == 'T')) - { -// Debugprintf("SeeifMessagestoForward BBSNo %d Msg %d", BBSNumber, Msg->number); - return TRUE; - } - } - else - { -// Debugprintf("SeeifMessagestoForward BBSNo %d Msg %d", BBSNumber, Msg->number); - return TRUE; - } - } - } - - return FALSE; -} - -int CountMessagestoForward (struct UserInfo * user) -{ - // See if any messages are queued for this BBS - - int m, n=0; - struct MsgInfo * Msg; - int BBSNumber = user->BBSNumber; - int FirstMessage = FirstMessageIndextoForward; - - if ((user->flags & F_NTSMPS)) - FirstMessage = 1; - - for (m = FirstMessage; m <= NumberofMessages; m++) - { - Msg=MsgHddrPtr[m]; - - if ((Msg->status != 'H') && (Msg->status != 'D') && Msg->type && check_fwd_bit(Msg->fbbs, BBSNumber)) - { - n++; - continue; // So we dont count twice in Flag set and NTS MPS - } - - // if an NTS MPS, also check for any matches - - if (Msg->type == 'T' && (user->flags & F_NTSMPS)) - { - struct BBSForwardingInfo * ForwardingInfo = user->ForwardingInfo; - int depth; - - if (Msg->status == 'N' && ForwardingInfo) - { - depth = CheckBBSToForNTS(Msg, ForwardingInfo); - - if (depth > -1 && Msg->Locked == 0) - { - n++; - continue; - } - depth = CheckBBSAtList(Msg, ForwardingInfo, Msg->via); - - if (depth && Msg->Locked == 0) - { - n++; - continue; - } - - depth = CheckBBSATListWildCarded(Msg, ForwardingInfo, Msg->via); - - if (depth > -1 && Msg->Locked == 0) - { - n++; - continue; - } - } - } - } - - return n; -} - -int ListMessagestoForward(CIRCUIT * conn, struct UserInfo * user) -{ - // See if any messages are queued for this BBS - - int m, n=0; - struct MsgInfo * Msg; - int BBSNumber = user->BBSNumber; - int FirstMessage = FirstMessageIndextoForward; - - if ((user->flags & F_NTSMPS)) - FirstMessage = 1; - - for (m = FirstMessage; m <= NumberofMessages; m++) - { - Msg=MsgHddrPtr[m]; - - if ((Msg->status != 'H') && (Msg->status != 'D') && Msg->type && check_fwd_bit(Msg->fbbs, BBSNumber)) - { - nodeprintf(conn, "%d %s\r", Msg->number, Msg->title); - continue; // So we dont count twice in Flag set and NTS MPS - } - - // if an NTS MPS, also check for any matches - - if (Msg->type == 'T' && (user->flags & F_NTSMPS)) - { - struct BBSForwardingInfo * ForwardingInfo = user->ForwardingInfo; - int depth; - - if (Msg->status == 'N' && ForwardingInfo) - { - depth = CheckBBSToForNTS(Msg, ForwardingInfo); - - if (depth > -1 && Msg->Locked == 0) - { - nodeprintf(conn, "%d %s\r", Msg->number, Msg->title); - continue; - } - depth = CheckBBSAtList(Msg, ForwardingInfo, Msg->via); - - if (depth && Msg->Locked == 0) - { - nodeprintf(conn, "%d %s\r", Msg->number, Msg->title); - continue; - } - - depth = CheckBBSATListWildCarded(Msg, ForwardingInfo, Msg->via); - - if (depth > -1 && Msg->Locked == 0) - { - nodeprintf(conn, "%d %s\r", Msg->number, Msg->title); - continue; - } - } - } - } - - return n; -} - -VOID SendWarningToSYSOP(struct MsgInfo * Msg) -{ - int Length=0; - char * MailBuffer = malloc(100); - char Title[100]; - - Length += sprintf(MailBuffer, "Warning - Message %d has nowhere to go", Msg->number); - sprintf(Title, "Warning - Message %d has nowhere to go", Msg->number); - SendMessageToSYSOP(Title, MailBuffer, Length); -} - - - -VOID SendMessageToSYSOP(char * Title, char * MailBuffer, int Length) -{ - struct MsgInfo * Msg = AllocateMsgRecord(); - BIDRec * BIDRec; - - char MsgFile[MAX_PATH]; - FILE * hFile; - size_t WriteLen=0; - - Msg->length = Length; - - GetSemaphore(&MsgNoSemaphore, 0); - Msg->number = ++LatestMsg; - MsgnotoMsg[Msg->number] = Msg; - - FreeSemaphore(&MsgNoSemaphore); - - strcpy(Msg->from, "SYSTEM"); - if (SendSYStoSYSOPCall) - strcpy(Msg->to, SYSOPCall); - else - strcpy(Msg->to, "SYSOP"); - - strcpy(Msg->title, Title); - - Msg->type = 'P'; - Msg->status = 'N'; - Msg->datereceived = Msg->datechanged = Msg->datecreated = time(NULL); - - sprintf_s(Msg->bid, sizeof(Msg->bid), "%d_%s", LatestMsg, BBSName); - - BIDRec = AllocateBIDRecord(); - strcpy(BIDRec->BID, Msg->bid); - BIDRec->mode = Msg->type; - BIDRec->u.msgno = LOWORD(Msg->number); - BIDRec->u.timestamp = LOWORD(time(NULL)/86400); - - sprintf_s(MsgFile, sizeof(MsgFile), "%s/m_%06d.mes", MailDir, Msg->number); - - hFile = fopen(MsgFile, "wb"); - - if (hFile) - { - WriteLen = fwrite(MailBuffer, 1, Msg->length, hFile); - fclose(hFile); - } - - MatchMessagetoBBSList(Msg, NULL); - free(MailBuffer); -} - -VOID CheckBBSNumber(int i) -{ - // Make sure number is unique - - int Count = 0; - struct UserInfo * user; - - for (user = BBSChain; user; user = user->BBSNext) - { - if (user->BBSNumber == i) - { - Count++; - - if (Count > 1) - { - // Second with same number - Renumber this one - - user->BBSNumber = FindFreeBBSNumber(); - - if (user->BBSNumber == 0) - user->BBSNumber = NBBBS; // cant really do much else - - Logprintf(LOG_BBS, NULL, '?', "Duplicate BBS Number found. BBS %s Old BBSNumber %d New BBS Number %d", user->Call, i, user->BBSNumber); - - } - } - } -} - - -int FindFreeBBSNumber() -{ - // returns the lowest number not used by any bbs or message. - - struct MsgInfo * Msg; - struct UserInfo * user; - int i, m; - - for (i = 1; i<= NBBBS; i++) - { - for (user = BBSChain; user; user = user->BBSNext) - { - if (user->BBSNumber == i) - goto nexti; // In use - } - - // Not used by BBS - check messages - - for (m = 1; m <= NumberofMessages; m++) - { - Msg=MsgHddrPtr[m]; - - if (check_fwd_bit(Msg->fbbs, i)) - goto nexti; // In use - - if (check_fwd_bit(Msg->forw, i)) - goto nexti; // In use - } - - // Not in Use - - return i; - -nexti:; - - } - - return 0; // All used -} - -BOOL SetupNewBBS(struct UserInfo * user) -{ - user->BBSNumber = FindFreeBBSNumber(); - - if (user->BBSNumber == 0) - return FALSE; - - user->BBSNext = BBSChain; - BBSChain = user; - - SortBBSChain(); - - ReinitializeFWDStruct(user); - - return TRUE; -} - -VOID DeleteBBS(struct UserInfo * user) -{ - struct UserInfo * BBSRec, * PrevBBS = NULL; - -#ifndef LINBPQ - RemoveMenu(hFWDMenu, IDM_FORWARD_ALL + user->BBSNumber, MF_BYCOMMAND); -#endif - for (BBSRec = BBSChain; BBSRec; PrevBBS = BBSRec, BBSRec = BBSRec->BBSNext) - { - if (user == BBSRec) - { - if (PrevBBS == NULL) // First in chain; - { - BBSChain = BBSRec->BBSNext; - break; - } - PrevBBS->BBSNext = BBSRec->BBSNext; - break; - } - } -} - - -VOID SetupFwdTimes(struct BBSForwardingInfo * ForwardingInfo); - -VOID SetupForwardingStruct(struct UserInfo * user) -{ - struct BBSForwardingInfo * ForwardingInfo; - - char Key[100] = "BBSForwarding."; - char Temp[100]; - - HKEY hKey=0; - char RegKey[100] = "SOFTWARE\\G8BPQ\\BPQ32\\BPQMailChat\\BBSForwarding\\"; - - int m; - struct MsgInfo * Msg; - - ForwardingInfo = user->ForwardingInfo = zalloc(sizeof(struct BBSForwardingInfo)); - - if (UsingingRegConfig == 0) - { - // Config from file - - if (isdigit(user->Call[0]) || user->Call[0] == '_') - strcat(Key, "*"); - - strcat(Key, user->Call); - - group = config_lookup (&cfg, Key); - - if (group == NULL) // No info - return; - else - { - ForwardingInfo->TOCalls = GetMultiStringValue(group, "TOCalls"); - ForwardingInfo->ConnectScript = GetMultiStringValue(group, "ConnectScript"); - ForwardingInfo->ATCalls = GetMultiStringValue(group, "ATCalls"); - ForwardingInfo->Haddresses = GetMultiStringValue(group, "HRoutes"); - ForwardingInfo->HaddressesP = GetMultiStringValue(group, "HRoutesP"); - ForwardingInfo->FWDTimes = GetMultiStringValue(group, "FWDTimes"); - - ForwardingInfo->Enabled = GetIntValue(group, "Enabled"); - ForwardingInfo->ReverseFlag = GetIntValue(group, "RequestReverse"); - ForwardingInfo->AllowBlocked = GetIntValue(group, "AllowBlocked"); - ForwardingInfo->AllowCompressed = GetIntValue(group, "AllowCompressed"); - ForwardingInfo->AllowB1 = GetIntValue(group, "UseB1Protocol"); - ForwardingInfo->AllowB2 = GetIntValue(group, "UseB2Protocol"); - ForwardingInfo->SendCTRLZ = GetIntValue(group, "SendCTRLZ"); - - if (ForwardingInfo->AllowB1 || ForwardingInfo->AllowB2) - ForwardingInfo->AllowCompressed = TRUE; - - if (ForwardingInfo->AllowCompressed) - ForwardingInfo->AllowBlocked = TRUE; - - ForwardingInfo->PersonalOnly = GetIntValue(group, "FWDPersonalsOnly"); - ForwardingInfo->SendNew = GetIntValue(group, "FWDNewImmediately"); - ForwardingInfo->FwdInterval = GetIntValue(group, "FwdInterval"); - ForwardingInfo->RevFwdInterval = GetIntValue(group, "RevFWDInterval"); - ForwardingInfo->MaxFBBBlockSize = GetIntValue(group, "MaxFBBBlock"); - ForwardingInfo->ConTimeout = GetIntValue(group, "ConTimeout"); - - if (ForwardingInfo->MaxFBBBlockSize == 0) - ForwardingInfo->MaxFBBBlockSize = 10000; - - if (ForwardingInfo->FwdInterval == 0) - ForwardingInfo->FwdInterval = 3600; - - if (ForwardingInfo->ConTimeout == 0) - ForwardingInfo->ConTimeout = 120; - - GetStringValue(group, "BBSHA", Temp); - - if (Temp[0]) - ForwardingInfo->BBSHA = _strdup(Temp); - else - ForwardingInfo->BBSHA = _strdup(""); - } - } - else - { -#ifndef LINBPQ - - int retCode,Type,Vallen; - - strcat(RegKey, user->Call); - retCode = RegOpenKeyEx (REGTREE, RegKey, 0, KEY_QUERY_VALUE, &hKey); - - if (retCode != ERROR_SUCCESS) - return; - else - { - ForwardingInfo->ConnectScript = RegGetMultiStringValue(hKey, "Connect Script"); - ForwardingInfo->TOCalls = RegGetMultiStringValue(hKey, "TOCalls"); - ForwardingInfo->ATCalls = RegGetMultiStringValue(hKey, "ATCalls"); - ForwardingInfo->Haddresses = RegGetMultiStringValue(hKey, "HRoutes"); - ForwardingInfo->HaddressesP = RegGetMultiStringValue(hKey, "HRoutesP"); - ForwardingInfo->FWDTimes = RegGetMultiStringValue(hKey, "FWD Times"); - - Vallen=4; - retCode += RegQueryValueEx(hKey, "Enabled", 0, - (ULONG *)&Type,(UCHAR *)&ForwardingInfo->Enabled,(ULONG *)&Vallen); - - Vallen=4; - retCode += RegQueryValueEx(hKey, "RequestReverse", 0, - (ULONG *)&Type,(UCHAR *)&ForwardingInfo->ReverseFlag,(ULONG *)&Vallen); - - Vallen=4; - retCode += RegQueryValueEx(hKey, "AllowCompressed", 0, - (ULONG *)&Type,(UCHAR *)&ForwardingInfo->AllowCompressed,(ULONG *)&Vallen); - - Vallen=4; - retCode += RegQueryValueEx(hKey, "Use B1 Protocol", 0, - (ULONG *)&Type,(UCHAR *)&ForwardingInfo->AllowB1,(ULONG *)&Vallen); - - Vallen=4; - retCode += RegQueryValueEx(hKey, "Use B2 Protocol", 0, - (ULONG *)&Type,(UCHAR *)&ForwardingInfo->AllowB2,(ULONG *)&Vallen); - - Vallen=4; - retCode += RegQueryValueEx(hKey, "SendCTRLZ", 0, - (ULONG *)&Type,(UCHAR *)&ForwardingInfo->SendCTRLZ,(ULONG *)&Vallen); - - if (ForwardingInfo->AllowB1 || ForwardingInfo->AllowB2) - ForwardingInfo->AllowCompressed = TRUE; - - Vallen=4; - retCode += RegQueryValueEx(hKey, "FWD Personals Only", 0, - (ULONG *)&Type,(UCHAR *)&ForwardingInfo->PersonalOnly,(ULONG *)&Vallen); - - Vallen=4; - retCode += RegQueryValueEx(hKey, "FWD New Immediately", 0, - (ULONG *)&Type,(UCHAR *)&ForwardingInfo->SendNew,(ULONG *)&Vallen); - - Vallen=4; - RegQueryValueEx(hKey,"FWDInterval",0, - (ULONG *)&Type,(UCHAR *)&ForwardingInfo->FwdInterval,(ULONG *)&Vallen); - - Vallen=4; - RegQueryValueEx(hKey,"RevFWDInterval",0, - (ULONG *)&Type,(UCHAR *)&ForwardingInfo->RevFwdInterval,(ULONG *)&Vallen); - - RegQueryValueEx(hKey,"MaxFBBBlock",0, - (ULONG *)&Type,(UCHAR *)&ForwardingInfo->MaxFBBBlockSize,(ULONG *)&Vallen); - - if (ForwardingInfo->MaxFBBBlockSize == 0) - ForwardingInfo->MaxFBBBlockSize = 10000; - - if (ForwardingInfo->FwdInterval == 0) - ForwardingInfo->FwdInterval = 3600; - - Vallen=0; - retCode = RegQueryValueEx(hKey,"BBSHA",0 , (ULONG *)&Type,NULL, (ULONG *)&Vallen); - - if (retCode != 0) - { - // No Key - Get from WP?? - - WPRec * ptr = LookupWP(user->Call); - - if (ptr) - { - if (ptr->first_homebbs) - { - ForwardingInfo->BBSHA = _strdup(ptr->first_homebbs); - } - } - } - - if (Vallen) - { - ForwardingInfo->BBSHA = malloc(Vallen); - RegQueryValueEx(hKey, "BBSHA", 0, (ULONG *)&Type, ForwardingInfo->BBSHA,(ULONG *)&Vallen); - } - - RegCloseKey(hKey); - } -#endif - } - - // Convert FWD Times and H Addresses - - if (ForwardingInfo->FWDTimes) - SetupFwdTimes(ForwardingInfo); - - if (ForwardingInfo->Haddresses) - SetupHAddreses(ForwardingInfo); - - if (ForwardingInfo->HaddressesP) - SetupHAddresesP(ForwardingInfo); - - if (ForwardingInfo->BBSHA) - { - if (ForwardingInfo->BBSHA[0]) - SetupHAElements(ForwardingInfo); - else - { - free(ForwardingInfo->BBSHA); - ForwardingInfo->BBSHA = NULL; - } - } - - for (m = FirstMessageIndextoForward; m <= NumberofMessages; m++) - { - Msg=MsgHddrPtr[m]; - - // If any forward bits are set, increment count on BBS record. - - if (memcmp(Msg->fbbs, zeros, NBMASK) != 0) - { - if (Msg->type && check_fwd_bit(Msg->fbbs, user->BBSNumber)) - { - user->ForwardingInfo->MsgCount++; - } - } - } -} - -VOID * GetMultiStringValue(config_setting_t * group, char * ValueName) -{ - char * ptr1; - char * MultiString = NULL; - const char * ptr; - int Count = 0; - char ** Value; - config_setting_t *setting; - char * Save; - - Value = zalloc(sizeof(void *)); // always NULL entry on end even if no values - Value[0] = NULL; - - setting = config_setting_get_member (group, ValueName); - - if (setting) - { - ptr = config_setting_get_string (setting); - - Save = _strdup(ptr); // DOnt want to change config string - ptr = Save; - - while (ptr && strlen(ptr)) - { - ptr1 = strchr(ptr, '|'); - - if (ptr1) - *(ptr1++) = 0; - - if (strlen(ptr)) // ignore null elements - { - Value = realloc(Value, (Count+2) * sizeof(void *)); - Value[Count++] = _strdup(ptr); - } - ptr = ptr1; - } - free(Save); - } - - Value[Count] = NULL; - return Value; -} - - -VOID * RegGetMultiStringValue(HKEY hKey, char * ValueName) -{ -#ifdef LINBPQ - return NULL; -#else - int retCode,Type,Vallen; - char * MultiString = NULL; - int ptr, len; - int Count = 0; - char ** Value; - - Value = zalloc(sizeof(void *)); // always NULL entry on end even if no values - - Value[0] = NULL; - - Vallen=0; - - - retCode = RegQueryValueEx(hKey, ValueName, 0, (ULONG *)&Type, NULL, (ULONG *)&Vallen); - - if ((retCode != 0) || (Vallen < 3)) // Two nulls means empty multistring - { - free(Value); - return FALSE; - } - - MultiString = malloc(Vallen); - - retCode = RegQueryValueEx(hKey, ValueName, 0, - (ULONG *)&Type,(UCHAR *)MultiString,(ULONG *)&Vallen); - - ptr=0; - - while (MultiString[ptr]) - { - len=strlen(&MultiString[ptr]); - - Value = realloc(Value, (Count+2) * sizeof(void *)); - Value[Count++] = _strdup(&MultiString[ptr]); - ptr+= (len + 1); - } - - Value[Count] = NULL; - - free(MultiString); - - return Value; -#endif -} - -VOID FreeForwardingStruct(struct UserInfo * user) -{ - struct BBSForwardingInfo * ForwardingInfo; - int i; - - - ForwardingInfo = user->ForwardingInfo; - - FreeList(ForwardingInfo->TOCalls); - FreeList(ForwardingInfo->ATCalls); - FreeList(ForwardingInfo->Haddresses); - FreeList(ForwardingInfo->HaddressesP); - - i=0; - if(ForwardingInfo->HADDRS) - { - while(ForwardingInfo->HADDRS[i]) - { - FreeList(ForwardingInfo->HADDRS[i]); - i++; - } - free(ForwardingInfo->HADDRS); - free(ForwardingInfo->HADDROffet); - } - - i=0; - if(ForwardingInfo->HADDRSP) - { - while(ForwardingInfo->HADDRSP[i]) - { - FreeList(ForwardingInfo->HADDRSP[i]); - i++; - } - free(ForwardingInfo->HADDRSP); - } - - FreeList(ForwardingInfo->ConnectScript); - FreeList(ForwardingInfo->FWDTimes); - if (ForwardingInfo->FWDBands) - { - i=0; - while(ForwardingInfo->FWDBands[i]) - { - free(ForwardingInfo->FWDBands[i]); - i++; - } - free(ForwardingInfo->FWDBands); - } - if (ForwardingInfo->BBSHAElements) - { - i=0; - while(ForwardingInfo->BBSHAElements[i]) - { - free(ForwardingInfo->BBSHAElements[i]); - i++; - } - free(ForwardingInfo->BBSHAElements); - } - free(ForwardingInfo->BBSHA); - -} - -VOID FreeList(char ** Hddr) -{ - VOID ** Save; - - if (Hddr) - { - Save = (void **)Hddr; - while(Hddr[0]) - { - free(Hddr[0]); - Hddr++; - } - free(Save); - } -} - - -VOID ReinitializeFWDStruct(struct UserInfo * user) -{ - if (user->ForwardingInfo) - { - FreeForwardingStruct(user); - free(user->ForwardingInfo); - } - - SetupForwardingStruct(user); - -} - -VOID SetupFwdTimes(struct BBSForwardingInfo * ForwardingInfo) -{ - char ** Times = ForwardingInfo->FWDTimes; - int Start, End; - int Count = 0; - - ForwardingInfo->FWDBands = zalloc(sizeof(struct FWDBAND)); - - if (Times) - { - while(Times[0]) - { - ForwardingInfo->FWDBands = realloc(ForwardingInfo->FWDBands, (Count+2)* sizeof(struct FWDBAND)); - ForwardingInfo->FWDBands[Count] = zalloc(sizeof(struct FWDBAND)); - - Start = atoi(Times[0]); - End = atoi(&Times[0][5]); - - ForwardingInfo->FWDBands[Count]->FWDStartBand = (time_t)(Start / 100) * 3600 + (Start % 100) * 60; - ForwardingInfo->FWDBands[Count]->FWDEndBand = (time_t)(End / 100) * 3600 + (End % 100) * 60 + 59; - - Count++; - Times++; - } - ForwardingInfo->FWDBands[Count] = NULL; - } -} -void StartForwarding(int BBSNumber, char ** TempScript) -{ - struct UserInfo * user; - struct BBSForwardingInfo * ForwardingInfo ; - time_t NOW = time(NULL); - - - for (user = BBSChain; user; user = user->BBSNext) - { - // See if any messages are queued for this BBS - - ForwardingInfo = user->ForwardingInfo; - - if ((BBSNumber == 0) || (user->BBSNumber == BBSNumber)) - if (ForwardingInfo) - if (ForwardingInfo->Enabled || BBSNumber) // Menu Command overrides enable - if (ForwardingInfo->ConnectScript && (ForwardingInfo->Forwarding == 0) && ForwardingInfo->ConnectScript[0]) - if (BBSNumber || SeeifMessagestoForward(user->BBSNumber, NULL) || - (ForwardingInfo->ReverseFlag && ((NOW - ForwardingInfo->LastReverseForward) >= ForwardingInfo->RevFwdInterval))) // Menu Command overrides Reverse - { - user->ForwardingInfo->ScriptIndex = -1; // Incremented before being used - - // See if TempScript requested - - if (user->ForwardingInfo->TempConnectScript) - FreeList(user->ForwardingInfo->TempConnectScript); - - user->ForwardingInfo->TempConnectScript = TempScript; - - if (ConnecttoBBS(user)) - ForwardingInfo->Forwarding = TRUE; - } - } - - return; -} - -size_t fwritex(CIRCUIT * conn, void * _Str, size_t _Size, size_t _Count, FILE * _File) -{ - if (_File) - return fwrite(_Str, _Size, _Count, _File); - - // Appending to MailBuffer - - memcpy(&conn->MailBuffer[conn->InputLen], _Str, _Count); - conn->InputLen += (int)_Count; - - return _Count; -} - - -BOOL ForwardMessagestoFile(CIRCUIT * conn, char * FN) -{ - BOOL AddCRLF = FALSE; - BOOL AutoImport = FALSE; - FILE * Handle = NULL; - char * Context; - BOOL Email = FALSE; - time_t now = time(NULL); - char * param; - - FN = strtok_s(FN, " ,", &Context); - - param = strtok_s(NULL, " ,", &Context); - - if (param) - { - if (_stricmp(param, "ADDCRLF") == 0) - AddCRLF = TRUE; - - if (_stricmp(param, "AutoImport") == 0) - AutoImport = TRUE; - - param = strtok_s(NULL, " ,", &Context); - - if (param) - { - if (_stricmp(param, "ADDCRLF") == 0) - AddCRLF = TRUE; - - if (_stricmp(param, "AutoImport") == 0) - AutoImport = TRUE; - - } - } - // If FN is an email address, write to a temp file, and send via rms or emali gateway - - if (strchr(FN, '@') || _memicmp(FN, "RMS:", 4) == 0) - { - Email = TRUE; - AddCRLF =TRUE; - conn->MailBuffer=malloc(100000); - conn->MailBufferSize=100000; - conn->InputLen = 0; - } - else - { - Handle = fopen(FN, "ab"); - - if (Handle == NULL) - { - int err = GetLastError(); - Logprintf(LOG_BBS, conn, '!', "Failed to open Export File %s", FN); - return FALSE; - } - } - - while (FindMessagestoForward(conn)) - { - struct MsgInfo * Msg; - struct tm * tm; - time_t temp; - char * MsgBytes = ReadMessageFile(conn->FwdMsg->number); - int MsgLen; - char * MsgPtr; - char Line[256]; - int len; - struct UserInfo * user = conn->UserPointer; - int Index = 0; - - Msg = conn->FwdMsg; - - if (Email) - if (conn->InputLen + Msg->length + 500 > conn->MailBufferSize) - break; - - if (Msg->type == 'P') - Index = PMSG; - else if (Msg->type == 'B') - Index = BMSG; - else if (Msg->type == 'T') - Index = TMSG; - - - if (Msg->via[0]) - len = sprintf(Line, "S%c %s @ %s < %s $%s\r\n", Msg->type, Msg->to, - Msg->via, Msg->from, Msg->bid); - else - len = sprintf(Line, "S%c %s < %s $%s\r\n", Msg->type, Msg->to, Msg->from, Msg->bid); - - fwritex(conn, Line, 1, len, Handle); - - len = sprintf(Line, "%s\r\n", Msg->title); - fwritex(conn, Line, 1, len, Handle); - - if (MsgBytes == 0) - { - MsgBytes = _strdup("Message file not found\r\n"); - conn->FwdMsg->length = (int)strlen(MsgBytes); - } - - MsgPtr = MsgBytes; - MsgLen = conn->FwdMsg->length; - - // If a B2 Message, remove B2 Header - - if (conn->FwdMsg->B2Flags & B2Msg) - { - // Remove all B2 Headers, and all but the first part. - - MsgPtr = strstr(MsgBytes, "Body:"); - - if (MsgPtr) - { - MsgLen = atoi(&MsgPtr[5]); - MsgPtr = strstr(MsgBytes, "\r\n\r\n"); // Blank Line after headers - - if (MsgPtr) - MsgPtr +=4; - else - MsgPtr = MsgBytes; - - } - else - MsgPtr = MsgBytes; - } - - memcpy(&temp, &Msg->datereceived, sizeof(time_t)); - tm = gmtime(&temp); - - len = sprintf(Line, "R:%02d%02d%02d/%02d%02dZ %d@%s.%s %s\r\n", - tm->tm_year-100, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, - conn->FwdMsg->number, BBSName, HRoute, RlineVer); - - fwritex(conn, Line, 1, len, Handle); - - if (memcmp(MsgPtr, "R:", 2) != 0) // No R line, so must be our message - put blank line after header - fwritex(conn, "\r\n", 1, 2, Handle); - - fwritex(conn, MsgPtr, 1, MsgLen, Handle); - - if (MsgPtr[MsgLen - 2] == '\r') - fwritex(conn, "/EX\r\n", 1, 5, Handle); - else - fwritex(conn, "\r\n/EX\r\n", 1, 7, Handle); - - if (AddCRLF) - fwritex(conn, "\r\n", 1, 2, Handle); - - free(MsgBytes); - - user->Total.MsgsSent[Index]++; - user->Total.BytesForwardedOut[Index] += MsgLen; - - Msg->datechanged = now; - - clear_fwd_bit(conn->FwdMsg->fbbs, user->BBSNumber); - set_fwd_bit(conn->FwdMsg->forw, user->BBSNumber); - - // Only mark as forwarded if sent to all BBSs that should have it - - if (memcmp(conn->FwdMsg->fbbs, zeros, NBMASK) == 0) - { - conn->FwdMsg->status = 'F'; // Mark as forwarded - conn->FwdMsg->datechanged=time(NULL); - } - - conn->UserPointer->ForwardingInfo->MsgCount--; - } - - if (Email) - { - struct MsgInfo * Msg; - BIDRec * BIDRec; - - if (conn->InputLen == 0) - { - free(conn->MailBuffer); - conn->MailBufferSize=0; - conn->MailBuffer=0; - - return TRUE; - } - - // Allocate a message Record slot - - Msg = AllocateMsgRecord(); - - // Set number here so they remain in sequence - - GetSemaphore(&MsgNoSemaphore, 0); - Msg->number = ++LatestMsg; - FreeSemaphore(&MsgNoSemaphore); - MsgnotoMsg[Msg->number] = Msg; - - Msg->type = 'P'; - Msg->status = 'N'; - Msg->datecreated = Msg->datechanged = Msg->datereceived = now; - - strcpy(Msg->from, BBSName); - - sprintf_s(Msg->bid, sizeof(Msg->bid), "%d_%s", LatestMsg, BBSName); - - if (AutoImport) - sprintf(Msg->title, "Batched messages for AutoImport from BBS %s", BBSName); - else - sprintf(Msg->title, "Batched messages from BBS %s", BBSName); - - Msg->length = conn->InputLen; - CreateMessageFile(conn, Msg); - - BIDRec = AllocateBIDRecord(); - - strcpy(BIDRec->BID, Msg->bid); - BIDRec->mode = Msg->type; - BIDRec->u.msgno = LOWORD(Msg->number); - BIDRec->u.timestamp = LOWORD(time(NULL)/86400); - - if (_memicmp(FN, "SMTP:", 5) == 0) - { - strcpy(Msg->via, &FN[5]); - SMTPMsgCreated=TRUE; - } - else - { - strcpy(Msg->to, "RMS"); - if (_memicmp(FN, "RMS:", 4) == 0) - strcpy(Msg->via, &FN[4]); - else - strcpy(Msg->via, FN); - } - - MatchMessagetoBBSList(Msg, conn); - - SaveMessageDatabase(); - SaveBIDDatabase(); - } - else - fclose(Handle); - - SaveMessageDatabase(); - return TRUE; -} - -BOOL ForwardMessagetoFile(struct MsgInfo * Msg, FILE * Handle) -{ - struct tm * tm; - time_t temp; - - char * MsgBytes = ReadMessageFile(Msg->number); - char * MsgPtr; - char Line[256]; - int len; - int MsgLen = Msg->length; - - if (Msg->via[0]) - len = sprintf(Line, "S%c %s @ %s < %s $%s\r\n", Msg->type, Msg->to, - Msg->via, Msg->from, Msg->bid); - else - len = sprintf(Line, "S%c %s < %s $%s\r\n", Msg->type, Msg->to, Msg->from, Msg->bid); - - fwrite(Line, 1, len, Handle); - - len = sprintf(Line, "%s\r\n", Msg->title); - fwrite(Line, 1, len, Handle); - - if (MsgBytes == 0) - { - MsgBytes = _strdup("Message file not found\r\n"); - MsgLen = (int)strlen(MsgBytes); - } - - MsgPtr = MsgBytes; - - // If a B2 Message, remove B2 Header - - if (Msg->B2Flags & B2Msg) - { - // Remove all B2 Headers, and all but the first part. - - MsgPtr = strstr(MsgBytes, "Body:"); - - if (MsgPtr) - { - MsgLen = atoi(&MsgPtr[5]); - - MsgPtr= strstr(MsgBytes, "\r\n\r\n"); // Blank Line after headers - - if (MsgPtr) - MsgPtr +=4; - else - MsgPtr = MsgBytes; - - } - else - MsgPtr = MsgBytes; - } - - memcpy(&temp, &Msg->datereceived, sizeof(time_t)); - tm = gmtime(&temp); - - len = sprintf(Line, "R:%02d%02d%02d/%02d%02dZ %d@%s.%s %s\r\n", - tm->tm_year-100, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, - Msg->number, BBSName, HRoute, RlineVer); - - fwrite(Line, 1, len, Handle); - - if (memcmp(MsgPtr, "R:", 2) != 0) // No R line, so must be our message - put blank line after header - fwrite("\r\n", 1, 2, Handle); - - fwrite(MsgPtr, 1, MsgLen, Handle); - - if (MsgPtr[MsgLen - 2] == '\r') - fwrite("/EX\r\n", 1, 5, Handle); - else - fwrite("\r\n/EX\r\n", 1, 7, Handle); - - free(MsgBytes); - - return TRUE; - -} - -BOOL ConnecttoBBS (struct UserInfo * user) -{ - int n, p; - CIRCUIT * conn; - struct BBSForwardingInfo * ForwardingInfo = user->ForwardingInfo; - - for (n = NumberofStreams-1; n >= 0 ; n--) - { - conn = &Connections[n]; - - if (conn->Active == FALSE) - { - p = conn->BPQStream; - memset(conn, 0, sizeof(ConnectionInfo)); // Clear everything - conn->BPQStream = p; - - // Can't set Active until Connected or Stuck Session detertor can clear session. - // But must set Active before Connected() runs or will appear is Incoming Connect. - // Connected() is semaphored, so get semaphore before ConnectUsingAppl - // Probably better to semaphore lost session code instead - - - strcpy(conn->Callsign, user->Call); - conn->BBSFlags |= (RunningConnectScript | OUTWARDCONNECT); - conn->UserPointer = user; - - Logprintf(LOG_BBS, conn, '|', "Connecting to BBS %s", user->Call); - - ForwardingInfo->MoreLines = TRUE; - - GetSemaphore(&ConSemaphore, 1); - conn->Active = TRUE; - ConnectUsingAppl(conn->BPQStream, BBSApplMask); - FreeSemaphore(&ConSemaphore); - - // If we are sending to a dump pms we may need to connect using the message sender's callsign. - // But we wont know until we run the connect script, which is a bit late to change call. Could add - // flag to forwarding config, but easier to look for SETCALLTOSENDER in the connect script. - - if (strstr(ForwardingInfo->ConnectScript[0], "SETCALLTOSENDER")) - { - conn->SendB = conn->SendP = conn->SendT = conn->DoReverse = TRUE; - conn->MaxBLen = conn->MaxPLen = conn->MaxTLen = 99999999; - - if (FindMessagestoForward(conn) && conn->FwdMsg) - { - // We have a message to send - - struct MsgInfo * Msg; - unsigned char AXCall[7]; - - Msg = conn->FwdMsg; - ConvToAX25(Msg->from, AXCall); - ChangeSessionCallsign(p, AXCall); - - conn->BBSFlags |= TEXTFORWARDING | SETCALLTOSENDER | NEWPACCOM; - conn->NextMessagetoForward = 0; // was set by FindMessages - } - conn->SendB = conn->SendP = conn->SendT = conn->DoReverse = FALSE; - } -#ifdef LINBPQ - { - BPQVECSTRUC * SESS; - SESS = &BPQHOSTVECTOR[conn->BPQStream - 1]; - - if (SESS->HOSTSESSION == NULL) - { - Logprintf(LOG_BBS, NULL, '|', "No L4 Sessions for connect to BBS %s", user->Call); - return FALSE; - } - - SESS->HOSTSESSION->Secure_Session = 1; - } -#endif - - strcpy(conn->Callsign, user->Call); - - // Connected Event will trigger connect to remote system - - RefreshMainWindow(); - - return TRUE; - } - } - - Logprintf(LOG_BBS, NULL, '|', "No Free Streams for connect to BBS %s", user->Call); - - return FALSE; - -} - -struct DelayParam -{ - struct UserInfo * User; - CIRCUIT * conn; - int Delay; -}; - -struct DelayParam DParam; // Not 100% safe, but near enough - -VOID ConnectDelayThread(struct DelayParam * DParam) -{ - struct UserInfo * User = DParam->User; - int Delay = DParam->Delay; - - User->ForwardingInfo->Forwarding = TRUE; // Minimize window for two connects - - Sleep(Delay); - - User->ForwardingInfo->Forwarding = TRUE; - ConnecttoBBS(User); - - return; -} - -VOID ConnectPauseThread(struct DelayParam * DParam) -{ - CIRCUIT * conn = DParam->conn; - int Delay = DParam->Delay; - char Msg[] = "Pause Ok\r "; - - Sleep(Delay); - - ProcessBBSConnectScript(conn, Msg, 9); - - return; -} - - -/* -BOOL ProcessBBSConnectScriptInner(CIRCUIT * conn, char * Buffer, int len); - - -BOOL ProcessBBSConnectScript(CIRCUIT * conn, char * Buffer, int len) -{ - BOOL Ret; - GetSemaphore(&ScriptSEM); - Ret = ProcessBBSConnectScriptInner(conn, Buffer, len); - FreeSemaphore(&ScriptSEM); - - return Ret; -} -*/ - -BOOL ProcessBBSConnectScript(CIRCUIT * conn, char * Buffer, int len) -{ - struct BBSForwardingInfo * ForwardingInfo = conn->UserPointer->ForwardingInfo; - char ** Scripts; - char callsign[10]; - int port, sesstype, paclen, maxframe, l4window; - char * ptr, * ptr2; - - WriteLogLine(conn, '<',Buffer, len-1, LOG_BBS); - - Buffer[len]=0; - _strupr(Buffer); - - if (ForwardingInfo->TempConnectScript) - Scripts = ForwardingInfo->TempConnectScript; - else - Scripts = ForwardingInfo->ConnectScript; - - if (ForwardingInfo->ScriptIndex == -1) - { - // First Entry - if first line is TIMES, check and skip forward if necessary - - int n = 0; - int Start, End; - time_t now = time(NULL), StartSecs, EndSecs; - char * Line; - - if (Localtime) - now -= (time_t)_MYTIMEZONE; - - now %= 86400; - Line = Scripts[n]; - - if (_memicmp(Line, "TIMES", 5) == 0) - { - NextBand: - Start = atoi(&Line[6]); - End = atoi(&Line[11]); - - StartSecs = (time_t)(Start / 100) * 3600 + (Start % 100) * 60; - EndSecs = (time_t)(End / 100) * 3600 + (End % 100) * 60 + 59; - - if ((StartSecs <= now) && (EndSecs >= now)) - goto InBand; // In band - - // Look for next TIME - NextLine: - Line = Scripts[++n]; - - if (Line == NULL) - { - // No more lines - Disconnect - - conn->BBSFlags &= ~RunningConnectScript; // so it doesn't get reentered - Disconnect(conn->BPQStream); - return FALSE; - } - - if (_memicmp(Line, "TIMES", 5) != 0) - goto NextLine; - else - goto NextBand; -InBand: - ForwardingInfo->ScriptIndex = n; - } - - } - else - { - // Dont check first time through - - if (strcmp(Buffer, "*** CONNECTED ") != 0) - { - if (Scripts[ForwardingInfo->ScriptIndex] == NULL || - _memicmp(Scripts[ForwardingInfo->ScriptIndex], "TIMES", 5) == 0 || // Only Check until script is finished - _memicmp(Scripts[ForwardingInfo->ScriptIndex], "ELSE", 4) == 0) // Only Check until script is finished - { - ForwardingInfo->MoreLines = FALSE; - } - if (!ForwardingInfo->MoreLines) - goto CheckForSID; - } - } - - if (strstr(Buffer, "BUSY") || strstr(Buffer, "FAILURE") || - (strstr(Buffer, "DOWNLINK") && strstr(Buffer, "ATTEMPTING") == 0) || - strstr(Buffer, "SORRY") || strstr(Buffer, "INVALID") || strstr(Buffer, "RETRIED") || - strstr(Buffer, "NO CONNECTION TO") || strstr(Buffer, "ERROR - ") || - strstr(Buffer, "UNABLE TO CONNECT") || strstr(Buffer, "DISCONNECTED") || - strstr(Buffer, "FAILED TO CONNECT") || strstr(Buffer, "REJECTED")) - { - // Connect Failed - - char * Cmd = Scripts[++ForwardingInfo->ScriptIndex]; - int Delay = 1000; - - // Look for an alternative connect block (Starting with ELSE) - - ElseLoop: - - // Skip any comments - - while (Cmd && ((strcmp(Cmd, " ") == 0 || Cmd[0] == ';' || Cmd[0] == '#'))) - Cmd = Scripts[++ForwardingInfo->ScriptIndex]; - - // TIMES terminates a script - - if (Cmd == 0 || _memicmp(Cmd, "TIMES", 5) == 0) // Only Check until script is finished - { - conn->BBSFlags &= ~RunningConnectScript; // so it doesn't get reentered - Disconnect(conn->BPQStream); - return FALSE; - } - - if (_memicmp(Cmd, "ELSE", 4) != 0) - { - Cmd = Scripts[++ForwardingInfo->ScriptIndex]; - goto ElseLoop; - } - - if (_memicmp(&Cmd[5], "DELAY", 5) == 0) - Delay = atoi(&Cmd[10]) * 1000; - else - Delay = 1000; - - conn->BBSFlags &= ~RunningConnectScript; // so it doesn't get reentered - Disconnect(conn->BPQStream); - - DParam.Delay = Delay; - DParam.User = conn->UserPointer; - - _beginthread((void (*)(void *))ConnectDelayThread, 0, &DParam); - - return FALSE; - } - - // The pointer is only updated when we get the connect, so we can tell when the last line is acked - // The first entry is always from Connected event, so don't have to worry about testing entry -1 below - - - // NETROM to KA node returns - - //c 1 milsw - //WIRAC:N9PMO-2} Connected to MILSW - //###CONNECTED TO NODE MILSW(N9ZXS) CHANNEL A - //You have reached N9ZXS's KA-Node MILSW - //ENTER COMMAND: B,C,J,N, or Help ? - - //C KB9PRF-7 - //###LINK MADE - //###CONNECTED TO NODE KB9PRF-7(KB9PRF-4) CHANNEL A - - // Look for (Space)Connected so we aren't fooled by ###CONNECTED TO NODE, which is not - // an indication of a connect. - - if (strstr(Buffer, " CONNECTED") || strstr(Buffer, "PACLEN") || strstr(Buffer, "IDLETIME") || - strstr(Buffer, "OK") || strstr(Buffer, "###LINK MADE") || strstr(Buffer, "VIRTUAL CIRCUIT ESTABLISHED")) - { - // If connected to SYNC, save IP address and port - - char * Cmd; - - if (strstr(Buffer, "*** CONNECTED TO SYNC")) - { - char * IPAddr = &Buffer[22]; - char * Port = strlop(IPAddr, ':'); - - if (Port) - { - if (conn->SyncHost) - free(conn->SyncHost); - - conn->SyncHost = _strdup(IPAddr); - conn->SyncPort = atoi(Port); - } - } - - if (conn->SkipConn) - { - conn->SkipConn = FALSE; - return TRUE; - } - - LoopBack: - - Cmd = Scripts[++ForwardingInfo->ScriptIndex]; - - // Only Check until script is finished - - if (Cmd && (strcmp(Cmd, " ") == 0 || Cmd[0] == ';' || Cmd[0] == '#')) - goto LoopBack; // Blank line - - if (Cmd && _memicmp(Cmd, "TIMES", 5) != 0 && _memicmp(Cmd, "ELSE", 4) != 0) // Only Check until script is finished - { - if (_memicmp(Cmd, "MSGTYPE", 7) == 0) - { - char * ptr; - - // Select Types to send. Only send types in param. Only reverse if R in param - - _strupr(Cmd); - - Logprintf(LOG_BBS, conn, '?', "Script %s", Cmd); - - conn->SendB = conn->SendP = conn->SendT = conn->DoReverse = FALSE; - - strcpy(conn->MSGTYPES, &Cmd[8]); - - if (strchr(&Cmd[8], 'R')) conn->DoReverse = TRUE; - - ptr = strchr(&Cmd[8], 'B'); - - if (ptr) - { - conn->SendB = TRUE; - conn->MaxBLen = atoi(++ptr); - if (conn->MaxBLen == 0) conn->MaxBLen = 99999999; - } - - ptr = strchr(&Cmd[8], 'T'); - - if (ptr) - { - conn->SendT = TRUE; - conn->MaxTLen = atoi(++ptr); - if (conn->MaxTLen == 0) conn->MaxTLen = 99999999; - } - ptr = strchr(&Cmd[8], 'P'); - - if (ptr) - { - conn->SendP = TRUE; - conn->MaxPLen = atoi(++ptr); - if (conn->MaxPLen == 0) conn->MaxPLen = 99999999; - } - - // If nothing to do, terminate script - - if (conn->DoReverse || SeeifMessagestoForward(conn->UserPointer->BBSNumber, conn)) - goto LoopBack; - - Logprintf(LOG_BBS, conn, '?', "Nothing to do - quitting"); - conn->BBSFlags &= ~RunningConnectScript; // so it doesn't get reentered - Disconnect(conn->BPQStream); - return FALSE; - } - - if (_memicmp(Cmd, "INTERLOCK ", 10) == 0) - { - // Used to limit connects on a port to 1 - - int Port; - char Option[80]; - - Logprintf(LOG_BBS, conn, '?', "Script %s", Cmd); - - sscanf(&Cmd[10], "%d %s", &Port, &Option[0]); - - if (CountConnectionsOnPort(Port)) - { - Logprintf(LOG_BBS, conn, '?', "Interlocked Port is busy - quitting"); - conn->BBSFlags &= ~RunningConnectScript; // so it doesn't get reentered - Disconnect(conn->BPQStream); - return FALSE; - } - - goto LoopBack; - } - - if (_memicmp(Cmd, "RADIO AUTH", 10) == 0) - { - // Generate a Password to enable RADIO commands on a remote node - char AuthCommand[80]; - - _strupr(Cmd); - strcpy(AuthCommand, Cmd); - - CreateOneTimePassword(&AuthCommand[11], &Cmd[11], 0); - - nodeprintf(conn, "%s\r", AuthCommand); - return TRUE; - } - - if (_memicmp(Cmd, "SKIPCON", 7) == 0) - { - // Remote Node sends Connected in CTEXT - we need to swallow it - - conn->SkipConn = TRUE; - goto CheckForEnd; - } - - if (_memicmp(Cmd, "SendWL2KPM", 10) == 0|| _memicmp(Cmd, "SendWL2KFW", 10) == 0) - { - // Send ;FW: command - - conn->SendWL2KFW = TRUE; - goto CheckForEnd; - } - - if (_memicmp(Cmd, "SKIPPROMPT", 10) == 0) - { - // Remote Node sends > at end of CTEXT - we need to swallow it - - conn->SkipPrompt++; - goto CheckForEnd; - } - - if (_memicmp(Cmd, "TEXTFORWARDING", 10) == 0) - { - conn->BBSFlags |= TEXTFORWARDING; - goto CheckForEnd; - } - - if (_memicmp(Cmd, "SETCALLTOSENDER", 15) == 0) - { - conn->BBSFlags |= TEXTFORWARDING | SETCALLTOSENDER; - goto CheckForEnd; - } - - if (_memicmp(Cmd, "RADIOONLY", 9) == 0) - { - conn->BBSFlags |= WINLINKRO; - goto CheckForEnd; - } - - if (_memicmp(Cmd, "SYNC", 4) == 0) - { - conn->BBSFlags |= SYNCMODE; - goto CheckForEnd; - } - - if (_memicmp(Cmd, "NEEDLF", 6) == 0) - { - conn->BBSFlags |= NEEDLF; - goto CheckForEnd; - } - - if (_memicmp(Cmd, "MCASTRX", 6) == 0) - { - conn->BBSFlags |= MCASTRX; - conn->MCastListenTime = atoi(&Cmd[7]) * 6; // Time to run session for *6 as value is mins put timer ticks 10 secs - - // send MCAST to Node - - nodeprintfEx(conn, "MCAST\r"); - return TRUE; - } - - if (_memicmp(Cmd, "FLARQ", 5) == 0) - { - conn->BBSFlags |= FLARQMAIL; - - CheckForEnd: - if (Scripts[ForwardingInfo->ScriptIndex + 1] == NULL || - memcmp(Scripts[ForwardingInfo->ScriptIndex +1], "TIMES", 5) == 0 || // Only Check until script is finished - memcmp(Scripts[ForwardingInfo->ScriptIndex + 1], "ELSE", 4) == 0) // Only Check until script is finished - ForwardingInfo->MoreLines = FALSE; - - goto LoopBack; - } - if (_memicmp(Cmd, "PAUSE", 5) == 0) - { - // Pause script - - Logprintf(LOG_BBS, conn, '?', "Script %s", Cmd); - - DParam.Delay = atoi(&Cmd[6]) * 1000; - DParam.conn = conn; - - _beginthread((void (*)(void *))ConnectPauseThread, 0, &DParam); - - return TRUE; - } - - if (_memicmp(Cmd, "FILE", 4) == 0) - { - if (Cmd[4] == 0) - { - // Missing Filename - - Logprintf(LOG_BBS, conn, '!', "Export file name missing"); - } - else - ForwardMessagestoFile(conn, &Cmd[5]); - - conn->BBSFlags &= ~RunningConnectScript; // so it doesn't get reentered - Disconnect(conn->BPQStream); - return FALSE; - } - - if (_memicmp(Cmd, "SMTP", 4) == 0) - { - conn->NextMessagetoForward = FirstMessageIndextoForward; - conn->UserPointer->Total.ConnectsOut++; - - SendAMPRSMTP(conn); - conn->BBSFlags &= ~RunningConnectScript; // so it doesn't get reentered - Disconnect(conn->BPQStream); - return FALSE; - } - - - if (_memicmp(Cmd, "IMPORT", 6) == 0) - { - char * File, * Context; - int Num; - char * Temp = _strdup(Cmd); - - File = strtok_s(&Temp[6], " ", &Context); - - if (File && File[0]) - { - Num = ImportMessages(NULL, File, TRUE); - - Logprintf(LOG_BBS, NULL, '|', "Imported %d Message(s) from %s", Num, File); - - if (Context && _stricmp(Context, "delete") == 0) - DeleteFile(File); - } - free(Temp); - - if (Scripts[ForwardingInfo->ScriptIndex + 1] == NULL || - memcmp(Scripts[ForwardingInfo->ScriptIndex +1], "TIMES", 5) == 0 || // Only Check until script is finished - memcmp(Scripts[ForwardingInfo->ScriptIndex + 1], "ELSE", 4) == 0) // Only Check until script is finished - { - conn->BBSFlags &= ~RunningConnectScript; // so it doesn't get reentered - Disconnect(conn->BPQStream); - return FALSE; - } - goto LoopBack; - } - - // Anything else is sent to Node - - // Replace \ with # so can send commands starting with # - - if (Cmd[0] == '\\') - { - Cmd[0] = '#'; - nodeprintfEx(conn, "%s\r", Cmd); - Cmd[0] = '\\'; // Put \ back in script - } - else - nodeprintfEx(conn, "%s\r", Cmd); - - return TRUE; - } - - // End of script. - - ForwardingInfo->MoreLines = FALSE; - - if (conn->BBSFlags & MCASTRX) - { - // No session with Multicast, so no SID - - conn->BBSFlags &= ~RunningConnectScript; - return TRUE; - } - - if (conn->BBSFlags & FLARQMAIL) - { - // FLARQ doesnt send a prompt - Just send message(es) - - conn->UserPointer->Total.ConnectsOut++; - conn->BBSFlags &= ~RunningConnectScript; - ForwardingInfo->LastReverseForward = time(NULL); - - // Update Paclen - - GetConnectionInfo(conn->BPQStream, callsign, &port, &sesstype, &paclen, &maxframe, &l4window); - - if (paclen > 0) - conn->paclen = paclen; - - SendARQMail(conn); - return TRUE; - } - - - return TRUE; - } - - ptr = strchr(Buffer, '}'); - - if (ptr && ForwardingInfo->MoreLines) // Beware it could be part of ctext - { - // Could be respsonse to Node Command - - ptr+=2; - - ptr2 = strchr(&ptr[0], ' '); - - if (ptr2) - { - if (_memicmp(ptr, Scripts[ForwardingInfo->ScriptIndex], ptr2-ptr) == 0) // Reply to last sscript command - { - if (Scripts[ForwardingInfo->ScriptIndex+1] && _memicmp(Scripts[ForwardingInfo->ScriptIndex+1], "else", 4) == 0) - { - // stray match or misconfigured - - return TRUE; - } - - ForwardingInfo->ScriptIndex++; - - if (Scripts[ForwardingInfo->ScriptIndex]) - if (_memicmp(Scripts[ForwardingInfo->ScriptIndex], "TIMES", 5) != 0) - nodeprintf(conn, "%s\r", Scripts[ForwardingInfo->ScriptIndex]); - - return TRUE; - } - } - } - - // Not Success or Fail. If last line is still outstanding, wait fot Response - // else look for SID or Prompt - - if (conn->SkipPrompt && Buffer[len-2] == '>') - { - conn->SkipPrompt--; - return TRUE; - } - - if (ForwardingInfo->MoreLines) - return TRUE; - - // No more steps, Look for SID or Prompt - -CheckForSID: - - if (strstr(Buffer, "POSYNCHELLO")) // RMS RELAY Sync process - { - conn->BBSFlags &= ~RunningConnectScript; // so it doesn't get reentered - conn->NextMessagetoForward = FirstMessageIndextoForward; - conn->UserPointer->Total.ConnectsOut++; - ForwardingInfo->LastReverseForward = time(NULL); - - ProcessLine(conn, 0, Buffer, len); - return FALSE; - } - - if (strstr(Buffer, "SORRY, NO")) // URONODE - { - conn->BBSFlags &= ~RunningConnectScript; // so it doesn't get reentered - Disconnect(conn->BPQStream); - return FALSE; - } - - if (memcmp(Buffer, ";PQ: ", 5) == 0) - { - // Secure CMS challenge - - int Len; - struct UserInfo * User = conn->UserPointer; - char * Pass = User->CMSPass; - int Response ; - char RespString[12]; - char ConnectingCall[10]; - -#ifdef LINBPQ - BPQVECSTRUC * SESS = &BPQHOSTVECTOR[0]; -#else - BPQVECSTRUC * SESS = (BPQVECSTRUC *)BPQHOSTVECPTR; -#endif - - SESS += conn->BPQStream - 1; - - ConvFromAX25(SESS->HOSTSESSION->L4USER, ConnectingCall); - - strlop(ConnectingCall, ' '); - - if (Pass[0] == 0) - { - Pass = User->pass; // Old Way - if (Pass[0] == 0) - { - strlop(ConnectingCall, '-'); - User = LookupCall(ConnectingCall); - if (User) - Pass = User->CMSPass; - } - } - - // - - Response = GetCMSHash(&Buffer[5], Pass); - - sprintf(RespString, "%010d", Response); - - Len = sprintf(conn->SecureMsg, ";PR: %s\r", &RespString[2]); - - // Save challengs in case needed for FW lines - - strcpy(conn->PQChallenge, &Buffer[5]); - - return FALSE; - } - - - if (Buffer[0] == '[' && Buffer[len-2] == ']') // SID - { - // Update PACLEN - - GetConnectionInfo(conn->BPQStream, callsign, &port, &sesstype, &paclen, &maxframe, &l4window); - - if (paclen > 0) - conn->paclen = paclen; - - - Parse_SID(conn, &Buffer[1], len-4); - - if (conn->BBSFlags & FBBForwarding) - { - conn->FBBIndex = 0; // ready for first block; - memset(&conn->FBBHeaders[0], 0, 5 * sizeof(struct FBBHeaderLine)); - conn->FBBChecksum = 0; - } - - return TRUE; - } - - if (memcmp(Buffer, "[PAKET ", 7) == 0) - { - conn->BBSFlags |= BBS; - conn->BBSFlags |= MBLFORWARDING; - } - - if (Buffer[len-2] == '>') - { - if (conn->SkipPrompt) - { - conn->SkipPrompt--; - return TRUE; - } - - conn->NextMessagetoForward = FirstMessageIndextoForward; - conn->UserPointer->Total.ConnectsOut++; - conn->BBSFlags &= ~RunningConnectScript; - ForwardingInfo->LastReverseForward = time(NULL); - - if (memcmp(Buffer, "[AEA PK", 7) == 0 || (conn->BBSFlags & TEXTFORWARDING)) - { - // PK232. Don't send a SID, and switch to Text Mode - - conn->BBSFlags |= (BBS | TEXTFORWARDING); - conn->Flags |= SENDTITLE; - - // Send Message. There is no mechanism for reverse forwarding - - if (FindMessagestoForward(conn) && conn->FwdMsg) - { - struct MsgInfo * Msg; - - // Send S line and wait for response - SB WANT @ USA < W8AAA $1029_N0XYZ - - Msg = conn->FwdMsg; - - if ((conn->BBSFlags & SETCALLTOSENDER)) - nodeprintf(conn, "S%c %s @ %s \r", Msg->type, Msg->to, - (Msg->via[0]) ? Msg->via : conn->UserPointer->Call); - else - nodeprintf(conn, "S%c %s @ %s < %s $%s\r", Msg->type, Msg->to, - (Msg->via[0]) ? Msg->via : conn->UserPointer->Call, - Msg->from, Msg->bid); - } - else - { - conn->BBSFlags &= ~RunningConnectScript; // so it doesn't get reentered - Disconnect(conn->BPQStream); - return FALSE; - } - - return TRUE; - } - - if (strcmp(conn->Callsign, "RMS") == 0 || conn->SendWL2KFW) - { - // Build a ;FW: line with all calls with PollRMS Set - - // According to Lee if you use secure login the first - // must be the BBS call - // Actually I don't think we need the first, - // as that is implied - - // If a secure password is available send the new - // call|response format. - - // I think this should use the session callsign, which - // normally will be the BBS ApplCall, and not the BBS Name, - // but coudl be changed by *** LINKED - - int i, s; - char FWLine[10000] = ";FW: "; - struct UserInfo * user; - char RMSCall[20]; - char ConnectingCall[10]; - -#ifdef LINBPQ - BPQVECSTRUC * SESS = &BPQHOSTVECTOR[0]; -#else - BPQVECSTRUC * SESS = (BPQVECSTRUC *)BPQHOSTVECPTR; -#endif - - SESS += conn->BPQStream - 1; - - ConvFromAX25(SESS->HOSTSESSION->L4USER, ConnectingCall); - strlop(ConnectingCall, ' '); - - strcat (FWLine, ConnectingCall); - - for (i = 0; i <= NumberofUsers; i++) - { - user = UserRecPtr[i]; - - if (user->flags & F_POLLRMS) - { - if (user->RMSSSIDBits == 0) user->RMSSSIDBits = 1; - - for (s = 0; s < 16; s++) - { - if (user->RMSSSIDBits & (1 << s)) - { - if (s) - sprintf(RMSCall, "%s-%d", user->Call, s); - else - sprintf(RMSCall, "%s", user->Call); - - // We added connectingcall at front - - if (strcmp(RMSCall, ConnectingCall) != 0) - { - strcat(FWLine, " "); - strcat(FWLine, RMSCall); - - if (user->CMSPass[0]) - { - int Response = GetCMSHash(conn->PQChallenge, user->CMSPass); - char RespString[12]; - - sprintf(RespString, "%010d", Response); - strcat(FWLine, "|"); - strcat(FWLine, &RespString[2]); - } - } - } - } - } - } - - strcat(FWLine, "\r"); - - nodeprintf(conn, FWLine); - } - - // Only declare B1 and B2 if other end did, and we are configued for it - - nodeprintfEx(conn, BBSSID, "BPQ-", - Ver[0], Ver[1], Ver[2], Ver[3], - (conn->BBSFlags & FBBCompressed) ? "B" : "", - (conn->BBSFlags & FBBB1Mode && !(conn->BBSFlags & FBBB2Mode)) ? "1" : "", - (conn->BBSFlags & FBBB2Mode) ? "2" : "", - (conn->BBSFlags & FBBForwarding) ? "F" : "", - (conn->BBSFlags & WINLINKRO) ? "" : "J"); - - if (conn->SecureMsg[0]) - { - struct UserInfo * user; - BBSputs(conn, conn->SecureMsg); - conn->SecureMsg[0] = 0; - - // Also send a Location Comment Line - - //; GM8BPQ-10 DE G8BPQ (IO92KX) - //; WL2K DE GM8BPQ () (PAT) - - user = LookupCall(BBSName); - - if (LOC && LOC[0]) - nodeprintf(conn, "; WL2K DE %s (%s)\r", BBSName, LOC); - } - - if (conn->BPQBBS && conn->MSGTYPES[0]) - - // Send a ; MSGTYPES to control what he sends us - - nodeprintf(conn, "; MSGTYPES %s\r", conn->MSGTYPES); - - if (conn->BBSFlags & FBBForwarding) - { - if (!FBBDoForward(conn)) // Send proposal if anthing to forward - { - if (conn->DoReverse) - FBBputs(conn, "FF\r"); - else - { - FBBputs(conn, "FQ\r"); - conn->CloseAfterFlush = 20; // 2 Secs - } - } - - return TRUE; - } - - return TRUE; - } - - return TRUE; -} - -VOID Parse_SID(CIRCUIT * conn, char * SID, int len) -{ - ChangeSessionIdletime(conn->BPQStream, BBSIDLETIME); // Default Idletime for BBS Sessions - - // scan backwards for first '-' - - if (strstr(SID, "BPQCHATSERVER")) - { - Disconnect(conn->BPQStream); - return; - } - - if (strstr(SID, "RMS Ex") || strstr(SID, "Winlink Ex")) - { - conn->RMSExpress = TRUE; - conn->Paclink = FALSE; - conn->PAT = FALSE; - - // Set new RMS Users as RMS User - - if (conn->NewUser) - conn->UserPointer->flags |= F_Temp_B2_BBS; - } - - if (stristr(SID, "PAT")) - { - // Set new PAT Users as RMS User - - conn->RMSExpress = FALSE; - conn->Paclink = FALSE; - conn->PAT = TRUE; - - if (conn->NewUser) - conn->UserPointer->flags |= F_Temp_B2_BBS; - } - if (strstr(SID, "Paclink")) - { - conn->RMSExpress = FALSE; - conn->Paclink = TRUE; - } - - if (strstr(SID, "WL2K-")) - { - conn->WL2K = TRUE; - conn->BBSFlags |= WINLINKRO; - } - - if (strstr(SID, "MFJ-")) - { - conn->BBSFlags |= MFJMODE; - } - - if (_memicmp(SID, "OpenBCM", 7) == 0) - { - // We should really only do this on Telnet Connections, as OpenBCM flag is used to remove relnet transparency - - - conn->OpenBCM = TRUE; - } - - if (_memicmp(SID, "PMS-3.2", 7) == 0) - { - // Paccom TNC that doesn't send newline prompt ater receiving subject - - conn->BBSFlags |= NEWPACCOM; - } - - // See if BPQ for selective forwarding - - if (strstr(SID, "BPQ")) - conn->BPQBBS = TRUE; - - while (len > 0) - { - switch (SID[len--]) - { - case '-': - - len=0; - break; - - case '$': - - conn->BBSFlags |= BBS | MBLFORWARDING; - conn->Paging = FALSE; - - break; - - case 'F': // FBB Blocked Forwarding - - // We now support blocked uncompressed. Not necessarily compatible with FBB - - if ((conn->UserPointer->ForwardingInfo == NULL) && (conn->UserPointer->flags & F_PMS)) - { - // We need to allocate a forwarding structure - - conn->UserPointer->ForwardingInfo = zalloc(sizeof(struct BBSForwardingInfo)); - conn->UserPointer->ForwardingInfo->AllowCompressed = TRUE; - conn->UserPointer->ForwardingInfo->AllowBlocked = TRUE; - conn->UserPointer->BBSNumber = NBBBS; - } - - if (conn->UserPointer->ForwardingInfo->AllowBlocked) - { - conn->BBSFlags |= FBBForwarding | BBS; - conn->BBSFlags &= ~MBLFORWARDING; - - conn->Paging = FALSE; - - if ((conn->UserPointer->ForwardingInfo == NULL) && (conn->UserPointer->flags & F_PMS)) - { - // We need to allocate a forwarding structure - - conn->UserPointer->ForwardingInfo = zalloc(sizeof(struct BBSForwardingInfo)); - conn->UserPointer->ForwardingInfo->AllowCompressed = TRUE; - conn->UserPointer->BBSNumber = NBBBS; - } - - // Allocate a Header Block - - conn->FBBHeaders = zalloc(5 * sizeof(struct FBBHeaderLine)); - } - break; - - case 'J': - - // Suspected to be associated with Winlink Radio Only - - conn->BBSFlags &= ~WINLINKRO; - break; - - case 'B': - - if (conn->UserPointer->ForwardingInfo->AllowCompressed) - { - conn->BBSFlags |= FBBCompressed; - conn->DontSaveRestartData = FALSE; // Allow restarts - - // Look for 1 or 2 or 12 as next 2 chars - - if (SID[len+2] == '1') - { - if (conn->UserPointer->ForwardingInfo->AllowB1 || - conn->UserPointer->ForwardingInfo->AllowB2) // B2 implies B1 - conn->BBSFlags |= FBBB1Mode; - - if (SID[len+3] == '2') - if (conn->UserPointer->ForwardingInfo->AllowB2) - conn->BBSFlags |= FBBB1Mode | FBBB2Mode; // B2 uses B1 mode (crc on front of file) - - break; - } - - if (SID[len+2] == '2') - { - if (conn->UserPointer->ForwardingInfo->AllowB2) - conn->BBSFlags |= FBBB1Mode | FBBB2Mode; // B2 uses B1 mode (crc on front of file) - - if (conn->UserPointer->ForwardingInfo->AllowB1) - conn->BBSFlags |= FBBB1Mode; // B2 should allow fallback to B1 (but RMS doesnt!) - - } - break; - } - - break; - } - } - - // Only allow blocked non-binary to other BPQ Nodes - - if ((conn->BBSFlags & FBBForwarding) && ((conn->BBSFlags & FBBCompressed) == 0) && (conn->BPQBBS == 0)) - { - // Switch back to MBL - - conn->BBSFlags |= MBLFORWARDING; - conn->BBSFlags &= ~FBBForwarding; // Turn off FBB Blocked - } - - return; -} - -VOID BBSSlowTimer() -{ - ConnectionInfo * conn; - int n; - - // Called every 10 seconds - - MCastTimer(); - - - for (n = 0; n < NumberofStreams; n++) - { - conn = &Connections[n]; - - if (conn->Active == TRUE) - { - // Check for stuck BBS sessions (BBS session but no Node Session) - - int state; - - GetSemaphore(&ConSemaphore, 1); - SessionStateNoAck(conn->BPQStream, &state); - FreeSemaphore(&ConSemaphore); - - if (state == 0) // No Node Session - { - // is it safe just to clear Active ?? - - conn->InputMode = 0; // So Disconnect wont save partial transfer - conn->BBSFlags = 0; - Disconnected (conn->BPQStream); - continue; - } - - if (conn->BBSFlags & MCASTRX) - MCastConTimer(conn); - - - // Check SIDTImers - used to detect failure to compete SID Handshake - - if (conn->SIDResponseTimer) - { - conn->SIDResponseTimer--; - if (conn->SIDResponseTimer == 0) - { - // Disconnect Session - - Disconnect(conn->BPQStream); - } - } - } - } - - // Flush logs - - for (n = 0; n < 4; n++) - { - if (LogHandle[n]) - { - time_t LT = time(NULL); - if ((LT - LastLogTime[n]) > 30) - { - LastLogTime[n] = LT; - fclose(LogHandle[n]); - LogHandle[n] = NULL; - } - } - } -} - - -VOID FWDTimerProc() -{ - struct UserInfo * user; - struct BBSForwardingInfo * ForwardingInfo ; - time_t NOW = time(NULL); - - for (user = BBSChain; user; user = user->BBSNext) - { - // See if any messages are queued for this BBS - - ForwardingInfo = user->ForwardingInfo; - ForwardingInfo->FwdTimer+=10; - - if (ForwardingInfo->FwdTimer >= ForwardingInfo->FwdInterval) - { - ForwardingInfo->FwdTimer=0; - - if (ForwardingInfo->FWDBands && ForwardingInfo->FWDBands[0]) - { - // Check Timebands - - struct FWDBAND ** Bands = ForwardingInfo->FWDBands; - int Count = 0; - time_t now = time(NULL); - - if (Localtime) - now -= (time_t)_MYTIMEZONE; - - now %= 86400; // Secs in day - - while(Bands[Count]) - { - if ((Bands[Count]->FWDStartBand < now) && (Bands[Count]->FWDEndBand >= now)) - goto FWD; // In band - - Count++; - } - continue; // Out of bands - } - FWD: - if (ForwardingInfo->Enabled) - { - if (ForwardingInfo->ConnectScript && (ForwardingInfo->Forwarding == 0) && ForwardingInfo->ConnectScript[0]) - { - //Temp Debug Code - -// Debugprintf("ReverseFlag = %d, Msgs to Forward Flag %d Msgs to Forward Count %d", -// ForwardingInfo->ReverseFlag, -// SeeifMessagestoForward(user->BBSNumber, NULL), -// CountMessagestoForward(user)); - - if (SeeifMessagestoForward(user->BBSNumber, NULL) || - (ForwardingInfo->ReverseFlag && ((NOW - ForwardingInfo->LastReverseForward) >= ForwardingInfo->RevFwdInterval))) - - { - user->ForwardingInfo->ScriptIndex = -1; // Incremented before being used - - - // remove any old TempScript - - if (user->ForwardingInfo->TempConnectScript) - { - FreeList(user->ForwardingInfo->TempConnectScript); - user->ForwardingInfo->TempConnectScript = NULL; - } - - if (ConnecttoBBS(user)) - ForwardingInfo->Forwarding = TRUE; - } - } - } - } - } -} - -VOID * _zalloc_dbg(size_t len, int type, char * file, int line) -{ - // ?? malloc and clear - - void * ptr; - -#ifdef WIN32 - ptr=_malloc_dbg(len, type, file, line); -#else - ptr = malloc(len); -#endif - if (ptr) - memset(ptr, 0, len); - - return ptr; -} - -struct MsgInfo * FindMessageByNumber(int msgno) - { - int m=NumberofMessages; - - struct MsgInfo * Msg; - - do - { - Msg=MsgHddrPtr[m]; - - if (Msg->number == msgno) - return Msg; - - if (Msg->number && Msg->number < msgno) // sometimes get zero msg number - return NULL; // Not found - - m--; - - } while (m > 0); - - return NULL; -} - -struct MsgInfo * FindMessageByBID(char * BID) -{ - int m = NumberofMessages; - - struct MsgInfo * Msg; - - while (m > 0) - { - Msg = MsgHddrPtr[m]; - - if (strcmp(Msg->bid, BID) == 0) - return Msg; - - m--; - } - - return NULL; -} - -VOID DecryptPass(char * Encrypt, unsigned char * Pass, unsigned int len) -{ - unsigned char hash[50]; - unsigned char key[100]; - unsigned int i, j = 0, val1, val2; - unsigned char hostname[100]=""; - - gethostname(hostname, 100); - - strcpy(key, hostname); - strcat(key, ISPPOP3Name); - - md5(key, hash); - memcpy(&hash[16], hash, 16); // in case very long password - - // String is now encoded as hex pairs, but still need to decode old format - - for (i=0; i < len; i++) - { - if (Encrypt[i] < '0' || Encrypt[i] > 'F') - goto OldFormat; - } - - // Only '0' to 'F' - - for (i=0; i < len; i++) - { - val1 = Encrypt[i++]; - val1 -= '0'; - if (val1 > 9) - val1 -= 7; - - val2 = Encrypt[i]; - val2 -= '0'; - if (val2 > 9) - val2 -= 7; - - Pass[j] = (val1 << 4) | val2; - Pass[j] ^= hash[j]; - j++; - } - - return; - -OldFormat: - - for (i=0; i < len; i++) - { - Pass[i] = Encrypt[i] ^ hash[i]; - } - - return; -} - -int EncryptPass(char * Pass, char * Encrypt) -{ - unsigned char hash[50]; - unsigned char key[100]; - unsigned int i, val; - unsigned char hostname[100]; - unsigned char extendedpass[100]; - unsigned int passlen; - unsigned char * ptr; - - gethostname(hostname, 100); - - strcpy(key, hostname); - strcat(key, ISPPOP3Name); - - md5(key, hash); - memcpy(&hash[16], hash, 16); // in case very long password - - // if password is less than 16 chars, extend with zeros - - passlen=(int)strlen(Pass); - - strcpy(extendedpass, Pass); - - if (passlen < 16) - { - for (i=passlen+1; i <= 16; i++) - { - extendedpass[i] = 0; - } - - passlen = 16; - } - - ptr = Encrypt; - Encrypt[0] = 0; - - for (i=0; i < passlen; i++) - { - val = extendedpass[i] ^ hash[i]; - ptr += sprintf(ptr, "%02X", val); - } - - return passlen * 2; -} - - - -VOID SaveIntValue(config_setting_t * group, char * name, int value) -{ - config_setting_t *setting; - - setting = config_setting_add(group, name, CONFIG_TYPE_INT); - if(setting) - config_setting_set_int(setting, value); -} - -VOID SaveInt64Value(config_setting_t * group, char * name, long long value) -{ - config_setting_t *setting; - - setting = config_setting_add(group, name, CONFIG_TYPE_INT64); - if(setting) - config_setting_set_int64(setting, value); -} - -VOID SaveFloatValue(config_setting_t * group, char * name, double value) -{ - config_setting_t *setting; - - setting = config_setting_add(group, name, CONFIG_TYPE_FLOAT); - if (setting) - config_setting_set_float(setting, value); -} - -VOID SaveStringValue(config_setting_t * group, char * name, char * value) -{ - config_setting_t *setting; - - setting = config_setting_add(group, name, CONFIG_TYPE_STRING); - if (setting) - config_setting_set_string(setting, value); - -} - - -VOID SaveOverride(config_setting_t * group, char * name, struct Override ** values) -{ - config_setting_t *setting; - struct Override ** Calls; - char Multi[10000]; - char * ptr = &Multi[1]; - - *ptr = 0; - - if (values) - { - Calls = values; - - while(Calls[0]) - { - ptr += sprintf(ptr, "%s, %d|", Calls[0]->Call, Calls[0]->Days); - Calls++; - } - *(--ptr) = 0; - } - - setting = config_setting_add(group, name, CONFIG_TYPE_STRING); - if (setting) - config_setting_set_string(setting, &Multi[1]); - -} - - -VOID SaveMultiStringValue(config_setting_t * group, char * name, char ** values) -{ - config_setting_t *setting; - char ** Calls; - char Multi[100000]; - char * ptr = &Multi[1]; - - *ptr = 0; - - if (values) - { - Calls = values; - - while(Calls[0]) - { - strcpy(ptr, Calls[0]); - ptr += strlen(Calls[0]); - *(ptr++) = '|'; - Calls++; - } - *(--ptr) = 0; - } - - setting = config_setting_add(group, name, CONFIG_TYPE_STRING); - if (setting) - config_setting_set_string(setting, &Multi[1]); - -} - -int configSaved = 0; - -VOID SaveConfig(char * ConfigName) -{ - struct UserInfo * user; - struct BBSForwardingInfo * ForwardingInfo ; - config_setting_t *root, *group, *bbs; - int i; - char Size[80]; - struct BBSForwardingInfo DummyForwardingInfo; - char Line[1024]; - - if (configSaved == 0) - { - // only create backup once per run - - CopyConfigFile(ConfigName); - configSaved = 1; - } - - memset(&DummyForwardingInfo, 0, sizeof(struct BBSForwardingInfo)); - - // Get rid of old config before saving - - config_destroy(&cfg); - - memset((void *)&cfg, 0, sizeof(config_t)); - - config_init(&cfg); - - root = config_root_setting(&cfg); - - group = config_setting_add(root, "main", CONFIG_TYPE_GROUP); - - SaveIntValue(group, "Streams", MaxStreams); - SaveIntValue(group, "BBSApplNum", BBSApplNum); - SaveStringValue(group, "BBSName", BBSName); - SaveStringValue(group, "SYSOPCall", SYSOPCall); - SaveStringValue(group, "H-Route", HRoute); - SaveStringValue(group, "AMPRDomain", AMPRDomain); - SaveIntValue(group, "EnableUI", EnableUI); - SaveIntValue(group, "RefuseBulls", RefuseBulls); - SaveIntValue(group, "OnlyKnown", OnlyKnown); - SaveIntValue(group, "SendSYStoSYSOPCall", SendSYStoSYSOPCall); - SaveIntValue(group, "SendBBStoSYSOPCall", SendBBStoSYSOPCall); - SaveIntValue(group, "DontHoldNewUsers", DontHoldNewUsers); - SaveIntValue(group, "DefaultNoWINLINK", DefaultNoWINLINK); - SaveIntValue(group, "AllowAnon", AllowAnon); - SaveIntValue(group, "DontNeedHomeBBS", DontNeedHomeBBS); - SaveIntValue(group, "DontCheckFromCall", DontCheckFromCall); - SaveIntValue(group, "UserCantKillT", UserCantKillT); - - SaveIntValue(group, "ForwardToMe", ForwardToMe); - SaveIntValue(group, "SMTPPort", SMTPInPort); - SaveIntValue(group, "POP3Port", POP3InPort); - SaveIntValue(group, "NNTPPort", NNTPInPort); - SaveIntValue(group, "RemoteEmail", RemoteEmail); - SaveIntValue(group, "SendAMPRDirect", SendAMPRDirect); - - SaveIntValue(group, "MailForInterval", MailForInterval); - SaveStringValue(group, "MailForText", MailForText); - - EncryptedPassLen = EncryptPass(ISPAccountPass, EncryptedISPAccountPass); - - SaveIntValue(group, "AuthenticateSMTP", SMTPAuthNeeded); - - SaveIntValue(group, "MulticastRX", MulticastRX); - - SaveIntValue(group, "SMTPGatewayEnabled", ISP_Gateway_Enabled); - SaveIntValue(group, "ISPSMTPPort", ISPSMTPPort); - SaveIntValue(group, "ISPPOP3Port", ISPPOP3Port); - SaveIntValue(group, "POP3PollingInterval", ISPPOP3Interval); - - SaveStringValue(group, "MyDomain", MyDomain); - SaveStringValue(group, "ISPSMTPName", ISPSMTPName); - SaveStringValue(group, "ISPEHLOName", ISPEHLOName); - SaveStringValue(group, "ISPPOP3Name", ISPPOP3Name); - SaveStringValue(group, "ISPAccountName", ISPAccountName); - SaveStringValue(group, "ISPAccountPass", EncryptedISPAccountPass); - - - // Save Window Sizes - -#ifndef LINBPQ - - if (ConsoleRect.right) - { - sprintf(Size,"%d,%d,%d,%d",ConsoleRect.left, ConsoleRect.right, - ConsoleRect.top, ConsoleRect.bottom); - - SaveStringValue(group, "ConsoleSize", Size); - } - - sprintf(Size,"%d,%d,%d,%d,%d",MonitorRect.left,MonitorRect.right,MonitorRect.top,MonitorRect.bottom, hMonitor ? 1 : 0); - SaveStringValue(group, "MonitorSize", Size); - - sprintf(Size,"%d,%d,%d,%d",MainRect.left,MainRect.right,MainRect.top,MainRect.bottom); - SaveStringValue(group, "WindowSize", Size); - - SaveIntValue(group, "Bells", Bells); - SaveIntValue(group, "FlashOnBell", FlashOnBell); - SaveIntValue(group, "StripLF", StripLF); - SaveIntValue(group, "WarnWrap", WarnWrap); - SaveIntValue(group, "WrapInput", WrapInput); - SaveIntValue(group, "FlashOnConnect", FlashOnConnect); - SaveIntValue(group, "CloseWindowOnBye", CloseWindowOnBye); - -#endif - - SaveIntValue(group, "Log_BBS", LogBBS); - SaveIntValue(group, "Log_TCP", LogTCP); - - sprintf(Size,"%d,%d,%d,%d", Ver[0], Ver[1], Ver[2], Ver[3]); - SaveStringValue(group, "Version", Size); - - // Save Welcome Messages and prompts - - SaveStringValue(group, "WelcomeMsg", WelcomeMsg); - SaveStringValue(group, "NewUserWelcomeMsg", NewWelcomeMsg); - SaveStringValue(group, "ExpertWelcomeMsg", ExpertWelcomeMsg); - - SaveStringValue(group, "Prompt", Prompt); - SaveStringValue(group, "NewUserPrompt", NewPrompt); - SaveStringValue(group, "ExpertPrompt", ExpertPrompt); - SaveStringValue(group, "SignoffMsg", SignoffMsg); - - SaveMultiStringValue(group, "RejFrom", RejFrom); - SaveMultiStringValue(group, "RejTo", RejTo); - SaveMultiStringValue(group, "RejAt", RejAt); - SaveMultiStringValue(group, "RejBID", RejBID); - - SaveMultiStringValue(group, "HoldFrom", HoldFrom); - SaveMultiStringValue(group, "HoldTo", HoldTo); - SaveMultiStringValue(group, "HoldAt", HoldAt); - SaveMultiStringValue(group, "HoldBID", HoldBID); - - SaveIntValue(group, "SendWP", SendWP); - SaveIntValue(group, "SendWPType", SendWPType); - SaveIntValue(group, "FilterWPBulls", FilterWPBulls); - SaveIntValue(group, "NoWPGuesses", NoWPGuesses); - - SaveStringValue(group, "SendWPTO", SendWPTO); - SaveStringValue(group, "SendWPVIA", SendWPVIA); - - SaveMultiStringValue(group, "SendWPAddrs", SendWPAddrs); - - // Save Forwarding Config - - // Interval and Max Sizes and Aliases are not user specific - - SaveIntValue(group, "MaxTXSize", MaxTXSize); - SaveIntValue(group, "MaxRXSize", MaxRXSize); - SaveIntValue(group, "ReaddressLocal", ReaddressLocal); - SaveIntValue(group, "ReaddressReceived", ReaddressReceived); - SaveIntValue(group, "WarnNoRoute", WarnNoRoute); - SaveIntValue(group, "Localtime", Localtime); - SaveIntValue(group, "SendPtoMultiple", SendPtoMultiple); - - SaveMultiStringValue(group, "FWDAliases", AliasText); - - bbs = config_setting_add(root, "BBSForwarding", CONFIG_TYPE_GROUP); - - for (i=1; i <= NumberofUsers; i++) - { - user = UserRecPtr[i]; - ForwardingInfo = user->ForwardingInfo; - - if (ForwardingInfo == NULL) - continue; - - if (memcmp(ForwardingInfo, &DummyForwardingInfo, sizeof(struct BBSForwardingInfo)) == 0) - continue; // Ignore empty records; - - if (isdigit(user->Call[0]) || user->Call[0] == '_') - { - char Key[20] = "*"; - strcat (Key, user->Call); - group = config_setting_add(bbs, Key, CONFIG_TYPE_GROUP); - } - else - group = config_setting_add(bbs, user->Call, CONFIG_TYPE_GROUP); - - SaveMultiStringValue(group, "TOCalls", ForwardingInfo->TOCalls); - SaveMultiStringValue(group, "ConnectScript", ForwardingInfo->ConnectScript); - SaveMultiStringValue(group, "ATCalls", ForwardingInfo->ATCalls); - SaveMultiStringValue(group, "HRoutes", ForwardingInfo->Haddresses); - SaveMultiStringValue(group, "HRoutesP", ForwardingInfo->HaddressesP); - SaveMultiStringValue(group, "FWDTimes", ForwardingInfo->FWDTimes); - - SaveIntValue(group, "Enabled", ForwardingInfo->Enabled); - SaveIntValue(group, "RequestReverse", ForwardingInfo->ReverseFlag); - SaveIntValue(group, "AllowBlocked", ForwardingInfo->AllowBlocked); - SaveIntValue(group, "AllowCompressed", ForwardingInfo->AllowCompressed); - SaveIntValue(group, "UseB1Protocol", ForwardingInfo->AllowB1); - SaveIntValue(group, "UseB2Protocol", ForwardingInfo->AllowB2); - SaveIntValue(group, "SendCTRLZ", ForwardingInfo->SendCTRLZ); - - SaveIntValue(group, "FWDPersonalsOnly", ForwardingInfo->PersonalOnly); - SaveIntValue(group, "FWDNewImmediately", ForwardingInfo->SendNew); - SaveIntValue(group, "FwdInterval", ForwardingInfo->FwdInterval); - SaveIntValue(group, "RevFWDInterval", ForwardingInfo->RevFwdInterval); - SaveIntValue(group, "MaxFBBBlock", ForwardingInfo->MaxFBBBlockSize); - SaveIntValue(group, "ConTimeout", ForwardingInfo->ConTimeout); - - SaveStringValue(group, "BBSHA", ForwardingInfo->BBSHA); - } - - - // Save Housekeeping config - - group = config_setting_add(root, "Housekeeping", CONFIG_TYPE_GROUP); - - SaveInt64Value(group, "LastHouseKeepingTime", LastHouseKeepingTime); - SaveInt64Value(group, "LastTrafficTime", LastTrafficTime); - SaveIntValue(group, "MaxMsgno", MaxMsgno); - SaveIntValue(group, "BidLifetime", BidLifetime); - SaveIntValue(group, "MaxAge", MaxAge); - SaveIntValue(group, "LogLifetime", LogAge); - SaveIntValue(group, "LogLifetime", LogAge); - SaveIntValue(group, "MaintInterval", MaintInterval); - SaveIntValue(group, "UserLifetime", UserLifetime); - SaveIntValue(group, "MaintTime", MaintTime); - SaveFloatValue(group, "PR", PR); - SaveFloatValue(group, "PUR", PUR); - SaveFloatValue(group, "PF", PF); - SaveFloatValue(group, "PNF", PNF); - SaveIntValue(group, "BF", BF); - SaveIntValue(group, "BNF", BNF); - SaveIntValue(group, "NTSD", NTSD); - SaveIntValue(group, "NTSF", NTSF); - SaveIntValue(group, "NTSU", NTSU); -// SaveIntValue(group, "AP", AP); -// SaveIntValue(group, "AB", AB); - SaveIntValue(group, "DeletetoRecycleBin", DeletetoRecycleBin); - SaveIntValue(group, "SuppressMaintEmail", SuppressMaintEmail); - SaveIntValue(group, "MaintSaveReg", SaveRegDuringMaint); - SaveIntValue(group, "OverrideUnsent", OverrideUnsent); - SaveIntValue(group, "SendNonDeliveryMsgs", SendNonDeliveryMsgs); - SaveIntValue(group, "GenerateTrafficReport", GenerateTrafficReport); - - SaveOverride(group, "LTFROM", LTFROM); - SaveOverride(group, "LTTO", LTTO); - SaveOverride(group, "LTAT", LTAT); - - // Save UI config - - for (i=1; i<=32; i++) - { - char Key[100]; - - sprintf(Key, "UIPort%d", i); - - group = config_setting_add(root, Key, CONFIG_TYPE_GROUP); - - if (group) - { - SaveIntValue(group, "Enabled", UIEnabled[i]); - SaveIntValue(group, "SendMF", UIMF[i]); - SaveIntValue(group, "SendHDDR", UIHDDR[i]); - SaveIntValue(group, "SendNull", UINull[i]); - - if (UIDigi[i]) - SaveStringValue(group, "Digis", UIDigi[i]); - } - } - - // Save User Config - - bbs = config_setting_add(root, "BBSUsers", CONFIG_TYPE_GROUP); - - for (i=1; i <= NumberofUsers; i++) - { - char stats[256], stats2[256]; - struct MsgStats * Stats; - char Key[20] = "*"; - - user = UserRecPtr[i]; - - if (isdigit(user->Call[0]) || user->Call[0] == '_') - { - strcat (Key, user->Call); -// group = config_setting_add(bbs, Key, CONFIG_TYPE_GROUP); - } - else - { - strcpy(Key, user->Call); -// group = config_setting_add(bbs, user->Call, CONFIG_TYPE_GROUP); - } - /* - SaveStringValue(group, "Name", user->Name); - SaveStringValue(group, "Address", user->Address); - SaveStringValue(group, "HomeBBS", user->HomeBBS); - SaveStringValue(group, "QRA", user->QRA); - SaveStringValue(group, "pass", user->pass); - SaveStringValue(group, "ZIP", user->ZIP); - SaveStringValue(group, "CMSPass", user->CMSPass); - - SaveIntValue(group, "lastmsg", user->lastmsg); - SaveIntValue(group, "flags", user->flags); - SaveIntValue(group, "PageLen", user->PageLen); - SaveIntValue(group, "BBSNumber", user->BBSNumber); - SaveIntValue(group, "RMSSSIDBits", user->RMSSSIDBits); - SaveIntValue(group, "WebSeqNo", user->WebSeqNo); - - SaveInt64Value(group, "TimeLastConnected", user->TimeLastConnected); -*/ - Stats = &user->Total; - -// sprintf(stats, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", - sprintf(stats, "%.0d,%.0d,%.0d,%.0d,%.0d,%.0d,%.0d,%.0d,%.0d,%.0d,%.0d,%.0d,%.0d,%.0d,%.0d,%.0d,%.0d,%.0d,%.0d,%.0d,%.0d,%.0d,%.0d,%.0d,%.0d,%.0d", - Stats->ConnectsIn, Stats->ConnectsOut, - Stats->MsgsReceived[0], Stats->MsgsReceived[1], Stats->MsgsReceived[2], Stats->MsgsReceived[3], - Stats->MsgsSent[0], Stats->MsgsSent[1], Stats->MsgsSent[2], Stats->MsgsSent[3], - Stats->MsgsRejectedIn[0], Stats->MsgsRejectedIn[1], Stats->MsgsRejectedIn[2], Stats->MsgsRejectedIn[3], - Stats->MsgsRejectedOut[0], Stats->MsgsRejectedOut[1], Stats->MsgsRejectedOut[2], Stats->MsgsRejectedOut[3], - Stats->BytesForwardedIn[0], Stats->BytesForwardedIn[1], Stats->BytesForwardedIn[2], Stats->BytesForwardedIn[3], - Stats->BytesForwardedOut[0], Stats->BytesForwardedOut[1], Stats->BytesForwardedOut[2], Stats->BytesForwardedOut[3]); - -// SaveStringValue(group, "Totsl", stats); - - Stats = &user->Last; - - sprintf(stats2, "%.0d,%.0d,%.0d,%.0d,%.0d,%.0d,%.0d,%.0d,%.0d,%.0d,%.0d,%.0d,%.0d,%.0d,%.0d,%.0d,%.0d,%.0d,%.0d,%.0d,%.0d,%.0d,%.0d,%.0d,%.0d,%.0d", -// sprintf(stats2, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", - Stats->ConnectsIn, Stats->ConnectsOut, - Stats->MsgsReceived[0], Stats->MsgsReceived[1], Stats->MsgsReceived[2], Stats->MsgsReceived[3], - Stats->MsgsSent[0], Stats->MsgsSent[1], Stats->MsgsSent[2], Stats->MsgsSent[3], - Stats->MsgsRejectedIn[0], Stats->MsgsRejectedIn[1], Stats->MsgsRejectedIn[2], Stats->MsgsRejectedIn[3], - Stats->MsgsRejectedOut[0], Stats->MsgsRejectedOut[1], Stats->MsgsRejectedOut[2], Stats->MsgsRejectedOut[3], - Stats->BytesForwardedIn[0], Stats->BytesForwardedIn[1], Stats->BytesForwardedIn[2], Stats->BytesForwardedIn[3], - Stats->BytesForwardedOut[0], Stats->BytesForwardedOut[1], Stats->BytesForwardedOut[2], Stats->BytesForwardedOut[3]); - -// SaveStringValue(group, "Last", stats2); - - sprintf(Line,"%s^%s^%s^%s^%s^%s^%s^%d^%d^%d^%d^%d^%d^%lld^%s^%s", - user->Name, user->Address, user->HomeBBS, user->QRA, user->pass, user->ZIP, user->CMSPass, - user->lastmsg, user->flags, user->PageLen, user->BBSNumber, user->RMSSSIDBits, user->WebSeqNo, - user->TimeLastConnected, stats, stats2); - - if (strlen(Line) < 10) - continue; - - SaveStringValue(bbs, Key, Line); - } - -/* - wp = config_setting_add(root, "WP", CONFIG_TYPE_GROUP); - - for (i = 0; i <= NumberofWPrecs; i++) - { - char WPString[1024]; - long long val1, val2; - - WP = WPRecPtr[i]; - val1 = WP->last_modif; - val2 = WP->last_seen; - - sprintf(Key, "R%d", i); - - sprintf(WPString, "%s|%s|%d|%d|%d|%s|%s|%s|%s|%s|%s|%ld|%ld", - &WP->callsign[0], &WP->name[0], WP->Type, WP->changed, WP->seen, &WP->first_homebbs[0], - &WP->secnd_homebbs[0], &WP->first_zip[0], &WP->secnd_zip[0], &WP->first_qth[0], &WP->secnd_qth[0], - val1, val2); - - SaveStringValue(wp, Key, WPString); - } - - // Save Message Headers - - msgs = config_setting_add(root, "MSGS", CONFIG_TYPE_GROUP); - - memset(MsgHddrPtr[0], 0, sizeof(struct MsgInfo)); - - MsgHddrPtr[0]->type = 'X'; - MsgHddrPtr[0]->status = '2'; - MsgHddrPtr[0]->number = 0; - MsgHddrPtr[0]->length = LatestMsg; - - - for (i = 0; i <= NumberofMessages; i++) - { - Msg = MsgHddrPtr[i]; - - for (n = 0; n < NBMASK; n++) - sprintf(&HEXString1[n * 2], "%02X", Msg->fbbs[n]); - - n = 39; - while (n >=0 && HEXString1[n] == '0') - HEXString1[n--] = 0; - - for (n = 0; n < NBMASK; n++) - sprintf(&HEXString2[n * 2], "%02X", Msg->forw[n]); - - n = 39; - while (n >= 0 && HEXString2[n] == '0') - HEXString2[n--] = 0; - - sprintf(Key, "R%d", Msg->number); - - n = sprintf(Line, "%c|%c|%d|%lld|%s|%s|%s|%s|%s|%d|%lld|%lld|%s|%s|%s|%d|%s", Msg->type, Msg->status, - Msg->length, Msg->datereceived, &Msg->bbsfrom[0], &Msg->via[0], &Msg->from[0], - &Msg->to[0], &Msg->bid[0], Msg->B2Flags, Msg->datecreated, Msg->datechanged, HEXString1, HEXString2, - &Msg->emailfrom[0], Msg->UTF8, &Msg->title[0]); - - SaveStringValue(msgs, Key, Line); - } - - // Save Bids - - msgs = config_setting_add(root, "BIDS", CONFIG_TYPE_GROUP); - - for (i=1; i <= NumberofBIDs; i++) - { - sprintf(Key, "R%s", BIDRecPtr[i]->BID); - sprintf(Line, "%d|%d", BIDRecPtr[i]->mode, BIDRecPtr[i]->u.timestamp); - SaveStringValue(msgs, Key, Line); - } - -#ifdef LINBPQ - - if(! config_write_file(&cfg,"/dev/shm/linmail.cfg.temp" )) - { - print("Error while writing file.\n"); - config_destroy(&cfg); - return; - } - - CopyFile("/dev/shm/linmail.cfg.temp", ConfigName, FALSE); - -#else -*/ - if(! config_write_file(&cfg, ConfigName)) - { - fprintf(stderr, "Error while writing file.\n"); - config_destroy(&cfg); - return; - } - -//#endif - - config_destroy(&cfg); - -/* - -#ifndef LINBPQ - - // Save a copy with current Date/Time Stamp for debugging - - { - char Backup[MAX_PATH]; - time_t LT; - struct tm * tm; - - LT = time(NULL); - tm = gmtime(<); - - sprintf(Backup,"%s.%02d%02d%02d%02d%02d.save", ConfigName, tm->tm_year-100, tm->tm_mon+1, - tm->tm_mday, tm->tm_hour, tm->tm_min); - - CopyFile(ConfigName, Backup, FALSE); // Copy to .bak - } -#endif -*/ -} - -int GetIntValue(config_setting_t * group, char * name) -{ - config_setting_t *setting; - - setting = config_setting_get_member (group, name); - if (setting) - return config_setting_get_int (setting); - - return 0; -} - -long long GetInt64Value(config_setting_t * group, char * name) -{ - config_setting_t *setting; - - setting = config_setting_get_member (group, name); - if (setting) - return config_setting_get_int64 (setting); - - return 0; -} - -double GetFloatValue(config_setting_t * group, char * name) -{ - config_setting_t *setting; - - setting = config_setting_get_member (group, name); - - if (setting) - { - return config_setting_get_float (setting); - } - return 0; -} - -int GetIntValueWithDefault(config_setting_t * group, char * name, int Default) -{ - config_setting_t *setting; - - setting = config_setting_get_member (group, name); - if (setting) - return config_setting_get_int (setting); - - return Default; -} - - -BOOL GetStringValue(config_setting_t * group, char * name, char * value) -{ - const char * str; - config_setting_t *setting; - - setting = config_setting_get_member (group, name); - if (setting) - { - str = config_setting_get_string (setting); - strcpy(value, str); - return TRUE; - } - value[0] = 0; - return FALSE; -} - -BOOL GetConfig(char * ConfigName) -{ - int i; - char Size[80]; - config_setting_t *setting; - const char * ptr; - - config_init(&cfg); - - /* Read the file. If there is an error, report it and exit. */ - - if(! config_read_file(&cfg, ConfigName)) - { - char Msg[256]; - sprintf(Msg, "Config File Line %d - %s\n", - config_error_line(&cfg), config_error_text(&cfg)); -#ifdef WIN32 - MessageBox(NULL, Msg, "BPQMail", MB_ICONSTOP); -#else - printf("%s", Msg); -#endif - 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"); - SendSYStoSYSOPCall = GetIntValue(group, "SendSYStoSYSOPCall"); - SendBBStoSYSOPCall = GetIntValue(group, "SendBBStoSYSOPCall"); - DontHoldNewUsers = GetIntValue(group, "DontHoldNewUsers"); - DefaultNoWINLINK = GetIntValue(group, "DefaultNoWINLINK"); - ForwardToMe = GetIntValue(group, "ForwardToMe"); - AllowAnon = GetIntValue(group, "AllowAnon"); - UserCantKillT = GetIntValue(group, "UserCantKillT"); - - DontNeedHomeBBS = GetIntValue(group, "DontNeedHomeBBS"); - DontCheckFromCall = GetIntValue(group, "DontCheckFromCall"); - MaxTXSize = GetIntValue(group, "MaxTXSize"); - MaxRXSize = GetIntValue(group, "MaxRXSize"); - ReaddressLocal = GetIntValue(group, "ReaddressLocal"); - ReaddressReceived = GetIntValue(group, "ReaddressReceived"); - WarnNoRoute = GetIntValue(group, "WarnNoRoute"); - SendPtoMultiple = GetIntValue(group, "SendPtoMultiple"); - Localtime = GetIntValue(group, "Localtime"); - AliasText = GetMultiStringValue(group, "FWDAliases"); - GetStringValue(group, "BBSName", BBSName); - GetStringValue(group, "MailForText", MailForText); - GetStringValue(group, "SYSOPCall", SYSOPCall); - GetStringValue(group, "H-Route", HRoute); - GetStringValue(group, "AMPRDomain", AMPRDomain); - SendAMPRDirect = GetIntValue(group, "SendAMPRDirect"); - ISP_Gateway_Enabled = GetIntValue(group, "SMTPGatewayEnabled"); - ISPPOP3Interval = GetIntValue(group, "POP3PollingInterval"); - GetStringValue(group, "MyDomain", MyDomain); - GetStringValue(group, "ISPSMTPName", ISPSMTPName); - GetStringValue(group, "ISPPOP3Name", ISPPOP3Name); - ISPSMTPPort = GetIntValue(group, "ISPSMTPPort"); - ISPPOP3Port = GetIntValue(group, "ISPPOP3Port"); - GetStringValue(group, "ISPAccountName", ISPAccountName); - GetStringValue(group, "ISPAccountPass", EncryptedISPAccountPass); - GetStringValue(group, "ISPAccountName", ISPAccountName); - - sprintf(SignoffMsg, "73 de %s\r", BBSName); // Default - GetStringValue(group, "SignoffMsg", SignoffMsg); - - DecryptPass(EncryptedISPAccountPass, ISPAccountPass, (int)strlen(EncryptedISPAccountPass)); - - SMTPAuthNeeded = GetIntValue(group, "AuthenticateSMTP"); - LogBBS = GetIntValue(group, "Log_BBS"); - LogTCP = GetIntValue(group, "Log_TCP"); - - MulticastRX = GetIntValue(group, "MulticastRX"); - -#ifndef LINBPQ - - GetStringValue(group, "MonitorSize", Size); - sscanf(Size,"%d,%d,%d,%d,%d",&MonitorRect.left,&MonitorRect.right,&MonitorRect.top,&MonitorRect.bottom,&OpenMon); - - GetStringValue(group, "WindowSize", Size); - sscanf(Size,"%d,%d,%d,%d",&MainRect.left,&MainRect.right,&MainRect.top,&MainRect.bottom); - - Bells = GetIntValue(group, "Bells"); - - FlashOnBell = GetIntValue(group, "FlashOnBell"); - - StripLF = GetIntValue(group, "StripLF"); - CloseWindowOnBye = GetIntValue(group, "CloseWindowOnBye"); - WarnWrap = GetIntValue(group, "WarnWrap"); - WrapInput = GetIntValue(group, "WrapInput"); - FlashOnConnect = GetIntValue(group, "FlashOnConnect"); - - GetStringValue(group, "ConsoleSize", Size); - sscanf(Size,"%d,%d,%d,%d,%d", &ConsoleRect.left, &ConsoleRect.right, - &ConsoleRect.top, &ConsoleRect.bottom,&OpenConsole); - -#endif - - // Get Welcome Messages - - setting = config_setting_get_member (group, "WelcomeMsg"); - - if (setting && setting->value.sval[0]) - { - ptr = config_setting_get_string (setting); - WelcomeMsg = _strdup(ptr); - } - else - WelcomeMsg = _strdup("Hello $I. Latest Message is $L, Last listed is $Z\r\n"); - - - setting = config_setting_get_member (group, "NewUserWelcomeMsg"); - - if (setting && setting->value.sval[0]) - { - ptr = config_setting_get_string (setting); - NewWelcomeMsg = _strdup(ptr); - } - else - NewWelcomeMsg = _strdup("Hello $I. Latest Message is $L, Last listed is $Z\r\n"); - - - setting = config_setting_get_member (group, "ExpertWelcomeMsg"); - - if (setting && setting->value.sval[0]) - { - ptr = config_setting_get_string (setting); - ExpertWelcomeMsg = _strdup(ptr); - } - else - ExpertWelcomeMsg = _strdup(""); - - // Get Prompts - - setting = config_setting_get_member (group, "Prompt"); - - if (setting && setting->value.sval[0]) - { - ptr = config_setting_get_string (setting); - Prompt = _strdup(ptr); - } - else - { - Prompt = malloc(20); - sprintf(Prompt, "de %s>\r\n", BBSName); - } - - setting = config_setting_get_member (group, "NewUserPrompt"); - - if (setting && setting->value.sval[0]) - { - ptr = config_setting_get_string (setting); - NewPrompt = _strdup(ptr); - } - else - { - NewPrompt = malloc(20); - sprintf(NewPrompt, "de %s>\r\n", BBSName); - } - - setting = config_setting_get_member (group, "ExpertPrompt"); - - if (setting && setting->value.sval[0]) - { - ptr = config_setting_get_string (setting); - ExpertPrompt = _strdup(ptr); - } - else - { - ExpertPrompt = malloc(20); - sprintf(ExpertPrompt, "de %s>\r\n", BBSName); - } - - TidyPrompts(); - - RejFrom = GetMultiStringValue(group, "RejFrom"); - RejTo = GetMultiStringValue(group, "RejTo"); - RejAt = GetMultiStringValue(group, "RejAt"); - RejBID = GetMultiStringValue(group, "RejBID"); - - HoldFrom = GetMultiStringValue(group, "HoldFrom"); - HoldTo = GetMultiStringValue(group, "HoldTo"); - HoldAt = GetMultiStringValue(group, "HoldAt"); - HoldBID = GetMultiStringValue(group, "HoldBID"); - - // Send WP Params - - SendWP = GetIntValue(group, "SendWP"); - SendWPType = GetIntValue(group, "SendWPType"); - - GetStringValue(group, "SendWPTO", SendWPTO); - GetStringValue(group, "SendWPVIA", SendWPVIA); - - SendWPAddrs = GetMultiStringValue(group, "SendWPAddrs"); - - FilterWPBulls = GetIntValue(group, "FilterWPBulls"); - NoWPGuesses = GetIntValue(group, "NoWPGuesses"); - - if (SendWPAddrs[0] == NULL && SendWPTO[0]) - { - // convert old format TO and VIA to entry in SendWPAddrs - - SendWPAddrs = realloc(SendWPAddrs, 8); // Add entry - - if (SendWPVIA[0]) - { - char WP[256]; - - sprintf(WP, "%s@%s", SendWPTO, SendWPVIA); - SendWPAddrs[0] = _strdup(WP); - } - else - SendWPAddrs[0] = _strdup(SendWPTO); - - - SendWPAddrs[1] = 0; - - SendWPTO[0] = 0; - SendWPVIA[0] = 0; - } - - GetStringValue(group, "Version", Size); - sscanf(Size,"%d,%d,%d,%d", &LastVer[0], &LastVer[1], &LastVer[2], &LastVer[3]); - - for (i=1; i<=32; i++) - { - char Key[100]; - - sprintf(Key, "UIPort%d", i); - - group = config_lookup (&cfg, Key); - - if (group) - { - UIEnabled[i] = GetIntValue(group, "Enabled"); - UIMF[i] = GetIntValueWithDefault(group, "SendMF", UIEnabled[i]); - UIHDDR[i] = GetIntValueWithDefault(group, "SendHDDR", UIEnabled[i]); - UINull[i] = GetIntValue(group, "SendNull"); - Size[0] = 0; - GetStringValue(group, "Digis", Size); - if (Size[0]) - UIDigi[i] = _strdup(Size); - } - } - - group = config_lookup (&cfg, "Housekeeping"); - - if (group) - { - LastHouseKeepingTime = GetIntValue(group, "LastHouseKeepingTime"); - LastTrafficTime = GetIntValue(group, "LastTrafficTime"); - MaxMsgno = GetIntValue(group, "MaxMsgno"); - LogAge = GetIntValue(group, "LogLifetime"); - BidLifetime = GetIntValue(group, "BidLifetime"); - MaxAge = GetIntValue(group, "MaxAge"); - if (MaxAge == 0) - MaxAge = 30; - UserLifetime = GetIntValue(group, "UserLifetime"); - MaintInterval = GetIntValue(group, "MaintInterval"); - - if (MaintInterval == 0) - MaintInterval = 24; - - MaintTime = GetIntValue(group, "MaintTime"); - - PR = GetFloatValue(group, "PR"); - PUR = GetFloatValue(group, "PUR"); - PF = GetFloatValue(group, "PF"); - PNF = GetFloatValue(group, "PNF"); - - BF = GetIntValue(group, "BF"); - BNF = GetIntValue(group, "BNF"); - NTSD = GetIntValue(group, "NTSD"); - NTSU = GetIntValue(group, "NTSU"); - NTSF = GetIntValue(group, "NTSF"); -// AP = GetIntValue(group, "AP"); -// AB = GetIntValue(group, "AB"); - DeletetoRecycleBin = GetIntValue(group, "DeletetoRecycleBin"); - SuppressMaintEmail = GetIntValue(group, "SuppressMaintEmail"); - SaveRegDuringMaint = GetIntValue(group, "MaintSaveReg"); - OverrideUnsent = GetIntValue(group, "OverrideUnsent"); - SendNonDeliveryMsgs = GetIntValue(group, "SendNonDeliveryMsgs"); - OverrideUnsent = GetIntValue(group, "OverrideUnsent"); - GenerateTrafficReport = GetIntValueWithDefault(group, "GenerateTrafficReport", 1); - - LTFROM = GetOverrides(group, "LTFROM"); - LTTO = GetOverrides(group, "LTTO"); - LTAT = GetOverrides(group, "LTAT"); - } - - return EXIT_SUCCESS; -} - - -int Connected(int Stream) -{ - int n, Mask; - CIRCUIT * conn; - struct UserInfo * user = NULL; - char callsign[10]; - int port, paclen, maxframe, l4window; - char ConnectedMsg[] = "*** CONNECTED "; - char Msg[100]; - char Title[100]; - int Freq = 0; - int Mode = 0; - BPQVECSTRUC * SESS; - TRANSPORTENTRY * Sess1 = NULL, * Sess2; - - for (n = 0; n < NumberofStreams; n++) - { - conn = &Connections[n]; - - if (Stream == conn->BPQStream) - { - if (conn->Active) - { - // Probably an outgoing connect - - ChangeSessionIdletime(Stream, USERIDLETIME); // Default Idletime for BBS Sessions - conn->SendB = conn->SendP = conn->SendT = conn->DoReverse = TRUE; - conn->MaxBLen = conn->MaxPLen = conn->MaxTLen = 99999999; - conn->ErrorCount = 0; - - if (conn->BBSFlags & RunningConnectScript) - { - // BBS Outgoing Connect - - conn->paclen = 236; - - // Run first line of connect script - - ChangeSessionIdletime(Stream, BBSIDLETIME); // Default Idletime for BBS Sessions - ProcessBBSConnectScript(conn, ConnectedMsg, 15); - return 0; - } - } - - // Incoming Connect - - // Try to find port, freq, mode, etc - -#ifdef LINBPQ - SESS = &BPQHOSTVECTOR[0]; -#else - SESS = (BPQVECSTRUC *)BPQHOSTVECPTR; -#endif - SESS +=(Stream - 1); - - if (SESS) - Sess1 = SESS->HOSTSESSION; - - if (Sess1) - { - Sess2 = Sess1->L4CROSSLINK; - - if (Sess2) - { - // See if L2 session - if so, get info from WL2K report line - - // if Session has report info, use it - - if (Sess2->Mode) - { - Freq = Sess2->Frequency; - Mode = Sess2->Mode; - } - else if (Sess2->L4CIRCUITTYPE & L2LINK) - { - LINKTABLE * LINK = Sess2->L4TARGET.LINK; - PORTCONTROLX * PORT = LINK->LINKPORT; - - Freq = PORT->WL2KInfo.Freq; - Mode = PORT->WL2KInfo.mode; - } - else - { - if (Sess2->RMSCall[0]) - { - Freq = Sess2->Frequency; - Mode = Sess2->Mode; - } - } - } - } - - memset(conn, 0, sizeof(ConnectionInfo)); // Clear everything - conn->Active = TRUE; - conn->BPQStream = Stream; - ChangeSessionIdletime(Stream, USERIDLETIME); // Default Idletime for BBS Sessions - - conn->SendB = conn->SendP = conn->SendT = conn->DoReverse = TRUE; - conn->MaxBLen = conn->MaxPLen = conn->MaxTLen = 99999999; - conn->ErrorCount = 0; - - conn->Secure_Session = GetConnectionInfo(Stream, callsign, - &port, &conn->SessType, &paclen, &maxframe, &l4window); - - strlop(callsign, ' '); // Remove trailing spaces - - if (strcmp(&callsign[strlen(callsign) - 2], "-T") == 0) - conn->RadioOnlyMode = 'T'; - else if (strcmp(&callsign[strlen(callsign) - 2], "-R") == 0) - conn->RadioOnlyMode = 'R'; - else - conn->RadioOnlyMode = 0; - - memcpy(conn->Callsign, callsign, 10); - - strlop(callsign, '-'); // Remove any SSID - - user = LookupCall(callsign); - - if (user == NULL) - { - int Length=0; - - if (OnlyKnown) - { - // Unknown users not allowed - - n = sprintf_s(Msg, sizeof(Msg), "Incoming Connect from unknown user %s Rejected", callsign); - WriteLogLine(conn, '|',Msg, n, LOG_BBS); - - Disconnect(Stream); - return 0; - } - - user = AllocateUserRecord(callsign); - user->Temp = zalloc(sizeof (struct TempUserInfo)); - - if (SendNewUserMessage) - { - char * MailBuffer = malloc(100); - Length += sprintf(MailBuffer, "New User %s Connected to Mailbox on Port %d Freq %d Mode %d\r\n", callsign, port, Freq, Mode); - - sprintf(Title, "New User %s", callsign); - - SendMessageToSYSOP(Title, MailBuffer, Length); - } - - if (user == NULL) return 0; // Cant happen?? - - if (!DontHoldNewUsers) - user->flags |= F_HOLDMAIL; - - if (DefaultNoWINLINK) - user->flags |= F_NOWINLINK; - - // Always set WLE User - can't see it doing any harm - - user->flags |= F_Temp_B2_BBS; - - conn->NewUser = TRUE; - } - - user->TimeLastConnected = time(NULL); - user->Total.ConnectsIn++; - - conn->UserPointer = user; - - conn->lastmsg = user->lastmsg; - - conn->NextMessagetoForward = FirstMessageIndextoForward; - - if (paclen == 0) - { - paclen = 236; - - if (conn->SessType & Sess_PACTOR) - paclen = 100; - } - - conn->paclen = paclen; - - // Set SYSOP flag if user is defined as SYSOP and Host Session - - if (((conn->SessType & Sess_BPQHOST) == Sess_BPQHOST) && (user->flags & F_SYSOP)) - conn->sysop = TRUE; - - if (conn->Secure_Session && (user->flags & F_SYSOP)) - conn->sysop = TRUE; - - Mask = 1 << (GetApplNum(Stream) - 1); - - if (user->flags & F_Excluded) - { - n=sprintf_s(Msg, sizeof(Msg), "Incoming Connect from %s Rejected by Exclude Flag", user->Call); - WriteLogLine(conn, '|',Msg, n, LOG_BBS); - Disconnect(Stream); - return 0; - } - - if (port) - n=sprintf_s(Msg, sizeof(Msg), "Incoming Connect from %s on Port %d Freq %d Mode %s", - user->Call, port, Freq, WL2KModes[Mode]); - else - n=sprintf_s(Msg, sizeof(Msg), "Incoming Connect from %s", user->Call); - - // Send SID and Prompt (Unless Sync) - - if (user->ForwardingInfo && user->ForwardingInfo->ConTimeout) - conn->SIDResponseTimer = user->ForwardingInfo->ConTimeout / 10; // 10 sec ticks - else - conn->SIDResponseTimer = 12; // Allow a couple of minutes for response to SID - - { - BOOL B1 = FALSE, B2 = FALSE, BIN = FALSE, BLOCKED = FALSE; - BOOL WL2KRO = FALSE; - - struct BBSForwardingInfo * ForwardingInfo; - - if (conn->RadioOnlyMode == 'R') - WL2KRO = 1; - - conn->PageLen = user->PageLen; - conn->Paging = (user->PageLen > 0); - - if (user->flags & F_Temp_B2_BBS) - { - // An RMS Express user that needs a temporary BBS struct - - if (user->ForwardingInfo == NULL) - { - // we now save the Forwarding info if BBS flag is cleared, - // so there may already be a ForwardingInfo - - user->ForwardingInfo = zalloc(sizeof(struct BBSForwardingInfo)); - } - - if (user->BBSNumber == 0) - user->BBSNumber = NBBBS; - - ForwardingInfo = user->ForwardingInfo; - - ForwardingInfo->AllowCompressed = TRUE; - B1 = ForwardingInfo->AllowB1 = FALSE; - B2 = ForwardingInfo->AllowB2 = TRUE; - BLOCKED = ForwardingInfo->AllowBlocked = TRUE; - } - - if (conn->NewUser) - { - BLOCKED = TRUE; - BIN = TRUE; - B2 = TRUE; - } - - if (user->ForwardingInfo) - { - BLOCKED = user->ForwardingInfo->AllowBlocked; - if (BLOCKED) - { - BIN = user->ForwardingInfo->AllowCompressed; - B1 = user->ForwardingInfo->AllowB1; - B2 = user->ForwardingInfo->AllowB2; - } - } - - WriteLogLine(conn, '|',Msg, n, LOG_BBS); - - if (conn->RadioOnlyMode) - nodeprintf(conn,";WL2K-Radio/Internet_Network\r"); - - if (!(conn->BBSFlags & SYNCMODE)) - { - - nodeprintf(conn, BBSSID, "BPQ-", - Ver[0], Ver[1], Ver[2], Ver[3], - BIN ? "B" : "", B1 ? "1" : "", B2 ? "2" : "", - BLOCKED ? "FW": "", WL2KRO ? "" : "J"); - - // if (user->flags & F_Temp_B2_BBS) - // nodeprintf(conn,";PQ: 66427529\r"); - - // nodeprintf(conn,"[WL2K-BPQ.1.0.4.39-B2FWIHJM$]\r"); - } - } - - if ((user->Name[0] == 0) & AllowAnon) - strcpy(user->Name, user->Call); - - if (!(conn->BBSFlags & SYNCMODE)) - { - if (user->Name[0] == 0) - { - conn->Flags |= GETTINGUSER; - BBSputs(conn, NewUserPrompt); - } - else - SendWelcomeMsg(Stream, conn, user); - } - else - { - // Seems to be a timing problem - see if this fixes it - - Sleep(500); - } - - RefreshMainWindow(); - - return 0; - } - } - - return 0; -} - -int Disconnected (int Stream) -{ - struct UserInfo * user = NULL; - CIRCUIT * conn; - int n; - char Msg[255]; - int len; - char DiscMsg[] = "DISCONNECTED "; - - for (n = 0; n <= NumberofStreams-1; n++) - { - conn=&Connections[n]; - - if (Stream == conn->BPQStream) - { - if (conn->Active == FALSE) - return 0; - - // if still running connect script, reenter it to see if - // there is an else - - if (conn->BBSFlags & RunningConnectScript) - { - // We need to see if we got as far as connnected, - // as if we have we need to reset the connect script - // over the ELSE - - struct BBSForwardingInfo * ForwardingInfo = conn->UserPointer->ForwardingInfo; - char ** Scripts; - - if (ForwardingInfo->TempConnectScript) - Scripts = ForwardingInfo->TempConnectScript; - else - Scripts = ForwardingInfo->ConnectScript; - - // First see if any script left - - if (Scripts[ForwardingInfo->ScriptIndex]) - { - if (ForwardingInfo->MoreLines == FALSE) - { - // Have reached end of script, so need to set back over ELSE - - ForwardingInfo->ScriptIndex--; - ForwardingInfo->MoreLines = TRUE; - } - - // if (Scripts[ForwardingInfo->ScriptIndex] == NULL || - // _memicmp(Scripts[ForwardingInfo->ScriptIndex], "TIMES", 5) == 0 || // Only Check until script is finished - // _memicmp(Scripts[ForwardingInfo->ScriptIndex], "ELSE", 4) == 0) // Only Check until script is finished - - - ProcessBBSConnectScript(conn, DiscMsg, 15); - return 0; - } - } - - // if sysop was chatting to user clear link -#ifndef LINBPQ - if (conn->BBSFlags & SYSOPCHAT) - { - SendUnbuffered(-1, "User has disconnected\n", 23); - BBSConsole.Console->SysopChatStream = 0; - } -#endif - ClearQueue(conn); - - if (conn->PacLinkCalls) - free(conn->PacLinkCalls); - - if (conn->InputBuffer) - { - free(conn->InputBuffer); - conn->InputBuffer = NULL; - conn->InputBufferLen = 0; - } - - if (conn->InputMode == 'B') - { - // Save partly received message for a restart - - if (conn->BBSFlags & FBBB1Mode) - if (conn->Paclink == 0) // Paclink doesn't do restarts - if (strcmp(conn->Callsign, "RMS") != 0) // Neither does RMS Packet. - if (conn->DontSaveRestartData == FALSE) - SaveFBBBinary(conn); - } - - conn->Active = FALSE; - - if (conn->FwdMsg) - conn->FwdMsg->Locked = 0; // Unlock - - RefreshMainWindow(); - - RemoveTempBIDS(conn); - - len=sprintf_s(Msg, sizeof(Msg), "%s Disconnected", conn->Callsign); - WriteLogLine(conn, '|',Msg, len, LOG_BBS); - - if (conn->FBBHeaders) - { - struct FBBHeaderLine * FBBHeader; - int n; - - for (n = 0; n < 5; n++) - { - FBBHeader = &conn->FBBHeaders[n]; - - if (FBBHeader->FwdMsg) - FBBHeader->FwdMsg->Locked = 0; // Unlock - - } - - free(conn->FBBHeaders); - conn->FBBHeaders = NULL; - } - - if (conn->UserPointer) - { - struct BBSForwardingInfo * FWDInfo = conn->UserPointer->ForwardingInfo; - - if (FWDInfo) - { - FWDInfo->Forwarding = FALSE; - -// if (FWDInfo->UserCall[0]) // Will be set if RMS -// { -// FindNextRMSUser(FWDInfo); -// } -// else - FWDInfo->FwdTimer = 0; - } - } - - conn->BBSFlags = 0; // Clear ARQ Mode - - return 0; - } - } - return 0; -} - -int DoReceivedData(int Stream) -{ - int count, InputLen; - size_t MsgLen; - int n; - CIRCUIT * conn; - struct UserInfo * user; - char * ptr, * ptr2; - char * Buffer; - - for (n = 0; n < NumberofStreams; n++) - { - conn = &Connections[n]; - - if (Stream == conn->BPQStream) - { - conn->SIDResponseTimer = 0; // Got a message, so cancel timeout. - - do - { - // May have several messages per packet, or message split over packets - - OuterLoop: - if (conn->InputLen + 1000 > conn->InputBufferLen ) // Shouldnt have lines longer than this in text mode - { - conn->InputBufferLen += 1000; - conn->InputBuffer = realloc(conn->InputBuffer, conn->InputBufferLen); - } - - GetMsg(Stream, &conn->InputBuffer[conn->InputLen], &InputLen, &count); - - if (InputLen == 0 && conn->InputMode != 'Y') - return 0; - - conn->InputLen += InputLen; - - if (conn->InputLen == 0) return 0; - - conn->Watchdog = 900; // 15 Minutes - - if (conn->InputMode == 'Y') // YAPP - { - if (ProcessYAPPMessage(conn)) // Returns TRUE if there could be more to process - goto OuterLoop; - - return 0; - } - - if (conn->InputMode == 'B') - { - // if in OpenBCM mode, remove FF transparency - - if (conn->OpenBCM) // Telnet, so escape any 0xFF - { - unsigned char * ptr1 = conn->InputBuffer; - unsigned char * ptr2; - int Len; - unsigned char c; - - // We can come through here again for the - // same data as we wait for a full packet - // So only check last InputLen bytes - - ptr1 += (conn->InputLen - InputLen); - ptr2 = ptr1; - Len = InputLen; - - while (Len--) - { - c = *(ptr1++); - - if (conn->InTelnetExcape) // Last char was ff - { - conn->InTelnetExcape = FALSE; - continue; - } - - *(ptr2++) = c; - - if (c == 0xff) // - conn->InTelnetExcape = TRUE; - } - - conn->InputLen = (int)(ptr2 - conn->InputBuffer); - } - - UnpackFBBBinary(conn); - goto OuterLoop; - } - else - { - - loop: - - if (conn->InputLen == 1 && conn->InputBuffer[0] == 0) // Single Null - { - conn->InputLen = 0; - return 0; - } - - user = conn->UserPointer; - - if (conn->BBSFlags & (MCASTRX | SYNCMODE)) - { - // MCAST and SYNCMODE deliver full packets - - if (conn->BBSFlags & RunningConnectScript) - ProcessBBSConnectScript(conn, conn->InputBuffer, conn->InputLen); - else - ProcessLine(conn, user, conn->InputBuffer, conn->InputLen); - - conn->InputLen=0; - continue; - } - - // This looks for CR, CRLF, LF or CR/Null and removes any LF or NULL, - // but this relies on both arriving in same packet. - // Need to check for LF and start of packet and ignore it - // But what if client is only using LF?? - // (WLE sends SID with CRLF, other packets with CR only) - - // We don't get here on the data part of a binary transfer, so - // don't need to worry about messing up binary data. - - ptr = memchr(conn->InputBuffer, '\r', conn->InputLen); - ptr2 = memchr(conn->InputBuffer, '\n', conn->InputLen); - - if (ptr) - conn->usingCR = 1; - - if ((ptr2 && ptr2 < ptr) || ptr == 0) // LF before CR, or no CR - ptr = ptr2; // Use LF - - if (ptr) // CR or LF in buffer - { - conn->lastLineEnd = *(ptr); - - *(ptr) = '\r'; // In case was LF - - ptr2 = &conn->InputBuffer[conn->InputLen]; - - if (++ptr == ptr2) - { - // Usual Case - single msg in buffer - - // if Length is 1 and Term is LF and normal line end is CR - // this is from a split CRLF - Ignore it - - if (conn->InputLen == 1 && conn->lastLineEnd == 0x0a && conn->usingCR) - Debugprintf("BPQMail split Line End Detected"); - else - { - if (conn->BBSFlags & RunningConnectScript) - ProcessBBSConnectScript(conn, conn->InputBuffer, conn->InputLen); - else - ProcessLine(conn, user, conn->InputBuffer, conn->InputLen); - } - conn->InputLen=0; - } - else - { - // buffer contains more that 1 message - - MsgLen = conn->InputLen - (ptr2-ptr); - - Buffer = malloc(MsgLen + 100); - - memcpy(Buffer, conn->InputBuffer, MsgLen); - - // if Length is 1 and Term is LF and normal line end is CR - // this is from a split CRLF - Ignore it - - if (MsgLen == 1 && conn->lastLineEnd == 0x0a && conn->usingCR) - Debugprintf("BPQMail split Line End Detected"); - else - { - if (conn->BBSFlags & RunningConnectScript) - ProcessBBSConnectScript(conn, Buffer, (int)MsgLen); - else - ProcessLine(conn, user, Buffer, (int)MsgLen); - } - free(Buffer); - - if (*ptr == 0 || *ptr == '\n') - { - /// CR LF or CR Null - - ptr++; - conn->InputLen--; - } - - memmove(conn->InputBuffer, ptr, conn->InputLen-MsgLen); - - conn->InputLen -= (int)MsgLen; - - goto loop; - - } - } - else - { - // Could be a YAPP Header - - - if (conn->InputLen == 2 && conn->InputBuffer[0] == ENQ && conn->InputBuffer[1] == 1) // YAPP Send_Init - { - UCHAR YAPPRR[2]; - YAPPRR[0] = ACK; - YAPPRR[1] = 1; - - conn->InputMode = 'Y'; - QueueMsg(conn, YAPPRR, 2); - - conn->InputLen = 0; - return 0; - } - } - } - - } while (count > 0); - - return 0; - } - } - - // Socket not found - - return 0; - -} -int DoBBSMonitorData(int Stream) -{ -// UCHAR Buffer[1000]; - UCHAR buff[500]; - - int len = 0,count=0; - int stamp; - - do - { - stamp=GetRaw(Stream, buff,&len,&count); - - if (len == 0) return 0; - - SeeifBBSUIFrame((struct _MESSAGEX *)buff, len); - } - - while (count > 0); - - - return 0; - -} - -VOID ProcessFLARQLine(ConnectionInfo * conn, struct UserInfo * user, char * Buffer, int MsgLen) -{ - Buffer[MsgLen] = 0; - - if (MsgLen == 1 && Buffer[0] == 13) - return; - - if (strcmp(Buffer, "ARQ::ETX\r") == 0) - { - // Decode it. - - UCHAR * ptr1, * ptr2, * ptr3; - int len, linelen; - struct MsgInfo * Msg = conn->TempMsg; - time_t Date; - char FullTo[100]; - char FullFrom[100]; - char ** RecpTo = NULL; // May be several Recipients - char ** HddrTo = NULL; // May be several Recipients - char ** Via = NULL; // May be several Recipients - int LocalMsg[1000] ; // Set if Recipient is a local wl2k address - - int B2To; // Offset to To: fields in B2 header - int Recipients = 0; - int RMSMsgs = 0, BBSMsgs = 0; - -// Msg->B2Flags |= B2Msg; - - - ptr1 = conn->MailBuffer; - len = Msg->length; - ptr1[len] = 0; - - if (strstr(ptr1, "ARQ:ENCODING::")) - { - // a file, not a message. If is called "BBSPOLL" do a reverse forward else Ignore for now - - _strupr(conn->MailBuffer); - if (strstr(conn->MailBuffer, "BBSPOLL")) - { - SendARQMail(conn); - } - - free(conn->MailBuffer); - conn->MailBuffer = NULL; - conn->MailBufferSize = 0; - - return; - } - Loop: - ptr2 = strchr(ptr1, '\r'); - - linelen = (int)(ptr2 - ptr1); - - if (_memicmp(ptr1, "From:", 5) == 0 && linelen > 6) // Can have empty From: - { - char SaveFrom[100]; - char * FromHA; - - memcpy(FullFrom, ptr1, linelen); - FullFrom[linelen] = 0; - - // B2 From may now contain an @BBS - - strcpy(SaveFrom, FullFrom); - - FromHA = strlop(SaveFrom, '@'); - - if (strlen(SaveFrom) > 12) SaveFrom[12] = 0; - - strcpy(Msg->from, &SaveFrom[6]); - - if (FromHA) - { - if (strlen(FromHA) > 39) FromHA[39] = 0; - Msg->emailfrom[0] = '@'; - strcpy(&Msg->emailfrom[1], _strupr(FromHA)); - } - - // Remove any SSID - - ptr3 = strchr(Msg->from, '-'); - if (ptr3) *ptr3 = 0; - - } - else if (_memicmp(ptr1, "To:", 3) == 0 || _memicmp(ptr1, "cc:", 3) == 0) - { - HddrTo=realloc(HddrTo, (Recipients+1) * sizeof(void *)); - HddrTo[Recipients] = zalloc(100); - - memset(FullTo, 0, 99); - memcpy(FullTo, &ptr1[4], linelen-4); - memcpy(HddrTo[Recipients], ptr1, linelen+2); - LocalMsg[Recipients] = FALSE; - - _strupr(FullTo); - - B2To = (int)(ptr1 - conn->MailBuffer); - - if (_memicmp(FullTo, "RMS:", 4) == 0) - { - // remove RMS and add @winlink.org - - strcpy(FullTo, "RMS"); - strcpy(Msg->via, &FullTo[4]); - } - else - { - ptr3 = strchr(FullTo, '@'); - - if (ptr3) - { - *ptr3++ = 0; - strcpy(Msg->via, ptr3); - } - else - Msg->via[0] = 0; - } - - if (_memicmp(&ptr1[4], "SMTP:", 5) == 0) - { - // Airmail Sends MARS messages as SMTP - - if (CheckifPacket(Msg->via)) - { - // Packet Message - - memmove(FullTo, &FullTo[5], strlen(FullTo) - 4); - _strupr(FullTo); - _strupr(Msg->via); - - // Update the saved to: line (remove the smtp:) - - strcpy(&HddrTo[Recipients][4], &HddrTo[Recipients][9]); - BBSMsgs++; - goto BBSMsg; - } - - // If a winlink.org address we need to convert to call - - if (_stricmp(Msg->via, "winlink.org") == 0) - { - memmove(FullTo, &FullTo[5], strlen(FullTo) - 4); - _strupr(FullTo); - LocalMsg[Recipients] = CheckifLocalRMSUser(FullTo); - } - else - { - memcpy(Msg->via, &ptr1[9], linelen); - Msg->via[linelen - 9] = 0; - strcpy(FullTo,"RMS"); - } -// FullTo[0] = 0; - - BBSMsg: - _strupr(FullTo); - _strupr(Msg->via); - } - - if (memcmp(FullTo, "RMS:", 4) == 0) - { - // remove RMS and add @winlink.org - - memmove(FullTo, &FullTo[4], strlen(FullTo) - 3); - strcpy(Msg->via, "winlink.org"); - sprintf(HddrTo[Recipients], "To: %s\r\n", FullTo); - } - - if (strcmp(Msg->via, "RMS") == 0) - { - // replace RMS with @winlink.org - - strcpy(Msg->via, "winlink.org"); - sprintf(HddrTo[Recipients], "To: %s@winlink.org\r\n", FullTo); - } - - if (strlen(FullTo) > 6) - FullTo[6] = 0; - - strlop(FullTo, '-'); - - strcpy(Msg->to, FullTo); - - if (SendBBStoSYSOPCall) - if (_stricmp(FullTo, BBSName) == 0) - strcpy(Msg->to, SYSOPCall); - - if ((Msg->via[0] == 0 || strcmp(Msg->via, "BPQ") == 0 || strcmp(Msg->via, "BBS") == 0)) - { - // No routing - check @BBS and WP - - struct UserInfo * ToUser = LookupCall(FullTo); - - Msg->via[0] = 0; // In case BPQ and not found - - if (ToUser) - { - // Local User. If Home BBS is specified, use it - - if (ToUser->HomeBBS[0]) - { - strcpy(Msg->via, ToUser->HomeBBS); - } - } - else - { - WPRecP WP = LookupWP(FullTo); - - if (WP) - { - strcpy(Msg->via, WP->first_homebbs); - - } - } - - // Fix To: address in B2 Header - - if (Msg->via[0]) - sprintf(HddrTo[Recipients], "To: %s@%s\r\n", FullTo, Msg->via); - else - sprintf(HddrTo[Recipients], "To: %s\r\n", FullTo); - - } - - RecpTo=realloc(RecpTo, (Recipients+1) * sizeof(void *)); - RecpTo[Recipients] = zalloc(10); - - Via=realloc(Via, (Recipients+1) * sizeof(void *)); - Via[Recipients] = zalloc(50); - - strcpy(Via[Recipients], Msg->via); - strcpy(RecpTo[Recipients++], FullTo); - - // Remove the To: Line from the buffer - - } - else if (_memicmp(ptr1, "Type:", 4) == 0) - { - if (ptr1[6] == 'N') - Msg->type = 'T'; // NTS - else - Msg->type = ptr1[6]; - } - else if (_memicmp(ptr1, "Subject:", 8) == 0) - { - size_t Subjlen = ptr2 - &ptr1[9]; - if (Subjlen > 60) Subjlen = 60; - memcpy(Msg->title, &ptr1[9], Subjlen); - - goto ProcessBody; - } -// else if (_memicmp(ptr1, "Body:", 4) == 0) -// { -// MsgLen = atoi(&ptr1[5]); -// StartofMsg = ptr1; -// } - else if (_memicmp(ptr1, "File:", 5) == 0) - { - Msg->B2Flags |= Attachments; - } - else if (_memicmp(ptr1, "Date:", 5) == 0) - { - struct tm rtime; - char seps[] = " ,\t\r"; - - memset(&rtime, 0, sizeof(struct tm)); - - // Date: 2009/07/25 10:08 - - sscanf(&ptr1[5], "%04d/%02d/%02d %02d:%02d:%02d", - &rtime.tm_year, &rtime.tm_mon, &rtime.tm_mday, &rtime.tm_hour, &rtime.tm_min, &rtime.tm_sec); - - sscanf(&ptr1[5], "%02d/%02d/%04d %02d:%02d:%02d", - &rtime.tm_mday, &rtime.tm_mon, &rtime.tm_year, &rtime.tm_hour, &rtime.tm_min, &rtime.tm_sec); - - rtime.tm_year -= 1900; - - Date = mktime(&rtime) - (time_t)_MYTIMEZONE; - - if (Date == (time_t)-1) - Date = time(NULL); - - Msg->datecreated = Date; - - } - - if (linelen) // Not Null line - { - ptr1 = ptr2 + 2; // Skip cr - goto Loop; - } - - - // Processed all headers -ProcessBody: - - ptr2 +=2; // skip crlf - - Msg->length = (int)(&conn->MailBuffer[Msg->length] - ptr2); - - memmove(conn->MailBuffer, ptr2, Msg->length); - - CreateMessageFromBuffer(conn); - - conn->BBSFlags = 0; // Clear ARQ Mode - return; - } - - // File away the data - - Buffer[MsgLen++] = 0x0a; // BBS Msgs stored with crlf - - if ((conn->TempMsg->length + MsgLen) > conn->MailBufferSize) - { - conn->MailBufferSize += 10000; - conn->MailBuffer = realloc(conn->MailBuffer, conn->MailBufferSize); - - if (conn->MailBuffer == NULL) - { - BBSputs(conn, "*** Failed to extend Message Buffer\r"); - conn->CloseAfterFlush = 20; // 2 Secs - - return; - } - } - - memcpy(&conn->MailBuffer[conn->TempMsg->length], Buffer, MsgLen); - - conn->TempMsg->length += MsgLen; - - return; - - // Not sure what to do yet with files, but will process emails (using text style forwarding - -/* -ARQ:FILE::flarqmail-1.eml -ARQ:EMAIL:: -ARQ:SIZE::96 -ARQ::STX -//FLARQ COMPOSER -Date: 16/01/2014 22:26:06 -To: g8bpq -From: -Subject: test message - -Hello -Hello - -ARQ::ETX -*/ - - return; -} - -VOID ProcessTextFwdLine(ConnectionInfo * conn, struct UserInfo * user, char * Buffer, int len) -{ - Buffer[len] = 0; -// Debugprintf(Buffer); - - // With TNC2 body prompt is a single CR, so that shouldn't be ignored. - - // If thia causes problems with other TNC PMS implementations I'll have to revisit this - -// if (len == 1 && Buffer[0] == 13) -// return; - - if (conn->Flags & SENDTITLE) - { - // Waiting for Subject: prompt - - struct MsgInfo * Msg = conn->FwdMsg; - - nodeprintf(conn, "%s\r", Msg->title); - - conn->Flags &= ~SENDTITLE; - conn->Flags |= SENDBODY; - - // New Paccom PMS (V3.2) doesn't prompt for body so drop through and send it - if ((conn->BBSFlags & NEWPACCOM) == 0) - return; - - } - - if (conn->Flags & SENDBODY) - { - // Waiting for Enter Message Prompt - - struct tm * tm; - time_t temp; - - char * MsgBytes = ReadMessageFile(conn->FwdMsg->number); - char * MsgPtr; - int MsgLen; - int Index = 0; - - if (MsgBytes == 0) - { - MsgBytes = _strdup("Message file not found\r"); - conn->FwdMsg->length = (int)strlen(MsgBytes); - } - - MsgPtr = MsgBytes; - MsgLen = conn->FwdMsg->length; - - // If a B2 Message, remove B2 Header - - if (conn->FwdMsg->B2Flags & B2Msg) - { - // Remove all B2 Headers, and all but the first part. - - MsgPtr = strstr(MsgBytes, "Body:"); - - if (MsgPtr) - { - MsgLen = atoi(&MsgPtr[5]); - MsgPtr= strstr(MsgBytes, "\r\n\r\n"); // Blank Line after headers - - if (MsgPtr) - MsgPtr +=4; - else - MsgPtr = MsgBytes; - - } - else - MsgPtr = MsgBytes; - } - - memcpy(&temp, &conn->FwdMsg->datereceived, sizeof(time_t)); - tm = gmtime(&temp); - - nodeprintf(conn, "R:%02d%02d%02d/%02d%02dZ %d@%s.%s %s\r", - tm->tm_year-100, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, - conn->FwdMsg->number, BBSName, HRoute, RlineVer); - - if (memcmp(MsgPtr, "R:", 2) != 0) // No R line, so must be our message - put blank line after header - BBSputs(conn, "\r"); - - MsgLen = RemoveLF(MsgPtr, MsgLen); - - QueueMsg(conn, MsgPtr, MsgLen); - - if (user->ForwardingInfo->SendCTRLZ) - nodeprintf(conn, "\r\x1a"); - else - nodeprintf(conn, "\r/ex\r"); - - free(MsgBytes); - - conn->FBBMsgsSent = TRUE; - - - if (conn->FwdMsg->type == 'P') - Index = PMSG; - else if (conn->FwdMsg->type == 'B') - Index = BMSG; - else if (conn->FwdMsg->type == 'T') - Index = TMSG; - - user->Total.MsgsSent[Index]++; - user->Total.BytesForwardedOut[Index] += MsgLen; - - conn->Flags &= ~SENDBODY; - conn->Flags |= WAITPROMPT; - - return; - } - - if (conn->Flags & WAITPROMPT) - { - if (Buffer[len-2] != '>') - return; - - conn->Flags &= ~WAITPROMPT; - - clear_fwd_bit(conn->FwdMsg->fbbs, user->BBSNumber); - set_fwd_bit(conn->FwdMsg->forw, user->BBSNumber); - - // Only mark as forwarded if sent to all BBSs that should have it - - if (memcmp(conn->FwdMsg->fbbs, zeros, NBMASK) == 0) - { - conn->FwdMsg->status = 'F'; // Mark as forwarded - conn->FwdMsg->datechanged=time(NULL); - } - - SaveMessageDatabase(); - - conn->UserPointer->ForwardingInfo->MsgCount--; - - // See if any more to forward - - if (FindMessagestoForward(conn) && conn->FwdMsg) - { - struct MsgInfo * Msg; - - // If we are using SETCALLTOSENDER make sure this message is from the same sender - -#ifdef LINBPQ - BPQVECSTRUC * SESS = &BPQHOSTVECTOR[0]; -#else - BPQVECSTRUC * SESS = (BPQVECSTRUC *)BPQHOSTVECPTR; -#endif - unsigned char AXCall[7]; - - Msg = conn->FwdMsg; - ConvToAX25(Msg->from, AXCall); - if (memcmp(SESS[conn->BPQStream - 1].HOSTSESSION->L4USER, AXCall, 7) != 0) - { - Disconnect(conn->BPQStream); - return; - } - - // Send S line and wait for response - SB WANT @ USA < W8AAA $1029_N0XYZ - - conn->Flags |= SENDTITLE; - - - if ((conn->BBSFlags & SETCALLTOSENDER)) - nodeprintf(conn, "S%c %s @ %s \r", Msg->type, Msg->to, - (Msg->via[0]) ? Msg->via : conn->UserPointer->Call); - else - nodeprintf(conn, "S%c %s @ %s < %s $%s\r", Msg->type, Msg->to, - (Msg->via[0]) ? Msg->via : conn->UserPointer->Call, - Msg->from, Msg->bid); - } - else - { - Disconnect(conn->BPQStream); - } - return; - } -} - - -#define N 2048 /* buffer size */ -#define F 60 /* lookahead buffer size */ -#define THRESHOLD 2 -#define NIL N /* leaf of tree */ - -extern UCHAR * infile; - -BOOL CheckforMIME(SocketConn * sockptr, char * Msg, char ** Body, int * MsgLen); - - -VOID ProcessLine(CIRCUIT * conn, struct UserInfo * user, char* Buffer, int len) -{ - char * Cmd, * Arg1; - char * Context; - char seps[] = " \t\r"; - int CmdLen; - - if (_memicmp(Buffer, "POSYNCLOGON", 11) == 0) - { - WriteLogLine(conn, '<', Buffer, len-1, LOG_BBS); - conn->BBSFlags |= SYNCMODE; - conn->FBBHeaders = zalloc(5 * sizeof(struct FBBHeaderLine)); - - Sleep(500); - - BBSputs(conn, "OK\r"); - Flush(conn); - return; - } - - if (_memicmp(Buffer, "POSYNCHELLO", 11) == 0) - { - // This is first message received after connecting to SYNC - // Save Callsign - - char Reply[32]; - conn->BBSFlags |= SYNCMODE; - conn->FBBHeaders = zalloc(5 * sizeof(struct FBBHeaderLine)); - - sprintf(Reply, "POSYNCLOGON %s\r", BBSName); - BBSputs(conn, Reply); - return; - } - - if (conn->BBSFlags & SYNCMODE) - { - ProcessSyncModeMessage(conn, user, Buffer, len); - return; - } - - WriteLogLine(conn, '<', Buffer, len-1, LOG_BBS); - - // A few messages should be trapped here and result in an immediate disconnect, whatever mode I think the session is in (it could be wrong) - - // *** Protocol Error - // Already Connected - // Invalid Command - - if (_memicmp(Buffer, "Already Connected", 17) == 0 || - _memicmp(Buffer, "Invalid Command", 15) == 0 || - _memicmp(Buffer, "*** Protocol Error", 18) == 0) - { - conn->BBSFlags |= DISCONNECTING; - Disconnect(conn->BPQStream); - return; - } - - if (conn->BBSFlags & FBBForwarding) - { - ProcessFBBLine(conn, user, Buffer, len); - return; - } - - if (conn->BBSFlags & FLARQMODE) - { - ProcessFLARQLine(conn, user, Buffer, len); - return; - } - - if (conn->BBSFlags & MCASTRX) - { - ProcessMCASTLine(conn, user, Buffer, len); - return; - } - - - if (conn->BBSFlags & TEXTFORWARDING) - { - ProcessTextFwdLine(conn, user, Buffer, len); - return; - } - - // if chatting to sysop pass message to BBS console - - if (conn->BBSFlags & SYSOPCHAT) - { - SendUnbuffered(-1, Buffer,len); - return; - } - - if (conn->Flags & GETTINGMESSAGE) - { - ProcessMsgLine(conn, user, Buffer, len); - return; - } - if (conn->Flags & GETTINGTITLE) - { - ProcessMsgTitle(conn, user, Buffer, len); - return; - } - - if (conn->BBSFlags & MBLFORWARDING) - { - ProcessMBLLine(conn, user, Buffer, len); - return; - } - - if (conn->Flags & GETTINGUSER || conn->NewUser) // Could be new user but dont need name - { - if (memcmp(Buffer, ";FW:", 4) == 0 || Buffer[0] == '[') - { - struct BBSForwardingInfo * ForwardingInfo; - - conn->Flags &= ~GETTINGUSER; - - // New User is a BBS - create a temp struct for it - - if ((user->flags & (F_BBS | F_Temp_B2_BBS)) == 0) // It could already be a BBS without a user name - { - // Not defined as BBS - allocate and initialise forwarding structure - - user->flags |= F_Temp_B2_BBS; - - // An RMS Express user that needs a temporary BBS struct - - ForwardingInfo = user->ForwardingInfo = zalloc(sizeof(struct BBSForwardingInfo)); - - ForwardingInfo->AllowCompressed = TRUE; - ForwardingInfo->AllowBlocked = TRUE; - conn->UserPointer->ForwardingInfo->AllowB2 = TRUE; - } - SaveUserDatabase(); - } - else - { - if (conn->Flags & GETTINGUSER) - { - conn->Flags &= ~GETTINGUSER; - if (len > 18) - len = 18; - - memcpy(user->Name, Buffer, len-1); - SendWelcomeMsg(conn->BPQStream, conn, user); - SaveUserDatabase(); - UpdateWPWithUserInfo(user); - return; - } - } - } - - // Process Command - - if (conn->Paging && (conn->LinesSent >= conn->PageLen)) - { - // Waiting for paging prompt - - if (len > 1) - { - if (_memicmp(Buffer, "Abort", 1) == 0) - { - ClearQueue(conn); - conn->LinesSent = 0; - - nodeprintf(conn, AbortedMsg); - - if (conn->UserPointer->Temp->ListSuspended) - nodeprintf(conn, "bort, , = Continue..>"); - - SendPrompt(conn, user); - return; - } - } - - conn->LinesSent = 0; - return; - } - - if (user->Temp->ListSuspended) - { - // Paging limit hit when listing. User may abort, continue, or read one or more messages - - ProcessSuspendedListCommand(conn, user, Buffer, len); - return; - } - if (len == 1) - { - SendPrompt(conn, user); - return; - } - - Buffer[len] = 0; - - if (strstr(Buffer, "ARQ:FILE:")) - { - // Message from FLARQ - - conn->BBSFlags |= FLARQMODE; - strcpy(conn->ARQFilename, &Buffer[10]); // Will need name when we decide what to do with files - - // Create a Temp Messge Stucture - - CreateMessage(conn, conn->Callsign, "", "", 'P', NULL, NULL); - - Buffer[len++] = 0x0a; // BBS Msgs stored with crlf - - if ((conn->TempMsg->length + len) > conn->MailBufferSize) - { - conn->MailBufferSize += 10000; - conn->MailBuffer = realloc(conn->MailBuffer, conn->MailBufferSize); - - if (conn->MailBuffer == NULL) - { - BBSputs(conn, "*** Failed to extend Message Buffer\r"); - conn->CloseAfterFlush = 20; // 2 Secs - - return; - } - } - - memcpy(&conn->MailBuffer[conn->TempMsg->length], Buffer, len); - - conn->TempMsg->length += len; - - return; - } - if (Buffer[0] == ';') // WL2K Comment - { - if (memcmp(Buffer, ";FW:", 4) == 0) - { - // Paclink User Select (poll for list) - - char * ptr1,* ptr2, * ptr3; - int index=0; - - // Convert string to Multistring - - Buffer[len-1] = 0; - - conn->PacLinkCalls = zalloc(len*3); - - ptr1 = &Buffer[5]; - ptr2 = (char *)conn->PacLinkCalls; - ptr2 += (len * 2); - strcpy(ptr2, ptr1); - - while (ptr2) - { - ptr3 = strlop(ptr2, ' '); - - if (strlen(ptr2)) - conn->PacLinkCalls[index++] = ptr2; - - ptr2 = ptr3; - } - - return; - } - - if (memcmp(Buffer, ";FR:", 4) == 0) - { - // New Message from TriMode - Just igonre till I know what to do with it - - return; - } - - // Ignore other ';' message - - return; - } - - - - if (Buffer[0] == '[' && Buffer[len-2] == ']') // SID - { - // If a BBS, set BBS Flag - - if (user->flags & ( F_BBS | F_Temp_B2_BBS)) - { - if (user->ForwardingInfo) - { - if (user->ForwardingInfo->Forwarding && ((conn->BBSFlags & OUTWARDCONNECT) == 0)) - { - BBSputs(conn, "Already Connected\r"); - Flush(conn); - Sleep(500); - Disconnect(conn->BPQStream); - return; - } - } - - if (user->ForwardingInfo) - { - user->ForwardingInfo->Forwarding = TRUE; - user->ForwardingInfo->FwdTimer = 0; // So we dont send to immediately - } - } - - if (user->flags & ( F_BBS | F_PMS | F_Temp_B2_BBS)) - { - Parse_SID(conn, &Buffer[1], len-4); - - if (conn->BBSFlags & FBBForwarding) - { - conn->FBBIndex = 0; // ready for first block; - conn->FBBChecksum = 0; - memset(&conn->FBBHeaders[0], 0, 5 * sizeof(struct FBBHeaderLine)); - } - else - FBBputs(conn, ">\r"); - - } - - return; - } - - Cmd = strtok_s(Buffer, seps, &Context); - - if (Cmd == NULL) - { - if (!CheckForTooManyErrors(conn)) - BBSputs(conn, "Invalid Command\r"); - - SendPrompt(conn, user); - return; - } - - Arg1 = strtok_s(NULL, seps, &Context); - CmdLen = (int)strlen(Cmd); - - // Check List first. If any other, save last listed to user record. - - if (_memicmp(Cmd, "L", 1) == 0 && _memicmp(Cmd, "LISTFILES", 3) != 0) - { - DoListCommand(conn, user, Cmd, Arg1, FALSE, Context); - SendPrompt(conn, user); - return; - } - - if (conn->lastmsg > user->lastmsg) - { - user->lastmsg = conn->lastmsg; - SaveUserDatabase(); - } - - if (_stricmp(Cmd, "SHOWRMSPOLL") == 0) - { - DoShowRMSCmd(conn, user, Arg1, Context); - return; - } - - if (_stricmp(Cmd, "AUTH") == 0) - { - DoAuthCmd(conn, user, Arg1, Context); - return; - } - - if (_memicmp(Cmd, "Abort", 1) == 0) - { - ClearQueue(conn); - conn->LinesSent = 0; - - nodeprintf(conn, AbortedMsg); - - if (conn->UserPointer->Temp->ListSuspended) - nodeprintf(conn, "bort, , = Continue..>"); - - SendPrompt(conn, user); - return; - } - if (_memicmp(Cmd, "Bye", CmdLen) == 0 || _stricmp(Cmd, "ELSE") == 0) - { - ExpandAndSendMessage(conn, SignoffMsg, LOG_BBS); - Flush(conn); - Sleep(1000); - - if (conn->BPQStream > 0) - Disconnect(conn->BPQStream); -#ifndef LINBPQ - else - CloseConsole(conn->BPQStream); -#endif - return; - } - - if (_memicmp(Cmd, "Node", 4) == 0) - { - ExpandAndSendMessage(conn, SignoffMsg, LOG_BBS); - Flush(conn); - Sleep(1000); - - if (conn->BPQStream > 0) - ReturntoNode(conn->BPQStream); -#ifndef LINBPQ - else - CloseConsole(conn->BPQStream); -#endif - return; - } - - if (_memicmp(Cmd, "IDLETIME", 4) == 0) - { - DoSetIdleTime(conn, user, Arg1, Context); - return; - } - - if (_stricmp(Cmd, "SETNEXTMESSAGENUMBER") == 0) - { - DoSetMsgNo(conn, user, Arg1, Context); - return; - } - - if (strlen(Cmd) < 12 && _memicmp(Cmd, "D", 1) == 0) - { - DoDeliveredCommand(conn, user, Cmd, Arg1, Context); - SendPrompt(conn, user); - return; - } - - if (_memicmp(Cmd, "K", 1) == 0) - { - DoKillCommand(conn, user, Cmd, Arg1, Context); - SendPrompt(conn, user); - return; - } - - - if (_memicmp(Cmd, "LISTFILES", 3) == 0 || _memicmp(Cmd, "FILES", 5) == 0) - { - ListFiles(conn, user, Arg1); - SendPrompt(conn, user); - return; - } - - if (_memicmp(Cmd, "READFILE", 4) == 0) - { - ReadBBSFile(conn, user, Arg1); - SendPrompt(conn, user); - return; - } - - if (_memicmp(Cmd, "REROUTEMSGS", 7) == 0) - { - if (conn->sysop == 0) - nodeprintf(conn, "Reroute Messages needs SYSOP status\r"); - else - { - ReRouteMessages(); - nodeprintf(conn, "Ok\r"); - } - SendPrompt(conn, user); - return; - } - - if (_memicmp(Cmd, "YAPP", 4) == 0) - { - YAPPSendFile(conn, user, Arg1); - return; - } - - if (_memicmp(Cmd, "UH", 2) == 0 && conn->sysop) - { - DoUnholdCommand(conn, user, Cmd, Arg1, Context); - SendPrompt(conn, user); - return; - } - - if (_stricmp(Cmd, "IMPORT") == 0) - { - DoImportCmd(conn, user, Arg1, Context); - return; - } - - if (_stricmp(Cmd, "EXPORT") == 0) - { - DoExportCmd(conn, user, Arg1, Context); - return; - } - - if (_memicmp(Cmd, "I", 1) == 0) - { - char * Save; - char * MsgBytes; - - if (Arg1) - { - // User WP lookup - - DoWPLookup(conn, user, Cmd[1], Arg1); - SendPrompt(conn, user); - return; - } - - - MsgBytes = Save = ReadInfoFile("info.txt"); - if (MsgBytes) - { - int Length; - - // Remove lf chars - - Length = RemoveLF(MsgBytes, (int)strlen(MsgBytes)); - - QueueMsg(conn, MsgBytes, Length); - free(Save); - } - else - BBSputs(conn, "SYSOP has not created an INFO file\r"); - - - SendPrompt(conn, user); - return; - } - - - if (_memicmp(Cmd, "Name", CmdLen) == 0) - { - if (Arg1) - { - if (strlen(Arg1) > 17) - Arg1[17] = 0; - - strcpy(user->Name, Arg1); - UpdateWPWithUserInfo(user); - - } - - SendWelcomeMsg(conn->BPQStream, conn, user); - SaveUserDatabase(); - - return; - } - - if (_memicmp(Cmd, "OP", 2) == 0) - { - int Lines; - - // Paging Control. Param is number of lines per page - - if (Arg1) - { - Lines = atoi(Arg1); - - if (Lines) // Sanity Check - { - if (Lines < 10) - { - nodeprintf(conn,"Page Length %d is too short\r", Lines); - SendPrompt(conn, user); - return; - } - } - - user->PageLen = Lines; - conn->PageLen = Lines; - conn->Paging = (Lines > 0); - SaveUserDatabase(); - } - - nodeprintf(conn,"Page Length is %d\r", user->PageLen); - SendPrompt(conn, user); - - return; - } - - if (_memicmp(Cmd, "QTH", CmdLen) == 0) - { - if (Arg1) - { - // QTH may contain spaces, so put back together, and just split at cr - - Arg1[strlen(Arg1)] = ' '; - strtok_s(Arg1, "\r", &Context); - - if (strlen(Arg1) > 60) - Arg1[60] = 0; - - strcpy(user->Address, Arg1); - UpdateWPWithUserInfo(user); - - } - - nodeprintf(conn,"QTH is %s\r", user->Address); - SendPrompt(conn, user); - - SaveUserDatabase(); - - return; - } - - if (_memicmp(Cmd, "ZIP", CmdLen) == 0) - { - if (Arg1) - { - if (strlen(Arg1) > 8) - Arg1[8] = 0; - - strcpy(user->ZIP, _strupr(Arg1)); - UpdateWPWithUserInfo(user); - } - - nodeprintf(conn,"ZIP is %s\r", user->ZIP); - SendPrompt(conn, user); - - SaveUserDatabase(); - - return; - } - - if (_memicmp(Cmd, "CMSPASS", 7) == 0) - { - if (Arg1 == 0) - { - nodeprintf(conn,"Must specify a password\r"); - } - else - { - if (strlen(Arg1) > 15) - Arg1[15] = 0; - - strcpy(user->CMSPass, Arg1); - nodeprintf(conn,"CMS Password Set\r"); - SaveUserDatabase(); - } - - SendPrompt(conn, user); - - return; - } - - if (_memicmp(Cmd, "PASS", CmdLen) == 0) - { - if (Arg1 == 0) - { - nodeprintf(conn,"Must specify a password\r"); - } - else - { - if (strlen(Arg1) > 12) - Arg1[12] = 0; - - strcpy(user->pass, Arg1); - nodeprintf(conn,"BBS Password Set\r"); - SaveUserDatabase(); - } - - SendPrompt(conn, user); - - return; - } - - - if (_memicmp(Cmd, "R", 1) == 0) - { - DoReadCommand(conn, user, Cmd, Arg1, Context); - SendPrompt(conn, user); - return; - } - - if (_memicmp(Cmd, "S", 1) == 0) - { - if (!DoSendCommand(conn, user, Cmd, Arg1, Context)) - SendPrompt(conn, user); - return; - } - - if ((_memicmp(Cmd, "Help", CmdLen) == 0) || (_memicmp(Cmd, "?", 1) == 0)) - { - char * Save; - char * MsgBytes = Save = ReadInfoFile("help.txt"); - - if (MsgBytes) - { - int Length; - - // Remove lf chars - - Length = RemoveLF(MsgBytes, (int)strlen(MsgBytes)); - - QueueMsg(conn, MsgBytes, Length); - free(Save); - } - else - { - BBSputs(conn, "A - Abort Output\r"); - BBSputs(conn, "B - Logoff\r"); - BBSputs(conn, "CMSPASS Password - Set CMS Password\r"); - BBSputs(conn, "D - Flag NTS Message(s) as Delivered - D num\r"); - BBSputs(conn, "HOMEBBS - Display or get HomeBBS\r"); - BBSputs(conn, "INFO - Display information about this BBS\r"); - BBSputs(conn, "I CALL - Lookup CALL in WP Allows *CALL CALL* *CALL* wildcards\r"); - BBSputs(conn, "I@ PARAM - Lookup @BBS in WP\r"); - BBSputs(conn, "IZ PARAM - Lookup Zip Codes in WP\r"); - BBSputs(conn, "IH PARAM - Lookup HA elements in WP - eg USA EU etc\r"); - - BBSputs(conn, "K - Kill Message(s) - K num, KM (Kill my read messages)\r"); - BBSputs(conn, "L - List Message(s) - \r"); - BBSputs(conn, " L = List New, LR = List New (Oldest first)\r"); - BBSputs(conn, " LM = List Mine, L> Call, L< Call, L@ = List to, from or at\r"); - BBSputs(conn, " LL num = List msg num, L num-num = List Range\r"); - BBSputs(conn, " LN LY LH LK LF L$ LD = List Message with corresponding Status\r"); - BBSputs(conn, " LB LP LT = List Mesaage with corresponding Type\r"); - BBSputs(conn, " LC = List TO fields of all active bulletins\r"); - BBSputs(conn, " You can combine most selections eg LMP, LMN LB< G8BPQ\r"); - BBSputs(conn, "LISTFILES or FILES - List files available for download\r"); - - BBSputs(conn, "N Name - Set Name\r"); - BBSputs(conn, "NODE - Return to Node\r"); - BBSputs(conn, "OP n - Set Page Length (Output will pause every n lines)\r"); - BBSputs(conn, "PASS Password - Set BBS Password\r"); - BBSputs(conn, "POLLRMS - Manage Polling for messages from RMS \r"); - BBSputs(conn, "Q QTH - Set QTH\r"); - BBSputs(conn, "R - Read Message(s) - R num \r"); - BBSputs(conn, " RM (Read new messages to me), RMR (RM oldest first)\r"); - BBSputs(conn, "READ Name - Read File\r"); - - BBSputs(conn, "S - Send Message - S or SP Send Personal, SB Send Bull, ST Send NTS,\r"); - BBSputs(conn, " SR Num - Send Reply, SC Num - Send Copy\r"); - BBSputs(conn, "X - Toggle Expert Mode\r"); - BBSputs(conn, "YAPP - Download file from BBS using YAPP protocol\r"); - if (conn->sysop) - { - BBSputs(conn, "DOHOUSEKEEPING - Run Housekeeping process\r"); - BBSputs(conn, "EU - Edit User Flags - Type EU for Help\r"); - BBSputs(conn, "EXPORT - Export messages to file - Type EXPORT for Help\r"); - BBSputs(conn, "FWD - Control Forwarding - Type FWD for Help\r"); - BBSputs(conn, "IMPORT - Import messages from file - Type IMPORT for Help\r"); - BBSputs(conn, "REROUTEMSGS - Rerun message routing process\r"); - BBSputs(conn, "SETNEXTMESSAGENUMBER - Sets next message number\r"); - BBSputs(conn, "SHOWRMSPOLL - Displays your RMS polling list\r"); - BBSputs(conn, "UH - Unhold Message(s) - UH ALL or UH num num num...\r"); - } - } - - SendPrompt(conn, user); - return; - } - - if (_memicmp(Cmd, "Ver", CmdLen) == 0) - { - nodeprintf(conn, "BBS Version %s\rNode Version %s\r", VersionStringWithBuild, GetVersionString()); - - SendPrompt(conn, user); - return; - } - - if (_memicmp(Cmd, "HOMEBBS", CmdLen) == 0) - { - if (Arg1) - { - if (strlen(Arg1) > 40) Arg1[40] = 0; - - strcpy(user->HomeBBS, _strupr(Arg1)); - UpdateWPWithUserInfo(user); - - if (!strchr(Arg1, '.')) - BBSputs(conn, "Please enter HA with HomeBBS eg g8bpq.gbr.eu - this will help message routing\r"); - } - - nodeprintf(conn,"HomeBBS is %s\r", user->HomeBBS); - SendPrompt(conn, user); - - SaveUserDatabase(); - - return; - } - - if ((_memicmp(Cmd, "EDITUSER", 5) == 0) || (_memicmp(Cmd, "EU", 2) == 0)) - { - DoEditUserCmd(conn, user, Arg1, Context); - return; - } - - if (_stricmp(Cmd, "POLLRMS") == 0) - { - DoPollRMSCmd(conn, user, Arg1, Context); - return; - } - - if (_stricmp(Cmd, "DOHOUSEKEEPING") == 0) - { - DoHousekeepingCmd(conn, user, Arg1, Context); - return; - } - - - if (_stricmp(Cmd, "FWD") == 0) - { - DoFwdCmd(conn, user, Arg1, Context); - return; - } - - if (_memicmp(Cmd, "X", 1) == 0) - { - user->flags ^= F_Expert; - - if (user->flags & F_Expert) - BBSputs(conn, "Expert Mode\r"); - else - BBSputs(conn, "Expert Mode off\r"); - - SaveUserDatabase(); - SendPrompt(conn, user); - return; - } - - if (conn->Flags == 0) - { - if (!CheckForTooManyErrors(conn)) - BBSputs(conn, "Invalid Command\r"); - - SendPrompt(conn, user); - } - - // Send if possible - - Flush(conn); -} - -VOID __cdecl nprintf(CIRCUIT * conn, const char * format, ...) -{ - // seems to be printf to a socket - - char buff[600]; - va_list(arglist); - - va_start(arglist, format); - vsprintf(buff, format, arglist); - - BBSputs(conn, buff); -} - -// Code to delete obsolete files from Mail folder - -#ifdef WIN32 - -int DeleteRedundantMessages() -{ - WIN32_FIND_DATA ffd; - - char szDir[MAX_PATH]; - char File[MAX_PATH]; - HANDLE hFind = INVALID_HANDLE_VALUE; - int Msgno; - - // Prepare string for use with FindFile functions. First, copy the - // string to a buffer, then append '\*' to the directory name. - - strcpy(szDir, MailDir); - strcat(szDir, "\\*.mes"); - - - - // Find the first file in the directory. - - hFind = FindFirstFile(szDir, &ffd); - - if (INVALID_HANDLE_VALUE == hFind) - { - return 0; - } - - do - { - if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - { - OutputDebugString(ffd.cFileName); - } - else - { - Msgno = atoi(&ffd.cFileName[2]); - - if (MsgnotoMsg[Msgno] == 0) - { - sprintf(File, "%s/%s%c", MailDir, ffd.cFileName, 0); - Debugprintf("Tidy Mail - Delete %s\n", File); - -// if (DeletetoRecycleBin) - DeletetoRecycle(File); -// else -// DeleteFile(File); - } - } - } - while (FindNextFile(hFind, &ffd) != 0); - - FindClose(hFind); - return 0; -} - -#else - -#include - -int MsgFilter(const struct dirent * dir) -{ - return (strstr(dir->d_name, ".mes") != 0); -} - -int DeleteRedundantMessages() -{ - struct dirent **namelist; - int n; - struct stat STAT; - int Msgno = 0, res; - char File[100]; - - n = scandir("Mail", &namelist, MsgFilter, alphasort); - - if (n < 0) - perror("scandir"); - else - { - while(n--) - { - if (stat(namelist[n]->d_name, &STAT) == 0); - { - Msgno = atoi(&namelist[n]->d_name[2]); - - if (MsgnotoMsg[Msgno] == 0) - { - sprintf(File, "Mail/%s", namelist[n]->d_name); - printf("Deleting %s\n", File); - unlink(File); - } - } - free(namelist[n]); - } - free(namelist); - } - return 0; -} -#endif - -VOID TidyWelcomeMsg(char ** pPrompt) -{ - // Make sure Welcome Message doesn't ends with > - - char * Prompt = *pPrompt; - - int i = (int)strlen(Prompt) - 1; - - *pPrompt = realloc(Prompt, i + 5); // In case we need to expand it - - Prompt = *pPrompt; - - while (Prompt[i] == 10 || Prompt[i] == 13) - { - Prompt[i--] = 0; - } - - while (i >= 0 && Prompt[i] == '>') - Prompt[i--] = 0; - - strcat(Prompt, "\r\n"); -} - -VOID TidyPrompt(char ** pPrompt) -{ - // Make sure prompt ends > CR LF - - char * Prompt = *pPrompt; - - int i = (int)strlen(Prompt) - 1; - - *pPrompt = realloc(Prompt, i + 5); // In case we need to expand it - - Prompt = *pPrompt; - - while (Prompt[i] == 10 || Prompt[i] == 13) - { - Prompt[i--] = 0; - } - - if (Prompt[i] != '>') - strcat(Prompt, ">"); - - strcat(Prompt, "\r\n"); -} - -VOID TidyPrompts() -{ - TidyPrompt(&Prompt); - TidyPrompt(&NewPrompt); - TidyPrompt(&ExpertPrompt); -} - -BOOL SendARQMail(CIRCUIT * conn) -{ - conn->NextMessagetoForward = FirstMessageIndextoForward; - - // Send Message. There is no mechanism for reverse forwarding - - if (FindMessagestoForward(conn)) - { - struct MsgInfo * Msg; - char MsgHddr[512]; - int HddrLen; - char TimeString[64]; - char * WholeMessage; - - char * MsgBytes = ReadMessageFile(conn->FwdMsg->number); - int MsgLen; - - if (MsgBytes == 0) - { - MsgBytes = _strdup("Message file not found\r"); - conn->FwdMsg->length = (int)strlen(MsgBytes); - } - - Msg = conn->FwdMsg; - WholeMessage = malloc(Msg->length + 512); - - FormatTime(TimeString, (time_t)Msg->datecreated); - -/* -ARQ:FILE::flarqmail-1.eml -ARQ:EMAIL:: -ARQ:SIZE::96 -ARQ::STX -//FLARQ COMPOSER -Date: 16/01/2014 22:26:06 -To: g8bpq -From: -Subject: test message - -Hello -Hello - -ARQ::ETX -*/ - Logprintf(LOG_BBS, conn, '>', "ARQ Send Msg %d From %s To %s", Msg->number, Msg->from, Msg->to); - - HddrLen = sprintf(MsgHddr, "Date: %s\nTo: %s\nFrom: %s\nSubject %s\n\n", - TimeString, Msg->to, Msg->from, Msg->title); - - MsgLen = sprintf(WholeMessage, "ARQ:FILE::Msg%s_%d\nARQ:EMAIL::\nARQ:SIZE::%d\nARQ::STX\n%s%s\nARQ::ETX\n", - BBSName, Msg->number, (int)(HddrLen + strlen(MsgBytes)), MsgHddr, MsgBytes); - - WholeMessage[MsgLen] = 0; - QueueMsg(conn,WholeMessage, MsgLen); - - free(WholeMessage); - free(MsgBytes); - - // FLARQ doesn't ACK the message, so set flag to look for all acked - - conn->BBSFlags |= ARQMAILACK; - conn->ARQClearCount = 10; // To make sure clear isn't reported too soon - - return TRUE; - } - - // Nothing to send - close - - Logprintf(LOG_BBS, conn, '>', "ARQ Send - Nothing to Send - Closing"); - - conn->CloseAfterFlush = 20; - return FALSE; -} - -char *stristr (char *ch1, char *ch2) -{ - char *chN1, *chN2; - char *chNdx; - char *chRet = NULL; - - chN1 = _strdup (ch1); - chN2 = _strdup (ch2); - if (chN1 && chN2) - { - chNdx = chN1; - while (*chNdx) - { - *chNdx = (char) tolower (*chNdx); - chNdx ++; - } - chNdx = chN2; - while (*chNdx) - { - *chNdx = (char) tolower (*chNdx); - chNdx ++; - } - - chNdx = strstr (chN1, chN2); - if (chNdx) - chRet = ch1 + (chNdx - chN1); - } - free (chN1); - free (chN2); - return chRet; -} - -#ifdef WIN32 - -void ListFiles(ConnectionInfo * conn, struct UserInfo * user, char * filename) -{ - - WIN32_FIND_DATA ffd; - - char szDir[MAX_PATH]; - HANDLE hFind = INVALID_HANDLE_VALUE; - - // Prepare string for use with FindFile functions. First, copy the - // string to a buffer, then append '\*' to the directory name. - - strcpy(szDir, GetBPQDirectory()); - strcat(szDir, "\\BPQMailChat\\Files\\*.*"); - - // Find the first file in the directory. - - hFind = FindFirstFile(szDir, &ffd); - - if (INVALID_HANDLE_VALUE == hFind) - { - nodeprintf(conn, "No Files\r"); - return; - } - - // List all the files in the directory with some info about them. - - do - { - if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - {} - else - { - if (filename == NULL || stristr(ffd.cFileName, filename)) - nodeprintf(conn, "%s %d\r", ffd.cFileName, ffd.nFileSizeLow); - } - } - while (FindNextFile(hFind, &ffd) != 0); - - FindClose(hFind); -} - -#else - -#include - -void ListFiles(ConnectionInfo * conn, struct UserInfo * user, char * filename) -{ - struct dirent **namelist; - int n, i; - struct stat STAT; - time_t now = time(NULL); - int Age = 0, res; - char FN[256]; - - n = scandir("Files", &namelist, NULL, alphasort); - - if (n < 0) - perror("scandir"); - else - { - for (i = 0; i < n; i++) - { - sprintf(FN, "Files/%s", namelist[i]->d_name); - - if (filename == NULL || stristr(namelist[i]->d_name, filename)) - if (FN[6] != '.' && stat(FN, &STAT) == 0) - nodeprintf(conn, "%s %d\r", namelist[i]->d_name, STAT.st_size); - - free(namelist[i]); - } - free(namelist); - } - return; -} -#endif - -void ReadBBSFile(ConnectionInfo * conn, struct UserInfo * user, char * filename) -{ - char * MsgBytes; - - int FileSize; - char MsgFile[MAX_PATH]; - FILE * hFile; - struct stat STAT; - - if (filename == NULL) - { - nodeprintf(conn, "Missing Filename\r"); - return; - } - - if (strstr(filename, "..") || strchr(filename, '/') || strchr(filename, '\\')) - { - nodeprintf(conn, "Invalid filename\r"); - return; - } - - if (BaseDir[0]) - sprintf_s(MsgFile, sizeof(MsgFile), "%s/Files/%s", BaseDir, filename); - else - sprintf_s(MsgFile, sizeof(MsgFile), "Files/%s", filename); - - if (stat(MsgFile, &STAT) != -1) - { - FileSize = STAT.st_size; - - hFile = fopen(MsgFile, "rb"); - - if (hFile) - { - int Length; - - MsgBytes=malloc(FileSize+1); - fread(MsgBytes, 1, FileSize, hFile); - fclose(hFile); - - MsgBytes[FileSize]=0; - - // Remove lf chars - - Length = RemoveLF(MsgBytes, (int)strlen(MsgBytes)); - - QueueMsg(conn, MsgBytes, Length); - free(MsgBytes); - - nodeprintf(conn, "\r\r[End of File %s]\r", filename); - return; - } - } - - nodeprintf(conn, "File %s not found\r", filename); -} - -VOID ProcessSuspendedListCommand(CIRCUIT * conn, struct UserInfo * user, char* Buffer, int len) -{ - struct TempUserInfo * Temp = user->Temp; - - Buffer[len] = 0; - - // Command entered during listing pause. May be A R or C (or ) - - if (Buffer[0] == 'A' || Buffer[0] == 'a') - { - // Abort - - Temp->ListActive = Temp->ListSuspended = FALSE; - SendPrompt(conn, user); - return; - } - - if (_memicmp(Buffer, "R ", 2) == 0) - { - // Read Message(es) - - int msgno; - char * ptr; - char * Context; - - ptr = strtok_s(&Buffer[2], " ", &Context); - - while (ptr) - { - msgno = atoi(ptr); - ReadMessage(conn, user, msgno); - - ptr = strtok_s(NULL, " ", &Context); - } - - nodeprintf(conn, "bort, , = Continue..>"); - return; - } - - if (Buffer[0] == 'C' || Buffer[0] == 'c' || Buffer[0] == '\r' ) - { - // Resume Listing from where we left off - - DoListCommand(conn, user, Temp->LastListCommand, Temp->LastListParams, TRUE, ""); - SendPrompt(conn, user); - return; - } - - nodeprintf(conn, "bort, , = Continue..>"); - -} -/* -CreateMessageWithAttachments() -{ - int i; - char * ptr, * ptr2, * ptr3, * ptr4; - char Boundary[1000]; - BOOL Multipart = FALSE; - BOOL ALT = FALSE; - int Partlen; - char * Save; - BOOL Base64 = FALSE; - BOOL QuotedP = FALSE; - - char FileName[100][250] = {""}; - int FileLen[100]; - char * FileBody[100]; - char * MallocSave[100]; - UCHAR * NewMsg; - - int Files = 0; - - ptr = Msg; - - if ((sockptr->MailSize + 2000) > sockptr->MailBufferSize) - { - sockptr->MailBufferSize += 2000; - sockptr->MailBuffer = realloc(sockptr->MailBuffer, sockptr->MailBufferSize); - - if (sockptr->MailBuffer == NULL) - { - CriticalErrorHandler("Failed to extend Message Buffer"); - shutdown(sockptr->socket, 0); - return FALSE; - } - } - - - NewMsg = sockptr->MailBuffer + 1000; - - NewMsg += sprintf(NewMsg, "Body: %d\r\n", FileLen[0]); - - for (i = 1; i < Files; i++) - { - NewMsg += sprintf(NewMsg, "File: %d %s\r\n", FileLen[i], FileName[i]); - } - - NewMsg += sprintf(NewMsg, "\r\n"); - - for (i = 0; i < Files; i++) - { - memcpy(NewMsg, FileBody[i], FileLen[i]); - NewMsg += FileLen[i]; - free(MallocSave[i]); - NewMsg += sprintf(NewMsg, "\r\n"); - } - - *MsgLen = NewMsg - (sockptr->MailBuffer + 1000); - *Body = sockptr->MailBuffer + 1000; - - return TRUE; // B2 Message -} - -*/ -VOID CreateUserReport() -{ - struct UserInfo * User; - int i; - char Line[200]; - int len; - char File[MAX_PATH]; - FILE * hFile; - - sprintf(File, "%s/UserList.csv", BaseDir); - - hFile = fopen(File, "wb"); - - if (hFile == NULL) - { - Debugprintf("Failed to create UserList.csv"); - return; - } - - for (i=1; i <= NumberofUsers; i++) - { - User = UserRecPtr[i]; - - len = sprintf(Line, "%s,%d,%s,%x,%s,\"%s\",%x,%s,%s,%s\r\n", - User->Call, - User->lastmsg, - FormatDateAndTime((time_t)User->TimeLastConnected, FALSE), - User->flags, - User->Name, - User->Address, - User->RMSSSIDBits, - User->HomeBBS, - User->QRA, - User->ZIP -// struct MsgStats Total; -// struct MsgStats Last; - ); - fwrite(Line, 1, len, hFile); - } - - fclose(hFile); -} - -BOOL ProcessYAPPMessage(CIRCUIT * conn) -{ - int Len = conn->InputLen; - UCHAR * Msg = conn->InputBuffer; - int pktLen = Msg[1]; - char Reply[2] = {ACK}; - int NameLen, SizeLen, OptLen; - char * ptr; - int FileSize; - char MsgFile[MAX_PATH]; - FILE * hFile; - char Mess[255]; - int len; - char * FN = &Msg[2]; - - switch (Msg[0]) - { - case ENQ: // YAPP Send_Init - - // Shouldn't occur in session. Reset state - - Mess[0] = ACK; - Mess[1] = 1; - QueueMsg(conn, Mess, 2); - Flush(conn); - conn->InputLen = 0; - if (conn->MailBuffer) - { - free(conn->MailBuffer); - conn->MailBufferSize=0; - conn->MailBuffer=0; - } - return TRUE; - - case SOH: - - // HD Send_Hdr SOH len (Filename) NUL (File Size in ASCII) NUL (Opt) - - // YAPPC has date/time in dos format - - if (Len < Msg[1] + 1) - return 0; - - NameLen = (int)strlen(FN); - strcpy(conn->ARQFilename, FN); - ptr = &Msg[3 + NameLen]; - SizeLen = (int)strlen(ptr); - FileSize = atoi(ptr); - - // Check file name for unsafe characters (.. / \) - - if (strstr(FN, "..") || strchr(FN, '/') || strchr(FN, '\\')) - { - Mess[0] = NAK; - Mess[1] = 0; - QueueMsg(conn, Mess, 2); - Flush(conn); - len = sprintf_s(Mess, sizeof(Mess), "YAPP File Name %s invalid\r", FN); - QueueMsg(conn, Mess, len); - SendPrompt(conn, conn->UserPointer); - WriteLogLine(conn, '!', Mess, len - 1, LOG_BBS); - - conn->InputLen = 0; - conn->InputMode = 0; - - return FALSE; - } - - OptLen = pktLen - (NameLen + SizeLen + 2); - - conn->YAPPDate = 0; - - if (OptLen >= 8) // We have a Date/Time for YAPPC - { - ptr = ptr + SizeLen + 1; - conn->YAPPDate = strtol(ptr, NULL, 16); - } - - // Check Size - - if (FileSize > MaxRXSize) - { - Mess[0] = NAK; - Mess[1] = sprintf(&Mess[2], "YAPP File %s size %d larger than limit %d\r", conn->ARQFilename, FileSize, MaxRXSize); - QueueMsg(conn, Mess, Mess[1] + 2); - - Flush(conn); - - len = sprintf_s(Mess, sizeof(Mess), "YAPP File %s size %d larger than limit %d\r", conn->ARQFilename, FileSize, MaxRXSize); - QueueMsg(conn, Mess, len); - SendPrompt(conn, conn->UserPointer); - WriteLogLine(conn, '!', Mess, len - 1, LOG_BBS); - - conn->InputLen = 0; - conn->InputMode = 0; - - return FALSE; - } - - // Make sure file does not exist - - - sprintf_s(MsgFile, sizeof(MsgFile), "%s/Files/%s", BaseDir, conn->ARQFilename); - - hFile = fopen(MsgFile, "rb"); - - if (hFile) - { - Mess[0] = NAK; - Mess[1] = sprintf(&Mess[2], "YAPP File %s already exists\r", conn->ARQFilename);; - QueueMsg(conn, Mess, Mess[1] + 2); - - Flush(conn); - - len = sprintf_s(Mess, sizeof(Mess), "YAPP File %s already exists\r", conn->ARQFilename); - QueueMsg(conn, Mess, len); - SendPrompt(conn, conn->UserPointer); - WriteLogLine(conn, '!', Mess, len - 1, LOG_BBS); - fclose(hFile); - - conn->InputLen = 0; - conn->InputMode = 0; - - return FALSE; - } - - - conn->MailBufferSize = FileSize; - conn->MailBuffer=malloc(FileSize); - conn->YAPPLen = 0; - - if (conn->YAPPDate) // If present use YAPPC - Reply[1] = ACK; //Receive_TPK - else - Reply[1] = 2; //Rcv_File - - QueueMsg(conn, Reply, 2); - - len = sprintf_s(Mess, sizeof(Mess), "YAPP upload to %s started", conn->ARQFilename); - WriteLogLine(conn, '!', Mess, len, LOG_BBS); - - conn->InputLen = 0; - return FALSE; - - case STX: - - // Data Packet - - // Check we have it all - - if (conn->YAPPDate) // If present use YAPPC so have checksum - { - if (pktLen > (Len - 3)) // -3 for header and checksum - return 0; // Wait for rest - } - else - { - if (pktLen > (Len - 2)) // -2 for header - return 0; // Wait for rest - } - - // Save data and remove from buffer - - // if YAPPC check checksum - - if (conn->YAPPDate) - { - UCHAR Sum = 0; - int i; - UCHAR * uptr = &Msg[2]; - - i = pktLen; - - while(i--) - Sum += *(uptr++); - - if (Sum != *uptr) - { - // Checksum Error - - Mess[0] = CAN; - Mess[1] = 0; - QueueMsg(conn, Mess, 2); - Flush(conn); - len = sprintf_s(Mess, sizeof(Mess), "YAPPC Checksum Error\r"); - QueueMsg(conn, Mess, len); - WriteLogLine(conn, '!', Mess, len - 1, LOG_BBS); - conn->InputLen = 0; - conn->InputMode = 0; - return TRUE; - } - } - - if ((conn->YAPPLen) + pktLen > conn->MailBufferSize) - { - // Too Big ?? - - Mess[0] = CAN; - Mess[1] = 0; - QueueMsg(conn, Mess, 2); - Flush(conn); - len = sprintf_s(Mess, sizeof(Mess), "YAPP Too much data received\r"); - QueueMsg(conn, Mess, len); - WriteLogLine(conn, '!', Mess, len - 1, LOG_BBS); - conn->InputLen = 0; - conn->InputMode = 0; - return TRUE; - } - - - memcpy(&conn->MailBuffer[conn->YAPPLen], &Msg[2], pktLen); - conn->YAPPLen += pktLen; - - if (conn->YAPPDate) - ++pktLen; // Add Checksum - - conn->InputLen -= (pktLen + 2); - memmove(conn->InputBuffer, &conn->InputBuffer[pktLen + 2], conn->InputLen); - - return TRUE; - - case ETX: - - // End Data - - - - if (conn->YAPPLen == conn->MailBufferSize) - { - // All received - - int ret; - DWORD Written = 0; - - sprintf_s(MsgFile, sizeof(MsgFile), "%s/Files/%s", BaseDir, conn->ARQFilename); - -#ifdef WIN32 - hFile = CreateFile(MsgFile, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - - if((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE)) - { - ret = WriteFile(hFile, conn->MailBuffer, conn->YAPPLen, &Written, NULL); - - if (conn->YAPPDate) - { - FILETIME FileTime; - struct tm TM; - struct timeval times[2]; - time_t TT; -/* - The MS-DOS date. The date is a packed value with the following format. - - cant use DosDateTimeToFileTime on Linux - - Bits Description - 0-4 Day of the month (1–31) - 5-8 Month (1 = January, 2 = February, and so on) - 9-15 Year offset from 1980 (add 1980 to get actual year) - wFatTime - The MS-DOS time. The time is a packed value with the following format. - Bits Description - 0-4 Second divided by 2 - 5-10 Minute (0–59) - 11-15 Hour (0–23 on a 24-hour clock) -*/ - memset(&TM, 0, sizeof(TM)); - - TM.tm_sec = (conn->YAPPDate & 0x1f) << 1; - TM.tm_min = ((conn->YAPPDate >> 5) & 0x3f); - TM.tm_hour = ((conn->YAPPDate >> 11) & 0x1f); - - TM.tm_mday = ((conn->YAPPDate >> 16) & 0x1f); - TM.tm_mon = ((conn->YAPPDate >> 21) & 0xf) - 1; - TM.tm_year = ((conn->YAPPDate >> 25) & 0x7f) + 80; - - Debugprintf("%d %d %d %d %d %d", TM.tm_year, TM.tm_mon, TM.tm_mday, TM.tm_hour, TM.tm_min, TM.tm_sec); - - TT = mktime(&TM); - times[0].tv_sec = times[1].tv_sec = - times[0].tv_usec = times[1].tv_usec = 0; - - DosDateTimeToFileTime((WORD)(conn->YAPPDate >> 16), (WORD)conn->YAPPDate & 0xFFFF, &FileTime); - ret = SetFileTime(hFile, &FileTime, &FileTime, &FileTime); - ret = GetLastError(); - - } - CloseHandle(hFile); - } -#else - - hFile = fopen(MsgFile, "wb"); - if (hFile) - { - Written = fwrite(conn->MailBuffer, 1, conn->YAPPLen, hFile); - fclose(hFile); - - if (conn->YAPPDate) - { - struct tm TM; - struct timeval times[2]; -/* - The MS-DOS date. The date is a packed value with the following format. - - cant use DosDateTimeToFileTime on Linux - - Bits Description - 0-4 Day of the month (1–31) - 5-8 Month (1 = January, 2 = February, and so on) - 9-15 Year offset from 1980 (add 1980 to get actual year) - wFatTime - The MS-DOS time. The time is a packed value with the following format. - Bits Description - 0-4 Second divided by 2 - 5-10 Minute (0–59) - 11-15 Hour (0–23 on a 24-hour clock) -*/ - memset(&TM, 0, sizeof(TM)); - - TM.tm_sec = (conn->YAPPDate & 0x1f) << 1; - TM.tm_min = ((conn->YAPPDate >> 5) & 0x3f); - TM.tm_hour = ((conn->YAPPDate >> 11) & 0x1f); - - TM.tm_mday = ((conn->YAPPDate >> 16) & 0x1f); - TM.tm_mon = ((conn->YAPPDate >> 21) & 0xf) - 1; - TM.tm_year = ((conn->YAPPDate >> 25) & 0x7f) + 80; - - Debugprintf("%d %d %d %d %d %d", TM.tm_year, TM.tm_mon, TM.tm_mday, TM.tm_hour, TM.tm_min, TM.tm_sec); - - times[0].tv_sec = times[1].tv_sec = mktime(&TM); - times[0].tv_usec = times[1].tv_usec = 0; - } - } -#endif - - free(conn->MailBuffer); - conn->MailBufferSize=0; - conn->MailBuffer=0; - - if (Written != conn->YAPPLen) - { - Mess[0] = CAN; - Mess[1] = 0; - QueueMsg(conn, Mess, 2); - Flush(conn); - len = sprintf_s(Mess, sizeof(Mess), "Failed to save YAPP File\r"); - QueueMsg(conn, Mess, len); - WriteLogLine(conn, '!', Mess, len - 1, LOG_BBS); - conn->InputLen = 0; - conn->InputMode = 0; - } - } - - Reply[1] = 3; //Ack_EOF - QueueMsg(conn, Reply, 2); - Flush(conn); - conn->InputLen = 0; - - return TRUE; - - case EOT: - - // End Session - - Reply[1] = 4; // Ack_EOT - QueueMsg(conn, Reply, 2); - Flush(conn); - conn->InputLen = 0; - conn->InputMode = 0; - - len = sprintf_s(Mess, sizeof(Mess), "YAPP file %s received\r", conn->ARQFilename); - WriteLogLine(conn, '!', Mess, len - 1, LOG_BBS); - QueueMsg(conn, Mess, len); - SendPrompt(conn, conn->UserPointer); - - return TRUE; - - case CAN: - - // Abort - - Mess[0] = ACK; - Mess[1] = 5; // CAN Ack - QueueMsg(conn, Mess, 2); - Flush(conn); - - if (conn->MailBuffer) - { - free(conn->MailBuffer); - conn->MailBufferSize=0; - conn->MailBuffer=0; - } - - // There may be a reason after the CAN - - len = Msg[1]; - - if (len) - { - char * errormsg = &Msg[2]; - errormsg[len] = 0; - nodeprintf(conn, "File Rejected - %s\r", errormsg); - } - else - - nodeprintf(conn, "File Rejected\r"); - - - len = sprintf_s(Mess, sizeof(Mess), "YAPP Transfer cancelled by Terminal\r"); - WriteLogLine(conn, '!', Mess, len - 1, LOG_BBS); - - conn->InputLen = 0; - conn->InputMode = 0; - conn->BBSFlags &= ~YAPPTX; - - return FALSE; - - case ACK: - - switch (Msg[1]) - { - case 1: // Rcv_Rdy - - // HD Send_Hdr SOH len (Filename) NUL (File Size in ASCII) NUL (Opt) - - len = (int)strlen(conn->ARQFilename) + 3; - - strcpy(&Mess[2], conn->ARQFilename); - len += sprintf(&Mess[len], "%d", conn->MailBufferSize); - len++; // include null - Mess[0] = SOH; - Mess[1] = len - 2; - - QueueMsg(conn, Mess, len); - Flush(conn); - conn->InputLen = 0; - - return FALSE; - - case 2: - - // Start sending message - - YAPPSendData(conn); - conn->InputLen = 0; - return FALSE; - - case 3: - - // ACK EOF - Send EOT - - - Mess[0] = EOT; - Mess[1] = 1; - QueueMsg(conn, Mess, 2); - Flush(conn); - - conn->InputLen = 0; - return FALSE; - - case 4: - - // ACK EOT - - conn->InputMode = 0; - conn->BBSFlags &= ~YAPPTX; - - conn->InputLen = 0; - return FALSE; - - default: - conn->InputLen = 0; - return FALSE; - - - - } - - case NAK: - - // Either Reject or Restart - - // RE Resume NAK len R NULL (File size in ASCII) NULL - - if (conn->InputLen > 2 && Msg[2] == 'R' && Msg[3] == 0) - { - int posn = atoi(&Msg[4]); - - conn->YAPPLen += posn; - conn->MailBufferSize -= posn; - - YAPPSendData(conn); - conn->InputLen = 0; - return FALSE; - - } - - // There may be a reason after the ack - - len = Msg[1]; - - if (len) - { - char * errormsg = &Msg[2]; - errormsg[len] = 0; - nodeprintf(conn, "File Rejected - %s\r", errormsg); - } - else - - nodeprintf(conn, "File Rejected\r"); - - conn->InputMode = 0; - conn->BBSFlags &= ~YAPPTX; - conn->InputLen = 0; - SendPrompt(conn, conn->UserPointer); - return FALSE; - } - - nodeprintf(conn, "Unexpected message during YAPP Transfer. Transfer canncelled\r"); - - conn->InputMode = 0; - conn->BBSFlags &= ~YAPPTX; - conn->InputLen = 0; - SendPrompt(conn, conn->UserPointer); - - return FALSE; - -} - -void YAPPSendFile(ConnectionInfo * conn, struct UserInfo * user, char * filename) -{ - int FileSize; - char MsgFile[MAX_PATH]; - FILE * hFile; - struct stat STAT; - - if (filename == NULL) - { - nodeprintf(conn, "Filename missing\r"); - SendPrompt(conn, user); - return; - } - - if (strstr(filename, "..") || strchr(filename, '/') || strchr(filename, '\\')) - { - nodeprintf(conn, "Invalid filename\r"); - SendPrompt(conn, user); - return; - } - - if (BaseDir[0]) - sprintf_s(MsgFile, sizeof(MsgFile), "%s/Files/%s", BaseDir, filename); - else - sprintf_s(MsgFile, sizeof(MsgFile), "Files/%s", filename); - - if (stat(MsgFile, &STAT) != -1) - { - FileSize = STAT.st_size; - - hFile = fopen(MsgFile, "rb"); - - if (hFile) - { - char Mess[255]; - strcpy(conn->ARQFilename, filename); - conn->MailBuffer = malloc(FileSize); - conn->MailBufferSize = FileSize; - conn->YAPPLen = 0; - fread(conn->MailBuffer, 1, FileSize, hFile); - fclose(hFile); - - Mess[0] = ENQ; - Mess[1] = 1; - - QueueMsg(conn, Mess, 2); - Flush(conn); - - conn->InputMode = 'Y'; - - return; - } - } - - nodeprintf(conn, "File %s not found\r", filename); - SendPrompt(conn, user); -} - -void YAPPSendData(ConnectionInfo * conn) -{ - char Mess[258]; - - conn->BBSFlags |= YAPPTX; - - while (TXCount(conn->BPQStream) < 15) - { - int Left = conn->MailBufferSize; - - if (Left == 0) - { - // Finished - send End Data - - Mess[0] = ETX; - Mess[1] = 1; - - QueueMsg(conn, Mess, 2); - Flush(conn); - - conn->BBSFlags &= ~YAPPTX; - break; - } - - if (Left > conn->paclen - 2) // 2 byte header - Left = conn->paclen -2; - - memcpy(&Mess[2], &conn->MailBuffer[conn->YAPPLen], Left); - Mess[0] = STX; - Mess[1] = Left; - - QueueMsg(conn, Mess, Left + 2); - Flush(conn); - - conn->YAPPLen += Left; - conn->MailBufferSize -= Left; - } -} - -char * AddUser(char * Call, char * password, BOOL BBSFlag) -{ - struct UserInfo * USER; - - strlop(Call, '-'); - - if (strlen(Call) > 6) - Call[6] = 0; - - _strupr(Call); - - if (Call[0] == 0 || LookupCall(Call)) - { - return("User already exists\r\n"); - } - - USER = AllocateUserRecord(Call); - USER->Temp = zalloc(sizeof (struct TempUserInfo)); - - if (strlen(password) > 12) - password[12] = 0; - - strcpy(USER->pass, password); - - if (BBSFlag) - { - if(SetupNewBBS(USER)) - USER->flags |= F_BBS; - else - printf("Cannot set user to be a BBS - you already have 160 BBS's defined\r\n"); - } - - SaveUserDatabase(); - UpdateWPWithUserInfo(USER); - - return("User added\r\n"); -} - -// Server Support Code - -// For the moment only internal REQDIR and REQFIL. - -// May add WPSERV and user implemented servers -/* -F6FBB BBS > - SP REQDIR @ F6ABJ.FRA.EU - Title of message : - YAPP\*.ZIP @ F6FBB.FMLR.FRA.EU - Text of message : - /EX - - F6FBB BBS > - SP REQFIL @ F6ABJ.FRA.EU - Title of message : - DEMOS\ESSAI.TXT @ F6FBB.FMLR.FRA.EU - Text of message : - /EX - - Note Text not used. - -*/ - -VOID SendServerReply(char * Title, char * MailBuffer, int Length, char * To); - -BOOL ProcessReqDir(struct MsgInfo * Msg) -{ - char * Buffer; - int Len = 0; - char * ptr; - - // Parse title - gives directory and return address - - // YAPP\*.ZIP @ F6FBB.FMLR.FRA.EU - - // At the moment we don't allow subdirectories but no harm handling here - - char Pattern[64]; - char * Address; - char * filename = NULL; // ?? Pattern Match ?? - -#ifdef WIN32 - - WIN32_FIND_DATA ffd; - - char szDir[MAX_PATH]; - HANDLE hFind = INVALID_HANDLE_VALUE; - -#else - - #include - - struct dirent **namelist; - int n, i; - struct stat STAT; - int res; - char FN[256]; - -#endif - - strcpy(Pattern, Msg->title); - - ptr = strchr(Pattern, '@'); - - if (ptr == NULL) - - // if we don't have return address no point - // but could we default to sender?? - - return FALSE; - - *ptr++ = 0; // Terminate Path - - strlop(Pattern, ' '); - - while (*ptr == ' ') - ptr++; // accept with or without spaces round @ - - Address = ptr; - - ptr = Buffer = malloc(MaxTXSize); - -#ifdef WIN32 - - // Prepare string for use with FindFile functions. First, copy the - // string to a buffer, then append '\*' to the directory name. - - strcpy(szDir, GetBPQDirectory()); - strcat(szDir, "\\BPQMailChat\\Files\\"); - strcat(szDir, Pattern); - - // Find the first file in the directory. - - hFind = FindFirstFile(szDir, &ffd); - - if (INVALID_HANDLE_VALUE == hFind) - { - Len = sprintf(Buffer, "No Files\r"); - } - else - { - do - { - if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - {} - else - { - if (filename == NULL || stristr(ffd.cFileName, filename)) - Len += sprintf(&Buffer[Len], "%s %d\r", ffd.cFileName, ffd.nFileSizeLow); - } - } - while (FindNextFile(hFind, &ffd) != 0); - - FindClose(hFind); - } - -#else - - n = scandir("Files", &namelist, NULL, alphasort); - - if (n < 0) - perror("scandir"); - else - { - for (i = 0; i < n; i++) - { - sprintf(FN, "Files/%s", namelist[i]->d_name); - - if (filename == NULL || stristr(namelist[i]->d_name, filename)) - if (FN[6] != '.' && stat(FN, &STAT) == 0) - Len += sprintf(&Buffer[Len], "%s %d\r", namelist[i]->d_name, STAT.st_size); - - free(namelist[i]); - } - free(namelist); - } - -#endif - - // Build Message - - SendServerReply("REQDIR Reply", Buffer, Len, _strupr(Address)); - return TRUE; -} - -/* - ' Augment Message ID with the Message Pickup Station we're directing this message to. - ' - Dim strAugmentedMessageID As String - If GetMidRMS(MessageId) <> "" Then - ' The MPS RMS is already set on the message ID - strAugmentedMessageID = MessageId - strMPS = GetMidRMS(MessageId) - ' "@R" at the end of the MID means route message only via radio - If GetMidForwarding(MessageId) = "" And (blnRadioOnly Or UploadThroughInternet()) Then - strAugmentedMessageID &= "@" & strHFOnlyFlag - End If - ElseIf strMPS <> "" Then - ' Add MPS to the message ID - strAugmentedMessageID = MessageId & "@" & strMPS - ' "@R" at the end of the MID means route message only via radio - If blnRadioOnly Or UploadThroughInternet() Then - strAugmentedMessageID &= "@" & strHFOnlyFlag - End If - Else - strAugmentedMessageID = MessageId - End If - -*/ - -void ProcessSyncModeMessage(CIRCUIT * conn, struct UserInfo * user, char* Buffer, int len) -{ - Buffer[len] = 0; - - if (conn->Flags & GETTINGSYNCMESSAGE) - { - // Data - - if ((conn->TempMsg->length + len) > conn->MailBufferSize) - { - conn->MailBufferSize += 10000; - conn->MailBuffer = realloc(conn->MailBuffer, conn->MailBufferSize); - - if (conn->MailBuffer == NULL) - { - BBSputs(conn, "*** Failed to extend Message Buffer\r"); - conn->CloseAfterFlush = 20; // 2 Secs - - return; - } - } - - memcpy(&conn->MailBuffer[conn->TempMsg->length], Buffer, len); - - conn->TempMsg->length += len; - - if (conn->TempMsg->length >= conn->SyncCompressedLen) - { - // Complete - decompress it - - conn->BBSFlags |= FBBCompressed; - Decode(conn, 1); - - conn->Flags &= !GETTINGSYNCMESSAGE; - - BBSputs(conn, "OK\r"); - return; - } - return; - } - - if (conn->Flags & PROPOSINGSYNCMSG) - { - // Waiting for response to TR AddMessage - - if (strcmp(Buffer, "OK\r") == 0) - { - char Msg[256]; - int n; - - WriteLogLine(conn, '<', Buffer, len-1, LOG_BBS); - - // Send the message, it has already been built - - conn->Flags &= !PROPOSINGSYNCMSG; - conn->Flags |= SENDINGSYNCMSG; - - n = sprintf_s(Msg, sizeof(Msg), "Sending SYNC message %s", conn->FwdMsg->bid); - WriteLogLine(conn, '|',Msg, n, LOG_BBS); - - QueueMsg(conn, conn->SyncMessage, conn->SyncCompressedLen); - return; - } - - if (strcmp(Buffer, "NO\r") == 0) - { - WriteLogLine(conn, '<', Buffer, len-1, LOG_BBS); - - // Message Rejected - ? duplicate - - if (conn->FwdMsg) - { - // Zap the entry - - clear_fwd_bit(conn->FwdMsg->fbbs, user->BBSNumber); - set_fwd_bit(conn->FwdMsg->forw, user->BBSNumber); - conn->UserPointer->ForwardingInfo->MsgCount--; - - // Only mark as forwarded if sent to all BBSs that should have it - - if (memcmp(conn->FwdMsg->fbbs, zeros, NBMASK) == 0) - { - conn->FwdMsg->status = 'F'; // Mark as forwarded - conn->FwdMsg->datechanged=time(NULL); - } - - conn->FwdMsg->Locked = 0; // Unlock - } - } - - BBSputs(conn, "BYE\r"); - conn->CloseAfterFlush = 20; // 2 Secs - conn->Flags &= !PROPOSINGSYNCMSG; - conn->BBSFlags &= ~SYNCMODE; - return; - } - - if (conn->Flags & SENDINGSYNCMSG) - { - if (strcmp(Buffer, "OK\r") == 0) - { - // Message Sent - - conn->Flags &= !SENDINGSYNCMSG; - free(conn->SyncMessage); - - if (conn->FwdMsg) - { - char Msg[256]; - int n; - - n = sprintf_s(Msg, sizeof(Msg), "SYNC message %s Sent", conn->FwdMsg->bid); - WriteLogLine(conn, '|',Msg, n, LOG_BBS); - - clear_fwd_bit(conn->FwdMsg->fbbs, user->BBSNumber); - set_fwd_bit(conn->FwdMsg->forw, user->BBSNumber); - conn->UserPointer->ForwardingInfo->MsgCount--; - - // Only mark as forwarded if sent to all BBSs that should have it - - if (memcmp(conn->FwdMsg->fbbs, zeros, NBMASK) == 0) - { - conn->FwdMsg->status = 'F'; // Mark as forwarded - conn->FwdMsg->datechanged=time(NULL); - } - - conn->FwdMsg->Locked = 0; // Unlock - } - - // drop through to send any more - } - else - { - WriteLogLine(conn, '<', Buffer, len-1, LOG_BBS); - - conn->Flags &= !SENDINGSYNCMSG; - free(conn->SyncMessage); - - BBSputs(conn, "BYE\r"); - conn->CloseAfterFlush = 20; // 2 Secs - conn->BBSFlags &= ~SYNCMODE; - - return; - } - } - - if (strcmp(Buffer, "OK\r") == 0) - { - WriteLogLine(conn, '<', Buffer, len-1, LOG_BBS); - - // Send Message(?s) to RMS Relay SYNC - -/* -OK ->TR AddMessage_V5JLSGH591JR 786 1219 522 True -BYE*/ - if (FindMessagestoForward(conn) && conn->FwdMsg) - { - struct MsgInfo * Msg = conn->FwdMsg; - char Buffer[128]; - char * Message; - - Message = FormatSYNCMessage(conn, Msg); - - // Need to compress it - - conn->SyncMessage = malloc(conn->SyncXMLLen + conn->SyncMsgLen + 4096); - - conn->SyncCompressedLen = Encode(Message, conn->SyncMessage, conn->SyncXMLLen + conn->SyncMsgLen, 0, 1); - - sprintf(Buffer, "TR AddMessage_%s %d %d %d True\r", // The True on end indicates compressed - Msg->bid, conn->SyncCompressedLen, conn->SyncXMLLen, conn->SyncMsgLen); - - free(Message); - - conn->Flags |= PROPOSINGSYNCMSG; - - BBSputs(conn, Buffer); - return; - } - - - BBSputs(conn, "BYE\r"); - conn->CloseAfterFlush = 20; // 2 Secs - conn->BBSFlags &= ~SYNCMODE; - return; - } - - if (memcmp(Buffer, "TR ", 2) == 0) - { - // Messages have TR_COMMAND_BID Compressed Len XML Len Bosy Len - - char * Command; - char * BIDptr; - - BIDRec * BID; - char *ptr1, *ptr2, *context; - - // TR AddMessage_1145_G8BPQ 727 1202 440 True - - WriteLogLine(conn, '<', Buffer, len-1, LOG_BBS); - - Command = strtok_s(&Buffer[3], "_", &context); - BIDptr = strtok_s(NULL, " ", &context); - ptr2 = strtok_s(NULL, " ", &context); - conn->SyncCompressedLen = atoi(ptr2); - ptr2 = strtok_s(NULL, " ", &context); - conn->SyncXMLLen = atoi(ptr2); - ptr2 = strtok_s(NULL, " ", &context); - conn->SyncMsgLen = atoi(ptr2); - ptr2 = strtok_s(NULL, " ", &context); - - // If addmessage need to check bid doesn't exist - - if (strcmp(Command, "AddMessage") == 0) - { - strlop(BIDptr, '@'); // sometimes has @CALL@R - if (strlen(BIDptr) > 12) - BIDptr[12] = 0; - - BID = LookupBID(BIDptr); - - if (BID) - { - BBSputs(conn, "Rejected - Duplicate BID\r"); - return; - } - } - - conn->TempMsg = zalloc(sizeof(struct MsgInfo)); - - conn->Flags |= GETTINGSYNCMESSAGE; - - BBSputs(conn, "OK\r"); - return; - } - - if (memcmp(Buffer, "BYE\r", 4) == 0) - { - WriteLogLine(conn, '<', Buffer, len-1, LOG_BBS); - conn->CloseAfterFlush = 20; // 2 Secs - conn->BBSFlags &= ~SYNCMODE; - return; - } - - if (memcmp(Buffer, "BBS\r", 4) == 0) - { - // Out of Sync - - WriteLogLine(conn, '<', Buffer, len-1, LOG_BBS); - conn->BBSFlags &= ~SYNCMODE; - return; - } - - WriteLogLine(conn, '<', Buffer, len-1, LOG_BBS); - WriteLogLine(conn, '<', "Unexpected SYNC Message", 23, LOG_BBS); - - BBSputs(conn, "BYE\r"); - conn->CloseAfterFlush = 20; // 2 Secs - conn->BBSFlags &= ~SYNCMODE; - return; -} -BOOL ProcessReqFile(struct MsgInfo * Msg) -{ - char FN[128]; - char * Buffer; - int Len = 0; - char * ptr; - struct stat STAT; - char MsgFile[MAX_PATH]; - FILE * hFile; - int FileSize; - char * MsgBytes; - - // Parse title - gives file and return address - - // DEMOS\ESSAI.TXT @ F6FBB.FMLR.FRA.EU - - // At the moment we don't allow subdirectories but no harm handling here - - char * Address; - char * filename = NULL; // ?? Pattern Match ?? - - strcpy(FN, Msg->title); - - ptr = strchr(FN, '@'); - - if (ptr == NULL) - - // if we don't have return address no point - // but could we default to sender?? - - return FALSE; - - *ptr++ = 0; // Terminate Path - - strlop(FN, ' '); - - while (*ptr == ' ') - ptr++; // accept with or without spaces round @ - - Address = ptr; - - ptr = Buffer = malloc(MaxTXSize + 1); // Allow terminating Null - - // Build Message - - if (FN == NULL) - { - Len = sprintf(Buffer, "Missing Filename\r"); - } - else if (strstr(FN, "..") || strchr(FN, '/') || strchr(FN, '\\')) - { - Len = sprintf(Buffer,"Invalid filename %s\r", FN); - } - else - { - if (BaseDir[0]) - sprintf_s(MsgFile, sizeof(MsgFile), "%s/Files/%s", BaseDir, FN); - else - sprintf_s(MsgFile, sizeof(MsgFile), "Files/%s", FN); - - if (stat(MsgFile, &STAT) != -1) - { - FileSize = STAT.st_size; - - hFile = fopen(MsgFile, "rb"); - - if (hFile) - { - int Length; - - if (FileSize > MaxTXSize) - FileSize = MaxTXSize; // Truncate to max size - - MsgBytes=malloc(FileSize+1); - fread(MsgBytes, 1, FileSize, hFile); - fclose(hFile); - - MsgBytes[FileSize]=0; - - // Remove lf chars - - Length = RemoveLF(MsgBytes, (int)strlen(MsgBytes)); - - Len = sprintf(Buffer, "%s", MsgBytes); - free(MsgBytes); - } - } - else - Len = sprintf(Buffer, "File %s not found\r", FN); - } - - SendServerReply("REQFIL Reply", Buffer, Len, _strupr(Address)); - return TRUE; -} - -BOOL CheckforMessagetoServer(struct MsgInfo * Msg) -{ - if (_stricmp(Msg->to, "REQDIR") == 0) - return ProcessReqDir(Msg); - - if (_stricmp(Msg->to, "REQFIL") == 0) - return ProcessReqFile(Msg); - - return FALSE; -} - -VOID SendServerReply(char * Title, char * MailBuffer, int Length, char * To) -{ - struct MsgInfo * Msg = AllocateMsgRecord(); - BIDRec * BIDRec; - char * Via; - char MsgFile[MAX_PATH]; - FILE * hFile; - size_t WriteLen=0; - - Msg->length = Length; - - GetSemaphore(&MsgNoSemaphore, 0); - Msg->number = ++LatestMsg; - MsgnotoMsg[Msg->number] = Msg; - - FreeSemaphore(&MsgNoSemaphore); - - strcpy(Msg->from, BBSName); - Via = strlop(To, '@'); - - if (Via) - strcpy(Msg->via, Via); - - strcpy(Msg->to, To); - strcpy(Msg->title, Title); - - Msg->type = 'P'; - Msg->status = 'N'; - Msg->datereceived = Msg->datechanged = Msg->datecreated = time(NULL); - - sprintf_s(Msg->bid, sizeof(Msg->bid), "%d_%s", LatestMsg, BBSName); - - BIDRec = AllocateBIDRecord(); - strcpy(BIDRec->BID, Msg->bid); - BIDRec->mode = Msg->type; - BIDRec->u.msgno = LOWORD(Msg->number); - BIDRec->u.timestamp = LOWORD(time(NULL)/86400); - - sprintf_s(MsgFile, sizeof(MsgFile), "%s/m_%06d.mes", MailDir, Msg->number); - - hFile = fopen(MsgFile, "wb"); - - if (hFile) - { - WriteLen = fwrite(MailBuffer, 1, Msg->length, hFile); - fclose(hFile); - } - - MatchMessagetoBBSList(Msg, NULL); - free(MailBuffer); -} - -void SendRequestSync(CIRCUIT * conn) -{ - // Only need XML Header - - char * Buffer = malloc(4096); - int Len = 0; - - struct tm *tm; - char Date[32]; - char MsgTime[32]; - time_t Time = time(NULL); - - char * Encoded; - - tm = gmtime(&Time); - - sprintf_s(Date, sizeof(Date), "%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); - - sprintf_s(MsgTime, sizeof(Date), "%04d/%02d/%02d %02d:%02d", - tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min); - - Len += sprintf(&Buffer[Len], "\r\n"); - - Len += sprintf(&Buffer[Len], "\r\n"); - Len += sprintf(&Buffer[Len], " \r\n"); - Len += sprintf(&Buffer[Len], " request_sync\r\n"); - Len += sprintf(&Buffer[Len], " %s\r\n", Date); - Len += sprintf(&Buffer[Len], " %s\r\n", BBSName); - Len += sprintf(&Buffer[Len], " \r\n"); - Len += sprintf(&Buffer[Len], " \r\n"); - Len += sprintf(&Buffer[Len], " BBSName\r\n"); - Len += sprintf(&Buffer[Len], " \r\n"); - Len += sprintf(&Buffer[Len], " %s\r\n", conn->SyncHost); - Len += sprintf(&Buffer[Len], " %d\r\n", conn->SyncPort); - Len += sprintf(&Buffer[Len], " \r\n"); - Len += sprintf(&Buffer[Len], " \r\n"); - Len += sprintf(&Buffer[Len], "\r\n"); - -/* - - - - request_sync - 20230205100652 - GI8BPQ - - - GI8BPQ - - 127.0.0.1 - 8780 - - - -*/ - - // Need to compress it - - conn->SyncXMLLen = Len; - conn->SyncMsgLen = 0; - - conn->SyncMessage = malloc(conn->SyncXMLLen + 4096); - - conn->SyncCompressedLen = Encode(Buffer, conn->SyncMessage, conn->SyncXMLLen, 0, 1); - - sprintf(Buffer, "TR RequestSync_%s_%d %d %d 0 True\r", // The True on end indicates compressed - 50, conn->SyncCompressedLen, conn->SyncXMLLen); - - free(Buffer); - - conn->Flags |= REQUESTINGSYNC; - - BBSputs(conn, Buffer); - return; -} - - -void ProcessSyncXML(CIRCUIT * conn, char * XML) -{ - // Process XML from RMS Relay Sync - - // All seem to start - - // - // - // - // - - char * Type = strstr(XML, ""); - - if (Type == NULL) - return; - - Type += strlen(""); - - if (memcmp(Type, "rms_location", 12) == 0) - { - return; - } - - - if (memcmp(Type, "request_sync", 12) == 0) - { - char * Call; - struct UserInfo * BBSREC; - - // This isn't requesting a poll, it is asking to be added as a sync partner - - Call = strstr(Type, ""); - - if (Call == NULL) - return; - - Call += 10; - strlop(Call, '<'); - BBSREC = FindBBS(Call); - - if (BBSREC == NULL) - return; - - if (BBSREC->ForwardingInfo->Forwarding == 0) - StartForwarding(BBSREC->BBSNumber, NULL); - - return; - } - - if (memcmp(Type, "remove_message", 14) == 0) - { - char * MID = strstr(Type, ""); - struct MsgInfo * Msg; - - if (MID == NULL) - return; - - MID += 11; - strlop(MID, '<'); - - strlop(MID, '@'); // sometimes has @CALL@R - if (strlen(MID) > 12) - MID[12] = 0; - - Msg = FindMessageByBID(MID); - - if (Msg == NULL) - return; - - Logprintf(LOG_BBS, conn, '|', "Killing Msg %d %s", Msg->number, Msg->bid); - - FlagAsKilled(Msg, TRUE); - return; - } - - if (memcmp(Type, "delivered", 9) == 0) - { - char * MID = strstr(Type, ""); - struct MsgInfo * Msg; - - if (MID == NULL) - return; - - MID += 11; - strlop(MID, '<'); - - strlop(MID, '@'); // sometimes has @CALL@R - if (strlen(MID) > 12) - MID[12] = 0; - - Msg = FindMessageByBID(MID); - - if (Msg == NULL) - return; - - Logprintf(LOG_BBS, conn, '|', "Message Msg %d %s Delivered", Msg->number, Msg->bid); - return; - } - - Debugprintf(Type); - return; - -/* - - - - request_sync - 20230205100652 - GI8BPQ - - - GI8BPQ - - 127.0.0.1 - 8780 - - - -} - - - - delivered - 20230205093113 - G8BPQ - - - 10845_GM8BPB - G8BPQ - G8BPQ - 3 - - - - Public Enum MessageDeliveryMethod - ' - ' Method used to deliver a message. None if the message hasn't been delivered. - ' - Unspecified = -1 - None = 0 - Telnet = 1 - CMS = 2 - Radio = 3 - Email = 4 -End Enum -*/ -} - -int ReformatSyncMessage(CIRCUIT * conn) -{ - // Message has been decompressed - reformat to look like a WLE message - - char * MsgBit; - char *ptr1, *ptr2; - int linelen; - char FullFrom[80]; - char FullTo[80]; - char BID[80]; - time_t Date; - char Mon[80]; - char Subject[80]; - int i = 0; - char * Boundary; - char * Input; - char * via = NULL; - char * NewMsg = conn->MailBuffer; - char * SaveMsg = NewMsg; - char DateString[80]; - struct tm * tm; - char Type[16] = "Private"; - char * part[100] = {""}; - char * partname[100]; - int partLen[100]; - char xml[4096]; - - // Message has an XML header then the message - - // The XML may have control info, so examine it. - - /* - Date: Mon, 25 Oct 2021 10:22:00 -0000 - From: GM8BPQ - Subject: Test - To: 2E1BGT - Message-ID: ALYJQJRXVQAO - X-Source: GM8BPQ - X-Relay: G8BPQ - MIME-Version: 1.0 - MIME-Version: 1.0 - Content-Type: multipart/mixed; boundary="boundaryBSoxlw==" - - --boundaryBSoxlw== - Content-Type: text/plain; charset="iso-8859-1" - Content-Transfer-Encoding: quoted-printable - - Hello Hello - - --boundaryBSoxlw==-- - */ - - // I think the best way is to reformat as if from Winlink Express, then pass - //through the normal B2 code. - -// WriteLogLine(conn, '<', conn->MailBuffer, conn->TempMsg->length, LOG_BBS); - - // display the message for testing - - conn->MailBuffer[conn->TempMsg->length] = 0; - -// OutputDebugString(conn->MailBuffer); - memcpy(xml, conn->MailBuffer, conn->SyncXMLLen); - xml[conn->SyncXMLLen] = 0; - - if (conn->SyncMsgLen == 0) - { - // No message, Just xml. Looks like a status report - - ProcessSyncXML(conn, xml); - return 0; - } - - MsgBit = &conn->MailBuffer[conn->SyncXMLLen]; - conn->TempMsg->length -= conn->SyncXMLLen; - - ptr1 = MsgBit; - -Loop: - - ptr2 = strchr(ptr1, '\r'); - - linelen = (int)(ptr2 - ptr1); - - if (_memicmp(ptr1, "From:", 5) == 0) - { - memcpy(FullFrom, &ptr1[6], linelen - 6); - FullFrom[linelen - 6] = 0; - } - - if (_memicmp(ptr1, "To:", 3) == 0) - { - memcpy(FullTo, &ptr1[4], linelen - 4); - FullTo[linelen - 4] = 0; - } - - else if (_memicmp(ptr1, "Subject:", 8) == 0) - { - memcpy(Subject, &ptr1[9], linelen - 9); - Subject[linelen - 9] = 0; - } - - else if (_memicmp(ptr1, "Message-ID", 10) == 0) - { - memcpy(BID, &ptr1[12], linelen - 12); - BID[linelen - 12] = 0; - } - - else if (_memicmp(ptr1, "Date:", 5) == 0) - { - struct tm rtime; - char seps[] = " ,\t\r"; - - memset(&rtime, 0, sizeof(struct tm)); - - // Date: Mon, 25 Oct 2021 10:22:00 -0000 - - sscanf(&ptr1[11], "%02d %s %04d %02d:%02d:%02d", - &rtime.tm_mday, &Mon, &rtime.tm_year, &rtime.tm_hour, &rtime.tm_min, &rtime.tm_sec); - - rtime.tm_year -= 1900; - - for (i = 0; i < 12; i++) - { - if (strcmp(Mon, month[i]) == 0) - break; - } - - rtime.tm_mon = i; - - Date = mktime(&rtime) - (time_t)_MYTIMEZONE; - - if (Date == (time_t)-1) - Date = time(NULL); - - } - - if (linelen) // Not Null line - { - ptr1 = ptr2 + 2; // Skip crlf - goto Loop; - } - - // Unpack Body - seems to be multipart even if only one - - // Can't we just send the whole body through ?? - // No, Attachment format is different - - // Mbo: GM8BPQ - // Body: 17 - // File: 1471 leadercoeffs.txt - - Input = MsgBit; - Boundary = initMultipartUnpack(&Input); - - i = 0; - - if (Boundary) - { - // input should be start of part - - // Find End of part - ie -- Boundary + CRLF or -- - - char * ptr, * saveptr; - char * Msgptr; - size_t BLen = strlen(Boundary); - size_t Partlen; - - saveptr = Msgptr = ptr = Input; - - while(ptr) // Just in case we run off end - { - if (*ptr == '-' && *(ptr+1) == '-') - { - if (memcmp(&ptr[2], Boundary, BLen) == 0) - { - // Found Boundary - - char * p1, *p2, *ptr3, *ptr4; - int llen; - int Base64 = 0; - int QuotedP = 0; - char * BoundaryStart = ptr; - - Partlen = ptr - Msgptr; - - ptr += (BLen + 2); // End of Boundary - - if (*ptr == '-') // Terminating Boundary - Input = NULL; - else - Input = ptr + 2; - - // Will check for quoted printable - - p1 = Msgptr; -Loop2: - p2 = strchr(p1, '\r'); - llen = (int)(p2 - p1); - - if (llen) - { - - if (_memicmp(p1, "Content-Transfer-Encoding:", 26) == 0) - { - if (_memicmp(&p1[27], "base64", 6) == 0) - Base64 = TRUE; - else if (_memicmp(&p1[27], "quoted", 6) == 0) - QuotedP = TRUE; - } - else if (_memicmp(p1, "Content-Disposition: ", 21) == 0) - { - ptr3 = strstr(&p1[21], "name"); - - if (ptr3) - { - ptr3 += 5; - if (*ptr3 == '"') ptr3++; - ptr4 = strchr(ptr3, '"'); - if (ptr4) *ptr4 = 0; - - partname[i] = ptr3; - } - } - - if (llen) // Not Null line - { - p1 = p2 + 2; // Skip crlf - goto Loop2; - } - } - - part[i] = strstr(p2, "\r\n"); // Over separator - - if (part[i]) - { - part[i] += 2; - partLen[i] = BoundaryStart - part[i] - 2; - if (QuotedP) - partLen[i] = decode_quoted_printable(part[i], partLen[i]); - else if (Base64) - { - int Len = partLen[i], NewLen; - char * ptr = part[i]; - char * ptr2 = part[i]; - - // WLE sends base64 with embedded crlf, so remove them - - while (Len-- > 0) - { - if ((*ptr) != 10 && (*ptr) != 13) - *(ptr2++) = *(ptr++); - else - ptr ++; - } - - Len = ptr2 - part[i]; - ptr = part[i]; - ptr2 = part[i]; - - while (Len > 0) - { - decodeblock(ptr, ptr2); - ptr += 4; - ptr2 += 3; - Len -= 4; - } - - NewLen = (int)(ptr2 - part[i]); - - if (*(ptr-1) == '=') - NewLen--; - - if (*(ptr-2) == '=') - NewLen--; - - partLen[i] = NewLen; - } - } - Msgptr = ptr = Input; - i++; - continue; } - - // See if more parts - } - ptr++; - } - ptr++; - } - - - // Build the message - - tm = gmtime(&Date); - - sprintf(DateString, "%04d/%02d/%02d %02d:%02d", - tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min); - - NewMsg += sprintf(NewMsg, - "MID: %s\r\n" - "Date: %s\r\n" - "Type: %s\r\n" - "From: %s\r\n", - BID, DateString, Type, FullFrom); - -// if (ToCalls) -// { -// int i; - -// for (i = 0; i < Calls; i++) -// NewMsg += sprintf(NewMsg, "To: %s\r\n", ToCalls[i]); - -// } -// else - { - NewMsg += sprintf(NewMsg, "To: %s\r\n", - FullTo); - } -// if (WebMail->CC && WebMail->CC[0]) -// NewMsg += sprintf(NewMsg, "CC: %s\r\n", WebMail->CC); - - NewMsg += sprintf(NewMsg, - "Subject: %s\r\n" - "Mbo: %s\r\n", - Subject, BBSName); - - // Write the Body: line and any File Lines - - NewMsg += sprintf(NewMsg, "Body: %d\r\n", partLen[0]); - - i = 1; - - while (part[i]) - { - NewMsg += sprintf(NewMsg, "File: %d %s\r\n", - partLen[i], partname[i]); - - i++; - } - - NewMsg += sprintf(NewMsg, "\r\n"); // Blank Line to end header - - // Now add parts - - i = 0; - - while (part[i]) - { - memmove(NewMsg, part[i], partLen[i]); - NewMsg += partLen[i]; - i++; - NewMsg += sprintf(NewMsg, "\r\n"); // Blank Line between attachments - } - - conn->TempMsg->length = NewMsg - SaveMsg; - conn->TempMsg->datereceived = conn->TempMsg->datechanged = time(NULL); - conn->TempMsg->datecreated = Date; - strcpy(conn->TempMsg->bid, BID); - - if (strlen(Subject) > 60) - Subject[60] = 0; - - strcpy(conn->TempMsg->title, Subject); - - return TRUE; -} - -char * FormatSYNCMessage(CIRCUIT * conn, struct MsgInfo * Msg) -{ - // First an XML Header - - char * Buffer = malloc(4096 + Msg->length); - int Len = 0; - - struct tm *tm; - char Date[32]; - char MsgTime[32]; - char Separator[33]=""; - time_t Time = time(NULL); - char * MailBuffer; - int BodyLen; - char * Encoded; - - // Get the message - may need length in header - - MailBuffer = ReadMessageFile(Msg->number); - - BodyLen = Msg->length; - - // Remove any B2 Header - - if (Msg->B2Flags & B2Msg) - { - // Remove B2 Headers (up to the File: Line) - - char * ptr; - ptr = strstr(MailBuffer, "Body:"); - if (ptr) - { - BodyLen = atoi(ptr + 5); - ptr = strstr(ptr, "\r\n\r\n"); - } - if (ptr) - { - memcpy(MailBuffer, ptr + 4, BodyLen); - MailBuffer[BodyLen] = 0; - } - } - - // encode body as quoted printable; - - Encoded = malloc(Msg->length * 3); - - BodyLen = encode_quoted_printable(MailBuffer, Encoded, BodyLen); - - // Create multipart Boundary - - CreateOneTimePassword(&Separator[0], "Key", 0); - CreateOneTimePassword(&Separator[16], "Key", 1); - - - tm = gmtime(&Time); - - sprintf_s(Date, sizeof(Date), "%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); - - tm = gmtime((time_t *)&Msg->datecreated); - - sprintf_s(MsgTime, sizeof(Date), "%04d/%02d/%02d %02d:%02d", - tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min); - - Len += sprintf(&Buffer[Len], "\r\n"); - - Len += sprintf(&Buffer[Len], "\r\n"); - Len += sprintf(&Buffer[Len], " \r\n"); - Len += sprintf(&Buffer[Len], " add_message\r\n"); - Len += sprintf(&Buffer[Len], " %s\r\n", Date); - Len += sprintf(&Buffer[Len], " %s\r\n", Msg->from); - Len += sprintf(&Buffer[Len], " \r\n"); - Len += sprintf(&Buffer[Len], " \r\n"); - Len += sprintf(&Buffer[Len], " \r\n"); - Len += sprintf(&Buffer[Len], " %s\r\n", Msg->bid); - Len += sprintf(&Buffer[Len], " \r\n", MsgTime); - Len += sprintf(&Buffer[Len], " %s\r\n", Msg->from); - Len += sprintf(&Buffer[Len], " %s\r\n", Msg->from); - Len += sprintf(&Buffer[Len], " 2\r\n"); - Len += sprintf(&Buffer[Len], " %s\r\n", (Msg->B2Flags & Attachments) ? "true" : "false"); - Len += sprintf(&Buffer[Len], " %d\r\n", BodyLen); - Len += sprintf(&Buffer[Len], " %s\r\n", Msg->title); - Len += sprintf(&Buffer[Len], " \r\n"); - Len += sprintf(&Buffer[Len], " \r\n"); - Len += sprintf(&Buffer[Len], " \r\n"); - Len += sprintf(&Buffer[Len], " \r\n"); - Len += sprintf(&Buffer[Len], " \r\n"); - Len += sprintf(&Buffer[Len], " %s\r\n", Msg->bid); - Len += sprintf(&Buffer[Len], " 450443\r\n"); - Len += sprintf(&Buffer[Len], " %s\r\n", Msg->to); - Len += sprintf(&Buffer[Len], " \r\n"); - Len += sprintf(&Buffer[Len], " 0\r\n"); - Len += sprintf(&Buffer[Len], " False\r\n"); - Len += sprintf(&Buffer[Len], " False\r\n"); - Len += sprintf(&Buffer[Len], " False\r\n"); - Len += sprintf(&Buffer[Len], " False\r\n"); - Len += sprintf(&Buffer[Len], " \r\n"); - Len += sprintf(&Buffer[Len], " \r\n"); - Len += sprintf(&Buffer[Len], " \r\n"); - Len += sprintf(&Buffer[Len], " True\r\n"); - Len += sprintf(&Buffer[Len], " False\r\n"); - Len += sprintf(&Buffer[Len], " \r\n"); - Len += sprintf(&Buffer[Len], " \r\n"); - Len += sprintf(&Buffer[Len], "\r\n"); - -// Debugprintf(Buffer); - - conn->SyncXMLLen = Len; - - Len += sprintf(&Buffer[Len], "Date: Sat, 04 Feb 2023 11:19:00 +0000\r\n"); - Len += sprintf(&Buffer[Len], "From: %s\r\n", Msg->from); - Len += sprintf(&Buffer[Len], "Subject: %s\r\n", Msg->title); - Len += sprintf(&Buffer[Len], "To: %s\r\n", Msg->to); - Len += sprintf(&Buffer[Len], "Message-ID: %s\r\n", Msg->bid); -// Len += sprintf(&Buffer[Len], "X-Source: G8BPQ\r\n"); -// Len += sprintf(&Buffer[Len], "X-Location: 52.979167N, 1.125000W (GRID SQUARE)\r\n"); -// Len += sprintf(&Buffer[Len], "X-RMS-Originator: G8BPQ\r\n"); -// Len += sprintf(&Buffer[Len], "X-RMS-Path: G8BPQ@2023-02-04-11:19:29\r\n"); - Len += sprintf(&Buffer[Len], "X-Relay: %s\r\n", BBSName); - - Len += sprintf(&Buffer[Len], "MIME-Version: 1.0\r\n"); - Len += sprintf(&Buffer[Len], "Content-Type: multipart/mixed; boundary=\"%s\"\r\n", Separator); - - Len += sprintf(&Buffer[Len], "\r\n"); // Blank line before separator - Len += sprintf(&Buffer[Len], "--%s\r\n", Separator); - Len += sprintf(&Buffer[Len], "Content-Type: text/plain; charset=\"iso-8859-1\"\r\n"); - Len += sprintf(&Buffer[Len], "Content-Transfer-Encoding: quoted-printable\r\n"); - Len += sprintf(&Buffer[Len], "\r\n"); // Blank line before body - - Len += sprintf(&Buffer[Len], "%s\r\n", Encoded); - Len += sprintf(&Buffer[Len], "--%s--\r\n", Separator); - - conn->SyncMsgLen = Len - conn->SyncXMLLen; - - free(Encoded); - free(MailBuffer); - - return Buffer; -} - -int encode_quoted_printable(char *s, char * out, int Len) -{ - int n = 0; - char * start = out; - - while(Len--) - { - if (n >= 73 && *s != 10 && *s != 13) - {strcpy(out, "=\r\n"); n = 0; out +=3;} - if (*s == 10 || *s == 13) {putchar(*s); n = 0;} - else if (*s<32 || *s==61 || *s>126) - out += sprintf(out, "=%02x", (unsigned char)*s); - else if (*s != 32 || (*(s+1) != 10 && *(s+1) != 13)) - {*(out++) = *s; n++;} - else n += printf("=20"); - - s++; - } - *out = 0; - - return out - start; -} - -int decode_quoted_printable(char *ptr, int len) -{ - // overwrite input with decoded version - - char * ptr2 = ptr; - char * End = ptr + len; - char * Start = ptr; - - while (ptr < End) - { - if ((*ptr) == '=') - { - char c = *(++ptr); - char d; - - c = c - 48; - if (c < 0) - { - // = CRLF as a soft break - - ptr += 2; - continue; - } - if (c > 9) c -= 7; - d = *(++ptr); - d = d - 48; - if (d > 9) d -= 7; - - *(ptr2) = c << 4 | d; - ptr2++; - ptr++; - } - else - *ptr2++ = *ptr++; - } - return ptr2 - Start; -} diff --git a/BPQINP3.c b/BPQINP3.c index 8a1860a..e541518 100644 --- a/BPQINP3.c +++ b/BPQINP3.c @@ -35,6 +35,9 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #include //#include "vmm.h" +uint64_t timeLoadedMS = 0; + + static VOID SendNetFrame(struct ROUTE * Route, struct _L3MESSAGEBUFFER * Frame) { // INP3 should only ever send over an active link, so just queue the message @@ -320,7 +323,7 @@ VOID ProcessRTTReply(struct ROUTE * Route, struct _L3MESSAGEBUFFER * Buff) Route->Timeout = 0; // Got Response sscanf(&Buff->L4DATA[6], "%d", &OrigTime); - RTT = GetTickCount() - OrigTime; + RTT = (GetTickCount() - timeLoadedMS) - OrigTime; if (RTT > 60000) return; // Ignore if more than 60 secs @@ -379,6 +382,11 @@ VOID ProcessINP3RIF(struct ROUTE * Route, UCHAR * ptr1, int msglen, int Port) rtt = (*ptr1++ << 8); rtt += *ptr1++; + // rtt is value from remote node. Add our RTT to that node and update hops + + rtt += Route->SRTT; + hops++; + msglen -= 10; while (*ptr1 && msglen > 0) @@ -766,7 +774,7 @@ VOID SendRTTMsg(struct ROUTE * Route) Msg->L4FLAGS = L4INFO; - sprintf(Stamp, "%10d %10d %10d %10d ", GetTickCount(), Route->SRTT/10, Route->RTT/10, 0); + sprintf(Stamp, "%10llu %10d %10d %10d ", (GetTickCount() - timeLoadedMS), Route->SRTT/10, Route->RTT/10, 0); memcpy(RTTMsg.TXTIME, Stamp, 44); memcpy(Msg->L4DATA, &RTTMsg, 236); diff --git a/BPQMail.aps b/BPQMail.aps index 2e2b5fe..694b39f 100644 Binary files a/BPQMail.aps and b/BPQMail.aps differ diff --git a/BPQMail.c b/BPQMail.c index b244671..3475f84 100644 --- a/BPQMail.c +++ b/BPQMail.c @@ -1118,6 +1118,9 @@ // Fix recently introduced crash when "Don't allow new users" is set (81) // Skip comments before TIMES at start of Connect Script (83) +// 6.0.25.1 ?? + +// Aff FBB reject.sys style filters (3) #include "bpqmail.h" #include "winstdint.h" diff --git a/BPQMail.c.bak b/BPQMail.c.bak deleted file mode 100644 index a4eecaf..0000000 --- a/BPQMail.c.bak +++ /dev/null @@ -1,3651 +0,0 @@ -// Mail and Chat Server for BPQ32 Packet Switch -// -// - -// Version 1.0.0.17re - -// Split Messasge, User and BBS Editing from Main Config. -// Add word wrap to Console input and output -// Flash Console on chat user connect -// Fix processing Name response in chat mode -// Fix processing of *RTL from station not defined as a Chat Node -// Fix overlength lines ln List responses -// Housekeeping expires BIDs -// Killing a message removes it from the forwarding counts - -// Version 1.0.0.18 - -// Save User Database when name is entered or updated so it is not lost on a crash -// Fix Protocol Error in Compressed Forwarding when switching direction -// Add Housekeeping results dialog. - -// Version 1.0.0.19 - -// Allow PACLEN in forward scripts. -// Store and forward messages with CRLF as line ends -// Send Disconnect after FQ ( for LinFBB) -// "Last Listed" is saved if MailChat is closed without closing Console -// Maximum acceptable message length can be specified (in Forwarding Config) - -// Version 1.0.0.20 - -// Fix error in saving forwarding config (introduced in .19) -// Limit size of FBB forwarding block. -// Clear old connection (instead of new) if duplicate connect on Chat Node-Node link -// Send FA for Compressed Mail (was sending FB for both Compressed and Uncompressed) - -// Version 1.0.0.21 - -// Fix Connect Script Processing (wasn't waiting for CONNECTED from last step) -// Implement Defer -// Fix MBL-style forwarding -// Fix Add User (Params were not saved) -// Add SC (Send Copy) Command -// Accept call@bbs as well as call @ bbs - -// Version 1.0.0.22 - -// Implement RB RP LN LR LF LN L$ Commands. -// Implement QTH and ZIP Commands. -// Entering an empty Title cancels the message. -// Uses HomeBBS field to set @ field for local users. -// Creates basic WP Database. -// Uses WP to lookup @ field for non-local calls. -// Console "Actions" Menu renamed "Options". -// Excluded flag is actioned. -// Asks user to set HomeBBS if not already set. -// Fix "Shrinking Message" problem, where message got shorter each time it was read Initroduced in .19). -// Flash Server window when anyone connects to chat (If Console Option "Flash on Chat User Connect" set). - -// Version 1.0.0.23 - -// Fix R: line scan bug - -// Version 1.0.0.24 - -// Fix closing console window on 'B'. -// Fix Message Creation time. -// Enable Delete function in WP edit dialog - -// Version 1.0.0.25 - -// Implement K< and K> commands -// Experimental support for B1 and B2 forwarding -// Experimental UI System -// Fix extracting QTH from WP updates - -// Version 1.0.0.26 - -// Add YN etc responses for FBB B1/B2 - -// Version 1.0.0.27 - -// Fix crash if NULL received as start of a packet. -// Add Save WP command -// Make B2 flag BBS-specific. -// Implement B2 Send - -// Version 1.0.0.28 - -// Fix parsing of smtp to addresses - eg smtp:john.wiseman@cantab.net -// Flag messages as Held if smtp server rejects from or to addresses -// Fix Kill to (K> Call) -// Edit Message dialog shows latest first -// Add chat debug window to try to track down occasional chat connection problems - -// Version 1.0.0.29 - -// Add loads of try/excspt - -// Version 1.0.0.30 - -// Writes Debug output to LOG_DEBUG_X and Monitor Window - -// Version 1.0.0.32 - -// Allow use of GoogleMail for ISP functions -// Accept SYSOP as alias for SYSOPCall - ie user can do SP SYSOP, and it will appear in sysop's LM, RM, etc -// Email Housekeeping Results to SYSOP - -// Version 1.0.0.33 - -// Housekeeping now runs at Maintenance Time. Maintenance Interval removed. -// Allow multiple numbers on R and K commands -// Fix L command with single number -// Log if Forward count is out of step with messages to forward. -// UI Processing improved and F< command implemented - -// Version 1.0.0.34 - -// Semaphore Chat Messages -// Display Semaphore Clashes -// More Program Error Traps -// Kill Messages more than BIDLifetime old - -// Version 1.0.0.35 - -// Test for Mike - Remove B1 check from Parse_SID - -// Version 1.0.0.36 - -// Fix calculation of Housekeeping Time. -// Set dialog box background explicitly. -// Remove tray entry for chat debug window. -// Add date to log file name. -// Add Actions Menu option to disable logging. -// Fix size of main window when it changes between versions. - -// Version 1.0.0.37 - -// Implement Paging. -// Fix L< command (was giving no messages). -// Implement LR LR mmm-nnn LR nnn- (and L nnn-) -// KM should no longer kill SYSOP bulls. -// ISP interfaces allows SMTP Auth to be configured -// SMTP Client would fail to send any more messages if a connection failed - -// Version 1.0.0.38 - -// Don't include killed messages in L commands (except LK!) -// Implement l@ -// Add forwarding timebands -// Allow resizing of main window. -// Add Ver command. - -// Version 1.0.1.1 - -// First Public Beta - -// Fix part line handling in Console -// Maintenance deletes old log files. -// Add option to delete files to the recycle bin. - -// Version 1.0.2.1 - -// Allow all Node SYSOP commands in connect scripts. -// Implement FBB B1 Protocol with Resume -// Make FBB Max Block size settable for each BBS. -// Add extra logging when Chat Sessions refused. -// Fix Crash on invalid housekeeping override. -// Add Hold Messages option. -// Trap CRT Errors -// Sort Actions/Start Forwarding List - -// Version 1.0.2.2 - -// Fill in gaps in BBS Number sequence -// Fix PE if ctext contains } -// Run Houskeeping at startup if previous Housekeeping was missed - -// Version 1.0.2.3 - -// Add configured nodes to /p listing - -// Version 1.0.2.4 - -// Fix RMS (it wanted B2 not B12) -// Send messages if available after rejecting all proposals -// Dont try to send msg back to originator. - -// Version 1.0.2.5 - -// Fix timeband processing when none specified. -// Improved Chat Help display. -// Add helpful responses to /n /q and /t - -// Version 1.0.2.6 - -// Kill Personal WP messages after processing -// Make sure a node doesnt try to "join" or "leave" a node as a user. -// More tracing to try to track down lost topic links. -// Add command recall to Console -// Show users in new topic when changing topic -// Add Send From Clipboard" Action - -// Version 1.0.2.7 - -// Hold messages from the future, or with invalid dates. -// Add KH (kill held) command. -// Send Message to SYSOP when a new user connects. - -// Version 1.0.2.8 - -// Don't reject personal message on Dup BID unless we already have an unforwarded copy. -// Hold Looping messages. -// Warn SYSOP of held messages. - -// Version 1.0.2.9 - -// Close connecton on receipt of *** DONE (MBL style forwarding). -// Improved validation in link_drop (Chat Node) -// Change to welcome prompt and Msg Header for Outpost. -// Fix Connect Script processing for KA Nodes - -// Version 1.0.3.1 - -// Fix incorrect sending of NO - BID. -// Fix problems caused by a user being connected to more than one chat node. -// Show idle time on Chat /u display. -// Rewrite forwarding by HA. -// Add "Bad Words" Test. -// Add reason for holding to SYSOP "Message Held" Message. -// Make topics case-insensitive. -// Allow SR for smtp mail. -// Try to fix some user's "Add User" problem. - - -// Version 1.0.3.2 - -// Fix program error when prcessing - response in FBB forwarding. -// Fix code to flag messages as sent. - - -// Version 1.0.3.3 - -// Attempt to fix message loop on topic_change -// Fix loop if compressed size is greater than 32K when receiving with B1 protocol. -// Fix selection of B1 - -// Version 1.0.3.4 - -// Add "KISS ONLY" Flag to R: Lines (Needs Node Version 4.10.12 (4.10l) or above) -// Add Basic NNTP Interface -// Fix possible loop in lzhuf encode - -// Version 1.0.3.5 - -// Fix forwarding of Held Messages -// More attempts to fix Chat crashes. -// Limit join/leave problem with mismatched nodes. -// Add Chat Node Monitoring System. -// Change order of elements in nntp addresses (now to.at, was at.to) - -// Version 1.0.3.6 - -// Restart and Exit if too many errors -// Fix forwarding of killed messages. -// Fix Forwarding to PaKet. -// Fix problem if BBS signon contains words from the "Fail" list - -// Version 1.0.3.7 - -// re-fix loop if compressed size is greater than 32K - reintroduced in 1.0.3.4 -// Add last message to edit users -// Change Console and Monitor Buffer sizes -// Don't flag msg as 'Y' on read if it was Held or Killed - -// Version 1.0.3.8 - -// Don't connect if all messages for a BBS are held. -// Hold message if From or To are missing. -// Fix parsing of /n and /q commands -// fix possible loop on changing name or qth - -// Version 1.0.3.9 - -// More Chat fixes and monitoring -// Added additional console for chat - -// Version 1.0.3.10 - -// Fix for corruption of CIrcuit-Node chain. - -// Version 1.0.3.11 - -// Fix flow control for SMTP and NNTP - -// Version 1.0.3.12 - -// Fix crash in SendChatStatus if no Chat Links Defined. -// Disable Chat Mode if there is no ApplCall for ChatApplNum, -// Add Edit Message to Manage Messages Dialog -// NNTP needs authentication - - -// Version 1.0.3.13 - -// Fix Chat ApplCall warning when ChatAppl = 0 -// Add NNTP NEWGROUPS Command -// Fix MBL Forwarding (remove extra > prompt after SP) - -// Version 1.0.3.14 - -// Fix topic switch code. -// Send SYSOP messages on POP3 interface if User SYSOP flag is set. -// NNTP only needs Authentication for posting, not reading. - -// Version 1.0.3.15 - -// Fix reset of First to Forward after househeeping - -// Version 1.0.3.16 - -// Fix check of HA for terminating WW -// MBL Mode remove extra > prompts -// Fix program error if WP record has unexpected format -// Connect Script changes for WINMOR -// Fix typo in unconfigured node has connected message - -// Version 1.0.3.17 - -// Fix forwarding of Personals - -// Version 1.0.3.18 - -// Fix detection of misconfigured nodes to work with new nodes. -// Limit connection attempt rate when a chat node is unavailable. -// Fix Program Error on long input lines (> ~250 chars). - -// Version 1.0.3.19 - -// Fix Restart of B2 mode transfers. -// Fix error if other end offers B1 and you are configured for B2 only. - - -// Version 1.0.3.20 - -// Fix Paging in Chat Mode. -// Report Node Versions. - -// Version 1.0.3.21 - -// Check node is not already known when processing OK -// Add option to suppress emailing of housekeeping results - -// Version 1.0.3.22 - -// Correct Version processing when user connects via the network -// Add time controlled forwarding scripts - -// Version 1.0.3.23 - -// Changes to RMS forwarding - -// Version 1.0.3.24 - -// Fix RMS: from SMTP interface -// Accept RMS/ instead of RMS: for Thunderbird - -// Version 1.0.3.25 - -// Accept smtp: addresses from smtp client, and route to ISP gateway. -// Set FROM address of messages from RMS that are delivered to smtp client so a reply will go back via RMS. - -// Version 1.0.3.26 - -// Improve display of rms and smtp messages in message lists and message display. - -// Version 1.0.3.27 - -// Correct code that prevents mail being retured to originating BBS. -// Tidy stuck Nodes and Topics when all links close -// Fix B2 handling of @ to TO Address. - -// Version 1.0.3.28 - -// Ensure user Record for the BBS Call has BBS bit set. -// Don't send messages addressed @winlink.org if addressee is a local user with Poll RMS set. -// Add user configurable welcome messages. - -// Version 1.0.3.29 - -// Add AUTH feature to Rig Control - -// Version 1.0.3.30 - -// Process Paclink Header (;FW:) - -// Version 1.0.3.31 - -// Process Messages with attachments. -// Add inactivity timeout to Chat Console sessions. - -// Version 1.0.3.32 - -// Fix for Paclink > BBS Addresses - -// Version 1.0.3.33 - -// Fix multiple transfers per session for B2. -// Kill messages eent to paclink. -// Add option to forward messages on arrival. - -// Version 1.0.3.34 - -// Fix bbs addresses to winlink. -// Fix adding @winlink.org to imcoming paclink msgs - -// Version 1.0.3.35 - -// Fix bbs addresses to winlink. (Again) - -// Version 1.0.3.36 - -// Restart changes for RMS/paclink - -// Version 1.0.3.37 - -// Fix for RMS Express forwarding - -// Version 1.0.3.38 - -// Fixes for smtp and lower case packet addresses from Airmail -// Fix missing > afer NO - Bid in MBL mode - -// Version 1.0.3.39 - -// Use ;FW: for RMS polling. - -// Version 1.0.3.40 - -// Add ELSE Option to connect scripts. - -// Version 1.0.3.41 - -// Improved handling of Multiple Addresses -// Add user colours to chat. - -// Version 1.0.3.42 - -// Poll multiple SSID's for RMS -// Colour support for BPQTEerminal -// New /C chat command to toggle colour on or off. - -// Version 1.0.3.43 - -// Add SKIPPROMPT command to forward scripts - -// Version 1.0.4.1 - -// Non - Beta Release -// Fix possible crash/corruption with long B2 messages - -// Version 1.0.4.2 - -// Add @winlink.org to the B2 From addresss if it is just a callsign -// Route Flood Bulls on TO as well as @ - -// Version 1.0.4.3 - -// Handle Packet Addresses from RMS Express -// Fix for Housekeeping B$ messages - -// Version 1.0.4.4 - -// Remove B2 header and all but the Body part from messages forwared using MBL -// Fix handling of ;FW: from RMS Express - -// Version 1.0.4.5 - -// Disable Paging on forwarding sessions. -// Kill Msgs sent to RMS Exxpress -// Add Name to Chat *** Joined msg - -// Version 1.0.4.6 - -// Pass smtp:winlink.org messages from Airmail to local user check -// Only apply local user check to RMS: messages @winlink.org -// Check locally input smtp: messages for local winlink.org users -// Provide facility to allow only one connect on a port - -// Version 1.0.4.8 - -// Only reset last listed on L or LR commands. - -// Version 1.0.4.9 - -// Fix error in handling smtp: messages to winlink.org addresses from Airmail - -// Version 1.0.4.10 - -// Fix Badwords processing -// Add Connect Script PAUSE command - -// Version 1.0.4.11 - -// Suppress display and listing of held messages -// Add option to exclude SYSOP messages from LM, KM, etc -// Fix crash whan receiving messages with long lines via plain text forwarding - -// Version 1.0.4.12 Jul 2010 - -// Route P messages on AT -// Allow Applications above 8 - -// Version 1.0.4.13 Aug 2010 - -// Fix TidyString for addresses of form John Wiseman -// Add Try/Except around socket routines - -// Version 1.0.4.14 Aug 2010 - -// Trap "Error - TNC Not Ready" in forward script response -// Fix restart after program error -// Add INFO command -// Add SYSOP-configurable HELP Text. - -// Version 1.0.4.15 Aug 2010 - -// Semaphore Connect/Disconnect -// Semaphore RemoveTempBIDS - -// Version 1.0.4.16 Aug 2010 - -// Remove prompt after receiving unrecognised line in MBL mode. (for MSYS) - -// Version 1.0.4.17 Aug 2010 - -// Fix receiving multiple messages in FBB Uncompressed Mode -// Try to trap phantom chat node connections -// Add delay to close - - -// Version 1.0.4.18 Aug 2010 - -// Add "Send SYSTEM messages to SYSOP Call" Option -// set fwd bit on local winlink.org msgs if user is a BBS -// add winlink.org to from address of messages from WL2K that don't already have an @ - -// Version 1.0.4.19 Sept 2010 - -// Build a B2 From: address if possible, so RMS Express can reply to packet messages. -// Fix handling of addresses from WL2K with SSID's -// L@ now only matches up to length of input string. -// Remove "Type H for help" from login prompt. - -// Version 1.0.4.20 Sept 2010 - -// Process FBB 'E' response -// Handle FROM addresses with an @BBS -// Fix FROM addresses with @ on end. -// Extend delay before close after sending FQ on winmor/pactor sessions. - -// Version 1.0.4.21 Sept 2010 - -// Fix handling B2 From: with an HA -// Add "Expert User" welcome message. - -// Version 1.0.4.22 Sept 2010 - -// Version 1.0.4.23 Oct 2010 - -// Add Dup message supression -// Dont change B2 from if going to RMS - -// Version 1.0.4.24 Oct 2010 - -// Add "Save Registry Config" command -// Add forwarding on wildcarded TO for NTS -// Add option to force text mode forwarding -// Define new users as a temporaty BBS if SID received in reply to Name prompt -// Reduce delay before sending close after sending FQ on pactor sessions -// Fix processing of MIME boundary from GMail - -// Send /ex instead of ctrl/z for text mode forwarding -// Send [WL2K-BPQ... SID if user flagged as RMS Express -// Fix Chat Map reporting when more than one AXIP port -// Add Message State D for NTS Messages -// Forward messages in priority order - T, P, B -// Add Reject and Hold Filters -// Fix holding messages to local RMS users when received as part of a multiple addressee message - -// Version 1.0.4.25 Nov 2010 - -// Renumbered for release -// Add option to save Registry Config during Housekeeping - -// Version 1.0.4.26 Nov 2010 - -// Fix F> loop when doing MBL forwarding between BPQ BBSes -// Allow multiple To: addresses, separated by ; -// Allow Houskeeping Lifetime Overrides to apply to Unsent Messages. -// Set Unforwarded Bulls to status '$' -// Accept MARS and USA as continent codes for MARS Packet Addresses -// Add option to send Non-delivery notifications. - -// Version 1.0.4.27 Dec 2010 - -// Add MSGTYPES fwd file option - -// Version 1.0.4.28 Dec 2010 - -// Renumbered to for release - -// Version 1.0.4.30 Dec 2010 - -// Fix rescan requeuing where bull was rejected by a BBS -// Fiz flagging bulls received by NNTP with $ if they need to be forwarded. -// Add Chat Keepalive option. -// Fix bug in non-delivery notification. - -// Version 1.0.4.32 Jan 2011 - -// Allow "Send from Clipboard" to send to rms: or smtp: -// Allow messages received via SMTP to be bulls (TO preceeded by bull/) or NTS (to nnnnn@NTSXX or nnnnn@NTSXX.NTS) -// Fix corruption of messages converted to B2 if body contains binary data -// Fix occasional program error when forwarding B2 messages -// Limit FBB protocol data blocks to 250 to try to fix restart problem. -// Add F2 to F5 to open windows. - -// Version 1.0.4.33 Jan 2011 - -// Fix holding old bulls with forwarding info. - -// Version 1.0.4.33 Jan 2011 - -// Prevent transfer restarting after a program error. -// Allow Housekeeping to kill held messages. - -// Version 1.0.4.35 Jan 2011 - -// Add Size limits for P and T messages to MSGTYPES command -// Fix Error in MBL processing when blank lines received (introduced in .33) -// Trap possible PE in Send_MON_Datagram -// Don't use paging on chat sessions - -// Version 1.0.4.36 Jan 2011 - -// Fix error after handling first FBB block. -// Add $X and $x welcome message options. - -// Version 1.0.4.37 Jan 2011 - -// Change L command not to list the last message if no new ones are available -// Add LC I I@ IH IZ commands -// Add option to send warning to sysop if forwarded P or T message has nowhere to go -// Fixes for Winpack Compressed Download -// Fix Houskeeping when "Apply Overrides to Unsent Bulls" is set. -// Add console copy/paste. -// Add "No Bulls" Option. -// Add "Mail For" Beacon. -// Tidied up Tab order in config dialogs to help text-to-speech programs. -// Limit MaxMsgno to 99000. - -// Version 1.0.4.38 Feb 2011 - -// Renumbered for release - -// Version 1.0.4.40 April 2011 - -// Add POLLRMS command - -// Changes for Vista/Win7 (registry key change) -// Workaround for changes to RMS Express -// Fix AUTH bug in SMTP server -// Add filter to Edit Messages dialog - -// Version 1.0.4.41 April 2011 - -// Extend B2 proposals to other BPQMail systems so Reject Filter will work. -// Add Edit User Command -// Use internal Registry Save routine instead of Regedit -// Fix Start Forward/All -// Allow Winpack Compressed Upload/Download if PMS flag set (as well as BBS flag) -// Add FWD SYSOP command -// Fix security on POLLRMS command -// Add AUTH command -// Leave selection in same place after Delete User -// Combine SMTP server messages to multiple WL2K addresses into one message to WL2k -// Add option to show name as well as call on Chat messages -// Fix program error if you try to define more than 80 BBS's - -// Version 1.0.4.45 October 2011 - -// Changes to program error reporting. -// BBS "Returh to Node" command added -// Move config to "Standard" location (BPQ Directory/BPQMailChat) . -// Fix crash if "Edit Message" clicked with no message selected. - -// Version 1.0.4.46 October 2011 - -// Fix BaseDir test when BaseDir ends with \ or / -// Fix long BaseDir values (>50 chars) - -// Version 1.4.47.1 January 2012 - -// Call CloseBPQ32 on exit -// Add option to flash window instead of sounding bell on Chat Connects -// Add ShowRMS SYSOP command -// Update WP with I records from R: lines -// Send WP Updates -// Fix Paclen on Pactor-like sessions -// Fix SID and Prompt when RMS Express User is set -// Try to stop loop in Program Error/Restarting code -// Trap "UNABLE TO CONNECT" response in connect script -// Add facility to print messages or save them to a text file - -// Version 1.4.48.1 January 2012 - -// Add Send Message (as well as Send from Clipboard) -// Fix Email From: Address when forwaring using B2 -// Send WP from BBSCALL not SYSOPCALL -// Send Chat Map reports via BPQ32.dll - - -// Version 1.4.49.1 February 2012 - - -// Fix Setting Paclink mode on SNOS connects -// Remove creation of debugging file for each message -// Add Message Export and Import functions -// All printing of more than one message at a time -// Add command to toggle "Expert" status - -// Version 1.4.50.1 February 2012 - -// Fix forwarding to RMS Express users -// Route messages received via B2 to an Internet email address to RMS -// Add Reverse Poll interval -// Add full FROM address to POP3 messages -// Include HOMEBBS command in Help - - -// Version 1.4.51.1 June 2012 - -// Allow bulls to be sent from RMS Express. -// Handle BASE64 and Quoted-printable encoding of single part messages -// Work round for RMS Express "All proposals rejected" Bug. - -// Version 1.4.52.1 August 2012 - -// Fix size limit on B2 To List when sending to multiple dests -// Fix initialisation of DIRMES.SYS control record -// Allow use of Tracker and UZ7HO ports for UI messages - -// Version 1.4.53.1 September 2012 - -// Fix crash if R: line with out a CR found. - -// Version 1.4.54.1 ?? 2012 - -// Add configurable prompts -// Fix KISS-Only Test -// Send EHLO instead of HELO when Authentication is needed on SMTP session -// Add option to use local tome for bbs forwarding config -// Allow comment lines (; or @) or single space in fwd scripts -// Fix loss of forwarding info if SAVE is clicked before selecting a call - -// Version 1.4.55.1 June 2013 - -// Add option to remove users that have not connected for a long time. -// Add l@ smtp: -// Fix From: sent to POP3 Client when meaages is from RMS -// Display Email From on Manage Messages - -// Version 1.4.56.1 July 2013 - -// Add timeout -// Verify prompts -// Add IDLETIME command - - - -// Version 1.4.57.1 - -// Change default IDLETIME -// Fix display of BBS's in Web "Manage Messages" -// Add separate househeeping lifetines for T messages -// Don't change flag on forwarded or delivered messages if they sre subsequently read -// Speed up processing, mainly to stop RMS Express timing out when connecting via Telnet -// Don't append winlink.org to RMS Express or Paclink addresses if RMS is not configured -// Fix receiving NTS messages via B2 -// Add option to send "Mail For", but not FBB Headers -// Fix corruption caused with Subject longer than 60 bytes reveived from Winlink systems -// Fix Endian bug in FBB Compression code - - -// Version 1.4.58.1 - -// Change control of appending winlink.org to RMS Express or Paclink addresses to a user flag -// Lookup HomeBBS and WP for calls without a via received from RMS Express or Paclink -// Treat call@bpq as request to look up address in Home BBS/WP for messages received from RMS Express or Paclink -// Collect stats by message type -// Fix Non-Delivery notifications to SMTP messages -// Add Message Type Stats to BBS Trafic Report -// Add "Batch forward to email" -// Add EXPORT command -// Allow more BBS records -// Allow lower case connect scripts -// Fix POP3 LIST command -// Fix MIME Multipart Alternate with first part Base64 or Quoted Printable encoding -// Fix duplicates of SP SYSOP@WW Messages -// Add command line option (tidymail) to delete redundant Mail files -// Add command line option (nohomebbs) to suppress HomeBBS prompt - -// 59 April 2014 - -// Add FLARQ Mail Mode -// Fix possible crash saving restart data -// Add script command ADDLF for connect scripts over Telnet -// Add recogniton of URONODE connected message -// Add option to stop Name prompt -// Add new RMS Express users with "RMS Express User" flag set -// Validate HTML Pages -// Add NTS swap file -// Add basic File list and read functions -// Fix Traffic report - -// 60 - -// Fix security hole in readfile - -// 61 August 2014 -// Set Messages to NTS:nnnnn@NTSXX to type 'T' and remove NTS -// Dont treat "Attempting downlink" as a failure -// Add option to read messages during a list -// Fix crash during message renumber on MAC -// Timeout response to SID to try to avoid hang on an incomplete connection. -// Save config in file instead of registry -// Fix Manage Messages "EXPORT" option and check filename on EXPORT command -// Fix reverse forward prompt in MBL mode. -// Fix From address in POP3 messages where path is @winlink.org -// Fix possible program error in T message procesing -// Add MaxAge param (for incoming Bulls) - - -//62 November 2014 -// Add ZIP and Permit Bulls flag to Manage Users -// Allow users to kill their own B and anyone to kill T messages -// Improve saving of "Last Listed" -// Fix LL when paging -// Send Date received in R: Line (should fix B2 message restarts) -// Fix occasional crash in terminal part line processing -// Add "SKIPCON" forwarding command to handle nodes that include "Connected" in their CTEXT -// Fix possible retry loop when message is deferred (FBB '=' response); -// Don't remove Attachments from received bulls. - -//63 Feb 2015 - -// Fix creating Bulls from RMS Express messages. -// Fix PE if message with no To: received. -// Fix setting "RMS Express User" flag on new connects from RMS Express -// Fix deleting 'T' messages downloaded by RMS Express -// Include MPS messages in count of messages to forward. -// Add new Welcome Message variable $F for messages to forward -// Fix setting Type in B2 header when usong NTS: or BULL: -// Remove trailing spaces from BID when Creating Message from Clipboard. -// Improved handling of FBB B1/B2 Restarts. - -//64 September 2015 - -// Fix Message Type in msgs from RMS Express to Internet -// Reopen Monitor window if open when program list closed -// Only apply NTS alias file to NTS Messages -// Fix failure to store some encrypted ISP passwords -// Allow EDITUSER to change "RMS Express User" flag -// Fix reporting of Config File errors -// Fix Finding MPS Messages (First to Forward was being used incorrectly) -// Add "Save Attachment" to Web Mgmt Interface -// Support Secure Signon on Forwarding sessions to CMS -// Save Forwarding config when BBS flag on user is cleared -// Pass internally generated SYSOP messages through routing process -// Add POP3 TOP command. -// Don't set 'T' messages to 'Y' when read. -// Add optional temporary connect script on "FWD NOW" command -// Add automatic import facility -// Accept RMS mail to BBS Call even if "Poll RMS" not set. - -// 65 November 2015 - -// Fix loading Housekeeping value for forwarded bulls. -// Fix re-using Fwd script override in timer driven forwarding. -// Add ampr.org handling -// Add "Dont forward" match on TO address for NTS -// Allow listing a combinatiom of state and type, such as LNT or LPF -// Fix handling ISP messages from gmail without a '+' -// Add basic WebMail support - -// 66 - -// Autoimport messages as Dummy Call, not SYSOP Call -// Add "My Messages" display option to WebMail -// Create .csv extract of User List during hourekeeping. -// Fix processing of NTS Alising of @ Addresses -// Don't reroute Delivered NTS Messages -// Add option to stop users killing T messages -// Add multicast Receive -// Fix initialising new message database format field -// Fix "Forward Messages to BBS Call" option. -// Add Filter WP Bulls option and allow multiple WP "TO" addresses -// Fix deleting P WP messages for other stations -// Fix saving blank lines in forwarding config -// Fix paging on L@ and l< -// Fix removing DELETE from IMPORT XXX DELETE and allow multiple IMPORT lines in script -// Run DeleteRedundantMessages before renumbering messages -// Connect script now tries ELSE lines if prompt not received from remote BBS -// Send connecting call instead of BBS Name when connecting to CMS server. -// Add BID filter to Manage Messages -// Fix handling of over long suject lines in IMPORT -// Allow comments before ELSE in connect script -// Add Copy and Clear to Multicast Window -// Fix possible duplicate messages with MBL forwarding -// Set "Permit EMail" on IMPORT dummy User. -// Fix repeated running of housekeeping if clock is stepped forward. -// Fix corruption of CMS Pass field by Web interface -// Kill B2 WP bulls if FilterWPBulls set -// Include Message Type in BPQ B2 proposal extensions - -// 6.0.14.1 July 2017 - -// Fix corruption of BBSNumber if RMS Ex User and BBS both checked -// Tread B messages without an AT as Flood. -// Make sure Message headers are always saved to disk when a message status changes -// Reject message instead of failing session if TO address too long in FBB forwarding -// Fix error when FBB restart data exactly fills a packet. -// Fix possible generation of msg number zero in send nondlivery notification -// Fix problem with Web "Manage Messages" when stray message number zero appears -// Fix Crash in AMPR forward when host missing from VIA -// Fix possible addition of an spurious password entry to the ;FW: line when connecting to CMS -// Fix test for Status "D" in forward check. -// Don't cancel AUTH on SMTP RSET -// Fix "nowhere to go" message on some messages sent to smtp addresses -// Add @ from Home BBS or WP is not spcified in "Send from Clipboard" - -// 6.0.15.1 Feb 2018 - -// Fix PE if Filename missing from FILE connect script command -// Suppress reporting errors after receiving FQ -// Fix problem caused by trailing spaces on callsign in WP database -// Support mixed case WINLINK Passwords - -// 6.0.16.1 March 2018 - -// Make sure messages sent to WL2K don;'t have @ on from: address -// If message to saildocs add R: line as an X header instead of to body -// Close session if more than 4 Invalid Commmad responses sent -// Report TOP in POP3 CAPA list. Allows POP3 to work with Windows Mail client - -// 6.0.17.1 November 2018 - -// Add source routing using ! eg sp g8bpq@winlink.org!gm8bpq to send via RMS on gm8bpq -// Accept an internet email address without rms: or smtp: -// Fix "Forward messages for BBS Call" when TO isn't BBS Call -// Accept NNTP commands in either case -// Add NNTP BODY command -// Timeout POP or SMTP TCP connections that are open too long -// Add YAPP support -// Fix connect script when Node CTEXT contains "} BBS " -// Fix handling null H Route -// Detect and correct duplicate BBS Numbers -// Fix problem if BBS requests FBB blocked forwarding without compression (ie SID of F without B) -// Fix crash if YAPP entered without filenmame and send BBS prompt after YAPP error messages -// Add support for Winlink HTML Forms to WebMail interface -// Update B2 header when using NTS alias file with B2 messages - -// 6.0.18.1 January 2019 - -// Ensure callsigns in WP database are upper case. -// Various fixes for Webmail -// Fix sending direct to ampr.org addresses -// Use SYSOP Call as default for Webmail if set -// Preparations for 64 bit version - - -// 6.0.19.1 September 2019 - -// Trap missing HTML reply Template or HTML files -// Fix case problems in HTML Templates -// Fix setting To call on reply to HTML messages -// More preparations for 64 bit including saving WP info as a text file. -// Set "RMS Express User" when a new user connects using PAT -// Increace maximum length on Forwarding Alias string in Web interface -// Expand multiaddress messages from Winlink Express if "Don't add @Winlink.org" set or no RMS BBS -// Fix program error if READ used without a filename -// Trap reject messages from Winlink CMS -// Fix "delete to recycle bin" on Linux -// Handle Radio Only Messages (-T or -R suffix on calling station) -// Fix program error on saving empty Alias list on Web Forwarding page -// Add REQDIR and REQFIL -// Experimental Blocked Uncompressed forwarding -// Security fix for YAPP -// Fix WebMail Cancel Send Message -// Fix processing Hold Message response from Winlink Express - -// 6.0.20.1 April 2020 - -// Improvments to YAPP -// Add Copy forwarding config -// Add Next and Previous buttons to Webmail message read screen -// Move HTML templates from HTMLPages to inline code. -// Fix Paclen on YAPP send -// Fix bug in handling "RMS Express User" -// Fix WINPACK compressed forwarding -// Add option to send P messages to more than one BBS -// Add "Default to Don't Add WINLINK.ORG" Config option -// Re-read Badwords.sys during Housekeeping -// Add BID Hold and Reject Filters -// On SMTP Send try HELO if EHLO rejected -// Allow SID response timeout to be configured per BBS -// Fix sending bulls with PAT -// Set "Forward Messages to BBS Call" when routing Bulls on TO -// Add option to send Mail For Message to APRS -// Fix WP update -// Fix Holding messages from Webmail Interface -// Add RMR command -// Add REROUTEMSGS BBS SYSOP command -// Disable null passwords and check Exclude flag in Webmail Signin -// Add basic Webmail logging - -// 6.0.21.1 December 2020 - -// Remove nulls from displayed messages. -// Fix Holding messages from SMTP and POP3 Interfaces -// Various fixes for handling messages to/from Internet email addresses -// Fix saving Email From field in Manage Messages -// Fix sending WL2K traffic reports via TriMode. -// Fix removing successive CR from Webmail Message display -// Fix Wildcarded @ forwarding -// Fix message type when receiving NTS Msgs form Airmail -// Fix address on SERVICE messages from Winlink -// Add multiple TO processing to Webmail non-template messages -// Don't backup config file if reading it fails -// Include Port and Freq on Connected log record -// Make sure welcome mesages don't end in > -// Allow flagging unread T messages as Delivered -// Replace \ with # in forward script so commands starting with # can be sent -// Fix forwarding NTS on TO field -// Fix possible crash in text mode forwarding -// Allow decimals of days in P message lifetimes and allow Houskeeping interval to be configured -// Add DOHOUSEKEEPING sysop command -// Add MARS continent code -// Try to trap 'zombie' BBS Sessions -// On Linux if "Delete to Recycle Bin" is set move deleted messages and logs to directory Deleted under current directory. -// Fix corruption of message length when reading R2 message via Read command -// Fix paging on List command and add new combinations of List options -// Fix NNTP list and LC command when bulls are killed - -// 6.0.22.1 August 2021 - -// Fix flagging messages with attachments as read. -// Fix possible corruption of WP database and subsequent crash on reloading. -// Fix format of Web Manage Messages display -// Include SETNEXTMESSAGENUMBER in SYSOP Help Message -// Fix occasional "Incoming Connect from SWITCH" -// Fix L> with numeric dests -// Improved diagnostic for MailTCP select() error. -// Clear "RMS Express User" if user is changed to a BBS -// Fix saving Window positions on exit -// Fix parsing ReplyTemplate name in Webmail -// Handle multiple addressees for WebMail Forms messages to packet stations -// Add option to allow only known users to connect -// Add basic callsign validation to From address -// Add option to forward a user's messages to Winlink -// Move User config to main config file. -// Update message status whne reading a Forms Webmail message -// Speed up killing multiple messages -// Allow SendWL2KFW as well as the (incorrect)SendWL2KPM command - -// 6.0.23.1 June 2022 - -// Fix crash when ; added to call in send commands -// Allow smtp/ override for messages from RMS Express to send via ISP gateway -// Send Internet email from RMS Express to ISP Gateway if enabled and RMS BBS not configured -// Recompiled for Web Interface changes in Node -// Add RMS Relay SYNC Mode (.17) -// Add Protocol changes for Relay RO forwarding -// Add SendWL2KPM command to connect script to allow users other than RMS to send ;FW: string to RMS Relay -// Fix B2 Header Date in Webmail message with sttachments. -// Fix bug when using YAPP with VARA (.27) -// Allow SendWL2KFW as well as the (incorrect)SendWL2KPM command -// Add mechsnism to send bbs log records to qttermtcp. (32) -// Add MFJ forwarding Mode (No @BBS on send) -// Fix handling CR/LF split over packet boundaries -// Add Header and Footers for Webmail Send (42) -// Fix Maintenance Interval in LinBPQ (53) -// Add RMS: to valid from addresses (.56) -// Fix Web management on Android deviced (.58) -// Disconnect immediately if "Invalid Command" "*** Protocol Error" or "Already Connected" received (.70) -// Check Badword and Reject filters before processing WP Messages - -// 6.0.24.1 ?? 2022 - -// Fix ' in Webmail subject (8) -// Change web buttons to white on black when pressed (10) -// Add auto-refresh option to Webmail index page (25) -// Fix displaying help and info files with crlf line endings on Linux (28) -// Improve validation of extended FC message (32) -// Improve WP check for SYSTEM as a callsign (33) -// Improvements to RMS Relay SYNC mode (47) -// Fix BID Hold and Reject filters -// Fix Webmail auto-refresh when page exceeds 64K bytes (54) -// Fix Webmail send when using both headers/footers and attachmonts (55) -// Fix R: line corruption on some 64 bit builds -// Dont drop empty lines inm TEXTFORWARDING (61) -// Dont wait for body prompt for TEXTFORWARDING for SID [PMS-3.2-C$] (62) -// Add forwarding mode SETCALLTOSENDER for PMS Systems that don't accept < in SP (63) -// QtTerm Monitoring fixed for 63 port version of BPQ (69) - - -#include "bpqmail.h" -#include "winstdint.h" -#define MAIL -#include "Versions.h" - -#include "GetVersion.h" - -#define MAX_LOADSTRING 100 - -typedef int (WINAPI FAR *FARPROCX)(); -typedef int (WINAPI FAR *FARPROCZ)(); - -FARPROCX pDllBPQTRACE; -FARPROCZ pGetLOC; -FARPROCX pRefreshWebMailIndex; -FARPROCX pRunEventProgram; - -BOOL WINE = FALSE; - -INT_PTR CALLBACK UserEditDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); -INT_PTR CALLBACK MsgEditDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); -INT_PTR CALLBACK FwdEditDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); -INT_PTR CALLBACK WPEditDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); - -VOID SetupNTSAliases(char * FN); - -HKEY REGTREE = HKEY_LOCAL_MACHINE; // Default -char * REGTREETEXT = "HKEY_LOCAL_MACHINE"; - -// Global Variables: -HINSTANCE hInst; // current instance -TCHAR szTitle[MAX_LOADSTRING]; // The title bar text -TCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name - -extern int LastVer[4]; // In case we need to do somthing the first time a version is run - -UINT BPQMsg; - -HWND MainWnd; -HWND hWndSess; -RECT MainRect; -HMENU hActionMenu; -static HMENU hMenu; -HMENU hDisMenu; // Disconnect Menu Handle -HMENU hFWDMenu; // Forward Menu Handle - -int SessX, SessY, SessWidth; // Params for Session Window - -char szBuff[80]; - -#define MaxSockets 64 - -int _MYTIMEZONE = 0; - -ConnectionInfo Connections[MaxSockets+1]; - -//struct SEM AllocSemaphore = {0, 0}; -//struct SEM ConSemaphore = {0, 0}; -//struct SEM OutputSEM = {0, 0}; - -//struct UserInfo ** UserRecPtr=NULL; -//int NumberofUsers=0; - -//struct UserInfo * BBSChain = NULL; // Chain of users that are BBSes - -//struct MsgInfo ** MsgHddrPtr=NULL; -//int NumberofMessages=0; - -//int FirstMessageIndextoForward=0; // Lowest Message wirh a forward bit set - limits search - -//BIDRec ** BIDRecPtr=NULL; -//int NumberofBIDs=0; - -extern BIDRec ** TempBIDRecPtr; -//int NumberofTempBIDs=0; - -//WPRec ** WPRecPtr=NULL; -//int NumberofWPrecs=0; - -extern char ** BadWords; -//int NumberofBadWords=0; -extern char * BadFile; - -//int LatestMsg = 0; -//struct SEM MsgNoSemaphore = {0, 0}; // For locking updates to LatestMsg -//int HighestBBSNumber = 0; - -//int MaxMsgno = 60000; -//int BidLifetime = 60; -//int MaintInterval = 24; -//int MaintTime = 0; -//int UserLifetime = 0; - - -BOOL cfgMinToTray; - -BOOL DisconnectOnClose; - -extern char PasswordMsg[100]; - -char cfgHOSTPROMPT[100]; - -char cfgCTEXT[100]; - -char cfgLOCALECHO[100]; - -char AttemptsMsg[]; -char disMsg[]; - -char LoginMsg[]; - -char BlankCall[]; - - -ULONG BBSApplMask; -ULONG ChatApplMask; - -int BBSApplNum; - -//int StartStream=0; -int NumberofStreams; -int MaxStreams; - -extern char BBSSID[]; -extern char ChatSID[]; - -extern char NewUserPrompt[100]; - -extern char * WelcomeMsg; -extern char * NewWelcomeMsg; -extern char * ExpertWelcomeMsg; - -extern char * Prompt; -extern char * NewPrompt; -extern char * ExpertPrompt; - -extern BOOL DontNeedHomeBBS; - -char BBSName[100]; -char MailForText[100]; - -char SignoffMsg[100]; - -char AbortedMsg[100]; - -extern char UserDatabaseName[MAX_PATH]; -extern char UserDatabasePath[MAX_PATH]; - -extern char MsgDatabasePath[MAX_PATH]; -extern char MsgDatabaseName[MAX_PATH]; - -extern char BIDDatabasePath[MAX_PATH]; -extern char BIDDatabaseName[MAX_PATH]; - -extern char WPDatabasePath[MAX_PATH]; -extern char WPDatabaseName[MAX_PATH]; - -extern char BadWordsPath[MAX_PATH]; -extern char BadWordsName[MAX_PATH]; - -char NTSAliasesPath[MAX_PATH]; -extern char NTSAliasesName[MAX_PATH]; - -char BaseDir[MAX_PATH]; -char BaseDirRaw[MAX_PATH]; // As set in registry - may contain %NAME% - -char MailDir[MAX_PATH]; - -char RlineVer[50]; - -extern BOOL KISSOnly; - -extern BOOL OpenMon; - -extern struct ALIAS ** NTSAliases; - -extern int EnableUI; -extern int RefuseBulls; -extern int SendSYStoSYSOPCall; -extern int SendBBStoSYSOPCall; -extern int DontHoldNewUsers; -extern int ForwardToMe; - -extern int MailForInterval; - -char zeros[NBMASK]; // For forward bitmask tests - -time_t MaintClock; // Time to run housekeeping - -struct MsgInfo * MsgnotoMsg[100000]; // Message Number to Message Slot List. - -// Filter Params - -char ** RejFrom; // Reject on FROM Call -char ** RejTo; // Reject on TO Call -char ** RejAt; // Reject on AT Call -char ** RejBID; // Reject on BID - -char ** HoldFrom; // Hold on FROM Call -char ** HoldTo; // Hold on TO Call -char ** HoldAt; // Hold on AT Call -char ** HoldBID; // Hold on BID - - -// Send WP Params - -BOOL SendWP; -char SendWPVIA[81]; -char SendWPTO[11]; -int SendWPType; - - -int ProgramErrors = 0; - -UCHAR BPQDirectory[260] = ""; - - -// Forward declarations of functions included in this code module: -ATOM MyRegisterClass(HINSTANCE hInstance); -ATOM RegisterMainWindowClass(HINSTANCE hInstance); -BOOL InitInstance(HINSTANCE, int); -LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); -INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM); -INT_PTR CALLBACK ClpMsgDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); -INT_PTR CALLBACK SendMsgDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); -INT_PTR CALLBACK ChatMapDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); - -unsigned long _beginthread( void( *start_address )(VOID * DParam), - unsigned stack_size, VOID * DParam); - -VOID SendMailForThread(VOID * Param); -BOOL CreatePipeThread(); -int DeleteRedundantMessages(); -VOID BBSSlowTimer(); -VOID CopyConfigFile(char * ConfigName); -BOOL CreateMulticastConsole(); -char * CheckToAddress(CIRCUIT * conn, char * Addr); -BOOL CheckifPacket(char * Via); -int GetHTMLForms(); - -struct _EXCEPTION_POINTERS exinfox; - -CONTEXT ContextRecord; -EXCEPTION_RECORD ExceptionRecord; - -DWORD Stack[16]; - -BOOL Restarting = FALSE; - -Dump_Process_State(struct _EXCEPTION_POINTERS * exinfo, char * Msg) -{ - unsigned int SPPtr; - unsigned int SPVal; - - memcpy(&ContextRecord, exinfo->ContextRecord, sizeof(ContextRecord)); - memcpy(&ExceptionRecord, exinfo->ExceptionRecord, sizeof(ExceptionRecord)); - - SPPtr = ContextRecord.Esp; - - Debugprintf("BPQMail *** Program Error %x at %x in %s", - ExceptionRecord.ExceptionCode, ExceptionRecord.ExceptionAddress, Msg); - - - __asm{ - - mov eax, SPPtr - mov SPVal,eax - lea edi,Stack - mov esi,eax - mov ecx,64 - rep movsb - - } - - Debugprintf("EAX %x EBX %x ECX %x EDX %x ESI %x EDI %x ESP %x", - ContextRecord.Eax, ContextRecord.Ebx, ContextRecord.Ecx, - ContextRecord.Edx, ContextRecord.Esi, ContextRecord.Edi, SPVal); - - Debugprintf("Stack:"); - - Debugprintf("%08x %08x %08x %08x %08x %08x %08x %08x %08x ", - SPVal, Stack[0], Stack[1], Stack[2], Stack[3], Stack[4], Stack[5], Stack[6], Stack[7]); - - Debugprintf("%08x %08x %08x %08x %08x %08x %08x %08x %08x ", - SPVal+32, Stack[8], Stack[9], Stack[10], Stack[11], Stack[12], Stack[13], Stack[14], Stack[15]); - -} - - - -void myInvalidParameterHandler(const wchar_t* expression, - const wchar_t* function, - const wchar_t* file, - unsigned int line, - uintptr_t pReserved) -{ - Logprintf(LOG_DEBUG_X, NULL, '!', "*** Error **** C Run Time Invalid Parameter Handler Called"); - - if (expression && function && file) - { - Logprintf(LOG_DEBUG_X, NULL, '!', "Expression = %S", expression); - Logprintf(LOG_DEBUG_X, NULL, '!', "Function %S", function); - Logprintf(LOG_DEBUG_X, NULL, '!', "File %S Line %d", file, line); - } -} - -// If program gets too many program errors, it will restart itself and shut down - -VOID CheckProgramErrors() -{ - STARTUPINFO SInfo; // pointer to STARTUPINFO - PROCESS_INFORMATION PInfo; // pointer to PROCESS_INFORMATION - char ProgName[256]; - - if (Restarting) - exit(0); // Make sure can't loop in restarting - - ProgramErrors++; - - if (ProgramErrors > 25) - { - Restarting = TRUE; - - Logprintf(LOG_DEBUG_X, NULL, '!', "Too Many Program Errors - Closing"); - - if (cfgMinToTray) - { - DeleteTrayMenuItem(MainWnd); - if (ConsHeader[0]->hConsole) - DeleteTrayMenuItem(ConsHeader[0]->hConsole); - if (ConsHeader[1]->hConsole) - DeleteTrayMenuItem(ConsHeader[1]->hConsole); - if (hMonitor) - DeleteTrayMenuItem(hMonitor); - } - - SInfo.cb=sizeof(SInfo); - SInfo.lpReserved=NULL; - SInfo.lpDesktop=NULL; - SInfo.lpTitle=NULL; - SInfo.dwFlags=0; - SInfo.cbReserved2=0; - SInfo.lpReserved2=NULL; - - GetModuleFileName(NULL, ProgName, 256); - - Debugprintf("Attempting to Restart %s", ProgName); - - CreateProcess(ProgName, "MailChat.exe WAIT", NULL, NULL, FALSE, 0, NULL, NULL, &SInfo, &PInfo); - - exit(0); - } -} - - -VOID WriteMiniDump() -{ -#ifdef WIN32 - - HANDLE hFile; - BOOL ret; - char FN[256]; - - sprintf(FN, "%s/Logs/MiniDump%x.dmp", GetBPQDirectory(), time(NULL)); - - hFile = CreateFile(FN, GENERIC_READ | GENERIC_WRITE, - 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - - if((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE)) - { - // Create the minidump - - ret = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), - hFile, MiniDumpNormal, 0, 0, 0 ); - - if(!ret) - Debugprintf("MiniDumpWriteDump failed. Error: %u", GetLastError()); - else - Debugprintf("Minidump %s created.", FN); - CloseHandle(hFile); - } -#endif -} - - -void GetSemaphore(struct SEM * Semaphore, int ID) -{ - // - // Wait for it to be free - // -#ifdef WIN32 - if (Semaphore->Flag != 0) - { - Semaphore->Clashes++; - } -loop1: - - while (Semaphore->Flag != 0) - { - Sleep(10); - } - - // - // try to get semaphore - // - - _asm{ - - mov eax,1 - mov ebx, Semaphore - xchg [ebx],eax // this instruction is locked - - cmp eax,0 - jne loop1 // someone else got it - try again -; -; ok, weve got the semaphore -; - } -#else - - while (Semaphore->Flag) - usleep(10000); - - Semaphore->Flag = 1; - -#endif - return; -} - -void FreeSemaphore(struct SEM * Semaphore) -{ - Semaphore->Flag = 0; - - return; -} - -char * CmdLine; - -extern int configSaved; - -int APIENTRY WinMain(HINSTANCE hInstance, - HINSTANCE hPrevInstance, - LPTSTR lpCmdLine, - int nCmdShow) -{ - MSG msg; - HACCEL hAccelTable; - int BPQStream, n; - struct UserInfo * user; - struct _EXCEPTION_POINTERS exinfo; - _invalid_parameter_handler oldHandler, newHandler; - char Msg[100]; - int i = 60; - struct NNTPRec * NNTPREC; - struct NNTPRec * SaveNNTPREC; - - CmdLine = _strdup(lpCmdLine); - _strlwr(CmdLine); - - if (_stricmp(lpCmdLine, "Wait") == 0) // If AutoRestart then Delay 60 Secs - { - hWnd = CreateWindow("STATIC", "Mail Restarting after Failure - Please Wait", 0, - CW_USEDEFAULT, 100, 550, 70, - NULL, NULL, hInstance, NULL); - - ShowWindow(hWnd, nCmdShow); - - while (i-- > 0) - { - sprintf(Msg, "Mail Restarting after Failure - Please Wait %d secs.", i); - SetWindowText(hWnd, Msg); - - Sleep(1000); - } - - DestroyWindow(hWnd); - } - - __try { - - // Trap CRT Errors - - newHandler = myInvalidParameterHandler; - oldHandler = _set_invalid_parameter_handler(newHandler); - - // Initialize global strings - LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); - LoadString(hInstance, IDC_BPQMailChat, szWindowClass, MAX_LOADSTRING); - MyRegisterClass(hInstance); - - // Perform application initialization: - - if (!InitInstance (hInstance, nCmdShow)) - { - return FALSE; - } - - hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_BPQMailChat)); - - // Main message loop: - - Logprintf(LOG_DEBUG_X, NULL, '!', "Program Starting"); - Logprintf(LOG_BBS, NULL, '!', "BPQMail Starting"); - Debugprintf("BPQMail Starting"); - - if (pDllBPQTRACE == 0) - Logprintf(LOG_BBS, NULL, '!', "Remote Monitor Log not available - update BPQ32.dll to enable"); - - - } My__except_Routine("Init"); - - while (GetMessage(&msg, NULL, 0, 0)) - { - __try - { - if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - } - #define EXCEPTMSG "GetMessageLoop" - #include "StdExcept.c" - - CheckProgramErrors(); - } - } - - __try - { - for (n = 0; n < NumberofStreams; n++) - { - BPQStream=Connections[n].BPQStream; - - if (BPQStream) - { - SetAppl(BPQStream, 0, 0); - Disconnect(BPQStream); - DeallocateStream(BPQStream); - } - } - - - hWnd = CreateWindow("STATIC", "Mail Closing - Please Wait", 0, - 150, 200, 350, 40, NULL, NULL, hInstance, NULL); - - ShowWindow(hWnd, nCmdShow); - - Sleep(1000); // A bit of time for links to close - - DestroyWindow(hWnd); - - if (ConsHeader[0]->hConsole) - DestroyWindow(ConsHeader[0]->hConsole); - if (ConsHeader[1]->hConsole) - DestroyWindow(ConsHeader[1]->hConsole); - if (hMonitor) - { - DestroyWindow(hMonitor); - hMonitor = (HWND)1; // For status Save - } - - -// SaveUserDatabase(); - SaveMessageDatabase(); - SaveBIDDatabase(); - - configSaved = 1; - SaveConfig(ConfigName); - - if (cfgMinToTray) - { - DeleteTrayMenuItem(MainWnd); - if (ConsHeader[0]->hConsole) - DeleteTrayMenuItem(ConsHeader[0]->hConsole); - if (ConsHeader[1]->hConsole) - DeleteTrayMenuItem(ConsHeader[1]->hConsole); - if (hMonitor) - DeleteTrayMenuItem(hMonitor); - } - - // Free all allocated memory - - for (n = 0; n <= NumberofUsers; n++) - { - user = UserRecPtr[n]; - - if (user->ForwardingInfo) - { - FreeForwardingStruct(user); - free(user->ForwardingInfo); - } - - free(user->Temp); - - free(user); - } - - free(UserRecPtr); - - for (n = 0; n <= NumberofMessages; n++) - free(MsgHddrPtr[n]); - - free(MsgHddrPtr); - - for (n = 0; n <= NumberofWPrecs; n++) - free(WPRecPtr[n]); - - free(WPRecPtr); - - for (n = 0; n <= NumberofBIDs; n++) - free(BIDRecPtr[n]); - - free(BIDRecPtr); - - if (TempBIDRecPtr) - free(TempBIDRecPtr); - - NNTPREC = FirstNNTPRec; - - while (NNTPREC) - { - SaveNNTPREC = NNTPREC->Next; - free(NNTPREC); - NNTPREC = SaveNNTPREC; - } - - if (BadWords) free(BadWords); - if (BadFile) free(BadFile); - - n = 0; - - if (Aliases) - { - while(Aliases[n]) - { - free(Aliases[n]->Dest); - free(Aliases[n]); - n++; - } - - free(Aliases); - FreeList(AliasText); - } - - n = 0; - - if (NTSAliases) - { - while(NTSAliases[n]) - { - free(NTSAliases[n]->Dest); - free(NTSAliases[n]); - n++; - } - - free(NTSAliases); - } - - FreeOverrides(); - - FreeList(RejFrom); - FreeList(RejTo); - FreeList(RejAt); - FreeList(RejBID); - FreeList(HoldFrom); - FreeList(HoldTo); - FreeList(HoldAt); - FreeList(HoldBID); - FreeList(SendWPAddrs); - - Free_UI(); - - for (n=1; n<20; n++) - { - if (MyElements[n]) free(MyElements[n]); - } - - free(WelcomeMsg); - free(NewWelcomeMsg); - free(ExpertWelcomeMsg); - - free(Prompt); - free(NewPrompt); - free(ExpertPrompt); - - FreeWebMailMallocs(); - - free(CmdLine); - - _CrtDumpMemoryLeaks(); - - } - My__except_Routine("Close Processing"); - - CloseBPQ32(); // Close Ext Drivers if last bpq32 process - - return (int) msg.wParam; -} - - - -// -// FUNCTION: MyRegisterClass() -// -// PURPOSE: Registers the window class. -// -// COMMENTS: -// -// This function and its usage are only necessary if you want this code -// to be compatible with Win32 systems prior to the 'RegisterClassEx' -// function that was added to Windows 95. It is important to call this function -// so that the application will get 'well formed' small icons associated -// with it. -// -// -#define BGCOLOUR RGB(236,233,216) -//#define BGCOLOUR RGB(245,245,245) - -HBRUSH bgBrush; - -ATOM MyRegisterClass(HINSTANCE hInstance) -{ - WNDCLASSEX wcex; - - bgBrush = CreateSolidBrush(BGCOLOUR); - - wcex.cbSize = sizeof(WNDCLASSEX); - - wcex.style = CS_HREDRAW | CS_VREDRAW; - wcex.lpfnWndProc = WndProc; - wcex.cbClsExtra = 0; - wcex.cbWndExtra = DLGWINDOWEXTRA; - wcex.hInstance = hInstance; - wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(BPQICON)); - wcex.hCursor = LoadCursor(NULL, IDC_ARROW); - wcex.hbrBackground = bgBrush; - wcex.lpszMenuName = MAKEINTRESOURCE(IDC_BPQMailChat); - wcex.lpszClassName = szWindowClass; - wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(BPQICON)); - - return RegisterClassEx(&wcex); -} - - -// -// FUNCTION: InitInstance(HINSTANCE, int) -// -// PURPOSE: Saves instance handle and creates main window -// -// COMMENTS: -// -// In this function, we save the instance handle in a global variable and -// create and display the main program window. -// - -HWND hWnd; - -int AXIPPort = 0; - -char LOC[7] = ""; - -BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) -{ - char Title[80]; - WSADATA WsaData; - HMENU hTopMenu; // handle of menu - HKEY hKey=0; - int retCode; - RECT InitRect; - RECT SessRect; - struct _EXCEPTION_POINTERS exinfo; - - HMODULE ExtDriver = LoadLibrary("bpq32.dll"); - - if (ExtDriver) - { - pDllBPQTRACE = GetProcAddress(ExtDriver,"_DllBPQTRACE@8"); - pGetLOC = GetProcAddress(ExtDriver,"_GetLOC@0"); - pRefreshWebMailIndex = GetProcAddress(ExtDriver,"_RefreshWebMailIndex@0"); - pRunEventProgram = GetProcAddress(ExtDriver,"_RunEventProgram@8"); - - if (pGetLOC) - { - char * pLOC = (char *)pGetLOC(); - memcpy(LOC, pLOC, 6); - } - } - - // See if running under WINE - - retCode = RegOpenKeyEx (HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine", 0, KEY_QUERY_VALUE, &hKey); - - if (retCode == ERROR_SUCCESS) - { - RegCloseKey(hKey); - WINE =TRUE; - Debugprintf("Running under WINE"); - } - - - REGTREE = GetRegistryKey(); - REGTREETEXT = GetRegistryKeyText(); - - Sleep(1000); - - { - int n; - struct _EXTPORTDATA * PORTVEC; - - KISSOnly = TRUE; - - for (n=1; n <= GetNumberofPorts(); n++) - { - PORTVEC = (struct _EXTPORTDATA * )GetPortTableEntryFromSlot(n); - - if (PORTVEC->PORTCONTROL.PORTTYPE == 16) // EXTERNAL - { - if (_memicmp(PORTVEC->PORT_DLL_NAME, "TELNET", 6) == 0) - KISSOnly = FALSE; - - if (PORTVEC->PORTCONTROL.PROTOCOL != 10) // Pactor/WINMOR - KISSOnly = FALSE; - - if (AXIPPort == 0) - { - if (_memicmp(PORTVEC->PORT_DLL_NAME, "BPQAXIP", 7) == 0) - { - AXIPPort = PORTVEC->PORTCONTROL.PORTNUMBER; - KISSOnly = FALSE; - } - } - } - } - } - - hInst = hInstance; - - hWnd=CreateDialog(hInst,szWindowClass,0,NULL); - - if (!hWnd) - { - return FALSE; - } - - MainWnd = hWnd; - - GetVersionInfo(NULL); - - sprintf(Title,"G8BPQ Mail Server Version %s", VersionString); - - sprintf(RlineVer, "BPQ%s%d.%d.%d", (KISSOnly) ? "K" : "", Ver[0], Ver[1], Ver[2]); - - SetWindowText(hWnd,Title); - - hWndSess = GetDlgItem(hWnd, 100); - - GetWindowRect(hWnd, &InitRect); - GetWindowRect(hWndSess, &SessRect); - - SessX = SessRect.left - InitRect.left ; - SessY = SessRect.top -InitRect.top; - SessWidth = SessRect.right - SessRect.left; - - // Get handles for updating menu items - - hTopMenu=GetMenu(MainWnd); - hActionMenu=GetSubMenu(hTopMenu,0); - - hFWDMenu=GetSubMenu(hActionMenu,0); - hMenu=GetSubMenu(hActionMenu,1); - hDisMenu=GetSubMenu(hActionMenu,2); - - CheckTimer(); - - cfgMinToTray = GetMinimizetoTrayFlag(); - - if ((nCmdShow == SW_SHOWMINIMIZED) || (nCmdShow == SW_SHOWMINNOACTIVE)) - if (cfgMinToTray) - { - ShowWindow(hWnd, SW_HIDE); - } - else - { - ShowWindow(hWnd, nCmdShow); - } - else - ShowWindow(hWnd, nCmdShow); - - UpdateWindow(hWnd); - - WSAStartup(MAKEWORD(2, 0), &WsaData); - - __try { - - return Initialise(); - - }My__except_Routine("Initialise"); - - return FALSE; -} - -// -// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM) -// -// PURPOSE: Processes messages for the main window. -// -// - - -LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - int wmId, wmEvent; - PAINTSTRUCT ps; - HDC hdc; - int state,change; - ConnectionInfo * conn; - struct _EXCEPTION_POINTERS exinfo; - - - if (message == BPQMsg) - { - if (lParam & BPQMonitorAvail) - { - __try - { - DoBBSMonitorData(wParam); - } - My__except_Routine("DoMonitorData"); - - return 0; - - } - if (lParam & BPQDataAvail) - { - // Dont trap error at this level - let Node error handler pick it up -// __try -// { - DoReceivedData(wParam); -// } -// My__except_Routine("DoReceivedData") - return 0; - } - if (lParam & BPQStateChange) - { - // Get current Session State. Any state changed is ACK'ed - // automatically. See BPQHOST functions 4 and 5. - - __try - { - SessionState(wParam, &state, &change); - - if (change == 1) - { - if (state == 1) // Connected - { - GetSemaphore(&ConSemaphore, 0); - __try {Connected(wParam);} - My__except_Routine("Connected"); - FreeSemaphore(&ConSemaphore); - } - else - { - GetSemaphore(&ConSemaphore, 0); - __try{Disconnected(wParam);} - My__except_Routine("Disconnected"); - FreeSemaphore(&ConSemaphore); - } - } - } - My__except_Routine("DoStateChange"); - - } - - return 0; - } - - - switch (message) - { - - case WM_KEYUP: - - switch (wParam) - { - case VK_F2: - CreateConsole(-1); - return 0; - - case VK_F3: - CreateMulticastConsole(); - return 0; - - case VK_F4: - CreateMonitor(); - return 0; - - case VK_TAB: - return TRUE; - - break; - - - - } - return 0; - - case WM_TIMER: - - if (wParam == 1) // Slow = 10 secs - { - __try - { - time_t NOW = time(NULL); - struct tm * tm; - RefreshMainWindow(); - CheckTimer(); - TCPTimer(); - BBSSlowTimer(); - FWDTimerProc(); - if (MaintClock < NOW) - { - while (MaintClock < NOW) // in case large time step - MaintClock += MaintInterval * 3600; - - Debugprintf("|Enter HouseKeeping"); - DoHouseKeeping(FALSE); - } - tm = gmtime(&NOW); - - if (tm->tm_wday == 0) // Sunday - { - if (GenerateTrafficReport && (LastTrafficTime + 86400) < NOW) - { - CreateBBSTrafficReport(); - LastTrafficTime = NOW; - } - } - } - My__except_Routine("Slow Timer"); - } - else - __try - { - TrytoSend(); - TCPFastTimer(); - } - My__except_Routine("TrytoSend"); - - return (0); - - - case WM_CTLCOLORDLG: - return (LONG)bgBrush; - - case WM_CTLCOLORSTATIC: - { - HDC hdcStatic = (HDC)wParam; - SetTextColor(hdcStatic, RGB(0, 0, 0)); - SetBkMode(hdcStatic, TRANSPARENT); - return (LONG)bgBrush; - } - - case WM_INITMENUPOPUP: - - if (wParam == (WPARAM)hActionMenu) - { - if (IsClipboardFormatAvailable(CF_TEXT)) - EnableMenuItem(hActionMenu,ID_ACTIONS_SENDMSGFROMCLIPBOARD, MF_BYCOMMAND | MF_ENABLED); - else - EnableMenuItem(hActionMenu,ID_ACTIONS_SENDMSGFROMCLIPBOARD, MF_BYCOMMAND | MF_GRAYED ); - - return TRUE; - } - - if (wParam == (WPARAM)hFWDMenu) - { - // Set up Forward Menu - - struct UserInfo * user; - char MenuLine[30]; - - for (user = BBSChain; user; user = user->BBSNext) - { - sprintf(MenuLine, "%s %d Msgs", user->Call, CountMessagestoForward(user)); - - if (ModifyMenu(hFWDMenu, IDM_FORWARD_ALL + user->BBSNumber, - MF_BYCOMMAND | MF_STRING, IDM_FORWARD_ALL + user->BBSNumber, MenuLine) == 0) - - AppendMenu(hFWDMenu, MF_STRING,IDM_FORWARD_ALL + user->BBSNumber, MenuLine); - } - return TRUE; - } - - if (wParam == (WPARAM)hDisMenu) - { - // Set up Disconnect Menu - - CIRCUIT * conn; - char MenuLine[30]; - int n; - - for (n = 0; n <= NumberofStreams-1; n++) - { - conn=&Connections[n]; - - RemoveMenu(hDisMenu, IDM_DISCONNECT + n, MF_BYCOMMAND); - - if (conn->Active) - { - sprintf_s(MenuLine, 30, "%d %s", conn->BPQStream, conn->Callsign); - AppendMenu(hDisMenu, MF_STRING, IDM_DISCONNECT + n, MenuLine); - } - } - return TRUE; - } - break; - - - case WM_COMMAND: - wmId = LOWORD(wParam); - wmEvent = HIWORD(wParam); - // Parse the menu selections: - - if (wmEvent == LBN_DBLCLK) - - break; - - if (wmId >= IDM_DISCONNECT && wmId < IDM_DISCONNECT+MaxSockets+1) - { - // disconnect user - - conn=&Connections[wmId-IDM_DISCONNECT]; - - if (conn->Active) - { - Disconnect(conn->BPQStream); - } - } - - if (wmId >= IDM_FORWARD_ALL && wmId < IDM_FORWARD_ALL + 100) - { - StartForwarding(wmId - IDM_FORWARD_ALL, NULL); - return 0; - } - - switch (wmId) - { - case IDM_LOGBBS: - - ToggleParam(hMenu, hWnd, &LogBBS, IDM_LOGBBS); - break; - - case IDM_LOGCHAT: - - ToggleParam(hMenu, hWnd, &LogCHAT, IDM_LOGCHAT); - break; - - case IDM_LOGTCP: - - ToggleParam(hMenu, hWnd, &LogTCP, IDM_LOGTCP); - break; - - case IDM_HOUSEKEEPING: - - DoHouseKeeping(TRUE); - - break; - - case IDM_CONSOLE: - - CreateConsole(-1); - break; - - case IDM_MCMONITOR: - - CreateMulticastConsole(); - break; - - case IDM_MONITOR: - - CreateMonitor(); - break; - - case RESCANMSGS: - - ReRouteMessages(); - break; - - case IDM_IMPORT: - - ImportMessages(NULL, "", FALSE); - break; - - case IDM_ABOUT: - DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); - break; - - case ID_HELP_ONLINEHELP: - - ShellExecute(hWnd,"open", - "http://www.cantab.net/users/john.wiseman/Documents/MailServer.html", - "", NULL, SW_SHOWNORMAL); - - break; - - case IDM_CONFIG: - DialogBox(hInst, MAKEINTRESOURCE(IDD_CONFIG), hWnd, ConfigWndProc); - break; - - case IDM_USERS: - DialogBox(hInst, MAKEINTRESOURCE(IDD_USEREDIT), hWnd, UserEditDialogProc); - break; - - case IDM_FWD: - DialogBox(hInst, MAKEINTRESOURCE(IDD_FORWARDING), hWnd, FwdEditDialogProc); - break; - - case IDM_MESSAGES: - DialogBox(hInst, MAKEINTRESOURCE(IDD_MSGEDIT), hWnd, MsgEditDialogProc); - break; - - case IDM_WP: - DialogBox(hInst, MAKEINTRESOURCE(IDD_EDITWP), hWnd, WPEditDialogProc); - break; - - case ID_ACTIONS_SENDMSGFROMCLIPBOARD: - DialogBox(hInst, MAKEINTRESOURCE(IDD_MSGFROMCLIPBOARD), hWnd, ClpMsgDialogProc); - break; - - case ID_ACTIONS_SENDMESSAGE: - DialogBox(hInst, MAKEINTRESOURCE(IDD_MSGFROMCLIPBOARD), hWnd, SendMsgDialogProc); - break; - - case ID_MULTICAST: - - MulticastRX = !MulticastRX; - CheckMenuItem(hActionMenu, ID_MULTICAST, (MulticastRX) ? MF_CHECKED : MF_UNCHECKED); - break; - - case IDM_EXIT: - DestroyWindow(hWnd); - break; - - - - default: - return DefWindowProc(hWnd, message, wParam, lParam); - } - break; - - case WM_SIZE: - - if (wParam == SIZE_MINIMIZED) - if (cfgMinToTray) - return ShowWindow(hWnd, SW_HIDE); - - return (0); - - - case WM_SIZING: - { - LPRECT lprc = (LPRECT) lParam; - int Height = lprc->bottom-lprc->top; - int Width = lprc->right-lprc->left; - - MoveWindow(hWndSess, 0, 30, SessWidth, Height - 100, TRUE); - - return TRUE; - } - - - case WM_PAINT: - hdc = BeginPaint(hWnd, &ps); - // TODO: Add any drawing code here... - EndPaint(hWnd, &ps); - break; - - case WM_DESTROY: - - GetWindowRect(MainWnd, &MainRect); // For save soutine - if (ConsHeader[0]->hConsole) - GetWindowRect(ConsHeader[0]->hConsole, &ConsHeader[0]->ConsoleRect); // For save soutine - if (ConsHeader[1]->hConsole) - GetWindowRect(ConsHeader[1]->hConsole, &ConsHeader[1]->ConsoleRect); // For save soutine - if (hMonitor) - GetWindowRect(hMonitor, &MonitorRect); // For save soutine - - KillTimer(hWnd,1); - KillTimer(hWnd,2); - PostQuitMessage(0); - break; - - default: - return DefWindowProc(hWnd, message, wParam, lParam); - } - return 0; -} - -INT_PTR CALLBACK SendMsgDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - switch (message) - { - case WM_INITDIALOG: - - SendDlgItemMessage(hDlg, IDC_MSGTYPE, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR) "B"); - SendDlgItemMessage(hDlg, IDC_MSGTYPE, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR) "P"); - SendDlgItemMessage(hDlg, IDC_MSGTYPE, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR) "T"); - - SendDlgItemMessage(hDlg, IDC_MSGTYPE, CB_SETCURSEL, 0, 0); - - return TRUE; - - case WM_SIZING: - { - HWND hWndEdit = GetDlgItem(hDlg, IDC_EDIT1); - - LPRECT lprc = (LPRECT) lParam; - int Height = lprc->bottom-lprc->top; - int Width = lprc->right-lprc->left; - - MoveWindow(hWndEdit, 5, 90, Width-20, Height - 140, TRUE); - - return TRUE; - } - - case WM_COMMAND: - - if (LOWORD(wParam) == IDSEND) - { - char status [3]; - struct MsgInfo * Msg; - char * via = NULL; - char BID[13]; - char FileList[32768]; - BIDRec * BIDRec; - int MsgLen; - char * MailBuffer; - char MsgFile[MAX_PATH]; - HANDLE hFile = INVALID_HANDLE_VALUE; - int WriteLen=0; - char HDest[61]; - char Destcopy[61]; - char * Vptr; - char * FileName[100]; - int FileLen[100]; - char * FileBody[100]; - int n, Files = 0; - int TotalFileSize = 0; - char * NewMsg; - - GetDlgItemText(hDlg, IDC_MSGTO, HDest, 60); - strcpy(Destcopy, HDest); - - GetDlgItemText(hDlg, IDC_MSGBID, BID, 13); - strlop(BID, ' '); - - GetDlgItemText(hDlg, IDC_ATTACHMENTS, FileList, 32767); - - // if there are attachments, check that they can be opened ane read - - n = 0; - - if (FileList[0]) - { - FILE * Handle; - struct stat STAT; - char * ptr1 = FileList, * ptr2; - - while(ptr1 && ptr1[0]) - { - ptr2 = strchr(ptr1, ';'); - - if (ptr2) - *(ptr2++) = 0; - - FileName[n++] = ptr1; - - ptr1 = ptr2; - } - - FileName[n] = 0; - - // read the files - - Files = n; - n = 0; - - while (FileName[n]) - { - if (stat(FileName[n], &STAT) == -1) - { - char ErrorMessage[512]; - sprintf(ErrorMessage,"Can't find file %s", FileName[n]); - MessageBox(NULL, ErrorMessage, "BPQMail", MB_ICONERROR); - return TRUE; - } - - FileLen[n] = STAT.st_size; - - Handle = fopen(FileName[n], "rb"); - - if (Handle == NULL) - { - char ErrorMessage[512]; - sprintf(ErrorMessage,"Can't open file %s", FileName[n]); - MessageBox(NULL, ErrorMessage, "BPQMail", MB_ICONERROR); - return TRUE; - } - - FileBody[n] = malloc(FileLen[n]+1); - - fread(FileBody[n], 1, FileLen[n], Handle); - - fclose(Handle); - - TotalFileSize += FileLen[n]; - n++; - } - } - - if (strlen(HDest) == 0) - { - MessageBox(NULL, "To: Call Missing!", "BPQMail", MB_ICONERROR); - return TRUE; - } - - if (strlen(BID)) - { - if (LookupBID(BID)) - { - // Duplicate bid - - MessageBox(NULL, "Duplicate BID", "BPQMail", MB_ICONERROR); - return TRUE; - } - } - - Msg = AllocateMsgRecord(); - - // Set number here so they remain in sequence - - Msg->number = ++LatestMsg; - MsgnotoMsg[Msg->number] = Msg; - - strcpy(Msg->from, SYSOPCall); - - Vptr = strlop(Destcopy, '@'); - - if (Vptr == 0 && strchr(Destcopy, '!')) // Bang route without @ - { - Vptr = strchr(Destcopy, '!'); - strcpy(Msg->via, Vptr); - strlop(Destcopy, '!'); - - if (strlen(Destcopy) > 6) - memcpy(Msg->to, Destcopy, 6); - else - strcpy(Msg->to, Destcopy); - goto gotAddr; - } - - if (strlen(Destcopy) > 6) - memcpy(Msg->to, Destcopy, 6); - else - strcpy(Msg->to, Destcopy); - - _strupr(Msg->to); - - if (_memicmp(HDest, "rms:", 4) == 0 || _memicmp(HDest, "rms/", 4) == 0) - { - Vptr = HDest; - memmove(HDest, &HDest[4], strlen(HDest)); - strcpy(Msg->to, "RMS"); - - } - else if (_memicmp(HDest, "smtp:", 5) == 0) - { - if (ISP_Gateway_Enabled) - { - Vptr = HDest; - memmove(HDest, &HDest[5], strlen(HDest)); - Msg->to[0] = 0; - } - } - else if (Vptr) - { - // If looks like a valid email address, treat as such - - int tolen = (Vptr - Destcopy) - 1; - - if (tolen > 6 || !CheckifPacket(Vptr)) - { - // Assume Email address - - Vptr = HDest; - - if (FindRMS() || strchr(Vptr, '!')) // have RMS or source route - strcpy(Msg->to, "RMS"); - else if (ISP_Gateway_Enabled) - Msg->to[0] = 0; - else - { - MessageBox(NULL, "Sending to Internet Email not available", "BPQMail", MB_ICONERROR); - return TRUE; - } - } - } - if (Vptr) - { - if (strlen(Vptr) > 40) - Vptr[40] = 0; - - strcpy(Msg->via, Vptr); - } -gotAddr: - GetDlgItemText(hDlg, IDC_MSGTITLE, Msg->title, 61); - GetDlgItemText(hDlg, IDC_MSGTYPE, status, 2); - Msg->type = status[0]; - Msg->status = 'N'; - - if (strlen(BID) == 0) - sprintf_s(BID, sizeof(BID), "%d_%s", LatestMsg, BBSName); - - strcpy(Msg->bid, BID); - - Msg->datereceived = Msg->datechanged = Msg->datecreated = time(NULL); - - BIDRec = AllocateBIDRecord(); - - strcpy(BIDRec->BID, Msg->bid); - BIDRec->mode = Msg->type; - BIDRec->u.msgno = LOWORD(Msg->number); - BIDRec->u.timestamp = LOWORD(time(NULL)/86400); - - MsgLen = SendDlgItemMessage(hDlg, IDC_EDIT1, WM_GETTEXTLENGTH, 0 ,0); - - MailBuffer = malloc(MsgLen + TotalFileSize + 2000); // Allow for a B2 Header if attachments - - if (Files) - { - char DateString[80]; - struct tm * tm; - - char Type[16] = "Private"; - - // Get Type - - if (Msg->type == 'B') - strcpy(Type, "Bulletin"); - else if (Msg->type == 'T') - strcpy(Type, "Traffic"); - - // Create a B2 Message - - // B2 Header - - NewMsg = MailBuffer + 1000; - - tm = gmtime((time_t *)&Msg->datecreated); - - sprintf(DateString, "%04d/%02d/%02d %02d:%02d", - tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min); - - // Remove last Source Route - - if (strchr(HDest, '!')) - { - char * bang = HDest + strlen(HDest); - - while (*(--bang) != '!'); // Find last ! - - *(bang) = 0; // remove it; - } - - NewMsg += sprintf(NewMsg, - "MID: %s\r\nDate: %s\r\nType: %s\r\nFrom: %s\r\nTo: %s\r\nSubject: %s\r\nMbo: %s\r\n", - Msg->bid, DateString, Type, Msg->from, HDest, Msg->title, BBSName); - - - NewMsg += sprintf(NewMsg, "Body: %d\r\n", MsgLen); - - for (n = 0; n < Files; n++) - { - char * p = FileName[n], * q; - - // Remove any path - - q = strchr(p, '\\'); - - while (q) - { - if (q) - *q++ = 0; - p = q; - q = strchr(p, '\\'); - } - - NewMsg += sprintf(NewMsg, "File: %d %s\r\n", FileLen[n], p); - } - - NewMsg += sprintf(NewMsg, "\r\n"); - GetDlgItemText(hDlg, IDC_EDIT1, NewMsg, MsgLen+1); - NewMsg += MsgLen; - NewMsg += sprintf(NewMsg, "\r\n"); - - for (n = 0; n < Files; n++) - { - memcpy(NewMsg, FileBody[n], FileLen[n]); - NewMsg += FileLen[n]; - free(FileBody[n]); - NewMsg += sprintf(NewMsg, "\r\n"); - } - - Msg->length = NewMsg - (MailBuffer + 1000); - NewMsg = MailBuffer + 1000; - Msg->B2Flags = B2Msg | Attachments; - } - - else - { - GetDlgItemText(hDlg, IDC_EDIT1, MailBuffer, MsgLen+1); - Msg->length = MsgLen; - NewMsg = MailBuffer; - } - - sprintf_s(MsgFile, sizeof(MsgFile), "%s/m_%06d.mes", MailDir, Msg->number); - - hFile = CreateFile(MsgFile, - GENERIC_WRITE, - FILE_SHARE_READ, - NULL, - CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL, - NULL); - - if (hFile != INVALID_HANDLE_VALUE) - { - WriteFile(hFile, NewMsg, Msg->length, &WriteLen, NULL); - CloseHandle(hFile); - } - - free(MailBuffer); - - MatchMessagetoBBSList(Msg, 0); - - BuildNNTPList(Msg); // Build NNTP Groups list - - SaveMessageDatabase(); - SaveBIDDatabase(); - - EndDialog(hDlg, LOWORD(wParam)); - - return TRUE; - } - - - if (LOWORD(wParam) == IDSelectFiles) - { - char FileNames[2048]; - char FullFileNames[32768]; - OPENFILENAME Ofn; - int err; - - FileNames[0] = 0; - - memset(&Ofn, 0, sizeof(Ofn)); - - Ofn.lStructSize = sizeof(OPENFILENAME); - Ofn.hInstance = hInst; - Ofn.hwndOwner = hDlg; - Ofn.lpstrFilter = NULL; - Ofn.lpstrFile= FileNames; - Ofn.nMaxFile = 2048; - Ofn.lpstrFileTitle = NULL; - Ofn.nMaxFileTitle = 0; - Ofn.lpstrInitialDir = (LPSTR)NULL; - Ofn.Flags = OFN_SHOWHELP | OFN_FILEMUSTEXIST | OFN_ALLOWMULTISELECT | OFN_EXPLORER; - Ofn.lpstrTitle = NULL;//; - - if (GetOpenFileName(&Ofn)) - { - // if one is selected, a single string is returned, if more than one, a single - // path, followed by all the strings, duuble null terminated. - - char * Names[101]; // Allow up to 100 names - int n = 0; - char * ptr = FileNames; - - while (*ptr) - { - Names[n++] = ptr; - ptr += strlen(ptr); - ptr++; - } - - GetDlgItemText(hDlg, IDC_ATTACHMENTS, FullFileNames, 32768); - - if (strlen(FullFileNames)) - strcat(FullFileNames, ";"); - - if (n == 1) - { - // Single Select - - strcat(FullFileNames, FileNames); - } - else - { - int i = 1; - - while(i < n) - { - strcat(FullFileNames, Names[0]); - strcat(FullFileNames, "\\"); - strcat(FullFileNames, Names[i]); - i++; - if (i < n) - strcat(FullFileNames, ";"); - } - } - SetDlgItemText(hDlg, IDC_ATTACHMENTS, FullFileNames); - } - else - err = GetLastError(); - return (INT_PTR)TRUE; - } - - - if (LOWORD(wParam) == IDCANCEL) - { - EndDialog(hDlg, LOWORD(wParam)); - return (INT_PTR)TRUE; - } - - return (INT_PTR)TRUE; - - break; - } - return (INT_PTR)FALSE; -} - -INT_PTR CALLBACK ClpMsgDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - HGLOBAL hglb; - LPTSTR lptstr; - - switch (message) - { - case WM_INITDIALOG: - - SetWindowText(hDlg, "Send Message from Clipboard"); - - if (!IsClipboardFormatAvailable(CF_TEXT)) - break; - - if (!OpenClipboard(hDlg)) - break; - - hglb = GetClipboardData(CF_TEXT); - - if (hglb != NULL) - { - lptstr = GlobalLock(hglb); - - if (lptstr != NULL) - { - SetDlgItemText(hDlg, IDC_EDIT1, lptstr); - GlobalUnlock(hglb); - } - } - CloseClipboard(); - } - - return SendMsgDialogProc(hDlg, message, wParam, lParam); - -} - -// Message handler for about box. -INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - UNREFERENCED_PARAMETER(lParam); - switch (message) - { - case WM_INITDIALOG: - return (INT_PTR)TRUE; - - case WM_COMMAND: - if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) - { - EndDialog(hDlg, LOWORD(wParam)); - return (INT_PTR)TRUE; - } - return (INT_PTR)TRUE; - - break; - } - return (INT_PTR)FALSE; -} - -SMTPMsgs = 0; - -int RefreshMainWindow() -{ - char msg[80]; - CIRCUIT * conn; - int i,n, SYSOPMsgs = 0, HeldMsgs = 0; - time_t now; - struct tm * tm; - char tim[20]; - - SendDlgItemMessage(MainWnd,100,LB_RESETCONTENT,0,0); - - SMTPMsgs = 0; - - for (n = 0; n < NumberofStreams; n++) - { - conn=&Connections[n]; - - if (!conn->Active) - { - strcpy(msg,"Idle"); - } - else - { - { - if (conn->UserPointer == 0) - strcpy(msg,"Logging in"); - else - { - i=sprintf_s(msg, sizeof(msg), "%-10s %-10s %2d %-10s%5d", - conn->UserPointer->Name, conn->UserPointer->Call, conn->BPQStream, - "BBS", conn->OutputQueueLength - conn->OutputGetPointer); - } - } - } - SendDlgItemMessage(MainWnd,100,LB_ADDSTRING,0,(LPARAM)msg); - } - - SetDlgItemInt(hWnd, IDC_MSGS, NumberofMessages, FALSE); - - 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++; - } - } - - SetDlgItemInt(hWnd, IDC_SYSOPMSGS, SYSOPMsgs, FALSE); - SetDlgItemInt(hWnd, IDC_HELD, HeldMsgs, FALSE); - SetDlgItemInt(hWnd, IDC_SMTP, SMTPMsgs, FALSE); - - SetDlgItemInt(hWnd, IDC_MSGSEM, MsgNoSemaphore.Clashes, FALSE); - SetDlgItemInt(hWnd, IDC_ALLOCSEM, AllocSemaphore.Clashes, FALSE); - SetDlgItemInt(hWnd, IDC_CONSEM, ConSemaphore.Clashes, FALSE); - - now = time(NULL); - - tm = gmtime(&now); - sprintf_s(tim, sizeof(tim), "%02d:%02d", tm->tm_hour, tm->tm_min); - SetDlgItemText(hWnd, IDC_UTC, tim); - - tm = localtime(&now); - sprintf_s(tim, sizeof(tim), "%02d:%02d", tm->tm_hour, tm->tm_min); - SetDlgItemText(hWnd, IDC_LOCAL, tim); - - - return 0; -} - -#define MAX_PENDING_CONNECTS 4 - -#define VERSION_MAJOR 2 -#define VERSION_MINOR 0 - -SOCKADDR_IN local_sin; /* Local socket - internet style */ - -PSOCKADDR_IN psin; - -SOCKET sock; - - - -BOOL Initialise() -{ - int i, len; - ConnectionInfo * conn; - struct UserInfo * user = NULL; - HKEY hKey=0; - char * ptr1; - int Attrs, ret; - char msg[500]; - TIME_ZONE_INFORMATION TimeZoneInformation; - struct stat STAT; - - GetTimeZoneInformation(&TimeZoneInformation); - - _tzset(); - _MYTIMEZONE = timezone; - _MYTIMEZONE = TimeZoneInformation.Bias * 60; - - // Register message for posting by BPQDLL - - BPQMsg = RegisterWindowMessage(BPQWinMsg); - - // See if we need to warn of possible problem with BaseDir moved by installer - - strcpy(BPQDirectory, GetBPQDirectory()); - - sprintf(BaseDir, "%s/BPQMailChat", BPQDirectory); - - len = strlen(BaseDir); - ptr1 = BaseDir; - - while (*ptr1) - { - if (*(ptr1) == '/') *(ptr1) = '\\'; - ptr1++; - } - - // Make Sure BASEDIR Exists - - Attrs = GetFileAttributes(BaseDir); - - if (Attrs == -1) - { - sprintf_s(msg, sizeof(msg), "Base Directory %s not found - should it be created?", BaseDir); - ret = MessageBox(NULL, msg, "BPQMail", MB_YESNO); - - if (ret == IDYES) - { - ret = CreateDirectory(BaseDir, NULL); - if (ret == 0) - { - MessageBox(NULL, "Failed to created Base Directory - exiting", "BPQMail", MB_ICONSTOP); - return FALSE; - } - } - else - { - MessageBox(NULL, "Can't Continue without a Base Directory - exiting", "BPQMailChat", MB_ICONSTOP); - return FALSE; - } - } - else - { - if (!(Attrs & FILE_ATTRIBUTE_DIRECTORY)) - { - sprintf_s(msg, sizeof(msg), "Base Directory %s is a file not a directory - exiting", BaseDir); - ret = MessageBox(NULL, msg, "BPQMail", MB_ICONSTOP); - - return FALSE; - } - } - - initUTF8(); - - // Set up file and directory names - - strcpy(UserDatabasePath, BaseDir); - strcat(UserDatabasePath, "\\"); - strcat(UserDatabasePath, UserDatabaseName); - - strcpy(MsgDatabasePath, BaseDir); - strcat(MsgDatabasePath, "\\"); - strcat(MsgDatabasePath, MsgDatabaseName); - - strcpy(BIDDatabasePath, BaseDir); - strcat(BIDDatabasePath, "\\"); - strcat(BIDDatabasePath, BIDDatabaseName); - - strcpy(WPDatabasePath, BaseDir); - strcat(WPDatabasePath, "\\"); - strcat(WPDatabasePath, WPDatabaseName); - - strcpy(BadWordsPath, BaseDir); - strcat(BadWordsPath, "\\"); - strcat(BadWordsPath, BadWordsName); - - strcpy(NTSAliasesPath, BaseDir); - strcat(NTSAliasesPath, "/"); - strcat(NTSAliasesPath, NTSAliasesName); - - strcpy(MailDir, BaseDir); - strcat(MailDir, "\\"); - strcat(MailDir, "Mail"); - - CreateDirectory(MailDir, NULL); // Just in case - - strcpy(ConfigName, BaseDir); - strcat(ConfigName, "\\"); - strcat(ConfigName, "BPQMail.cfg"); - - UsingingRegConfig = FALSE; - - // if config file exists use it else try to get from Registry - - if (stat(ConfigName, &STAT) == -1) - { - UsingingRegConfig = TRUE; - - if (GetConfigFromRegistry()) - { - SaveConfig(ConfigName); - } - else - { - int retCode; - - strcpy(BBSName, GetNodeCall()); - strlop(BBSName, '-'); - strlop(BBSName, ' '); - - sprintf(msg, "No configuration found - Dummy Config created"); - - retCode = MessageBox(NULL, msg, "BPQMailChat", MB_OKCANCEL); - - if (retCode == IDCANCEL) - return FALSE; - - SaveConfig(ConfigName); - } - } - - if (GetConfig(ConfigName) == EXIT_FAILURE) - { - ret = MessageBox(NULL, - "BBS Config File seems corrupt - check before continuing", "BPQMail", MB_ICONSTOP); - return FALSE; - } - - // Got a Config File - - if (MainRect.right < 100 || MainRect.bottom < 100) - { - GetWindowRect(MainWnd, &MainRect); - } - - MoveWindow(MainWnd, MainRect.left, MainRect.top, MainRect.right-MainRect.left, MainRect.bottom-MainRect.top, TRUE); - - if (OpenMon) - CreateMonitor(); - - BBSApplMask = 1<<(BBSApplNum-1); - - ShowWindow(GetDlgItem(MainWnd, 901), SW_HIDE); - ShowWindow(GetDlgItem(MainWnd, 902), SW_HIDE); - ShowWindow(GetDlgItem(MainWnd, 903), SW_HIDE); - - // Make backup copies of Databases - - CopyBIDDatabase(); - CopyMessageDatabase(); - CopyUserDatabase(); - CopyWPDatabase(); - - SetupMyHA(); - SetupFwdAliases(); - SetupNTSAliases(NTSAliasesPath); - - GetWPDatabase(); - GetMessageDatabase(); - GetUserDatabase(); - GetBIDDatabase(); - GetBadWordFile(); - GetHTMLForms(); - - UsingingRegConfig = FALSE; - - // Make sure SYSOPCALL is set - - if (SYSOPCall[0] == 0) - strcpy(SYSOPCall, BBSName); - - // Make sure there is a user record for the BBS, with BBS bit set. - - user = LookupCall(BBSName); - - if (user == NULL) - { - user = AllocateUserRecord(BBSName); - user->Temp = zalloc(sizeof (struct TempUserInfo)); - } - - if ((user->flags & F_BBS) == 0) - { - // Not Defined as a BBS - - if (SetupNewBBS(user)) - user->flags |= F_BBS; - } - - // if forwarding AMPR mail make sure User/BBS AMPR exists - - if (SendAMPRDirect) - { - BOOL NeedSave = FALSE; - - user = LookupCall("AMPR"); - - if (user == NULL) - { - user = AllocateUserRecord("AMPR"); - user->Temp = zalloc(sizeof (struct TempUserInfo)); - NeedSave = TRUE; - } - - if ((user->flags & F_BBS) == 0) - { - // Not Defined as a BBS - - if (SetupNewBBS(user)) - user->flags |= F_BBS; - NeedSave = TRUE; - } - - if (NeedSave) - SaveUserDatabase(); - } - - // Allocate Streams - - for (i=0; i < MaxStreams; i++) - { - conn = &Connections[i]; - conn->BPQStream = FindFreeStream(); - - if (conn->BPQStream == 255) break; - - NumberofStreams++; - - BPQSetHandle(conn->BPQStream, hWnd); - - SetAppl(conn->BPQStream, (i == 0 && EnableUI) ? 0x82 : 2, BBSApplMask | ChatApplMask); - Disconnect(conn->BPQStream); - } - - InitialiseTCP(); - - InitialiseNNTP(); - - SetupListenSet(); // Master set of listening sockets - - if (BBSApplNum) - { - SetupUIInterface(); - if (MailForInterval) - _beginthread(SendMailForThread, 0, 0); - } - - if (cfgMinToTray) - { - AddTrayMenuItem(MainWnd, "Mail Server"); - } - - SetTimer(hWnd,1,10000,NULL); // Slow Timer (10 Secs) - SetTimer(hWnd,2,100,NULL); // Send to Node and TCP Poll (100 ms) - - // Calulate time to run Housekeeping - { - struct tm *tm; - time_t now; - - now = time(NULL); - - tm = gmtime(&now); - - tm->tm_hour = MaintTime / 100; - tm->tm_min = MaintTime % 100; - tm->tm_sec = 0; - - MaintClock = _mkgmtime(tm); - - while (MaintClock < now) - MaintClock += MaintInterval * 3600; - - Debugprintf("Maint Clock %lld NOW %lld Time to HouseKeeping %lld", (long long)MaintClock, (long long)now, (long long)(MaintClock - now)); - - if (LastHouseKeepingTime) - { - if ((now - LastHouseKeepingTime) > MaintInterval * 3600) - { - DoHouseKeeping(FALSE); - } - } - } - - if (strstr(CmdLine, "tidymail")) - DeleteRedundantMessages(); - - if (strstr(CmdLine, "nohomebbs")) - DontNeedHomeBBS = TRUE; - - if (strstr(CmdLine, "DontCheckFromCall")) - DontCheckFromCall = TRUE; - - CheckMenuItem(hMenu,IDM_LOGBBS, (LogBBS) ? MF_CHECKED : MF_UNCHECKED); - CheckMenuItem(hMenu,IDM_LOGTCP, (LogTCP) ? MF_CHECKED : MF_UNCHECKED); - CheckMenuItem(hMenu,IDM_LOGCHAT, (LogCHAT) ? MF_CHECKED : MF_UNCHECKED); - - RefreshMainWindow(); - -// CreateWPReport(); - - CreatePipeThread(); - - return TRUE; -} - -int ConnectState(Stream) -{ - int state; - - SessionStateNoAck(Stream, &state); - return state; -} -UCHAR * EncodeCall(UCHAR * Call) -{ - static char axcall[10]; - - ConvToAX25(Call, axcall); - return &axcall[0]; - -} - -/* -VOID FindNextRMSUser(struct BBSForwardingInfo * FWDInfo) -{ - struct UserInfo * user; - - int i = FWDInfo->UserIndex; - - if (i == -1) - { - FWDInfo->UserIndex = FWDInfo->UserCall[0] = 0; // Not scanning users - } - - for (i++; i <= NumberofUsers; i++) - { - user = UserRecPtr[i]; - - if (user->flags & F_POLLRMS) - { - FWDInfo->UserIndex = i; - strcpy(FWDInfo->UserCall, user->Call); - FWDInfo->FwdTimer = FWDInfo->FwdInterval - 20; - return ; - } - } - - // Finished Scan - - FWDInfo->UserIndex = FWDInfo->FwdTimer = FWDInfo->UserCall[0] = 0; -} -*/ - -#ifndef NEWROUTING - -VOID SetupHAddreses(struct BBSForwardingInfo * ForwardingInfo) -{ -} -VOID SetupMyHA() -{ -} -VOID SetupFwdAliases() -{ -} - -int MatchMessagetoBBSList(struct MsgInfo * Msg, CIRCUIT * conn) -{ - struct UserInfo * bbs; - struct BBSForwardingInfo * ForwardingInfo; - char ATBBS[41]; - char * HRoute; - int Count =0; - - strcpy(ATBBS, Msg->via); - HRoute = strlop(ATBBS, '.'); - - if (Msg->type == 'P') - { - // P messages are only sent to one BBS, but check the TO and AT of all BBSs before routing on HA - - for (bbs = BBSChain; bbs; bbs = bbs->BBSNext) - { - ForwardingInfo = bbs->ForwardingInfo; - - if (CheckBBSToList(Msg, bbs, ForwardingInfo)) - { - if (_stricmp(bbs->Call, BBSName) != 0) // Dont forward to ourself - already here! - { - if ((conn == NULL) || (_stricmp(conn->UserPointer->Call, bbs->Call) != 0)) // Dont send back - { - set_fwd_bit(Msg->fbbs, bbs->BBSNumber); - ForwardingInfo->MsgCount++; - } - } - return 1; - } - } - - for (bbs = BBSChain; bbs; bbs = bbs->BBSNext) - { - ForwardingInfo = bbs->ForwardingInfo; - - if (CheckBBSAtList(Msg, ForwardingInfo, ATBBS)) - { - if (_stricmp(bbs->Call, BBSName) != 0) // Dont forward to ourself - already here! - { - if ((conn == NULL) || (_stricmp(conn->UserPointer->Call, bbs->Call) != 0)) // Dont send back - { - set_fwd_bit(Msg->fbbs, bbs->BBSNumber); - ForwardingInfo->MsgCount++; - } - } - return 1; - } - } - - for (bbs = BBSChain; bbs; bbs = bbs->BBSNext) - { - ForwardingInfo = bbs->ForwardingInfo; - - if (CheckBBSHList(Msg, bbs, ForwardingInfo, ATBBS, HRoute)) - { - if (_stricmp(bbs->Call, BBSName) != 0) // Dont forward to ourself - already here! - { - if ((conn == NULL) || (_stricmp(conn->UserPointer->Call, bbs->Call) != 0)) // Dont send back - { - set_fwd_bit(Msg->fbbs, bbs->BBSNumber); - ForwardingInfo->MsgCount++; - } - } - return 1; - } - } - - return FALSE; - } - - // Bulls go to all matching BBSs, so the order of checking doesn't matter - - for (bbs = BBSChain; bbs; bbs = bbs->BBSNext) - { - ForwardingInfo = bbs->ForwardingInfo; - - if (CheckABBS(Msg, bbs, ForwardingInfo, ATBBS, HRoute)) - { - if (_stricmp(bbs->Call, BBSName) != 0) // Dont forward to ourself - already here! - { - if ((conn == NULL) || (_stricmp(conn->UserPointer->Call, bbs->Call) != 0)) // Dont send back - { - set_fwd_bit(Msg->fbbs, bbs->BBSNumber); - ForwardingInfo->MsgCount++; - } - } - Count++; - } - } - - return Count; -} -BOOL CheckABBS(struct MsgInfo * Msg, struct UserInfo * bbs, struct BBSForwardingInfo * ForwardingInfo, char * ATBBS, char * HRoute) -{ - char ** Calls; - char ** HRoutes; - int i, j; - - if (strcmp(ATBBS, bbs->Call) == 0) // @BBS = BBS - return TRUE; - - // Check TO distributions - - if (ForwardingInfo->TOCalls) - { - Calls = ForwardingInfo->TOCalls; - - while(Calls[0]) - { - if (strcmp(Calls[0], Msg->to) == 0) - return TRUE; - - Calls++; - } - } - - // Check AT distributions - - if (ForwardingInfo->ATCalls) - { - Calls = ForwardingInfo->ATCalls; - - while(Calls[0]) - { - if (strcmp(Calls[0], ATBBS) == 0) - return TRUE; - - Calls++; - } - } - if ((HRoute) && (ForwardingInfo->Haddresses)) - { - // Match on Routes - - HRoutes = ForwardingInfo->Haddresses; - - while(HRoutes[0]) - { - i = strlen(HRoutes[0]) - 1; - j = strlen(HRoute) - 1; - - while ((i >= 0) && (j >= 0)) // Until one string rus out - { - if (HRoutes[0][i--] != HRoute[j--]) // Compare backwards - goto next; - } - - return TRUE; - next: - HRoutes++; - } - } - - - return FALSE; - -} - -BOOL CheckBBSToList(struct MsgInfo * Msg, struct UserInfo * bbs, struct BBSForwardingInfo * ForwardingInfo) -{ - char ** Calls; - - // Check TO distributions - - if (ForwardingInfo->TOCalls) - { - Calls = ForwardingInfo->TOCalls; - - while(Calls[0]) - { - if (strcmp(Calls[0], Msg->to) == 0) - return TRUE; - - Calls++; - } - } - return FALSE; -} - -BOOL CheckBBSAtList(struct MsgInfo * Msg, struct BBSForwardingInfo * ForwardingInfo, char * ATBBS) -{ - char ** Calls; - - // Check AT distributions - - if (strcmp(ATBBS, bbs->Call) == 0) // @BBS = BBS - return TRUE; - - if (ForwardingInfo->ATCalls) - { - Calls = ForwardingInfo->ATCalls; - - while(Calls[0]) - { - if (strcmp(Calls[0], ATBBS) == 0) - return TRUE; - - Calls++; - } - } - return FALSE; -} - -BOOL CheckBBSHList(struct MsgInfo * Msg, struct UserInfo * bbs, struct BBSForwardingInfo * ForwardingInfo, char * ATBBS, char * HRoute) -{ - char ** HRoutes; - int i, j; - - if ((HRoute) && (ForwardingInfo->Haddresses)) - { - // Match on Routes - - HRoutes = ForwardingInfo->Haddresses; - - while(HRoutes[0]) - { - i = strlen(HRoutes[0]) - 1; - j = strlen(HRoute) - 1; - - while ((i >= 0) && (j >= 0)) // Until one string rus out - { - if (HRoutes[0][i--] != HRoute[j--]) // Compare backwards - goto next; - } - - return TRUE; - next: - HRoutes++; - } - } - return FALSE; -} - -#endif - -char * strlop(char * buf, char delim) -{ - // Terminate buf at delim, and return rest of string - - char * ptr; - - if (buf == NULL) return NULL; // Protect - - ptr = strchr(buf, delim); - - if (ptr == NULL) return NULL; - - *(ptr)++=0; - - return ptr; -} diff --git a/BPQMail.rc b/BPQMail.rc index 24bda1f..75ae17f 100644 --- a/BPQMail.rc +++ b/BPQMail.rc @@ -254,7 +254,7 @@ END IDD_USEREDIT DIALOGEX 20, 20, 293, 281 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Edit User" -FONT 8, "System" +FONT 8, "System", 0, 0, 0x1 BEGIN COMBOBOX 5000,7,10,57,123,CBS_SIMPLE | CBS_SORT | CBS_UPPERCASE | WS_VSCROLL | WS_TABSTOP @@ -1072,39 +1072,45 @@ BEGIN ES_AUTOHSCROLL END -FILTERS DIALOG DISCARDABLE 26, 5, 382, 287 +FILTERS DIALOG DISCARDABLE 26, 5, 382, 371 STYLE WS_CHILD | WS_VISIBLE FONT 8, "System" BEGIN - LTEXT "Reject Messages:",IDC_STATIC,162,29,70,10 - LTEXT "From",IDC_STATIC,83,155,28,10 - EDITTEXT IDC_HOLDFROM,58,167,64,83,ES_MULTILINE | ES_UPPERCASE | + LTEXT "Reject Messages:",IDC_STATIC,162,26,70,10 + LTEXT "From",IDC_STATIC,83,137,28,10 + EDITTEXT IDC_HOLDFROM,58,149,64,83,ES_MULTILINE | ES_UPPERCASE | ES_AUTOVSCROLL | ES_WANTRETURN - LTEXT "To",IDC_STATIC,152,155,27,10 - EDITTEXT IDC_HOLDTO,126,167,64,83,ES_MULTILINE | ES_UPPERCASE | + LTEXT "To",IDC_STATIC,152,137,27,10 + EDITTEXT IDC_HOLDTO,126,149,64,83,ES_MULTILINE | ES_UPPERCASE | ES_AUTOVSCROLL | ES_WANTRETURN - LTEXT "At",IDC_STATIC,223,155,15,10 - EDITTEXT IDC_HOLDAT,194,167,64,83,ES_MULTILINE | ES_UPPERCASE | + LTEXT "At",IDC_STATIC,223,137,15,10 + EDITTEXT IDC_HOLDAT,194,149,64,83,ES_MULTILINE | ES_UPPERCASE | ES_AUTOVSCROLL | ES_WANTRETURN - DEFPUSHBUTTON "Save",IDC_FILTERSAVE,171,266,50,14,BS_CENTER | + DEFPUSHBUTTON "Save",IDC_FILTERSAVE,171,341,50,14,BS_CENTER | BS_VCENTER LTEXT "From",IDC_STATIC,83,40,28,10 - EDITTEXT IDC_REJFROM,58,52,64,83,ES_MULTILINE | ES_UPPERCASE | + EDITTEXT IDC_REJFROM,58,52,64,67,ES_MULTILINE | ES_UPPERCASE | ES_AUTOVSCROLL | ES_WANTRETURN LTEXT "To",IDC_STATIC,154,40,27,10 - EDITTEXT IDC_REJTO,126,52,64,83,ES_MULTILINE | ES_UPPERCASE | + EDITTEXT IDC_REJTO,126,52,64,68,ES_MULTILINE | ES_UPPERCASE | ES_AUTOVSCROLL | ES_WANTRETURN LTEXT "At",IDC_STATIC,223,40,15,10 - EDITTEXT IDC_REJAT,194,52,64,83,ES_MULTILINE | ES_UPPERCASE | + EDITTEXT IDC_REJAT,194,52,64,68,ES_MULTILINE | ES_UPPERCASE | ES_AUTOVSCROLL | ES_WANTRETURN LTEXT "Message Filtering Setup.",IDC_STATIC,152,10,95,15 - LTEXT "Hold Messages:",IDC_STATIC,166,143,60,9 - EDITTEXT IDC_REJBID,262,52,64,83,ES_MULTILINE | ES_UPPERCASE | + LTEXT "Hold Messages:",IDC_STATIC,166,128,60,9 + EDITTEXT IDC_REJBID,262,52,64,68,ES_MULTILINE | ES_UPPERCASE | ES_AUTOVSCROLL | ES_WANTRETURN - EDITTEXT IDC_HOLDBID,262,167,64,83,ES_MULTILINE | ES_UPPERCASE | + EDITTEXT IDC_HOLDBID,262,149,64,83,ES_MULTILINE | ES_UPPERCASE | ES_AUTOVSCROLL | ES_WANTRETURN - LTEXT "BID",IDC_STATIC,289,155,15,10 + LTEXT "BID",IDC_STATIC,289,137,15,10 LTEXT "BID",IDC_STATIC,289,41,15,10 + EDITTEXT IDC_REJSYS,58,265,270,66,ES_MULTILINE | ES_UPPERCASE | + ES_AUTOVSCROLL | ES_WANTRETURN + LTEXT "Composite Rules (like fbb reject.sys)",IDC_STATIC,152, + 236,134,9 + LTEXT "Action, Type, from, @BBS, to, BID, maximum size", + IDC_STATIC,59,251,247,9 END WPUPDATE DIALOG DISCARDABLE 26, 5, 382, 287 @@ -1258,6 +1264,7 @@ BEGIN "FILTERS", DIALOG BEGIN RIGHTMARGIN, 377 + BOTTOMMARGIN, 355 END IDD_RMSBULLDLG, DIALOG @@ -1444,6 +1451,11 @@ BEGIN 0x0000 END +FILTERS AFX_DIALOG_LAYOUT MOVEABLE PURE +BEGIN + 0x0000 +END + ///////////////////////////////////////////////////////////////////////////// // diff --git a/BPQMail.vcproj b/BPQMail.vcproj index 3c7ef20..3bfb0b5 100644 --- a/BPQMail.vcproj +++ b/BPQMail.vcproj @@ -68,7 +68,7 @@ + + + + + + + + + + diff --git a/BPQMail.vcxproj b/BPQMail.vcxproj index 2ebc492..5aa7387 100644 --- a/BPQMail.vcxproj +++ b/BPQMail.vcxproj @@ -5,23 +5,16 @@ Debug Win32 - - Debug - x64 - Release Win32 - - Release - x64 - {3766AA10-C777-4ED8-A83D-F1452DE9B665} TelnetServer Win32Proj + 10.0.17763.0 @@ -30,39 +23,21 @@ NotSet true - - Application - v141 - NotSet - true - Application v141 false NotSet - - Application - v141 - false - NotSet - - - - - - - <_ProjectFileVersion>15.0.28307.799 @@ -72,17 +47,11 @@ C:\Dev\Msdev2005\Intermed\$(SolutionName)\$(ProjectName)\$(Configuration)\ true - - true - C:\Dev\Msdev2005\$(SolutionName)\$(ProjectName)\$(Configuration)\ C:\Dev\Msdev2005\Intermed\$(SolutionName)\$(ProjectName)\$(Configuration)\ false - - false - @@ -117,40 +86,6 @@ MachineX86 - - - - - - - Disabled - ..\CKernel;..\CInclude;..\CommonSource;..\BPQMail;%(AdditionalIncludeDirectories) - WIN32;_DEBUG;_WINDOWS;_USE_32BIT_TIME_T;%(PreprocessorDefinitions) - EnableFastChecks - MultiThreadedDebug - true - - - Level3 - ProgramDatabase - CompileAsC - - - ..\Include;%(AdditionalIncludeDirectories) - - - ..\lib\bpq32.lib;wsock32.lib;comctl32.lib;winmm.lib;..\lib\libconfig.lib;DbgHelp.lib;%(AdditionalDependencies) - c:\DevProgs\bpq32\BPQMail.exe - false - LIBCMT;%(IgnoreSpecificDefaultLibraries) - true - $(IntDir)$(TargetName).pdb - true - $(IntDir)BBSListings\bpqmail.map - true - Windows - - @@ -186,124 +121,58 @@ MachineX86 - - - - - - - - - - - MaxSpeed - false - ..\CKernel;..\CInclude;..\CommonSource;..\BPQMail;%(AdditionalIncludeDirectories) - WIN32;NDEBUG;_WINDOWS;_USE_32BIT_TIME_T;%(PreprocessorDefinitions) - MultiThreaded - - - Level3 - ProgramDatabase - CompileAsC - - - ..\Include;%(AdditionalIncludeDirectories) - - - ..\lib\bpq32.lib;wsock32.lib;comctl32.lib;winmm.lib;..\lib\libconfig.lib;DbgHelp.lib;%(AdditionalDependencies) - c:\DevProgs\bpq32\BPQMail.exe - true - c:\DevProgs\bpq32\BPQMail.pdb - true - c:\DevProgs\bpq32\BPQMail.map - Windows - true - true - - - - $(IntDir)%(Filename)1.obj - $(IntDir)%(Filename)1.obj $(IntDir)%(Filename)1.xdc - $(IntDir)%(Filename)1.xdc All - All $(IntDir) - $(IntDir) $(IntDir)%(Filename)1.obj - $(IntDir)%(Filename)1.obj $(IntDir)%(Filename)1.xdc - $(IntDir)%(Filename)1.xdc $(IntDir)%(Filename)1.obj - $(IntDir)%(Filename)1.obj $(IntDir)%(Filename)1.xdc - $(IntDir)%(Filename)1.xdc $(IntDir)%(Filename)1.obj - $(IntDir)%(Filename)1.obj $(IntDir)%(Filename)1.xdc - $(IntDir)%(Filename)1.xdc $(IntDir)%(Filename)1.obj - $(IntDir)%(Filename)1.obj $(IntDir)%(Filename)1.xdc - $(IntDir)%(Filename)1.xdc All - All $(IntDir) - $(IntDir) $(IntDir) - $(IntDir) $(IntDir)%(Filename)1.xdc - $(IntDir)%(Filename)1.xdc $(IntDir)%(Filename)1.obj - $(IntDir)%(Filename)1.obj $(IntDir)%(Filename)1.xdc - $(IntDir)%(Filename)1.xdc $(IntDir)%(Filename)1.obj - $(IntDir)%(Filename)1.obj $(IntDir)%(Filename)1.xdc - $(IntDir)%(Filename)1.xdc $(IntDir)%(Filename)1.obj - $(IntDir)%(Filename)1.obj $(IntDir)%(Filename)1.xdc - $(IntDir)%(Filename)1.xdc $(IntDir)%(Filename)1.obj - $(IntDir)%(Filename)1.obj $(IntDir)%(Filename)1.xdc - $(IntDir)%(Filename)1.xdc $(IntDir)%(Filename)1.obj - $(IntDir)%(Filename)1.obj $(IntDir)%(Filename)1.xdc - $(IntDir)%(Filename)1.xdc $(IntDir)%(Filename)1.obj - $(IntDir)%(Filename)1.obj $(IntDir)%(Filename)1.xdc - $(IntDir)%(Filename)1.xdc @@ -312,25 +181,17 @@ $(IntDir)%(Filename)1.obj - $(IntDir)%(Filename)1.obj $(IntDir)%(Filename)1.xdc - $(IntDir)%(Filename)1.xdc $(IntDir)%(Filename)1.obj - $(IntDir)%(Filename)1.obj $(IntDir)%(Filename)1.xdc - $(IntDir)%(Filename)1.xdc $(IntDir)%(Filename)1.obj - $(IntDir)%(Filename)1.obj $(IntDir)%(Filename)1.xdc - $(IntDir)%(Filename)1.xdc $(IntDir)%(Filename)1.obj - $(IntDir)%(Filename)1.obj $(IntDir)%(Filename)1.xdc - $(IntDir)%(Filename)1.xdc diff --git a/BPQMailrc.h b/BPQMailrc.h index e13267c..750d898 100644 --- a/BPQMailrc.h +++ b/BPQMailrc.h @@ -255,6 +255,8 @@ #define IDC_REJFROM 7077 #define IDC_REJTO 7078 #define IDC_REJAT 7079 +#define IDC_HOLDFROM2 7080 +#define IDC_REJSYS 7080 #define IDM_HOUSEKEEPING 9000 #define IDM_PR 9001 #define IDM_PUR 9002 @@ -322,7 +324,7 @@ // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 30012 +#define _APS_NEXT_RESOURCE_VALUE 30013 #define _APS_NEXT_COMMAND_VALUE 40027 #define _APS_NEXT_CONTROL_VALUE 1093 #define _APS_NEXT_SYMED_VALUE 101 diff --git a/Bpq32.c b/Bpq32.c index 5ee2c61..c2a80c3 100644 --- a/Bpq32.c +++ b/Bpq32.c @@ -1183,6 +1183,17 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses // Version 6.0.25.? // Fix 64 bit compatibility problems in SCSTracker and UZ7HO drivers +// Add Chat PACLEN config (5) +// Fix NC to Application Call (6) +// Fix INP3 L3RTT messages on Linux and correct RTT calculation (9) +// Get Beacon config from config file on Windows (9) +// fix processing DED TNC Emulator M command with space between M and params (10) +// Fix sending UI frames on SCSPACTOR (11) +// Dont allow ports that can't set digi'ed bit in callsigns to digipeat. (11) +// Add SDRAngel rig control (11) +// Add option to specify config and data directories on linbpq (12) +// Allow zero resptime (send RR immediately) (13) +// Fix corruptions in Webmail on 64 bit builds, eg in displaying 7+ files (15) #define CKernel @@ -1408,6 +1419,10 @@ extern char MAPCOMMENT[]; // Locator for Reporting - may be Maidenhead or LAT:L extern char LOC[7]; // Maidenhead Locator for Reporting extern char ReportDest[7]; +extern UCHAR ConfigDirectory[260]; + +extern uint64_t timeLoadedMS; + VOID __cdecl Debugprintf(const char * format, ...); VOID __cdecl Consoleprintf(const char * format, ...); @@ -2290,6 +2305,9 @@ FirstInit() GetModuleFileNameExPtr = (FARPROCX)GetProcAddress(ExtDriver,"GetModuleFileNameExA"); EnumProcessesPtr = (FARPROCX)GetProcAddress(ExtDriver,"EnumProcesses"); } + + timeLoadedMS = GetTickCount(); + INITIALISEPORTS(); OpenReportingSockets(); @@ -3269,6 +3287,8 @@ if (_winver < 0x0600) RegCloseKey(hKey); } + strcpy(ConfigDirectory, BPQDirectory); + if (LogDirectory[0] == 0) strcpy(LogDirectory, BPQDirectory); diff --git a/CBPQ32.suo b/CBPQ32.suo deleted file mode 100644 index b8ffa3c..0000000 Binary files a/CBPQ32.suo and /dev/null differ diff --git a/CBPQ32.vcproj b/CBPQ32.vcproj index f1a0357..c1c95a2 100644 --- a/CBPQ32.vcproj +++ b/CBPQ32.vcproj @@ -20,7 +20,7 @@ -//#include "vmm.h" -//#include "SHELLAPI.H" - -#include "CHeaders.h" -#include "bpqaprs.h" - -#pragma pack() - -#include "tncinfo.h" -#include "telnetserver.h" - -//#include "GetVersion.h" - -//#define DllImport __declspec( dllimport ) -//#define DllExport __declspec( dllexport ) - -BOOL DecodeCallString(char * Calls, BOOL * Stay, BOOL * Spy, UCHAR *AXCalls); -VOID Send_AX_Datagram(PDIGIMESSAGE Block, DWORD Len, UCHAR Port); -int APIENTRY ClearNodes(); -VOID GetJSONValue(char * _REPLYBUFFER, char * Name, char * Value); -VOID SendHTTPRequest(SOCKET sock, char * Host, int Port, char * Request, char * Params, int Len, char * Return); -SOCKET OpenWL2KHTTPSock(); -VOID FormatTime3(char * Time, time_t cTime); -VOID Format_Addr(unsigned char * Addr, char * Output, BOOL IPV6); -VOID Tel_Format_Addr(struct ConnectionInfo * sockptr, char * dst); -VOID FindLostBuffers(); -BOOL CheckCMS(struct TNCINFO * TNC); -VOID L2SENDXID(struct _LINKTABLE * LINK); -int CountBits(unsigned long in); -VOID SaveMH(); -BOOL RestartTNC(struct TNCINFO * TNC); -void GetPortCTEXT(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD); -VOID WriteMiniDump(); - -char COMMANDBUFFER[81] = ""; // Command Hander input buffer -char OrigCmdBuffer[81] = ""; // Command Hander input buffer - -struct DATAMESSAGE * REPLYBUFFER = NULL; -UINT APPLMASK = 0; -UCHAR SAVEDAPPLFLAGS = 0; - -UCHAR ALIASINVOKED = 0; - -extern struct TNCINFO * TNCInfo[41]; - -VOID * CMDPTR = 0; - -short CMDPACLEN = 0; - -char OKMSG[] = "Ok\r"; - -char CMDERRMSG[] = "Invalid command - Enter ? for command list\r"; -#define CMDERRLEN sizeof(CMDERRMSG) - 1 - -char PASSWORDMSG[] = "Command requires SYSOP status - enter password\r"; -#define LPASSMSG sizeof(PASSWORDMSG) - 1 - -char CMDLIST[] = "CONNECT BYE INFO NODES PORTS ROUTES USERS MHEARD"; - -#define CMDLISTLEN sizeof(CMDLIST) - 1 - -char BADMSG[] = "Bad Parameter\r"; -char BADPORT[] = "Invalid Port Number\r"; -char NOTEXTPORT[] = "Only valid on EXT ports\r"; -char NOVALCALLS[] = "No Valid Calls defined on this port\r"; - -char BADVALUEMSG[] = "Invalid parameter\r"; - -char BADCONFIGMSG[] = "Configuration File check falled - will continue with old config\r"; -#ifdef LINBPQ -char REBOOTOK[] = "Rebooting\r"; -#else -char REBOOTOK[] = "Rebooting in 20 secs\r"; -#endif -char REBOOTFAILED[] = "Shutdown failed\r"; - -char RESTARTOK[] = "Restarting\r"; -char RESTARTFAILED[] = "Restart failed\r"; - -UCHAR ARDOP[7] = {'A'+'A','R'+'R','D'+'D','O'+'O','P'+'P',' '+' '}; // ARDOP IN AX25 -UCHAR VARA[7] = {'V'+'V','A'+'A','R'+'R','A'+'A',' '+' ',' '+' '}; // VARA IN AX25 - -int STATSTIME = 0; -int MAXBUFFS = 0; -int QCOUNT = 0; -int MINBUFFCOUNT = 65535; -int NOBUFFCOUNT = 0; -int BUFFERWAITS = 0; -int MAXDESTS = 0; -int NUMBEROFNODES = 0; -int L4CONNECTSOUT = 0; -int L4CONNECTSIN = 0; -int L4FRAMESTX = 0; -int L4FRAMESRX = 0; -int L4FRAMESRETRIED = 0; -int OLDFRAMES = 0; -int L3FRAMES = 0; - -VOID SENDSABM(); -VOID RESET2(); - -int APPL1 = 0; -int PASSCMD = 0; - -#pragma pack(1) - -struct _EXTPORTDATA DP; // Only way I can think of to get offets to port data into cmd table - -char CMDALIAS[ALIASLEN][NumberofAppls] = {0}; -char * ALIASPTR = &CMDALIAS[0][0]; - -extern int RigReconfigFlag; - -CMDX COMMANDS[]; - -int CMDXLEN = sizeof (CMDX); - -VOID SENDNODESMSG(); -VOID KISSCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD); -VOID STOPCMS(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD); -VOID STARTCMS(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD); -VOID STOPPORT(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD); -VOID STARTPORT(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD); -VOID FINDBUFFS(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD); -VOID WL2KSYSOP(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD); -VOID AXRESOLVER(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD); -VOID AXMHEARD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD); -VOID SHOWTELNET(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD); -VOID SHOWAGW(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD); -VOID SHOWARP(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD); -VOID SHOWNAT(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD); -VOID PING(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD); -VOID SHOWIPROUTE(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD); -VOID FLMSG(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * UserCMD); -void ListExcludedCalls(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD); -VOID APRSCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD); -VOID RECONFIGTELNET (TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD); -VOID HELPCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD); - - - -char * __cdecl Cmdprintf(TRANSPORTENTRY * Session, char * Bufferptr, const char * format, ...) -{ - // Send Command response checking PACLEN - - char Mess[4096]; - va_list(arglist); - int OldLen; - int MsgLen; - struct DATAMESSAGE * Buffer; - char * Messptr = Mess; - int Paclen = Session->SESSPACLEN; - - if (Paclen == 0) - Paclen = 255; - - va_start(arglist, format); - - MsgLen = vsprintf(Mess, format, arglist); - - OldLen = (int)(Bufferptr - (char *)REPLYBUFFER->L2DATA); - - while ((OldLen + MsgLen) > Paclen) - { - // Have to send Paclen then get a new buffer - - int ThisBit = Paclen - OldLen; // What we can send this time - - if (ThisBit < 0) - ThisBit = 0; // How can this happen?? - - memcpy(Bufferptr, Messptr, ThisBit); - Messptr += ThisBit; - MsgLen -= ThisBit; - - // QUEUE IT AND GET ANOTHER BUFFER - - Buffer = (struct DATAMESSAGE *)GetBuff(); - - if (Buffer == NULL) - - // No buffers, so just reuse the old one (better than crashing !!) - - Buffer = REPLYBUFFER; - else - SendCommandReply(Session, REPLYBUFFER, Paclen + (4 + sizeof(void *))); - - - REPLYBUFFER = Buffer; - Buffer->PID = 0xf0; - - Bufferptr = &Buffer->L2DATA[0]; - OldLen = 0; - } - - // Add last bit to buffer - - memcpy(Bufferptr, Messptr, MsgLen); - - return Bufferptr + MsgLen; -} - - -VOID SENDNODES(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - SENDNODESMSG(); - - strcpy(Bufferptr, OKMSG); - Bufferptr += (int)strlen(OKMSG); - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - -VOID SAVEMHCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - SaveMH(); - - strcpy(Bufferptr, OKMSG); - Bufferptr += (int)strlen(OKMSG); - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - -VOID SAVENODES(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - SaveNodes(); - - strcpy(Bufferptr, OKMSG); - Bufferptr += (int)strlen(OKMSG); - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - -VOID DUMPCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - WriteMiniDump(); - - strcpy(Bufferptr, OKMSG); - Bufferptr += (int)strlen(OKMSG); - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - -VOID RIGRECONFIG(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - if (!ProcessConfig()) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Configuration File check falled - will continue with old config"); - } - else - { - RigReconfigFlag = TRUE; - Bufferptr = Cmdprintf(Session, Bufferptr, "Rigcontrol Reconfig requested"); - } - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - -VOID REBOOT(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - if (Reboot()) - { - strcpy(Bufferptr, REBOOTOK); - Bufferptr += (int)strlen(REBOOTOK); - } - else - { - strcpy(Bufferptr, REBOOTFAILED); - Bufferptr += (int)strlen(REBOOTFAILED); - } - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - -VOID RESTART(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - if (Restart()) - { - strcpy(Bufferptr, RESTARTOK); - Bufferptr += (int)strlen(RESTARTOK); - } - else - { - strcpy(Bufferptr, RESTARTFAILED); - Bufferptr += (int)strlen(RESTARTFAILED); - } - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - -VOID RESTARTTNC(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - char * ptr, *Context; - int portno; - - ptr = strtok_s(CmdTail, " ", &Context); - - if (ptr) - { - portno = atoi (ptr); - - if (portno && portno < 33) - { - struct TNCINFO * TNC = TNCInfo[portno]; - - if (TNC == NULL) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid Port\r"); - } - else - { - if (TNC->ProgramPath) - { - if (RestartTNC(TNC)) - Bufferptr = Cmdprintf(Session, Bufferptr, "Restart %s Ok\r", TNC->ProgramPath); - else - Bufferptr = Cmdprintf(Session, Bufferptr, "Restart %s Failed\r", TNC->ProgramPath); - } - else - { - Bufferptr = Cmdprintf(Session, Bufferptr, "PATH not defined so can't restart TNC\r"); - } - } - } - else - Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid Port\r"); - - } - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - -UCHAR VALNODESFLAG = 0, EXTONLY = 0; - -VOID PORTVAL (TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD); - -VOID VALNODES(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - VALNODESFLAG = 1; - PORTVAL(Session, Bufferptr, CmdTail, CMD); -} - -VOID EXTPORTVAL(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - EXTONLY = 1; - PORTVAL(Session, Bufferptr, CmdTail, CMD); -} -VOID PORTVAL(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - // PROCESS PORT VALUE COMMANDS - - char * ptr, *Context, * ptr1; - int portno; - UCHAR oldvalue, newvalue; - struct PORTCONTROL * PORT = PORTTABLE; - int n = NUMBEROFPORTS; - UCHAR * valueptr; - - // Get port number - - ptr = strtok_s(CmdTail, " ", &Context); - - if (ptr) - { - portno = atoi (ptr); - - if (portno) - { - while (n--) - { - if (PORT->PORTNUMBER == portno) - { - if (VALNODESFLAG) - { - char * VNPtr = PORT->PERMITTEDCALLS; - char Normcall[10]; - - VALNODESFLAG = 0; - - if (VNPtr) - { - while (VNPtr[0]) - { - Normcall[ConvFromAX25(VNPtr, Normcall)] = 0; - Bufferptr = Cmdprintf(Session, Bufferptr, "%s ", Normcall); - VNPtr += 7; - } - - Bufferptr = Cmdprintf(Session, Bufferptr, "\r"); - } - else - { - Bufferptr = Cmdprintf(Session, Bufferptr, "%s", NOVALCALLS); - } - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - - return; - - } - - if (EXTONLY) - { - // Make sure an Extenal Port - - EXTONLY = 0; - - if (PORT->PORTTYPE != 0x10) - { - strcpy(Bufferptr, NOTEXTPORT); - Bufferptr += (int)strlen(NOTEXTPORT); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - } - - valueptr = (UCHAR *)PORT + CMD->CMDFLAG; - oldvalue = *valueptr; - - // Display Param Namee - - ptr1 = &CMD->String[0]; - n = 12; - - while (*(ptr1) != ' ' && n--) - *(Bufferptr++) = *(ptr1++); - - // See if another param - if not, just display current value - - ptr = strtok_s(NULL, " ", &Context); - - if (ptr && ptr[0]) - { - // Get new value - - newvalue = atoi(ptr); - *valueptr = newvalue; - - Bufferptr = Cmdprintf(Session, Bufferptr, " was %d now %d\r", oldvalue, newvalue); - } - - else - Bufferptr = Cmdprintf(Session, Bufferptr, " %d\r", oldvalue); - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - - } - PORT = PORT->PORTPOINTER; - } - } - } - - // Bad port - - strcpy(Bufferptr, BADPORT); - Bufferptr += (int)strlen(BADPORT); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - -} - -VOID SWITCHVAL (TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - // Update switch 8 bit value - - char * ptr, *Context, * ptr1; - UCHAR oldvalue, newvalue; - int n; - UCHAR * valueptr; - - valueptr = (UCHAR *)CMD->CMDFLAG; - - oldvalue = *valueptr; - - // Display Param Name - - ptr1 = &CMD->String[0]; - n = 12; - - while (*(ptr1) != ' ' && n--) - *(Bufferptr++) = *(ptr1++); - - // See if a param - if not, just display current value - - ptr = strtok_s(CmdTail, " ", &Context); - - if (ptr && ptr[0]) - { - // Get new value - - newvalue = atoi(ptr); - *valueptr = newvalue; - - Bufferptr = Cmdprintf(Session, Bufferptr, " was %d now %d\r", oldvalue, newvalue); - - if (memcmp(CMD->String, "NODESINT ", 8) == 0) - L3TIMER = L3INTERVAL; - } - else - Bufferptr = Cmdprintf(Session, Bufferptr, " %d\r", oldvalue); - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - -} - -VOID SWITCHVALW (TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - // Update switch 16 bit value - - char * ptr, *Context, * ptr1; - USHORT oldvalue, newvalue; - int n; - USHORT * valueptr; - - valueptr = (USHORT *)CMD->CMDFLAG; - - oldvalue = (USHORT)*valueptr; - - // Display Param Name - - ptr1 = &CMD->String[0]; - n = 12; - - while (*(ptr1) != ' ' && n--) - *(Bufferptr++) = *(ptr1++); - - // See if a param - if not, just display current value - - ptr = strtok_s(CmdTail, " ", &Context); - - if (ptr && ptr[0]) - { - // Get new value - - newvalue = atoi(ptr); - *valueptr = newvalue; - - Bufferptr = Cmdprintf(Session, Bufferptr, " was %d now %d\r", oldvalue, newvalue); - } - else - Bufferptr = Cmdprintf(Session, Bufferptr, " %d\r", oldvalue); - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - -} - -TRANSPORTENTRY * SetupSessionFromSession(TRANSPORTENTRY * Session, PBPQVECSTRUC HOSTSESS, UINT APPLMASK) -{ - // Create a Transport (L4) session linked to an incoming Session - - TRANSPORTENTRY * NewSess = L4TABLE; - int Index = 0; - - while (Index < MAXCIRCUITS) - { - if (NewSess->L4USER[0] == 0) - { - // Got One - - UCHAR * ourcall = &MYCALL[0]; - - Session->L4CROSSLINK = NewSess; - NewSess->L4CROSSLINK = Session; - - if (APPLMASK) - { - // Circuit for APPL - look for an APPLCALL - - APPLCALLS * APPL = APPLCALLTABLE; - - while ((APPLMASK & 1) == 0) - { - APPLMASK >>= 1; - APPL++; - } - if (APPL->APPLCALL[0] > 0x40) // We have an applcall - ourcall = &APPL->APPLCALL[0]; - } - - memcpy(NewSess->L4USER, ourcall, 7); - memcpy(NewSess->L4MYCALL, Session->L4MYCALL, 7); - - NewSess->CIRCUITINDEX = Index; //OUR INDEX - NewSess->CIRCUITID = NEXTID; - - NEXTID++; - if (NEXTID == 0) - NEXTID++; // kEEP nON-ZERO - - NewSess->SESSIONT1 = Session->SESSIONT1; - NewSess->L4WINDOW = (UCHAR)L4DEFAULTWINDOW; - NewSess->SESSPACLEN = PACLEN; // Default; - - NewSess->L4TARGET.HOST = HOSTSESS; - NewSess->L4STATE = 5; - return NewSess; - } - Index++; - NewSess++; - } - return NULL; -} - -extern int GETCONNECTIONINFO(); - - -BOOL cATTACHTOBBS(TRANSPORTENTRY * Session, UINT Mask, int Paclen, int * AnySessions) -{ - PBPQVECSTRUC HOSTSESS = BPQHOSTVECTOR; - TRANSPORTENTRY * NewSess; - int ApplNum; - int n = BPQHOSTSTREAMS; - int ConfigedPorts = 0; - - // LOOK FOR A FREE HOST SESSION - - while (n--) - { - if (HOSTSESS->HOSTAPPLMASK & Mask) - { - // Right appl - - ConfigedPorts++; - - if (HOSTSESS->HOSTSESSION == NULL && (HOSTSESS->HOSTFLAGS & 3) == 0) // Not attached and no report outstanding - { - // WEVE GOT A FREE BPQ HOST PORT - USE IT - - NewSess = SetupSessionFromSession(Session, HOSTSESS, Mask); - - if (NewSess == NULL) - return FALSE; // Appl not available - - HOSTSESS->HOSTSESSION = NewSess; - - // Convert APPLMASK to APPLNUM - - ApplNum = 1; - - while (APPLMASK && (APPLMASK & 1) == 0) - { - ApplNum++; - APPLMASK >>= 1; - } - - HOSTSESS->HOSTAPPLNUM = ApplNum; - - HOSTSESS->HOSTFLAGS |= 2; // Indicate State Change - - NewSess->L4CIRCUITTYPE = BPQHOST | DOWNLINK; - - PostStateChange(NewSess); - - NewSess->SESS_APPLFLAGS = HOSTSESS->HOSTAPPLFLAGS; - - NewSess->SESSPACLEN = Paclen; - - return TRUE; - } - } - HOSTSESS++; - } - - *AnySessions = ConfigedPorts; // to distinguish between none and all in use - return FALSE; -} - -VOID APPLCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - BOOL CONFAILED = 0; - UINT CONERROR ; - char APPName[13]; - char * ptr1, *ptr2; - int n = 12; - BOOL Stay = FALSE; - - // Copy Appl and Null Terminate - - ptr1 = &CMD->String[0]; - ptr2 = APPName; - - while (*(ptr1) != ' ' && n--) - *(ptr2++) = *(ptr1++); - - *(ptr2) = 0; - - if (Session->LISTEN) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Can't use %s while listening\r", APPName); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - - if (CmdTail[0] == 'S') - Stay = TRUE; - - Session->STAYFLAG = Stay; - - memcpy(Session->APPL, CMD->String, 12); - - // SEE IF THERE IS AN ALIAS DEFINDED FOR THIS COMMAND - - if (ALIASPTR[0] > ' ') - { - // COPY ALIAS TO COMMAND BUFFER, THEN REENTER COMMAND HANDLER - - int SaveSecure = Session->Secure_Session; - - memcpy(COMMANDBUFFER, ALIASPTR, ALIASLEN); - _strupr(COMMANDBUFFER); - memcpy(OrigCmdBuffer, ALIASPTR, ALIASLEN); // In case original case version needed - - ALIASINVOKED = 1; // To prevent Alias Loops - - // Set secure session for application alias in case telnet outward connect - - Session->Secure_Session = 1; - DoTheCommand(Session); - Session->Secure_Session = SaveSecure; - - return; - } - - if (cATTACHTOBBS(Session, APPLMASK, CMDPACLEN, &CONERROR) == 0) - { - // No Streams - - if (CONERROR) - Bufferptr = Cmdprintf(Session, Bufferptr, "Sorry, All %s Ports are in use - Please try later\r", APPName); - else - Bufferptr = Cmdprintf(Session, Bufferptr, "Sorry, Application %s is not running - Please try later\r", APPName); - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - // IF CMD_TO_APPL SET IN APPLFLAGS, SEND INPUT MSG TO APPL - - if (Session->L4CROSSLINK->SESS_APPLFLAGS & CMD_TO_APPL) - { - struct DATAMESSAGE * Msg = (struct DATAMESSAGE *)GetBuff(); - TRANSPORTENTRY * XSession = Session->L4CROSSLINK; - - if (Msg) - { - COMMANDBUFFER[72] = 13; - memcpy(Msg->L2DATA, COMMANDBUFFER, 73); - Msg->LENGTH = 73 + 4 + sizeof(void *); - Msg->PID = 0xf0; - - C_Q_ADD(&XSession->L4TX_Q, (UINT *)Msg); - PostDataAvailable(XSession); - } - } - - if (Stay) - Session->L4CROSSLINK->L4TARGET.HOST->HOSTFLAGS |= 0x20; - - // IF MSG_TO_USER SET, SEND 'CONNECTED' MESSAGE TO USER - - Session->SESS_APPLFLAGS = Session->L4CROSSLINK->SESS_APPLFLAGS; - - if (Session->L4CROSSLINK->SESS_APPLFLAGS & MSG_TO_USER) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Connected to %s\r", APPName); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - - // DONT NEED BUFFER ANY MORE - - ReleaseBuffer((UINT *)REPLYBUFFER); - return; -} - - -VOID CMDI00(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - Bufferptr = Cmdprintf(Session, Bufferptr, "%s", INFOMSG); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - -VOID CMDV00(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - if (sizeof(void *) == 4) - Bufferptr = Cmdprintf(Session, Bufferptr, "Version %s\r", VersionString); - else - Bufferptr = Cmdprintf(Session, Bufferptr, "Version %s (64 bit)\r", VersionString); - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - -VOID BYECMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - CLOSECURRENTSESSION(Session); // Kills any crosslink, plus local link - ReleaseBuffer((UINT *)REPLYBUFFER); - return; -} - -VOID CMDPAC(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - // SET PACLEN FOR THIS SESSION - - char * ptr, *Context; - int newvalue; - - ptr = strtok_s(CmdTail, " ", &Context); - - if (ptr && ptr[0]) - { - // Get new value - - newvalue = atoi(ptr); - if (newvalue > 29 && newvalue < 256) - Session->SESSPACLEN = newvalue & 0xff; - } - - Bufferptr = Cmdprintf(Session, Bufferptr, "PACLEN - %d\r", Session->SESSPACLEN); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - -VOID CMDIDLE(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - // SET IDLETIME FOR THIS SESSION - - char * ptr, *Context; - int newvalue; - - ptr = strtok_s(CmdTail, " ", &Context); - - if (ptr && ptr[0]) - { - // Get new value - - newvalue = atoi(ptr); - if (newvalue > 59 && newvalue < 901) - Session->L4LIMIT = newvalue; - } - - Bufferptr = Cmdprintf(Session, Bufferptr, "IDLETIME - %d\r", Session->L4LIMIT); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - -} -VOID CMDT00(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - // SET L4 TIMEOUT FOR CONNECTS ON THIS SESSION - - char * ptr, *Context; - int newvalue; - - ptr = strtok_s(CmdTail, " ", &Context); - - if (ptr && ptr[0]) - { - // Get new value - - newvalue = atoi(ptr); - if (newvalue > 20) - Session->SESSIONT1 = newvalue; - } - - Bufferptr = Cmdprintf(Session, Bufferptr, "L4TIMEOUT - %d\r", Session->SESSIONT1); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - -UCHAR PWLen; -char PWTEXT[80]; - -VOID PWDCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - char * ptr, *Context; - USHORT pwsum = 0; - int n = 5, p1, p2, p3, p4, p5; - - if (Session->Secure_Session) // HOST - SET AUTHORISED REGARDLESS - { - Session->PASSWORD = 0xFFFF; // SET AUTHORISED - Session->Secure_Session = 1; - strcpy(Bufferptr, OKMSG); - Bufferptr += (int)strlen(OKMSG); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - ptr = strtok_s(CmdTail, " ", &Context); - - if (ptr && ptr[0]) - { - // Check Password - - n = 5; - - while (n--) - pwsum += *(ptr++); - - if (Session->PASSWORD == pwsum) - { - Session->PASSWORD = 0xFFFF; // SET AUTHORISED - Session->Secure_Session = 1; - strcpy(Bufferptr, OKMSG); - Bufferptr += (int)strlen(OKMSG); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - ReleaseBuffer((UINT *)REPLYBUFFER); - return; - } - - // SEND PASSWORD PROMPT - - if (PWLen == 0) - PWLen = 1; - - p1 = rand() % PWLen; - pwsum += PWTEXT[p1++]; - - p2 = rand() % PWLen; - pwsum += PWTEXT[p2++]; - - p3 = rand() % PWLen; - pwsum += PWTEXT[p3++]; - - p4 = rand() % PWLen; - pwsum += PWTEXT[p4++]; - - p5 = rand() % PWLen; - pwsum += PWTEXT[p5++]; - - Session->PASSWORD = pwsum; - - Bufferptr = Cmdprintf(Session, Bufferptr, "%d %d %d %d %d\r", p1, p2, p3, p4, p5); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; -} - -VOID CMDSTATS(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - char * ptr, *Context; - int Port = 0, cols = NUMBEROFPORTS, i; - char * uptime; - struct PORTCONTROL * PORT = PORTTABLE; - struct PORTCONTROL * STARTPORT; - - Bufferptr = Cmdprintf(Session, Bufferptr, "\r"); - - // SEE IF ANY PARAM - - ptr = strtok_s(CmdTail, " ", &Context); - - if (ptr && ptr[0]) - Port = atoi(ptr); - - // IF ASKING FOR PORT STATS, DONT DO SYSTEM ONES - - if (Port == 0) - { - uptime = FormatUptime(STATSTIME); - Bufferptr = Cmdprintf(Session, Bufferptr, "%s", uptime); - - Bufferptr = Cmdprintf(Session, Bufferptr, "Semaphore Get-Rel/Clashes %9d%9d\r", - Semaphore.Gets - Semaphore.Rels, Semaphore.Clashes); - - Bufferptr = Cmdprintf(Session, Bufferptr, "Buffers:Max/Cur/Min/Out/Wait%9d%9d%9d%9d%9d\r", - MAXBUFFS, QCOUNT, MINBUFFCOUNT, NOBUFFCOUNT, BUFFERWAITS); - - Bufferptr = Cmdprintf(Session, Bufferptr, "Known Nodes/Max Nodes %9d%9d\r", - NUMBEROFNODES, MAXDESTS); - - Bufferptr = Cmdprintf(Session, Bufferptr, "L4 Connects Sent/Rxed %9d%9d\r", - L4CONNECTSOUT, L4CONNECTSIN); - - Bufferptr = Cmdprintf(Session, Bufferptr, "L4 Frames TX/RX/Resent/Reseq%9d%9d%9d%9d\r", - L4FRAMESTX, L4FRAMESRX, L4FRAMESRETRIED, OLDFRAMES); - - Bufferptr = Cmdprintf(Session, Bufferptr, "L3 Frames Relayed %9d\r", L3FRAMES); - - if (ptr && ptr[0] == 'S') - { - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - } - - // POSITION TO REQUESTED PORT - - if (Port) - { - while (PORT && PORT->PORTNUMBER != Port) - { - PORT = PORT->PORTPOINTER; - cols--; - } - } - - if (PORT == NULL) // REQUESTED PORT NOT FOUND - { - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - STARTPORT = PORT; - - if (cols > 7) - cols = 7; - - Bufferptr = Cmdprintf(Session, Bufferptr, " "); - - for (i = 0; i < cols; i++) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Port %02d ", PORT->PORTNUMBER); - PORT = PORT->PORTPOINTER; - } - - Bufferptr = Cmdprintf(Session, Bufferptr, "\r"); - - PORT = STARTPORT; - Bufferptr = Cmdprintf(Session, Bufferptr, "L2 Frames Digied"); - - for (i = 0; i < cols; i++) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "%9d", PORT->L2DIGIED); - PORT = PORT->PORTPOINTER; - } - Bufferptr = Cmdprintf(Session, Bufferptr, "\r"); - - PORT = STARTPORT; - Bufferptr = Cmdprintf(Session, Bufferptr, "L2 Frames Heard "); - - for (i = 0; i < cols; i++) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "%9d", PORT->L2FRAMES); - PORT = PORT->PORTPOINTER; - } - Bufferptr = Cmdprintf(Session, Bufferptr, "\r"); - - PORT = STARTPORT; - Bufferptr = Cmdprintf(Session, Bufferptr, "L2 Frames Rxed "); - - for (i = 0; i < cols; i++) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "%9d", PORT->L2FRAMESFORUS); - PORT = PORT->PORTPOINTER; - } - Bufferptr = Cmdprintf(Session, Bufferptr, "\r"); - - PORT = STARTPORT; - Bufferptr = Cmdprintf(Session, Bufferptr, "L2 Frames Sent "); - - for (i = 0; i < cols; i++) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "%9d", PORT->L2FRAMESSENT); - PORT = PORT->PORTPOINTER; - } - Bufferptr = Cmdprintf(Session, Bufferptr, "\r"); - - PORT = STARTPORT; - Bufferptr = Cmdprintf(Session, Bufferptr, "L2 Timeouts "); - - for (i = 0; i < cols; i++) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "%9d", PORT->L2TIMEOUTS); - PORT = PORT->PORTPOINTER; - } - Bufferptr = Cmdprintf(Session, Bufferptr, "\r"); - - PORT = STARTPORT; - Bufferptr = Cmdprintf(Session, Bufferptr, "REJ Frames Rxed "); - - for (i = 0; i < cols; i++) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "%9d", PORT->L2REJCOUNT); - PORT = PORT->PORTPOINTER; - } - Bufferptr = Cmdprintf(Session, Bufferptr, "\r"); - - PORT = STARTPORT; - Bufferptr = Cmdprintf(Session, Bufferptr, "RX out of Seq "); - - for (i = 0; i < cols; i++) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "%9d", PORT->L2OUTOFSEQ); - PORT = PORT->PORTPOINTER; - } - Bufferptr = Cmdprintf(Session, Bufferptr, "\r"); - - PORT = STARTPORT; - Bufferptr = Cmdprintf(Session, Bufferptr, "L2 Resequenced "); - - for (i = 0; i < cols; i++) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "%9d", PORT->L2RESEQ); - PORT = PORT->PORTPOINTER; - } - Bufferptr = Cmdprintf(Session, Bufferptr, "\r"); - - PORT = STARTPORT; - Bufferptr = Cmdprintf(Session, Bufferptr, "Undrun/Poll T/o "); - - for (i = 0; i < cols; i++) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "%9d", PORT->L2URUNC); - PORT = PORT->PORTPOINTER; - } - Bufferptr = Cmdprintf(Session, Bufferptr, "\r"); - - PORT = STARTPORT; - Bufferptr = Cmdprintf(Session, Bufferptr, "RX Overruns "); - - for (i = 0; i < cols; i++) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "%9d", PORT->L2ORUNC); - PORT = PORT->PORTPOINTER; - } - Bufferptr = Cmdprintf(Session, Bufferptr, "\r"); - - PORT = STARTPORT; - Bufferptr = Cmdprintf(Session, Bufferptr, "RX CRC Errors "); - - for (i = 0; i < cols; i++) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "%9d", PORT->RXERRORS); - PORT = PORT->PORTPOINTER; - } - Bufferptr = Cmdprintf(Session, Bufferptr, "\r"); - - PORT = STARTPORT; - Bufferptr = Cmdprintf(Session, Bufferptr, "FRMRs Sent "); - - for (i = 0; i < cols; i++) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "%9d", PORT->L2FRMRTX); - PORT = PORT->PORTPOINTER; - } - Bufferptr = Cmdprintf(Session, Bufferptr, "\r"); - - PORT = STARTPORT; - Bufferptr = Cmdprintf(Session, Bufferptr, "FRMRs Received "); - - for (i = 0; i < cols; i++) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "%9d", PORT->L2FRMRRX); - PORT = PORT->PORTPOINTER; - } - Bufferptr = Cmdprintf(Session, Bufferptr, "\r"); - - PORT = STARTPORT; - Bufferptr = Cmdprintf(Session, Bufferptr, "Frames abandoned"); - - for (i = 0; i < cols; i++) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "%9d", PORT->L1DISCARD); - PORT = PORT->PORTPOINTER; - } - Bufferptr = Cmdprintf(Session, Bufferptr, "\r"); - - PORT = STARTPORT; - Bufferptr = Cmdprintf(Session, Bufferptr, "Link Active %% "); - - for (i = 0; i < cols; i++) - { - Bufferptr = Cmdprintf(Session, Bufferptr, " %2d %3d", PORT->AVSENDING, PORT->AVACTIVE); - PORT = PORT->PORTPOINTER; - } - Bufferptr = Cmdprintf(Session, Bufferptr, "\r"); - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - -VOID CMDL00(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - // PROCESS 'LINKS' MESSAGE - - struct _LINKTABLE * LINK = LINKS; - int n = MAXLINKS; - int len; - char Normcall[11] = ""; - - Bufferptr = Cmdprintf(Session, Bufferptr, "Links\r"); - - while (n--) - { - if (LINK->LINKCALL[0]) - { - len = ConvFromAX25(LINK->LINKCALL, Normcall); - - Bufferptr = Cmdprintf(Session, Bufferptr, "%s", Normcall); - - len = ConvFromAX25(LINK->OURCALL, Normcall); - Bufferptr = Cmdprintf(Session, Bufferptr, "%s", Normcall); - - if (LINK->Ver2point2) - Bufferptr = Cmdprintf(Session, Bufferptr, " S=%d P=%d T=%d V=2.2\r", - LINK->L2STATE, LINK->LINKPORT->PORTNUMBER, LINK->LINKTYPE); - else - Bufferptr = Cmdprintf(Session, Bufferptr, " S=%d P=%d T=%d V=%d\r", - LINK->L2STATE, LINK->LINKPORT->PORTNUMBER, LINK->LINKTYPE, 2 - LINK->VER1FLAG); - } - LINK++; - } - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - - -VOID CMDS00(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - // PROCESS 'USERS' - - 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]; - - Bufferptr = Cmdprintf(Session, Bufferptr, "%s%d)\r", SESSIONHDDR, QCOUNT); - - while (n--) - { - if (L4->L4USER[0]) - { - RHS[0] = MID[0] = 0; - - if ((L4->L4CIRCUITTYPE & UPLINK) == 0) //SHORT CMDS10A ; YES - { - // IF DOWNLINK, ONLY DISPLAY IF NO CROSSLINK - - if (L4->L4CROSSLINK == 0) //jne CMDS60 ; WILL PROCESS FROM OTHER END - { - // ITS A DOWNLINK WITH NO PARTNER - MUST BE A CLOSING SESSION - // DISPLAY TO THE RIGHT FOR NOW - - strcpy(LHS, "(Closing) "); - DISPLAYCIRCUIT(L4, RHS); - goto CMDS50; - } - else - goto CMDS60; // WILL PROCESS FROM OTHER END - } - - if (L4->L4CROSSLINK == 0) - { - // Single Entry - - DISPLAYCIRCUIT(L4, LHS); - } - else - { - DISPLAYCIRCUIT(L4, LHS); - - Partner = L4->L4CROSSLINK; - - if (Partner->L4STATE == 5) - strcpy(MID, "<-->"); - else - strcpy(MID, "<~~>"); - - DISPLAYCIRCUIT(Partner, RHS); - } -CMDS50: - memset(Line, 32, 100); - memcpy(Line, LHS, (int)strlen(LHS)); - memcpy(&Line[35], MID, (int)strlen(MID)); - strcpy(&Line[40], RHS); - strcat(&Line[40], "\r"); - Bufferptr = Cmdprintf(Session, Bufferptr, "%s", Line); - } -CMDS60: - L4++; - } - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - -VOID CMDP00(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - // Process PORTS Message - - struct PORTCONTROL * PORT = PORTTABLE; - - Bufferptr = Cmdprintf(Session, Bufferptr, "Ports\r"); - - while (PORT) - { - if (PORT->Hide == 0) - Bufferptr = Cmdprintf(Session, Bufferptr, " %2d %s\r", PORT->PORTNUMBER, PORT->PORTDESCRIPTION); - - PORT = PORT->PORTPOINTER; - } - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - -char * DisplayRoute(TRANSPORTENTRY * Session, char * Bufferptr, struct ROUTE * Routes, char Verbose) -{ - char Normcall[10]; - char locked[] = " ! "; - int NodeCount; - int Percent = 0; - char PercentString[20]; - int Iframes, Retries; - char Active[10]; - int Queued; - - int Port = 0; - - int len = ConvFromAX25(Routes->NEIGHBOUR_CALL, Normcall); - - Normcall[9]=0; - - if ((Routes->NEIGHBOUR_FLAG & 1) == 1) - strcpy(locked, "!"); - else - strcpy(locked, " "); - - NodeCount = COUNTNODES(Routes); - - if (Routes->NEIGHBOUR_LINK && Routes->NEIGHBOUR_LINK->L2STATE >= 5) - strcpy(Active, ">"); - else - strcpy(Active, " "); - - if (Verbose) - { - if (Routes->NEIGHBOUR_LINK) - Queued = COUNT_AT_L2(Routes->NEIGHBOUR_LINK); // SEE HOW MANY QUEUED - else - Queued = 0; - - Iframes = Routes->NBOUR_IFRAMES; - Retries = Routes->NBOUR_RETRIES; - - if (Iframes) - { - Percent = (Retries * 100) / Iframes; - sprintf(PercentString, "%3d%%", Percent); - } - else - strcpy(PercentString, " "); - - - Bufferptr = Cmdprintf(Session, Bufferptr, "%s%2d %s %3d %3d%s%4d %4d %s %d %d %02d:%02d %d %d", - Active, Routes->NEIGHBOUR_PORT, Normcall, - Routes->NEIGHBOUR_QUAL, NodeCount, locked, Iframes, Retries, PercentString, Routes->NBOUR_MAXFRAME, Routes->NBOUR_FRACK, - Routes->NEIGHBOUR_TIME >> 8, (Routes->NEIGHBOUR_TIME) & 0xff, Queued, Routes->OtherendsRouteQual); - - // IF INP3 DISPLAY SRTT - - if (Routes->INP3Node) // INP3 Enabled? - { - double srtt = Routes->SRTT/1000.0; - double nsrtt = Routes->NeighbourSRTT/1000.0; - - Bufferptr = Cmdprintf(Session, Bufferptr, " %4.2fs %4.2fs", srtt, nsrtt); - } - - Bufferptr = Cmdprintf(Session, Bufferptr, "\r"); - } - else - { - Bufferptr = Cmdprintf(Session, Bufferptr, "%s %d %s %d %d%s\r", - Active, Routes->NEIGHBOUR_PORT, Normcall, Routes->NEIGHBOUR_QUAL, NodeCount, locked); - } - - return Bufferptr; -} - - -VOID CMDR00(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - struct ROUTE * Routes = NEIGHBOURS; - int MaxRoutes = MAXNEIGHBOURS; - char locked[] = " ! "; - int Percent = 0; - char * ptr, * Context; - char Verbose = 0; - int Port = 0; - char AXCALL[7]; - BOOL Found; - - ptr = strtok_s(CmdTail, " ", &Context); - - if (ptr && (int)strlen(ptr) > 1) - { - // Route Update - - goto ROUTEUPDATE; - } - - if (ptr) - { - Verbose = ptr[0]; - ptr = strtok_s(NULL, " ", &Context); - if (ptr) - Port = atoi(ptr); - } - - Bufferptr = Cmdprintf(Session, Bufferptr, "Routes\r"); - - while (MaxRoutes--) - { - if (Routes->NEIGHBOUR_CALL[0] != 0) - if (Port == 0 || Port == Routes->NEIGHBOUR_PORT) - Bufferptr = DisplayRoute(Session, Bufferptr, Routes, Verbose); - - Routes++; - } - goto SendReply; - -ROUTEUPDATE: - - if (Session->PASSWORD != 0xFFFF) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "%s", PASSWORDMSG); - goto SendReply; - } - - // Line is - - // ROUTES G8BPQ-2 2 100 - Set quality to 100 - // ROUTES G8BPQ-2 2 ! - Toggle 'Locked Route' flag - // ROUTES G8BPQ-2 2 100 ! - Set quality and toggle 'locked' flag - - - ConvToAX25(ptr, AXCALL); - - ptr = strtok_s(NULL, " ", &Context); - - if (ptr) - Port = atoi(ptr); - - if (Port == 0) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Port Number Missing \r"); - goto SendReply; - } - - Found = FindNeighbour(AXCALL, Port, &Routes); - - if (Context && Context[0] > 32) - { - // More Params - - ptr = strtok_s(NULL, " ", &Context); - - if (ptr) - { - // Adding - - memcpy(Routes->NEIGHBOUR_CALL, AXCALL, 7); // In case Add - Routes->NEIGHBOUR_PORT = Port; - Found = TRUE; - } - - if (strcmp(ptr, "!") == 0) - { - // Toggle Lock - - Routes->NEIGHBOUR_FLAG ^= 1; // FLIP LOCKED BIT - goto Displayit; - } - - if (strcmp(ptr, "Z") == 0) - { - // Clear Counts - - Routes->NBOUR_IFRAMES = 0; - Routes->NBOUR_RETRIES = 0; - goto Displayit; - } - - Routes->NEIGHBOUR_QUAL = atoi(ptr); - - if (Context && Context[0] == '!') - { - // Toggle Lock - - Routes->NEIGHBOUR_FLAG ^= 1; // FLIP LOCKED BIT - goto Displayit; - } - } - -Displayit: - - // Just display - - if (Found) - Bufferptr = DisplayRoute(Session, Bufferptr, Routes, 1); - else - Bufferptr = Cmdprintf(Session, Bufferptr, "Not Found\r"); - - - -/* MOV ROUTEDISP,1 - - CMP BYTE PTR [ESI],20H - JE SHORT JUSTDISPLAY - - MOV ZAPFLAG,0 - - CMP BYTE PTR [ESI],'Z' - JNE SHORT NOTZAP - - MOV ZAPFLAG,1 - JMP SHORT JUSTDISPLAY - - PUBLIC NOTZAP -NOTZAP: - - MOV ROUTEDISP,2 ; LOCK UPDATE - - CMP BYTE PTR [ESI],'!' - JE SHORT JUSTDISPLAY -; -; LOOK FOR V FOR ADDING A DIGI -; - CMP WORD PTR [ESI],' V' ; V [SPACE] - JE ADDDIGI - - CALL GETVALUE ; GET NUMBER, UP TO SPACE , CR OR OFFH - JC SHORT BADROUTECMD ; INVALID DIGITS - - MOV NEWROUTEVAL,AL - - MOV ROUTEDISP,0 - - CALL SCAN ; SEE IF ! - MOV AH,[ESI] - - - PUBLIC JUSTDISPLAY -JUSTDISPLAY: - - - MOV ESI,OFFSET32 AX25CALL - CALL _FINDNEIGHBOUR - JZ SHORT FOUNDROUTE ; IN LIST - OK - - CMP EBX,0 - JE SHORT BADROUTECMD ; TABLE FULL?? - - MOV ECX,7 - MOV EDI,EBX - REP MOVSB ; PUT IN CALL - - MOV AL,SAVEPORT - MOV NEIGHBOUR_PORT[EBX],AL - - JMP SHORT FOUNDROUTE - - - PUBLIC BADROUTECMD -BADROUTECMD: - - POP EDI - - JMP PBADVALUE - - PUBLIC FOUNDROUTE -FOUNDROUTE: - - CMP ZAPFLAG,1 - JNE SHORT NOTCLEARCOUNTS - - XOR AX,AX - MOV ES:WORD PTR NBOUR_IFRAMES[EDI],AX - MOV ES:WORD PTR NBOUR_IFRAMES+2[EDI],AX - MOV ES:WORD PTR NBOUR_RETRIES[EDI],AX - MOV ES:WORD PTR NBOUR_RETRIES+2[EDI],AX - - JMP SHORT NOUPDATE - - PUBLIC NOTCLEARCOUNTS -NOTCLEARCOUNTS: - - CMP ROUTEDISP,1 - JE SHORT NOUPDATE - - CMP ROUTEDISP,2 - JE SHORT LOCKUPDATE - - MOV AL,NEWROUTEVAL - MOV NEIGHBOUR_QUAL[EBX],AL - - CMP AH,'!' - JNE SHORT NOUPDATE - - PUBLIC LOCKUPDATE -LOCKUPDATE: - - XOR NEIGHBOUR_FLAG[EBX],1 ; FLIP LOCKED BIT - - PUBLIC NOUPDATE -NOUPDATE: - - MOV ESI,EBX - POP EDI - - POP EBX - CALL DISPLAYROUTE - - JMP SENDCOMMANDREPLY - - PUBLIC ADDDIGI -ADDDIGI: - - ADD ESI,2 - PUSH ESI ; SAVE INPUT BUFFER - - MOV ESI,OFFSET32 AX25CALL - CALL _FINDNEIGHBOUR - - POP ESI - - JZ SHORT ADD_FOUND ; IN LIST - OK - - JMP BADROUTECMD - - PUBLIC ADD_FOUND -ADD_FOUND: - - CALL CONVTOAX25 ; GET DIGI CALLSIGN - - PUSH ESI - - MOV ESI,OFFSET32 AX25CALL - LEA EDI,NEIGHBOUR_DIGI[EBX] - MOV ECX,7 - REP MOVSB - - POP ESI ; MSG BUFFER -; -; SEE IF ANOTHER DIGI -; - CMP BYTE PTR [ESI],20H - JE SHORT NOMORE - - CALL CONVTOAX25 ; GET DIGI CALLSIGN - MOV ESI,OFFSET32 AX25CALL - LEA EDI,NEIGHBOUR_DIGI+7[EBX] - MOV ECX,7 - REP MOVSB - - PUBLIC NOMORE -NOMORE: - - JMP NOUPDATE - - - -*/ - -SendReply: - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - - -VOID LISTENCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - // PROCESS LISTEN COMMAND - - // for monitoring a remote ax.25 port - - int Port = 0, index =0; - unsigned int ListenMask = 0; - char * ptr, *Context; - struct PORTCONTROL * PORT = NULL; - char ListenPortList[128] = ""; - - ptr = strtok_s(CmdTail, " ,", &Context); - - // Now accepts a list of ports - - if (ptr == 0 || memcmp(ptr, "OFF", 3) == 0) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Listening disabled\r"); - Session->LISTEN = 0; - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - while (ptr) - { - Port = atoi(ptr); - - if (Port == 0 && NUMBEROFPORTS == 1) - Port = 1; - - ptr = strtok_s(NULL, ", ", &Context); // Get Unproto String - - if (Port) - PORT = GetPortTableEntryFromPortNum(Port); - - if (PORT == NULL) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid Port %d\r", Port); - continue; - } - - if (PORT->PROTOCOL == 10 && PORT->UICAPABLE == 0) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Sorry, port %d is not an ax.25 port\r", Port); - continue; - } - - if (PORT->PORTL3FLAG) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Sorry, port %d is for internode traffic only\r", Port); - continue; - } - - if (Session->L4CIRCUITTYPE == L2LINK + UPLINK) - { - if (Session->L4TARGET.LINK->LINKPORT->PORTNUMBER == Port) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "You can't Listen to the port you are connected on\r"); - continue; - } - } - - sprintf(ListenPortList, "%s %d", ListenPortList, Port); - - - ListenMask |= (1 << (Port - 1)); - } - - Session->LISTEN = ListenMask; - - if (ListenMask) - { - if (CountBits(ListenMask) == 1) - Bufferptr = Cmdprintf(Session, Bufferptr, "Listening on port%s. Use CQ to send a beacon, LIS to disable\r", ListenPortList); - else - Bufferptr = Cmdprintf(Session, Bufferptr, "Listening on ports%s. Use LIS to disable\r", ListenPortList); - } - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; -} - - -VOID UNPROTOCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - // PROCESS UNPROTO COMMAND - - int Port = 0, index =0; - char * ptr, *Context; - struct PORTCONTROL * PORT = NULL; - UCHAR axcalls[64]; - BOOL Stay, Spy; - ptr = strtok_s(CmdTail, " ", &Context); - - if (ptr) - Port = atoi(ptr); - - if (Port == 0 && NUMBEROFPORTS == 1) - Port = 1; - else - ptr = strtok_s(NULL, " ", &Context); // Get Unproto String - - if (Port) - PORT = GetPortTableEntryFromPortNum(Port); - - if (PORT == NULL) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid Port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - if (ptr == NULL) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Destination missing\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - ptr[strlen(ptr)] = ' '; // Put param back together - - if (DecodeCallString(ptr, &Stay, &Spy, &axcalls[0]) == 0) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid Call\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - if (PORT->PROTOCOL == 10 && PORT->UICAPABLE == 0) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Sorry, port is not an ax.25 port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - if (PORT->PORTL3FLAG) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Sorry, port is for internode traffic only\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - // Copy Address Info to Session Record - - Session->UNPROTO = Port; - Session->UAddrLen = (int)strlen(axcalls); - memcpy(Session->UADDRESS, axcalls, 63); - - Bufferptr = Cmdprintf(Session, Bufferptr, "Unproto Mode - enter ctrl/z or /ex to exit\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; -} - -VOID CALCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - // PROCESS CAL COMMAND - - int Port = 0, index = 0, Count = 0; - char * ptr, *Context; - struct PORTCONTROL * PORT = NULL; - - ptr = strtok_s(CmdTail, " ", &Context); - - if (ptr) - Port = atoi(ptr); - - if (Port == 0 && NUMBEROFPORTS == 1) - Port = 1; - else - ptr = strtok_s(NULL, " ", &Context); // Get Unproto String - - if (Port) - PORT = GetPortTableEntryFromPortNum(Port); - - if (PORT == NULL) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid Port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - if (PORT->PROTOCOL == 10 && PORT->UICAPABLE == 0) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Sorry, port is not an ax.25 port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - if (ptr == NULL) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Count Missing\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - Count = atoi(ptr); - - ptr = strtok_s(NULL, " ", &Context); // Get Unproto String - - Bufferptr = Cmdprintf(Session, Bufferptr, "Ok\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; -} - - - -VOID CQCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - // Send a CQ Beacon on a radio port. Must be in LISTEN state - - DIGIMESSAGE Msg; - int Port = 0; - int OneBits = 0; - unsigned int MaskCopy = Session->LISTEN; - int Len; - UCHAR CQCALL[7]; - char Empty[] = ""; - char * ptr1 = &OrigCmdBuffer[3]; - UCHAR * axptr = &Msg.DIGIS[0][0]; - char * ptr2, *Context; - - while (MaskCopy) - { - if (MaskCopy & 1) - OneBits++; - - Port++; - MaskCopy = MaskCopy >> 1; - } - - if (OneBits == 0) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "You must enter LISTEN before calling CQ\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - if (OneBits > 1) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "You can't call CQ if LISTENing on more than one port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - - Len = (int)strlen(OrigCmdBuffer) - 3; - - if (Len < 0) - Len = 0; - - memset(&Msg, 0, sizeof(Msg)); - - Msg.PORT = Port; - Msg.CTL = 3; // UI - - // see if a Via specified - - if (_memicmp(ptr1, "via ", 4) == 0) - { - ptr2 = strtok_s(ptr1 + 4, ",", &Context); - - while (ptr2) - { - if (ConvToAX25(ptr2, axptr) == 0) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid via string\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - axptr += 7; - - if (axptr == &Msg.DIGIS[7][0]) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Too many digis\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - ptr1 = ptr2; - ptr2 = strtok_s(NULL, ",", &Context); - } - - // ptr1 is start of last digi call. We need to position to data - - ptr1 = strchr(ptr1, ' '); - - if (ptr1 == NULL) - ptr1 = Empty; - else - ptr1++ ; // to message - - Len = (int)strlen(ptr1); - - } - - ConvToAX25("CQ", CQCALL); - memcpy(Msg.DEST, CQCALL, 7); - memcpy(Msg.ORIGIN, Session->L4USER, 7); - Msg.ORIGIN[6] ^= 0x1e; // Flip SSID - Msg.PID = 0xf0; // Data PID - memcpy(&Msg.L2DATA, ptr1, Len); - - Send_AX_Datagram(&Msg, Len + 2, Port); // Len is Payload ie CTL, PID and Data - - Bufferptr = Cmdprintf(Session, Bufferptr, "CQ sent\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - -} - - -TRANSPORTENTRY * SetupNewSession(TRANSPORTENTRY * Session, char * Bufferptr) -{ - TRANSPORTENTRY * NewSess = L4TABLE; - int Index = 0; - - while (Index < MAXCIRCUITS) - { - if (NewSess->L4USER[0] == 0) - { - // Got One - - Session->L4CROSSLINK = NewSess; - NewSess->L4CROSSLINK = Session; - - memcpy(NewSess->L4USER, Session->L4USER, 7); - memcpy(NewSess->L4MYCALL, Session->L4MYCALL, 7); - - - NewSess->CIRCUITINDEX = Index; //OUR INDEX - NewSess->CIRCUITID = NEXTID; - - NEXTID++; - if (NEXTID == 0) - NEXTID++; // kEEP nON-ZERO - - NewSess->SESSIONT1 = Session->SESSIONT1; - NewSess->L4WINDOW = (UCHAR)L4DEFAULTWINDOW; - - return NewSess; - } - Index++; - NewSess++; - } - - if (Bufferptr) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Sorry - System Tables Full\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - } - - return NULL; -} - - -VOID DoNetromConnect(TRANSPORTENTRY * Session, char * Bufferptr, struct DEST_LIST * Dest, BOOL Spy) -{ - TRANSPORTENTRY * NewSess; - - NewSess = SetupNewSession(Session, Bufferptr); - - if (NewSess == NULL) - return; // Tables Full - - NewSess->L4CIRCUITTYPE = SESSION + DOWNLINK; - - NewSess->L4TARGET.DEST = Dest; - NewSess->L4STATE = 2; // CONNECTING - - NewSess->SPYFLAG = Spy; - - ReleaseBuffer((UINT *)REPLYBUFFER); - - SENDL4CONNECT(NewSess); - - L4CONNECTSOUT++; - - return; -} - -BOOL FindLink(UCHAR * LinkCall, UCHAR * OurCall, int Port, struct _LINKTABLE ** REQLINK) -{ - struct _LINKTABLE * LINK = LINKS; - struct _LINKTABLE * FIRSTSPARE = NULL; - int n = MAXLINKS; - - while (n--) - { - if (LINK->LINKCALL[0] == 0) // Spare - { - if (FIRSTSPARE == NULL) - FIRSTSPARE = LINK; - - LINK++; - continue; - } - - if ((LINK->LINKPORT->PORTNUMBER == Port) && CompareCalls(LINK->LINKCALL, LinkCall) && CompareCalls(LINK->OURCALL, OurCall)) - { - *REQLINK = LINK; - return TRUE; - } - - LINK++; - } - // ENTRY NOT FOUND - FIRSTSPARE HAS FIRST FREE ENTRY, OR ZERO IF TABLE FULL - - *REQLINK = FIRSTSPARE; - return FALSE; -} - -VOID ATTACHCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * UserCMD); - -VOID CMDC00(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - // PROCESS CONNECT COMMAND - - TRANSPORTENTRY * NewSess; - - int CONNECTPORT, Port; - BOOL CallEvenIfInNodes = FALSE; - char * ptr, *Context; - UCHAR axcalls[64]; - UCHAR ourcall[7]; // Call we are using (may have SSID bits inverted - int ret; - struct PORTCONTROL * PORT = PORTTABLE; - struct _LINKTABLE * LINK; - int CQFLAG = 0; // NOT CQ CALL - BOOL Stay, Spy; - int n; - char TextCall[10]; - int TextCallLen; - char PortString[10]; - char cmdCopy[256]; - struct _EXTPORTDATA * EXTPORT = (struct _EXTPORTDATA *)PORT;; - - -#ifdef EXCLUDEBITS - - if (CheckExcludeList(Session->L4USER) == FALSE) - { - // CONNECTS FROM THIS STATION ARE NOT ALLOWED - - ReleaseBuffer((UINT *)REPLYBUFFER); - return; - } - -#endif - - if (Session->LISTEN) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Can't connect while listening\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - CONNECTPORT = 0; // NO PORT SPECIFIED - - ptr = strtok_s(CmdTail, " ", &Context); - - strcpy(cmdCopy, Context); // Save in case Telnet Connect - - if (ptr == 0) - { - // No param - - if (CFLAG) // C Command Disabled ? - { - // Convert to HOST (appl 32) command - - //MOV _CMDPTR,OFFSET32 _HOSTCMD - //MOV _ALIASPTR,OFFSET32 _HOSTCMD + 32 * 31 - - //MOV _APPLMASK, 80000000H ; Internal Term - - } - - Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid Call\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - Port = atoi(ptr); - - if (Port) - { - // IF THERE IS NOTHING FOLLOWING THE NUMBER, ASSUME IT IS A - // NUMERIC ALIAS INSTEAD OF A PORT - - sprintf(PortString, "%d", Port); - - if (strlen(PortString) < (int)strlen(ptr)) - goto NoPort; - - PORT = GetPortTableEntryFromPortNum(Port); - - if (PORT == NULL) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid Port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - EXTPORT = (struct _EXTPORTDATA *)PORT; - - ptr = strtok_s(NULL, " ", &Context); - - if (ptr == 0) - { - // No param - - Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid Call\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - CONNECTPORT = Port; - - if (strcmp(ptr, "CMS") == 0 || strcmp(ptr, "HOST") == 0) // In case someeone has CMS or HOST as an alias - goto Downlink; - - } - -NoPort: - - ptr[strlen(ptr)] = ' '; // Put param back together - - if (ptr[0] == '!') - { - CallEvenIfInNodes = TRUE; - ptr++; - } - - if (memcmp(ptr, "RELAY ", 5) == 0 || memcmp(ptr, "SYNC ", 5) == 0) - { - // c p relay with extra parms - - goto Downlink; - } - - // Skip call validation if using a ptc to allow 1:call, 2:call format - - if (Port && PORT->PROTOCOL == 10 && memcmp(EXTPORT->PORT_DLL_NAME, "SCSPACTOR", 9) == 0) - { - char * p; - - if (p = strstr(cmdCopy, " S ")) - { - Stay = TRUE; - p++; - *p = ' '; - } - - if (p = strstr(cmdCopy, " Z ")) - { - Spy = TRUE; - p++; - *p = ' '; - } - - goto Downlink; - } - else - { - if (DecodeCallString(ptr, &Stay, &Spy, &axcalls[0]) == 0) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid Call\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - } - - Session->STAYFLAG = Stay; - - TextCallLen = ConvFromAX25(axcalls, TextCall); - - if (CallEvenIfInNodes) - goto Downlink; - - // SEE IF CALL TO ANY OF OUR HOST SESSIONS - UNLESS DIGIS SPECIFIED - - if (axcalls[7] == 0) - { - // If this connect is as a result of a command alias, don't check appls or we will loop - - if (ALIASINVOKED == 0) - { - APPLCALLS * APPL = APPLCALLTABLE; - int n = NumberofAppls; - APPLMASK = 1; - - while (n--) - { - if (memcmp(axcalls, APPL->APPLALIAS, 6) == 0 || CompareCalls(axcalls, APPL->APPLCALL)) - { - // Call to an appl - - // Convert to an APPL command, so any alias is actioned - - // SEE IF THERE IS AN ALIAS DEFINDED FOR THIS COMMAND - - if (APPL->APPLHASALIAS && APPL->APPLALIASVAL[0] != 0x20) - { - // COPY ALIAS TO COMMAND _BUFFER, THEN REENTER COMMAND HANDLER - - memcpy(COMMANDBUFFER, APPL->APPLALIASVAL, ALIASLEN); - COMMANDBUFFER[80] = 0; - _strupr(COMMANDBUFFER); - memcpy(OrigCmdBuffer, APPL->APPLALIASVAL, ALIASLEN); // In case original case version needed - - ALIASINVOKED = TRUE; // To prevent Alias Loops - } - else - { - - // Copy Appl Command to Command Buffer. Ensure doesn't contain old command - - memset(COMMANDBUFFER, ' ', 72); - memcpy(COMMANDBUFFER, APPL->APPLCMD, 12); - } - DoTheCommand(Session); - return; - } - APPL++; - APPLMASK <<= 1; - } - } - } - - if (axcalls[7] == 0) - { - // SEE IF CALL TO ANOTHER NODE - - struct DEST_LIST * Dest = DESTS; - int n = MAXDESTS; - - if (axcalls[6] == 0x60) // if SSID, dont check aliases - { - while (n--) - { - if (memcmp(Dest->DEST_ALIAS, TextCall, 6) == 0) - { - DoNetromConnect(Session, Bufferptr, Dest, Spy); - return; - } - Dest++; - } - } - - Dest = DESTS; - n = MAXDESTS; - - while (n--) - { - if (CompareCalls(Dest->DEST_CALL, axcalls)) - { - DoNetromConnect(Session, Bufferptr, Dest, Spy); - return; - } - Dest++; - } - } - - // Must be Downlink Connect - -Downlink: - - if (CONNECTPORT == 0 && NUMBEROFPORTS > 1) - { - // L2 NEEDS PORT NUMBER - - Bufferptr = Cmdprintf(Session, Bufferptr, "Downlink connect needs port number - C P CALLSIGN\r"); - - // Send Port List - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - // ENSURE PORT IS AVAILABLE FOR L2 USE - - if (PORT->PROTOCOL >= 10) // Pactor=-style port? - { - int count; - - // if Via PACTOR ARDOP WINMOR or VARA, convert to attach and call = Digi's are in AX25STRING (+7) - - if (memcmp(&axcalls[7], &WINMOR[0], 6) == 0 || - memcmp(&axcalls[7], &ARDOP[0], 6) == 0 || - memcmp(&axcalls[7], &VARA[0], 6) == 0 || - memcmp(&axcalls[7], &PACTORCALL[0], 6) == 0) - { - char newcmd[80]; - - TextCall[TextCallLen] = 0; - sprintf(newcmd, "%s %s", CmdTail, TextCall); - - ATTACHCMD(Session, Bufferptr, newcmd, NULL); - return; - } - - // If on a KAM or SCS with ax.25 on port 2, do an Attach command, then pass on connect - - if (EXTPORT->MAXHOSTMODESESSIONS <= 1) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Sorry, port is not an ax.25 port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - // Only Allow Attach VHF from Secure Applications or if PERMITGATEWAY is set - - if (EXTPORT->PERMITGATEWAY == 0 && Session->Secure_Session == 0) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Sorry, you are not allowed to use this port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - count = EXTPORT->MAXHOSTMODESESSIONS; - count--; // First is Pactor Stream, count is now last ax.25 session - - while (count) - { - if (EXTPORT->ATTACHEDSESSIONS[count] == 0) - { - int Paclen, PortPaclen; - struct DATAMESSAGE * Buffer; - struct DATAMESSAGE Message = {0}; - char Callstring[80]; - int len; - - // Found a free one - use it - - // See if TNC is OK - - Message.PORT = count; - - ret = PORT->PORTTXCHECKCODE(PORT, Message.PORT); - - if ((ret & 0xff00) == 0) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Error - TNC Not Ready\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - // GET CIRCUIT TABLE ENTRY FOR OTHER END OF LINK - - NewSess = SetupNewSession(Session, Bufferptr); - if (NewSess == NULL) - return; - - // if a UZ7HO port, and the uplink is L2 or Uz7HO invert SSID bits - - // We only get here if multisession - - if (memcmp(EXTPORT->PORT_DLL_NAME, "UZ7HO", 5) != 0) - goto noFlip; - - if ((Session->L4CIRCUITTYPE & BPQHOST))// host - goto noFlip; - - if ((Session->L4CIRCUITTYPE & PACTOR)) - { - // incoming is Pactorlike - see if UZ7HO - - if (memcmp(Session->L4TARGET.EXTPORT->PORT_DLL_NAME, "UZ7HO", 5) != 0) - goto noFlip; - else - NewSess->L4USER[6] ^= 0x1e; // UZ7HO Uplink - flip - } - else - - // Must be L2 uplink - flip - - NewSess->L4USER[6] ^= 0x1e; // Flip SSID -noFlip: - EXTPORT->ATTACHEDSESSIONS[count] = NewSess; - - NewSess->KAMSESSION = count; - - // Set paclen to lower of incoming and outgoing - - Paclen = Session->SESSPACLEN; // Incoming PACLEN - - if (Paclen == 0) - Paclen = 256; // 0 = 256 - - PortPaclen = PORT->PORTPACLEN; - - if (PortPaclen == 0) - PortPaclen = 256; // 0 = 256 - - if (PortPaclen < Paclen) - Paclen = PortPaclen; - - NewSess->SESSPACLEN = Paclen; - Session->SESSPACLEN = Paclen; - - NewSess->L4STATE = 5; - NewSess->L4CIRCUITTYPE = DOWNLINK + PACTOR; - NewSess->L4TARGET.PORT = PORT; - - // Send the connect command to the TNC - - Buffer = REPLYBUFFER; - - Buffer->PORT = count; - Buffer->PID = 0xf0; - - // if on Telnet Port convert use original cmd tail - - // Why just on telnet - what not all ports?? - - if (memcmp(EXTPORT->PORT_DLL_NAME, "TELNET", 6) == 0 || memcmp(EXTPORT->PORT_DLL_NAME, "SCSPACTOR", 9) == 0) - { - NewSess->Secure_Session = Session->Secure_Session; - len = sprintf(Callstring,"C %s", cmdCopy); - } - else - { - TextCall[TextCallLen] = 0; - - len = sprintf(Callstring,"C %s", TextCall); - - if (axcalls[7]) - { - int digi = 7; - - // we have digis - - len += sprintf(&Callstring[len], " via"); - - while (axcalls[digi]) - { - TextCall[ConvFromAX25(&axcalls[digi], TextCall)] = 0; - len += sprintf(&Callstring[len], " %s", TextCall); - digi += 7; - } - } - } - Callstring[len++] = 13; - Callstring[len] = 0; - - Buffer->LENGTH = len + MSGHDDRLEN + 1; - memcpy(Buffer->L2DATA, Callstring, len); - C_Q_ADD(&PORT->PORTTX_Q, (UINT *)Buffer); - - return; - } - count--; - } - - Bufferptr = Cmdprintf(Session, Bufferptr, "Error - No free streams on this port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - if ((Session->L4CIRCUITTYPE & BPQHOST) == 0 && PORT->PORTL3FLAG) - { - //Port only for L3 - - Bufferptr = Cmdprintf(Session, Bufferptr, "Sorry, port is for internode traffic only\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - if (PORT->PortUIONLY) - { - //Port only for UI - - Bufferptr = Cmdprintf(Session, Bufferptr, "Sorry, port is for UI traffic only\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - if (Session->L4USER[6] == 0x42 || Session->L4USER[6] == 0x44) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Sorry - Can't make ax.25 calls with SSID of T or R\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - // Get Session Entry for Downlink - - NewSess = SetupNewSession(Session, Bufferptr); - if (NewSess == NULL) - return; - - NewSess->L4CIRCUITTYPE = L2LINK + DOWNLINK; - - // FORMAT LINK TABLE ENTRY FOR THIS CONNECTION - - memcpy(ourcall, NewSess->L4USER, 7); - - // SSID SWAP TEST - LEAVE ALONE FOR HOST or Pactor like (unless UZ7HO) - - if ((Session->L4CIRCUITTYPE & BPQHOST))// host - goto noFlip3; - - if ((Session->L4CIRCUITTYPE & PACTOR)) - { - // incoming is Pactorlike - see if UZ7HO - - if (memcmp(Session->L4TARGET.EXTPORT->PORT_DLL_NAME, "UZ7HO", 5) != 0) - goto noFlip3; - - if (Session->L4TARGET.EXTPORT->MAXHOSTMODESESSIONS < 2) // Not multisession - goto noFlip3; - - ourcall[6] ^= 0x1e; // UZ7HO Uplink - flip - } - else - - // Must be L2 uplink - flip - - ourcall[6] ^= 0x1e; // Flip SSID - -noFlip3: - - // SET UP NEW SESSION (OR RESET EXISTING ONE) - - FindLink(axcalls, ourcall, Port, &LINK); - - if (LINK == NULL) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Sorry - System Tables Full\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - - // Should release NewSess - - return; - } - - memcpy(LINK->LINKCALL, axcalls, 7); - memcpy(LINK->OURCALL, ourcall, 7); - - LINK->LINKPORT = PORT; - - LINK->L2TIME = PORT->PORTT1; - - // Copy Digis - - n = 7; - ptr = &LINK->DIGIS[0]; - - while (axcalls[n]) - { - memcpy(ptr, &axcalls[n], 7); - n += 7; - ptr += 7; - - LINK->L2TIME += 2 * PORT->PORTT1; // ADJUST TIMER VALUE FOR 1 DIGI - } - - LINK->LINKTYPE = 2; // DOWNLINK - LINK->LINKWINDOW = PORT->PORTWINDOW; - - RESET2(LINK); // RESET ALL FLAGS - - if (CMD->String[0] == 'N' && SUPPORT2point2) - LINK->L2STATE = 1; // New (2.2) send XID - else - LINK->L2STATE = 2; // Send SABM - - LINK->CIRCUITPOINTER = NewSess; - - NewSess->L4TARGET.LINK = LINK; - - if (PORT->PORTPACLEN) - NewSess->SESSPACLEN = Session->SESSPACLEN = PORT->PORTPACLEN; - - if (CQFLAG == 0) // if a CQ CALL DONT SEND SABM - { - if (LINK->L2STATE == 1) - L2SENDXID(LINK); - else - SENDSABM(LINK); - } - ReleaseBuffer((UINT *)REPLYBUFFER); - return; -} - -BOOL DecodeCallString(char * Calls, BOOL * Stay, BOOL * Spy, UCHAR * AXCalls) -{ - // CONVERT CALL + OPTIONAL DIGI STRING TO AX25, RETURN - // CONVERTED STRING IN AXCALLS. Return FALSE if invalied - - char * axptr = AXCalls; - char * ptr, *Context; - int CQFLAG = 0; // NOT CQ CALL - int n = 8; // Max digis - - *Stay = 0; - *Spy = 0; - - memset(AXCalls, 0, 64); - - ptr = strtok_s(Calls, " ,", &Context); - - if (ptr == NULL) - return FALSE; - - // First field is Call - - if (ConvToAX25(ptr, axptr) == 0) - return FALSE; - - axptr += 7; - - ptr = strtok_s(NULL, " ,", &Context); - - while (ptr && n--) - { - // NEXT FIELD = COULD BE CALLSIGN, VIA, OR S (FOR STAY) - - if (strcmp(ptr, "S") == 0) - *Stay = TRUE; - else if (strcmp(ptr, "Z") == 0) - *Spy = TRUE; - else if (memcmp(ptr, "VIA", (int)strlen(ptr)) == 0) - { - } //skip via - else - { - // Convert next digi - - if (ConvToAX25(ptr, axptr) == 0) - return FALSE; - - axptr += 7; - } - - ptr = strtok_s(NULL, " ,", &Context); - } - - return TRUE; -} - - -VOID LINKCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - // PROCESS *** LINKED to CALLSIGN - - char * ptr, *Context; - UCHAR axcall[7]; - int ret; - - if (LINKEDFLAG == 'Y' || // UNCONDITIONAL? - (LINKEDFLAG == 'A' && - ((Session->L4CIRCUITTYPE & BPQHOST) || Session->Secure_Session || Session->PASSWORD == 0xffff))) - { - ptr = strtok_s(CmdTail, " ", &Context); - if (ptr) - ptr = strtok_s(NULL, " ", &Context); - - if (ptr) - { - ret = ConvToAX25Ex(ptr, axcall); - - if (ret) - { - memcpy(Session->L4USER, axcall, 7); - strcpy(Bufferptr, OKMSG); - Bufferptr += (int)strlen(OKMSG); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - } - - strcpy(Bufferptr, BADMSG); - Bufferptr += (int)strlen(BADMSG); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - memcpy(Bufferptr, PASSWORDMSG, LPASSMSG); - Bufferptr += LPASSMSG; - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - -int CompareNode(const void *a, const void *b); -int CompareAlias(const void *a, const void *b); - -char * DoOneNode(TRANSPORTENTRY * Session, char * Bufferptr, struct DEST_LIST * Dest) -{ - char Normcall[10]; - char Alias[10]; - struct NR_DEST_ROUTE_ENTRY * NRRoute; - struct DEST_ROUTE_ENTRY * Route; - struct ROUTE * Neighbour; - int i, Active, len; - - Alias[6] = 0; - - memcpy(Alias, Dest->DEST_ALIAS, 6); - strlop(Alias, ' '); - - Normcall[ConvFromAX25(Dest->DEST_CALL, Normcall)] = 0; - - Bufferptr = Cmdprintf(Session, Bufferptr, "Routes to: %s:%s", Alias, Normcall); - - if (Dest->DEST_COUNT) - Bufferptr = Cmdprintf(Session, Bufferptr, " RTT=%4.2f FR=%d %c %.1d\r", - Dest->DEST_RTT /1000.0, Dest->DEST_COUNT, - (Dest->DEST_STATE & 0x40)? 'B':' ', (Dest->DEST_STATE & 63)); - else - Bufferptr = Cmdprintf(Session, Bufferptr, "\r"); - - NRRoute = &Dest->NRROUTE[0]; - - Active = Dest->DEST_ROUTE; - - for (i = 1; i < 4; i++) - { - Neighbour = NRRoute->ROUT_NEIGHBOUR; - - if (Neighbour) - { - len = ConvFromAX25(Neighbour->NEIGHBOUR_CALL, Normcall); - Normcall[len] = 0; - - Bufferptr = Cmdprintf(Session, Bufferptr, "%c %d %d %d %s\r", - (Active == i)?'>':' ',NRRoute->ROUT_QUALITY, NRRoute->ROUT_OBSCOUNT, Neighbour->NEIGHBOUR_PORT, Normcall); - } - NRRoute++; - } - - // DISPLAY INP3 ROUTES - - Route = &Dest->ROUTE[0]; - - Active = Dest->DEST_ROUTE; - - for (i = 1; i < 4; i++) - { - Neighbour = Route->ROUT_NEIGHBOUR; - - if (Neighbour) - { - double srtt = Route->SRTT/1000.0; - - len = ConvFromAX25(Neighbour->NEIGHBOUR_CALL, Normcall); - Normcall[len] = 0; - - Bufferptr = Cmdprintf(Session, Bufferptr, "%c %d %4.2fs %d %s\r", - (Active == i + 3)?'>':' ',Route->Hops, srtt, Neighbour->NEIGHBOUR_PORT, Normcall); - } - Route++; - } - - return Bufferptr; -} - - -int DoViaEntry(struct DEST_LIST * Dest, int n, char * line, int cursor) -{ - char Portcall[10]; - int len; - - if (Dest->NRROUTE[n].ROUT_NEIGHBOUR != 0 && Dest->NRROUTE[n].ROUT_NEIGHBOUR->INP3Node == 0) - { - len=ConvFromAX25(Dest->NRROUTE[n].ROUT_NEIGHBOUR->NEIGHBOUR_CALL, Portcall); - Portcall[len]=0; - - len=sprintf(&line[cursor],"%s %d %d ", - Portcall, - Dest->NRROUTE[n].ROUT_NEIGHBOUR->NEIGHBOUR_PORT, - Dest->NRROUTE[n].ROUT_QUALITY); - - cursor+=len; - - if (Dest->NRROUTE[n].ROUT_OBSCOUNT > 127) - { - len=sprintf(&line[cursor],"! "); - cursor+=len; - } - } - return cursor; -} - -int DoINP3ViaEntry(struct DEST_LIST * Dest, int n, char * line, int cursor) -{ - char Portcall[10]; - int len; - double srtt; - - if (Dest->ROUTE[n].ROUT_NEIGHBOUR != 0) - { - srtt = Dest->ROUTE[n].SRTT/1000.0; - - len=ConvFromAX25(Dest->ROUTE[n].ROUT_NEIGHBOUR->NEIGHBOUR_CALL, Portcall); - Portcall[len]=0; - - len=sprintf(&line[cursor],"%s %d %d %4.2fs ", - Portcall, - Dest->ROUTE[n].ROUT_NEIGHBOUR->NEIGHBOUR_PORT, - Dest->ROUTE[n].Hops, srtt); - - cursor+=len; - - if (Dest->NRROUTE[n].ROUT_OBSCOUNT > 127) - { - len=sprintf(&line[cursor],"! "); - cursor+=len; - } - } - return cursor; -} - -int WildCmp(char * pattern, char * string) -{ - // Check if string is at end or not. - - if (*pattern == '\0') - return *string == '\0'; - - // Check for single character missing or match - - if (*pattern == '?' || *pattern == *string) - return *string != '\0' && WildCmp(pattern + 1, string + 1); - - if (*pattern == '*') - { - // Check for multiple character missing - - return WildCmp(pattern + 1, string) || (*string != '\0' && WildCmp(pattern, string + 1)); - } - - return 0; -} - -VOID CMDN00(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - struct DEST_LIST * Dest = DESTS; - int count = MAXDESTS, i; - char Normcall[10]; - char Alias[10]; - int Width = 4; - int x = 0, n = 0; - struct DEST_LIST * List[1000]; - char Param = 0; - char * ptr, * param2,* Context; - char Nodeline[21]; - char AXCALL[7]; - char * Call; - char * Qualptr; - int Qual; - char line[160]; - int cursor, len; - UCHAR axcall[7]; - int SavedOBSINIT = OBSINIT; - struct ROUTE * ROUTE = NULL; - char Pattern[80] = ""; - char * firststar; - int minqual = 0; - - ptr = strtok_s(CmdTail, " ", &Context); - param2 = strtok_s(NULL, " ", &Context); - - if (ptr) - { - if (strcmp(ptr, "ADD") == 0) - goto NODE_ADD; - - if (strcmp(ptr, "DEL") == 0) - goto NODE_DEL; - - if (strcmp(ptr, "VIA") == 0) - goto NODE_VIA; - } - - if (ptr) - { - // Could be C or a pattern. Accept C pattern or pattern C - - if ((int)strlen(ptr) > 1) - { - strcpy(Pattern, ptr); - if (param2 && param2[0] == 'C') - Param = 'C'; - } - else - { - Param = ptr[0]; - if (param2) - strcpy(Pattern, param2); - } - } - - // Pattern >nnn selects nodes with at least that quality - - if (Pattern[0] == '>') - { - minqual = atoi(&Pattern[1]); - Pattern[0] = 0; - } - - // We need to pick out CALL or CALL* from other patterns (as call use detail display) - - firststar = strchr(Pattern, '*'); - - if ((firststar && *(firststar + 1) != 0)|| strchr(Pattern, '?')) //(* not on end) - - // definitely pattern - - goto DoNodePattern; - - // If it works as CALL*, process, else drop through - - if (Pattern[0]) - { - UCHAR AXCall[8]; - int count; - int paramlen = (int)strlen(ptr); - char parampadded[20]; - int n = 0; - - Alias[8] = 0; - strcpy(parampadded, Pattern); - strcat(parampadded, " "); - - ConvToAX25(Pattern, AXCall); - - // if * on end, list all ssids - - if (firststar) - { - AXCall[6] = 0; - - Bufferptr = Cmdprintf(Session, Bufferptr, "\r"); - - while (AXCall[6] < 32) - { - Dest = DESTS; - - for (count = 0; count < MAXDESTS; count++) - { - if (memcmp(Dest->DEST_ALIAS, parampadded, 6) == 0 || CompareCalls(Dest->DEST_CALL, AXCall)) - { - break; - } - Dest++; - } - - if (count < MAXDESTS) - { - Bufferptr = DoOneNode(Session, Bufferptr, Dest); - n++; - } - - AXCall[6] += 2; - } - - if (n) // Found Some - { - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - Dest = DESTS; // Reset - - // Drop through to try as pattern - } - else - { - // process as just call - - for (count = 0; count < MAXDESTS; count++) - { - if (memcmp(Dest->DEST_ALIAS, parampadded, 6) == 0 || CompareCalls(Dest->DEST_CALL, AXCall)) - { - break; - } - Dest++; - } - - if (count == MAXDESTS) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Not found\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - Bufferptr = DoOneNode(Session, Bufferptr, Dest); - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - } - -DoNodePattern: - - Bufferptr = Cmdprintf(Session, Bufferptr, "Nodes\r"); - - while (count--) - { - if (Dest->DEST_CALL[0] != 0) - { - if (Dest->NRROUTE->ROUT_QUALITY >= minqual) - if (Param != 'T' || Dest->DEST_COUNT) - List[n++] = Dest; - - if (n > 999) - break; - } - Dest++; - } - - if (Param == 'C') - qsort(List, n, sizeof(void *), CompareNode); - else - qsort(List, n, sizeof(void *), CompareAlias); - - - for (i = 0; i < n; i++) - { - int len = ConvFromAX25(List[i]->DEST_CALL, Normcall); - Normcall[len]=0; - - memcpy(Alias, List[i]->DEST_ALIAS, 6); - Alias[6] = 0; - strlop(Alias, ' '); - - if (strlen(Alias)) - strcat(Alias, ":"); - - if (Alias[0] == '#' && HIDENODES == 1 && Param != '*') // Hidden Node and not N * command - continue; - - if (Pattern[0]) - if (!WildCmp(Pattern, Normcall) && !WildCmp(Pattern, Alias)) - continue; - - if (Param == 'T') - { - Bufferptr = Cmdprintf(Session, Bufferptr, "%s%s RTT=%4.2f Frames = %d %c %.1d\r", - Alias, Normcall, List[i]->DEST_RTT /1000.0, List[i]->DEST_COUNT, - (List[i]->DEST_STATE & 0x40)? 'B':' ', (List[i]->DEST_STATE & 63)); - } - else - { - len = sprintf(Nodeline, "%s%s", Alias, Normcall); - memset(&Nodeline[len], ' ', 20 - len); - Nodeline[20] = 0; - Bufferptr = Cmdprintf(Session, Bufferptr, "%s", Nodeline); - - if (++x == Width) - { - x = 0; - Bufferptr = Cmdprintf(Session, Bufferptr, "\r"); - } - } - } - - if (x) - Bufferptr = Cmdprintf(Session, Bufferptr, "\r"); - - goto SendReply; - - -NODE_VIA: - - // List Nodes reachable via a neighbour - - ptr = param2; - - if (ptr == NULL) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Missing Call\r"); - goto SendReply; - } - - Bufferptr = Cmdprintf(Session, Bufferptr, "\r"); - - ConvToAX25(ptr, AXCALL); - - Dest = DESTS; - - Dest-=1; - - for (count=0; countNRROUTE[0].ROUT_NEIGHBOUR == 0 && Dest->ROUTE[0].ROUT_NEIGHBOUR == 0) - continue; - - - if ((Dest->NRROUTE[0].ROUT_NEIGHBOUR && CompareCalls(Dest->NRROUTE[0].ROUT_NEIGHBOUR->NEIGHBOUR_CALL, AXCALL)) - || (Dest->NRROUTE[1].ROUT_NEIGHBOUR && CompareCalls(Dest->NRROUTE[1].ROUT_NEIGHBOUR->NEIGHBOUR_CALL, AXCALL)) - || (Dest->NRROUTE[2].ROUT_NEIGHBOUR && CompareCalls(Dest->NRROUTE[2].ROUT_NEIGHBOUR->NEIGHBOUR_CALL, AXCALL)) - - || (Dest->ROUTE[0].ROUT_NEIGHBOUR && CompareCalls(Dest->ROUTE[0].ROUT_NEIGHBOUR->NEIGHBOUR_CALL, AXCALL)) - || (Dest->ROUTE[1].ROUT_NEIGHBOUR && CompareCalls(Dest->ROUTE[1].ROUT_NEIGHBOUR->NEIGHBOUR_CALL, AXCALL)) - || (Dest->ROUTE[2].ROUT_NEIGHBOUR && CompareCalls(Dest->ROUTE[2].ROUT_NEIGHBOUR->NEIGHBOUR_CALL, AXCALL))) - { - len=ConvFromAX25(Dest->DEST_CALL,Normcall); - - Normcall[len]=0; - - memcpy(Alias,Dest->DEST_ALIAS,6); - - Alias[6]=0; - - for (i=0;i<6;i++) - { - if (Alias[i] == ' ') - Alias[i] = 0; - } - - cursor=sprintf(line,"%s:%s ", Alias,Normcall); - - cursor = DoViaEntry(Dest, 0, line, cursor); - cursor = DoViaEntry(Dest, 1, line, cursor); - cursor = DoViaEntry(Dest, 2, line, cursor); - cursor = DoINP3ViaEntry(Dest, 0, line, cursor); - cursor = DoINP3ViaEntry(Dest, 1, line, cursor); - cursor = DoINP3ViaEntry(Dest, 2, line, cursor); - - line[cursor++]='\r'; - line[cursor++]=0; - - Bufferptr = Cmdprintf(Session, Bufferptr, "%s", line); - } - } - - - goto SendReply; - -NODE_ADD: - - // FORMAT IS NODE ADD ALIAS:CALL QUAL ROUTE PORT - - - if (Session->PASSWORD != 0xFFFF) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "%s", PASSWORDMSG); - goto SendReply; - } - - ptr = param2; - - if (ptr == NULL) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Missing Alias:Call\r"); - goto SendReply; - } - - Call = strlop(ptr, ':'); - - if (Call == NULL) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Missing Alias:Call\r"); - goto SendReply; - } - - - ConvToAX25(Call, AXCALL); - - Qualptr = strtok_s(NULL, " ", &Context); - - if (Qualptr == 0) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Quality missing\r"); - goto SendReply; - } - - Qual = atoi(Qualptr); - - if (Qual < MINQUAL) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Quality is below MINQUAL\r"); - goto SendReply; - } - - if (FindDestination(AXCALL, &Dest)) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Node already in Table\r"); - goto SendReply; - } - - if (Dest == NULL) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Node Table Full\r"); - goto SendReply; - } - - memcpy(Dest->DEST_CALL, AXCALL, 7); - memcpy(Dest->DEST_ALIAS, ptr, 6); - - NUMBEROFNODES++; - - ptr = strtok_s(NULL, " ", &Context); - - if (ptr == NULL || ptr[0] == 0) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Neighbour missing\r"); - goto SendReply; - } - - if (ConvToAX25(ptr, axcall) == 0) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid Neighbour\r"); - goto SendReply; - } - else - { - int Port; - - ptr = strtok_s(NULL, " ", &Context); - if (ptr == NULL) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Port missing\r"); - goto SendReply; - } - - Port = atoi(ptr); - - if (Context[0] == '!') - { - OBSINIT = 255; //; SPECIAL FOR LOCKED - } - - if (FindNeighbour(axcall, Port, &ROUTE)) - { - PROCROUTES(Dest, ROUTE, Qual); - } - - OBSINIT = SavedOBSINIT; - - Bufferptr = Cmdprintf(Session, Bufferptr, "Node Added\r"); - goto SendReply; - } - - - - -/* -PNODE48: - - -; GET NEIGHBOURS FOR THIS DESTINATION -; - CALL CONVTOAX25 - JNZ SHORT BADROUTE -; - CALL GETVALUE - MOV SAVEPORT,AL ; SET PORT FOR _FINDNEIGHBOUR - - CALL GETVALUE - MOV ROUTEQUAL,AL -; - MOV ESI,OFFSET32 AX25CALL - - PUSH EBX ; SAVE DEST - CALL _FINDNEIGHBOUR - MOV EAX,EBX ; ROUTE TO AX - POP EBX - - JZ SHORT NOTBADROUTE - - JMP SHORT BADROUTE - -NOTBADROUTE: -; -; UPDATE ROUTE LIST FOR THIS DEST -; - MOV ROUT1_NEIGHBOUR[EBX],EAX - MOV AL,ROUTEQUAL - MOV ROUT1_QUALITY[EBX],AL - MOV ROUT1_OBSCOUNT[EBX],255 ; LOCKED -; - POP EDI - POP EBX - - INC _NUMBEROFNODES - - JMP SENDOK - -BADROUTE: -; -; KILL IT -; - MOV ECX,TYPE DEST_LIST - MOV EDI,EBX - MOV AL,0 - REP STOSB - - JMP BADROUTECMD - -*/ - - goto SendReply; - - -NODE_DEL: - - if (Session->PASSWORD != 0xFFFF) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "%s", PASSWORDMSG); - goto SendReply; - } - - ptr = param2; - - if (ptr == NULL) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Missing Call\r"); - goto SendReply; - } - - if (strcmp(ptr, "ALL") == 0) - { - struct DEST_LIST * DEST = DESTS; - int n = MAXDESTS; - - while (n--) - { - if (DEST->DEST_CALL[0] && ((DEST->DEST_STATE & 0x80) == 0)) // Don't delete appl node - REMOVENODE(DEST); - - DEST++; - } - - ClearNodes(); - - Bufferptr = Cmdprintf(Session, Bufferptr, "All Nodes Deleted\r"); - goto SendReply; - } - - ConvToAX25(ptr, AXCALL); - - if (FindDestination(AXCALL, &Dest) == 0) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Not Found\r"); - goto SendReply; - } - - if (Dest->DEST_STATE & 0x80) - Bufferptr = Cmdprintf(Session, Bufferptr, "APPL Node - Can't delete\r"); - else - { - REMOVENODE(Dest); - Bufferptr = Cmdprintf(Session, Bufferptr, "Node Deleted\r"); - } - Bufferptr = Cmdprintf(Session, Bufferptr, "Node Deleted\r"); - -SendReply: - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - -VOID CMDQUERY(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * UserCMD) -{ - // DISPLAY AVAILABLE COMMANDS - - int n; - char * ptr; - char ApplList[2048]; - char * out = ApplList; - - CMDX * CMD = &COMMANDS[APPL1]; - - for (n = 0; n < NumberofAppls; n++) - { - ptr = &CMD->String[0]; - if (*(ptr) != '*') - { - while (*ptr != ' ') - { - *(out++) = *(ptr++); - } - *(out++) = ' '; - } - CMD++; - } - - *(out) = 0; - - n = CMDLISTLEN; - - if (NEEDMH == 0) - n -= 7; // Dont show MH - - Bufferptr = Cmdprintf(Session, Bufferptr, "%s%s\r", ApplList, CMDLIST); - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - -char * FormatMH(MHSTRUC * MH, char Format); - -VOID MHCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - // DISPLAY HEARD LIST - - int Port = 0, sess = 0; - char * ptr, *Context, *pattern; - struct PORTCONTROL * PORT = NULL; - MHSTRUC * MH; - int count = MHENTRIES; - int n; - char Normcall[20]; - char From[10]; - char DigiList[100]; - char * Output; - int len; - char Digi = 0; - - - // Note that the MHDIGIS field may contain rubbish. You have to check End of Address bit to find - // how many digis there are - - ptr = strtok_s(CmdTail, " ", &Context); - - if (ptr) - Port = atoi(ptr); - - if (Port) - PORT = GetPortTableEntryFromPortNum(Port); - - if (PORT == NULL) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid Port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - pattern = strtok_s(NULL, " ", &Context); - - if (pattern) - _strupr(pattern); // Optional filter - - MH = PORT->PORTMHEARD; - - if (MH == NULL) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "MHEARD not enabled on that port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - if (pattern && strstr(pattern, "CLEAR")) - { - if (Session->Secure_Session) - { - memset(MH, 0, MHENTRIES * sizeof(MHSTRUC)); - SaveMH(); - Bufferptr = Cmdprintf(Session, Bufferptr, "Heard List for Port %d Cleared\r", Port); - } - else - { - Bufferptr = Cmdprintf(Session, Bufferptr, "MH Clear needs SYSOP status\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - } - else - { - if (CMD->String[2] == 'V') // MHV - { - Bufferptr = Cmdprintf(Session, Bufferptr, "MHeard List %s for Port %d\r", MYNODECALL, Port); - Bufferptr = Cmdprintf(Session, Bufferptr, "Callsign Last heard Pkts RX via Digi ;) \r"); - Bufferptr = Cmdprintf(Session, Bufferptr, "--------- ----------- ------- ------------------------------------------\r"); - } - else - if (pattern) - Bufferptr = Cmdprintf(Session, Bufferptr, "Heard List for Port %d filtered by %s\r", Port, pattern); - else - Bufferptr = Cmdprintf(Session, Bufferptr, "Heard List for Port %d\r", Port); - } - while (count--) - { - if (MH->MHCALL[0] == 0) - break; - - Digi = 0; - - len = ConvFromAX25(MH->MHCALL, Normcall); - - Normcall[len++] = MH->MHDIGI; - Normcall[len++] = 0; - - if (pattern && strstr(Normcall, pattern) == 0) - { - MH++; - continue; - } - - n = 8; // Max number of digi-peaters - - ptr = &MH->MHCALL[6]; // End of Address bit - - Output = &DigiList[0]; - - if ((*ptr & 1) == 0) - { - // at least one digi - - strcpy(Output, "via "); - Output += 4; - - while ((*ptr & 1) == 0) - { - // MORE TO COME - - From[ConvFromAX25(ptr + 1, From)] = 0; - Output += sprintf((char *)Output, "%s", From); - - ptr += 7; - n--; - - if (n == 0) - break; - - // See if digi actioned - put a * on last actioned - - if (*ptr & 0x80) - { - if (*ptr & 1) // if last address, must need * - { - *(Output++) = '*'; - Digi = '*'; - } - - else - if ((ptr[7] & 0x80) == 0) // Repeased by next? - { - *(Output++) = '*'; // No, so need * - Digi = '*'; - } - -} - *(Output++) = ','; - } - *(--Output) = 0; // remove last comma - } - else - *(Output) = 0; - - // if we used a digi set * on call and display via string - - - if (Digi) - Normcall[len++] = Digi; - else - DigiList[0] = 0; // Dont show list if not used - - Normcall[len++] = 0; - - - ptr = FormatMH(MH, CMD->String[2]); - - if (CMD->String[2] == 'V') // MHV - Bufferptr = Cmdprintf(Session, Bufferptr, "%-10s %-10s %-10d %-30s\r", - Normcall, ptr, MH->MHCOUNT, DigiList); - else - Bufferptr = Cmdprintf(Session, Bufferptr, "%-10s %s %s\r", Normcall, ptr, DigiList); - - MH++; - } - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - -int Rig_Command(int Session, char * Command); - -VOID RADIOCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * UserCMD) -{ - char * ptr; - - if (Rig_Command(Session->CIRCUITINDEX, CmdTail)) - { - ReleaseBuffer((UINT *)REPLYBUFFER); - return; - } - - // Error Message is in buffer - - ptr = strchr(CmdTail, 13); - - if (ptr) - { - int len = (int)(++ptr - CmdTail); - - memcpy(Bufferptr, CmdTail, len); - Bufferptr += len; - } - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - - -VOID SendNRRecordRoute(struct DEST_LIST * DEST, TRANSPORTENTRY * Session); - - -VOID NRRCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * UserCMD) -{ - // PROCESS 'NRR - Netrom Record Route' COMMAND - - char * ptr, *Context; - struct DEST_LIST * Dest = DESTS; - int count = MAXDESTS; - - ptr = strtok_s(CmdTail, " ", &Context); - - if (ptr) - { - UCHAR AXCall[8]; - int count; - - ConvToAX25(ptr, AXCall); - strcat(ptr, " "); - - for (count = 0; count < MAXDESTS; count++) - { - if (memcmp(Dest->DEST_ALIAS, ptr, 6) == 0 || CompareCalls(Dest->DEST_CALL, AXCall)) - { - SendNRRecordRoute(Dest, Session); - memcpy(Bufferptr, OKMSG, 3); - Bufferptr += 3; - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - - return; - } - Dest++; - } - } - Bufferptr = Cmdprintf(Session, Bufferptr, "Not found\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; -} - -int CHECKINTERLOCK(struct PORTCONTROL * OURPORT) -{ - // See if any Interlocked ports are Busy - - struct PORTCONTROL * PORT = PORTTABLE; - struct _EXTPORTDATA * EXTPORT; - - int n = NUMBEROFPORTS; - int ourgroup = OURPORT->PORTINTERLOCK; - - while (PORT) - { - if (PORT != OURPORT) - { - if (PORT->PORTINTERLOCK == ourgroup) - { - // Same Group - is it busy - - int i = 0; - - EXTPORT = (struct _EXTPORTDATA *)PORT; - - while (i < 27) - if (EXTPORT->ATTACHEDSESSIONS[i++]) - return PORT->PORTNUMBER; - } - } - PORT = PORT->PORTPOINTER; - } - - return 0; -} - -VOID ATTACHCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * UserCMD) -{ - // ATTACH to a PACTOR or similar port - - TRANSPORTENTRY * NewSess; - struct _EXTPORTDATA * EXTPORT; - struct TNCINFO * TNC; - - int Port = 0, sess = 0; - char * ptr, *Context; - int ret; - struct PORTCONTROL * PORT = NULL; - struct DATAMESSAGE Message = {0}; - int Paclen, PortPaclen; - struct DATAMESSAGE * Buffer; - - ptr = strtok_s(CmdTail, " ", &Context); - - if (ptr) - Port = atoi(ptr); - - if (Port) - PORT = GetPortTableEntryFromPortNum(Port); - - if (PORT == NULL || PORT->PROTOCOL < 10) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid Port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - // If attach on telnet port, find a free stream - - EXTPORT = (struct _EXTPORTDATA *)PORT; - - if (strstr(EXTPORT->PORT_DLL_NAME, "TELNET")) - { - int count = EXTPORT->MAXHOSTMODESESSIONS; - count--; // First is Pactor Stream, count is now last ax.25 session - - while (count) - { - if (EXTPORT->ATTACHEDSESSIONS[count] == 0) - { - int Paclen, PortPaclen; - struct DATAMESSAGE Message = {0}; - - // Found a free one - use it - - // See if TNC is OK - - Message.PORT = count; - - ret = PORT->PORTTXCHECKCODE(PORT, Message.PORT); - - if ((ret & 0xff00) == 0) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Error - TNC Not Ready\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - // GET CIRCUIT TABLE ENTRY FOR OTHER END OF LINK - - NewSess = SetupNewSession(Session, Bufferptr); - - if (NewSess == NULL) - return; - - EXTPORT->ATTACHEDSESSIONS[count] = NewSess; - - NewSess->Secure_Session = Session->Secure_Session; - - NewSess->KAMSESSION = count; - - // Set paclen to lower of incoming and outgoing - - Paclen = Session->SESSPACLEN; // Incoming PACLEN - - if (Paclen == 0) - Paclen = 256; // 0 = 256 - - PortPaclen = PORT->PORTPACLEN; - - if (PortPaclen == 0) - PortPaclen = 256; // 0 = 256 - - if (PortPaclen < Paclen) - Paclen = PortPaclen; - - NewSess->SESSPACLEN = Paclen; - Session->SESSPACLEN = Paclen; - - NewSess->L4STATE = 5; - NewSess->L4CIRCUITTYPE = DOWNLINK + PACTOR; - NewSess->L4TARGET.PORT = PORT; - - ptr = strtok_s(NULL, " ", &Context); - sess = count; - - // Replace command tail with original (before conversion to upper case - - Context = Context + (OrigCmdBuffer - COMMANDBUFFER); - - goto checkattachandcall; - - - memcpy(Bufferptr, OKMSG, 3); - Bufferptr += 3; - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - - return; - } - count--; - } - - Bufferptr = Cmdprintf(Session, Bufferptr, "Error - No free streams on this port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - Message.PORT = 0; - - ret = PORT->PORTTXCHECKCODE(PORT, Message.PORT); - - if ((ret & 0xff00) == 0) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Error - TNC Not Ready\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - // See if "Attach and Call" (for VHF ports) - - ptr = strtok_s(NULL, " ", &Context); - - if (ptr && strcmp(ptr, "S") == 0) - { - Session->STAYFLAG = TRUE; - ptr = strtok_s(NULL, " ", &Context); - } - - if (ptr) - { - // we have another param - - // if it is a single char it is a channel number for vhf attach - - if (strlen(ptr) == 1) - { - // Only Allow Attach VHF from Secure Applications or if PERMITGATEWAY is set - - if (EXTPORT->PERMITGATEWAY == 0 && Session->Secure_Session == 0) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Sorry, you are not allowed to use this port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - sess = ptr[0] - '@'; - - if (sess < 1 || sess > EXTPORT->MAXHOSTMODESESSIONS) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Error - Invalid Channel\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - ptr = strtok_s(NULL, " ", &Context); - - if (ptr && strcmp(ptr, "S") == 0) - { - Session->STAYFLAG = TRUE; - ptr = strtok_s(NULL, " ", &Context); - } - } - } - - if (ret & 0x8000) // Disconnecting - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Error - Port in use\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - // Check Interlock. Only ports with a TNC record can be interlocked - - TNC = PORT->TNC; - - if (TNC) - { - // See if any interlocked ports are in use - - struct TNCINFO * OtherTNC; - int i; - int rxInterlock = TNC->RXRadio; - int txInterlock = TNC->TXRadio; - - if (rxInterlock || txInterlock) - { - for (i=1; i<33; i++) - { - OtherTNC = TNCInfo[i]; - - if (OtherTNC == NULL) - continue; - - if (OtherTNC == TNC) - continue; - - if (rxInterlock == OtherTNC->RXRadio || txInterlock == OtherTNC->TXRadio) // Same Group - { - int n; - - for (n = 0; n <= 26; n++) - { - if (OtherTNC->PortRecord->ATTACHEDSESSIONS[n]) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Sorry, interlocked port %d is in use\r", i); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - } - } - } - } - } - - - - - if (EXTPORT->ATTACHEDSESSIONS[sess]) - { - // In use - - Bufferptr = Cmdprintf(Session, Bufferptr, "Error - Port in use\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - // GET CIRCUIT TABLE ENTRY FOR OTHER END OF LINK - - NewSess = SetupNewSession(Session, Bufferptr); - - if (NewSess == NULL) - return; - - // if a UZ7HO port, and the uplink is L2 or Uz7HO and multisession, - // invert SSID bits - - if (memcmp(EXTPORT->PORT_DLL_NAME, "UZ7HO", 5) != 0) - goto noFlip1; - - if (EXTPORT->MAXHOSTMODESESSIONS < 2) // Not multisession - goto noFlip1; - - if ((Session->L4CIRCUITTYPE & BPQHOST)) // host - goto noFlip1; - - if ((Session->L4CIRCUITTYPE & PACTOR)) - { - // incoming is Pactorlike - see if UZ7HO - - if (memcmp(Session->L4TARGET.EXTPORT->PORT_DLL_NAME, "UZ7HO", 5) != 0) - goto noFlip1; - else - NewSess->L4USER[6] ^= 0x1e; // UZ7HO Uplink - flip - } - else - - // Must be L2 uplink - flip - - NewSess->L4USER[6] ^= 0x1e; // Flip SSID -noFlip1: - - EXTPORT->ATTACHEDSESSIONS[sess] = NewSess; - - NewSess->KAMSESSION = sess; - - // Set paclen to lower of incoming and outgoing - - Paclen = Session->SESSPACLEN; // Incoming PACLEN - - if (Paclen == 0) - Paclen = 256; // 0 = 256 - - PortPaclen = PORT->PORTPACLEN; - - if (PortPaclen == 0) - PortPaclen = 256; // 0 = 256 - - if (PortPaclen < Paclen) - Paclen = PortPaclen; - - NewSess->SESSPACLEN = Paclen; - Session->SESSPACLEN = Paclen; - NewSess->L4STATE = 5; - NewSess->L4CIRCUITTYPE = DOWNLINK + PACTOR; - NewSess->L4TARGET.PORT = PORT; - -checkattachandcall: - - if (ptr) - { - // we have a call to connect to - - char Callstring[80]; - int len; - - Buffer = REPLYBUFFER; - Buffer->PORT = sess; - Buffer->PID = 0xf0; - - len = sprintf(Callstring,"C %s", ptr); - - ptr = strtok_s(NULL, " ", &Context); - - while (ptr) // if any other params (such as digis) copy them - { - if (strcmp(ptr, "S") == 0) - { - Session->STAYFLAG = TRUE; - } - else - len += sprintf(&Callstring[len], " %s", ptr); - - ptr = strtok_s(NULL, " ", &Context); - } - - Callstring[len++] = 13; - Callstring[len] = 0; - - Buffer->LENGTH = len + MSGHDDRLEN + 1; - memcpy(Buffer->L2DATA, Callstring, len); - C_Q_ADD(&PORT->PORTTX_Q, (UINT *)Buffer); - - return; - } - - memcpy(Bufferptr, OKMSG, 3); - Bufferptr += 3; - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - - return; -} - -// SYSOP COMMANDS - -CMDX COMMANDS[] = -{ - "SAVENODES ",8, SAVENODES, 0, - "TELRECONFIG ",4, RECONFIGTELNET, 0, - "SAVEMH ",6, SAVEMHCMD, 0, - "REBOOT ",6, REBOOT, 0, - "RIGRECONFIG ",8 , RIGRECONFIG, 0, - "RESTART ",7,RESTART,0, - "RESTARTTNC ",10,RESTARTTNC,0, - "SENDNODES ",8,SENDNODES,0, - "EXTRESTART ",10, EXTPORTVAL, offsetof(EXTPORTDATA, EXTRESTART), - "TXDELAY ",3, PORTVAL, offsetof(PORTCONTROLX, PORTTXDELAY), - "MAXFRAME ",3, PORTVAL, offsetof(PORTCONTROLX, PORTWINDOW), - "RETRIES ",3, PORTVAL, offsetof(PORTCONTROLX, PORTN2), - "FRACK ",3,PORTVAL, offsetof(PORTCONTROLX, PORTT1), - "RESPTIME ",3,PORTVAL, offsetof(PORTCONTROLX, PORTT2), - "PPACLEN ",3,PORTVAL, offsetof(PORTCONTROLX, PORTPACLEN), - "QUALITY ",3,PORTVAL, offsetof(PORTCONTROLX, PORTQUALITY), - "PERSIST ",2,PORTVAL, offsetof(PORTCONTROLX, PORTPERSISTANCE), - "TXTAIL ",3,PORTVAL, offsetof(PORTCONTROLX, PORTTAILTIME), - "XMITOFF ",7,PORTVAL, offsetof(PORTCONTROLX, PORTDISABLED), - "DIGIFLAG ",5,PORTVAL, offsetof(PORTCONTROLX, DIGIFLAG), - "DIGIPORT ",5,PORTVAL, offsetof(PORTCONTROLX, DIGIPORT), - "MAXUSERS ",4,PORTVAL, offsetof(PORTCONTROLX, USERS), - "L3ONLY ",6,PORTVAL, offsetof(PORTCONTROLX, PORTL3FLAG), - "BBSALIAS ",4,PORTVAL, offsetof(PORTCONTROLX, PORTBBSFLAG), - "VALIDCALLS ",5,VALNODES,0, - "WL2KSYSOP ",5,WL2KSYSOP,0, - "STOPPORT ",4,STOPPORT,0, - "STARTPORT ",5,STARTPORT,0, - "STOPCMS ",7,STOPCMS,0, - "STARTCMS ",8,STARTCMS,0, - - "FINDBUFFS ",4,FINDBUFFS,0, - "KISS ",4,KISSCMD,0, - "GETPORTCTEXT",9,GetPortCTEXT, 0, - -#ifdef EXCLUDEBITS - - "EXCLUDE ",4,ListExcludedCalls,0, - -#endif - - "FULLDUP ",4,PORTVAL, offsetof(PORTCONTROLX, FULLDUPLEX), - "SOFTDCD ",4,PORTVAL, offsetof(PORTCONTROLX, SOFTDCDFLAG), - "OBSINIT ",7,SWITCHVAL,(size_t)&OBSINIT, - "OBSMIN ",6,SWITCHVAL,(size_t)&OBSMIN, - "NODESINT ",8,SWITCHVAL,(size_t)&L3INTERVAL, - "L3TTL ",5,SWITCHVAL,(size_t)&L3LIVES, - "L4RETRIES ",5,SWITCHVAL,(size_t)&L4N2, - "L4TIMEOUT ",5,SWITCHVALW,(size_t)&L4T1, - "T3 ",2,SWITCHVALW,(size_t)&T3, - "NODEIDLETIME",8,SWITCHVALW,(size_t)&L4LIMIT, - "LINKEDFLAG ",10,SWITCHVAL,(size_t)&LINKEDFLAG, - "IDINTERVAL ",5,SWITCHVAL,(size_t)&IDINTERVAL, - "MINQUAL ",7,SWITCHVAL,(size_t)&MINQUAL, - "FULLCTEXT ",6,SWITCHVAL,(size_t)&FULL_CTEXT, - "HIDENODES ",8,SWITCHVAL,(size_t)&HIDENODES, - "L4DELAY ",7,SWITCHVAL,(size_t)&L4DELAY, - "L4WINDOW ",6,SWITCHVAL,(size_t)&L4DEFAULTWINDOW, - "BTINTERVAL ",5,SWITCHVAL,(size_t)&BTINTERVAL, - "PASSWORD ", 8, PWDCMD, 0, - - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, // Apppl 32 is internal Terminal - "*** LINKED ",10,LINKCMD,0, - "CQ ",2,CQCMD,0, - "CONNECT ",1,CMDC00,0, - "NC ",2,CMDC00,0, - "BYE ",1,BYECMD,0, - "QUIT ",1,BYECMD,0, - "INFO ",1,CMDI00,0, - "HELP ",1,HELPCMD,0, - "VERSION ",1,CMDV00,0, - "NODES ",1,CMDN00,0, - "LINKS ",1,CMDL00,0, - "LISTEN ",3,LISTENCMD,0, - "L4T1 ",2,CMDT00,0, - "PORTS ",1,CMDP00,0, - "PACLEN ",3,CMDPAC,0, - "IDLETIME ",4,CMDIDLE,0, - "ROUTES ",1,CMDR00,0, - "STATS ",1,CMDSTATS,0, - "USERS ",1,CMDS00,0, - "UNPROTO ",2,UNPROTOCMD,0, - "? ",1,CMDQUERY,0, - "DUMP ",4,DUMPCMD,0, - "MHU ",3,MHCMD,0, // UTC Times - "MHL ",3,MHCMD,0, // Local Times - "MHV ",3,MHCMD,0, - "MHEARD ",1,MHCMD,0, - "APRS ",2,APRSCMD,0, - "ATTACH ",1,ATTACHCMD,0, - "RADIO ",3,RADIOCMD,0, - "AXRESOLVER ",3,AXRESOLVER,0, - "AXMHEARD ",3,AXMHEARD,0, - "TELSTATUS ",3,SHOWTELNET,0, - "NRR ",1,NRRCMD,0, - "PING ",2,PING,0, - "AGWSTATUS ",3,SHOWAGW,0, - "ARP ",3,SHOWARP,0, - "NAT ",3,SHOWNAT,0, - "IPROUTE ",3,SHOWIPROUTE,0, - "..FLMSG ",7,FLMSG,0 -}; - -CMDX * CMD = NULL; - -int NUMBEROFCOMMANDS = sizeof(COMMANDS)/sizeof(CMDX); - -char * ReplyPointer; // Pointer into reply buffer - -int DecodeNodeName(char * NodeName, char * ptr) -{ - // NodeName is TABLE ENTRY WITH AX25 CALL AND ALIAS - - // Copyies 20 byte 20 DECODED NAME IN FORM ALIAS:CALL to ptr - // Returns significant length of string - - int len; - char Normcall[10]; - char * alias = &NodeName[7]; - int n = 6; - char * start = ptr; - - memset(ptr, ' ', 20); - - len = ConvFromAX25(NodeName, Normcall); - - if (*(alias) > ' ') // Does alias start with a null or a space ? - { - while (*(alias) > ' ' && n--) - { - *ptr++ = *alias++; - } - *ptr++ = ':'; - } - - memcpy(ptr, Normcall, len); - ptr += len; - - return (int)(ptr - start); -} - -char * SetupNodeHeader(struct DATAMESSAGE * Buffer) -{ - char Header[20]; - int len; - - char * ptr = &Buffer->L2DATA[0]; - - len = DecodeNodeName(MYCALLWITHALIAS, Header); - - memcpy (ptr, Header, len); - ptr += len; - - (*ptr++) = HEADERCHAR; - (*ptr++) = ' '; - - return ptr; -} - -VOID SendCommandReply(TRANSPORTENTRY * Session, struct DATAMESSAGE * Buffer, int Len) -{ - if (Len == (4 + sizeof(void *))) // Null Packet - { - ReleaseBuffer((UINT *)Buffer); - return; - } - - Buffer->LENGTH = Len; - - C_Q_ADD(&Session->L4TX_Q, (UINT *)Buffer); - - PostDataAvailable(Session); -} - - -VOID CommandHandler(TRANSPORTENTRY * Session, struct DATAMESSAGE * Buffer) -{ - // ignore frames with single NULL (Keepalive) - - if (Buffer->LENGTH == sizeof(void *) + 5 && Buffer->L2DATA[0] == 0) - { - ReleaseBuffer(Buffer); - return; - } - - if (Buffer->LENGTH > 100) - { -// Debugprintf("BPQ32 command too long %s", Buffer->L2DATA); - ReleaseBuffer(Buffer); - return; - } - -InnerLoop: - - InnerCommandHandler(Session, Buffer); - -// See if any more commands in buffer - - if (Session->PARTCMDBUFFER) - { - char * ptr1, * ptr2; - int len; - - Buffer = Session->PARTCMDBUFFER; - - // Check that message has a CR, if not save buffer and exit - - len = Buffer->LENGTH - (4 + sizeof(void *)); - ptr1 = &Buffer->L2DATA[0]; - - ptr2 = memchr(ptr1, 13, len); - - if (ptr2 == NULL) - return; - - Session->PARTCMDBUFFER = NULL; - - goto InnerLoop; - } -} - - -VOID InnerCommandHandler(TRANSPORTENTRY * Session, struct DATAMESSAGE * Buffer) -{ - char * ptr1, * ptr2, *ptr3; - int len, oldlen, newlen, rest, n; - struct DATAMESSAGE * OldBuffer; - struct DATAMESSAGE * SaveBuffer; - char c; - - // If a partial command is stored, append this data to it. - - if (Session->PARTCMDBUFFER) - { - len = Buffer->LENGTH - (sizeof(void *) + 4); - ptr1 = &Buffer->L2DATA[0]; - - OldBuffer = Session->PARTCMDBUFFER; // Old Data - - if (OldBuffer == Buffer) - { - // something has gone horribly wrong - - Session->PARTCMDBUFFER = NULL; - return; - } - - oldlen = OldBuffer->LENGTH; - - newlen = len + oldlen; - - if (newlen > 200) - { - // Command far too long - ignore previous - - OldBuffer->LENGTH = oldlen = sizeof(void *) + 4; - } - - OldBuffer->LENGTH += len; - memcpy(&OldBuffer->L2DATA[oldlen - (sizeof(void *) + 4)], Buffer->L2DATA, len); - - ReleaseBuffer((UINT *)Buffer); - - Buffer = OldBuffer; - - Session->PARTCMDBUFFER = NULL; - } - - // Check that message has a CR, if not save buffer and exit - - len = Buffer->LENGTH - (sizeof(void *) + 4); - ptr1 = &Buffer->L2DATA[0]; - - // Check for sending YAPP to Node - - if (len == 2 && ptr1[0] == 5 && ptr1[1] == 1) - { - ptr1[0] = 0x15; // NAK - - ptr1[1] = sprintf(&ptr1[2], "Node doesn't support YAPP Transfers"); - - Buffer->LENGTH += ptr1[1]; - - C_Q_ADD(&Session->L4TX_Q, (UINT *)Buffer); - PostDataAvailable(Session); - return; - } - - - ptr2 = memchr(ptr1, ';', len); - - if (ptr2 == 0) - { - ptr2 = memchr(ptr1, 13, len); - - if (ptr2 == 0) - { - // No newline - - Session->PARTCMDBUFFER = Buffer; - return; - } - } - - ptr2++; - - rest = len - (int)(ptr2 - ptr1); - - if (rest) - { - // there are chars beyond the cr in the buffer - - // see if LF after CR - - if ((*ptr2) == 10) // LF - { - ptr2++; - rest--; - } - - if (rest) // May only have had LF - { - // Get a new buffer, and copy extra data to it. - - SaveBuffer = (struct DATAMESSAGE *)GetBuff(); - - if (SaveBuffer) //`Just ignore if no buffers - { - SaveBuffer->LENGTH = rest + MSGHDDRLEN + 1; - SaveBuffer->PID = 0xf0; - memcpy(&SaveBuffer->L2DATA[0], ptr2, rest); - Session->PARTCMDBUFFER = SaveBuffer; - } - } - } - - // GET PACLEN FOR THIS CONNECTION - - CMDPACLEN = Session->SESSPACLEN; - - if (CMDPACLEN == 0) - CMDPACLEN = PACLEN; // Use default if no Session PACLEN - - // If sesion is in UNPROTO Mode, send message as a UI message - - if (Session->UNPROTO) - { - DIGIMESSAGE Msg; - int Port = Session->UNPROTO; - int Len = Buffer->LENGTH - (MSGHDDRLEN -1); // Need PID - - // First check for UNPROTO exit - ctrl/z or /ex - - if (Buffer->L2DATA[0] == 26 || (Len == 6 && _memicmp(&Buffer->L2DATA[0], "/ex", 3) == 0)) // CTRL/Z or /ex - { - REPLYBUFFER = Buffer; - - Session->UNPROTO = 0; - memset(Session->UADDRESS, 0, 64); - - // SET UP HEADER - - Buffer->PID = 0xf0; - ptr1 = SetupNodeHeader(Buffer); - memcpy(ptr1, OKMSG, 3); - ptr1 += 3; - SendCommandReply(Session, Buffer, (int)(ptr1 - (char *)Buffer)); - - return; - } - - memset(&Msg, 0, sizeof(Msg)); - - Msg.PORT = Port; - Msg.CTL = 3; // UI - memcpy(Msg.DEST, Session->UADDRESS, 7); - memcpy(Msg.ORIGIN, Session->L4USER, 7); - memcpy(Msg.DIGIS, &Session->UADDRESS[7], Session->UAddrLen - 7); - memcpy(&Msg.PID, &Buffer->PID, Len); - - Send_AX_Datagram(&Msg, Len, Port); // Len is Payload - CTL, PID and Data - -// SendUIModeFrame(Session, (PMESSAGE)Buffer, Session->UNPROTO); - - ReleaseBuffer((UINT *)Buffer); // Not using buffer for reply - - return; - } - - memset(COMMANDBUFFER, 32, 80); // Clear to spaces - - ptr1 = &Buffer->L2DATA[0]; - ptr2 = &COMMANDBUFFER[0]; - ptr3 = &OrigCmdBuffer[0]; - - memset(OrigCmdBuffer, 0, 80); - n = 80; - - while (n--) - { - c = *(ptr1++) & 0x7f; // Mask paritu - - if (c == 13 || c == ';') - break; // CR - - *(ptr3++) = c; // Original Case - - c = toupper(c); - *(ptr2++) = c; - } - - - // USE INPUT MESSAGE _BUFFER FOR REPLY - - REPLYBUFFER = Buffer; - - // SET UP HEADER - - Buffer->PID = 0xf0; - ptr1 = SetupNodeHeader(Buffer); - - ReplyPointer = ptr1; - - ALIASINVOKED = 0; // Clear "Invoked by APPL ALIAS flag" - - DoTheCommand(Session); // We also call DotheCommand when we need to reprocess - eg for alias handling -} - -VOID DoTheCommand(TRANSPORTENTRY * Session) -{ - struct DATAMESSAGE * Buffer = REPLYBUFFER; - char * ptr1, * ptr2; - int n; - - ptr1 = &COMMANDBUFFER[0]; // - - n = 10; - - while ((*ptr1 == ' ' || *ptr1 == 0) && n--) - ptr1++; // STRIP LEADING SPACES and nulls (from keepalive) - - if (n == -1) - { - // Null command - - ReleaseBuffer((UINT *)Buffer); - return; - } - - ptr2 = ptr1; // Save - - - CMD = &COMMANDS[0]; - n = 0; - - for (n = 0; n < NUMBEROFCOMMANDS; n++) - { - int CL = CMD->CMDLEN; - - ptr1 = ptr2; - - CMDPTR = CMD; - - if (n == APPL1) // First APPL command - { - APPLMASK = 1; // FOR APPLICATION ATTACH REQUESTS - ALIASPTR = &CMDALIAS[0][0]; - } - - // ptr1 is input command - - if (memcmp(CMD->String, ptr1, CL) == 0) - { - // Found match so far - check rest - - char * ptr2 = &CMD->String[CL]; - - ptr1 += CL; - - if (*(ptr1) != ' ') - { - while(*(ptr1) == *ptr2 && *(ptr1) != ' ') - { - ptr1++; - ptr2++; - } - } - - if (*(ptr1) == ' ') - { - Session->BADCOMMANDS = 0; // RESET ERROR COUNT - - // SEE IF SYSOP COMMAND, AND IF SO IF PASSWORD HAS BEEN ENTERED - - if (n < PASSCMD) - { - //NEEDS PASSWORD FOR SYSOP COMMANDS - - if (Session->PASSWORD != 0xFFFF) - { - ptr1 = ReplyPointer; - - memcpy(ptr1, PASSWORDMSG, LPASSMSG); - ptr1 += LPASSMSG; - - SendCommandReply(Session, Buffer, (int)(ptr1 - (char *)Buffer)); - return; - } - } -// VALNODESFLAG = 0; // NOT VALID NODES COMMAND - - ptr1++; // Skip space - - CMD->CMDPROC(Session, ReplyPointer, ptr1, CMD); - return; - } - } - - APPLMASK <<= 1; - ALIASPTR += ALIASLEN; - - CMD++; - - } - Session->BADCOMMANDS++; - - if (Session->BADCOMMANDS > 6) // TOO MANY ERRORS - { - ReleaseBuffer((UINT *)Buffer); - Session->STAYFLAG = 0; - CLOSECURRENTSESSION(Session); - return; - } - - ptr1 = ReplyPointer; - - memcpy(ptr1, CMDERRMSG, CMDERRLEN); - ptr1 += CMDERRLEN; - - SendCommandReply(Session, Buffer, (int)(ptr1 - (char *)Buffer)); -} - - -VOID StatsTimer() -{ - struct PORTCONTROL * PORT = PORTTABLE; - int sum; - - while(PORT) - { - sum = PORT->SENDING / 11; - PORT->AVSENDING = sum; - - sum = (PORT->SENDING + PORT->ACTIVE) /11; - PORT->AVACTIVE = sum; - - PORT->SENDING = 0; - PORT->ACTIVE = 0; - - PORT = PORT->PORTPOINTER; - } -} - - - -extern struct AXIPPORTINFO * Portlist[]; - -#define TCPConnected 4 - - -VOID AXRESOLVER(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - // DISPLAY AXIP Resolver info - - int Port = 0, index =0; - char * ptr, *Context; - struct PORTCONTROL * PORT = NULL; - struct AXIPPORTINFO * AXPORT; - char Normcall[11]; - char Flags[10]; - struct arp_table_entry * arp; - - ptr = strtok_s(CmdTail, " ", &Context); - - if (ptr) - Port = atoi(ptr); - - if (Port) - PORT = GetPortTableEntryFromPortNum(Port); - - if (PORT == NULL) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid Port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - AXPORT = Portlist[Port]; - - if (AXPORT == NULL) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Not an AXIP port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - Bufferptr = Cmdprintf(Session, Bufferptr, "AXIP Resolver info for Port %d\r", Port); - - while (index < AXPORT->arp_table_len) - { - arp = &AXPORT->arp_table[index]; - - if (arp->ResolveFlag && arp->error != 0) - { - // resolver error - Display Error Code - sprintf(AXPORT->hostaddr, "Error %d", arp->error); - } - else - { - if (arp->IPv6) - Format_Addr((unsigned char *)&arp->destaddr6.sin6_addr, AXPORT->hostaddr, TRUE); - else - Format_Addr((unsigned char *)&arp->destaddr.sin_addr, AXPORT->hostaddr, FALSE); - } - - ConvFromAX25(arp->callsign, Normcall); - - Flags[0] = 0; - - if (arp->BCFlag) - strcat(Flags, "B "); - - if (arp->TCPState == TCPConnected) - strcat(Flags, "C "); - - if (arp->AutoAdded) - strcat(Flags, "A"); - - if (arp->port == arp->SourcePort) - Bufferptr = Cmdprintf(Session, Bufferptr,"%.10s = %.64s %d = %-.42s %s\r", - Normcall, - arp->hostname, - arp->port, - AXPORT->hostaddr, - Flags); - - else - Bufferptr = Cmdprintf(Session, Bufferptr,"%.10s = %.64s %d<%d = %-.42s %s\r", - Normcall, - arp->hostname, - arp->port, - arp->SourcePort, - AXPORT->hostaddr, - Flags); - - index++; - } - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - -VOID AXMHEARD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - // DISPLAY AXIP Mheard info - - int Port = 0, index = 0; - char * ptr, *Context; - struct PORTCONTROL * PORT = NULL; - struct AXIPPORTINFO * AXPORT; - int n = MHENTRIES; - char Normcall[11]; - - ptr = strtok_s(CmdTail, " ", &Context); - - if (ptr) - Port = atoi(ptr); - - if (Port) - PORT = GetPortTableEntryFromPortNum(Port); - - if (PORT == NULL) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid Port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - AXPORT = Portlist[Port]; - - if (AXPORT == NULL) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Not an AXIP port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - Bufferptr = Cmdprintf(Session, Bufferptr, "AXIP Mheard for Port %d\r", Port); - - while (index < MaxMHEntries) - { - if (AXPORT->MHTable[index].proto != 0) - { - char Addr[80]; - - Format_Addr((unsigned char *)&AXPORT->MHTable[index].ipaddr6, Addr, AXPORT->MHTable[index].IPv6); - - Normcall[ConvFromAX25(AXPORT->MHTable[index].callsign, Normcall)] = 0; - - Bufferptr = Cmdprintf(Session, Bufferptr, "%-10s%-15s %c %-6d %-25s%c\r", Normcall, - Addr, - AXPORT->MHTable[index].proto, - AXPORT->MHTable[index].port, - asctime(gmtime( &AXPORT->MHTable[index].LastHeard )), - (AXPORT->MHTable[index].Keepalive == 0) ? ' ' : 'K'); - - Bufferptr[-3] = ' '; // Clear CR returned by asctime - } - - index++; - } - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - -#pragma pack() - -extern struct TNCINFO * TNCInfo[41]; - -extern char WL2KCall[10]; -extern char WL2KLoc[7]; - -BOOL GetWL2KSYSOPInfo(char * Call, char * _REPLYBUFFER); -BOOL UpdateWL2KSYSOPInfo(char * Call, char * SQL); - -VOID WL2KSYSOP(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - char _REPLYBUFFER[1000] = ""; - - char LastUpdated[100]; - char Name[100] = ""; - char Addr1[100] = ""; - char Addr2[100] = ""; - char City[100] = ""; - char State[100] = ""; - char Country[100] = ""; - char PostCode[100] = ""; - char Email[100] = ""; - char Website[100] = ""; - char Phone[100] = ""; - char Data[100] = ""; - char LOC[100] = ""; - BOOL Exists = TRUE; - time_t LastUpdateSecs = 0; - char * ptr1, * ptr2; - - SOCKET sock; - - int Len; - char Message[2048]; - - if (WL2KCall[0] < 33) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Winlink reporting is not configured\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - - if (GetWL2KSYSOPInfo(WL2KCall, _REPLYBUFFER) == 0) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Failed to connect to WL2K Database\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - if (strstr(_REPLYBUFFER, "\"ErrorMessage\":")) - Exists = FALSE; - - GetJSONValue(_REPLYBUFFER, "\"SysopName\":", Name); - GetJSONValue(_REPLYBUFFER, "\"StreetAddress1\":", Addr1); - GetJSONValue(_REPLYBUFFER, "\"StreetAddress2\":", Addr2); - GetJSONValue(_REPLYBUFFER, "\"City\":", City); - GetJSONValue(_REPLYBUFFER, "\"State\":", State); - GetJSONValue(_REPLYBUFFER, "\"Country\":", Country); - GetJSONValue(_REPLYBUFFER, "\"PostalCode\":", PostCode); - GetJSONValue(_REPLYBUFFER, "\"Email\":", Email); - GetJSONValue(_REPLYBUFFER, "\"Website\":", Website); - GetJSONValue(_REPLYBUFFER, "\"Phones\":", Phone); - GetJSONValue(_REPLYBUFFER, "\"Comments\":", Data); - GetJSONValue(_REPLYBUFFER, "\"GridSquare\":", LOC); - GetJSONValue(_REPLYBUFFER, "\"Timestamp\":", LastUpdated); - - ptr1 = strchr(LastUpdated, '('); - - if (ptr1) - { - ptr2 = strchr(++ptr1, ')'); - - if (ptr2) - { - *(ptr2 - 3) = 0; // remove millisecs - LastUpdateSecs = atoi(ptr1); - - FormatTime3(LastUpdated, LastUpdateSecs); - } - } - - if (_memicmp(CmdTail, "SET ", 4) == 0) - { - if (Exists) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Record already exists in WL2K Database\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - // Set New Values. Any other params are values to set, separated by | - -// ptr1 = strtok_s(&CmdTail[4], ",", &Context); - -// if (ptr1 == NULL) -// goto DoReplace; - -// strcpy(Name, ptr1); - -//DoReplace: - - Len = sprintf(Message, - "\"Callsign\":\"%s\"," - "\"GridSquare\":\"%s\"," - "\"SysopName\":\"%s\"," - "\"StreetAddress1\":\"%s\"," - "\"StreetAddress2\":\"%s\"," - "\"City\":\"%s\"," - "\"State\":\"%s\"," - "\"Country\":\"%s\"," - "\"PostalCode\":\"%s\"," - "\"Email\":\"%s\"," - "\"Phones\":\"%s\"," - "\"Website\":\"%s\"," - "\"Comments\":\"%s\",", - - WL2KCall, WL2KLoc, Name, Addr1, Addr2, City, State, Country, PostCode, Email, Phone, Website, Data); - - Debugprintf("Sending %s", Message); - - sock = OpenWL2KHTTPSock(); - - if (sock) - SendHTTPRequest(sock, "api.winlink.org", 80, - "/sysop/add", Message, Len, NULL); - - closesocket(sock); - - Bufferptr = Cmdprintf(Session, Bufferptr, "Database Updated\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - if (Exists) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "\rWL2K SYSOP Info for %s\r", WL2KCall); - Bufferptr = Cmdprintf(Session, Bufferptr, "Grid Square: %s\r", LOC); - Bufferptr = Cmdprintf(Session, Bufferptr, "Name: %s\r", Name); - Bufferptr = Cmdprintf(Session, Bufferptr, "Addr Line 1: %s\r", Addr1); - Bufferptr = Cmdprintf(Session, Bufferptr, "Addr Line 2: %s\r", Addr2); - Bufferptr = Cmdprintf(Session, Bufferptr, "City: %s\r", City); - Bufferptr = Cmdprintf(Session, Bufferptr, "State: %s\r", State); - Bufferptr = Cmdprintf(Session, Bufferptr, "Country: %s\r", Country); - Bufferptr = Cmdprintf(Session, Bufferptr, "PostCode: %s\r", PostCode); - Bufferptr = Cmdprintf(Session, Bufferptr, "Email Address: %s\r", Email); - Bufferptr = Cmdprintf(Session, Bufferptr, "Website: %s\r", Website); - Bufferptr = Cmdprintf(Session, Bufferptr, "Phone: %s\r", Phone); - Bufferptr = Cmdprintf(Session, Bufferptr, "Additional Data: %s\r", Data); - Bufferptr = Cmdprintf(Session, Bufferptr, "Last Updated: %s\r", LastUpdated); - } - else - Bufferptr = Cmdprintf(Session, Bufferptr, "No SYSOP record for %s\r", WL2KCall); - - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; -} - -VOID CloseKISSPort(struct PORTCONTROL * PortVector); -int OpenConnection(struct PORTCONTROL * PortVector); - -VOID STOPCMS(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - char _REPLYBUFFER[1000] = ""; - char * ptr, * Context; - - int portno; - - struct TNCINFO * TNC; - struct TCPINFO * TCP; - struct PORTCONTROL * PORT = PORTTABLE; - int n = NUMBEROFPORTS; - - // Get port number - - ptr = strtok_s(CmdTail, " ", &Context); - - if (ptr) - { - portno = atoi (ptr); - - if (portno) - { - while (n--) - { - if (PORT->PORTNUMBER == portno) - { - TNC = TNCInfo[portno]; - - if (!TNC || !TNC->TCPInfo) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Not a Telnet Port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - TCP = TNC->TCPInfo; - - TCP->CMS = 0; - TCP->CMSOK = FALSE; -#ifndef LINBPQ - CheckMenuItem(TCP->hActionMenu, 3, MF_BYPOSITION | TCP->CMS<<3); - SetWindowText(TCP->hCMSWnd, "CMS Off"); -#endif - Bufferptr = Cmdprintf(Session, Bufferptr, "CMS Server Disabled\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - PORT = PORT->PORTPOINTER; - } - } - } - - // Bad port - - strcpy(Bufferptr, BADPORT); - Bufferptr += (int)strlen(BADPORT); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; -} - - -VOID STARTCMS(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - char _REPLYBUFFER[1000] = ""; - char * ptr, * Context; - - int portno; - - struct TNCINFO * TNC; - struct TCPINFO * TCP; - struct PORTCONTROL * PORT = PORTTABLE; - int n = NUMBEROFPORTS; - - // Get port number - - ptr = strtok_s(CmdTail, " ", &Context); - - if (ptr) - { - portno = atoi (ptr); - - if (portno) - { - while (n--) - { - if (PORT->PORTNUMBER == portno) - { - TNC = TNCInfo[portno]; - - if (!TNC || !TNC->TCPInfo) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Not a Telnet Port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - TCP = TNC->TCPInfo; - TCP->CMS = 1; -#ifndef LINBPQ - CheckMenuItem(TCP->hActionMenu, 3, MF_BYPOSITION | TCP->CMS<<3); -#endif - CheckCMS(TNC); - - Bufferptr = Cmdprintf(Session, Bufferptr, "CMS Server Enabled\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - PORT = PORT->PORTPOINTER; - } - } - } - - // Bad port - - strcpy(Bufferptr, BADPORT); - Bufferptr += (int)strlen(BADPORT); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; -} - - -VOID STOPPORT(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - char _REPLYBUFFER[1000] = ""; - char * ptr, * Context; - - int portno; - struct PORTCONTROL * PORT = PORTTABLE; - int n = NUMBEROFPORTS; - - // Get port number - - ptr = strtok_s(CmdTail, " ", &Context); - - if (ptr) - { - portno = atoi (ptr); - - if (portno) - { - while (n--) - { - if (PORT->PORTNUMBER == portno) - { - struct KISSINFO * KISS; - - if (PORT->PORTSTOPCODE) - { - // Port has Close Routine - - PORT->PortStopped = TRUE; - - if (PORT->PORTSTOPCODE(PORT)) - Bufferptr = Cmdprintf(Session, Bufferptr, "Port Closed\r"); - else - Bufferptr = Cmdprintf(Session, Bufferptr, "Port Close Failed\r"); - - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - if (PORT->PORTTYPE != 0) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Not a KISS Port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - if (PORT->PORTIPADDR.s_addr || PORT->KISSSLAVE) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Not a serial port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - KISS = (struct KISSINFO *) PORT; - - if (KISS->FIRSTPORT != KISS) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Not first port of a Multidrop Set\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - CloseKISSPort(PORT); - PORT->PortStopped = TRUE; - Bufferptr = Cmdprintf(Session, Bufferptr, "Port Closed\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - - return; - } - PORT = PORT->PORTPOINTER; - } - } - } - - // Bad port - - strcpy(Bufferptr, BADPORT); - Bufferptr += (int)strlen(BADPORT); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; -} - - -VOID STARTPORT(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - char _REPLYBUFFER[1000] = ""; - char * ptr, * Context; - - int portno; - struct PORTCONTROL * PORT = PORTTABLE; - int n = NUMBEROFPORTS; - - // Get port number - - ptr = strtok_s(CmdTail, " ", &Context); - - if (ptr) - { - portno = atoi (ptr); - - if (portno) - { - while (n--) - { - if (PORT->PORTNUMBER == portno) - { - struct KISSINFO * KISS; - - if (PORT->PORTSTARTCODE) - { - // Port has Open Routine - - PORT->PortStopped = FALSE; - - if (PORT->PORTSTARTCODE(PORT)) - Bufferptr = Cmdprintf(Session, Bufferptr, "Port Opened\r"); - else - Bufferptr = Cmdprintf(Session, Bufferptr, "Port Open Failed\r"); - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - - if (PORT->PORTTYPE != 0) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Not a KISS Port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - if (PORT->PORTIPADDR.s_addr || PORT->KISSSLAVE) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Not a serial port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - KISS = (struct KISSINFO *) PORT; - - if (KISS->FIRSTPORT != KISS) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Not first port of a Multidrop Set\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - if (OpenConnection(PORT), TRUE) - Bufferptr = Cmdprintf(Session, Bufferptr, "Port Opened\r"); - else - Bufferptr = Cmdprintf(Session, Bufferptr, "Port Open Failed\r"); - - PORT->PortStopped = FALSE; - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - PORT = PORT->PORTPOINTER; - } - } - } - - // Bad port - - strcpy(Bufferptr, BADPORT); - Bufferptr += (int)strlen(BADPORT); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; -} - - - -#define FEND 0xC0 -int ASYSEND(struct PORTCONTROL * PortVector, char * buffer, int count); - - -VOID KISSCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - char _REPLYBUFFER[1000] = ""; - char * ptr, * Context; - - int portno = 0; - int cmd = 0, val = 0; - struct PORTCONTROL * PORT = PORTTABLE; - int n = NUMBEROFPORTS; - - // Send KISS Command to TNC - - // Get port number - - ptr = strtok_s(CmdTail, " ", &Context); - - if (ptr) - { - portno = atoi (ptr); - ptr = strtok_s(NULL, " ", &Context); - - if (ptr) - { - cmd = atoi (ptr); - ptr = strtok_s(NULL, " ", &Context); - - if (ptr) - val = atoi (ptr); - } - } - - if (portno == 0 || cmd == 0) - { - strcpy(Bufferptr, BADMSG); - Bufferptr += (int)strlen(BADMSG); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - while (n--) - { - if (PORT->PORTNUMBER == portno) - { - struct KISSINFO * KISS; - UCHAR ENCBUFF[16]; - unsigned char * ptr = ENCBUFF; - - if (PORT->PORTTYPE != 0 && PORT->PORTTYPE != 22) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Not a KISS Port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - KISS = (struct KISSINFO *) PORT; - - if (KISS->FIRSTPORT != KISS) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Not first port of a Multidrop Set\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - // Send Command - - *(ptr++) = FEND; - *(ptr++) = KISS->OURCTRL | cmd; - *(ptr++) = (UCHAR)val; - *(ptr++) = FEND; - - PORT = (struct PORTCONTROL *)KISS->FIRSTPORT; // ALL FRAMES GO ON SAME Q - - PORT->Session = Session; - PORT->LastKISSCmdTime = time(NULL); - - ASYSEND(PORT, ENCBUFF, 4); - - Bufferptr = Cmdprintf(Session, Bufferptr, "Command Sent\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - PORT = PORT->PORTPOINTER; - } - - - // Bad port - - strcpy(Bufferptr, BADPORT); - Bufferptr += (int)strlen(BADPORT); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; -} - - -VOID FINDBUFFS(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - FindLostBuffers(); - -#ifdef WIN32 - Bufferptr = Cmdprintf(Session, Bufferptr, "Lost buffer info dumped to Debugview\r"); -#else - Bufferptr = Cmdprintf(Session, Bufferptr, "Lost buffer info dumped to syslog\r"); -#endif - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - -VOID FLMSG(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * UserCMD) -{ - // Telnet Connection from FLMSG - CLOSECURRENTSESSION(Session); // Kills any crosslink, plus local link - ReleaseBuffer((UINT *)REPLYBUFFER); -} - -BOOL CheckExcludeList(UCHAR * Call) -{ - UCHAR * ptr1 = ExcludeList; - - while (*ptr1) - { - if (memcmp(Call, ptr1, 6) == 0) - return FALSE; - - ptr1 += 7; - } - - return TRUE; -} - - -void ListExcludedCalls(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - - UCHAR * ptr = ExcludeList; - char Normcall[10] = ""; - UCHAR AXCall[8] = ""; - - if (*CmdTail == ' ') - goto DISPLIST; - - if (*CmdTail == 'Z') - { - // CLEAR LIST - - memset(ExcludeList, 0, 70); - goto DISPLIST; - } - - ConvToAX25(CmdTail, AXCall); - - if (strlen(ExcludeList) < 70) - strcat(ExcludeList, AXCall); - -DISPLIST: - - while (*ptr) - { - Normcall[ConvFromAX25(ptr, Normcall)] = 0; - Bufferptr = Cmdprintf(Session, Bufferptr, "%s ", Normcall); - ptr += 7; - } - - *(Bufferptr++) = '\r'; - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - -BOOL isSYSOP(TRANSPORTENTRY * Session, char * Bufferptr) -{ - if (Session->PASSWORD != 0xFFFF) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "%s", PASSWORDMSG); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - - return FALSE; - } - - return TRUE; -} - -VOID HELPCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - int FileSize; - char MsgFile[MAX_PATH]; - FILE * hFile; - char * MsgBytes; - struct stat STAT; - char * ptr1, * ptr, * ptr2; - - sprintf_s(MsgFile, sizeof(MsgFile), "%s/%s", BPQDirectory, "NodeHelp.txt"); - - if (stat(MsgFile, &STAT) == -1) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Help file not found\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - FileSize = STAT.st_size; - - hFile = fopen(MsgFile, "rb"); - - if (hFile == NULL) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Help file not found\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - MsgBytes = malloc(FileSize+1); - - fread(MsgBytes, 1, FileSize, hFile); - - fclose(hFile); - - MsgBytes[FileSize] = 0; - - ptr1 = MsgBytes; - - // Replace LF or CRLF with CR - - // First remove cr from crlf - - while(ptr2 = strstr(ptr1, "\r\n")) - { - memmove(ptr2, ptr2 + 1, strlen(ptr2)); - } - - // Now replace lf with cr - - ptr1 = MsgBytes; - - while (*ptr1) - { - if (*ptr1 == '\n') - *(ptr1) = '\r'; - - ptr1++; - } - - ptr = ptr1 = MsgBytes; - - Bufferptr = Cmdprintf(Session, Bufferptr, "\r"); - - // Read and send a line at a time, converting any line endings into CR - - while (*ptr1) - { - if (*ptr1 == '\r') - { - *(ptr1++) = 0; - - Bufferptr = Cmdprintf(Session, Bufferptr, "%s\r", ptr); - - ptr = ptr1; - } - else - ptr1++; - } - - free(MsgBytes); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - - - - - - - - - - diff --git a/Cmd-HPLaptop.c b/Cmd-HPLaptop.c deleted file mode 100644 index 22fdd43..0000000 --- a/Cmd-HPLaptop.c +++ /dev/null @@ -1,5495 +0,0 @@ -/* -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 -*/ - -// -// C replacement for cmd.asm -// -#define Kernel - -#define _CRT_SECURE_NO_DEPRECATE -#pragma data_seg("_BPQDATA") - -//#include "windows.h" -//#include "winerror.h" - - -#include "time.h" -#include "stdio.h" -#include -//#include "vmm.h" -//#include "SHELLAPI.H" - -#include "CHeaders.h" -#include "bpqaprs.h" - -#pragma pack() - -#include "tncinfo.h" -#include "telnetserver.h" - -//#include "GetVersion.h" - -//#define DllImport __declspec( dllimport ) -//#define DllExport __declspec( dllexport ) - -BOOL DecodeCallString(char * Calls, BOOL * Stay, BOOL * Spy, UCHAR *AXCalls); -VOID Send_AX_Datagram(PDIGIMESSAGE Block, DWORD Len, UCHAR Port); -int APIENTRY ClearNodes(); -VOID GetJSONValue(char * _REPLYBUFFER, char * Name, char * Value); -VOID SendHTTPRequest(SOCKET sock, char * Host, int Port, char * Request, char * Params, int Len, char * Return); -SOCKET OpenWL2KHTTPSock(); -VOID FormatTime3(char * Time, time_t cTime); -VOID Format_Addr(unsigned char * Addr, char * Output, BOOL IPV6); -VOID Tel_Format_Addr(struct ConnectionInfo * sockptr, char * dst); -VOID FindLostBuffers(); -BOOL CheckCMS(struct TNCINFO * TNC); -VOID L2SENDXID(struct _LINKTABLE * LINK); -int CountBits(unsigned long in); -VOID SaveMH(); -BOOL RestartTNC(struct TNCINFO * TNC); -void GetPortCTEXT(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD); -VOID WriteMiniDump(); - -char COMMANDBUFFER[81] = ""; // Command Hander input buffer -char OrigCmdBuffer[81] = ""; // Command Hander input buffer - -struct DATAMESSAGE * REPLYBUFFER = NULL; -UINT APPLMASK = 0; -UCHAR SAVEDAPPLFLAGS = 0; - -UCHAR ALIASINVOKED = 0; - -extern struct TNCINFO * TNCInfo[41]; - -VOID * CMDPTR = 0; - -short CMDPACLEN = 0; - -char OKMSG[] = "Ok\r"; - -char CMDERRMSG[] = "Invalid command - Enter ? for command list\r"; -#define CMDERRLEN sizeof(CMDERRMSG) - 1 - -char PASSWORDMSG[] = "Command requires SYSOP status - enter password\r"; -#define LPASSMSG sizeof(PASSWORDMSG) - 1 - -char CMDLIST[] = "CONNECT BYE INFO NODES PORTS ROUTES USERS MHEARD"; - -#define CMDLISTLEN sizeof(CMDLIST) - 1 - -char BADMSG[] = "Bad Parameter\r"; -char BADPORT[] = "Invalid Port Number\r"; -char NOTEXTPORT[] = "Only valid on EXT ports\r"; -char NOVALCALLS[] = "No Valid Calls defined on this port\r"; - -char BADVALUEMSG[] = "Invalid parameter\r"; - -char BADCONFIGMSG[] = "Configuration File check falled - will continue with old config\r"; -#ifdef LINBPQ -char REBOOTOK[] = "Rebooting\r"; -#else -char REBOOTOK[] = "Rebooting in 20 secs\r"; -#endif -char REBOOTFAILED[] = "Shutdown failed\r"; - -char RESTARTOK[] = "Restarting\r"; -char RESTARTFAILED[] = "Restart failed\r"; - -UCHAR ARDOP[7] = {'A'+'A','R'+'R','D'+'D','O'+'O','P'+'P',' '+' '}; // ARDOP IN AX25 -UCHAR VARA[7] = {'V'+'V','A'+'A','R'+'R','A'+'A',' '+' ',' '+' '}; // VARA IN AX25 - -int STATSTIME = 0; -int MAXBUFFS = 0; -int QCOUNT = 0; -int MINBUFFCOUNT = 65535; -int NOBUFFCOUNT = 0; -int BUFFERWAITS = 0; -int MAXDESTS = 0; -int NUMBEROFNODES = 0; -int L4CONNECTSOUT = 0; -int L4CONNECTSIN = 0; -int L4FRAMESTX = 0; -int L4FRAMESRX = 0; -int L4FRAMESRETRIED = 0; -int OLDFRAMES = 0; -int L3FRAMES = 0; - -VOID SENDSABM(); -VOID RESET2(); - -int APPL1 = 0; -int PASSCMD = 0; - -#pragma pack(1) - -struct _EXTPORTDATA DP; // Only way I can think of to get offets to port data into cmd table - -char CMDALIAS[ALIASLEN][NumberofAppls] = {0}; -char * ALIASPTR = &CMDALIAS[0][0]; - -extern int RigReconfigFlag; - -CMDX COMMANDS[]; - -int CMDXLEN = sizeof (CMDX); - -VOID SENDNODESMSG(); -VOID KISSCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD); -VOID STOPCMS(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD); -VOID STARTCMS(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD); -VOID STOPPORT(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD); -VOID STARTPORT(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD); -VOID FINDBUFFS(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD); -VOID WL2KSYSOP(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD); -VOID AXRESOLVER(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD); -VOID AXMHEARD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD); -VOID SHOWTELNET(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD); -VOID SHOWAGW(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD); -VOID SHOWARP(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD); -VOID SHOWNAT(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD); -VOID PING(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD); -VOID SHOWIPROUTE(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD); -VOID FLMSG(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * UserCMD); -void ListExcludedCalls(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD); -VOID APRSCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD); -VOID RECONFIGTELNET (TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD); - -char * __cdecl Cmdprintf(TRANSPORTENTRY * Session, char * Bufferptr, const char * format, ...) -{ - // Send Command response checking PACLEN - - char Mess[4096]; - va_list(arglist); - int OldLen; - int MsgLen; - struct DATAMESSAGE * Buffer; - char * Messptr = Mess; - int Paclen = Session->SESSPACLEN; - - if (Paclen == 0) - Paclen = 255; - - va_start(arglist, format); - - MsgLen = vsprintf(Mess, format, arglist); - - OldLen = (int)(Bufferptr - (char *)REPLYBUFFER->L2DATA); - - while ((OldLen + MsgLen) > Paclen) - { - // Have to send Paclen then get a new buffer - - int ThisBit = Paclen - OldLen; // What we can send this time - - if (ThisBit < 0) - ThisBit = 0; // How can this happen?? - - memcpy(Bufferptr, Messptr, ThisBit); - Messptr += ThisBit; - MsgLen -= ThisBit; - - // QUEUE IT AND GET ANOTHER BUFFER - - Buffer = (struct DATAMESSAGE *)GetBuff(); - - if (Buffer == NULL) - - // No buffers, so just reuse the old one (better than crashing !!) - - Buffer = REPLYBUFFER; - else - SendCommandReply(Session, REPLYBUFFER, Paclen + (4 + sizeof(void *))); - - - REPLYBUFFER = Buffer; - Buffer->PID = 0xf0; - - Bufferptr = &Buffer->L2DATA[0]; - OldLen = 0; - } - - // Add last bit to buffer - - memcpy(Bufferptr, Messptr, MsgLen); - - return Bufferptr + MsgLen; -} - - -VOID SENDNODES(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - SENDNODESMSG(); - - strcpy(Bufferptr, OKMSG); - Bufferptr += (int)strlen(OKMSG); - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - -VOID SAVEMHCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - SaveMH(); - - strcpy(Bufferptr, OKMSG); - Bufferptr += (int)strlen(OKMSG); - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - -VOID SAVENODES(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - SaveNodes(); - - strcpy(Bufferptr, OKMSG); - Bufferptr += (int)strlen(OKMSG); - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - -VOID DUMPCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - WriteMiniDump(); - - strcpy(Bufferptr, OKMSG); - Bufferptr += (int)strlen(OKMSG); - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - -VOID RIGRECONFIG(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - if (!ProcessConfig()) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Configuration File check falled - will continue with old config"); - } - else - { - RigReconfigFlag=TRUE; - Bufferptr = Cmdprintf(Session, Bufferptr, "Rigcontrol Reconfig requested"); - } - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - -VOID REBOOT(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - if (Reboot()) - { - strcpy(Bufferptr, REBOOTOK); - Bufferptr += (int)strlen(REBOOTOK); - } - else - { - strcpy(Bufferptr, REBOOTFAILED); - Bufferptr += (int)strlen(REBOOTFAILED); - } - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - -VOID RESTART(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - if (Restart()) - { - strcpy(Bufferptr, RESTARTOK); - Bufferptr += (int)strlen(RESTARTOK); - } - else - { - strcpy(Bufferptr, RESTARTFAILED); - Bufferptr += (int)strlen(RESTARTFAILED); - } - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - -VOID RESTARTTNC(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - char * ptr, *Context; - int portno; - - ptr = strtok_s(CmdTail, " ", &Context); - - if (ptr) - { - portno = atoi (ptr); - - if (portno && portno < 33) - { - struct TNCINFO * TNC = TNCInfo[portno]; - - if (TNC == NULL) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid Port\r"); - } - else - { - if (TNC->ProgramPath) - { - if (RestartTNC(TNC)) - Bufferptr = Cmdprintf(Session, Bufferptr, "Restart %s Ok\r", TNC->ProgramPath); - else - Bufferptr = Cmdprintf(Session, Bufferptr, "Restart %s Failed\r", TNC->ProgramPath); - } - else - { - Bufferptr = Cmdprintf(Session, Bufferptr, "PATH not defined so can't restart TNC\r"); - } - } - } - else - Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid Port\r"); - - } - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - -UCHAR VALNODESFLAG = 0, EXTONLY = 0; - -VOID PORTVAL (TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD); - -VOID VALNODES(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - VALNODESFLAG = 1; - PORTVAL(Session, Bufferptr, CmdTail, CMD); -} - -VOID EXTPORTVAL(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - EXTONLY = 1; - PORTVAL(Session, Bufferptr, CmdTail, CMD); -} -VOID PORTVAL(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - // PROCESS PORT VALUE COMMANDS - - char * ptr, *Context, * ptr1; - int portno; - UCHAR oldvalue, newvalue; - struct PORTCONTROL * PORT = PORTTABLE; - int n = NUMBEROFPORTS; - UCHAR * valueptr; - - // Get port number - - ptr = strtok_s(CmdTail, " ", &Context); - - if (ptr) - { - portno = atoi (ptr); - - if (portno) - { - while (n--) - { - if (PORT->PORTNUMBER == portno) - { - if (VALNODESFLAG) - { - char * VNPtr = PORT->PERMITTEDCALLS; - char Normcall[10]; - - VALNODESFLAG = 0; - - if (VNPtr) - { - while (VNPtr[0]) - { - Normcall[ConvFromAX25(VNPtr, Normcall)] = 0; - Bufferptr = Cmdprintf(Session, Bufferptr, "%s ", Normcall); - VNPtr += 7; - } - - Bufferptr = Cmdprintf(Session, Bufferptr, "\r"); - } - else - { - Bufferptr = Cmdprintf(Session, Bufferptr, "%s", NOVALCALLS); - } - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - - return; - - } - - if (EXTONLY) - { - // Make sure an Extenal Port - - EXTONLY = 0; - - if (PORT->PORTTYPE != 0x10) - { - strcpy(Bufferptr, NOTEXTPORT); - Bufferptr += (int)strlen(NOTEXTPORT); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - } - - valueptr = (UCHAR *)PORT + CMD->CMDFLAG; - oldvalue = *valueptr; - - // Display Param Namee - - ptr1 = &CMD->String[0]; - n = 12; - - while (*(ptr1) != ' ' && n--) - *(Bufferptr++) = *(ptr1++); - - // See if another param - if not, just display current value - - ptr = strtok_s(NULL, " ", &Context); - - if (ptr && ptr[0]) - { - // Get new value - - newvalue = atoi(ptr); - *valueptr = newvalue; - - Bufferptr = Cmdprintf(Session, Bufferptr, " was %d now %d\r", oldvalue, newvalue); - } - - else - Bufferptr = Cmdprintf(Session, Bufferptr, " %d\r", oldvalue); - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - - } - PORT = PORT->PORTPOINTER; - } - } - } - - // Bad port - - strcpy(Bufferptr, BADPORT); - Bufferptr += (int)strlen(BADPORT); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - -} - -VOID SWITCHVAL (TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - // Update switch 8 bit value - - char * ptr, *Context, * ptr1; - UCHAR oldvalue, newvalue; - int n; - UCHAR * valueptr; - - valueptr = (UCHAR *)CMD->CMDFLAG; - - oldvalue = *valueptr; - - // Display Param Name - - ptr1 = &CMD->String[0]; - n = 12; - - while (*(ptr1) != ' ' && n--) - *(Bufferptr++) = *(ptr1++); - - // See if a param - if not, just display current value - - ptr = strtok_s(CmdTail, " ", &Context); - - if (ptr && ptr[0]) - { - // Get new value - - newvalue = atoi(ptr); - *valueptr = newvalue; - - Bufferptr = Cmdprintf(Session, Bufferptr, " was %d now %d\r", oldvalue, newvalue); - - if (memcmp(CMD->String, "NODESINT ", 8) == 0) - L3TIMER = L3INTERVAL; - } - else - Bufferptr = Cmdprintf(Session, Bufferptr, " %d\r", oldvalue); - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - -} - -VOID SWITCHVALW (TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - // Update switch 16 bit value - - char * ptr, *Context, * ptr1; - USHORT oldvalue, newvalue; - int n; - USHORT * valueptr; - - valueptr = (USHORT *)CMD->CMDFLAG; - - oldvalue = (USHORT)*valueptr; - - // Display Param Name - - ptr1 = &CMD->String[0]; - n = 12; - - while (*(ptr1) != ' ' && n--) - *(Bufferptr++) = *(ptr1++); - - // See if a param - if not, just display current value - - ptr = strtok_s(CmdTail, " ", &Context); - - if (ptr && ptr[0]) - { - // Get new value - - newvalue = atoi(ptr); - *valueptr = newvalue; - - Bufferptr = Cmdprintf(Session, Bufferptr, " was %d now %d\r", oldvalue, newvalue); - } - else - Bufferptr = Cmdprintf(Session, Bufferptr, " %d\r", oldvalue); - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - -} - -TRANSPORTENTRY * SetupSessionFromSession(TRANSPORTENTRY * Session, PBPQVECSTRUC HOSTSESS, UINT APPLMASK) -{ - // Create a Transport (L4) session linked to an incoming Session - - TRANSPORTENTRY * NewSess = L4TABLE; - int Index = 0; - - while (Index < MAXCIRCUITS) - { - if (NewSess->L4USER[0] == 0) - { - // Got One - - UCHAR * ourcall = &MYCALL[0]; - - Session->L4CROSSLINK = NewSess; - NewSess->L4CROSSLINK = Session; - - if (APPLMASK) - { - // Circuit for APPL - look for an APPLCALL - - APPLCALLS * APPL = APPLCALLTABLE; - - while ((APPLMASK & 1) == 0) - { - APPLMASK >>= 1; - APPL++; - } - if (APPL->APPLCALL[0] > 0x40) // We have an applcall - ourcall = &APPL->APPLCALL[0]; - } - - memcpy(NewSess->L4USER, ourcall, 7); - memcpy(NewSess->L4MYCALL, Session->L4MYCALL, 7); - - NewSess->CIRCUITINDEX = Index; //OUR INDEX - NewSess->CIRCUITID = NEXTID; - - NEXTID++; - if (NEXTID == 0) - NEXTID++; // kEEP nON-ZERO - - NewSess->SESSIONT1 = Session->SESSIONT1; - NewSess->L4WINDOW = (UCHAR)L4DEFAULTWINDOW; - NewSess->SESSPACLEN = PACLEN; // Default; - - NewSess->L4TARGET.HOST = HOSTSESS; - NewSess->L4STATE = 5; - return NewSess; - } - Index++; - NewSess++; - } - return NULL; -} - -extern int GETCONNECTIONINFO(); - - -BOOL cATTACHTOBBS(TRANSPORTENTRY * Session, UINT Mask, int Paclen, int * AnySessions) -{ - PBPQVECSTRUC HOSTSESS = BPQHOSTVECTOR; - TRANSPORTENTRY * NewSess; - int ApplNum; - int n = BPQHOSTSTREAMS; - int ConfigedPorts = 0; - - // LOOK FOR A FREE HOST SESSION - - while (n--) - { - if (HOSTSESS->HOSTAPPLMASK & Mask) - { - // Right appl - - ConfigedPorts++; - - if (HOSTSESS->HOSTSESSION == NULL && (HOSTSESS->HOSTFLAGS & 3) == 0) // Not attached and no report outstanding - { - // WEVE GOT A FREE BPQ HOST PORT - USE IT - - NewSess = SetupSessionFromSession(Session, HOSTSESS, Mask); - - if (NewSess == NULL) - return FALSE; // Appl not available - - HOSTSESS->HOSTSESSION = NewSess; - - // Convert APPLMASK to APPLNUM - - ApplNum = 1; - - while (APPLMASK && (APPLMASK & 1) == 0) - { - ApplNum++; - APPLMASK >>= 1; - } - - HOSTSESS->HOSTAPPLNUM = ApplNum; - - HOSTSESS->HOSTFLAGS |= 2; // Indicate State Change - - NewSess->L4CIRCUITTYPE = BPQHOST | DOWNLINK; - - PostStateChange(NewSess); - - NewSess->SESS_APPLFLAGS = HOSTSESS->HOSTAPPLFLAGS; - - NewSess->SESSPACLEN = Paclen; - - return TRUE; - } - } - HOSTSESS++; - } - - *AnySessions = ConfigedPorts; // to distinguish between none and all in use - return FALSE; -} - -VOID APPLCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - BOOL CONFAILED = 0; - UINT CONERROR ; - char APPName[13]; - char * ptr1, *ptr2; - int n = 12; - BOOL Stay = FALSE; - - // Copy Appl and Null Terminate - - ptr1 = &CMD->String[0]; - ptr2 = APPName; - - while (*(ptr1) != ' ' && n--) - *(ptr2++) = *(ptr1++); - - *(ptr2) = 0; - - if (Session->LISTEN) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Can't use %s while listening\r", APPName); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - - if (CmdTail[0] == 'S') - Stay = TRUE; - - Session->STAYFLAG = Stay; - - memcpy(Session->APPL, CMD->String, 12); - - // SEE IF THERE IS AN ALIAS DEFINDED FOR THIS COMMAND - - if (ALIASPTR[0] > ' ') - { - // COPY ALIAS TO COMMAND BUFFER, THEN REENTER COMMAND HANDLER - - int SaveSecure = Session->Secure_Session; - - memcpy(COMMANDBUFFER, ALIASPTR, ALIASLEN); - _strupr(COMMANDBUFFER); - memcpy(OrigCmdBuffer, ALIASPTR, ALIASLEN); // In case original case version needed - - ALIASINVOKED = 1; // To prevent Alias Loops - - // Set secure session for application alias in case telnet outward connect - - Session->Secure_Session = 1; - DoTheCommand(Session); - Session->Secure_Session = SaveSecure; - - return; - } - - if (cATTACHTOBBS(Session, APPLMASK, CMDPACLEN, &CONERROR) == 0) - { - // No Streams - - if (CONERROR) - Bufferptr = Cmdprintf(Session, Bufferptr, "Sorry, All %s Ports are in use - Please try later\r", APPName); - else - Bufferptr = Cmdprintf(Session, Bufferptr, "Sorry, Application %s is not running - Please try later\r", APPName); - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - // IF CMD_TO_APPL SET IN APPLFLAGS, SEND INPUT MSG TO APPL - - if (Session->L4CROSSLINK->SESS_APPLFLAGS & CMD_TO_APPL) - { - struct DATAMESSAGE * Msg = (struct DATAMESSAGE *)GetBuff(); - TRANSPORTENTRY * XSession = Session->L4CROSSLINK; - - if (Msg) - { - COMMANDBUFFER[72] = 13; - memcpy(Msg->L2DATA, COMMANDBUFFER, 73); - Msg->LENGTH = 73 + 4 + sizeof(void *); - Msg->PID = 0xf0; - - C_Q_ADD(&XSession->L4TX_Q, (UINT *)Msg); - PostDataAvailable(XSession); - } - } - - if (Stay) - Session->L4CROSSLINK->L4TARGET.HOST->HOSTFLAGS |= 0x20; - - // IF MSG_TO_USER SET, SEND 'CONNECTED' MESSAGE TO USER - - Session->SESS_APPLFLAGS = Session->L4CROSSLINK->SESS_APPLFLAGS; - - if (Session->L4CROSSLINK->SESS_APPLFLAGS & MSG_TO_USER) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Connected to %s\r", APPName); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - - // DONT NEED BUFFER ANY MORE - - ReleaseBuffer((UINT *)REPLYBUFFER); - return; -} - - -VOID CMDI00(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - Bufferptr = Cmdprintf(Session, Bufferptr, "%s", INFOMSG); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - -VOID CMDV00(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - if (sizeof(void *) == 4) - Bufferptr = Cmdprintf(Session, Bufferptr, "Version %s\r", VersionString); - else - Bufferptr = Cmdprintf(Session, Bufferptr, "Version %s (64 bit)\r", VersionString); - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - -VOID BYECMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - CLOSECURRENTSESSION(Session); // Kills any crosslink, plus local link - ReleaseBuffer((UINT *)REPLYBUFFER); - return; -} - -VOID CMDPAC(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - // SET PACLEN FOR THIS SESSION - - char * ptr, *Context; - int newvalue; - - ptr = strtok_s(CmdTail, " ", &Context); - - if (ptr && ptr[0]) - { - // Get new value - - newvalue = atoi(ptr); - if (newvalue > 29 && newvalue < 256) - Session->SESSPACLEN = newvalue & 0xff; - } - - Bufferptr = Cmdprintf(Session, Bufferptr, "PACLEN - %d\r", Session->SESSPACLEN); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - -VOID CMDIDLE(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - // SET IDLETIME FOR THIS SESSION - - char * ptr, *Context; - int newvalue; - - ptr = strtok_s(CmdTail, " ", &Context); - - if (ptr && ptr[0]) - { - // Get new value - - newvalue = atoi(ptr); - if (newvalue > 59 && newvalue < 901) - Session->L4LIMIT = newvalue; - } - - Bufferptr = Cmdprintf(Session, Bufferptr, "IDLETIME - %d\r", Session->L4LIMIT); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - -} -VOID CMDT00(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - // SET L4 TIMEOUT FOR CONNECTS ON THIS SESSION - - char * ptr, *Context; - int newvalue; - - ptr = strtok_s(CmdTail, " ", &Context); - - if (ptr && ptr[0]) - { - // Get new value - - newvalue = atoi(ptr); - if (newvalue > 20) - Session->SESSIONT1 = newvalue; - } - - Bufferptr = Cmdprintf(Session, Bufferptr, "L4TIMEOUT - %d\r", Session->SESSIONT1); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - -UCHAR PWLen; -char PWTEXT[80]; - -VOID PWDCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - char * ptr, *Context; - USHORT pwsum = 0; - int n = 5, p1, p2, p3, p4, p5; - - if (Session->Secure_Session) // HOST - SET AUTHORISED REGARDLESS - { - Session->PASSWORD = 0xFFFF; // SET AUTHORISED - Session->Secure_Session = 1; - strcpy(Bufferptr, OKMSG); - Bufferptr += (int)strlen(OKMSG); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - ptr = strtok_s(CmdTail, " ", &Context); - - if (ptr && ptr[0]) - { - // Check Password - - n = 5; - - while (n--) - pwsum += *(ptr++); - - if (Session->PASSWORD == pwsum) - { - Session->PASSWORD = 0xFFFF; // SET AUTHORISED - Session->Secure_Session = 1; - strcpy(Bufferptr, OKMSG); - Bufferptr += (int)strlen(OKMSG); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - ReleaseBuffer((UINT *)REPLYBUFFER); - return; - } - - // SEND PASSWORD PROMPT - - if (PWLen == 0) - PWLen = 1; - - p1 = rand() % PWLen; - pwsum += PWTEXT[p1++]; - - p2 = rand() % PWLen; - pwsum += PWTEXT[p2++]; - - p3 = rand() % PWLen; - pwsum += PWTEXT[p3++]; - - p4 = rand() % PWLen; - pwsum += PWTEXT[p4++]; - - p5 = rand() % PWLen; - pwsum += PWTEXT[p5++]; - - Session->PASSWORD = pwsum; - - Bufferptr = Cmdprintf(Session, Bufferptr, "%d %d %d %d %d\r", p1, p2, p3, p4, p5); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; -} - -VOID CMDSTATS(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - char * ptr, *Context; - int Port = 0, cols = NUMBEROFPORTS, i; - char * uptime; - struct PORTCONTROL * PORT = PORTTABLE; - struct PORTCONTROL * STARTPORT; - - Bufferptr = Cmdprintf(Session, Bufferptr, "\r"); - - // SEE IF ANY PARAM - - ptr = strtok_s(CmdTail, " ", &Context); - - if (ptr && ptr[0]) - Port = atoi(ptr); - - // IF ASKING FOR PORT STATS, DONT DO SYSTEM ONES - - if (Port == 0) - { - uptime = FormatUptime(STATSTIME); - Bufferptr = Cmdprintf(Session, Bufferptr, "%s", uptime); - - Bufferptr = Cmdprintf(Session, Bufferptr, "Semaphore Get-Rel/Clashes %9d%9d\r", - Semaphore.Gets - Semaphore.Rels, Semaphore.Clashes); - - Bufferptr = Cmdprintf(Session, Bufferptr, "Buffers:Max/Cur/Min/Out/Wait%9d%9d%9d%9d%9d\r", - MAXBUFFS, QCOUNT, MINBUFFCOUNT, NOBUFFCOUNT, BUFFERWAITS); - - Bufferptr = Cmdprintf(Session, Bufferptr, "Known Nodes/Max Nodes %9d%9d\r", - NUMBEROFNODES, MAXDESTS); - - Bufferptr = Cmdprintf(Session, Bufferptr, "L4 Connects Sent/Rxed %9d%9d\r", - L4CONNECTSOUT, L4CONNECTSIN); - - Bufferptr = Cmdprintf(Session, Bufferptr, "L4 Frames TX/RX/Resent/Reseq%9d%9d%9d%9d\r", - L4FRAMESTX, L4FRAMESRX, L4FRAMESRETRIED, OLDFRAMES); - - Bufferptr = Cmdprintf(Session, Bufferptr, "L3 Frames Relayed %9d\r", L3FRAMES); - - if (ptr && ptr[0] == 'S') - { - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - } - - // POSITION TO REQUESTED PORT - - if (Port) - { - while (PORT && PORT->PORTNUMBER != Port) - { - PORT = PORT->PORTPOINTER; - cols--; - } - } - - if (PORT == NULL) // REQUESTED PORT NOT FOUND - { - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - STARTPORT = PORT; - - if (cols > 7) - cols = 7; - - Bufferptr = Cmdprintf(Session, Bufferptr, " "); - - for (i = 0; i < cols; i++) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Port %02d ", PORT->PORTNUMBER); - PORT = PORT->PORTPOINTER; - } - - Bufferptr = Cmdprintf(Session, Bufferptr, "\r"); - - PORT = STARTPORT; - Bufferptr = Cmdprintf(Session, Bufferptr, "L2 Frames Digied"); - - for (i = 0; i < cols; i++) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "%9d", PORT->L2DIGIED); - PORT = PORT->PORTPOINTER; - } - Bufferptr = Cmdprintf(Session, Bufferptr, "\r"); - - PORT = STARTPORT; - Bufferptr = Cmdprintf(Session, Bufferptr, "L2 Frames Heard "); - - for (i = 0; i < cols; i++) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "%9d", PORT->L2FRAMES); - PORT = PORT->PORTPOINTER; - } - Bufferptr = Cmdprintf(Session, Bufferptr, "\r"); - - PORT = STARTPORT; - Bufferptr = Cmdprintf(Session, Bufferptr, "L2 Frames Rxed "); - - for (i = 0; i < cols; i++) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "%9d", PORT->L2FRAMESFORUS); - PORT = PORT->PORTPOINTER; - } - Bufferptr = Cmdprintf(Session, Bufferptr, "\r"); - - PORT = STARTPORT; - Bufferptr = Cmdprintf(Session, Bufferptr, "L2 Frames Sent "); - - for (i = 0; i < cols; i++) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "%9d", PORT->L2FRAMESSENT); - PORT = PORT->PORTPOINTER; - } - Bufferptr = Cmdprintf(Session, Bufferptr, "\r"); - - PORT = STARTPORT; - Bufferptr = Cmdprintf(Session, Bufferptr, "L2 Timeouts "); - - for (i = 0; i < cols; i++) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "%9d", PORT->L2TIMEOUTS); - PORT = PORT->PORTPOINTER; - } - Bufferptr = Cmdprintf(Session, Bufferptr, "\r"); - - PORT = STARTPORT; - Bufferptr = Cmdprintf(Session, Bufferptr, "REJ Frames Rxed "); - - for (i = 0; i < cols; i++) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "%9d", PORT->L2REJCOUNT); - PORT = PORT->PORTPOINTER; - } - Bufferptr = Cmdprintf(Session, Bufferptr, "\r"); - - PORT = STARTPORT; - Bufferptr = Cmdprintf(Session, Bufferptr, "RX out of Seq "); - - for (i = 0; i < cols; i++) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "%9d", PORT->L2OUTOFSEQ); - PORT = PORT->PORTPOINTER; - } - Bufferptr = Cmdprintf(Session, Bufferptr, "\r"); - - PORT = STARTPORT; - Bufferptr = Cmdprintf(Session, Bufferptr, "L2 Resequenced "); - - for (i = 0; i < cols; i++) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "%9d", PORT->L2RESEQ); - PORT = PORT->PORTPOINTER; - } - Bufferptr = Cmdprintf(Session, Bufferptr, "\r"); - - PORT = STARTPORT; - Bufferptr = Cmdprintf(Session, Bufferptr, "Undrun/Poll T/o "); - - for (i = 0; i < cols; i++) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "%9d", PORT->L2URUNC); - PORT = PORT->PORTPOINTER; - } - Bufferptr = Cmdprintf(Session, Bufferptr, "\r"); - - PORT = STARTPORT; - Bufferptr = Cmdprintf(Session, Bufferptr, "RX Overruns "); - - for (i = 0; i < cols; i++) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "%9d", PORT->L2ORUNC); - PORT = PORT->PORTPOINTER; - } - Bufferptr = Cmdprintf(Session, Bufferptr, "\r"); - - PORT = STARTPORT; - Bufferptr = Cmdprintf(Session, Bufferptr, "RX CRC Errors "); - - for (i = 0; i < cols; i++) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "%9d", PORT->RXERRORS); - PORT = PORT->PORTPOINTER; - } - Bufferptr = Cmdprintf(Session, Bufferptr, "\r"); - - PORT = STARTPORT; - Bufferptr = Cmdprintf(Session, Bufferptr, "FRMRs Sent "); - - for (i = 0; i < cols; i++) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "%9d", PORT->L2FRMRTX); - PORT = PORT->PORTPOINTER; - } - Bufferptr = Cmdprintf(Session, Bufferptr, "\r"); - - PORT = STARTPORT; - Bufferptr = Cmdprintf(Session, Bufferptr, "FRMRs Received "); - - for (i = 0; i < cols; i++) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "%9d", PORT->L2FRMRRX); - PORT = PORT->PORTPOINTER; - } - Bufferptr = Cmdprintf(Session, Bufferptr, "\r"); - - PORT = STARTPORT; - Bufferptr = Cmdprintf(Session, Bufferptr, "Frames abandoned"); - - for (i = 0; i < cols; i++) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "%9d", PORT->L1DISCARD); - PORT = PORT->PORTPOINTER; - } - Bufferptr = Cmdprintf(Session, Bufferptr, "\r"); - - PORT = STARTPORT; - Bufferptr = Cmdprintf(Session, Bufferptr, "Link Active %% "); - - for (i = 0; i < cols; i++) - { - Bufferptr = Cmdprintf(Session, Bufferptr, " %2d %3d", PORT->AVSENDING, PORT->AVACTIVE); - PORT = PORT->PORTPOINTER; - } - Bufferptr = Cmdprintf(Session, Bufferptr, "\r"); - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - -VOID CMDL00(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - // PROCESS 'LINKS' MESSAGE - - struct _LINKTABLE * LINK = LINKS; - int n = MAXLINKS; - int len; - char Normcall[11] = ""; - - Bufferptr = Cmdprintf(Session, Bufferptr, "Links\r"); - - while (n--) - { - if (LINK->LINKCALL[0]) - { - len = ConvFromAX25(LINK->LINKCALL, Normcall); - - Bufferptr = Cmdprintf(Session, Bufferptr, "%s", Normcall); - - len = ConvFromAX25(LINK->OURCALL, Normcall); - Bufferptr = Cmdprintf(Session, Bufferptr, "%s", Normcall); - - if (LINK->Ver2point2) - Bufferptr = Cmdprintf(Session, Bufferptr, " S=%d P=%d T=%d V=2.2\r", - LINK->L2STATE, LINK->LINKPORT->PORTNUMBER, LINK->LINKTYPE); - else - Bufferptr = Cmdprintf(Session, Bufferptr, " S=%d P=%d T=%d V=%d\r", - LINK->L2STATE, LINK->LINKPORT->PORTNUMBER, LINK->LINKTYPE, 2 - LINK->VER1FLAG); - } - LINK++; - } - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - - -VOID CMDS00(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - // PROCESS 'USERS' - - 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]; - - Bufferptr = Cmdprintf(Session, Bufferptr, "%s%d)\r", SESSIONHDDR, QCOUNT); - - while (n--) - { - if (L4->L4USER[0]) - { - RHS[0] = MID[0] = 0; - - if ((L4->L4CIRCUITTYPE & UPLINK) == 0) //SHORT CMDS10A ; YES - { - // IF DOWNLINK, ONLY DISPLAY IF NO CROSSLINK - - if (L4->L4CROSSLINK == 0) //jne CMDS60 ; WILL PROCESS FROM OTHER END - { - // ITS A DOWNLINK WITH NO PARTNER - MUST BE A CLOSING SESSION - // DISPLAY TO THE RIGHT FOR NOW - - strcpy(LHS, "(Closing) "); - DISPLAYCIRCUIT(L4, RHS); - goto CMDS50; - } - else - goto CMDS60; // WILL PROCESS FROM OTHER END - } - - if (L4->L4CROSSLINK == 0) - { - // Single Entry - - DISPLAYCIRCUIT(L4, LHS); - } - else - { - DISPLAYCIRCUIT(L4, LHS); - - Partner = L4->L4CROSSLINK; - - if (Partner->L4STATE == 5) - strcpy(MID, "<-->"); - else - strcpy(MID, "<~~>"); - - DISPLAYCIRCUIT(Partner, RHS); - } -CMDS50: - memset(Line, 32, 100); - memcpy(Line, LHS, (int)strlen(LHS)); - memcpy(&Line[35], MID, (int)strlen(MID)); - strcpy(&Line[40], RHS); - strcat(&Line[40], "\r"); - Bufferptr = Cmdprintf(Session, Bufferptr, "%s", Line); - } -CMDS60: - L4++; - } - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - -VOID CMDP00(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - // Process PORTS Message - - struct PORTCONTROL * PORT = PORTTABLE; - - Bufferptr = Cmdprintf(Session, Bufferptr, "Ports\r"); - - while (PORT) - { - if (PORT->Hide == 0) - Bufferptr = Cmdprintf(Session, Bufferptr, " %2d %s\r", PORT->PORTNUMBER, PORT->PORTDESCRIPTION); - - PORT = PORT->PORTPOINTER; - } - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - -char * DisplayRoute(TRANSPORTENTRY * Session, char * Bufferptr, struct ROUTE * Routes, char Verbose) -{ - char Normcall[10]; - char locked[] = " ! "; - int NodeCount; - int Percent = 0; - char PercentString[20]; - int Iframes, Retries; - char Active[10]; - int Queued; - - int Port = 0; - - int len = ConvFromAX25(Routes->NEIGHBOUR_CALL, Normcall); - - Normcall[9]=0; - - if ((Routes->NEIGHBOUR_FLAG & 1) == 1) - strcpy(locked, "!"); - else - strcpy(locked, " "); - - NodeCount = COUNTNODES(Routes); - - if (Routes->NEIGHBOUR_LINK && Routes->NEIGHBOUR_LINK->L2STATE >= 5) - strcpy(Active, ">"); - else - strcpy(Active, " "); - - if (Verbose) - { - if (Routes->NEIGHBOUR_LINK) - Queued = COUNT_AT_L2(Routes->NEIGHBOUR_LINK); // SEE HOW MANY QUEUED - else - Queued = 0; - - Iframes = Routes->NBOUR_IFRAMES; - Retries = Routes->NBOUR_RETRIES; - - if (Iframes) - { - Percent = (Retries * 100) / Iframes; - sprintf(PercentString, "%3d%%", Percent); - } - else - strcpy(PercentString, " "); - - - Bufferptr = Cmdprintf(Session, Bufferptr, "%s%2d %s %3d %3d%s%4d %4d %s %d %d %02d:%02d %d %d", - Active, Routes->NEIGHBOUR_PORT, Normcall, - Routes->NEIGHBOUR_QUAL, NodeCount, locked, Iframes, Retries, PercentString, Routes->NBOUR_MAXFRAME, Routes->NBOUR_FRACK, - Routes->NEIGHBOUR_TIME >> 8, (Routes->NEIGHBOUR_TIME) & 0xff, Queued, Routes->OtherendsRouteQual); - - // IF INP3 DISPLAY SRTT - - if (Routes->INP3Node) // INP3 Enabled? - { - double srtt = Routes->SRTT/1000.0; - double nsrtt = Routes->NeighbourSRTT/1000.0; - - Bufferptr = Cmdprintf(Session, Bufferptr, " %4.2fs %4.2fs", srtt, nsrtt); - } - - Bufferptr = Cmdprintf(Session, Bufferptr, "\r"); - } - else - { - Bufferptr = Cmdprintf(Session, Bufferptr, "%s %d %s %d %d%s\r", - Active, Routes->NEIGHBOUR_PORT, Normcall, Routes->NEIGHBOUR_QUAL, NodeCount, locked); - } - - return Bufferptr; -} - - -VOID CMDR00(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - struct ROUTE * Routes = NEIGHBOURS; - int MaxRoutes = MAXNEIGHBOURS; - char locked[] = " ! "; - int Percent = 0; - char * ptr, * Context; - char Verbose = 0; - int Port = 0; - char AXCALL[7]; - BOOL Found; - - ptr = strtok_s(CmdTail, " ", &Context); - - if (ptr && (int)strlen(ptr) > 1) - { - // Route Update - - goto ROUTEUPDATE; - } - - if (ptr) - { - Verbose = ptr[0]; - ptr = strtok_s(NULL, " ", &Context); - if (ptr) - Port = atoi(ptr); - } - - Bufferptr = Cmdprintf(Session, Bufferptr, "Routes\r"); - - while (MaxRoutes--) - { - if (Routes->NEIGHBOUR_CALL[0] != 0) - if (Port == 0 || Port == Routes->NEIGHBOUR_PORT) - Bufferptr = DisplayRoute(Session, Bufferptr, Routes, Verbose); - - Routes++; - } - goto SendReply; - -ROUTEUPDATE: - - if (Session->PASSWORD != 0xFFFF) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "%s", PASSWORDMSG); - goto SendReply; - } - - // Line is - - // ROUTES G8BPQ-2 2 100 - Set quality to 100 - // ROUTES G8BPQ-2 2 ! - Toggle 'Locked Route' flag - // ROUTES G8BPQ-2 2 100 ! - Set quality and toggle 'locked' flag - - - ConvToAX25(ptr, AXCALL); - - ptr = strtok_s(NULL, " ", &Context); - - if (ptr) - Port = atoi(ptr); - - if (Port == 0) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Port Number Missing \r"); - goto SendReply; - } - - Found = FindNeighbour(AXCALL, Port, &Routes); - - if (Context && Context[0] > 32) - { - // More Params - - ptr = strtok_s(NULL, " ", &Context); - - if (ptr) - { - // Adding - - memcpy(Routes->NEIGHBOUR_CALL, AXCALL, 7); // In case Add - Routes->NEIGHBOUR_PORT = Port; - Found = TRUE; - } - - if (strcmp(ptr, "!") == 0) - { - // Toggle Lock - - Routes->NEIGHBOUR_FLAG ^= 1; // FLIP LOCKED BIT - goto Displayit; - } - - if (strcmp(ptr, "Z") == 0) - { - // Clear Counts - - Routes->NBOUR_IFRAMES = 0; - Routes->NBOUR_RETRIES = 0; - goto Displayit; - } - - Routes->NEIGHBOUR_QUAL = atoi(ptr); - - if (Context && Context[0] == '!') - { - // Toggle Lock - - Routes->NEIGHBOUR_FLAG ^= 1; // FLIP LOCKED BIT - goto Displayit; - } - } - -Displayit: - - // Just display - - if (Found) - Bufferptr = DisplayRoute(Session, Bufferptr, Routes, 1); - else - Bufferptr = Cmdprintf(Session, Bufferptr, "Not Found\r"); - - - -/* MOV ROUTEDISP,1 - - CMP BYTE PTR [ESI],20H - JE SHORT JUSTDISPLAY - - MOV ZAPFLAG,0 - - CMP BYTE PTR [ESI],'Z' - JNE SHORT NOTZAP - - MOV ZAPFLAG,1 - JMP SHORT JUSTDISPLAY - - PUBLIC NOTZAP -NOTZAP: - - MOV ROUTEDISP,2 ; LOCK UPDATE - - CMP BYTE PTR [ESI],'!' - JE SHORT JUSTDISPLAY -; -; LOOK FOR V FOR ADDING A DIGI -; - CMP WORD PTR [ESI],' V' ; V [SPACE] - JE ADDDIGI - - CALL GETVALUE ; GET NUMBER, UP TO SPACE , CR OR OFFH - JC SHORT BADROUTECMD ; INVALID DIGITS - - MOV NEWROUTEVAL,AL - - MOV ROUTEDISP,0 - - CALL SCAN ; SEE IF ! - MOV AH,[ESI] - - - PUBLIC JUSTDISPLAY -JUSTDISPLAY: - - - MOV ESI,OFFSET32 AX25CALL - CALL _FINDNEIGHBOUR - JZ SHORT FOUNDROUTE ; IN LIST - OK - - CMP EBX,0 - JE SHORT BADROUTECMD ; TABLE FULL?? - - MOV ECX,7 - MOV EDI,EBX - REP MOVSB ; PUT IN CALL - - MOV AL,SAVEPORT - MOV NEIGHBOUR_PORT[EBX],AL - - JMP SHORT FOUNDROUTE - - - PUBLIC BADROUTECMD -BADROUTECMD: - - POP EDI - - JMP PBADVALUE - - PUBLIC FOUNDROUTE -FOUNDROUTE: - - CMP ZAPFLAG,1 - JNE SHORT NOTCLEARCOUNTS - - XOR AX,AX - MOV ES:WORD PTR NBOUR_IFRAMES[EDI],AX - MOV ES:WORD PTR NBOUR_IFRAMES+2[EDI],AX - MOV ES:WORD PTR NBOUR_RETRIES[EDI],AX - MOV ES:WORD PTR NBOUR_RETRIES+2[EDI],AX - - JMP SHORT NOUPDATE - - PUBLIC NOTCLEARCOUNTS -NOTCLEARCOUNTS: - - CMP ROUTEDISP,1 - JE SHORT NOUPDATE - - CMP ROUTEDISP,2 - JE SHORT LOCKUPDATE - - MOV AL,NEWROUTEVAL - MOV NEIGHBOUR_QUAL[EBX],AL - - CMP AH,'!' - JNE SHORT NOUPDATE - - PUBLIC LOCKUPDATE -LOCKUPDATE: - - XOR NEIGHBOUR_FLAG[EBX],1 ; FLIP LOCKED BIT - - PUBLIC NOUPDATE -NOUPDATE: - - MOV ESI,EBX - POP EDI - - POP EBX - CALL DISPLAYROUTE - - JMP SENDCOMMANDREPLY - - PUBLIC ADDDIGI -ADDDIGI: - - ADD ESI,2 - PUSH ESI ; SAVE INPUT BUFFER - - MOV ESI,OFFSET32 AX25CALL - CALL _FINDNEIGHBOUR - - POP ESI - - JZ SHORT ADD_FOUND ; IN LIST - OK - - JMP BADROUTECMD - - PUBLIC ADD_FOUND -ADD_FOUND: - - CALL CONVTOAX25 ; GET DIGI CALLSIGN - - PUSH ESI - - MOV ESI,OFFSET32 AX25CALL - LEA EDI,NEIGHBOUR_DIGI[EBX] - MOV ECX,7 - REP MOVSB - - POP ESI ; MSG BUFFER -; -; SEE IF ANOTHER DIGI -; - CMP BYTE PTR [ESI],20H - JE SHORT NOMORE - - CALL CONVTOAX25 ; GET DIGI CALLSIGN - MOV ESI,OFFSET32 AX25CALL - LEA EDI,NEIGHBOUR_DIGI+7[EBX] - MOV ECX,7 - REP MOVSB - - PUBLIC NOMORE -NOMORE: - - JMP NOUPDATE - - - -*/ - -SendReply: - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - - -VOID LISTENCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - // PROCESS LISTEN COMMAND - - // for monitoring a remote ax.25 port - - int Port = 0, index =0; - unsigned int ListenMask = 0; - char * ptr, *Context; - struct PORTCONTROL * PORT = NULL; - char ListenPortList[128] = ""; - - ptr = strtok_s(CmdTail, " ,", &Context); - - // Now accepts a list of ports - - if (ptr == 0 || memcmp(ptr, "OFF", 3) == 0) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Listening disabled\r"); - Session->LISTEN = 0; - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - while (ptr) - { - Port = atoi(ptr); - - if (Port == 0 && NUMBEROFPORTS == 1) - Port = 1; - - ptr = strtok_s(NULL, ", ", &Context); // Get Unproto String - - if (Port) - PORT = GetPortTableEntryFromPortNum(Port); - - if (PORT == NULL) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid Port %d\r", Port); - continue; - } - - if (PORT->PROTOCOL == 10 && PORT->UICAPABLE == 0) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Sorry, port %d is not an ax.25 port\r", Port); - continue; - } - - if (PORT->PORTL3FLAG) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Sorry, port %d is for internode traffic only\r", Port); - continue; - } - - if (Session->L4CIRCUITTYPE == L2LINK + UPLINK) - { - if (Session->L4TARGET.LINK->LINKPORT->PORTNUMBER == Port) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "You can't Listen to the port you are connected on\r"); - continue; - } - } - - sprintf(ListenPortList, "%s %d", ListenPortList, Port); - - - ListenMask |= (1 << (Port - 1)); - } - - Session->LISTEN = ListenMask; - - if (ListenMask) - { - if (CountBits(ListenMask) == 1) - Bufferptr = Cmdprintf(Session, Bufferptr, "Listening on port%s. Use CQ to send a beacon, LIS to disable\r", ListenPortList); - else - Bufferptr = Cmdprintf(Session, Bufferptr, "Listening on ports%s. Use LIS to disable\r", ListenPortList); - } - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; -} - - -VOID UNPROTOCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - // PROCESS UNPROTO COMMAND - - int Port = 0, index =0; - char * ptr, *Context; - struct PORTCONTROL * PORT = NULL; - UCHAR axcalls[64]; - BOOL Stay, Spy; - ptr = strtok_s(CmdTail, " ", &Context); - - if (ptr) - Port = atoi(ptr); - - if (Port == 0 && NUMBEROFPORTS == 1) - Port = 1; - else - ptr = strtok_s(NULL, " ", &Context); // Get Unproto String - - if (Port) - PORT = GetPortTableEntryFromPortNum(Port); - - if (PORT == NULL) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid Port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - if (ptr == NULL) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Destination missing\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - ptr[strlen(ptr)] = ' '; // Put param back together - - if (DecodeCallString(ptr, &Stay, &Spy, &axcalls[0]) == 0) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid Call\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - if (PORT->PROTOCOL == 10 && PORT->UICAPABLE == 0) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Sorry, port is not an ax.25 port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - if (PORT->PORTL3FLAG) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Sorry, port is for internode traffic only\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - // Copy Address Info to Session Record - - Session->UNPROTO = Port; - Session->UAddrLen = (int)strlen(axcalls); - memcpy(Session->UADDRESS, axcalls, 63); - - Bufferptr = Cmdprintf(Session, Bufferptr, "Unproto Mode - enter ctrl/z or /ex to exit\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; -} - -VOID CALCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - // PROCESS CAL COMMAND - - int Port = 0, index = 0, Count = 0; - char * ptr, *Context; - struct PORTCONTROL * PORT = NULL; - - ptr = strtok_s(CmdTail, " ", &Context); - - if (ptr) - Port = atoi(ptr); - - if (Port == 0 && NUMBEROFPORTS == 1) - Port = 1; - else - ptr = strtok_s(NULL, " ", &Context); // Get Unproto String - - if (Port) - PORT = GetPortTableEntryFromPortNum(Port); - - if (PORT == NULL) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid Port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - if (PORT->PROTOCOL == 10 && PORT->UICAPABLE == 0) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Sorry, port is not an ax.25 port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - if (ptr == NULL) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Count Missing\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - Count = atoi(ptr); - - ptr = strtok_s(NULL, " ", &Context); // Get Unproto String - - Bufferptr = Cmdprintf(Session, Bufferptr, "Ok\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; -} - - - -VOID CQCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - // Send a CQ Beacon on a radio port. Must be in LISTEN state - - DIGIMESSAGE Msg; - int Port = 0; - int OneBits = 0; - unsigned int MaskCopy = Session->LISTEN; - int Len; - UCHAR CQCALL[7]; - char Empty[] = ""; - char * ptr1 = &OrigCmdBuffer[3]; - UCHAR * axptr = &Msg.DIGIS[0][0]; - char * ptr2, *Context; - - while (MaskCopy) - { - if (MaskCopy & 1) - OneBits++; - - Port++; - MaskCopy = MaskCopy >> 1; - } - - if (OneBits == 0) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "You must enter LISTEN before calling CQ\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - if (OneBits > 1) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "You can't call CQ if LISTENing on more than one port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - - Len = (int)strlen(OrigCmdBuffer) - 3; - - if (Len < 0) - Len = 0; - - memset(&Msg, 0, sizeof(Msg)); - - Msg.PORT = Port; - Msg.CTL = 3; // UI - - // see if a Via specified - - if (_memicmp(ptr1, "via ", 4) == 0) - { - ptr2 = strtok_s(ptr1 + 4, ",", &Context); - - while (ptr2) - { - if (ConvToAX25(ptr2, axptr) == 0) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid via string\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - axptr += 7; - - if (axptr == &Msg.DIGIS[7][0]) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Too many digis\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - ptr1 = ptr2; - ptr2 = strtok_s(NULL, ",", &Context); - } - - // ptr1 is start of last digi call. We need to position to data - - ptr1 = strchr(ptr1, ' '); - - if (ptr1 == NULL) - ptr1 = Empty; - else - ptr1++ ; // to message - - Len = (int)strlen(ptr1); - - } - - ConvToAX25("CQ", CQCALL); - memcpy(Msg.DEST, CQCALL, 7); - memcpy(Msg.ORIGIN, Session->L4USER, 7); - Msg.ORIGIN[6] ^= 0x1e; // Flip SSID - Msg.PID = 0xf0; // Data PID - memcpy(&Msg.L2DATA, ptr1, Len); - - Send_AX_Datagram(&Msg, Len + 2, Port); // Len is Payload ie CTL, PID and Data - - Bufferptr = Cmdprintf(Session, Bufferptr, "CQ sent\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - -} - - -TRANSPORTENTRY * SetupNewSession(TRANSPORTENTRY * Session, char * Bufferptr) -{ - TRANSPORTENTRY * NewSess = L4TABLE; - int Index = 0; - - while (Index < MAXCIRCUITS) - { - if (NewSess->L4USER[0] == 0) - { - // Got One - - Session->L4CROSSLINK = NewSess; - NewSess->L4CROSSLINK = Session; - - memcpy(NewSess->L4USER, Session->L4USER, 7); - memcpy(NewSess->L4MYCALL, Session->L4MYCALL, 7); - - - NewSess->CIRCUITINDEX = Index; //OUR INDEX - NewSess->CIRCUITID = NEXTID; - - NEXTID++; - if (NEXTID == 0) - NEXTID++; // kEEP nON-ZERO - - NewSess->SESSIONT1 = Session->SESSIONT1; - NewSess->L4WINDOW = (UCHAR)L4DEFAULTWINDOW; - - return NewSess; - } - Index++; - NewSess++; - } - - if (Bufferptr) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Sorry - System Tables Full\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - } - - return NULL; -} - - -VOID DoNetromConnect(TRANSPORTENTRY * Session, char * Bufferptr, struct DEST_LIST * Dest, BOOL Spy) -{ - TRANSPORTENTRY * NewSess; - - NewSess = SetupNewSession(Session, Bufferptr); - - if (NewSess == NULL) - return; // Tables Full - - NewSess->L4CIRCUITTYPE = SESSION + DOWNLINK; - - NewSess->L4TARGET.DEST = Dest; - NewSess->L4STATE = 2; // CONNECTING - - NewSess->SPYFLAG = Spy; - - ReleaseBuffer((UINT *)REPLYBUFFER); - - SENDL4CONNECT(NewSess); - - L4CONNECTSOUT++; - - return; -} - -BOOL FindLink(UCHAR * LinkCall, UCHAR * OurCall, int Port, struct _LINKTABLE ** REQLINK) -{ - struct _LINKTABLE * LINK = LINKS; - struct _LINKTABLE * FIRSTSPARE = NULL; - int n = MAXLINKS; - - while (n--) - { - if (LINK->LINKCALL[0] == 0) // Spare - { - if (FIRSTSPARE == NULL) - FIRSTSPARE = LINK; - - LINK++; - continue; - } - - if ((LINK->LINKPORT->PORTNUMBER == Port) && CompareCalls(LINK->LINKCALL, LinkCall) && CompareCalls(LINK->OURCALL, OurCall)) - { - *REQLINK = LINK; - return TRUE; - } - - LINK++; - } - // ENTRY NOT FOUND - FIRSTSPARE HAS FIRST FREE ENTRY, OR ZERO IF TABLE FULL - - *REQLINK = FIRSTSPARE; - return FALSE; -} - -VOID ATTACHCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * UserCMD); - -VOID CMDC00(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - // PROCESS CONNECT COMMAND - - TRANSPORTENTRY * NewSess; - - int CONNECTPORT, Port; - BOOL CallEvenIfInNodes = FALSE; - char * ptr, *Context; - UCHAR axcalls[64]; - UCHAR ourcall[7]; // Call we are using (may have SSID bits inverted - int ret; - struct PORTCONTROL * PORT = PORTTABLE; - struct _LINKTABLE * LINK; - int CQFLAG = 0; // NOT CQ CALL - BOOL Stay, Spy; - int n; - char TextCall[10]; - int TextCallLen; - char PortString[10]; - char cmdCopy[256]; - struct _EXTPORTDATA * EXTPORT = (struct _EXTPORTDATA *)PORT;; - - -#ifdef EXCLUDEBITS - - if (CheckExcludeList(Session->L4USER) == FALSE) - { - // CONNECTS FROM THIS STATION ARE NOT ALLOWED - - ReleaseBuffer((UINT *)REPLYBUFFER); - return; - } - -#endif - - if (Session->LISTEN) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Can't connect while listening\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - CONNECTPORT = 0; // NO PORT SPECIFIED - - ptr = strtok_s(CmdTail, " ", &Context); - - strcpy(cmdCopy, Context); // Save in case Telnet Connect - - if (ptr == 0) - { - // No param - - if (CFLAG) // C Command Disabled ? - { - // Convert to HOST (appl 32) command - - //MOV _CMDPTR,OFFSET32 _HOSTCMD - //MOV _ALIASPTR,OFFSET32 _HOSTCMD + 32 * 31 - - //MOV _APPLMASK, 80000000H ; Internal Term - - } - - Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid Call\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - Port = atoi(ptr); - - if (Port) - { - // IF THERE IS NOTHING FOLLOWING THE NUMBER, ASSUME IT IS A - // NUMERIC ALIAS INSTEAD OF A PORT - - sprintf(PortString, "%d", Port); - - if (strlen(PortString) < (int)strlen(ptr)) - goto NoPort; - - PORT = GetPortTableEntryFromPortNum(Port); - - if (PORT == NULL) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid Port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - EXTPORT = (struct _EXTPORTDATA *)PORT; - - ptr = strtok_s(NULL, " ", &Context); - - if (ptr == 0) - { - // No param - - Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid Call\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - CONNECTPORT = Port; - - if (strcmp(ptr, "CMS") == 0 || strcmp(ptr, "HOST") == 0) // In case someeone has CMS or HOST as an alias - goto Downlink; - - } - -NoPort: - - ptr[strlen(ptr)] = ' '; // Put param back together - - if (ptr[0] == '!') - { - CallEvenIfInNodes = TRUE; - ptr++; - } - - if (memcmp(ptr, "RELAY ", 5) == 0 || memcmp(ptr, "SYNC ", 5) == 0) - { - // c p relay with extra parms - - goto Downlink; - } - - // Skip call validation if using a ptc to allow 1:call, 2:call format - - if (PORT->PROTOCOL == 10 && memcmp(EXTPORT->PORT_DLL_NAME, "SCSPACTOR", 9) == 0) - { - char * p; - - if (p = strstr(cmdCopy, " S ")) - { - Stay = TRUE; - p++; - *p = ' '; - } - - if (p = strstr(cmdCopy, " Z ")) - { - Spy = TRUE; - p++; - *p = ' '; - } - - goto Downlink; - } - else - { - if (DecodeCallString(ptr, &Stay, &Spy, &axcalls[0]) == 0) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid Call\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - } - - Session->STAYFLAG = Stay; - - TextCallLen = ConvFromAX25(axcalls, TextCall); - - if (CallEvenIfInNodes) - goto Downlink; - - // SEE IF CALL TO ANY OF OUR HOST SESSIONS - UNLESS DIGIS SPECIFIED - - if (axcalls[7] == 0) - { - // If this connect is as a result of a command alias, don't check appls or we will loop - - if (ALIASINVOKED == 0) - { - APPLCALLS * APPL = APPLCALLTABLE; - int n = NumberofAppls; - APPLMASK = 1; - - while (n--) - { - if (memcmp(axcalls, APPL->APPLALIAS, 6) == 0 || CompareCalls(axcalls, APPL->APPLCALL)) - { - // Call to an appl - - // Convert to an APPL command, so any alias is actioned - - // SEE IF THERE IS AN ALIAS DEFINDED FOR THIS COMMAND - - if (APPL->APPLHASALIAS && APPL->APPLALIASVAL[0] != 0x20) - { - // COPY ALIAS TO COMMAND _BUFFER, THEN REENTER COMMAND HANDLER - - memcpy(COMMANDBUFFER, APPL->APPLALIASVAL, ALIASLEN); - COMMANDBUFFER[80] = 0; - _strupr(COMMANDBUFFER); - memcpy(OrigCmdBuffer, APPL->APPLALIASVAL, ALIASLEN); // In case original case version needed - - ALIASINVOKED = TRUE; // To prevent Alias Loops - } - else - { - - // Copy Appl Command to Command Buffer - - memcpy(COMMANDBUFFER, APPL->APPLCMD, 12); - COMMANDBUFFER[12] = 13; - } - DoTheCommand(Session); - return; - } - APPL++; - APPLMASK <<= 1; - } - } - } - - if (axcalls[7] == 0) - { - // SEE IF CALL TO ANOTHER NODE - - struct DEST_LIST * Dest = DESTS; - int n = MAXDESTS; - - if (axcalls[6] == 0x60) // if SSID, dont check aliases - { - while (n--) - { - if (memcmp(Dest->DEST_ALIAS, TextCall, 6) == 0) - { - DoNetromConnect(Session, Bufferptr, Dest, Spy); - return; - } - Dest++; - } - } - - Dest = DESTS; - n = MAXDESTS; - - while (n--) - { - if (CompareCalls(Dest->DEST_CALL, axcalls)) - { - DoNetromConnect(Session, Bufferptr, Dest, Spy); - return; - } - Dest++; - } - } - - // Must be Downlink Connect - -Downlink: - - if (CONNECTPORT == 0 && NUMBEROFPORTS > 1) - { - // L2 NEEDS PORT NUMBER - - Bufferptr = Cmdprintf(Session, Bufferptr, "Downlink connect needs port number - C P CALLSIGN\r"); - - // Send Port List - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - // ENSURE PORT IS AVAILABLE FOR L2 USE - - if (PORT->PROTOCOL >= 10) // Pactor=-style port? - { - int count; - - // if Via PACTOR ARDOP WINMOR or VARA, convert to attach and call = Digi's are in AX25STRING (+7) - - if (memcmp(&axcalls[7], &WINMOR[0], 6) == 0 || - memcmp(&axcalls[7], &ARDOP[0], 6) == 0 || - memcmp(&axcalls[7], &VARA[0], 6) == 0 || - memcmp(&axcalls[7], &PACTORCALL[0], 6) == 0) - { - char newcmd[80]; - - TextCall[TextCallLen] = 0; - sprintf(newcmd, "%s %s", CmdTail, TextCall); - - ATTACHCMD(Session, Bufferptr, newcmd, NULL); - return; - } - - // If on a KAM or SCS with ax.25 on port 2, do an Attach command, then pass on connect - - if (EXTPORT->MAXHOSTMODESESSIONS <= 1) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Sorry, port is not an ax.25 port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - // Only Allow Attach VHF from Secure Applications or if PERMITGATEWAY is set - - if (EXTPORT->PERMITGATEWAY == 0 && Session->Secure_Session == 0) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Sorry, you are not allowed to use this port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - count = EXTPORT->MAXHOSTMODESESSIONS; - count--; // First is Pactor Stream, count is now last ax.25 session - - while (count) - { - if (EXTPORT->ATTACHEDSESSIONS[count] == 0) - { - int Paclen, PortPaclen; - struct DATAMESSAGE * Buffer; - struct DATAMESSAGE Message = {0}; - char Callstring[80]; - int len; - - // Found a free one - use it - - // See if TNC is OK - - Message.PORT = count; - - ret = PORT->PORTTXCHECKCODE(PORT, Message.PORT); - - if ((ret & 0xff00) == 0) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Error - TNC Not Ready\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - // GET CIRCUIT TABLE ENTRY FOR OTHER END OF LINK - - NewSess = SetupNewSession(Session, Bufferptr); - if (NewSess == NULL) - return; - - // if a UZ7HO port, and the uplink is L2 or Uz7HO invert SSID bits - - // We only get here if multisession - - if (memcmp(EXTPORT->PORT_DLL_NAME, "UZ7HO", 5) != 0) - goto noFlip; - - if ((Session->L4CIRCUITTYPE & BPQHOST))// host - goto noFlip; - - if ((Session->L4CIRCUITTYPE & PACTOR)) - { - // incoming is Pactorlike - see if UZ7HO - - if (memcmp(Session->L4TARGET.EXTPORT->PORT_DLL_NAME, "UZ7HO", 5) != 0) - goto noFlip; - else - NewSess->L4USER[6] ^= 0x1e; // UZ7HO Uplink - flip - } - else - - // Must be L2 uplink - flip - - NewSess->L4USER[6] ^= 0x1e; // Flip SSID -noFlip: - EXTPORT->ATTACHEDSESSIONS[count] = NewSess; - - NewSess->KAMSESSION = count; - - // Set paclen to lower of incoming and outgoing - - Paclen = Session->SESSPACLEN; // Incoming PACLEN - - if (Paclen == 0) - Paclen = 256; // 0 = 256 - - PortPaclen = PORT->PORTPACLEN; - - if (PortPaclen == 0) - PortPaclen = 256; // 0 = 256 - - if (PortPaclen < Paclen) - Paclen = PortPaclen; - - NewSess->SESSPACLEN = Paclen; - Session->SESSPACLEN = Paclen; - - NewSess->L4STATE = 5; - NewSess->L4CIRCUITTYPE = DOWNLINK + PACTOR; - NewSess->L4TARGET.PORT = PORT; - - // Send the connect command to the TNC - - Buffer = REPLYBUFFER; - - Buffer->PORT = count; - Buffer->PID = 0xf0; - - // if on Telnet Port convert use original cmd tail - - // Why just on telnet - what not all ports?? - - if (memcmp(EXTPORT->PORT_DLL_NAME, "TELNET", 6) == 0 || memcmp(EXTPORT->PORT_DLL_NAME, "SCSPACTOR", 9) == 0) - { - NewSess->Secure_Session = Session->Secure_Session; - len = sprintf(Callstring,"C %s", cmdCopy); - } - else - { - TextCall[TextCallLen] = 0; - - len = sprintf(Callstring,"C %s", TextCall); - - if (axcalls[7]) - { - int digi = 7; - - // we have digis - - len += sprintf(&Callstring[len], " via"); - - while (axcalls[digi]) - { - TextCall[ConvFromAX25(&axcalls[digi], TextCall)] = 0; - len += sprintf(&Callstring[len], " %s", TextCall); - digi += 7; - } - } - } - Callstring[len++] = 13; - Callstring[len] = 0; - - Buffer->LENGTH = len + MSGHDDRLEN + 1; - memcpy(Buffer->L2DATA, Callstring, len); - C_Q_ADD(&PORT->PORTTX_Q, (UINT *)Buffer); - - return; - } - count--; - } - - Bufferptr = Cmdprintf(Session, Bufferptr, "Error - No free streams on this port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - if ((Session->L4CIRCUITTYPE & BPQHOST) == 0 && PORT->PORTL3FLAG) - { - //Port only for L3 - - Bufferptr = Cmdprintf(Session, Bufferptr, "Sorry, port is for internode traffic only\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - if (PORT->PortUIONLY) - { - //Port only for UI - - Bufferptr = Cmdprintf(Session, Bufferptr, "Sorry, port is for UI traffic only\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - if (Session->L4USER[6] == 0x42 || Session->L4USER[6] == 0x44) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Sorry - Can't make ax.25 calls with SSID of T or R\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - // Get Session Entry for Downlink - - NewSess = SetupNewSession(Session, Bufferptr); - if (NewSess == NULL) - return; - - NewSess->L4CIRCUITTYPE = L2LINK + DOWNLINK; - - // FORMAT LINK TABLE ENTRY FOR THIS CONNECTION - - memcpy(ourcall, NewSess->L4USER, 7); - - // SSID SWAP TEST - LEAVE ALONE FOR HOST or Pactor like (unless UZ7HO) - - if ((Session->L4CIRCUITTYPE & BPQHOST))// host - goto noFlip3; - - if ((Session->L4CIRCUITTYPE & PACTOR)) - { - // incoming is Pactorlike - see if UZ7HO - - if (memcmp(Session->L4TARGET.EXTPORT->PORT_DLL_NAME, "UZ7HO", 5) != 0) - goto noFlip3; - - if (Session->L4TARGET.EXTPORT->MAXHOSTMODESESSIONS < 2) // Not multisession - goto noFlip3; - - ourcall[6] ^= 0x1e; // UZ7HO Uplink - flip - } - else - - // Must be L2 uplink - flip - - ourcall[6] ^= 0x1e; // Flip SSID - -noFlip3: - - // SET UP NEW SESSION (OR RESET EXISTING ONE) - - FindLink(axcalls, ourcall, Port, &LINK); - - if (LINK == NULL) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Sorry - System Tables Full\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - - // Should release NewSess - - return; - } - - memcpy(LINK->LINKCALL, axcalls, 7); - memcpy(LINK->OURCALL, ourcall, 7); - - LINK->LINKPORT = PORT; - - LINK->L2TIME = PORT->PORTT1; - - // Copy Digis - - n = 7; - ptr = &LINK->DIGIS[0]; - - while (axcalls[n]) - { - memcpy(ptr, &axcalls[n], 7); - n += 7; - ptr += 7; - - LINK->L2TIME += 2 * PORT->PORTT1; // ADJUST TIMER VALUE FOR 1 DIGI - } - - LINK->LINKTYPE = 2; // DOWNLINK - LINK->LINKWINDOW = PORT->PORTWINDOW; - - RESET2(LINK); // RESET ALL FLAGS - - if (CMD->String[0] == 'N' && SUPPORT2point2) - LINK->L2STATE = 1; // New (2.2) send XID - else - LINK->L2STATE = 2; // Send SABM - - LINK->CIRCUITPOINTER = NewSess; - - NewSess->L4TARGET.LINK = LINK; - - if (PORT->PORTPACLEN) - NewSess->SESSPACLEN = Session->SESSPACLEN = PORT->PORTPACLEN; - - if (CQFLAG == 0) // if a CQ CALL DONT SEND SABM - { - if (LINK->L2STATE == 1) - L2SENDXID(LINK); - else - SENDSABM(LINK); - } - ReleaseBuffer((UINT *)REPLYBUFFER); - return; -} - -BOOL DecodeCallString(char * Calls, BOOL * Stay, BOOL * Spy, UCHAR * AXCalls) -{ - // CONVERT CALL + OPTIONAL DIGI STRING TO AX25, RETURN - // CONVERTED STRING IN AXCALLS. Return FALSE if invalied - - char * axptr = AXCalls; - char * ptr, *Context; - int CQFLAG = 0; // NOT CQ CALL - int n = 8; // Max digis - - *Stay = 0; - *Spy = 0; - - memset(AXCalls, 0, 64); - - ptr = strtok_s(Calls, " ,", &Context); - - if (ptr == NULL) - return FALSE; - - // First field is Call - - if (ConvToAX25(ptr, axptr) == 0) - return FALSE; - - axptr += 7; - - ptr = strtok_s(NULL, " ,", &Context); - - while (ptr && n--) - { - // NEXT FIELD = COULD BE CALLSIGN, VIA, OR S (FOR STAY) - - if (strcmp(ptr, "S") == 0) - *Stay = TRUE; - else if (strcmp(ptr, "Z") == 0) - *Spy = TRUE; - else if (memcmp(ptr, "VIA", (int)strlen(ptr)) == 0) - { - } //skip via - else - { - // Convert next digi - - if (ConvToAX25(ptr, axptr) == 0) - return FALSE; - - axptr += 7; - } - - ptr = strtok_s(NULL, " ,", &Context); - } - - return TRUE; -} - - -VOID LINKCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - // PROCESS *** LINKED to CALLSIGN - - char * ptr, *Context; - UCHAR axcall[7]; - int ret; - - if (LINKEDFLAG == 'Y' || // UNCONDITIONAL? - (LINKEDFLAG == 'A' && - ((Session->L4CIRCUITTYPE & BPQHOST) || Session->Secure_Session || Session->PASSWORD == 0xffff))) - { - ptr = strtok_s(CmdTail, " ", &Context); - if (ptr) - ptr = strtok_s(NULL, " ", &Context); - - if (ptr) - { - ret = ConvToAX25Ex(ptr, axcall); - - if (ret) - { - memcpy(Session->L4USER, axcall, 7); - strcpy(Bufferptr, OKMSG); - Bufferptr += (int)strlen(OKMSG); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - } - - strcpy(Bufferptr, BADMSG); - Bufferptr += (int)strlen(BADMSG); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - memcpy(Bufferptr, PASSWORDMSG, LPASSMSG); - Bufferptr += LPASSMSG; - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - -int CompareNode(const void *a, const void *b); -int CompareAlias(const void *a, const void *b); - -char * DoOneNode(TRANSPORTENTRY * Session, char * Bufferptr, struct DEST_LIST * Dest) -{ - char Normcall[10]; - char Alias[10]; - struct NR_DEST_ROUTE_ENTRY * NRRoute; - struct DEST_ROUTE_ENTRY * Route; - struct ROUTE * Neighbour; - int i, Active, len; - - Alias[6] = 0; - - memcpy(Alias, Dest->DEST_ALIAS, 6); - strlop(Alias, ' '); - - Normcall[ConvFromAX25(Dest->DEST_CALL, Normcall)] = 0; - - Bufferptr = Cmdprintf(Session, Bufferptr, "Routes to: %s:%s", Alias, Normcall); - - if (Dest->DEST_COUNT) - Bufferptr = Cmdprintf(Session, Bufferptr, " RTT=%4.2f FR=%d %c %.1d\r", - Dest->DEST_RTT /1000.0, Dest->DEST_COUNT, - (Dest->DEST_STATE & 0x40)? 'B':' ', (Dest->DEST_STATE & 63)); - else - Bufferptr = Cmdprintf(Session, Bufferptr, "\r"); - - NRRoute = &Dest->NRROUTE[0]; - - Active = Dest->DEST_ROUTE; - - for (i = 1; i < 4; i++) - { - Neighbour = NRRoute->ROUT_NEIGHBOUR; - - if (Neighbour) - { - len = ConvFromAX25(Neighbour->NEIGHBOUR_CALL, Normcall); - Normcall[len] = 0; - - Bufferptr = Cmdprintf(Session, Bufferptr, "%c %d %d %d %s\r", - (Active == i)?'>':' ',NRRoute->ROUT_QUALITY, NRRoute->ROUT_OBSCOUNT, Neighbour->NEIGHBOUR_PORT, Normcall); - } - NRRoute++; - } - - // DISPLAY INP3 ROUTES - - Route = &Dest->ROUTE[0]; - - Active = Dest->DEST_ROUTE; - - for (i = 1; i < 4; i++) - { - Neighbour = Route->ROUT_NEIGHBOUR; - - if (Neighbour) - { - double srtt = Route->SRTT/1000.0; - - len = ConvFromAX25(Neighbour->NEIGHBOUR_CALL, Normcall); - Normcall[len] = 0; - - Bufferptr = Cmdprintf(Session, Bufferptr, "%c %d %4.2fs %d %s\r", - (Active == i + 3)?'>':' ',Route->Hops, srtt, Neighbour->NEIGHBOUR_PORT, Normcall); - } - Route++; - } - - return Bufferptr; -} - - -int DoViaEntry(struct DEST_LIST * Dest, int n, char * line, int cursor) -{ - char Portcall[10]; - int len; - - if (Dest->NRROUTE[n].ROUT_NEIGHBOUR != 0 && Dest->NRROUTE[n].ROUT_NEIGHBOUR->INP3Node == 0) - { - len=ConvFromAX25(Dest->NRROUTE[n].ROUT_NEIGHBOUR->NEIGHBOUR_CALL, Portcall); - Portcall[len]=0; - - len=sprintf(&line[cursor],"%s %d %d ", - Portcall, - Dest->NRROUTE[n].ROUT_NEIGHBOUR->NEIGHBOUR_PORT, - Dest->NRROUTE[n].ROUT_QUALITY); - - cursor+=len; - - if (Dest->NRROUTE[n].ROUT_OBSCOUNT > 127) - { - len=sprintf(&line[cursor],"! "); - cursor+=len; - } - } - return cursor; -} - -int DoINP3ViaEntry(struct DEST_LIST * Dest, int n, char * line, int cursor) -{ - char Portcall[10]; - int len; - double srtt; - - if (Dest->ROUTE[n].ROUT_NEIGHBOUR != 0) - { - srtt = Dest->ROUTE[n].SRTT/1000.0; - - len=ConvFromAX25(Dest->ROUTE[n].ROUT_NEIGHBOUR->NEIGHBOUR_CALL, Portcall); - Portcall[len]=0; - - len=sprintf(&line[cursor],"%s %d %d %4.2fs ", - Portcall, - Dest->ROUTE[n].ROUT_NEIGHBOUR->NEIGHBOUR_PORT, - Dest->ROUTE[n].Hops, srtt); - - cursor+=len; - - if (Dest->NRROUTE[n].ROUT_OBSCOUNT > 127) - { - len=sprintf(&line[cursor],"! "); - cursor+=len; - } - } - return cursor; -} - -int WildCmp(char * pattern, char * string) -{ - // Check if string is at end or not. - - if (*pattern == '\0') - return *string == '\0'; - - // Check for single character missing or match - - if (*pattern == '?' || *pattern == *string) - return *string != '\0' && WildCmp(pattern + 1, string + 1); - - if (*pattern == '*') - { - // Check for multiple character missing - - return WildCmp(pattern + 1, string) || (*string != '\0' && WildCmp(pattern, string + 1)); - } - - return 0; -} - -VOID CMDN00(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - struct DEST_LIST * Dest = DESTS; - int count = MAXDESTS, i; - char Normcall[10]; - char Alias[10]; - int Width = 4; - int x = 0, n = 0; - struct DEST_LIST * List[1000]; - char Param = 0; - char * ptr, * param2,* Context; - char Nodeline[21]; - char AXCALL[7]; - char * Call; - char * Qualptr; - int Qual; - char line[160]; - int cursor, len; - UCHAR axcall[7]; - int SavedOBSINIT = OBSINIT; - struct ROUTE * ROUTE = NULL; - char Pattern[80] = ""; - char * firststar; - - ptr = strtok_s(CmdTail, " ", &Context); - param2 = strtok_s(NULL, " ", &Context); - - if (ptr) - { - if (strcmp(ptr, "ADD") == 0) - goto NODE_ADD; - - if (strcmp(ptr, "DEL") == 0) - goto NODE_DEL; - - if (strcmp(ptr, "VIA") == 0) - goto NODE_VIA; - } - - if (ptr) - { - // Could be C or a pattern. Accept C pattern or pattern C - - if ((int)strlen(ptr) > 1) - { - strcpy(Pattern, ptr); - if (param2 && param2[0] == 'C') - Param = 'C'; - } - else - { - Param = ptr[0]; - if (param2) - strcpy(Pattern, param2); - } - } - - // We need to pick out CALL or CALL* from other patterns (as call use detail display) - - firststar = strchr(Pattern, '*'); - - if ((firststar && *(firststar + 1) != 0)|| strchr(Pattern, '?')) //(* not on end) - - // definitely pattern - - goto DoNodePattern; - - // If it works as CALL*, process, else drop through - - if (Pattern[0]) - { - UCHAR AXCall[8]; - int count; - int paramlen = (int)strlen(ptr); - char parampadded[20]; - int n = 0; - - Alias[8] = 0; - strcpy(parampadded, Pattern); - strcat(parampadded, " "); - - ConvToAX25(Pattern, AXCall); - - // if * on end, list all ssids - - if (firststar) - { - AXCall[6] = 0; - - Bufferptr = Cmdprintf(Session, Bufferptr, "\r"); - - while (AXCall[6] < 32) - { - Dest = DESTS; - - for (count = 0; count < MAXDESTS; count++) - { - if (memcmp(Dest->DEST_ALIAS, parampadded, 6) == 0 || CompareCalls(Dest->DEST_CALL, AXCall)) - { - break; - } - Dest++; - } - - if (count < MAXDESTS) - { - Bufferptr = DoOneNode(Session, Bufferptr, Dest); - n++; - } - - AXCall[6] += 2; - } - - if (n) // Found Some - { - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - Dest = DESTS; // Reset - - // Drop through to try as pattern - } - else - { - // process as just call - - for (count = 0; count < MAXDESTS; count++) - { - if (memcmp(Dest->DEST_ALIAS, parampadded, 6) == 0 || CompareCalls(Dest->DEST_CALL, AXCall)) - { - break; - } - Dest++; - } - - if (count == MAXDESTS) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Not found\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - Bufferptr = DoOneNode(Session, Bufferptr, Dest); - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - } - -DoNodePattern: - - Bufferptr = Cmdprintf(Session, Bufferptr, "Nodes\r"); - - while (count--) - { - if (Dest->DEST_CALL[0] != 0) - { - if (Param != 'T' || Dest->DEST_COUNT) - List[n++] = Dest; - - if (n > 999) - break; - } - - Dest++; - } - - if (Param == 'C') - qsort(List, n, sizeof(void *), CompareNode); - else - qsort(List, n, sizeof(void *), CompareAlias); - - - for (i = 0; i < n; i++) - { - int len = ConvFromAX25(List[i]->DEST_CALL, Normcall); - Normcall[len]=0; - - memcpy(Alias, List[i]->DEST_ALIAS, 6); - Alias[6] = 0; - strlop(Alias, ' '); - - if (strlen(Alias)) - strcat(Alias, ":"); - - if (Alias[0] == '#' && HIDENODES == 1 && Param != '*') // Hidden Node and not N * command - continue; - - if (Pattern[0]) - if (!WildCmp(Pattern, Normcall) && !WildCmp(Pattern, Alias)) - continue; - - if (Param == 'T') - { - Bufferptr = Cmdprintf(Session, Bufferptr, "%s%s RTT=%4.2f Frames = %d %c %.1d\r", - Alias, Normcall, List[i]->DEST_RTT /1000.0, List[i]->DEST_COUNT, - (List[i]->DEST_STATE & 0x40)? 'B':' ', (List[i]->DEST_STATE & 63)); - } - else - { - len = sprintf(Nodeline, "%s%s", Alias, Normcall); - memset(&Nodeline[len], ' ', 20 - len); - Nodeline[20] = 0; - Bufferptr = Cmdprintf(Session, Bufferptr, "%s", Nodeline); - - if (++x == Width) - { - x = 0; - Bufferptr = Cmdprintf(Session, Bufferptr, "\r"); - } - } - } - - if (x) - Bufferptr = Cmdprintf(Session, Bufferptr, "\r"); - - goto SendReply; - - -NODE_VIA: - - // List Nodes reachable via a neighbour - - ptr = param2; - - if (ptr == NULL) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Missing Call\r"); - goto SendReply; - } - - Bufferptr = Cmdprintf(Session, Bufferptr, "\r"); - - ConvToAX25(ptr, AXCALL); - - Dest = DESTS; - - Dest-=1; - - for (count=0; countNRROUTE[0].ROUT_NEIGHBOUR == 0 && Dest->ROUTE[0].ROUT_NEIGHBOUR == 0) - continue; - - - if ((Dest->NRROUTE[0].ROUT_NEIGHBOUR && CompareCalls(Dest->NRROUTE[0].ROUT_NEIGHBOUR->NEIGHBOUR_CALL, AXCALL)) - || (Dest->NRROUTE[1].ROUT_NEIGHBOUR && CompareCalls(Dest->NRROUTE[1].ROUT_NEIGHBOUR->NEIGHBOUR_CALL, AXCALL)) - || (Dest->NRROUTE[2].ROUT_NEIGHBOUR && CompareCalls(Dest->NRROUTE[2].ROUT_NEIGHBOUR->NEIGHBOUR_CALL, AXCALL)) - - || (Dest->ROUTE[0].ROUT_NEIGHBOUR && CompareCalls(Dest->ROUTE[0].ROUT_NEIGHBOUR->NEIGHBOUR_CALL, AXCALL)) - || (Dest->ROUTE[1].ROUT_NEIGHBOUR && CompareCalls(Dest->ROUTE[1].ROUT_NEIGHBOUR->NEIGHBOUR_CALL, AXCALL)) - || (Dest->ROUTE[2].ROUT_NEIGHBOUR && CompareCalls(Dest->ROUTE[2].ROUT_NEIGHBOUR->NEIGHBOUR_CALL, AXCALL))) - { - len=ConvFromAX25(Dest->DEST_CALL,Normcall); - - Normcall[len]=0; - - memcpy(Alias,Dest->DEST_ALIAS,6); - - Alias[6]=0; - - for (i=0;i<6;i++) - { - if (Alias[i] == ' ') - Alias[i] = 0; - } - - cursor=sprintf(line,"%s:%s ", Alias,Normcall); - - cursor = DoViaEntry(Dest, 0, line, cursor); - cursor = DoViaEntry(Dest, 1, line, cursor); - cursor = DoViaEntry(Dest, 2, line, cursor); - cursor = DoINP3ViaEntry(Dest, 0, line, cursor); - cursor = DoINP3ViaEntry(Dest, 1, line, cursor); - cursor = DoINP3ViaEntry(Dest, 2, line, cursor); - - line[cursor++]='\r'; - line[cursor++]=0; - - Bufferptr = Cmdprintf(Session, Bufferptr, "%s", line); - } - } - - - goto SendReply; - -NODE_ADD: - - // FORMAT IS NODE ADD ALIAS:CALL QUAL ROUTE PORT - - - if (Session->PASSWORD != 0xFFFF) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "%s", PASSWORDMSG); - goto SendReply; - } - - ptr = param2; - - if (ptr == NULL) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Missing Alias:Call\r"); - goto SendReply; - } - - Call = strlop(ptr, ':'); - - if (Call == NULL) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Missing Alias:Call\r"); - goto SendReply; - } - - - ConvToAX25(Call, AXCALL); - - Qualptr = strtok_s(NULL, " ", &Context); - - if (Qualptr == 0) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Quality missing\r"); - goto SendReply; - } - - Qual = atoi(Qualptr); - - if (Qual < MINQUAL) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Quality is below MINQUAL\r"); - goto SendReply; - } - - if (FindDestination(AXCALL, &Dest)) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Node already in Table\r"); - goto SendReply; - } - - if (Dest == NULL) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Node Table Full\r"); - goto SendReply; - } - - memcpy(Dest->DEST_CALL, AXCALL, 7); - memcpy(Dest->DEST_ALIAS, ptr, 6); - - NUMBEROFNODES++; - - ptr = strtok_s(NULL, " ", &Context); - - if (ptr == NULL || ptr[0] == 0) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Neighbour missing\r"); - goto SendReply; - } - - if (ConvToAX25(ptr, axcall) == 0) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid Neighbour\r"); - goto SendReply; - } - else - { - int Port; - - ptr = strtok_s(NULL, " ", &Context); - if (ptr == NULL) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Port missing\r"); - goto SendReply; - } - - Port = atoi(ptr); - - if (Context[0] == '!') - { - OBSINIT = 255; //; SPECIAL FOR LOCKED - } - - if (FindNeighbour(axcall, Port, &ROUTE)) - { - PROCROUTES(Dest, ROUTE, Qual); - } - - OBSINIT = SavedOBSINIT; - - Bufferptr = Cmdprintf(Session, Bufferptr, "Node Added\r"); - goto SendReply; - } - - - - -/* -PNODE48: - - -; GET NEIGHBOURS FOR THIS DESTINATION -; - CALL CONVTOAX25 - JNZ SHORT BADROUTE -; - CALL GETVALUE - MOV SAVEPORT,AL ; SET PORT FOR _FINDNEIGHBOUR - - CALL GETVALUE - MOV ROUTEQUAL,AL -; - MOV ESI,OFFSET32 AX25CALL - - PUSH EBX ; SAVE DEST - CALL _FINDNEIGHBOUR - MOV EAX,EBX ; ROUTE TO AX - POP EBX - - JZ SHORT NOTBADROUTE - - JMP SHORT BADROUTE - -NOTBADROUTE: -; -; UPDATE ROUTE LIST FOR THIS DEST -; - MOV ROUT1_NEIGHBOUR[EBX],EAX - MOV AL,ROUTEQUAL - MOV ROUT1_QUALITY[EBX],AL - MOV ROUT1_OBSCOUNT[EBX],255 ; LOCKED -; - POP EDI - POP EBX - - INC _NUMBEROFNODES - - JMP SENDOK - -BADROUTE: -; -; KILL IT -; - MOV ECX,TYPE DEST_LIST - MOV EDI,EBX - MOV AL,0 - REP STOSB - - JMP BADROUTECMD - -*/ - - goto SendReply; - - -NODE_DEL: - - if (Session->PASSWORD != 0xFFFF) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "%s", PASSWORDMSG); - goto SendReply; - } - - ptr = param2; - - if (ptr == NULL) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Missing Call\r"); - goto SendReply; - } - - if (strcmp(ptr, "ALL") == 0) - { - struct DEST_LIST * DEST = DESTS; - int n = MAXDESTS; - - while (n--) - { - if (DEST->DEST_CALL[0] && ((DEST->DEST_STATE & 0x80) == 0)) // Don't delete appl node - REMOVENODE(DEST); - - DEST++; - } - - ClearNodes(); - - Bufferptr = Cmdprintf(Session, Bufferptr, "All Nodes Deleted\r"); - goto SendReply; - } - - ConvToAX25(ptr, AXCALL); - - if (FindDestination(AXCALL, &Dest) == 0) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Not Found\r"); - goto SendReply; - } - - if (Dest->DEST_STATE & 0x80) - Bufferptr = Cmdprintf(Session, Bufferptr, "APPL Node - Can't delete\r"); - else - { - REMOVENODE(Dest); - Bufferptr = Cmdprintf(Session, Bufferptr, "Node Deleted\r"); - } - Bufferptr = Cmdprintf(Session, Bufferptr, "Node Deleted\r"); - -SendReply: - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - -VOID CMDQUERY(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * UserCMD) -{ - // DISPLAY AVAILABLE COMMANDS - - int n; - char * ptr; - char ApplList[2048]; - char * out = ApplList; - - CMDX * CMD = &COMMANDS[APPL1]; - - for (n = 0; n < NumberofAppls; n++) - { - ptr = &CMD->String[0]; - if (*(ptr) != '*') - { - while (*ptr != ' ') - { - *(out++) = *(ptr++); - } - *(out++) = ' '; - } - CMD++; - } - - *(out) = 0; - - n = CMDLISTLEN; - - if (NEEDMH == 0) - n -= 7; // Dont show MH - - Bufferptr = Cmdprintf(Session, Bufferptr, "%s%s\r", ApplList, CMDLIST); - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - -char * FormatMH(MHSTRUC * MH, char Format); - -VOID MHCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - // DISPLAY HEARD LIST - - int Port = 0, sess = 0; - char * ptr, *Context, *pattern; - struct PORTCONTROL * PORT = NULL; - MHSTRUC * MH; - int count = MHENTRIES; - int n; - char Normcall[20]; - char From[10]; - char DigiList[100]; - char * Output; - int len; - char Digi = 0; - - - // Note that the MHDIGIS field may contain rubbish. You have to check End of Address bit to find - // how many digis there are - - ptr = strtok_s(CmdTail, " ", &Context); - - if (ptr) - Port = atoi(ptr); - - if (Port) - PORT = GetPortTableEntryFromPortNum(Port); - - if (PORT == NULL) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid Port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - pattern = strtok_s(NULL, " ", &Context); - - if (pattern) - _strupr(pattern); // Optional filter - - MH = PORT->PORTMHEARD; - - if (MH == NULL) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "MHEARD not enabled on that port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - if (pattern && strstr(pattern, "CLEAR")) - { - if (Session->Secure_Session) - { - memset(MH, 0, MHENTRIES * sizeof(MHSTRUC)); - SaveMH(); - Bufferptr = Cmdprintf(Session, Bufferptr, "Heard List for Port %d Cleared\r", Port); - } - else - { - Bufferptr = Cmdprintf(Session, Bufferptr, "MH Clear needs SYSOP status\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - } - else - { - if (CMD->String[2] == 'V') // MHV - { - Bufferptr = Cmdprintf(Session, Bufferptr, "MHeard List %s for Port %d\r", MYNODECALL, Port); - Bufferptr = Cmdprintf(Session, Bufferptr, "Callsign Last heard Pkts RX via Digi ;) \r"); - Bufferptr = Cmdprintf(Session, Bufferptr, "--------- ----------- ------- ------------------------------------------\r"); - } - else - if (pattern) - Bufferptr = Cmdprintf(Session, Bufferptr, "Heard List for Port %d filtered by %s\r", Port, pattern); - else - Bufferptr = Cmdprintf(Session, Bufferptr, "Heard List for Port %d\r", Port); - } - while (count--) - { - if (MH->MHCALL[0] == 0) - break; - - Digi = 0; - - len = ConvFromAX25(MH->MHCALL, Normcall); - - Normcall[len++] = MH->MHDIGI; - Normcall[len++] = 0; - - if (pattern && strstr(Normcall, pattern) == 0) - { - MH++; - continue; - } - - n = 8; // Max number of digi-peaters - - ptr = &MH->MHCALL[6]; // End of Address bit - - Output = &DigiList[0]; - - if ((*ptr & 1) == 0) - { - // at least one digi - - strcpy(Output, "via "); - Output += 4; - - while ((*ptr & 1) == 0) - { - // MORE TO COME - - From[ConvFromAX25(ptr + 1, From)] = 0; - Output += sprintf((char *)Output, "%s", From); - - ptr += 7; - n--; - - if (n == 0) - break; - - // See if digi actioned - put a * on last actioned - - if (*ptr & 0x80) - { - if (*ptr & 1) // if last address, must need * - { - *(Output++) = '*'; - Digi = '*'; - } - - else - if ((ptr[7] & 0x80) == 0) // Repeased by next? - { - *(Output++) = '*'; // No, so need * - Digi = '*'; - } - -} - *(Output++) = ','; - } - *(--Output) = 0; // remove last comma - } - else - *(Output) = 0; - - // if we used a digi set * on call and display via string - - - if (Digi) - Normcall[len++] = Digi; - else - DigiList[0] = 0; // Dont show list if not used - - Normcall[len++] = 0; - - - ptr = FormatMH(MH, CMD->String[2]); - - if (CMD->String[2] == 'V') // MHV - Bufferptr = Cmdprintf(Session, Bufferptr, "%-10s %-10s %-10d %-30s\r", - Normcall, ptr, MH->MHCOUNT, DigiList); - else - Bufferptr = Cmdprintf(Session, Bufferptr, "%-10s %s %s\r", Normcall, ptr, DigiList); - - MH++; - } - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - -int Rig_Command(int Session, char * Command); - -VOID RADIOCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * UserCMD) -{ - char * ptr; - - if (Rig_Command(Session->CIRCUITINDEX, CmdTail)) - { - ReleaseBuffer((UINT *)REPLYBUFFER); - return; - } - - // Error Message is in buffer - - ptr = strchr(CmdTail, 13); - - if (ptr) - { - int len = (int)(++ptr - CmdTail); - - memcpy(Bufferptr, CmdTail, len); - Bufferptr += len; - } - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - - -VOID SendNRRecordRoute(struct DEST_LIST * DEST, TRANSPORTENTRY * Session); - - -VOID NRRCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * UserCMD) -{ - // PROCESS 'NRR - Netrom Record Route' COMMAND - - char * ptr, *Context; - struct DEST_LIST * Dest = DESTS; - int count = MAXDESTS; - - ptr = strtok_s(CmdTail, " ", &Context); - - if (ptr) - { - UCHAR AXCall[8]; - int count; - - ConvToAX25(ptr, AXCall); - strcat(ptr, " "); - - for (count = 0; count < MAXDESTS; count++) - { - if (memcmp(Dest->DEST_ALIAS, ptr, 6) == 0 || CompareCalls(Dest->DEST_CALL, AXCall)) - { - SendNRRecordRoute(Dest, Session); - memcpy(Bufferptr, OKMSG, 3); - Bufferptr += 3; - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - - return; - } - Dest++; - } - } - Bufferptr = Cmdprintf(Session, Bufferptr, "Not found\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; -} - -int CHECKINTERLOCK(struct PORTCONTROL * OURPORT) -{ - // See if any Interlocked ports are Busy - - struct PORTCONTROL * PORT = PORTTABLE; - struct _EXTPORTDATA * EXTPORT; - - int n = NUMBEROFPORTS; - int ourgroup = OURPORT->PORTINTERLOCK; - - while (PORT) - { - if (PORT != OURPORT) - { - if (PORT->PORTINTERLOCK == ourgroup) - { - // Same Group - is it busy - - int i = 0; - - EXTPORT = (struct _EXTPORTDATA *)PORT; - - while (i < 27) - if (EXTPORT->ATTACHEDSESSIONS[i++]) - return PORT->PORTNUMBER; - } - } - PORT = PORT->PORTPOINTER; - } - - return 0; -} - -VOID ATTACHCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * UserCMD) -{ - // ATTACH to a PACTOR or similar port - - TRANSPORTENTRY * NewSess; - struct _EXTPORTDATA * EXTPORT; - struct TNCINFO * TNC; - - int Port = 0, sess = 0; - char * ptr, *Context; - int ret; - struct PORTCONTROL * PORT = NULL; - struct DATAMESSAGE Message = {0}; - int Paclen, PortPaclen; - struct DATAMESSAGE * Buffer; - - ptr = strtok_s(CmdTail, " ", &Context); - - if (ptr) - Port = atoi(ptr); - - if (Port) - PORT = GetPortTableEntryFromPortNum(Port); - - if (PORT == NULL || PORT->PROTOCOL < 10) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid Port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - // If attach on telnet port, find a free stream - - EXTPORT = (struct _EXTPORTDATA *)PORT; - - if (strstr(EXTPORT->PORT_DLL_NAME, "TELNET")) - { - int count = EXTPORT->MAXHOSTMODESESSIONS; - count--; // First is Pactor Stream, count is now last ax.25 session - - while (count) - { - if (EXTPORT->ATTACHEDSESSIONS[count] == 0) - { - int Paclen, PortPaclen; - struct DATAMESSAGE Message = {0}; - - // Found a free one - use it - - // See if TNC is OK - - Message.PORT = count; - - ret = PORT->PORTTXCHECKCODE(PORT, Message.PORT); - - if ((ret & 0xff00) == 0) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Error - TNC Not Ready\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - // GET CIRCUIT TABLE ENTRY FOR OTHER END OF LINK - - NewSess = SetupNewSession(Session, Bufferptr); - - if (NewSess == NULL) - return; - - EXTPORT->ATTACHEDSESSIONS[count] = NewSess; - - NewSess->Secure_Session = Session->Secure_Session; - - NewSess->KAMSESSION = count; - - // Set paclen to lower of incoming and outgoing - - Paclen = Session->SESSPACLEN; // Incoming PACLEN - - if (Paclen == 0) - Paclen = 256; // 0 = 256 - - PortPaclen = PORT->PORTPACLEN; - - if (PortPaclen == 0) - PortPaclen = 256; // 0 = 256 - - if (PortPaclen < Paclen) - Paclen = PortPaclen; - - NewSess->SESSPACLEN = Paclen; - Session->SESSPACLEN = Paclen; - - NewSess->L4STATE = 5; - NewSess->L4CIRCUITTYPE = DOWNLINK + PACTOR; - NewSess->L4TARGET.PORT = PORT; - - ptr = strtok_s(NULL, " ", &Context); - sess = count; - - // Replace command tail with original (before conversion to upper case - - Context = Context + (OrigCmdBuffer - COMMANDBUFFER); - - goto checkattachandcall; - - - memcpy(Bufferptr, OKMSG, 3); - Bufferptr += 3; - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - - return; - } - count--; - } - - Bufferptr = Cmdprintf(Session, Bufferptr, "Error - No free streams on this port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - - Message.PORT = 0; - - ret = PORT->PORTTXCHECKCODE(PORT, Message.PORT); - - if ((ret & 0xff00) == 0) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Error - TNC Not Ready\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - // See if "Attach and Call" (for VHF ports) - - ptr = strtok_s(NULL, " ", &Context); - - if (ptr && strcmp(ptr, "S") == 0) - { - Session->STAYFLAG = TRUE; - ptr = strtok_s(NULL, " ", &Context); - } - - if (ptr) - { - // we have another param - - // if it is a single char it is a channel number for vhf attach - - if (strlen(ptr) == 1) - { - // Only Allow Attach VHF from Secure Applications or if PERMITGATEWAY is set - - if (EXTPORT->PERMITGATEWAY == 0 && Session->Secure_Session == 0) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Sorry, you are not allowed to use this port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - sess = ptr[0] - '@'; - - if (sess < 1 || sess > EXTPORT->MAXHOSTMODESESSIONS) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Error - Invalid Channel\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - ptr = strtok_s(NULL, " ", &Context); - - if (ptr && strcmp(ptr, "S") == 0) - { - Session->STAYFLAG = TRUE; - ptr = strtok_s(NULL, " ", &Context); - } - } - } - - if (ret & 0x8000) // Disconnecting - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Error - Port in use\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - // Check Interlock. Only ports with a TNC record can be interlocked - - TNC = PORT->TNC; - - if (TNC) - { - // See if any interlocked ports are in use - - struct TNCINFO * OtherTNC; - int i; - int rxInterlock = TNC->RXRadio; - int txInterlock = TNC->TXRadio; - - if (rxInterlock || txInterlock) - { - for (i=1; i<33; i++) - { - OtherTNC = TNCInfo[i]; - - if (OtherTNC == NULL) - continue; - - if (OtherTNC == TNC) - continue; - - if (rxInterlock == OtherTNC->RXRadio || txInterlock == OtherTNC->TXRadio) // Same Group - { - if (OtherTNC->PortRecord->ATTACHEDSESSIONS[0]) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Sorry, interlocked port %d is in use\r", i); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - } - } - } - } - - - - - if (EXTPORT->ATTACHEDSESSIONS[sess]) - { - // In use - - Bufferptr = Cmdprintf(Session, Bufferptr, "Error - Port in use\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - // GET CIRCUIT TABLE ENTRY FOR OTHER END OF LINK - - NewSess = SetupNewSession(Session, Bufferptr); - - if (NewSess == NULL) - return; - - // if a UZ7HO port, and the uplink is L2 or Uz7HO and multisession, - // invert SSID bits - - if (memcmp(EXTPORT->PORT_DLL_NAME, "UZ7HO", 5) != 0) - goto noFlip1; - - if (EXTPORT->MAXHOSTMODESESSIONS < 2) // Not multisession - goto noFlip1; - - if ((Session->L4CIRCUITTYPE & BPQHOST)) // host - goto noFlip1; - - if ((Session->L4CIRCUITTYPE & PACTOR)) - { - // incoming is Pactorlike - see if UZ7HO - - if (memcmp(Session->L4TARGET.EXTPORT->PORT_DLL_NAME, "UZ7HO", 5) != 0) - goto noFlip1; - else - NewSess->L4USER[6] ^= 0x1e; // UZ7HO Uplink - flip - } - else - - // Must be L2 uplink - flip - - NewSess->L4USER[6] ^= 0x1e; // Flip SSID -noFlip1: - - EXTPORT->ATTACHEDSESSIONS[sess] = NewSess; - - NewSess->KAMSESSION = sess; - - // Set paclen to lower of incoming and outgoing - - Paclen = Session->SESSPACLEN; // Incoming PACLEN - - if (Paclen == 0) - Paclen = 256; // 0 = 256 - - PortPaclen = PORT->PORTPACLEN; - - if (PortPaclen == 0) - PortPaclen = 256; // 0 = 256 - - if (PortPaclen < Paclen) - Paclen = PortPaclen; - - NewSess->SESSPACLEN = Paclen; - Session->SESSPACLEN = Paclen; - NewSess->L4STATE = 5; - NewSess->L4CIRCUITTYPE = DOWNLINK + PACTOR; - NewSess->L4TARGET.PORT = PORT; - -checkattachandcall: - - if (ptr) - { - // we have a call to connect to - - char Callstring[80]; - int len; - - Buffer = REPLYBUFFER; - Buffer->PORT = sess; - Buffer->PID = 0xf0; - - len = sprintf(Callstring,"C %s", ptr); - - ptr = strtok_s(NULL, " ", &Context); - - while (ptr) // if any other params (such as digis) copy them - { - if (strcmp(ptr, "S") == 0) - { - Session->STAYFLAG = TRUE; - } - else - len += sprintf(&Callstring[len], " %s", ptr); - - ptr = strtok_s(NULL, " ", &Context); - } - - Callstring[len++] = 13; - Callstring[len] = 0; - - Buffer->LENGTH = len + MSGHDDRLEN + 1; - memcpy(Buffer->L2DATA, Callstring, len); - C_Q_ADD(&PORT->PORTTX_Q, (UINT *)Buffer); - - return; - } - - memcpy(Bufferptr, OKMSG, 3); - Bufferptr += 3; - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - - return; -} - -// SYSOP COMMANDS - -CMDX COMMANDS[] = -{ - "SAVENODES ",8, SAVENODES, 0, - "TELRECONFIG ",4, RECONFIGTELNET, 0, - "SAVEMH ",6, SAVEMHCMD, 0, - "REBOOT ",6, REBOOT, 0, - "RIGRECONFIG ",8 , RIGRECONFIG, 0, - "RESTART ",7,RESTART,0, - "RESTARTTNC ",10,RESTARTTNC,0, - "SENDNODES ",8,SENDNODES,0, - "EXTRESTART ",10, EXTPORTVAL, offsetof(EXTPORTDATA, EXTRESTART), - "TXDELAY ",3, PORTVAL, offsetof(PORTCONTROLX, PORTTXDELAY), - "MAXFRAME ",3, PORTVAL, offsetof(PORTCONTROLX, PORTWINDOW), - "RETRIES ",3, PORTVAL, offsetof(PORTCONTROLX, PORTN2), - "FRACK ",3,PORTVAL, offsetof(PORTCONTROLX, PORTT1), - "RESPTIME ",3,PORTVAL, offsetof(PORTCONTROLX, PORTT2), - "PPACLEN ",3,PORTVAL, offsetof(PORTCONTROLX, PORTPACLEN), - "QUALITY ",3,PORTVAL, offsetof(PORTCONTROLX, PORTQUALITY), - "PERSIST ",2,PORTVAL, offsetof(PORTCONTROLX, PORTPERSISTANCE), - "TXTAIL ",3,PORTVAL, offsetof(PORTCONTROLX, PORTTAILTIME), - "XMITOFF ",7,PORTVAL, offsetof(PORTCONTROLX, PORTDISABLED), - "DIGIFLAG ",5,PORTVAL, offsetof(PORTCONTROLX, DIGIFLAG), - "DIGIPORT ",5,PORTVAL, offsetof(PORTCONTROLX, DIGIPORT), - "MAXUSERS ",4,PORTVAL, offsetof(PORTCONTROLX, USERS), - "L3ONLY ",6,PORTVAL, offsetof(PORTCONTROLX, PORTL3FLAG), - "BBSALIAS ",4,PORTVAL, offsetof(PORTCONTROLX, PORTBBSFLAG), - "VALIDCALLS ",5,VALNODES,0, - "WL2KSYSOP ",5,WL2KSYSOP,0, - "STOPPORT ",4,STOPPORT,0, - "STARTPORT ",5,STARTPORT,0, - "STOPCMS ",7,STOPCMS,0, - "STARTCMS ",8,STARTCMS,0, - - "FINDBUFFS ",4,FINDBUFFS,0, - "KISS ",4,KISSCMD,0, - "GETPORTCTEXT",9,GetPortCTEXT, 0, - -#ifdef EXCLUDEBITS - - "EXCLUDE ",4,ListExcludedCalls,0, - -#endif - - "FULLDUP ",4,PORTVAL, offsetof(PORTCONTROLX, FULLDUPLEX), - "SOFTDCD ",4,PORTVAL, offsetof(PORTCONTROLX, SOFTDCDFLAG), - "OBSINIT ",7,SWITCHVAL,(size_t)&OBSINIT, - "OBSMIN ",6,SWITCHVAL,(size_t)&OBSMIN, - "NODESINT ",8,SWITCHVAL,(size_t)&L3INTERVAL, - "L3TTL ",5,SWITCHVAL,(size_t)&L3LIVES, - "L4RETRIES ",5,SWITCHVAL,(size_t)&L4N2, - "L4TIMEOUT ",5,SWITCHVALW,(size_t)&L4T1, - "T3 ",2,SWITCHVALW,(size_t)&T3, - "NODEIDLETIME",8,SWITCHVALW,(size_t)&L4LIMIT, - "LINKEDFLAG ",10,SWITCHVAL,(size_t)&LINKEDFLAG, - "IDINTERVAL ",5,SWITCHVAL,(size_t)&IDINTERVAL, - "MINQUAL ",7,SWITCHVAL,(size_t)&MINQUAL, - "FULLCTEXT ",6,SWITCHVAL,(size_t)&FULL_CTEXT, - "HIDENODES ",8,SWITCHVAL,(size_t)&HIDENODES, - "L4DELAY ",7,SWITCHVAL,(size_t)&L4DELAY, - "L4WINDOW ",6,SWITCHVAL,(size_t)&L4DEFAULTWINDOW, - "BTINTERVAL ",5,SWITCHVAL,(size_t)&BTINTERVAL, - "PASSWORD ", 8, PWDCMD, 0, - - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, - "************", 12, APPLCMD, 0, // Apppl 32 is internal Terminal - "*** LINKED ",10,LINKCMD,0, - "CQ ",2,CQCMD,0, - "CONNECT ",1,CMDC00,0, - "NC ",2,CMDC00,0, - "BYE ",1,BYECMD,0, - "QUIT ",1,BYECMD,0, - "INFO ",1,CMDI00,0, - "VERSION ",1,CMDV00,0, - "NODES ",1,CMDN00,0, - "LINKS ",1,CMDL00,0, - "LISTEN ",3,LISTENCMD,0, - "L4T1 ",2,CMDT00,0, - "PORTS ",1,CMDP00,0, - "PACLEN ",3,CMDPAC,0, - "IDLETIME ",4,CMDIDLE,0, - "ROUTES ",1,CMDR00,0, - "STATS ",1,CMDSTATS,0, - "USERS ",1,CMDS00,0, - "UNPROTO ",2,UNPROTOCMD,0, - "? ",1,CMDQUERY,0, - "DUMP ",4,DUMPCMD,0, - "MHU ",3,MHCMD,0, // UTC Times - "MHL ",3,MHCMD,0, // Local Times - "MHV ",3,MHCMD,0, - "MHEARD ",1,MHCMD,0, - "APRS ",2,APRSCMD,0, - "ATTACH ",1,ATTACHCMD,0, - "RADIO ",3,RADIOCMD,0, - "AXRESOLVER ",3,AXRESOLVER,0, - "AXMHEARD ",3,AXMHEARD,0, - "TELSTATUS ",3,SHOWTELNET,0, - "NRR ",1,NRRCMD,0, - "PING ",2,PING,0, - "AGWSTATUS ",3,SHOWAGW,0, - "ARP ",3,SHOWARP,0, - "NAT ",3,SHOWNAT,0, - "IPROUTE ",3,SHOWIPROUTE,0, - "..FLMSG ",7,FLMSG,0 -}; - -CMDX * CMD = NULL; - -int NUMBEROFCOMMANDS = sizeof(COMMANDS)/sizeof(CMDX); - -char * ReplyPointer; // Pointer into reply buffer - -int DecodeNodeName(char * NodeName, char * ptr) -{ - // NodeName is TABLE ENTRY WITH AX25 CALL AND ALIAS - - // Copyies 20 byte 20 DECODED NAME IN FORM ALIAS:CALL to ptr - // Returns significant length of string - - int len; - char Normcall[10]; - char * alias = &NodeName[7]; - int n = 6; - char * start = ptr; - - memset(ptr, ' ', 20); - - len = ConvFromAX25(NodeName, Normcall); - - if (*(alias) > ' ') // Does alias start with a null or a space ? - { - while (*(alias) > ' ' && n--) - { - *ptr++ = *alias++; - } - *ptr++ = ':'; - } - - memcpy(ptr, Normcall, len); - ptr += len; - - return (int)(ptr - start); -} - -char * SetupNodeHeader(struct DATAMESSAGE * Buffer) -{ - char Header[20]; - int len; - - char * ptr = &Buffer->L2DATA[0]; - - len = DecodeNodeName(MYCALLWITHALIAS, Header); - - memcpy (ptr, Header, len); - ptr += len; - - (*ptr++) = HEADERCHAR; - (*ptr++) = ' '; - - return ptr; -} - -VOID SendCommandReply(TRANSPORTENTRY * Session, struct DATAMESSAGE * Buffer, int Len) -{ - if (Len == (4 + sizeof(void *))) // Null Packet - { - ReleaseBuffer((UINT *)Buffer); - return; - } - - Buffer->LENGTH = Len; - - C_Q_ADD(&Session->L4TX_Q, (UINT *)Buffer); - - PostDataAvailable(Session); -} - - -VOID CommandHandler(TRANSPORTENTRY * Session, struct DATAMESSAGE * Buffer) -{ - // ignore frames with single NULL (Keepalive) - - if (Buffer->LENGTH == sizeof(void *) + 5 && Buffer->L2DATA[0] == 0) - { - ReleaseBuffer(Buffer); - return; - } - - if (Buffer->LENGTH > 100) - { -// Debugprintf("BPQ32 command too long %s", Buffer->L2DATA); - ReleaseBuffer(Buffer); - return; - } - -InnerLoop: - - InnerCommandHandler(Session, Buffer); - -// See if any more commands in buffer - - if (Session->PARTCMDBUFFER) - { - char * ptr1, * ptr2; - int len; - - Buffer = Session->PARTCMDBUFFER; - - // Check that message has a CR, if not save buffer and exit - - len = Buffer->LENGTH - (4 + sizeof(void *)); - ptr1 = &Buffer->L2DATA[0]; - - ptr2 = memchr(ptr1, 13, len); - - if (ptr2 == NULL) - return; - - Session->PARTCMDBUFFER = NULL; - - goto InnerLoop; - } -} - - -VOID InnerCommandHandler(TRANSPORTENTRY * Session, struct DATAMESSAGE * Buffer) -{ - char * ptr1, * ptr2, *ptr3; - int len, oldlen, newlen, rest, n; - struct DATAMESSAGE * OldBuffer; - struct DATAMESSAGE * SaveBuffer; - char c; - - // If a partial command is stored, append this data to it. - - if (Session->PARTCMDBUFFER) - { - len = Buffer->LENGTH - (sizeof(void *) + 4); - ptr1 = &Buffer->L2DATA[0]; - - OldBuffer = Session->PARTCMDBUFFER; // Old Data - - if (OldBuffer == Buffer) - { - // something has gone horribly wrong - - Session->PARTCMDBUFFER = NULL; - return; - } - - oldlen = OldBuffer->LENGTH; - - newlen = len + oldlen; - - if (newlen > 200) - { - // Command far too long - ignore previous - - OldBuffer->LENGTH = oldlen = sizeof(void *) + 4; - } - - OldBuffer->LENGTH += len; - memcpy(&OldBuffer->L2DATA[oldlen - (sizeof(void *) + 4)], Buffer->L2DATA, len); - - ReleaseBuffer((UINT *)Buffer); - - Buffer = OldBuffer; - - Session->PARTCMDBUFFER = NULL; - } - - // Check that message has a CR, if not save buffer and exit - - len = Buffer->LENGTH - (sizeof(void *) + 4); - ptr1 = &Buffer->L2DATA[0]; - - // Check for sending YAPP to Node - - if (len == 2 && ptr1[0] == 5 && ptr1[1] == 1) - { - ptr1[0] = 0x15; // NAK - - ptr1[1] = sprintf(&ptr1[2], "Node doesn't support YAPP Transfers"); - - Buffer->LENGTH += ptr1[1]; - - C_Q_ADD(&Session->L4TX_Q, (UINT *)Buffer); - PostDataAvailable(Session); - return; - } - - - ptr2 = memchr(ptr1, ';', len); - - if (ptr2 == 0) - { - ptr2 = memchr(ptr1, 13, len); - - if (ptr2 == 0) - { - // No newline - - Session->PARTCMDBUFFER = Buffer; - return; - } - } - - ptr2++; - - rest = len - (int)(ptr2 - ptr1); - - if (rest) - { - // there are chars beyond the cr in the buffer - - // see if LF after CR - - if ((*ptr2) == 10) // LF - { - ptr2++; - rest--; - } - - if (rest) // May only have had LF - { - // Get a new buffer, and copy extra data to it. - - SaveBuffer = (struct DATAMESSAGE *)GetBuff(); - - if (SaveBuffer) //`Just ignore if no buffers - { - SaveBuffer->LENGTH = rest + MSGHDDRLEN + 1; - SaveBuffer->PID = 0xf0; - memcpy(&SaveBuffer->L2DATA[0], ptr2, rest); - Session->PARTCMDBUFFER = SaveBuffer; - } - } - } - - // GET PACLEN FOR THIS CONNECTION - - CMDPACLEN = Session->SESSPACLEN; - - if (CMDPACLEN == 0) - CMDPACLEN = PACLEN; // Use default if no Session PACLEN - - // If sesion is in UNPROTO Mode, send message as a UI message - - if (Session->UNPROTO) - { - DIGIMESSAGE Msg; - int Port = Session->UNPROTO; - int Len = Buffer->LENGTH - (MSGHDDRLEN -1); // Need PID - - // First check for UNPROTO exit - ctrl/z or /ex - - if (Buffer->L2DATA[0] == 26 || (Len == 6 && _memicmp(&Buffer->L2DATA[0], "/ex", 3) == 0)) // CTRL/Z or /ex - { - REPLYBUFFER = Buffer; - - Session->UNPROTO = 0; - memset(Session->UADDRESS, 0, 64); - - // SET UP HEADER - - Buffer->PID = 0xf0; - ptr1 = SetupNodeHeader(Buffer); - memcpy(ptr1, OKMSG, 3); - ptr1 += 3; - SendCommandReply(Session, Buffer, (int)(ptr1 - (char *)Buffer)); - - return; - } - - memset(&Msg, 0, sizeof(Msg)); - - Msg.PORT = Port; - Msg.CTL = 3; // UI - memcpy(Msg.DEST, Session->UADDRESS, 7); - memcpy(Msg.ORIGIN, Session->L4USER, 7); - memcpy(Msg.DIGIS, &Session->UADDRESS[7], Session->UAddrLen - 7); - memcpy(&Msg.PID, &Buffer->PID, Len); - - Send_AX_Datagram(&Msg, Len, Port); // Len is Payload - CTL, PID and Data - -// SendUIModeFrame(Session, (PMESSAGE)Buffer, Session->UNPROTO); - - ReleaseBuffer((UINT *)Buffer); // Not using buffer for reply - - return; - } - - memset(COMMANDBUFFER, 32, 80); // Clear to spaces - - ptr1 = &Buffer->L2DATA[0]; - ptr2 = &COMMANDBUFFER[0]; - ptr3 = &OrigCmdBuffer[0]; - - memset(OrigCmdBuffer, 0, 80); - n = 80; - - while (n--) - { - c = *(ptr1++) & 0x7f; // Mask paritu - - if (c == 13 || c == ';') - break; // CR - - *(ptr3++) = c; // Original Case - - c = toupper(c); - *(ptr2++) = c; - } - - - // USE INPUT MESSAGE _BUFFER FOR REPLY - - REPLYBUFFER = Buffer; - - // SET UP HEADER - - Buffer->PID = 0xf0; - ptr1 = SetupNodeHeader(Buffer); - - ReplyPointer = ptr1; - - ALIASINVOKED = 0; // Clear "Invoked by APPL ALIAS flag" - - DoTheCommand(Session); // We also call DotheCommand when we need to reprocess - eg for alias handling -} - -VOID DoTheCommand(TRANSPORTENTRY * Session) -{ - struct DATAMESSAGE * Buffer = REPLYBUFFER; - char * ptr1, * ptr2; - int n; - - ptr1 = &COMMANDBUFFER[0]; // - - n = 10; - - while ((*ptr1 == ' ' || *ptr1 == 0) && n--) - ptr1++; // STRIP LEADING SPACES and nulls (from keepalive) - - if (n == -1) - { - // Null command - - ReleaseBuffer((UINT *)Buffer); - return; - } - - ptr2 = ptr1; // Save - - - CMD = &COMMANDS[0]; - n = 0; - - for (n = 0; n < NUMBEROFCOMMANDS; n++) - { - int CL = CMD->CMDLEN; - - ptr1 = ptr2; - - CMDPTR = CMD; - - if (n == APPL1) // First APPL command - { - APPLMASK = 1; // FOR APPLICATION ATTACH REQUESTS - ALIASPTR = &CMDALIAS[0][0]; - } - - // ptr1 is input command - - if (memcmp(CMD->String, ptr1, CL) == 0) - { - // Found match so far - check rest - - char * ptr2 = &CMD->String[CL]; - - ptr1 += CL; - - if (*(ptr1) != ' ') - { - while(*(ptr1) == *ptr2 && *(ptr1) != ' ') - { - ptr1++; - ptr2++; - } - } - - if (*(ptr1) == ' ') - { - Session->BADCOMMANDS = 0; // RESET ERROR COUNT - - // SEE IF SYSOP COMMAND, AND IF SO IF PASSWORD HAS BEEN ENTERED - - if (n < PASSCMD) - { - //NEEDS PASSWORD FOR SYSOP COMMANDS - - if (Session->PASSWORD != 0xFFFF) - { - ptr1 = ReplyPointer; - - memcpy(ptr1, PASSWORDMSG, LPASSMSG); - ptr1 += LPASSMSG; - - SendCommandReply(Session, Buffer, (int)(ptr1 - (char *)Buffer)); - return; - } - } -// VALNODESFLAG = 0; // NOT VALID NODES COMMAND - - ptr1++; // Skip space - - CMD->CMDPROC(Session, ReplyPointer, ptr1, CMD); - return; - } - } - - APPLMASK <<= 1; - ALIASPTR += ALIASLEN; - - CMD++; - - } - Session->BADCOMMANDS++; - - if (Session->BADCOMMANDS > 6) // TOO MANY ERRORS - { - ReleaseBuffer((UINT *)Buffer); - Session->STAYFLAG = 0; - CLOSECURRENTSESSION(Session); - return; - } - - ptr1 = ReplyPointer; - - memcpy(ptr1, CMDERRMSG, CMDERRLEN); - ptr1 += CMDERRLEN; - - SendCommandReply(Session, Buffer, (int)(ptr1 - (char *)Buffer)); -} - - -VOID StatsTimer() -{ - struct PORTCONTROL * PORT = PORTTABLE; - int sum; - - while(PORT) - { - sum = PORT->SENDING / 11; - PORT->AVSENDING = sum; - - sum = (PORT->SENDING + PORT->ACTIVE) /11; - PORT->AVACTIVE = sum; - - PORT->SENDING = 0; - PORT->ACTIVE = 0; - - PORT = PORT->PORTPOINTER; - } -} - - - -extern struct AXIPPORTINFO * Portlist[]; - -#define TCPConnected 4 - - -VOID AXRESOLVER(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - // DISPLAY AXIP Resolver info - - int Port = 0, index =0; - char * ptr, *Context; - struct PORTCONTROL * PORT = NULL; - struct AXIPPORTINFO * AXPORT; - char Normcall[11]; - char Flags[10]; - struct arp_table_entry * arp; - - ptr = strtok_s(CmdTail, " ", &Context); - - if (ptr) - Port = atoi(ptr); - - if (Port) - PORT = GetPortTableEntryFromPortNum(Port); - - if (PORT == NULL) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid Port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - AXPORT = Portlist[Port]; - - if (AXPORT == NULL) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Not an AXIP port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - Bufferptr = Cmdprintf(Session, Bufferptr, "AXIP Resolver info for Port %d\r", Port); - - while (index < AXPORT->arp_table_len) - { - arp = &AXPORT->arp_table[index]; - - if (arp->ResolveFlag && arp->error != 0) - { - // resolver error - Display Error Code - sprintf(AXPORT->hostaddr, "Error %d", arp->error); - } - else - { - if (arp->IPv6) - Format_Addr((unsigned char *)&arp->destaddr6.sin6_addr, AXPORT->hostaddr, TRUE); - else - Format_Addr((unsigned char *)&arp->destaddr.sin_addr, AXPORT->hostaddr, FALSE); - } - - ConvFromAX25(arp->callsign, Normcall); - - Flags[0] = 0; - - if (arp->BCFlag) - strcat(Flags, "B "); - - if (arp->TCPState == TCPConnected) - strcat(Flags, "C "); - - if (arp->AutoAdded) - strcat(Flags, "A"); - - if (arp->port == arp->SourcePort) - Bufferptr = Cmdprintf(Session, Bufferptr,"%.10s = %.64s %d = %-.42s %s\r", - Normcall, - arp->hostname, - arp->port, - AXPORT->hostaddr, - Flags); - - else - Bufferptr = Cmdprintf(Session, Bufferptr,"%.10s = %.64s %d<%d = %-.42s %s\r", - Normcall, - arp->hostname, - arp->port, - arp->SourcePort, - AXPORT->hostaddr, - Flags); - - index++; - } - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - -VOID AXMHEARD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - // DISPLAY AXIP Mheard info - - int Port = 0, index = 0; - char * ptr, *Context; - struct PORTCONTROL * PORT = NULL; - struct AXIPPORTINFO * AXPORT; - int n = MHENTRIES; - char Normcall[11]; - - ptr = strtok_s(CmdTail, " ", &Context); - - if (ptr) - Port = atoi(ptr); - - if (Port) - PORT = GetPortTableEntryFromPortNum(Port); - - if (PORT == NULL) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid Port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - AXPORT = Portlist[Port]; - - if (AXPORT == NULL) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Not an AXIP port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - Bufferptr = Cmdprintf(Session, Bufferptr, "AXIP Mheard for Port %d\r", Port); - - while (index < MaxMHEntries) - { - if (AXPORT->MHTable[index].proto != 0) - { - char Addr[80]; - - Format_Addr((unsigned char *)&AXPORT->MHTable[index].ipaddr6, Addr, AXPORT->MHTable[index].IPv6); - - Normcall[ConvFromAX25(AXPORT->MHTable[index].callsign, Normcall)] = 0; - - Bufferptr = Cmdprintf(Session, Bufferptr, "%-10s%-15s %c %-6d %-25s%c\r", Normcall, - Addr, - AXPORT->MHTable[index].proto, - AXPORT->MHTable[index].port, - asctime(gmtime( &AXPORT->MHTable[index].LastHeard )), - (AXPORT->MHTable[index].Keepalive == 0) ? ' ' : 'K'); - - Bufferptr[-3] = ' '; // Clear CR returned by asctime - } - - index++; - } - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - -#pragma pack() - -extern struct TNCINFO * TNCInfo[41]; - -extern char WL2KCall[10]; -extern char WL2KLoc[7]; - -BOOL GetWL2KSYSOPInfo(char * Call, char * _REPLYBUFFER); -BOOL UpdateWL2KSYSOPInfo(char * Call, char * SQL); - -VOID WL2KSYSOP(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - char _REPLYBUFFER[1000] = ""; - - char LastUpdated[100]; - char Name[100] = ""; - char Addr1[100] = ""; - char Addr2[100] = ""; - char City[100] = ""; - char State[100] = ""; - char Country[100] = ""; - char PostCode[100] = ""; - char Email[100] = ""; - char Website[100] = ""; - char Phone[100] = ""; - char Data[100] = ""; - char LOC[100] = ""; - BOOL Exists = TRUE; - time_t LastUpdateSecs = 0; - char * ptr1, * ptr2; - - SOCKET sock; - - int Len; - char Message[2048]; - - if (WL2KCall[0] < 33) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Winlink reporting is not configured\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - - if (GetWL2KSYSOPInfo(WL2KCall, _REPLYBUFFER) == 0) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Failed to connect to WL2K Database\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - if (strstr(_REPLYBUFFER, "\"ErrorMessage\":")) - Exists = FALSE; - - GetJSONValue(_REPLYBUFFER, "\"SysopName\":", Name); - GetJSONValue(_REPLYBUFFER, "\"StreetAddress1\":", Addr1); - GetJSONValue(_REPLYBUFFER, "\"StreetAddress2\":", Addr2); - GetJSONValue(_REPLYBUFFER, "\"City\":", City); - GetJSONValue(_REPLYBUFFER, "\"State\":", State); - GetJSONValue(_REPLYBUFFER, "\"Country\":", Country); - GetJSONValue(_REPLYBUFFER, "\"PostalCode\":", PostCode); - GetJSONValue(_REPLYBUFFER, "\"Email\":", Email); - GetJSONValue(_REPLYBUFFER, "\"Website\":", Website); - GetJSONValue(_REPLYBUFFER, "\"Phones\":", Phone); - GetJSONValue(_REPLYBUFFER, "\"Comments\":", Data); - GetJSONValue(_REPLYBUFFER, "\"GridSquare\":", LOC); - GetJSONValue(_REPLYBUFFER, "\"Timestamp\":", LastUpdated); - - ptr1 = strchr(LastUpdated, '('); - - if (ptr1) - { - ptr2 = strchr(++ptr1, ')'); - - if (ptr2) - { - *(ptr2 - 3) = 0; // remove millisecs - LastUpdateSecs = atoi(ptr1); - - FormatTime3(LastUpdated, LastUpdateSecs); - } - } - - if (_memicmp(CmdTail, "SET ", 4) == 0) - { - if (Exists) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Record already exists in WL2K Database\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - // Set New Values. Any other params are values to set, separated by | - -// ptr1 = strtok_s(&CmdTail[4], ",", &Context); - -// if (ptr1 == NULL) -// goto DoReplace; - -// strcpy(Name, ptr1); - -//DoReplace: - - Len = sprintf(Message, - "\"Callsign\":\"%s\"," - "\"GridSquare\":\"%s\"," - "\"SysopName\":\"%s\"," - "\"StreetAddress1\":\"%s\"," - "\"StreetAddress2\":\"%s\"," - "\"City\":\"%s\"," - "\"State\":\"%s\"," - "\"Country\":\"%s\"," - "\"PostalCode\":\"%s\"," - "\"Email\":\"%s\"," - "\"Phones\":\"%s\"," - "\"Website\":\"%s\"," - "\"Comments\":\"%s\",", - - WL2KCall, WL2KLoc, Name, Addr1, Addr2, City, State, Country, PostCode, Email, Phone, Website, Data); - - Debugprintf("Sending %s", Message); - - sock = OpenWL2KHTTPSock(); - - if (sock) - SendHTTPRequest(sock, "api.winlink.org", 80, - "/sysop/add", Message, Len, NULL); - - closesocket(sock); - - Bufferptr = Cmdprintf(Session, Bufferptr, "Database Updated\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - if (Exists) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "\rWL2K SYSOP Info for %s\r", WL2KCall); - Bufferptr = Cmdprintf(Session, Bufferptr, "Grid Square: %s\r", LOC); - Bufferptr = Cmdprintf(Session, Bufferptr, "Name: %s\r", Name); - Bufferptr = Cmdprintf(Session, Bufferptr, "Addr Line 1: %s\r", Addr1); - Bufferptr = Cmdprintf(Session, Bufferptr, "Addr Line 2: %s\r", Addr2); - Bufferptr = Cmdprintf(Session, Bufferptr, "City: %s\r", City); - Bufferptr = Cmdprintf(Session, Bufferptr, "State: %s\r", State); - Bufferptr = Cmdprintf(Session, Bufferptr, "Country: %s\r", Country); - Bufferptr = Cmdprintf(Session, Bufferptr, "PostCode: %s\r", PostCode); - Bufferptr = Cmdprintf(Session, Bufferptr, "Email Address: %s\r", Email); - Bufferptr = Cmdprintf(Session, Bufferptr, "Website: %s\r", Website); - Bufferptr = Cmdprintf(Session, Bufferptr, "Phone: %s\r", Phone); - Bufferptr = Cmdprintf(Session, Bufferptr, "Additional Data: %s\r", Data); - Bufferptr = Cmdprintf(Session, Bufferptr, "Last Updated: %s\r", LastUpdated); - } - else - Bufferptr = Cmdprintf(Session, Bufferptr, "No SYSOP record for %s\r", WL2KCall); - - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; -} - -VOID CloseKISSPort(struct PORTCONTROL * PortVector); -int OpenConnection(struct PORTCONTROL * PortVector); - -VOID STOPCMS(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - char _REPLYBUFFER[1000] = ""; - char * ptr, * Context; - - int portno; - - struct TNCINFO * TNC; - struct TCPINFO * TCP; - struct PORTCONTROL * PORT = PORTTABLE; - int n = NUMBEROFPORTS; - - // Get port number - - ptr = strtok_s(CmdTail, " ", &Context); - - if (ptr) - { - portno = atoi (ptr); - - if (portno) - { - while (n--) - { - if (PORT->PORTNUMBER == portno) - { - TNC = TNCInfo[portno]; - - if (!TNC || !TNC->TCPInfo) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Not a Telnet Port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - TCP = TNC->TCPInfo; - - TCP->CMS = 0; - TCP->CMSOK = FALSE; -#ifndef LINBPQ - CheckMenuItem(TCP->hActionMenu, 3, MF_BYPOSITION | TCP->CMS<<3); - SetWindowText(TCP->hCMSWnd, "CMS Off"); -#endif - Bufferptr = Cmdprintf(Session, Bufferptr, "CMS Server Disabled\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - PORT = PORT->PORTPOINTER; - } - } - } - - // Bad port - - strcpy(Bufferptr, BADPORT); - Bufferptr += (int)strlen(BADPORT); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; -} - - -VOID STARTCMS(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - char _REPLYBUFFER[1000] = ""; - char * ptr, * Context; - - int portno; - - struct TNCINFO * TNC; - struct TCPINFO * TCP; - struct PORTCONTROL * PORT = PORTTABLE; - int n = NUMBEROFPORTS; - - // Get port number - - ptr = strtok_s(CmdTail, " ", &Context); - - if (ptr) - { - portno = atoi (ptr); - - if (portno) - { - while (n--) - { - if (PORT->PORTNUMBER == portno) - { - TNC = TNCInfo[portno]; - - if (!TNC || !TNC->TCPInfo) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Not a Telnet Port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - TCP = TNC->TCPInfo; - TCP->CMS = 1; -#ifndef LINBPQ - CheckMenuItem(TCP->hActionMenu, 3, MF_BYPOSITION | TCP->CMS<<3); -#endif - CheckCMS(TNC); - - Bufferptr = Cmdprintf(Session, Bufferptr, "CMS Server Enabled\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - PORT = PORT->PORTPOINTER; - } - } - } - - // Bad port - - strcpy(Bufferptr, BADPORT); - Bufferptr += (int)strlen(BADPORT); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; -} - - -VOID STOPPORT(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - char _REPLYBUFFER[1000] = ""; - char * ptr, * Context; - - int portno; - struct PORTCONTROL * PORT = PORTTABLE; - int n = NUMBEROFPORTS; - - // Get port number - - ptr = strtok_s(CmdTail, " ", &Context); - - if (ptr) - { - portno = atoi (ptr); - - if (portno) - { - while (n--) - { - if (PORT->PORTNUMBER == portno) - { - struct KISSINFO * KISS; - - if (PORT->PORTSTOPCODE) - { - // Port has Close Routine - - PORT->PortStopped = TRUE; - - if (PORT->PORTSTOPCODE(PORT)) - Bufferptr = Cmdprintf(Session, Bufferptr, "Port Closed\r"); - else - Bufferptr = Cmdprintf(Session, Bufferptr, "Port Close Failed\r"); - - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - if (PORT->PORTTYPE != 0) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Not a KISS Port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - if (PORT->PORTIPADDR.s_addr || PORT->KISSSLAVE) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Not a serial port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - KISS = (struct KISSINFO *) PORT; - - if (KISS->FIRSTPORT != KISS) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Not first port of a Multidrop Set\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - CloseKISSPort(PORT); - PORT->PortStopped = TRUE; - Bufferptr = Cmdprintf(Session, Bufferptr, "Port Closed\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - - return; - } - PORT = PORT->PORTPOINTER; - } - } - } - - // Bad port - - strcpy(Bufferptr, BADPORT); - Bufferptr += (int)strlen(BADPORT); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; -} - - -VOID STARTPORT(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - char _REPLYBUFFER[1000] = ""; - char * ptr, * Context; - - int portno; - struct PORTCONTROL * PORT = PORTTABLE; - int n = NUMBEROFPORTS; - - // Get port number - - ptr = strtok_s(CmdTail, " ", &Context); - - if (ptr) - { - portno = atoi (ptr); - - if (portno) - { - while (n--) - { - if (PORT->PORTNUMBER == portno) - { - struct KISSINFO * KISS; - - if (PORT->PORTSTARTCODE) - { - // Port has Open Routine - - PORT->PortStopped = FALSE; - - if (PORT->PORTSTARTCODE(PORT)) - Bufferptr = Cmdprintf(Session, Bufferptr, "Port Opened\r"); - else - Bufferptr = Cmdprintf(Session, Bufferptr, "Port Open Failed\r"); - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - - if (PORT->PORTTYPE != 0) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Not a KISS Port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - if (PORT->PORTIPADDR.s_addr || PORT->KISSSLAVE) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Not a serial port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - KISS = (struct KISSINFO *) PORT; - - if (KISS->FIRSTPORT != KISS) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Not first port of a Multidrop Set\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - if (OpenConnection(PORT), TRUE) - Bufferptr = Cmdprintf(Session, Bufferptr, "Port Opened\r"); - else - Bufferptr = Cmdprintf(Session, Bufferptr, "Port Open Failed\r"); - - PORT->PortStopped = FALSE; - - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - PORT = PORT->PORTPOINTER; - } - } - } - - // Bad port - - strcpy(Bufferptr, BADPORT); - Bufferptr += (int)strlen(BADPORT); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; -} - - - -#define FEND 0xC0 -int ASYSEND(struct PORTCONTROL * PortVector, char * buffer, int count); - - -VOID KISSCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - char _REPLYBUFFER[1000] = ""; - char * ptr, * Context; - - int portno = 0; - int cmd = 0, val = 0; - struct PORTCONTROL * PORT = PORTTABLE; - int n = NUMBEROFPORTS; - - // Send KISS Command to TNC - - // Get port number - - ptr = strtok_s(CmdTail, " ", &Context); - - if (ptr) - { - portno = atoi (ptr); - ptr = strtok_s(NULL, " ", &Context); - - if (ptr) - { - cmd = atoi (ptr); - ptr = strtok_s(NULL, " ", &Context); - - if (ptr) - val = atoi (ptr); - } - } - - if (portno == 0 || cmd == 0) - { - strcpy(Bufferptr, BADMSG); - Bufferptr += (int)strlen(BADMSG); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - while (n--) - { - if (PORT->PORTNUMBER == portno) - { - struct KISSINFO * KISS; - UCHAR ENCBUFF[16]; - unsigned char * ptr = ENCBUFF; - - if (PORT->PORTTYPE != 0 && PORT->PORTTYPE != 22) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Not a KISS Port\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - KISS = (struct KISSINFO *) PORT; - - if (KISS->FIRSTPORT != KISS) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "Not first port of a Multidrop Set\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - - // Send Command - - *(ptr++) = FEND; - *(ptr++) = KISS->OURCTRL | cmd; - *(ptr++) = (UCHAR)val; - *(ptr++) = FEND; - - PORT = (struct PORTCONTROL *)KISS->FIRSTPORT; // ALL FRAMES GO ON SAME Q - - PORT->Session = Session; - PORT->LastKISSCmdTime = time(NULL); - - ASYSEND(PORT, ENCBUFF, 4); - - Bufferptr = Cmdprintf(Session, Bufferptr, "Command Sent\r"); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; - } - PORT = PORT->PORTPOINTER; - } - - - // Bad port - - strcpy(Bufferptr, BADPORT); - Bufferptr += (int)strlen(BADPORT); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - return; -} - - -VOID FINDBUFFS(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - FindLostBuffers(); - -#ifdef WIN32 - Bufferptr = Cmdprintf(Session, Bufferptr, "Lost buffer info dumped to Debugview\r"); -#else - Bufferptr = Cmdprintf(Session, Bufferptr, "Lost buffer info dumped to syslog\r"); -#endif - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - -VOID FLMSG(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * UserCMD) -{ - // Telnet Connection from FLMSG - CLOSECURRENTSESSION(Session); // Kills any crosslink, plus local link - ReleaseBuffer((UINT *)REPLYBUFFER); -} - -BOOL CheckExcludeList(UCHAR * Call) -{ - UCHAR * ptr1 = ExcludeList; - - while (*ptr1) - { - if (memcmp(Call, ptr1, 6) == 0) - return FALSE; - - ptr1 += 7; - } - - return TRUE; -} - - -void ListExcludedCalls(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) -{ - - UCHAR * ptr = ExcludeList; - char Normcall[10] = ""; - UCHAR AXCall[8] = ""; - - if (*CmdTail == ' ') - goto DISPLIST; - - if (*CmdTail == 'Z') - { - // CLEAR LIST - - memset(ExcludeList, 0, 70); - goto DISPLIST; - } - - ConvToAX25(CmdTail, AXCall); - - if (strlen(ExcludeList) < 70) - strcat(ExcludeList, AXCall); - -DISPLIST: - - while (*ptr) - { - Normcall[ConvFromAX25(ptr, Normcall)] = 0; - Bufferptr = Cmdprintf(Session, Bufferptr, "%s ", Normcall); - ptr += 7; - } - - *(Bufferptr++) = '\r'; - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); -} - -BOOL isSYSOP(TRANSPORTENTRY * Session, char * Bufferptr) -{ - if (Session->PASSWORD != 0xFFFF) - { - Bufferptr = Cmdprintf(Session, Bufferptr, "%s", PASSWORDMSG); - SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); - - return FALSE; - } - - return TRUE; -} - - - - - - - diff --git a/Cmd.c b/Cmd.c index 44bf503..1e2955c 100644 --- a/Cmd.c +++ b/Cmd.c @@ -3676,6 +3676,13 @@ VOID MHCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CM ptr = strtok_s(CmdTail, " ", &Context); + if (ptr == NULL || ptr[0] == 0) + { + Bufferptr = Cmdprintf(Session, Bufferptr, "Port Number needed eg MH 1\r"); + SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); + return; + } + if (ptr) Port = atoi(ptr); @@ -4137,7 +4144,7 @@ VOID ATTACHCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX if (OtherTNC == TNC) continue; - if (rxInterlock == OtherTNC->RXRadio || txInterlock == OtherTNC->TXRadio) // Same Group + if (rxInterlock && rxInterlock == OtherTNC->RXRadio || txInterlock && txInterlock == OtherTNC->TXRadio) // Same Group { int n; diff --git a/CommonCode.c b/CommonCode.c index 7060c77..6eeb7aa 100644 --- a/CommonCode.c +++ b/CommonCode.c @@ -68,7 +68,11 @@ VOID WriteMiniDump(); void printStack(void); char * FormatMH(PMHSTRUC MH, char Format); void WriteConnectLog(char * fromCall, char * toCall, UCHAR * Mode); +void SendDataToPktMap(char *Msg); + extern BOOL LogAllConnects; +extern BOOL M0LTEMap; + extern VOID * ENDBUFFERPOOL; @@ -2095,9 +2099,28 @@ DllExport struct PORTCONTROL * APIENTRY GetPortTableEntryFromSlot(int portslot) return PORTVEC; } +int CanPortDigi(int Port) +{ + struct PORTCONTROL * PORTVEC = GetPortTableEntryFromPortNum(Port); + struct TNCINFO * TNC; + + if (PORTVEC == NULL) + return FALSE; + + TNC = PORTVEC->TNC; + + if (TNC == NULL) + return TRUE; + + if (TNC->Hardware == H_SCS || TNC->Hardware == H_TRK || TNC->Hardware == H_TRKM || TNC->Hardware == H_WINRPR) + return FALSE; + + return TRUE; +} + struct PORTCONTROL * APIENTRY GetPortTableEntryFromPortNum(int portnum) { - struct PORTCONTROL * PORTVEC=PORTTABLE; + struct PORTCONTROL * PORTVEC = PORTTABLE; do { @@ -2337,6 +2360,13 @@ BOOL WriteCOMBlock(HANDLE fd, char * Block, int BytesToWrite) DWORD BytesWritten; DWORD ErrorFlags; COMSTAT ComStat; + DWORD Mask = 0; + int Err; + + Err = GetCommModemStatus(fd, &Mask); + + if ((Mask & MS_CTS_ON) == 0) // trap com0com other end not open + return TRUE; fWriteStat = WriteFile(fd, Block, BytesToWrite, &BytesWritten, NULL ); @@ -3302,6 +3332,9 @@ VOID SendLocation() SendReportMsg((char *)&AXMSG.DEST, Len + 16); + if (M0LTEMap) + SendDataToPktMap(""); + return; } @@ -4088,10 +4121,10 @@ VOID SaveUIConfig() config_destroy(&cfg); } +int GetRegConfig(); + VOID GetUIConfig() { -#ifdef LINBPQ - char Key[100]; char CfgFN[256]; char Digis[100]; @@ -4118,7 +4151,13 @@ VOID GetUIConfig() if (stat(CfgFN, &STAT) == -1) { + // No file. If Windows try to read from registy + +#ifndef LINBPQ + GetRegConfig(); +#else Debugprintf("UIUtil Config File not found\n"); +#endif return; } @@ -4158,8 +4197,42 @@ VOID GetUIConfig() } } -#else + _beginthread(UIThread, 0, NULL); + +} + +#ifndef LINBPQ + +int GetIntValue(config_setting_t * group, char * name) +{ + config_setting_t *setting; + + setting = config_setting_get_member (group, name); + if (setting) + return config_setting_get_int (setting); + + return 0; +} + +BOOL GetStringValue(config_setting_t * group, char * name, char * value) +{ + const char * str; + config_setting_t *setting; + + setting = config_setting_get_member (group, name); + if (setting) + { + str = config_setting_get_string (setting); + strcpy(value, str); + return TRUE; + } + value[0] = 0; + return FALSE; +} + +int GetRegConfig() +{ int retCode, Vallen, Type, i; char Key[80]; char Size[80]; @@ -4234,14 +4307,9 @@ VOID GetUIConfig() SaveUIConfig(); -#endif - - _beginthread(UIThread, 0, NULL); - + return TRUE; } -#ifndef LINBPQ - INT_PTR CALLBACK ChildDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { // This processes messages from controls on the tab subpages @@ -4749,6 +4817,540 @@ void GetPortCTEXT(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CM Debugprintf("CTEXT Read for ports %s\r", &PortList[1]); } +SOCKET OpenHTTPSock(char * Host) +{ + SOCKET sock = 0; + struct sockaddr_in destaddr; + struct sockaddr_in sinx; + int addrlen=sizeof(sinx); + struct hostent * HostEnt; + int err; + u_long param=1; + BOOL bcopt=TRUE; + + destaddr.sin_family = AF_INET; + destaddr.sin_port = htons(80); + + // Resolve name to address + + HostEnt = gethostbyname (Host); + + if (!HostEnt) + { + err = WSAGetLastError(); + + Debugprintf("Resolve Failed for %s %d %x", "api.winlink.org", err, err); + return 0 ; // Resolve failed + } + + memcpy(&destaddr.sin_addr.s_addr,HostEnt->h_addr,4); + + // Allocate a Socket entry + + sock = socket(AF_INET,SOCK_STREAM,0); + + if (sock == INVALID_SOCKET) + return 0; + + setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, (const char FAR *)&bcopt,4); + + sinx.sin_family = AF_INET; + sinx.sin_addr.s_addr = INADDR_ANY; + sinx.sin_port = 0; + + if (bind(sock, (struct sockaddr *) &sinx, addrlen) != 0 ) + return FALSE; + + if (connect(sock,(struct sockaddr *) &destaddr, sizeof(destaddr)) != 0) + { + err=WSAGetLastError(); + closesocket(sock); + return 0; + } + + return sock; +} + +static char HeaderTemplate[] = "POST %s HTTP/1.1\r\n" + "Accept: application/json\r\n" +// "Accept-Encoding: gzip,deflate,gzip, deflate\r\n" + "Content-Type: application/json\r\n" + "Host: %s:%d\r\n" + "Content-Length: %d\r\n" + //r\nUser-Agent: BPQ32(G8BPQ)\r\n" +// "Expect: 100-continue\r\n" + "\r\n"; + + +VOID SendWebRequest(SOCKET sock, char * Host, char * Request, char * Params, int Len, char * Return) +{ + int InputLen = 0; + int inptr = 0; + char Buffer[4096]; + char Header[256]; + char * ptr, * ptr1; + int Sent; + + sprintf(Header, HeaderTemplate, Request, Host, 80, Len, Params); + Sent = send(sock, Header, (int)strlen(Header), 0); + Sent = send(sock, Params, (int)strlen(Params), 0); + + if (Sent == -1) + { + int Err = WSAGetLastError(); + Debugprintf("Error %d from Web Update send()", Err); + return; + } + + while (InputLen != -1) + { + InputLen = recv(sock, &Buffer[inptr], 4096 - inptr, 0); + + if (InputLen == -1 || InputLen == 0) + { + int Err = WSAGetLastError(); + Debugprintf("Error %d from Web Update recv()", Err); + return; + } + + // As we are using a persistant connection, can't look for close. Check + // for complete message + + inptr += InputLen; + + Buffer[inptr] = 0; + + ptr = strstr(Buffer, "\r\n\r\n"); + + if (ptr) + { + // got header + + int Hddrlen = (int)(ptr - Buffer); + + ptr1 = strstr(Buffer, "Content-Length:"); + + if (ptr1) + { + // Have content length + + int ContentLen = atoi(ptr1 + 16); + + if (ContentLen + Hddrlen + 4 == inptr) + { + // got whole response + + if (strstr(Buffer, " 200 OK")) + { + if (Return) + { + memcpy(Return, ptr + 4, ContentLen); + Return[ContentLen] = 0; + } + else + Debugprintf("Map Database update ok"); + + } + else + { + strlop(Buffer, 13); + Debugprintf("Map Update Params - %s", Params); + Debugprintf("Map Update failed - %s", Buffer); + } + return; + } + } + else + { + ptr1 = strstr(_strlwr(Buffer), "transfer-encoding:"); + + if (ptr1) + { + // Just accept anything until I've sorted things with Lee + Debugprintf("%s", ptr1); + Debugprintf("Web Database update ok"); + return; + } + } + } + } +} + +// https://packetnodes.spots.radio/api/NodeData/{callsign} + +//SendHTTPRequest(sock, "/account/exists", Message, Len, Response); + +#include "kiss.h" + +extern char MYALIASLOPPED[10]; +extern int MasterPort[MAXBPQPORTS+1]; + +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; + int Baud; + int Bitrate; + char * Mode; + char * Use; + char * Type; + char * Modulation; + + char locked[] = " ! "; + int Percent = 0; + int Port = 0; + char Normcall[10]; + char Copy[20]; + + char * ptr = Params; + + printf("Sending to new map\n"); + + sprintf(Request, "/api/NodeData/%s", MYNODECALL); + +// https://packetnodes.spots.radio/swagger/index.html + + // This builds the request and sends it + + // Minimum header seems to be + + // "nodeAlias": "BPQ", + // "location": {"locator": "IO68VL"}, + // "software": {"name": "BPQ32","version": "6.0.24.3"}, + + ptr += sprintf(ptr, "{\"nodeAlias\": \"%s\",\r\n", MYALIASLOPPED); + + if (strlen(LOCATOR) == 6) + ptr += sprintf(ptr, "\"location\": {\"locator\": \"%s\"},\r\n", LOCATOR); + else + { + // Lat Lon + + double myLat, myLon; + char LocCopy[80]; + char * context; + + strcpy(LocCopy, LOCATOR); + + myLat = atof(strtok_s(LocCopy, ",:; ", &context)); + myLon = atof(context); + + ptr += sprintf(ptr, "\"location\": {\"coords\": {\"lat\": %f, \"lon\": %f}},\r\n", + myLat, myLon); + + } + +#ifdef LINBPQ + ptr += sprintf(ptr, "\"software\": {\"name\": \"LINBPQ\",\"version\": \"%s\"},\r\n", VersionString); +#else + ptr += sprintf(ptr, "\"software\": {\"name\": \"BPQ32\",\"version\": \"%s\"},\r\n", VersionString); +#endif + ptr += sprintf(ptr, "\"source\": \"ReportedByNode\",\r\n"); + + //Ports + + ptr += sprintf(ptr, "\"ports\": ["); + + // Get active ports + + while (PORT) + { + PortNo = PORT->PORTNUMBER; + + if (PORT->Hide) + { + PORT = PORT->PORTPOINTER; + continue; + } + + if (PORT->SendtoM0LTEMap == 0) + { + PORT = PORT->PORTPOINTER; + continue; + } + + // Try to get port status - may not be possible with some + + if (PORT->PortStopped) + { + PORT = PORT->PORTPOINTER; + continue; + } + + Active = 0; + Freq = 0; + Baud = 0; + Mode = "ax.25"; + Use = ""; + Type = "RF"; + Bitrate = 0; + Modulation = "FSK"; + + if (PORT->PORTTYPE == 0) + { + struct KISSINFO * KISS = (struct KISSINFO *)PORT; + NPASYINFO Port; + + SAVEPORT = PORT; + + if (KISS->FIRSTPORT && KISS->FIRSTPORT != KISS) + { + // Not first port on device + + PORT = (struct PORTCONTROL *)KISS->FIRSTPORT; + Port = KISSInfo[PortNo]; + } + + Port = KISSInfo[PORT->PORTNUMBER]; + + if (Port) + { + // KISS like - see if connected + + if (PORT->PORTIPADDR.s_addr || PORT->KISSSLAVE) + { + // KISS over UDP or TCP + + if (PORT->KISSTCP) + { + if (Port->Connected) + Active = 1; + } + else + Active = 1; // UDP - Cant tell + } + else + if (Port->idComDev) // Serial port Open + Active = 1; + + PORT = SAVEPORT; + } + } + else if (PORT->PORTTYPE == 14) // Loopback + Active = 0; + + else if (PORT->PORTTYPE == 16) // External + { + if (PORT->PROTOCOL == 10) // 'HF' Port + { + struct TNCINFO * TNC = TNCInfo[PortNo]; + struct AGWINFO * AGW; + + if (TNC == NULL) + { + PORT = PORT->PORTPOINTER; + continue; + } + + if (TNC->RIG) + Freq = TNC->RIG->RigFreq * 1000000; + + switch (TNC->Hardware) // Hardware Type + { + case H_KAM: + case H_AEA: + case H_HAL: + case H_SERIAL: + + // Serial + + if (TNC->hDevice) + Active = 1; + + break; + + case H_SCS: + case H_TRK: + case H_WINRPR: + + if (TNC->HostMode) + Active = 1; + + break; + + + case H_UZ7HO: + + if (TNCInfo[MasterPort[PortNo]]->CONNECTED) + Active = 1; + + // Try to get mode and frequency + + AGW = TNC->AGWInfo; + + if (AGW && AGW->isQTSM) + { + if (AGW->ModemName[0]) + { + char * ptr1, * ptr2, *Context; + + strcpy(Copy, AGW->ModemName); + ptr1 = strtok_s(Copy, " ", & Context); + ptr2 = strtok_s(NULL, " ", & Context); + + if (Context) + { + Modulation = Copy; + + if (strstr(ptr1, "BPSK") || strstr(ptr1, "AFSK")) + { + Baud = Bitrate = atoi(Context); + } + else if (strstr(ptr1, "QPSK")) + { + Modulation = "QPSK"; + Bitrate = atoi(Context); + Baud = Bitrate /2; + } + } + } + } + + 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_FREEDATA: + + // TCP + + Mode = Modenames[TNC->Hardware]; + + if (TNC->CONNECTED) + Active = 1; + + break; + + case H_TELNET: + + Active = 1; + Type = "Internet"; + Mode = ""; + } + } + else + { + // External but not HF - AXIP, BPQETHER VKISS, ?? + + struct _EXTPORTDATA * EXTPORT = (struct _EXTPORTDATA *)PORT; + Type = "Internet"; + Active = 1; + } + } + + if (Active) + { + 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); + } + + PORT = PORT->PORTPOINTER; + } + + ptr -= 3; + ptr += sprintf(ptr, "],\r\n"); + + // Neighbours + + ptr += sprintf(ptr, "\"neighbours\": [\r\n"); + + while (MaxRoutes--) + { + if (Routes->NEIGHBOUR_CALL[0] != 0) + if (Routes->NEIGHBOUR_LINK && Routes->NEIGHBOUR_LINK->L2STATE >= 5) + { + ConvFromAX25(Routes->NEIGHBOUR_CALL, Normcall); + strlop(Normcall, ' '); + + ptr += sprintf(ptr, + "{\"node\": \"%s\", \"port\": \"%d\", \"quality\": \"%d\"},\r\n", + Normcall, Routes->NEIGHBOUR_PORT, Routes->NEIGHBOUR_QUAL); + } + + Routes++; + } + + ptr -= 3; + ptr += sprintf(ptr, "]}"); + +/* +{ + "nodeAlias": "BPQ", + "location": {"locator": "IO92KX"}, + "software": {"name": "BPQ32","version": "6.0.24.11 Debug Build "}, + "contact": "G8BPQ", + "sysopComment": "Testing", + "source": "ReportedByNode" +} + + "ports": [ + { + "id": "string", + "linkType": "RF", + "freq": 0, + "mode": "string", + "modulation": "string", + "baud": 0, + "bitrate": 0, + "usage": "Access", + "comment": "string" + } + ], + + + +*/ + // "contact": "string", + // "neighbours": [{"node": "G7TAJ","port": "30"}] + + sock = OpenHTTPSock("packetnodes.spots.radio"); + + if (sock == 0) + return; + + SendWebRequest(sock, "packetnodes.spots.radio", Request, Params, strlen(Params), Return); + closesocket(sock); +} + +// ="{\"neighbours\": [{\"node\": \"G7TAJ\",\"port\": \"30\"}]}"; + +//'POST' \ +// 'https://packetnodes.spots.radio/api/NodeData/GM8BPQ' \ +// -H 'accept: */*' \ +// -H 'Content-Type: application/json' \ +// -d '{ +// "nodeAlias": "BPQ", +// "location": {"locator": "IO68VL"}, +// "software": {"name": "BPQ32","version": "6.0.24.3"}, +// "contact": "string", +// "neighbours": [{"node": "G7TAJ","port": "30"}] +//}' + + + + + diff --git a/FBBRoutines.c b/FBBRoutines.c index 2fae431..051afe6 100644 --- a/FBBRoutines.c +++ b/FBBRoutines.c @@ -472,7 +472,7 @@ ok: // Check Filters - if (CheckRejFilters(FBBHeader->From, FBBHeader->To, FBBHeader->ATBBS, FBBHeader->BID, FBBHeader->MsgType)) + if (CheckRejFilters(FBBHeader->From, FBBHeader->To, FBBHeader->ATBBS, FBBHeader->BID, FBBHeader->MsgType, FBBHeader->Size)) { memset(FBBHeader, 0, sizeof(struct FBBHeaderLine)); // Clear header conn->FBBReplyChars[conn->FBBReplyIndex++] = '-'; @@ -604,7 +604,7 @@ ok: char * To = strtok_s(NULL, seps, &Context); char * Type = strtok_s(NULL, seps, &Context); - if (From && To && ATBBS && Type && CheckRejFilters(From, To, ATBBS, NULL, *Type)) + if (From && To && ATBBS && Type && CheckRejFilters(From, To, ATBBS, NULL, *Type, FBBHeader->Size)) { memset(FBBHeader, 0, sizeof(struct FBBHeaderLine)); // Clear header conn->FBBReplyChars[conn->FBBReplyIndex++] = '-'; diff --git a/HALDriver.c.bak b/HALDriver.c.bak deleted file mode 100644 index 31e03cf..0000000 --- a/HALDriver.c.bak +++ /dev/null @@ -1,1903 +0,0 @@ -/* -Copyright 2001-2022 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 -*/ - -// -// DLL to inteface HAL Communications Corp Clover/Pacor controllers to BPQ32 switch -// -// Uses BPQ EXTERNAL interface -// - -#define _CRT_SECURE_NO_WARNINGS -#define _CRT_SECURE_NO_DEPRECATE - -#include "time.h" - -#include "CHeaders.h" -#include "tncinfo.h" - -#include "bpq32.h" - -#define HAL 1 - -#define SetMYCALL 0x13 -#define ConnectEnable 0x52 -#define ConnectDisable 0x42 -#define SetEAS 0x59 // Echo as Sent -#define SetTones 0xec -#define ClearOnDisc 0x57 - -static char ClassName[]="HALSTATUS"; - -static char WindowTitle[] = "HAL"; -static int RigControlRow = 185; - -#define SOH 0x01 // CONTROL CODES -#define ETB 0x17 -#define DLE 0x10 - -//int MaxStreams = 0; - -#ifndef LINBPQ -extern HFONT hFont; -#endif - -static char status[23][50] = {"IDLE", "TFC", "RQ", "ERR", "PHS", "OVER", "FSK TX", - "FSK RX", "P-MODE100", "P-MODE200", "HUFMAN ON", "HUFMAN OFF", "P-MODE SBY(LISTEN ON)", - "P-MODE SBY(LISTEN OFF)", "ISS", "IRS", - "AMTOR SBY(LISTEN ON)", "AMTOR SBY(LISTEN OFF)", "AMTOR FEC TX", "AMTOR FEC RX", "P-MODE FEC TX", - "FREE SIGNAL TX (AMTOR)", "FREE SIGNAL TX TIMED OUT (AMTOR)"}; - -struct TNCINFO * CreateTTYInfo(int port, int speed); -BOOL SetupConnection(int); -static BOOL WriteCommBlock(struct TNCINFO * TNC); -static void CheckRX(struct TNCINFO * TNC); -VOID HALPoll(int Port); -VOID ProcessDEDFrame(struct TNCINFO * TNC, UCHAR * rxbuff, int len); -VOID ProcessTermModeResponse(struct TNCINFO * TNC); -static VOID DoTNCReinit(struct TNCINFO * TNC); -VOID DoTermModeTimeout(struct TNCINFO * TNC); -VOID ProcessHALBuffer(struct TNCINFO * TNC, int Length); -VOID ProcessHALCmd(struct TNCINFO * TNC); -VOID ProcessHALData(struct TNCINFO * TNC); -VOID ProcessKHOSTPacket(struct TNCINFO * TNC, UCHAR * rxbuffer, int Len); -VOID ProcessKNormCommand(struct TNCINFO * TNC, UCHAR * rxbuffer); -VOID ProcessHostFrame(struct TNCINFO * TNC, UCHAR * rxbuffer, int Len); -VOID DoMonitor(struct TNCINFO * TNC, UCHAR * Msg, int Len); - -BOOL HALConnected(struct TNCINFO * TNC, char * Call); -VOID HALDisconnected(struct TNCINFO * TNC); - -static VOID EncodeAndSend(struct TNCINFO * TNC, UCHAR * txbuffer, int Len); -VOID SendCmd(struct TNCINFO * TNC, UCHAR * txbuffer, int Len); -int DLEEncode(UCHAR * inbuff, UCHAR * outbuff, int len); -int DLEDecode(UCHAR * inbuff, UCHAR * outbuff, int len); - -VOID COMClearDTR(HANDLE fd); -VOID COMClearRTS(HANDLE fd); -int DoScanLine(struct TNCINFO * TNC, char * Buff, int Len); - - - -//static HANDLE LogHandle[4] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}; - -//char * Logs[4] = {"1", "2", "3", "4"}; - -//char BaseDir[]="c:"; - -static VOID CloseLogfile(int Flags) -{ -// CloseHandle(LogHandle[Flags]); -// LogHandle[Flags] = INVALID_HANDLE_VALUE; -} - -static VOID OpenLogfile(int Flags) -{ -/* -UCHAR FN[MAX_PATH]; - time_t T; - struct tm * tm; - - T = time(NULL); - tm = gmtime(&T); - - sprintf(FN,"%s\\HALLog_%02d%02d%02d_%s.bin", BaseDir, tm->tm_mday, tm->tm_hour, tm->tm_min, Logs[Flags]); - - LogHandle[Flags] = CreateFile(FN, - GENERIC_WRITE, - FILE_SHARE_READ, - NULL, - OPEN_ALWAYS, - FILE_ATTRIBUTE_NORMAL, - NULL); - - SetFilePointer(LogHandle[Flags], 0, 0, FILE_END); - - return (LogHandle[Flags] != INVALID_HANDLE_VALUE); -*/ -} - -static void WriteLogLine(int Flags, char * Msg, int MsgLen) -{ -// int cnt; -// WriteFile(LogHandle[Flags] ,Msg , MsgLen, &cnt, NULL); -} - - - -int ProcessLine(char * buf, int Port) -{ - UCHAR * ptr,* p_cmd; - char * p_ipad = 0; - char * p_port = 0; - unsigned short WINMORport = 0; - int BPQport; - int len=510; - struct TNCINFO * TNC; - char errbuf[256]; - - strcpy(errbuf, buf); - - ptr = strtok(buf, " \t\n\r"); - - if(ptr == NULL) return (TRUE); - - if(*ptr =='#') return (TRUE); // comment - - if(*ptr ==';') return (TRUE); // comment - - ptr = strtok(NULL, " \t\n\r"); - - if (_stricmp(buf, "APPL") == 0) // Using BPQ32 COnfig - { - BPQport = Port; - p_cmd = ptr; - } - else - if (_stricmp(buf, "PORT") != 0) // Using Old Config - { - // New config without a PORT or APPL - this is a Config Command - - strcpy(buf, errbuf); - strcat(buf, "\r"); - - BPQport = Port; - - TNC = TNCInfo[BPQport] = zalloc(sizeof(struct TNCINFO)); - - TNC->InitScript = malloc(1000); - TNC->InitScript[0] = 0; - goto ConfigLine; - } - else - - { - - // Old Config from file - - BPQport=0; - BPQport = atoi(ptr); - - p_cmd = strtok(NULL, " \t\n\r"); - - if (Port && Port != BPQport) - { - // Want a particular port, and this isn't it - - while(TRUE) - { - if (GetLine(buf) == 0) - return TRUE; - - if (memcmp(buf, "****", 4) == 0) - return TRUE; - - } - } - } - if(BPQport > 0 && BPQport < 33) - { - TNC = TNCInfo[BPQport] = zalloc(sizeof(struct TNCINFO)); - TNC->InitScript = malloc(1000); - TNC->InitScript[0] = 0; - - if (p_cmd != NULL) - { - if (p_cmd[0] != ';' && p_cmd[0] != '#') - TNC->ApplCmd=_strdup(p_cmd); - } - - // Read Initialisation lines - - while(TRUE) - { - if (GetLine(buf) == 0) - return TRUE; -ConfigLine: - strcpy(errbuf, buf); - - if (memcmp(buf, "****", 4) == 0) - return TRUE; - - ptr = strchr(buf, ';'); - if (ptr) - { - *ptr++ = 13; - *ptr = 0; - } - - if (_memicmp(buf, "WL2KREPORT", 10) == 0) - { - TNC->WL2K = DecodeWL2KReportLine(buf); - continue; - } - if (_memicmp(buf, "NEEDXONXOFF", 10) == 0) - { - TNC->XONXOFF = TRUE; - continue; - } - - if (_memicmp(buf, "TONES", 5) == 0) - { - int tone1 = 0, tone2 = 0; - - ptr = strtok(&buf[6], " ,/\t\n\r"); - if (ptr) - { - tone1 = atoi(ptr); - ptr = strtok(NULL, " ,/\t\n\r"); - if (ptr) - { - tone2 = atoi(ptr); - ptr = &TNC->InitScript[TNC->InitScriptLen]; - - // Try putting into FSK mode first - - *(ptr++) = 0x84; - *(ptr++) = SetTones; // Set Tones (Mark, Space HI byte first) - *(ptr++) = tone1 >> 8; - *(ptr++) = tone1 & 0xff; - *(ptr++) = tone2 >> 8; - *(ptr++) = tone2 & 0xff; - - TNC->InitScriptLen += 6; - - continue; - } - } - goto BadLine; - } - if (_memicmp(buf, "DEFAULTMODE ", 12) == 0) - { - - ptr = strtok(&buf[12], " ,\t\n\r"); - if (ptr) - { - if (_stricmp(ptr, "CLOVER") == 0) - TNC->DefaultMode = Clover; - else if (_stricmp(ptr, "PACTOR") == 0) - TNC->DefaultMode = Pactor; - else if (_stricmp(ptr, "AMTOR") == 0) - TNC->DefaultMode = AMTOR; - else goto BadLine; - - continue; - } - goto BadLine; - } - } - BadLine: - WritetoConsole(" Bad config record "); - WritetoConsole(errbuf); - WritetoConsole("\r\n"); - } - - return (TRUE); -} - -static size_t ExtProc(int fn, int port,unsigned char * buff) -{ - int txlen = 0; - PMSGWITHLEN buffptr; - struct TNCINFO * TNC = TNCInfo[port]; - struct STREAMINFO * STREAM; - int Stream; - - if (TNC == NULL) - return 0; - - if (fn < 4 || fn > 5) - if (TNC->hDevice == 0) - return 0; // Port not open - - STREAM = &TNC->Streams[0]; - - switch (fn) - { - case 1: // poll - - while (TNC->PortRecord->UI_Q) // Release anything accidentally put on UI_Q - { - buffptr = Q_REM(&TNC->PortRecord->UI_Q); - ReleaseBuffer(buffptr); - } - - //for (Stream = 0; Stream <= MaxStreams; Stream++) - { - if (STREAM->ReportDISC) - { - STREAM->ReportDISC = FALSE; - buff[4] = 0; - - return -1; - } - } - - CheckRX(TNC); - HALPoll(port); - - //for (Stream = 0; Stream <= MaxStreams; Stream++) - { - if (STREAM->PACTORtoBPQ_Q !=0) - { - int datalen; - - buffptr=Q_REM(&STREAM->PACTORtoBPQ_Q); - - datalen=buffptr->Len; - - buff[4] = 0; - buff[7] = 0xf0; - memcpy(&buff[8],buffptr->Data,datalen); // Data goes to +7, but we have an extra byte - datalen+=8; - - PutLengthinBuffer((PDATAMESSAGE)buff, datalen); - - // buff[5]=(datalen & 0xff); - // buff[6]=(datalen >> 8); - - ReleaseBuffer(buffptr); - - return (1); - } - } - - return 0; - - case 2: // send - - buffptr = GetBuff(); - - if (buffptr == 0) return (0); // No buffers, so ignore - - // Find TNC Record - - Stream = buff[4]; - - if (!TNC->TNCOK) - { - // Send Error Response - - buffptr->Len = 36; - memcpy(buffptr->Data, "No Connection to PACTOR TNC\r", 36); - - C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr); - - return 0; - } - - txlen = GetLengthfromBuffer((PDATAMESSAGE)buff) - 8; - - buffptr->Len = txlen; - memcpy(buffptr->Data, &buff[8], txlen); - - C_Q_ADD(&STREAM->BPQtoPACTOR_Q, buffptr); - - STREAM->FramesQueued++; - - return (0); - - - case 3: // CHECK IF OK TO SEND. Also used to check if TNC is responding - - Stream = (int)buff; - - if (STREAM->FramesQueued > 4) - return (1 | TNC->HostMode << 8); - - return TNC->HostMode << 8 | STREAM->Disconnecting << 15; // OK, but lock attach if disconnecting - - case 4: // reinit - - return (0); - - case 5: // Close - - CloseCOMPort(TNCInfo[port]->hDevice); - return (0); - - case 6: // Scan Control - - return 0; // None Yet - - } - return 0; - -} - -static int WebProc(struct TNCINFO * TNC, char * Buff, BOOL LOCAL) -{ - int Len = sprintf(Buff, "" - "HAL Status

HAL Status

"); - - Len += sprintf(&Buff[Len], ""); - - Len += sprintf(&Buff[Len], "", TNC->WEB_COMMSSTATE); - Len += sprintf(&Buff[Len], "", TNC->WEB_TNCSTATE); - Len += sprintf(&Buff[Len], "", TNC->WEB_MODE); - Len += sprintf(&Buff[Len], "", TNC->WEB_STATE); - Len += sprintf(&Buff[Len], "", TNC->WEB_TXRX); - Len += sprintf(&Buff[Len], "", TNC->WEB_TRAFFIC); - Len += sprintf(&Buff[Len], ""); - Len += sprintf(&Buff[Len], "", TNC->WEB_LEDS); - Len += sprintf(&Buff[Len], "
Comms State%s
TNC State%s
Mode%s
Status%s
TX/RX State%s
Traffic%s
LEDSSTBY CALL LINK ERROR TX RX
%s
"); - - Len = DoScanLine(TNC, Buff, Len); - - return Len; -} - - -UINT HALExtInit(EXTPORTDATA * PortEntry) -{ - char msg[500]; - struct TNCINFO * TNC; - int port; - char * ptr; - int len; - char Msg[80]; - HWND x; - - // - // Will be called once for each Pactor Port - // The COM port number is in IOBASE - // - - sprintf(msg,"HAL Driver %s", PortEntry->PORTCONTROL.SerialPortName); - WritetoConsole(msg); - - port=PortEntry->PORTCONTROL.PORTNUMBER; - - ReadConfigFile(port, ProcessLine); - TNC = TNCInfo[port]; - - if (TNC == NULL) - { - // Not defined in Config file - - sprintf(msg," ** Error - no info in BPQ32.cfg for this port"); - WritetoConsole(msg); - - return (int)ExtProc; - } - - TNC->Port = port; - - TNC->Hardware = H_HAL; - - if (PortEntry->PORTCONTROL.PORTINTERLOCK && TNC->RXRadio == 0 && TNC->TXRadio == 0) - TNC->RXRadio = TNC->TXRadio = PortEntry->PORTCONTROL.PORTINTERLOCK; - - PortEntry->MAXHOSTMODESESSIONS = 1; // Default - - TNC->PortRecord = PortEntry; - - if (PortEntry->PORTCONTROL.PORTCALL[0] == 0) - { - memcpy(TNC->NodeCall, MYNODECALL, 10); - } - else - { - ConvFromAX25(&PortEntry->PORTCONTROL.PORTCALL[0], TNC->NodeCall); - } - - PortEntry->PORTCONTROL.PROTOCOL = 10; - PortEntry->PORTCONTROL.PORTQUALITY = 0; - - if (PortEntry->PORTCONTROL.PORTPACLEN == 0) - PortEntry->PORTCONTROL.PORTPACLEN = 100; - - ptr=strchr(TNC->NodeCall, ' '); - if (ptr) *(ptr) = 0; // Null Terminate - - if (TNC->DefaultMode) - TNC->CurrentMode = TNC->DefaultMode; - else - TNC->CurrentMode = Clover; - - TNC->PollDelay = 999999999; - - // Set Disable +?, ExpandedStatus , Channel Stats Off, ClearOnDisc, EAS and MYCALL - - len = sprintf(Msg, "%c%c%c%c%c%c%s", 0xcc, 0x56, 0x41, ClearOnDisc, SetEAS, SetMYCALL, TNC->NodeCall); - len++; // We include the NULL - - memcpy(&TNC->InitScript[TNC->InitScriptLen], Msg, len); - TNC->InitScriptLen += len; - - PortEntry->PORTCONTROL.TNC = TNC; - - TNC->WebWindowProc = WebProc; - TNC->WebWinX = 510; - TNC->WebWinY = 280; - - TNC->WEB_COMMSSTATE = zalloc(100); - TNC->WEB_TNCSTATE = zalloc(100); - strcpy(TNC->WEB_TNCSTATE, "Free"); - TNC->WEB_MODE = zalloc(100); - TNC->WEB_TRAFFIC = zalloc(100); - TNC->WEB_BUFFERS = zalloc(100); - TNC->WEB_STATE = zalloc(100); - TNC->WEB_TXRX = zalloc(100); - TNC->WEB_LEDS = zalloc(100); - strcpy(TNC->WEB_LEDS, " X X X X X X"); - -#ifndef LINBPQ - - CreatePactorWindow(TNC, ClassName, WindowTitle, RigControlRow, PacWndProc, 500, 233, ForcedClose); - - x = CreateWindowEx(0, "STATIC", "Comms State", WS_CHILD | WS_VISIBLE, 10,6,120,20, TNC->hDlg, NULL, hInstance, NULL); - x = TNC->xIDC_COMMSSTATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,6,386,20, TNC->hDlg, NULL, hInstance, NULL); - - x = CreateWindowEx(0, "STATIC", "TNC State", WS_CHILD | WS_VISIBLE, 10,28,106,20, TNC->hDlg, NULL, hInstance, NULL); - x = TNC->xIDC_TNCSTATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,28,520,20, TNC->hDlg, NULL, hInstance, NULL); - - x = CreateWindowEx(0, "STATIC", "Mode", WS_CHILD | WS_VISIBLE, 10,50,80,20, TNC->hDlg, NULL, hInstance, NULL); - x = TNC->xIDC_MODE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,50,200,20, TNC->hDlg, NULL, hInstance, NULL); - - x = CreateWindowEx(0, "STATIC", "Status", WS_CHILD | WS_VISIBLE, 10,72,110,20, TNC->hDlg, NULL, hInstance, NULL); - x = TNC->xIDC_STATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,72,144,20, TNC->hDlg, NULL, hInstance, NULL); - - x = CreateWindowEx(0, "STATIC", "TX/RX State", WS_CHILD | WS_VISIBLE,10,94,80,20, TNC->hDlg, NULL, hInstance, NULL); - x = TNC->xIDC_TXRX = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE,116,94,374,20 , TNC->hDlg, NULL, hInstance, NULL); - - x = CreateWindowEx(0, "STATIC", "Traffic", WS_CHILD | WS_VISIBLE,10,116,80,20, TNC->hDlg, NULL, hInstance, NULL); - x = TNC->xIDC_TRAFFIC = CreateWindowEx(0, "STATIC", "RX 0 TX 0 ACKED 0", WS_CHILD | WS_VISIBLE,116,116,374,20 , TNC->hDlg, NULL, hInstance, NULL); - - x = CreateWindowEx(0, "STATIC", "LEDS", WS_CHILD | WS_VISIBLE,10,138,60,20, TNC->hDlg, NULL, hInstance, NULL); - SendMessage(x, WM_SETFONT, (WPARAM)hFont, 0); - x = CreateWindowEx(0, "STATIC", "STBY CALL LINK ERROR TX RX", WS_CHILD | WS_VISIBLE,116,138,280,20, TNC->hDlg, NULL, hInstance, NULL); - SendMessage(x, WM_SETFONT, (WPARAM)hFont, 0); - x = TNC->xIDC_LEDS = CreateWindowEx(0, "STATIC", " X X X X X X", WS_CHILD | WS_VISIBLE,116,158,280,20 , TNC->hDlg, NULL, hInstance, NULL); - SendMessage(x, WM_SETFONT, (WPARAM)hFont, 0); - - TNC->ClientHeight = 233; - TNC->ClientWidth = 500; - - MoveWindows(TNC); -#endif - - OpenCOMMPort(TNC, PortEntry->PORTCONTROL.SerialPortName, PortEntry->PORTCONTROL.BAUDRATE, FALSE); - - SendCmd(TNC, "\x09" , 1); // Reset - - WritetoConsole("\n"); - - return ((int)ExtProc); -} - - - -static VOID KISSCLOSE(int Port) -{ - struct TNCINFO * conn = TNCInfo[Port]; - - // drop DTR and RTS - - COMClearDTR(conn->hDevice); - COMClearRTS(conn->hDevice); - - // purge any outstanding reads/writes and close device handle - - CloseCOMPort(conn->hDevice); - - return; -} - - -static void CheckRX(struct TNCINFO * TNC) -{ - int Length, Len; - UCHAR * Xptr; - - // only try to read number of bytes in queue - - if (TNC->RXLen == 500) - TNC->RXLen = 0; - - Len = ReadCOMBlock(TNC->hDevice, &TNC->RXBuffer[TNC->RXLen], 500 - TNC->RXLen); - - if (Len == 0) - return; - - TNC->RXLen += Len; - - Length = TNC->RXLen; - - // We need to konw whether data is received or echoed, so we can't split commands and data here. - // Pass everything to the Command Handler. It will check that there are enough bytes for the command, - // and wait for more if not. - - // The USB version also uses 0x91 0x31 to eacape 0x11, 0x91 0x33 for 0x13 and 0x91 0xB1 for 0x91 - - // If USB version, we might get unescaped xon and xoff, which we must ignore - - if (TNC->XONXOFF) - { - Xptr = memchr(&TNC->RXBuffer, 0x11, Length); - - while(Xptr) - { - Debugprintf("XON Port %d", TNC->Port); - memmove(Xptr, Xptr + 1, Length-- - (TNC->RXBuffer - Xptr)); - Xptr = memchr(&TNC->RXBuffer, 0x11, Length); - } - - Xptr = memchr(&TNC->RXBuffer, 0x13, Length); - - while(Xptr) - { - Debugprintf("XOFF Port %d", TNC->Port); - memmove(Xptr, Xptr + 1, Length-- - (TNC->RXBuffer - Xptr)); - Xptr = memchr(&TNC->RXBuffer, 0x13, Length); - } - - Xptr = memchr(&TNC->RXBuffer, 0x91, Length); // See if packet contains 0x91 escape - - if (Xptr) - - // Make sure we have the escaped char as well - - if ((Xptr - &TNC->RXBuffer[0]) == Length - 1) // x91 is last char - return; - } - - ProcessHALBuffer(TNC, Length); - - TNC->RXLen = 0; - - return; - -} - - - -static BOOL WriteCommBlock(struct TNCINFO * TNC) -{ - WriteCOMBlock(TNC->hDevice, TNC->TXBuffer, TNC->TXLen); - return TRUE; -} - -VOID HALPoll(int Port) -{ - struct TNCINFO * TNC = TNCInfo[Port]; - struct STREAMINFO * STREAM = &TNC->Streams[0]; - - UCHAR * Poll = TNC->TXBuffer; - char Status[80]; - UCHAR TXMsg[1000]; - int datalen; - - if (TNC->Timeout) - { - TNC->Timeout--; - - if (TNC->Timeout) // Still waiting - return; - - // Timed Out - - TNC->TNCOK = FALSE; - TNC->HostMode = 0; - - sprintf(TNC->WEB_COMMSSTATE,"%s Open but TNC not responding", TNC->PortRecord->PORTCONTROL.SerialPortName); - MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE); - - //for (Stream = 0; Stream <= MaxStreams; Stream++) - { - if (TNC->PortRecord->ATTACHEDSESSIONS[0]) // Connected - { - STREAM->Connected = FALSE; // Back to Command Mode - STREAM->ReportDISC = TRUE; // Tell Node - } - } - - } - - // if we have just restarted or TNC appears to be in terminal mode, run Initialisation Sequence - - if (TNC->TNCOK) - if (!TNC->HostMode) - { - DoTNCReinit(TNC); - return; - } - - if (TNC->PortRecord->ATTACHEDSESSIONS[0] && STREAM->Attached == 0) - { - // New Attach - - int calllen; - char Msg[80]; - - STREAM->Attached = TRUE; - - STREAM->BytesRXed = STREAM->BytesTXed = STREAM->BytesAcked = 0; - - calllen = ConvFromAX25(TNC->PortRecord->ATTACHEDSESSIONS[0]->L4USER, STREAM->MyCall); - STREAM->MyCall[calllen] = 0; - - datalen = sprintf(TXMsg, "%c%s", SetMYCALL, STREAM->MyCall); - SendCmd(TNC, TXMsg, datalen + 1); // Send the NULL - - sprintf(TNC->WEB_TNCSTATE, "In Use by %s", STREAM->MyCall); - MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE); - - // Stop Scanning - - sprintf(Msg, "%d SCANSTOP", TNC->Port); - - Rig_Command( (TRANSPORTENTRY *) -1, Msg); - - SendCmd(TNC, "\x42", 1); // Connect Enable off - - return; - - } - - //for (Stream = 0; Stream <= MaxStreams; Stream++) - - if (STREAM->Attached) - CheckForDetach(TNC, 0, STREAM, TidyClose, ForcedClose, CloseComplete); - - if (TNC->NeedPACTOR) - { - TNC->NeedPACTOR--; - - if (TNC->NeedPACTOR == 0) - { - int datalen; - - UCHAR TXMsg[80]; - - datalen = sprintf(TXMsg, "%c%s", SetMYCALL, TNC->NodeCall); - SendCmd(TNC, TXMsg, datalen + 1); // Send the NULL - - // Set Listen Mode - - switch (TNC->CurrentMode) - { - case Pactor: - - SendCmd(TNC, "\x84", 1); // FSK - SendCmd(TNC, "\x83", 1); // Select P-MODE Standby - SendCmd(TNC, "\x58", 1); // Listen - - break; - - case Clover: - - SendCmd(TNC, "\x80", 1); // Clover - SendCmd(TNC, "\x54", 1); // Enable adaptive Clover format - SendCmd(TNC, "\x41", 1); // No Statistics - SendCmd(TNC, "\x60\x09", 2); // Robust Retries - SendCmd(TNC, "\x61\x09", 2); // Normal Retries - - break; - } - - SendCmd(TNC, "\x52", 1); // ConnectEnable - - // Restart Scanning - - sprintf(Status, "%d SCANSTART 15", TNC->Port); - - Rig_Command( (TRANSPORTENTRY *) -1, Status); - - return; - } - } - -#define MAXHALTX 256 - - //for (Stream = 0; Stream <= MaxStreams; Stream++) - { - if (TNC->TNCOK && STREAM->BPQtoPACTOR_Q && (STREAM->BytesTXed - STREAM->BytesAcked < 600)) - { - int datalen; - PMSGWITHLEN buffptr; - UCHAR * MsgPtr; - unsigned char TXMsg[500]; - - buffptr = (PMSGWITHLEN)STREAM->BPQtoPACTOR_Q; - datalen = buffptr->Len; - MsgPtr = buffptr->Data; - - if (STREAM->Connected) - { - if (TNC->SwallowSignon) - { - TNC->SwallowSignon = FALSE; - if (strstr(MsgPtr, "Connected")) // Discard *** connected - { - ReleaseBuffer(buffptr); - STREAM->FramesQueued--; - return; - } - } - - // Must send data in small chunks - the Hal has limited buffer space - - // If in IRS force a turnround - - if (TNC->TXRXState == 'R' && TNC->CurrentMode != Clover) - { - if (TNC->TimeInRX++ > 15) - SendCmd(TNC, "\x87", 1); // Changeover to ISS - else - goto Poll; - } - - TNC->TimeInRX = 0; - - EncodeAndSend(TNC, MsgPtr, datalen); - buffptr=Q_REM(&STREAM->BPQtoPACTOR_Q); - ReleaseBuffer(buffptr); - WriteLogLine(2, MsgPtr, datalen); - - STREAM->BytesTXed += datalen; - STREAM->FramesQueued--; - - ShowTraffic(TNC); - - return; - } - else - { - buffptr=Q_REM(&STREAM->BPQtoPACTOR_Q); - STREAM->FramesQueued--; - - // Command. Do some sanity checking and look for things to process locally - - datalen--; // Exclude CR - MsgPtr[datalen] = 0; // Null Terminate - _strupr(MsgPtr); - - if (memcmp(MsgPtr, "RADIO ", 6) == 0) - { - sprintf(&MsgPtr[40], "%d %s", TNC->Port, &MsgPtr[6]); - if (Rig_Command(TNC->PortRecord->ATTACHEDSESSIONS[0]->L4CROSSLINK, &MsgPtr[40])) - { - ReleaseBuffer(buffptr); - } - else - { - buffptr->Len = sprintf((UCHAR *)buffptr->Data, "%s", &MsgPtr[40]); - C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr); - } - return; - } - - if (memcmp(MsgPtr, "MODE CLOVER", 11) == 0) - { - TNC->CurrentMode = Clover; - buffptr->Len = sprintf((UCHAR *)buffptr->Data,"HAL} Ok\r"); - C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr); - - MySetWindowText(TNC->xIDC_MODE, "Clover"); - strcpy(TNC->WEB_MODE, "Clover"); - - SendCmd(TNC, "\x80", 1); // Clover - SendCmd(TNC, "\x54", 1); // Enable adaptive Clover format - SendCmd(TNC, "\x41", 1); // No Statistics - - return; - } - - if (memcmp(MsgPtr, "MODE PACTOR", 11) == 0) - { - TNC->CurrentMode = Pactor; - buffptr->Len = sprintf((UCHAR *)buffptr->Data,"HAL} Ok\r"); - C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr); - - SendCmd(TNC, "\x84", 1); // FSK - SendCmd(TNC, "\x83", 1); // Select P-MODE Standby - SendCmd(TNC, "\x48", 1); // Listen Off - - return; - } - if (memcmp(MsgPtr, "MODE AMTOR", 11) == 0) - { - TNC->CurrentMode = AMTOR; - buffptr->Len = sprintf((UCHAR *)buffptr->Data,"HAL} Ok\r"); - C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr); - - return; - } - - if (MsgPtr[0] == 'C' && MsgPtr[1] == ' ' && datalen > 2) // Connect - { - memcpy(STREAM->RemoteCall, &MsgPtr[2], 9); - - switch (TNC->CurrentMode) - { - case Pactor: - - SendCmd(TNC, "\x84", 1); // FSK - SendCmd(TNC, "\x83", 1); // Select P-MODE Standby - - datalen = sprintf(TXMsg, "\x19%s", STREAM->RemoteCall); - - sprintf(TNC->WEB_TNCSTATE, "%s Connecting to %s - PACTOR", STREAM->MyCall, STREAM->RemoteCall); - - // DOnt set connecting till we get the 19 response so we can trap listen as a fail - break; - - case Clover: - - SendCmd(TNC, "\x54", 1); // Enable adaptive Clover format - SendCmd(TNC, "\x57", 1); // Enable TX buffer clear on disconnect - - datalen = sprintf(TXMsg, "\x11%s", STREAM->RemoteCall); - - sprintf(TNC->WEB_TNCSTATE, "%s Connecting to %s - CLOVER", STREAM->MyCall, STREAM->RemoteCall); - - break; - } - - MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE); - SendCmd(TNC, TXMsg, datalen + 1); // Include NULL - - ReleaseBuffer(buffptr); - - return; - } - - if (memcmp(MsgPtr, "CLOVER ", 7) == 0) - { - memcpy(STREAM->RemoteCall, &MsgPtr[2], 9); - - SendCmd(TNC, "\x54", 1); // Enable adaptive Clover format - SendCmd(TNC, "\x57", 1); // Enable TX buffer clear on disconnect - - datalen = sprintf(TXMsg, "\x11%s", STREAM->RemoteCall); - SendCmd(TNC, TXMsg, datalen + 1); // Include NULL - - sprintf(TNC->WEB_TNCSTATE, "%s Connecting to %s - CLOVER", - STREAM->MyCall, STREAM->RemoteCall); - MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE); - - ReleaseBuffer(buffptr); - - return; - } - - if (memcmp(MsgPtr, "DISCONNECT", datalen) == 0) // Disconnect - { - SendCmd(TNC, "\x07", 1); // Normal Disconnect - TNC->NeedPACTOR = 50; - - STREAM->Connecting = FALSE; - STREAM->ReportDISC = TRUE; - ReleaseBuffer(buffptr); - - return; - } - - // Other Command ?? Treat as HEX string - - datalen = sscanf(MsgPtr, "%X %X %X %X %X %X %X %X %X %X %X %X %X %X %X %X", - (UINT *)&TXMsg[0], (UINT *)&TXMsg[1], (UINT *)&TXMsg[2], (UINT *)&TXMsg[3], (UINT *)&TXMsg[4], - (UINT *)&TXMsg[5], (UINT *)&TXMsg[6], (UINT *)&TXMsg[7], (UINT *)&TXMsg[8], (UINT *)&TXMsg[9], - (UINT *)&TXMsg[10], (UINT *)&TXMsg[11], (UINT *)&TXMsg[12], (UINT *)&TXMsg[13], - (UINT *)&TXMsg[14], (UINT *)&TXMsg[15]); - -// SendCmd(TNC, TXMsg, datalen); - ReleaseBuffer(buffptr); - TNC->InternalCmd = 0; - } - } - } -Poll: - // Nothing doing - send Poll (but not too often) - - TNC->PollDelay++; - - if (TNC->PollDelay < 20) - return; - - TNC->PollDelay = 0; - - if (TNC->TNCOK) - SendCmd(TNC, "\x7d" , 1); // Use Get LEDS as Poll - else - SendCmd(TNC, "\x09" , 1); // Reset - - TNC->Timeout = 100; - - return; -} - -static VOID DoTNCReinit(struct TNCINFO * TNC) -{ - // TNC Has Restarted, send init commands (can probably send all at once) - -// TNC->TXBuffer[0] = 0x1b; -// TNC->TXLen = 1; - - WriteCommBlock(TNC); - - SendCmd(TNC, TNC->InitScript, TNC->InitScriptLen); - - TNC->HostMode = TRUE; // Should now be in Host Mode - TNC->NeedPACTOR = 20; // Need to set Calls and start scan - - TNC->DataMode = RXDATA; // Start with RX Data - - SendCmd(TNC, "\x7d" , 1); // Use Get LEDS as Poll -// SendCmd(TNC, "\xc9" , 1); // Huffman Off - SendCmd(TNC, "\x57", 1); // Enable TX buffer clear on disconnect - - SendCmd(TNC, "\x60\x06", 2); // Robust Mode Retries - -// SendCmd(TNC, "\x6f\x03" , 2); // Undocumented XON/XOFF On - used to see if old or new style modem - - TNC->Timeout = 50; - - return; - -} - -VOID ProcessHALData(struct TNCINFO * TNC) -{ - // Received Data just pass to Appl - - PMSGWITHLEN buffptr; - int Len = TNC->DataLen; - struct STREAMINFO * STREAM = &TNC->Streams[0]; - - TNC->DataLen = 0; - - if (TNC->DataMode == TXDATA) - { - STREAM->BytesAcked += Len; -// Debugprintf("Acked %d", Len); - - if (STREAM->BytesAcked > STREAM->BytesTXed) - Debugprintf("Too Much Acked"); - - if ((STREAM->BPQtoPACTOR_Q == 0) && STREAM->BytesAcked >= STREAM->BytesTXed) - { - // All sent - - if (STREAM->Disconnecting) - TidyClose(TNC, 0); - else - if (TNC->CurrentMode != Clover) - - // turn round link - - SendCmd(TNC, "\x0c" , 1); // Turnround - - } - } - else - { - if (TNC->DataMode == RXDATA) - { -// Debugprintf("RXed %d", Len); - buffptr = GetBuff(); - if (buffptr == NULL) - return; // No buffers, so ignore - - buffptr->Len = Len; // Length - - WriteLogLine(1, TNC->DataBuffer, Len); - - STREAM->BytesRXed += Len; - - memcpy(buffptr->Data, TNC->DataBuffer, Len); - - C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr); - } - } - - ShowTraffic(TNC); - - return; -} - - - -VOID ProcessHALBuffer(struct TNCINFO * TNC, int Length) -{ - UCHAR Char; - UCHAR * inptr; - UCHAR * cmdptr; - UCHAR * dataptr; - BOOL CmdEsc, DataEsc; - - inptr = TNC->RXBuffer; - - cmdptr = &TNC->CmdBuffer[TNC->CmdLen]; - dataptr = &TNC->DataBuffer[TNC->DataLen]; - CmdEsc = TNC->CmdEsc; - DataEsc = TNC->DataEsc; - - // HAL uses HEX 80 as a command escape, 81 to ESCAPE 80 and 81 - - // The USB version also uses 0x91 0x31 to eacape 0x11, 0x91 0x33 for 0x13 and 0x91 0xB1 for 0x91 - - // Command Responses can be variable length - - // Command Handler will check for each command/response if it has enough - if not it will wait till more arrives - - while(Length--) - { - Char = *(inptr++); - - if (CmdEsc) - { - CmdEsc = FALSE; - - if (TNC->XONXOFF && Char == 0x91) - { - // XON/XOFF escape. We ensured above that data follows so we can process it inline - - Length--; - Char = *(inptr++) - 0x20; - } - *(cmdptr++) = Char; - } - else if (DataEsc) - { - DataEsc = FALSE; - goto DataChar; - } - else -NotData: - if (Char == 0x80) // Next Char is Command - CmdEsc = TRUE; - else if (Char == 0x81) // Next Char is escaped data (80 or 81) - DataEsc = TRUE; - else - { - // This is a Data Char. We must process any Commands received so far, so we know the type of data - - DataChar: - - TNC->CmdLen = cmdptr - TNC->CmdBuffer; - ProcessHALCmd(TNC); - cmdptr = &TNC->CmdBuffer[TNC->CmdLen]; - dataptr = &TNC->DataBuffer[TNC->DataLen]; - - *(dataptr++) = Char; // Normal Data - - // Now process any other data chars - - while(Length--) - { - Char = *(inptr++); - - if (TNC->XONXOFF && Char == 0x91) - { - // XON/XOFF escape within data. We ensured above that data follows so we - // can process it here - - Length--; - Char = *(inptr++) - 0x20; - } - - if (Char == 0x80 || Char == 0x81) - { - // Process any data we have, then loop back - - TNC->DataLen = dataptr - TNC->DataBuffer; - ProcessHALData(TNC); - - goto NotData; - } - *(dataptr++) = Char; // Normal Data - } - - // Used all data - - TNC->DataLen = dataptr - TNC->DataBuffer; - - ProcessHALData(TNC); - TNC->CmdEsc = CmdEsc; - TNC->DataEsc = DataEsc; - - return; - } - } - - // Save State - - TNC->CmdLen = cmdptr - TNC->CmdBuffer; - - TNC->CmdEsc = CmdEsc; - TNC->DataEsc = DataEsc; - - if (TNC->DataLen) - ProcessHALData(TNC); - - if (TNC->CmdLen) - ProcessHALCmd(TNC); -} - -VOID mySetWindowText(struct TNCINFO * TNC, char * Msg) -{ - MySetWindowText(TNC->xIDC_STATE, Msg); - strcpy(TNC->WEB_STATE, Msg); -} - -VOID ProcessHALCmd(struct TNCINFO * TNC) -{ - char * Call; - int Stream = 0; - int Opcode; - int StatusByte; - int Leds; - int Len; - int Used; - struct STREAMINFO * STREAM = &TNC->Streams[0]; - -CmdLoop: - - Opcode = TNC->CmdBuffer[0]; - Len = TNC->CmdLen; - - if (Len == 0) - return; - - TNC->TNCOK = TRUE; - TNC->Timeout = 0; - - sprintf(TNC->WEB_COMMSSTATE,"%s TNC link OK", TNC->PortRecord->PORTCONTROL.SerialPortName); - MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE); - - // We may have more than one response in the buffer, and only each cmd/response decoder knows how many it needs - - switch(Opcode) - { - case 0x09: //Hardware Reset - equivalent to power on reset - - // Hardware has reset - need to reinitialise - - TNC->HostMode = 0; // Force Reinit - - Used = 1; - break; - - case 0x7a: // FSK Modes Status - - // Mixture of mode and state - eg listen huffman on/off irs/iss, so cant just display - - if (Len < 2) return; // Wait for more - - StatusByte = TNC->CmdBuffer[1]; - - switch (StatusByte) - { - case 0x06: // FSK TX (RTTY) - case 0x07: // FSK RX (RTTY) - case 0x10: // AMTOR STANDBY (LISTEN ON) - case 0x11: // AMTOR STANDBY (LISTEN OFF) - case 0x12: // AMTOR FEC TX (AMTOR) - case 0x13: // AMTOR FEC RX (AMTOR) - case 0x14: // P-MODE FEC TX (P-MODE) - case 0x15: // FREE SIGNAL TX (AMTOR) - case 0x16: // FREE SIGNAL TX TIMED OUT (AMTOR) - - // Diaplay Linke Status - - MySetWindowText(TNC->xIDC_MODE, status[StatusByte]); - strcpy(TNC->WEB_MODE, status[StatusByte]); - - break; - - case 0x0C: // P-MODE STANDBY (LISTEN ON) - case 0x0D: // P-MODE STANDBY (LISTEN OFF) - - // if we were connecting, this means connect failed. - - MySetWindowText(TNC->xIDC_MODE, status[StatusByte]); - strcpy(TNC->WEB_MODE, status[StatusByte]); - - if (STREAM->Connecting) - HALDisconnected(TNC); - - break; - - case 0x0E: // ISS (AMTOR/P-MODE) - - MySetWindowText(TNC->xIDC_TXRX,"ISS"); - strcpy(TNC->WEB_TXRX, "ISS"); - TNC->TXRXState = 'S'; - break; - - case 0x0F: // IRS (AMTOR/P-MODE) - - MySetWindowText(TNC->xIDC_TXRX,"IRS"); - strcpy(TNC->WEB_TXRX, "IRS"); - TNC->TXRXState = 'R'; - break; - - case 0x00: // IDLE (AMTOR/P-MODE) - case 0x01: // TFC (AMTOR/P-MODE) - case 0x02: // RQ (AMTOR/P-MODE) - case 0x03: // ERR (AMTOR/P-MODE) - case 0x04: // PHS (AMTOR/P-MODE) - case 0x05: // OVER (AMTOR/P-MODE) (not implemented) - - MySetWindowText(TNC->xIDC_STATE, status[StatusByte]); - strcpy(TNC->WEB_MODE, status[StatusByte]); - - - -//$807A $8008 P-MODE100 (P-MODE) -//$807A $8009 P-MODE200 (P-MODE) -//$807A $800A HUFFMAN ON (P-MODE) -//$807A $800B HUFFMAN OFF (P-MODE) - ; - } - Used = 2; - break; - - - case 0x7d: // Get LED Status - - // We use Get LED Status as a Poll - - if (Len < 2) return; // Wait for more - - Leds = TNC->CmdBuffer[1]; - sprintf(TNC->WEB_LEDS," %c %c %c %c %c %c ", - (Leds & 0x20)? 'X' : ' ', - (Leds & 0x10)? 'X' : ' ', - (Leds & 0x08)? 'X' : ' ', - (Leds & 0x04)? 'X' : ' ', - (Leds & 0x02)? 'X' : ' ', - (Leds & 0x01)? 'X' : ' '); - -// STBY CALL LINK ERROR TX RX - MySetWindowText(TNC->xIDC_LEDS, TNC->WEB_LEDS); - - Used = 2; - break; - - case 0x21: // Monitored FEC CCB - case 0x22: // Monitored ARQ CCB - - // As the reply is variable, make sure we have the terminating NULL - - if (memchr(TNC->CmdBuffer, 0, Len) == NULL) - return; // Wait for more - - Call = &TNC->CmdBuffer[1]; - Used = strlen(Call) + 2; // Opcode and Null - - UpdateMH(TNC, Call, '!', 0); - - break; - - case 0x27: // Clover ARQ LINK REQUEST status message - - //indicates an incoming link request to either MYCALL ($8027 $8000), or MYALTCALL ($8027 $8001). - - if (Len < 2) return; // Wait for more - - // Don't need to do anything (but may eventally use ALTCALL as an APPLCALL - Used = 2; - break; - - case 0x2D: // FSK ARQ Link Request status message - - // $802D $8001 $8000 CLOVER Link Request (not implemented) - // $802D $8002 $8000 AMTOR CCIR-476 Link Request - // $802D $8003 $8000 AMTOR CCIR-625 Link Request - // $802D $8004 $8000 P-MODE Link Request - - if (Len < 3) return; // Wait for more - - // Don't need to do anything (but may save Session type later - - Used = 3; - break; - - - case 0x28: // Monitored Call - - // As the reply is variable, make sure we have the terminating NULL - - if (memchr(TNC->CmdBuffer, 0, Len) == NULL) - return; // Wait for more - - Call = &TNC->CmdBuffer[1]; - Used = strlen(Call) + 2; // Opcode and Null - - // Could possibly be used for APPLCALLS by changing MYCALL when we see a call to one of our calls - - break; - - - case 0x20: // Clover Linked with - Call Connected - case 0x29: // The Linked 476 message indicates the start of a CCIR 476 linked session. - case 0x2A: // The Linked 625 message indicates the start of a CCIR 625 linked session to . - case 0x2B: // P-MODE link to - - // As the reply is variable, make sure we have the terminating NULL - - if (memchr(TNC->CmdBuffer, 0, Len) == NULL) - return; // Wait for more - - Call = &TNC->CmdBuffer[1]; - Used = strlen(Call) + 2; // Opcode and Null - - HALConnected(TNC, Call); - - break; - - case 0x23: // Normal Disconnected - followed by $8000 - case 0x24: // Link failed (any of the link errors) - case 0x25: // Signal Lost (LOS) - - if (Len < 2) return; // Wait for more - - HALDisconnected(TNC); - - Used = 2; - break; - - - // Stream Switch Reports - we will need to do something with these if Echo as Sent is set - // or we do something with the secondary port - - case 0x30: // Switch to Receive Data characters - case 0x31: // Switch to Transmit Data characters - case 0x32: // Switch to RX data from secondary port - - TNC->DataMode = Opcode; - Used = 1; - break; - - case 0x33: // Send TX data to modem - case 0x34: // Send TX data to secondary port - - TNC->TXMode = Opcode; - Used = 1; - break; - - case 0x70: // Channel Spectra Data - // $807F $80xx $8030 Invalid or unimplemented command code - if (Len < 9) return; // Wait for more - - Used = 9; - break; - - case 0x71: // SelCall On/Off - - if (Len < 2) return; // Wait for more - - Used = 2; - break; - - case 0x72: // Channel Spectra Data - // $807F $80xx $8030 Invalid or unimplemented command code - if (Len < 15) return; // Wait for more - - Used = 15; - break; - - case 0x73: // Clover Link state - - if (Len < 2) return; // Wait for more - - StatusByte = TNC->CmdBuffer[1]; - - switch (StatusByte) - { - case 0x00: mySetWindowText(TNC, "Channel idle"); break; - case 0x01: mySetWindowText(TNC, "Channel occupied with non-Clover signal"); break; - case 0x42: mySetWindowText(TNC, "Linked stations monitored"); break; - case 0x64: mySetWindowText(TNC, "Attempting normal link"); break; - case 0x65: mySetWindowText(TNC, "Attempting robust link"); break; - case 0x66: mySetWindowText(TNC, "Calling ARQ CQ"); break; - case 0x78: mySetWindowText(TNC, "Clover Control Block (CCB) send retry"); break; - case 0x79: mySetWindowText(TNC, "Clover Control Block (CCB) receive retry"); break; - case 0x7D: mySetWindowText(TNC, "Clover Control Block (CCB) received successfully"); break; - case 0x8A: mySetWindowText(TNC, "TX data block sent"); break; - case 0x8B: mySetWindowText(TNC, "RX data block received ok (precedes data block)"); break; - case 0x8C: mySetWindowText(TNC, "TX data block re-sent"); break; - case 0x8D: mySetWindowText(TNC, "RX data block decode failed (precedes data block)"); break; - case 0x8E: mySetWindowText(TNC, "TX idle"); break; - case 0x8F: mySetWindowText(TNC, "RX idle"); break; - case 0x9C: mySetWindowText(TNC, "Link failed: CCB send retries exceeded"); break; - case 0x9D: mySetWindowText(TNC, "Link failed: CCB receive retries exceeded"); break; - case 0x9E: mySetWindowText(TNC, "Link failed: protocol error"); break; - case 0xA0: mySetWindowText(TNC, "Receiving FEC SYNC sequence"); break; - } - - Used = 2; - break; - - case 0x75: // Clover waveform format - - if (Len < 5) return; // Wait for more - - Used = 5; - break; - - case 0x7F: // Error $80xx $80yy Error in command $80xx of type $80yy - // $807F $80xx $8030 Invalid or unimplemented command code - // $807F $80xx $8031 Invalid parameter value - // $807F $80xx $8032 Not allowed when connected - // $807F $80xx $8033 Not allowed when disconnected - // $807F $80xx $8034 Not valid in this mode - // $807F $80xx $8035 Not valid in this code - // $807F $8096 $8036 EEPROM write error - - if (Len < 3) return; // Wait for more - - if (TNC->CmdBuffer[1] == 0x6f && TNC->CmdBuffer[2] == 0x31) - { - // Reject of XON/XOFF enable - -// TNC->XONXOFF = FALSE; -// Debugprintf("BPQ32 HAL Port %d - Disabling XON/XOFF mode", TNC->Port); - } - else - Debugprintf("HAL Port %d Command Error Cmd %X Error %X", TNC->Port, TNC->CmdBuffer[1], TNC->CmdBuffer[2]); - - Used = 3; - break; - - // Following are all immediate commands - response is echo of command - - case 0x6f: // XON/XOFF on - -// TNC->XONXOFF = TRUE; // And drop through -// Debugprintf("BPQ32 HAL Port %d - Enabling XON/XOFF mode", TNC->Port); - - case 0x19: // Call P-MODE to - case 0x10: // Robust Link to using MYCALL - case 0x11: // Normal Link to using MYCALL - - STREAM->Connecting = TRUE; - - case 0x00: // P Load LOD file - case 0x01: // P Load S28 file - case 0x02: //Check Unit Error Status - case 0x03: //F Check System Clock - case 0x04: //C Close PTT and transmit Clover waveform - case 0x05: //Open PTT and stop transmit test - case 0x06: //Immediate Abort (Panic Kill) - case 0x07: //Normal disconnect (wait for ACK) - case 0x08: //Software reset - restore all program defaults - case 0x0A: //Send CW ID - case 0x0B: //Close PTT and transmit Single Tone - case 0x0C: //F Normal OVER (AMTOR,P-MODE) - case 0x0D: //F Force RTTY TX (Baudot/ASCII) - case 0x0E: //F Go to RTTY RX (Baudot/ASCII) - case 0x0F: //Go to LOD/S28 file loader - case SetMYCALL: // Set MYCALL Response - - case 0x1E: // Set MYALTCALL Response - - case 0x41: - case 0x42: - case 0x46: - case 0x47: - case 0x48: - case 0x4d: - case 0x52: // Enable adaptive Clover format - case 0x54: // Enable adaptive Clover format - - case 0x56: // Expanded Link State Reports OFF/ON - case 0x57: // Clear buffers on disc - case 0x58: - case 0x59: - case 0x60: // Robust Mode Retries - case 0x61: // Normal Mode Retries - case 0x80: //Switch to CLOVER mode - case 0x81: //Select AMTOR Standby - case 0x82: //Select AMTOR FEC - case 0x83: //Select P-MODE Standby - case 0x84: //Switch to FSK modes - case 0x85: //Select Baudot - case 0x86: //Select ASCII - case 0x87: //Forced OVER (AMTOR, P-MODE) - case 0x88: //Forced END (AMTOR, P-MODE) - case 0x89: //Force LTRS shift - case 0x8A: //Force FIGS shift - case 0x8B: //Send MARK tone - case 0x8C: //Send SPACE tone - case 0x8D: //Send MARK/SPACE tones - case 0x8E: //Received first character on line - case 0x8F: //Close PTT only (no tones) - - case 0xC9: //Huffman Off/On - case 0xCC: - case 0xD9: //Close PTT only (no tones) - - case SetTones: - - Used = 1; - break; - - case 0x91: // ???? - -// if (Len < 2) return; // Wait for more - - Used = 1; - break; - - default: - - // We didn't recognise command, so don't know how long it is - disaster! - - Debugprintf("HAL Port %d Unrecognised Command %x", TNC->Port, Opcode); - TNC->CmdLen = 0; - - return; - } - - if (Used == Len) - { - // All used - most likely case - - TNC->CmdLen = 0; - return; - } - - // Move Command Down buffer, and reenter - - TNC->CmdLen -= Used; - - memmove(TNC->CmdBuffer, &TNC->CmdBuffer[Used], TNC->CmdLen); - - goto CmdLoop; - - -} - - -VOID HALDisconnected(struct TNCINFO * TNC) -{ - struct STREAMINFO * STREAM = &TNC->Streams[0]; - - CloseLogfile(0); - CloseLogfile(1); - CloseLogfile(2); - - if ((STREAM->Connecting | STREAM->Connected) == 0) - { - // Not connected or Connecting. Probably response to going into Pactor Listen Mode - - return; - } - - if (STREAM->Connecting && STREAM->Disconnecting == FALSE) - { - PMSGWITHLEN buffptr; - - // Connect Failed - actually I think HAL uses another code for connect failed, but leave here for now - - buffptr = GetBuff(); - - if (buffptr) - { - buffptr->Len = sprintf(buffptr->Data, "*** Failure with %s\r", STREAM->RemoteCall); - - C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr); - } - - STREAM->Connecting = FALSE; - STREAM->Connected = FALSE; // In case! - STREAM->FramesQueued = 0; - - sprintf(TNC->WEB_TNCSTATE, "In Use by %s", STREAM->MyCall); - MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE); - - return; - } - - // Connected, or Disconnecting - Release Session - - STREAM->Connecting = FALSE; - STREAM->Connected = FALSE; // Back to Command Mode - STREAM->FramesQueued = 0; - - if (STREAM->Disconnecting == FALSE) - STREAM->ReportDISC = TRUE; // Tell Node - - STREAM->Disconnecting = FALSE; - - // Need to reset Pactor Call in case it was changed - - TNC->NeedPACTOR = 20; -} - -BOOL HALConnected(struct TNCINFO * TNC, char * Call) -{ - char Msg[80]; - PMSGWITHLEN buffptr; - struct STREAMINFO * STREAM = &TNC->Streams[0]; - char CallCopy[80]; - - strcpy(CallCopy, Call); - strcat(CallCopy, " "); // Some routines expect 10 char calls - - STREAM->BytesRXed = STREAM->BytesTXed = STREAM->BytesAcked = 0; - STREAM->ConnectTime = time(NULL); - - // Stop Scanner - - sprintf(Msg, "%d SCANSTOP", TNC->Port); - - Rig_Command( (TRANSPORTENTRY *) -1, Msg); - - ShowTraffic(TNC); - - TNC->DataMode = RXDATA; - - OpenLogfile(0); - OpenLogfile(1); - OpenLogfile(2); - - if (TNC->PortRecord->ATTACHEDSESSIONS[0] == 0) - { - // Incoming Connect - - ProcessIncommingConnect(TNC, CallCopy, 0, TRUE); - - sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Inbound", STREAM->RemoteCall, TNC->NodeCall); - MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE); - - if (TNC->CurrentMode != Clover) - SendCmd(TNC, "\x87", 1); // Changeover to ISS - - // If an autoconnect APPL is defined, send it - - if (TNC->ApplCmd) - { - buffptr = GetBuff(); - if (buffptr == 0) return TRUE; // No buffers, so ignore - - buffptr->Len = sprintf((UCHAR *)buffptr->Data, "%s\r", TNC->ApplCmd); - C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr); - TNC->SwallowSignon = TRUE; - - return TRUE; - } - - if (FULL_CTEXT && HFCTEXTLEN == 0) - { - EncodeAndSend(TNC, CTEXTMSG, CTEXTLEN); - WriteLogLine(2, CTEXTMSG, CTEXTLEN); - - STREAM->BytesTXed += CTEXTLEN; - } - return TRUE; - } - - // Connect Complete - - buffptr = GetBuff(); - if (buffptr == 0) return TRUE; // No buffers, so ignore - - buffptr->Len = sprintf((UCHAR *)buffptr->Data, "*** Connected to %s\r", Call);; - - C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr); - - STREAM->Connecting = FALSE; - STREAM->Connected = TRUE; // Subsequent data to data channel - - sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Outbound", TNC->NodeCall, STREAM->RemoteCall); - MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE); - - UpdateMH(TNC, CallCopy, '+', 'O'); - - - return TRUE; -} - - -static VOID EncodeAndSend(struct TNCINFO * TNC, UCHAR * txbuffer, int Len) -{ - // Send A Packet With DLE Encoding Encoding - - TNC->TXLen = DLEEncode(txbuffer, TNC->TXBuffer, Len); - - WriteCommBlock(TNC); -} - -VOID SendCmd(struct TNCINFO * TNC, UCHAR * txbuffer, int Len) -{ - // Send A Packet With Command Encoding (preceed each with 0x80 - - int i,txptr=0; - UCHAR * outbuff = TNC->TXBuffer; - - for (i=0; iTXLen = txptr; - WriteCommBlock(TNC); -} - -int DLEEncode(UCHAR * inbuff, UCHAR * outbuff, int len) -{ - int i, txptr = 0; - UCHAR c; - - // Escape x80 and x81 with x81 - -// outbuff[0] = 0x80; -// outbuff[1] = 0x33; // Send data to modem - - for (i=0;iNeedPACTOR = 30; -} - - - - diff --git a/HTTPcode.c b/HTTPcode.c index daeb195..30cf2bd 100644 --- a/HTTPcode.c +++ b/HTTPcode.c @@ -99,6 +99,8 @@ extern UCHAR LogDirectory[]; extern struct RIGPORTINFO * PORTInfo[34]; extern int NumberofPorts; +extern UCHAR ConfigDirectory[260]; + char * strlop(char * buf, char delim); VOID sendandcheck(SOCKET sock, const char * Buffer, int Len); int CompareNode(const void *a, const void *b); @@ -1475,13 +1477,13 @@ VOID SaveConfigFile(SOCKET sock , char * MsgPtr, char * Rest, int LOCAL) MsgLen = (int)strlen(input + 8); - if (BPQDirectory[0] == 0) + if (ConfigDirectory[0] == 0) { strcpy(inputname, "bpq32.cfg"); } else { - strcpy(inputname,BPQDirectory); + strcpy(inputname,ConfigDirectory); strcat(inputname,"/"); strcat(inputname, "bpq32.cfg"); } @@ -3024,13 +3026,13 @@ doHeader: if (COOKIE ==FALSE) Key = DummyKey; - if (BPQDirectory[0] == 0) + if (ConfigDirectory[0] == 0) { strcpy(inputname, "bpq32.cfg"); } else { - strcpy(inputname,BPQDirectory); + strcpy(inputname,ConfigDirectory); strcat(inputname,"/"); strcat(inputname, "bpq32.cfg"); } diff --git a/HTTPcode.c.bak b/HTTPcode.c.bak deleted file mode 100644 index 209a80f..0000000 --- a/HTTPcode.c.bak +++ /dev/null @@ -1,4849 +0,0 @@ -/* -Copyright 2001-2022 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 WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers - -#define _CRT_SECURE_NO_DEPRECATE - -#define DllImport - -#include "CHeaders.h" -#include - -#include "tncinfo.h" -#include "time.h" -#include "bpq32.h" -#include "telnetserver.h" - -// This is needed to link with a lib built from source - -#ifdef WIN32 -#define ZEXPORT __stdcall -#endif - -#include "zlib.h" - -#define CKernel -#include "httpconnectioninfo.h" - -extern int MAXBUFFS, QCOUNT, MINBUFFCOUNT, NOBUFFCOUNT, BUFFERWAITS, L3FRAMES; -extern int NUMBEROFNODES, MAXDESTS, L4CONNECTSOUT, L4CONNECTSIN, L4FRAMESTX, L4FRAMESRX, L4FRAMESRETRIED, OLDFRAMES; -extern int STATSTIME; -extern TRANSPORTENTRY * L4TABLE; -extern BPQVECSTRUC BPQHOSTVECTOR[]; -extern BOOL APRSApplConnected; -extern char VersionString[]; -VOID FormatTime3(char * Time, time_t cTime); -DllExport int APIENTRY Get_APPLMASK(int Stream); -VOID SaveUIConfig(); -int ProcessNodeSignon(SOCKET sock, struct TCPINFO * TCP, char * MsgPtr, char * Appl, char * Reply, struct HTTPConnectionInfo ** Session, int LOCAL); -VOID SetupUI(int Port); -VOID SendUIBeacon(int Port); -VOID GetParam(char * input, char * key, char * value); -VOID ARDOPAbort(struct TNCINFO * TNC); -VOID WriteMiniDump(); -BOOL KillTNC(struct TNCINFO * TNC); -BOOL RestartTNC(struct TNCINFO * TNC); -int GetAISPageInfo(char * Buffer, int ais, int adsb); -int GetAPRSPageInfo(char * Buffer, double N, double S, double W, double E, int aprs, int ais, int adsb); -unsigned char * Compressit(unsigned char * In, int Len, int * OutLen); -char * stristr (char *ch1, char *ch2); -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); - -extern struct ROUTE * NEIGHBOURS; -extern int ROUTE_LEN; -extern int MAXNEIGHBOURS; - -extern struct DEST_LIST * DESTS; // NODE LIST -extern int DEST_LIST_LEN; -extern int MAXDESTS; // MAX NODES IN SYSTEM - -extern struct _LINKTABLE * LINKS; -extern int LINK_TABLE_LEN; -extern int MAXLINKS; -extern char * RigWebPage; -extern COLORREF Colours[256]; - -extern BOOL IncludesMail; -extern BOOL IncludesChat; - -extern BOOL APRSWeb; -extern BOOL RigActive; - -extern HKEY REGTREE; - -extern BOOL APRSActive; - -extern UCHAR LogDirectory[]; - -extern struct RIGPORTINFO * PORTInfo[34]; -extern int NumberofPorts; - -char * strlop(char * buf, char delim); -VOID sendandcheck(SOCKET sock, const char * Buffer, int Len); -int CompareNode(const void *a, const void *b); -int CompareAlias(const void *a, const void *b); -void ProcessMailHTTPMessage(struct HTTPConnectionInfo * Session, char * Method, char * URL, char * input, char * Reply, int * RLen, int InputLen); -void ProcessChatHTTPMessage(struct HTTPConnectionInfo * Session, char * Method, char * URL, char * input, char * Reply, int * RLen); -struct PORTCONTROL * APIENTRY GetPortTableEntryFromSlot(int portslot); -int SetupNodeMenu(char * Buff, int SYSOP); -int StatusProc(char * Buff); -int ProcessMailSignon(struct TCPINFO * TCP, char * MsgPtr, char * Appl, char * Reply, struct HTTPConnectionInfo ** Session, BOOL WebMail, int LOCAL); -int ProcessChatSignon(struct TCPINFO * TCP, char * MsgPtr, char * Appl, char * Reply, struct HTTPConnectionInfo ** Session, int LOCAL); -VOID APRSProcessHTTPMessage(SOCKET sock, char * MsgPtr, BOOL LOCAL, BOOL COOKIE); - - -static struct HTTPConnectionInfo * SessionList; // active term mode sessions - -char Mycall[10]; - -char MAILPipeFileName[] = "\\\\.\\pipe\\BPQMAILWebPipe"; -char CHATPipeFileName[] = "\\\\.\\pipe\\BPQCHATWebPipe"; - -char Index[] = "%s's BPQ32 Web Server

" -"" -"" -"
Node PagesAPRS Pages
"; - -char IndexNoAPRS[] = "" -""; - -//char APRSBit[] = "
APRS Pages"; - -//char MailBit[] = "Mail Mgmt" -// "WebMail"; -//char ChatBit[] = "Chat Mgmt"; - -char Tail[] = ""; - -char RouteHddr[] = "

Routes

" -""; - -char RouteLine[] = ""; -char xNodeHddr[] = "
" -"
PortCallQualityNode CountFrame CountRetriesPercentMaxframeFrackLast HeardQueuedRem Qual
%s%d%s%c%d%d%d%d%d%%d%d%02d:%02d%d%d
" -"
" -"" -"
" -"

Nodes %s

"; - -char NodeHddr[] = "
" -"" -"" -"
" -"

Nodes %s

"; - -char NodeLine[] = ""; - - -char StatsHddr[] = "

Node Stats

%s:%s
" -""; - -char PortStatsHddr[] = "

Stats for Port %d

"; - -char PortStatsLine[] = ""; - - -char Beacons[] = "

Beacon Configuration for Port %d

You need to be signed in to save changes

%s %d
" -"" -"
" -"" -"" -"" -"" -"" -"
Send Interval (Minutes)
To
Path
Send From File
Text
" -"" - -"

" -""; - - -char LinkHddr[] = "

Links

" -""; - -char LinkLine[] = ""; - -char UserHddr[] = "

Sessions

Far CallOur CallPortax.25 stateLink Typeax.25 Version
%s%s%d%s%s%d
"; - -char UserLine[] = ""; - -char TermSignon[] = "BPQ32 Node %s Terminal Access" -"

BPQ32 Node %s Terminal Access

" -"

Please enter username and password to access the node

" -"" -"
%s%s%s
" -"" -"
User
Password
" -"

" -""; - - -char PassError[] = "

Sorry, User or Password is invalid - please try again

"; - -char BusyError[] = "

Sorry, No sessions available - please try later

"; - -char LostSession[] = "Sorry, Session had been lost - refresh page to sign in again"; -char NoSessions[] = "Sorry, No Sessions available - refresh page to try again"; - -char TermPage[] = "" -"BPQ32 Node %s" -"" -"" -"

BPQ32 Node %s

" -"
" -"

" -"" -"" -""; - -char TermOutput[] = "" -"" -"" -"" -"" -"" -"" -"
\""; - - -// font-family:monospace;background-color:black;color:lawngreen;font-size:12px - -char TermOutputTail[] = "
"; - -/* -char InputLine[] = "" -"
" -"" -"
"; -*/ -char InputLine[] = "" -"
" -"\" id=inp type=text text width=100%% name=input />" -"
"; - -static char NodeSignon[] = "BPQ32 Node SYSOP Access" -"

BPQ32 Node %s SYSOP Access

" -"

This page sets Cookies. Don't continue if you object to this

" -"

Please enter Callsign and Password to access the Node

" -"
" -"" -"" -"
User
Password
" -"

"; - - -static char MailSignon[] = "BPQ32 Mail Server Access" -"

BPQ32 Mail Server %s Access

" -"

Please enter Callsign and Password to access the BBS

" -"
" -"" -"" -"
User
Password
" -"

"; - -static char ChatSignon[] = "BPQ32 Chat Server Access" -"

BPQ32 Chat Server %s Access

" -"

Please enter Callsign and Password to access the Chat Server

" -"
" -"" -"" -"
User
Password
" -"

"; - - -static char MailLostSession[] = "" -"
" -"Sorry, Session had been lost

    " -"
"; - - -static char ConfigEditPage[] = "" -"Edit Config" -"
" -"

" -"
"; - -static char EXCEPTMSG[80] = ""; - - -void UndoTransparency(char * input) -{ - char * ptr1, * ptr2; - char c; - int hex; - - if (input == NULL) - return; - - ptr1 = ptr2 = input; - - // Convert any %xx constructs - - while (1) - { - c = *(ptr1++); - - if (c == 0) - break; - - if (c == '%') - { - c = *(ptr1++); - if(isdigit(c)) - hex = (c - '0') << 4; - else - hex = (tolower(c) - 'a' + 10) << 4; - - c = *(ptr1++); - if(isdigit(c)) - hex += (c - '0'); - else - hex += (tolower(c) - 'a' + 10); - - *(ptr2++) = hex; - } - else if (c == '+') - *(ptr2++) = 32; - else - *(ptr2++) = c; - } - *ptr2 = 0; -} - - - - -VOID PollSession(struct HTTPConnectionInfo * Session) -{ - int state, change; - int count, len; - char Msg[400] = ""; - char Formatted[8192]; - char * ptr1, * ptr2; - char c; - int Line; - - // Poll Node - - SessionState(Session->Stream, &state, &change); - - if (change == 1) - { - int Line = Session->LastLine++; - free(Session->ScreenLines[Line]); - - if (state == 1)// Connected - Session->ScreenLines[Line] = _strdup("*** Connected
\r\n"); - else - Session->ScreenLines[Line] = _strdup("*** Disconnected
\r\n"); - - if (Line == 99) - Session->LastLine = 0; - - Session->Changed = TRUE; - } - - if (RXCount(Session->Stream) > 0) - { - int realLen = 0; - - do - { - GetMsg(Session->Stream, &Msg[0], &len, &count); - - // replace cr with
and space with   - - - ptr1 = Msg; - ptr2 = &Formatted[0]; - - if (Session->PartLine) - { - // Last line was incomplete - append to it - - realLen = Session->PartLine; - - Line = Session->LastLine - 1; - - if (Line < 0) - Line = 99; - - strcpy(Formatted, Session->ScreenLines[Line]); - ptr2 += strlen(Formatted); - - Session->LastLine = Line; - Session->PartLine = FALSE; - } - - while (len--) - { - c = *(ptr1++); - realLen++; - - if (c == 13) - { - int LineLen; - - strcpy(ptr2, "
\r\n"); - - // Write to screen - - Line = Session->LastLine++; - free(Session->ScreenLines[Line]); - - LineLen = (int)strlen(Formatted); - - // if line starts with a colour code, process it - - if (Formatted[0] == 0x1b && LineLen > 1) - { - int ColourCode = Formatted[1] - 10; - COLORREF Colour = Colours[ColourCode]; - char ColString[30]; - - memmove(&Formatted[20], &Formatted[2], LineLen); - sprintf(ColString, "", GetRValue(Colour), GetGValue(Colour), GetBValue(Colour)); - memcpy(Formatted, ColString, 20); - strcat(Formatted, ""); - LineLen =+ 28; - } - - Session->ScreenLineLen[Line] = LineLen; - Session->ScreenLines[Line] = _strdup(Formatted); - - if (Line == 99) - Session->LastLine = 0; - - ptr2 = &Formatted[0]; - realLen = 0; - - } - else if (c == 32) - { - memcpy(ptr2, " ", 6); - ptr2 += 6; - - // Make sure line isn't too long - // but beware of spaces expanded to   - count chars in line - - if ((realLen) > 100) - { - strcpy(ptr2, "
\r\n"); - - Line = Session->LastLine++; - free(Session->ScreenLines[Line]); - - Session->ScreenLines[Line] = _strdup(Formatted); - - if (Line == 99) - Session->LastLine = 0; - - ptr2 = &Formatted[0]; - realLen = 0; - } - } - else if (c == '>') - { - memcpy(ptr2, ">", 4); - ptr2 += 4; - } - else if (c == '<') - { - memcpy(ptr2, "<", 4); - ptr2 += 4; - } - else - *(ptr2++) = c; - - } - - *ptr2 = 0; - - if (ptr2 != &Formatted[0]) - { - // Incomplete line - - // Save to screen - - Line = Session->LastLine++; - free(Session->ScreenLines[Line]); - - Session->ScreenLines[Line] = _strdup(Formatted); - - if (Line == 99) - Session->LastLine = 0; - - Session->PartLine = realLen; - } - - // strcat(Session->ScreenBuffer, Formatted); - Session->Changed = TRUE; - - } while (count > 0); - } -} - - -VOID HTTPTimer() -{ - // Run every tick. Check for status change and data available - - struct HTTPConnectionInfo * Session = SessionList; // active term mode sessions - struct HTTPConnectionInfo * PreviousSession = NULL; - -// inf(); - - while (Session) - { - Session->KillTimer++; - - if (Session->Key[0] != 'T') - { - PreviousSession = Session; - Session = Session->Next; - continue; - } - - if (Session->KillTimer > 3000) // Around 5 mins - { - int i; - int Stream = Session->Stream; - - for (i = 0; i < 100; i++) - { - free(Session->ScreenLines[i]); - } - - SessionControl(Stream, 2, 0); - SessionState(Stream, &i, &i); - DeallocateStream(Stream); - - if (PreviousSession) - PreviousSession->Next = Session->Next; // Remove from chain - else - SessionList = Session->Next; - - free(Session); - - break; - } - - PollSession(Session); - - // if (Session->ResponseTimer == 0 && Session->Changed) - // Debugprintf("Data to send but no outstanding GET"); - - if (Session->ResponseTimer) - { - Session->ResponseTimer--; - - if (Session->ResponseTimer == 0 || Session->Changed) - { - SOCKET sock = Session->sock; - char _REPLYBUFFER[100000]; - int ReplyLen; - char Header[256]; - int HeaderLen; - int Last = Session->LastLine; - int n; - struct TNCINFO * TNC = Session->TNC; - struct TCPINFO * TCP = 0; - - if (TNC) - TCP = TNC->TCPInfo; - - if (TCP && TCP->WebTermCSS) - sprintf(_REPLYBUFFER, TermOutput, TCP->WebTermCSS); - else - sprintf(_REPLYBUFFER, TermOutput, ""); - - for (n = Last;;) - { - strcat(_REPLYBUFFER, Session->ScreenLines[n]); - - if (n == 99) - n = -1; - - if (++n == Last) - break; - } - - ReplyLen = (int)strlen(_REPLYBUFFER); - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "%s", TermOutputTail); - - HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n", ReplyLen); - sendandcheck(sock, Header, HeaderLen); - sendandcheck(sock, _REPLYBUFFER, ReplyLen); - - Session->ResponseTimer = Session->Changed = 0; - } - } - PreviousSession = Session; - Session = Session->Next; - } -} - -struct HTTPConnectionInfo * AllocateSession(SOCKET sock, char Mode) -{ - time_t KeyVal; - struct HTTPConnectionInfo * Session = zalloc(sizeof(struct HTTPConnectionInfo)); - int i; - - if (Session == NULL) - return NULL; - - if (Mode == 'T') - { - // Terminal - - for (i = 0; i < 20; i++) - Session->ScreenLines[i] = _strdup("Scroll to end
"); - - for (i = 20; i < 100; i++) - Session->ScreenLines[i] = _strdup("
\r\n"); - - Session->Stream = FindFreeStream(); - - if (Session->Stream == 0) - return NULL; - - SessionControl(Session->Stream, 1, 0); - } - - KeyVal = (int)sock * time(NULL); - - sprintf(Session->Key, "%c%012X", Mode, (int)KeyVal); - - if (SessionList) - Session->Next = SessionList; - - SessionList = Session; - - return Session; -} - -struct HTTPConnectionInfo * FindSession(char * Key) -{ - struct HTTPConnectionInfo * Session = SessionList; - - while (Session) - { - if (strcmp(Session->Key, Key) == 0) - return Session; - - Session = Session->Next; - } - - return NULL; -} - -void ProcessTermInput(SOCKET sock, char * MsgPtr, int MsgLen, char * Key) -{ - char _REPLYBUFFER[1024]; - int ReplyLen; - char Header[256]; - int HeaderLen; - int State; - struct HTTPConnectionInfo * Session = FindSession(Key); - int Stream; - - if (Session == NULL) - { - ReplyLen = sprintf(_REPLYBUFFER, "%s", LostSession); - } - else - { - char * input = strstr(MsgPtr, "\r\n\r\n"); // End of headers - char * end = &MsgPtr[MsgLen]; - int Line = Session->LastLine++; - char * ptr1, * ptr2; - char c; - UCHAR hex; - - struct TNCINFO * TNC = Session->TNC; - struct TCPINFO * TCP = 0; - - if (TNC) - TCP = TNC->TCPInfo; - - if (TCP && TCP->WebTermCSS) - ReplyLen = sprintf(_REPLYBUFFER, InputLine, Key, TCP->WebTermCSS); - else - ReplyLen = sprintf(_REPLYBUFFER, InputLine, Key, ""); - - - Stream = Session->Stream; - - input += 10; - ptr1 = ptr2 = input; - - // Convert any %xx constructs - - while (ptr1 != end) - { - c = *(ptr1++); - if (c == '%') - { - c = *(ptr1++); - if(isdigit(c)) - hex = (c - '0') << 4; - else - hex = (tolower(c) - 'a' + 10) << 4; - - c = *(ptr1++); - if(isdigit(c)) - hex += (c - '0'); - else - hex += (tolower(c) - 'a' + 10); - - *(ptr2++) = hex; - } - else if (c == '+') - *(ptr2++) = 32; - else - *(ptr2++) = c; - } - - end = ptr2; - - *ptr2 = 0; - - strcat(input, "
\r\n"); - - free(Session->ScreenLines[Line]); - - Session->ScreenLines[Line] = _strdup(input); - - if (Line == 99) - Session->LastLine = 0; - - *end++ = 13; - *end = 0; - - SessionStateNoAck(Stream, &State); - - if (State == 0) - { - char AXCall[10]; - SessionControl(Stream, 1, 0); - if (BPQHOSTVECTOR[Session->Stream -1].HOSTSESSION == NULL) - { - //No L4 sessions free - - ReplyLen = sprintf(_REPLYBUFFER, "%s", NoSessions); - HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n", ReplyLen + (int)strlen(Tail)); - send(sock, Header, HeaderLen, 0); - send(sock, _REPLYBUFFER, ReplyLen, 0); - send(sock, Tail, (int)strlen(Tail), 0); - return; - } - - ConvToAX25(Session->HTTPCall, AXCall); - ChangeSessionCallsign(Stream, AXCall); - if (Session->USER) - BPQHOSTVECTOR[Session->Stream -1].HOSTSESSION->Secure_Session = Session->USER->Secure; - else - Debugprintf("HTTP Term Session->USER is NULL"); - } - - SendMsg(Stream, input, (int)(end - input)); - Session->Changed = TRUE; - Session->KillTimer = 0; - } - - HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n", ReplyLen + (int)strlen(Tail)); - send(sock, Header, HeaderLen, 0); - send(sock, _REPLYBUFFER, ReplyLen, 0); - send(sock, Tail, (int)strlen(Tail), 0); -} - - -void ProcessTermClose(SOCKET sock, char * MsgPtr, int MsgLen, char * Key, int LOCAL) -{ - char _REPLYBUFFER[8192]; - int ReplyLen = sprintf(_REPLYBUFFER, InputLine, Key, ""); - char Header[256]; - int HeaderLen; - struct HTTPConnectionInfo * Session = FindSession(Key); - - if (Session) - { - Session->KillTimer = 99999; - } - - ReplyLen = SetupNodeMenu(_REPLYBUFFER, LOCAL); - - HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n" - "\r\n", ReplyLen + (int)strlen(Tail)); - send(sock, Header, HeaderLen, 0); - send(sock, _REPLYBUFFER, ReplyLen, 0); - send(sock, Tail, (int)strlen(Tail), 0); -} - -int ProcessTermSignon(struct TNCINFO * TNC, SOCKET sock, char * MsgPtr, int MsgLen, int LOCAL) -{ - char _REPLYBUFFER[8192]; - int ReplyLen; - char Header[256]; - int HeaderLen; - char * input = strstr(MsgPtr, "\r\n\r\n"); // End of headers - char * user, * password, * Context, * Appl; - char NoApp[] = ""; - struct TCPINFO * TCP = TNC->TCPInfo; - - if (input) - { - int i; - struct UserRec * USER; - - UndoTransparency(input); - - if (strstr(input, "Cancel=Cancel")) - { - ReplyLen = SetupNodeMenu(_REPLYBUFFER, LOCAL); - goto Sendit; - } - user = strtok_s(&input[9], "&", &Context); - password = strtok_s(NULL, "=", &Context); - password = strtok_s(NULL, "&", &Context); - - Appl = strtok_s(NULL, "=", &Context); - Appl = strtok_s(NULL, "&", &Context); - - if (Appl == 0) - Appl = NoApp; - - if (password == NULL) - { - ReplyLen = sprintf(_REPLYBUFFER, TermSignon, Mycall, Mycall, Appl); - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "%s", PassError); - goto Sendit; - } - - for (i = 0; i < TCP->NumberofUsers; i++) - { - USER = TCP->UserRecPtr[i]; - - if ((strcmp(password, USER->Password) == 0) && - ((_stricmp(user, USER->UserName) == 0 ) || (_stricmp(USER->UserName, "ANON") == 0))) - { - // ok - - struct HTTPConnectionInfo * Session = AllocateSession(sock, 'T'); - - if (Session) - { - char AXCall[10]; - ReplyLen = sprintf(_REPLYBUFFER, TermPage, Mycall, Mycall, Session->Key, Session->Key, Session->Key); - if (_stricmp(USER->UserName, "ANON") == 0) - strcpy(Session->HTTPCall, _strupr(user)); - else - strcpy(Session->HTTPCall, USER->Callsign); - ConvToAX25(Session->HTTPCall, AXCall); - ChangeSessionCallsign(Session->Stream, AXCall); - BPQHOSTVECTOR[Session->Stream -1].HOSTSESSION->Secure_Session = USER->Secure; - Session->USER = USER; - - if (USER->Appl[0]) - SendMsg(Session->Stream, USER->Appl, (int)strlen(USER->Appl)); - } - else - { - ReplyLen = SetupNodeMenu(_REPLYBUFFER, LOCAL); - - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "%s", BusyError); - } - break; - } - } - - if (i == TCP->NumberofUsers) - { - // Not found - - ReplyLen = sprintf(_REPLYBUFFER, TermSignon, Mycall, Mycall, Appl); - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "%s", PassError); - } - - } - -Sendit: - - HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n", ReplyLen + (int)strlen(Tail)); - send(sock, Header, HeaderLen, 0); - send(sock, _REPLYBUFFER, ReplyLen, 0); - send(sock, Tail, (int)strlen(Tail), 0); - - return 1; -} - -char * LookupKey(char * Key) -{ - if (strcmp(Key, "##MY_CALLSIGN##") == 0) - { - char Mycall[10]; - memcpy(Mycall, &MYNODECALL, 10); - strlop(Mycall, ' '); - - return _strdup(Mycall); - } - return NULL; -} - - -int ProcessSpecialPage(char * Buffer, int FileSize) -{ - // replaces ##xxx### constructs with the requested data - - char * NewMessage = malloc(100000); - char * ptr1 = Buffer, * ptr2, * ptr3, * ptr4, * NewPtr = NewMessage; - int PrevLen; - int BytesLeft = FileSize; - int NewFileSize = FileSize; - char * StripPtr = ptr1; - - // strip comments blocks - - while (ptr4 = strstr(ptr1, ""); - if (ptr2) - { - PrevLen = (int)(ptr4 - ptr1); - memcpy(StripPtr, ptr1, PrevLen); - StripPtr += PrevLen; - ptr1 = ptr2 + 3; - BytesLeft = (int)(FileSize - (ptr1 - Buffer)); - } - } - - memcpy(StripPtr, ptr1, BytesLeft); - StripPtr += BytesLeft; - - BytesLeft = (int)(StripPtr - Buffer); - - FileSize = BytesLeft; - NewFileSize = FileSize; - ptr1 = Buffer; - ptr1[FileSize] = 0; - -loop: - ptr2 = strstr(ptr1, "##"); - - if (ptr2) - { - PrevLen = (int)(ptr2 - ptr1); // Bytes before special text - - ptr3 = strstr(ptr2+2, "##"); - - if (ptr3) - { - char Key[80] = ""; - int KeyLen; - char * NewText; - int NewTextLen; - - ptr3 += 2; - KeyLen = (int)(ptr3 - ptr2); - - if (KeyLen < 80) - memcpy(Key, ptr2, KeyLen); - - NewText = LookupKey(Key); - - if (NewText) - { - NewTextLen = (int)strlen(NewText); - NewFileSize = NewFileSize + NewTextLen - KeyLen; - // NewMessage = realloc(NewMessage, NewFileSize); - - memcpy(NewPtr, ptr1, PrevLen); - NewPtr += PrevLen; - memcpy(NewPtr, NewText, NewTextLen); - NewPtr += NewTextLen; - - free(NewText); - NewText = NULL; - } - else - { - // Key not found, so just leave - - memcpy(NewPtr, ptr1, PrevLen + KeyLen); - NewPtr += (PrevLen + KeyLen); - } - - ptr1 = ptr3; // Continue scan from here - BytesLeft = (int)(Buffer + FileSize - ptr3); - } - else // Unmatched ## - { - memcpy(NewPtr, ptr1, PrevLen + 2); - NewPtr += (PrevLen + 2); - ptr1 = ptr2 + 2; - } - goto loop; - } - - // Copy Rest - - memcpy(NewPtr, ptr1, BytesLeft); - NewMessage[NewFileSize] = 0; - - strcpy(Buffer, NewMessage); - free(NewMessage); - - return NewFileSize; -} - -int SendMessageFile(SOCKET sock, char * FN, BOOL OnlyifExists, int allowDeflate) -{ - int FileSize = 0, Sent, Loops = 0; - char * MsgBytes; - char MsgFile[512]; - FILE * hFile; - int ReadLen; - BOOL Special = FALSE; - int Len; - int HeaderLen; - char Header[256]; - char TimeString[64]; - char FileTimeString[64]; - struct stat STAT; - char * ptr; - char * Compressed = 0; - char Encoding[] = "Content-Encoding: deflate\r\n"; - char Type[64] = "Content-Type: text/html\r\n"; - -#ifdef WIN32 - - struct _EXCEPTION_POINTERS exinfo; - strcpy(EXCEPTMSG, "SendMessageFile"); - - __try { -#endif - - UndoTransparency(FN); - - if (strstr(FN, "..")) - { - FN[0] = '/'; - FN[1] = 0; - } - - if (strlen(FN) > 256) - { - FN[256] = 0; - Debugprintf("HTTP File Name too long %s", FN); - } - - if (strcmp(FN, "/") == 0) - if (APRSActive) - sprintf(MsgFile, "%s/HTML/index.html", BPQDirectory); - else - sprintf(MsgFile, "%s/HTML/indexnoaprs.html", BPQDirectory); - else - sprintf(MsgFile, "%s/HTML%s", BPQDirectory, FN); - - - // First see if file exists so we can override standard ones in code - - if (stat(MsgFile, &STAT) == 0 && (hFile = fopen(MsgFile, "rb"))) - { - FileSize = STAT.st_size; - - MsgBytes = zalloc(FileSize + 1); - - ReadLen = (int)fread(MsgBytes, 1, FileSize, hFile); - - fclose(hFile); - - // ft.QuadPart -= 116444736000000000; - // ft.QuadPart /= 10000000; - - // ctime = ft.LowPart; - - FormatTime3(FileTimeString, STAT.st_ctime); - } - else - { - // See if it is a hard coded file - - MsgBytes = GetStandardPage(&FN[1], &FileSize); - - if (MsgBytes) - { - if (FileSize == 0) - FileSize = strlen(MsgBytes); - - FormatTime3(FileTimeString, 0); - } - else - { - if (OnlyifExists) // Set if we dont want an error response if missing - return -1; - - Len = sprintf(Header, "HTTP/1.1 404 Not Found\r\nContent-Length: 16\r\n\r\nPage not found\r\n"); - send(sock, Header, Len, 0); - return 0; - } - } - - // if HTML file, look for ##...## substitutions - - if ((strcmp(FN, "/") == 0 || strstr(FN, "htm" ) || strstr(FN, "HTM")) && strstr(MsgBytes, "##" )) - { - FileSize = ProcessSpecialPage(MsgBytes, FileSize); - FormatTime3(FileTimeString, time(NULL)); - - } - - FormatTime3(TimeString, time(NULL)); - - ptr = FN; - - while (strchr(ptr, '.')) - { - ptr = strchr(ptr, '.'); - ++ptr; - } - - if (_stricmp(ptr, "js") == 0) - strcpy(Type, "Content-Type: text/javascript\r\n"); - - if (_stricmp(ptr, "pdf") == 0) - strcpy(Type, "Content-Type: application/pdf\r\n"); - - if (allowDeflate) - { - Compressed = Compressit(MsgBytes, FileSize, &FileSize); - } - else - { - Encoding[0] = 0; - Compressed = MsgBytes; - } - - if (_stricmp(ptr, "jpg") == 0 || _stricmp(ptr, "jpeg") == 0 || _stricmp(ptr, "png") == 0 || _stricmp(ptr, "gif") == 0 || _stricmp(ptr, "ico") == 0) - strcpy(Type, "Content-Type: image\r\n"); - - HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\n" - "Date: %s\r\n" - "Last-Modified: %s\r\n" - "%s%s" - "\r\n", FileSize, TimeString, FileTimeString, Type, Encoding); - - send(sock, Header, HeaderLen, 0); - - Sent = send(sock, Compressed, FileSize, 0); - - while (Sent != FileSize && Loops++ < 3000) // 100 secs max - { - if (Sent > 0) // something sent - { -// Debugprintf("%d out of %d sent", Sent, FileSize); - FileSize -= Sent; - memmove(Compressed, &Compressed[Sent], FileSize); - } - - Sleep(30); - Sent = send(sock, Compressed, FileSize, 0); - } - -// Debugprintf("%d out of %d sent %d loops", Sent, FileSize, Loops); - - - free (MsgBytes); - if (allowDeflate) - free (Compressed); - -#ifdef WIN32 - } -#include "StdExcept.c" - Debugprintf("Sending FIle %s", FN); -} -#endif - -return 0; -} - -VOID sendandcheck(SOCKET sock, const char * Buffer, int Len) -{ - int Loops = 0; - int Sent = send(sock, Buffer, Len, 0); - char * Copy = NULL; - - while (Sent != Len && Loops++ < 300) // 10 secs max - { - // Debugprintf("%d out of %d sent %d Loops", Sent, Len, Loops); - - if (Copy == NULL) - { - Copy = malloc(Len); - memcpy(Copy, Buffer, Len); - } - - if (Sent > 0) // something sent - { - Len -= Sent; - memmove(Copy, &Copy[Sent], Len); - } - - Sleep(30); - Sent = send(sock, Copy, Len, 0); - } - - if (Copy) - free(Copy); - - return; -} - -int RefreshTermWindow(struct TCPINFO * TCP, struct HTTPConnectionInfo * Session, char * _REPLYBUFFER) -{ - char Msg[400] = ""; - int HeaderLen, ReplyLen; - char Header[256]; - - PollSession(Session); // See if anything received - - if (Session->Changed) - { - int Last = Session->LastLine; - int n; - - if (TCP && TCP->WebTermCSS) - sprintf(_REPLYBUFFER, TermOutput, TCP->WebTermCSS); - else - sprintf(_REPLYBUFFER, TermOutput, ""); - - for (n = Last;;) - { - strcat(_REPLYBUFFER, Session->ScreenLines[n]); - - if (n == 99) - n = -1; - - if (++n == Last) - break; - } - - Session->Changed = 0; - - ReplyLen = (int)strlen(_REPLYBUFFER); - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "%s", TermOutputTail); - - HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n", ReplyLen); - sendandcheck(Session->sock, Header, HeaderLen); - sendandcheck(Session->sock, _REPLYBUFFER, ReplyLen); - - return 1; - } - else - return 0; -} - -int SetupNodeMenu(char * Buff, int LOCAL) -{ - int Len = 0, i; - struct TNCINFO * TNC; - int top = 0, left = 0; - - char NodeMenuHeader[] = "%s's BPQ32 Web Server" - "" - - "" - "

BPQ32 Node %s

" - "

" - "" - "" - "" - "" - "" - "" - "%s%s%s%s%s%s"; - - char DriverBit[] = "" - ""; - - char APRSBit[] = ""; - - char MailBit[] = "" - ""; - - char ChatBit[] = ""; - char SigninBit[] = ""; - - char NodeTail[] = - "" - "
RoutesNodesPortsLinksUsersStatsTerminalDriver WindowsStream StatusAPRS PagesMail MgmtWebMailChat MgmtSYSOP SigninEdit Config" - "
"; - - - Len = sprintf(Buff, NodeMenuHeader, Mycall); - - for (i=1; i <= MAXBPQPORTS; i++) - { - TNC = TNCInfo[i]; - if (TNC == NULL) - continue; - - if (TNC->WebWindowProc) - { - Len += sprintf(&Buff[Len], NodeMenuLine, i, TNC->WebWinX, TNC->WebWinY, top, left); - top += 22; - left += 22; - } - } - - Len += sprintf(&Buff[Len], NodeMenuRest, Mycall, - DriverBit, - (APRSWeb)?APRSBit:"", - (IncludesMail)?MailBit:"", (IncludesChat)?ChatBit:"", (LOCAL)?"":SigninBit, NodeTail); - - return Len; -} - -VOID SaveConfigFile(SOCKET sock , char * MsgPtr, char * Rest, int LOCAL) -{ - int ReplyLen = 0; - char * ptr, * ptr1, * ptr2, *input; - char c; - int MsgLen, WriteLen = 0; - char inputname[250]="bpq32.cfg"; - FILE *fp1; - char Header[256]; - int HeaderLen; - char Reply[4096]; - char Mess[256]; - char Backup1[MAX_PATH]; - char Backup2[MAX_PATH]; - struct stat STAT; - - input = strstr(MsgPtr, "\r\n\r\n"); // End of headers - - if (input) - { - if (strstr(input, "Cancel=Cancel")) - { - ReplyLen = SetupNodeMenu(Reply, LOCAL); - // ReplyLen = sprintf(Reply, "%s", ""); - HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n", ReplyLen + (int)strlen(Tail)); - send(sock, Header, HeaderLen, 0); - send(sock, Reply, ReplyLen, 0); - send(sock, Tail, (int)strlen(Tail), 0); - 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; - - c = m * 16 + n; - } - else if (c == '+') - c = ' '; - -#ifndef WIN32 - if (c != 13) // Strip CR if Linux -#endif - *(ptr2++) = c; - - c = *(ptr1++); - - } - - *(ptr2++) = 0; - - MsgLen = (int)strlen(input + 8); - - if (BPQDirectory[0] == 0) - { - strcpy(inputname, "bpq32.cfg"); - } - else - { - strcpy(inputname,BPQDirectory); - strcat(inputname,"/"); - strcat(inputname, "bpq32.cfg"); - } - - // Make a backup of the config - - // Keep 4 Generations - - strcpy(Backup2, inputname); - strcat(Backup2, ".bak.3"); - - strcpy(Backup1, inputname); - strcat(Backup1, ".bak.2"); - - DeleteFile(Backup2); // Remove old .bak.3 - MoveFile(Backup1, Backup2); // Move .bak.2 to .bak.3 - - strcpy(Backup2, inputname); - strcat(Backup2, ".bak.1"); - - MoveFile(Backup2, Backup1); // Move .bak.1 to .bak.2 - - strcpy(Backup1, inputname); - strcat(Backup1, ".bak"); - - MoveFile(Backup1, Backup2); // Move .bak to .bak.1 - - CopyFile(inputname, Backup1, FALSE); // Copy to .bak - - // Get length to compare with new length - - stat(inputname, &STAT); - - fp1 = fopen(inputname, "wb"); - - if (fp1) - { - WriteLen = (int)fwrite(input + 8, 1, MsgLen, fp1); - fclose(fp1); - } - - if (WriteLen != MsgLen) - sprintf_s(Mess, sizeof(Mess), "Failed to write Config File"); - else - sprintf_s(Mess, sizeof(Mess), "Configuration Saved, Orig Length %d New Length %d", - STAT.st_size, MsgLen); - } - - ReplyLen = sprintf(Reply, "", Mess); - HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n", ReplyLen + (int)strlen(Tail)); - send(sock, Header, HeaderLen, 0); - send(sock, Reply, ReplyLen, 0); - send(sock, Tail, (int)strlen(Tail), 0); - } - return; -} - -// Compress using deflate. Caller must free output buffer after use - -unsigned char * Compressit(unsigned char * In, int Len, int * OutLen) -{ - z_stream defstream; - int maxSize; - unsigned char * Out; - - defstream.zalloc = Z_NULL; - defstream.zfree = Z_NULL; - defstream.opaque = Z_NULL; - - defstream.avail_in = Len; // size of input - defstream.next_in = (Bytef *)In; // input char array - - deflateInit(&defstream, Z_BEST_COMPRESSION); - maxSize = deflateBound(&defstream, Len); - - Out = malloc(maxSize); - - defstream.avail_out = maxSize; // size of output - defstream.next_out = (Bytef *)Out; // output char array - - deflate(&defstream, Z_FINISH); - deflateEnd(&defstream); - - *OutLen = defstream.total_out; - - return Out; -} - - -int InnerProcessHTTPMessage(struct ConnectionInfo * conn) -{ - struct TCPINFO * TCP = conn->TNC->TCPInfo; - SOCKET sock = conn->socket; - char * MsgPtr = conn->InputBuffer; - int MsgLen = conn->InputLen; - int InputLen = 0; - int OutputLen = 0; - int Bufferlen; - struct HTTPConnectionInfo CI; - struct HTTPConnectionInfo * sockptr = &CI; - struct HTTPConnectionInfo * Session = NULL; - - char URL[100000]; - char * ptr; - char * encPtr = 0; - int allowDeflate = 0; - char * Compressed = 0; - char * HostPtr = 0; - - char * Context, * Method, * NodeURL, * Key; - char _REPLYBUFFER[250000]; - char Reply[250000]; - - int ReplyLen = 0; - char Header[256]; - int HeaderLen; - char TimeString[64]; - BOOL LOCAL = FALSE; - BOOL COOKIE = FALSE; - int Len; - char * WebSock = 0; - - char PortsHddr[] = "

Ports

" - ""; - - char PortLine[] = ""; - - char PortLineWithBeacon[] = "" - "\r\n"; - - char SessionPortLine[] = "" - "\r\n"; - - char PortLineWithDriver[] = "" - "\r\n"; - - - char PortLineWithBeaconAndDriver[] = "" - "" - "\r\n"; - - char RigControlLine[] = "" - "\r\n"; - - - char Encoding[] = "Content-Encoding: deflate\r\n"; - -#ifdef WIN32 - - struct _EXCEPTION_POINTERS exinfo; - strcpy(EXCEPTMSG, "ProcessHTTPMessage"); - - __try { -#endif - - Len = (int)strlen(MsgPtr); - if (Len > 100000) - return 0; - - strcpy(URL, MsgPtr); - - HostPtr = strstr(MsgPtr, "Host: "); - - WebSock = strstr(MsgPtr, "Upgrade"); - - if (HostPtr) - { - uint32_t Host; - char Hostname[32]= ""; - struct LOCALNET * LocalNet = conn->TNC->TCPInfo->LocalNets; - - HostPtr += 6; - memcpy(Hostname, HostPtr, 31); - strlop(Hostname, ':'); - Host = inet_addr(Hostname); - - if (strcmp(Hostname, "127.0.0.1") == 0) - LOCAL = TRUE; - else - { - if (conn->sin.sin_family != AF_INET6) - { - while(LocalNet) - { - uint32_t MaskedHost = conn->sin.sin_addr.s_addr & LocalNet->Mask; - if (MaskedHost == LocalNet->Network) - { - LOCAL = 1; - break; - } - LocalNet = LocalNet->Next; - } - } - } - } - - encPtr = stristr(MsgPtr, "Accept-Encoding:"); - - if (encPtr && stristr(encPtr, "deflate")) - allowDeflate = 1; - else - Encoding[0] = 0; - - ptr = strstr(MsgPtr, "BPQSessionCookie=N"); - - if (ptr) - { - COOKIE = TRUE; - Key = ptr + 17; - ptr = strchr(Key, ','); - if (ptr) - { - *ptr = 0; - Session = FindSession(Key); - *ptr = ','; - } - else - { - ptr = strchr(Key, 13); - if (ptr) - { - *ptr = 0; - Session = FindSession(Key); - *ptr = 13; - } - } - } - - if (WebSock) - { - // Websock connection request - Reply and remember state. - - char KeyMsg[128]; - char Webx[] = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; // Fixed UID - char Hash[64] = ""; - char * Hash64; // base 64 version - char * ptr; - - //Sec-WebSocket-Key: l622yZS3n+zI+hR6SVWkPw== - - char ReplyMsg[] = - "HTTP/1.1 101 Switching Protocols\r\n" - "Upgrade: websocket\r\n" - "Connection: Upgrade\r\n" - "Sec-WebSocket-Accept: %s\r\n" -// "Sec-WebSocket-Protocol: chat\r\n" - "\r\n"; - - ptr = strstr(MsgPtr, "Sec-WebSocket-Key:"); - - if (ptr) - { - ptr += 18; - while (*ptr == ' ') - ptr++; - - memcpy(KeyMsg, ptr, 40); - strlop(KeyMsg, 13); - strlop(KeyMsg, ' '); - strcat(KeyMsg, Webx); - - SHA1PasswordHash(KeyMsg, Hash); - Hash64 = byte_base64_encode(Hash, 20); - - conn->WebSocks = 1; - strlop(&URL[4], ' '); - strcpy(conn->WebURL, &URL[4]); - - ReplyLen = sprintf(Reply, ReplyMsg, Hash64); - - free(Hash64); - goto Returnit; - - } - } - - - ptr = strstr(URL, " HTTP"); - - if (ptr) - *ptr = 0; - - Method = strtok_s(URL, " ", &Context); - - memcpy(Mycall, &MYNODECALL, 10); - strlop(Mycall, ' '); - - - // APRS process internally - - if (_memicmp(Context, "/APRS/", 6) == 0 || _stricmp(Context, "/APRS") == 0) - { - APRSProcessHTTPMessage(sock, MsgPtr, LOCAL, COOKIE); - return 0; - } - - - if (_stricmp(Context, "/Node/Signon?Node") == 0) - { - char * IContext; - - NodeURL = strtok_s(Context, "?", &IContext); - Key = strtok_s(NULL, "?", &IContext); - - ProcessNodeSignon(sock, TCP, MsgPtr, Key, Reply, &Session, LOCAL); - return 0; - - } - - // If for Mail or Chat, check for a session, and send login screen if necessary - - // Moved here to simplify operation with both internal and external clients - - if (_memicmp(Context, "/Mail/", 6) == 0) - { - int RLen = 0; - char Appl; - char * input; - char * IContext; - - NodeURL = strtok_s(Context, "?", &IContext); - Key = strtok_s(NULL, "?", &IContext); - - if (_stricmp(NodeURL, "/Mail/Signon") == 0) - { - ReplyLen = ProcessMailSignon(TCP, MsgPtr, Key, Reply, &Session, FALSE, LOCAL); - - if (ReplyLen) - { - goto Returnit; - } - -#ifdef LINBPQ - strcpy(Context, "/Mail/Header"); -#else - strcpy(MsgPtr, "POST /Mail/Header"); -#endif - goto doHeader; - } - - if (_stricmp(NodeURL, "/Mail/Lost") == 0) - { - input = strstr(MsgPtr, "\r\n\r\n"); // End of headers - - if (input && strstr(input, "Cancel=Exit")) - { - ReplyLen = SetupNodeMenu(Reply, LOCAL); - RLen = ReplyLen; - goto Returnit; - } - if (Key) - Appl = Key[0]; - - Key = 0; - } - - if (Key == 0 || Key[0] == 0) - { - // No Session - - // if not local send a signon screen, else create a user session - - if (LOCAL || COOKIE) - { - Session = AllocateSession(sock, 'M'); - - if (Session) - { - strcpy(Context, "/Mail/Header"); - goto doHeader; - } - else - { - ReplyLen = SetupNodeMenu(Reply, LOCAL); - ReplyLen += sprintf(&Reply[ReplyLen], "%s", BusyError); - } - RLen = ReplyLen; - - goto Returnit; - - } - - ReplyLen = sprintf(Reply, MailSignon, Mycall, Mycall); - - RLen = ReplyLen; - goto Returnit; - } - - Session = FindSession(Key); - - if (Session == NULL) - { - ReplyLen = sprintf(Reply, MailLostSession, Key); - RLen = ReplyLen; - goto Returnit; - } - } - - if (_memicmp(Context, "/Chat/", 6) == 0) - { - int RLen = 0; - char Appl; - char * input; - char * IContext; - - - HostPtr = strstr(MsgPtr, "Host: "); - - if (HostPtr) - { - uint32_t Host; - char Hostname[32]= ""; - struct LOCALNET * LocalNet = conn->TNC->TCPInfo->LocalNets; - - HostPtr += 6; - memcpy(Hostname, HostPtr, 31); - strlop(Hostname, ':'); - Host = inet_addr(Hostname); - - if (strcmp(Hostname, "127.0.0.1") == 0) - LOCAL = TRUE; - else while(LocalNet) - { - uint32_t MaskedHost = Host & LocalNet->Mask; - if (MaskedHost == LocalNet->Network) - { - char * rest; - LOCAL = 1; - rest = strchr(HostPtr, 13); - if (rest) - { - memmove(HostPtr + 9, rest, strlen(rest) + 1); - memcpy(HostPtr, "127.0.0.1", 9); - break; - } - } - LocalNet = LocalNet->Next; - } - } - - NodeURL = strtok_s(Context, "?", &IContext); - Key = strtok_s(NULL, "?", &IContext); - - if (_stricmp(NodeURL, "/Chat/Signon") == 0) - { - ReplyLen = ProcessChatSignon(TCP, MsgPtr, Key, Reply, &Session, LOCAL); - - if (ReplyLen) - { - goto Returnit; - } - -#ifdef LINBPQ - strcpy(Context, "/Chat/Header"); -#else - strcpy(MsgPtr, "POST /Chat/Header"); -#endif - goto doHeader; - } - - if (_stricmp(NodeURL, "/Chat/Lost") == 0) - { - input = strstr(MsgPtr, "\r\n\r\n"); // End of headers - - if (input && strstr(input, "Cancel=Exit")) - { - ReplyLen = SetupNodeMenu(Reply, LOCAL); - RLen = ReplyLen; - goto Returnit; - } - if (Key) - Appl = Key[0]; - - Key = 0; - } - - if (Key == 0 || Key[0] == 0) - { - // No Session - - // if not local send a signon screen, else create a user session - - if (LOCAL || COOKIE) - { - Session = AllocateSession(sock, 'C'); - - if (Session) - { - strcpy(Context, "/Chat/Header"); - goto doHeader; - } - else - { - ReplyLen = SetupNodeMenu(Reply, LOCAL); - ReplyLen += sprintf(&Reply[ReplyLen], "%s", BusyError); - } - RLen = ReplyLen; - - goto Returnit; - - } - - ReplyLen = sprintf(Reply, ChatSignon, Mycall, Mycall); - - RLen = ReplyLen; - goto Returnit; - } - - Session = FindSession(Key); - - if (Session == NULL) - { - int Sent, Loops = 0; - ReplyLen = sprintf(Reply, MailLostSession, Key); - RLen = ReplyLen; -Returnit: - if (memcmp(Reply, "HTTP", 4) == 0) - { - // Full Header provided by appl - just send it - - // Send may block - - Sent = send(sock, Reply, ReplyLen, 0); - - while (Sent != ReplyLen && Loops++ < 3000) // 100 secs max - { - // Debugprintf("%d out of %d sent %d Loops", Sent, InputLen, Loops); - - if (Sent > 0) // something sent - { - InputLen -= Sent; - memmove(Reply, &Reply[Sent], ReplyLen); - } - - Sleep(30); - Sent = send(sock, Reply, ReplyLen, 0); - } - - return 0; - } - - // Add tail - - strcpy(&Reply[ReplyLen], Tail); - ReplyLen += strlen(Tail); - - // compress if allowed - - if (allowDeflate) - Compressed = Compressit(Reply, ReplyLen, &ReplyLen); - 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); - sendandcheck(sock, Header, HeaderLen); - sendandcheck(sock, Compressed, ReplyLen); - - if (allowDeflate) - free (Compressed); - - return 0; - } - } - -doHeader: - -#ifdef LINBPQ - - if ((_memicmp(Context, "/MAIL/", 6) == 0) || (_memicmp(Context, "/WebMail", 8) == 0)) - { - char _REPLYBUFFER[250000]; - struct HTTPConnectionInfo Dummy = {0}; - int Sent, Loops = 0; - - ReplyLen = 0; - - if (Session == 0) - Session = &Dummy; - - Session->TNC = (void *)LOCAL; // TNC only used for Web Terminal Sessions - - ProcessMailHTTPMessage(Session, Method, Context, MsgPtr, _REPLYBUFFER, &ReplyLen, MsgLen); - - if (memcmp(_REPLYBUFFER, "HTTP", 4) == 0) - { - // Full Header provided by appl - just send it - - // Send may block - - Sent = send(sock, _REPLYBUFFER, ReplyLen, 0); - - while (Sent != ReplyLen && Loops++ < 3000) // 100 secs max - { - // Debugprintf("%d out of %d sent %d Loops", Sent, InputLen, Loops); - - if (Sent > 0) // something sent - { - InputLen -= Sent; - memmove(_REPLYBUFFER, &_REPLYBUFFER[Sent], ReplyLen); - } - - Sleep(30); - Sent = send(sock, _REPLYBUFFER, ReplyLen, 0); - } - return 0; - } - - // Add tail - - strcpy(&_REPLYBUFFER[ReplyLen], Tail); - ReplyLen += strlen(Tail); - - // compress if allowed - - if (allowDeflate) - Compressed = Compressit(_REPLYBUFFER, ReplyLen, &ReplyLen); - 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); - sendandcheck(sock, Header, HeaderLen); - sendandcheck(sock, Compressed, ReplyLen); - - if (allowDeflate) - free (Compressed); - - return 0; - - -/* - - HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n", ReplyLen + (int)strlen(Tail)); - send(sock, Header, HeaderLen, 0); - - // Send may block - - Sent = send(sock, _REPLYBUFFER, ReplyLen, 0); - - if (Sent == -1) - return 0; - - while (Sent != ReplyLen && Loops++ < 3000) // 100 secs max - { - // Debugprintf("%d out of %d sent %d Loops", Sent, InputLen, Loops); - - if (Sent > 0) // something sent - { - InputLen -= Sent; - memmove(_REPLYBUFFER, &_REPLYBUFFER[Sent], ReplyLen); - } - - Sleep(30); - Sent = send(sock, _REPLYBUFFER, ReplyLen, 0); - } - - send(sock, Tail, (int)strlen(Tail), 0); - return 0; -*/ - } - - if (_memicmp(Context, "/CHAT/", 6) == 0) - { - char _REPLYBUFFER[100000]; - - ReplyLen = 0; - - ProcessChatHTTPMessage(Session, Method, Context, MsgPtr, _REPLYBUFFER, &ReplyLen); - - HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n", ReplyLen + (int)strlen(Tail)); - send(sock, Header, HeaderLen, 0); - send(sock, _REPLYBUFFER, ReplyLen, 0); - send(sock, Tail, (int)strlen(Tail), 0); - - return 0; - - } - - - /* - Sent = send(sock, _REPLYBUFFER, InputLen, 0); - - while (Sent != InputLen && Loops++ < 3000) // 100 secs max - { - // Debugprintf("%d out of %d sent %d Loops", Sent, InputLen, Loops); - - if (Sent > 0) // something sent - { - InputLen -= Sent; - memmove(_REPLYBUFFER, &_REPLYBUFFER[Sent], InputLen); - } - - Sleep(30); - Sent = send(sock, _REPLYBUFFER, InputLen, 0); - } - return 0; - } - */ -#else - - // Pass to MailChat if active - - if ((_memicmp(Context, "/MAIL/", 6) == 0) || (_memicmp(Context, "/WebMail", 8) == 0)) - { - // If for Mail, Pass to Mail Server via Named Pipe - - HANDLE hPipe; - - hPipe = CreateFile(MAILPipeFileName, GENERIC_READ | GENERIC_WRITE, - 0, // exclusive access - NULL, // no security attrs - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - NULL ); - - if (hPipe == (HANDLE)-1) - { - InputLen = sprintf(Reply, "HTTP/1.1 404 Not Found\r\nContent-Length: 28\r\n\r\nMail Data is not available\r\n"); - send(sock, Reply, InputLen, 0); - } - else - { - // int Sent; - int Loops = 0; - struct HTTPConnectionInfo Dummy = {0}; - - if (Session == 0) - Session = &Dummy; - - Session->TNC = LOCAL; // TNC is only used on Web Terminal Sessions so can reuse as LOCAL flag - - WriteFile(hPipe, Session, sizeof (struct HTTPConnectionInfo), &InputLen, NULL); - WriteFile(hPipe, MsgPtr, MsgLen, &InputLen, NULL); - - - ReadFile(hPipe, Session, sizeof (struct HTTPConnectionInfo), &InputLen, NULL); - ReadFile(hPipe, Reply, 250000, &ReplyLen, NULL); - if (ReplyLen <= 0) - { - InputLen = GetLastError(); - } - - CloseHandle(hPipe); - goto Returnit; - } - return 0; - } - - if (_memicmp(Context, "/CHAT/", 6) == 0) - { - HANDLE hPipe; - - hPipe = CreateFile(CHATPipeFileName, GENERIC_READ | GENERIC_WRITE, - 0, // exclusive access - NULL, // no security attrs - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - NULL ); - - if (hPipe == (HANDLE)-1) - { - InputLen = sprintf(Reply, "HTTP/1.1 404 Not Found\r\nContent-Length: 28\r\n\r\nChat Data is not available\r\n"); - send(sock, Reply, InputLen, 0); - } - else - { - // int Sent; - int Loops = 0; - - WriteFile(hPipe, Session, sizeof (struct HTTPConnectionInfo), &InputLen, NULL); - WriteFile(hPipe, MsgPtr, MsgLen, &InputLen, NULL); - - - ReadFile(hPipe, Session, sizeof (struct HTTPConnectionInfo), &InputLen, NULL); - ReadFile(hPipe, Reply, 100000, &ReplyLen, NULL); - if (ReplyLen <= 0) - { - InputLen = GetLastError(); - } - - CloseHandle(hPipe); - goto Returnit; - } - return 0; - } - -#endif - - NodeURL = strtok_s(NULL, "?", &Context); - - if (NodeURL == NULL) - return 0; - - if (strcmp(Method, "POST") == 0) - { - if (_stricmp(NodeURL, "/Node/freqOffset") == 0) - { - char * input = strstr(MsgPtr, "\r\n\r\n"); // End of headers - int port = atoi(Context); - - if (input == 0) - return 1; - - input += 4; - - if (port > 0 && port <= MaxBPQPortNo) - { - struct TNCINFO * TNC = TNCInfo[port]; - char value[6]; - - if (TNC == 0) - return 1; - - TNC->TXOffset = atoi(input); -#ifdef WIN32 - sprintf(value, "%d", TNC->TXOffset); - MySetWindowText(TNC->xIDC_TXTUNEVAL, value); - SendMessage(TNC->xIDC_TXTUNE, TBM_SETPOS, (WPARAM) TRUE, (LPARAM) TNC->TXOffset); // min. & max. positions - -#endif - } - return 1; - } - - if (_stricmp(NodeURL, "/Node/PortAction") == 0) - { - char * input = strstr(MsgPtr, "\r\n\r\n"); // End of headers - int port = atoi(Context); - - if (input == 0) - return 1; - - input += 4; - - if (port > 0 && port <= MaxBPQPortNo) - { - struct TNCINFO * TNC = TNCInfo[port]; - - if (TNC == 0) - return 1; - - if (LOCAL == FALSE && COOKIE == FALSE) - return 1; - - if (strcmp(input, "Abort") == 0) - { - if (TNC->ForcedCloseProc) - TNC->ForcedCloseProc(TNC, 0); - } - else if (strcmp(input, "Kill") == 0) - { - TNC->DontRestart = TRUE; - KillTNC(TNC); - } - else if (strcmp(input, "KillRestart") == 0) - { - TNC->DontRestart = FALSE; - KillTNC(TNC); - RestartTNC(TNC); - - } - } - return 1; - } - - if (_stricmp(NodeURL, "/TermInput") == 0) - { - ProcessTermInput(sock, MsgPtr, MsgLen, Context); - return 0; - } - - if (_stricmp(NodeURL, "/Node/TermSignon") == 0) - { - ProcessTermSignon(conn->TNC, sock, MsgPtr, MsgLen, LOCAL); - } - - if (_stricmp(NodeURL, "/Node/Signon") == 0) - { - ProcessNodeSignon(sock, TCP, MsgPtr, Key, Reply, &Session, LOCAL); - return 0; - } - - if (_stricmp(NodeURL, "/Node/TermClose") == 0) - { - ProcessTermClose(sock, MsgPtr, MsgLen, Context, LOCAL); - return 0; - } - - if (_stricmp(NodeURL, "/Node/BeaconAction") == 0) - { - char Header[256]; - int HeaderLen; - char * input = strstr(MsgPtr, "\r\n\r\n"); // End of headers - int Port; - char Param[100]; -#ifndef LINBPQ - int retCode, disp; - char Key[80]; - HKEY hKey; -#endif - struct PORTCONTROL * PORT; - int Slot = 0; - - - if (LOCAL == FALSE && COOKIE == FALSE) - { - // Send Not Authorized - - ReplyLen = SetupNodeMenu(_REPLYBUFFER, LOCAL); - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "
Not authorized - please sign in"); - HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n", ReplyLen + (int)strlen(Tail)); - send(sock, Header, HeaderLen, 0); - send(sock, _REPLYBUFFER, ReplyLen, 0); - send(sock, Tail, (int)strlen(Tail), 0); - - return 1; - } - - if (strstr(input, "Cancel=Cancel")) - { - ReplyLen = SetupNodeMenu(_REPLYBUFFER, LOCAL); - HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n", ReplyLen + (int)strlen(Tail)); - send(sock, Header, HeaderLen, 0); - send(sock, _REPLYBUFFER, ReplyLen, 0); - send(sock, Tail, (int)strlen(Tail), 0); - - return 1; - } - - GetParam(input, "Port", &Param[0]); - Port = atoi(&Param[1]); - PORT = GetPortTableEntryFromPortNum(Port); // Need slot not number - if (PORT) - Slot = PORT->PortSlot; - - GetParam(input, "Every", &Param[0]); - Interval[Slot] = atoi(&Param[1]); - - GetParam(input, "Dest", &Param[0]); - _strupr(Param); - strcpy(UIUIDEST[Slot], &Param[1]); - - GetParam(input, "Path", &Param[0]); - _strupr(Param); - if (UIUIDigi[Slot]) - free(UIUIDigi[Slot]); - UIUIDigi[Slot] = _strdup(&Param[1]); - - GetParam(input, "File", &Param[0]); - strcpy(FN[Slot], &Param[1]); - GetParam(input, "Text", &Param[0]); - strcpy(Message[Slot], &Param[1]); - - MinCounter[Slot] = Interval[Slot]; - - SendFromFile[Slot] = 0; - - if (FN[Slot][0]) - SendFromFile[Slot] = 1; - - SetupUI(Slot); - -#ifdef LINBPQ - SaveUIConfig(); -#else - SaveUIConfig(); - - wsprintf(Key, "SOFTWARE\\G8BPQ\\BPQ32\\UIUtil\\UIPort%d", Port); - - retCode = RegCreateKeyEx(REGTREE, - Key, 0, 0, 0, KEY_ALL_ACCESS, NULL, &hKey, &disp); - - if (retCode == ERROR_SUCCESS) - { - retCode = RegSetValueEx(hKey, "UIDEST", 0, REG_SZ,(BYTE *)&UIUIDEST[Port][0], strlen(&UIUIDEST[Port][0])); - retCode = RegSetValueEx(hKey, "FileName", 0, REG_SZ,(BYTE *)&FN[Port][0], strlen(&FN[Port][0])); - retCode = RegSetValueEx(hKey, "Message", 0, REG_SZ,(BYTE *)&Message[Port][0], strlen(&Message[Port][0])); - retCode = RegSetValueEx(hKey, "Interval", 0, REG_DWORD,(BYTE *)&Interval[Port], 4); - retCode = RegSetValueEx(hKey, "SendFromFile", 0, REG_DWORD,(BYTE *)&SendFromFile[Port], 4); - retCode = RegSetValueEx(hKey, "Digis",0, REG_SZ, UIUIDigi[Port], strlen(UIUIDigi[Port])); - - RegCloseKey(hKey); - } -#endif - if (strstr(input, "Test=Test")) - SendUIBeacon(Slot); - - - ReplyLen = SetupNodeMenu(_REPLYBUFFER, LOCAL); - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], Beacons, Port, - Interval[Slot], &UIUIDEST[Slot][0], &UIUIDigi[Slot][0], &FN[Slot][0], &Message[Slot][0], Port); - - HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n", ReplyLen + (int)strlen(Tail)); - send(sock, Header, HeaderLen, 0); - send(sock, _REPLYBUFFER, ReplyLen, 0); - send(sock, Tail, (int)strlen(Tail), 0); - - return 1; - } - - if (_stricmp(NodeURL, "/Node/CfgSave") == 0) - { - // Save Config File - - SaveConfigFile(sock, MsgPtr, Key, LOCAL); - return 0; - } - - if (_stricmp(NodeURL, "/Node/LogAction") == 0) - { - ReplyLen = SetupNodeMenu(_REPLYBUFFER, LOCAL); - HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n", ReplyLen + (int)strlen(Tail)); - send(sock, Header, HeaderLen, 0); - send(sock, _REPLYBUFFER, ReplyLen, 0); - send(sock, Tail, (int)strlen(Tail), 0); - - return 1; - } - - - if (_stricmp(NodeURL, "/Node/ARDOPAbort") == 0) - { - int port = atoi(Context); - - if (port > 0 && port <= MaxBPQPortNo) - { - struct TNCINFO * TNC = TNCInfo[port]; - - if (TNC && TNC->ForcedCloseProc) - TNC->ForcedCloseProc(TNC, 0); - - - if (TNC && TNC->WebWindowProc) - ReplyLen = TNC->WebWindowProc(TNC, _REPLYBUFFER, LOCAL); - - - ReplyLen = sprintf(Reply, "", "Ok"); - HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n", ReplyLen + (int)strlen(Tail)); - send(sock, Header, HeaderLen, 0); - send(sock, Reply, ReplyLen, 0); - send(sock, Tail, (int)strlen(Tail), 0); - - // goto SendResp; - - // HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n", ReplyLen + strlen(Tail)); - // send(sock, Header, HeaderLen, 0); - // send(sock, _REPLYBUFFER, ReplyLen, 0); - // send(sock, Tail, strlen(Tail), 0); - - return 1; - } - - } - - send(sock, _REPLYBUFFER, InputLen, 0); - return 0; - } - - if (_stricmp(NodeURL, "/") == 0 || _stricmp(NodeURL, "/Index.html") == 0) - { - // Send if present, else use default - - Bufferlen = SendMessageFile(sock, NodeURL, TRUE, allowDeflate); // return -1 if not found - - if (Bufferlen != -1) - return 0; // We've sent it - else - { - if (APRSApplConnected) - ReplyLen = sprintf(_REPLYBUFFER, Index, Mycall, Mycall); - else - ReplyLen = sprintf(_REPLYBUFFER, IndexNoAPRS, Mycall, Mycall); - - HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n", ReplyLen + (int)strlen(Tail)); - send(sock, Header, HeaderLen, 0); - send(sock, _REPLYBUFFER, ReplyLen, 0); - send(sock, Tail, (int)strlen(Tail), 0); - - return 0; - } - } - - else if (_stricmp(NodeURL, "/NodeMenu.html") == 0 || _stricmp(NodeURL, "/Node/NodeMenu.html") == 0) - { - // Send if present, else use default - - char Menu[] = "/NodeMenu.html"; - - Bufferlen = SendMessageFile(sock, Menu, TRUE, allowDeflate); // return -1 if not found - - if (Bufferlen != -1) - return 0; // We've sent it - } - - else if (_memicmp(NodeURL, "/aisdata.txt", 12) == 0) - { - char * Compressed; - ReplyLen = GetAISPageInfo(_REPLYBUFFER, 1, 1); - - if (allowDeflate) - Compressed = Compressit(_REPLYBUFFER, ReplyLen, &ReplyLen); - else - Compressed = _REPLYBUFFER; - - HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: Text\r\n%s\r\n", ReplyLen, Encoding); - sendandcheck(sock, Header, HeaderLen); - sendandcheck(sock, Compressed, ReplyLen); - - if (allowDeflate) - free (Compressed); - - return 0; - } - - else if (_memicmp(NodeURL, "/aprsdata.txt", 13) == 0) - { - char * Compressed; - char * ptr; - double N, S, W, E; - int aprs = 1, ais = 1, adsb = 1; - - ptr = &NodeURL[14]; - - N = atof(ptr); - ptr = strlop(ptr, '|'); - S = atof(ptr); - ptr = strlop(ptr, '|'); - W = atof(ptr); - ptr = strlop(ptr, '|'); - E = atof(ptr); - ptr = strlop(ptr, '|'); - if (ptr) - { - aprs = atoi(ptr); - ptr = strlop(ptr, '|'); - ais = atoi(ptr); - ptr = strlop(ptr, '|'); - adsb = atoi(ptr); - } - ReplyLen = GetAPRSPageInfo(_REPLYBUFFER, N, S, W, E, aprs, ais, adsb); - - if (ReplyLen < 240000) - ReplyLen += GetAISPageInfo(&_REPLYBUFFER[ReplyLen], ais, adsb); - - if (allowDeflate) - Compressed = Compressit(_REPLYBUFFER, ReplyLen, &ReplyLen); - else - Compressed = _REPLYBUFFER; - - HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: %d\r\nContent-Type: Text\r\n%s\r\n", ReplyLen, Encoding); - sendandcheck(sock, Header, HeaderLen); - sendandcheck(sock, Compressed, ReplyLen); - - if (allowDeflate) - free (Compressed); - - return 0; - } - - else if (_memicmp(NodeURL, "/Icon", 5) == 0 && _memicmp(&NodeURL[10], ".png", 4) == 0) - { - // APRS internal Icon - - char * Compressed; - - ReplyLen = GetAPRSIcon(_REPLYBUFFER, NodeURL); - - if (allowDeflate) - Compressed = Compressit(_REPLYBUFFER, ReplyLen, &ReplyLen); - else - Compressed = _REPLYBUFFER; - - HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: Text\r\n%s\r\n", ReplyLen, Encoding); - sendandcheck(sock, Header, HeaderLen); - sendandcheck(sock, Compressed, ReplyLen); - - if (allowDeflate) - free (Compressed); - - return 0; - - } - - else if (_memicmp(NodeURL, "/NODE/", 6)) - { - // Not Node, See if a local file - - Bufferlen = SendMessageFile(sock, NodeURL, FALSE, allowDeflate); // Send error if not found - return 0; - } - - // Node URL - - { - - ReplyLen = SetupNodeMenu(_REPLYBUFFER, LOCAL); - - if (_stricmp(NodeURL, "/Node/webproc.css") == 0) - { - char WebprocCSS[] = - ".dropbtn {position: relative; border: 1px solid black;padding:1px;}\r\n" - ".dropdown {position: relative; display: inline-block;}\r\n" - ".dropdown-content {display: none; position: absolute;background-color: #ccc; " - "min-width: 160px; box-shadow: 0px 8px 16px 0px rgba(0,0,00.2); z-index: 1;}\r\n" - ".dropdown-content a {color: black; padding: 1px 1px;text-decoration:none;display:block;}" - ".dropdown-content a:hover {background-color: #dddfff;}\r\n" - ".dropdown:hover .dropdown-content {display: block;}\r\n" - ".dropdown:hover .dropbtn {background-color: #ddd;}\r\n" - "input.btn:active {background:black;color:white;}\r\n" - "submit.btn:active {background:black;color:white;}\r\n"; - ReplyLen = sprintf(_REPLYBUFFER, "%s", WebprocCSS); - } - - else if (_stricmp(NodeURL, "/Node/Killandrestart") == 0) - { - int port = atoi(Context); - - if (port > 0 && port <= MaxBPQPortNo) - { - struct TNCINFO * TNC = TNCInfo[port]; - - KillTNC(TNC); - TNC->DontRestart = FALSE; - RestartTNC(TNC); - - if (TNC && TNC->WebWindowProc) - ReplyLen = TNC->WebWindowProc(TNC, _REPLYBUFFER, LOCAL); - - } - } - - else if (_stricmp(NodeURL, "/Node/Port") == 0 || _stricmp(NodeURL, "/Node/ARDOPAbort") == 0) - { - int port = atoi(Context); - - if (port > 0 && port <= MaxBPQPortNo) - { - struct TNCINFO * TNC = TNCInfo[port]; - - if (TNC && TNC->WebWindowProc) - ReplyLen = TNC->WebWindowProc(TNC, _REPLYBUFFER, LOCAL); - } - - } - - else if (_stricmp(NodeURL, "/Node/Streams") == 0) - { - ReplyLen = StatusProc(_REPLYBUFFER); - } - - else if (_stricmp(NodeURL, "/Node/Stats.html") == 0) - { - struct tm * TM; - char UPTime[50]; - time_t szClock = STATSTIME * 60; - - TM = gmtime(&szClock); - - sprintf(UPTime, "%.2d:%.2d:%.2d", TM->tm_yday, TM->tm_hour, TM->tm_min); - - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "%s", StatsHddr); - - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "", - "Version", VersionString); - - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "", - "Uptime (Days Hours Mins)", UPTime); - - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "", - "Semaphore: Get-Rel/Clashes", Semaphore.Gets - Semaphore.Rels, Semaphore.Clashes); - - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "", - "Buffers: Max/Cur/Min/Out/Wait", MAXBUFFS, QCOUNT, MINBUFFCOUNT, NOBUFFCOUNT, BUFFERWAITS); - - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "", - "Known Nodes/Max Nodes", NUMBEROFNODES, MAXDESTS); - - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "", - "L4 Connects Sent/Rxed ", L4CONNECTSOUT, L4CONNECTSIN); - - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "", - "L4 Frames TX/RX/Resent/Reseq", L4FRAMESTX, L4FRAMESRX, L4FRAMESRETRIED, OLDFRAMES); - - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "", - "L3 Frames Relayed", L3FRAMES); - - } - - else if (_stricmp(NodeURL, "/Node/RigControl.html") == 0) - { - char Test[] = - "\r\n" - "Rigcontrol\r\n" - "\r\n" - "\r\n" - "\r\n" - "
Waiting for data...
\r\n" - "\r\n"; - - - char NoRigCtl[] = - "\r\n" - "Rigcontrol\r\n" - "\r\n" - "\r\n" - "
RigControl Not Configured...
\r\n" - "\r\n"; - - if (RigWebPage) - ReplyLen = sprintf(_REPLYBUFFER, "%s", Test); - else - ReplyLen = sprintf(_REPLYBUFFER, "%s", NoRigCtl); - } - - else if (_stricmp(NodeURL, "/Node/ShowLog.html") == 0) - { - char ShowLogPage[] = - "" - "" - "Log Display" - "" - "
" - "
" -// "" - "" - "" - "
"; - - char * _REPLYBUFFER; - int ReplyLen; - char Header[256]; - int HeaderLen; - char * CfgBytes; - int CfgLen; - char inputname[250]; - FILE *fp1; - struct stat STAT; - char DummyKey[] = "DummyKey"; - time_t T; - struct tm * tm; - char Name[64] = ""; - - T = time(NULL); - tm = gmtime(&T); - - if (LOCAL == FALSE && COOKIE == FALSE) - { - // Send Not Authorized - - char _REPLYBUFFER[4096]; - ReplyLen = SetupNodeMenu(_REPLYBUFFER, LOCAL); - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "
Not authorized - please sign in"); - HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n", ReplyLen + (int)strlen(Tail)); - send(sock, Header, HeaderLen, 0); - send(sock, _REPLYBUFFER, ReplyLen, 0); - send(sock, Tail, (int)strlen(Tail), 0); - return 1; - } - - if (COOKIE == FALSE) - Key = DummyKey; - - if (memcmp(Context, "date=", 5) == 0) - { - memset(tm, 0, sizeof(struct tm)); - tm->tm_year = atoi(&Context[5]) - 1900; - tm->tm_mon = atoi(&Context[10]) - 1; - tm->tm_mday = atoi(&Context[13]); - } - - - - if (strcmp(Context, "input=Back") == 0) - { - ReplyLen = SetupNodeMenu(Reply, LOCAL); - HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n", ReplyLen + (int)strlen(Tail)); - send(sock, Header, HeaderLen, 0); - send(sock, Reply, ReplyLen, 0); - send(sock, Tail, (int)strlen(Tail), 0); - return 1; - } - - if (LogDirectory[0] == 0) - { - strcpy(inputname, "logs/"); - } - else - { - strcpy(inputname,LogDirectory); - strcat(inputname,"/"); - strcat(inputname, "/logs/"); - } - - if (strstr(Context, "CMS")) - { - sprintf(Name, "CMSAccess_%04d%02d%02d.log", - tm->tm_year +1900, tm->tm_mon+1, tm->tm_mday); - } - else if (strstr(Context, "Debug")) - { - sprintf(Name, "log_%02d%02d%02d_DEBUG.txt", - tm->tm_year - 100, tm->tm_mon+1, tm->tm_mday); - } - else if (strstr(Context, "BBS")) - { - sprintf(Name, "log_%02d%02d%02d_BBS.txt", - tm->tm_year - 100, tm->tm_mon+1, tm->tm_mday); - } - else if (strstr(Context, "Chat")) - { - sprintf(Name, "log_%02d%02d%02d_CHAT.txt", - tm->tm_year - 100, tm->tm_mon+1, tm->tm_mday); - } - else if (strstr(Context, "Telnet")) - { - sprintf(Name, "Telnet_%02d%02d%02d.log", - tm->tm_year - 100, tm->tm_mon+1, tm->tm_mday); - } - - strcat(inputname, Name); - - if (stat(inputname, &STAT) == -1) - { - CfgBytes = malloc(256); - sprintf(CfgBytes, "Log %s not found", inputname); - CfgLen = strlen(CfgBytes); - } - else - { - fp1 = fopen(inputname, "rb"); - - if (fp1 == 0) - { - CfgBytes = malloc(256); - sprintf(CfgBytes, "Log %s not found", inputname); - CfgLen = strlen(CfgBytes); - } - else - { - CfgLen = STAT.st_size; - - CfgBytes = malloc(CfgLen + 1); - - CfgLen = (int)fread(CfgBytes, 1, CfgLen, fp1); - CfgBytes[CfgLen] = 0; - } - } - - _REPLYBUFFER = malloc(CfgLen + 1000); - - ReplyLen = sprintf(_REPLYBUFFER, ShowLogPage, CfgBytes); - free (CfgBytes); - - HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n", ReplyLen + (int)strlen(Tail)); - sendandcheck(sock, Header, HeaderLen); - sendandcheck(sock, _REPLYBUFFER, ReplyLen); - sendandcheck(sock, Tail, (int)strlen(Tail)); - free (_REPLYBUFFER); - - return 1; - } - - else if (_stricmp(NodeURL, "/Node/EditCfg.html") == 0) - { - char * _REPLYBUFFER; - int ReplyLen; - char Header[256]; - int HeaderLen; - char * CfgBytes; - int CfgLen; - char inputname[250]="bpq32.cfg"; - FILE *fp1; - struct stat STAT; - char DummyKey[] = "DummyKey"; - - if (LOCAL == FALSE && COOKIE == FALSE) - { - // Send Not Authorized - - char _REPLYBUFFER[4096]; - ReplyLen = SetupNodeMenu(_REPLYBUFFER, LOCAL); - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "
Not authorized - please sign in"); - HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n", ReplyLen + (int)strlen(Tail)); - send(sock, Header, HeaderLen, 0); - send(sock, _REPLYBUFFER, ReplyLen, 0); - send(sock, Tail, (int)strlen(Tail), 0); - return 1; - } - - if (COOKIE ==FALSE) - Key = DummyKey; - - if (BPQDirectory[0] == 0) - { - strcpy(inputname, "bpq32.cfg"); - } - else - { - strcpy(inputname,BPQDirectory); - strcat(inputname,"/"); - strcat(inputname, "bpq32.cfg"); - } - - - if (stat(inputname, &STAT) == -1) - { - CfgBytes = _strdup("Config File not found"); - } - else - { - fp1 = fopen(inputname, "rb"); - - if (fp1 == 0) - { - CfgBytes = _strdup("Config File not found"); - } - else - { - CfgLen = STAT.st_size; - - CfgBytes = malloc(CfgLen + 1); - - CfgLen = (int)fread(CfgBytes, 1, CfgLen, fp1); - CfgBytes[CfgLen] = 0; - } - } - - _REPLYBUFFER = malloc(CfgLen + 1000); - - ReplyLen = sprintf(_REPLYBUFFER, ConfigEditPage, Key, CfgBytes); - free (CfgBytes); - - HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n", ReplyLen + (int)strlen(Tail)); - sendandcheck(sock, Header, HeaderLen); - sendandcheck(sock, _REPLYBUFFER, ReplyLen); - sendandcheck(sock, Tail, (int)strlen(Tail)); - free (_REPLYBUFFER); - - return 1; - } - - - - if (_stricmp(NodeURL, "/Node/PortBeacons") == 0) - { - char * PortChar = strtok_s(NULL, "&", &Context); - int PortNo = atoi(PortChar); - struct PORTCONTROL * PORT; - int PortSlot = 0; - - PORT = GetPortTableEntryFromPortNum(PortNo); // Need slot not number - if (PORT) - PortSlot = PORT->PortSlot; - - - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], Beacons, PortNo, - Interval[PortSlot], &UIUIDEST[PortSlot][0], &UIUIDigi[PortSlot][0], &FN[PortSlot][0], &Message[PortSlot][0], PortNo); - } - - - - if (_stricmp(NodeURL, "/Node/PortStats") == 0) - { - struct _EXTPORTDATA * Port; - - char * PortChar = strtok_s(NULL, "&", &Context); - int PortNo = atoi(PortChar); - int Protocol; - int PortType; - - // char PORTTYPE; // H/W TYPE - // 0 = ASYNC, 2 = PC120, 4 = DRSI - // 6 = TOSH, 8 = QUAD, 10 = RLC100 - // 12 = RLC400 14 = INTERNAL 16 = EXTERNAL - -#define KISS 0 -#define NETROM 2 -#define HDLC 6 -#define L2 8 -#define WINMOR 10 - - - // char PROTOCOL; // PORT PROTOCOL - // 0 = KISS, 2 = NETROM, 4 = BPQKISS - //; 6 = HDLC, 8 = L2 - - - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], PortStatsHddr, PortNo); - - Port = (struct _EXTPORTDATA *)GetPortTableEntryFromPortNum(PortNo); - - if (Port == NULL) - { - ReplyLen = sprintf(_REPLYBUFFER, "Invalid Port"); - goto SendResp; - } - - Protocol = Port->PORTCONTROL.PROTOCOL; - PortType = Port->PORTCONTROL.PROTOCOL; - - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], PortStatsLine, "L2 Frames Digied", Port->PORTCONTROL.L2DIGIED); - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], PortStatsLine, "L2 Frames Heard", Port->PORTCONTROL.L2FRAMES); - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], PortStatsLine, "L2 Frames Received", Port->PORTCONTROL.L2FRAMESFORUS); - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], PortStatsLine, "L2 Frames Sent", Port->PORTCONTROL.L2FRAMESSENT); - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], PortStatsLine, "L2 Timeouts", Port->PORTCONTROL.L2TIMEOUTS); - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], PortStatsLine, "REJ Frames Received", Port->PORTCONTROL.L2REJCOUNT); - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], PortStatsLine, "RX out of Seq", Port->PORTCONTROL.L2OUTOFSEQ); - // ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], PortStatsLine, "L2 Resequenced", Port->PORTCONTROL.L2RESEQ); - if (Protocol == HDLC) - { - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], PortStatsLine, "Underrun", Port->PORTCONTROL.L2URUNC); - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], PortStatsLine, "RX Overruns", Port->PORTCONTROL.L2ORUNC); - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], PortStatsLine, "RX CRC Errors", Port->PORTCONTROL.RXERRORS); - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], PortStatsLine, "Frames abandoned", Port->PORTCONTROL.L1DISCARD); - } - else if ((Protocol == KISS && Port->PORTCONTROL.KISSFLAGS) || Protocol == NETROM) - { - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], PortStatsLine, "Poll Timeout", Port->PORTCONTROL.L2URUNC); - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], PortStatsLine, "RX CRC Errors", Port->PORTCONTROL.RXERRORS); - } - - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], PortStatsLine, "FRMRs Sent", Port->PORTCONTROL.L2FRMRTX); - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], PortStatsLine, "FRMRs Received", Port->PORTCONTROL.L2FRMRRX); - - // DB 'Link Active % ' - // DD AVSENDING - - } - - if (_stricmp(NodeURL, "/Node/Ports.html") == 0) - { - struct _EXTPORTDATA * ExtPort; - struct PORTCONTROL * Port; - - int count; - char DLL[20]; - - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "%s", PortsHddr); - - for (count = 1; count <= NUMBEROFPORTS; count++) - { - Port = GetPortTableEntryFromSlot(count); - ExtPort = (struct _EXTPORTDATA *)Port; - - if (Port->PORTTYPE == 0x10) - { - strcpy(DLL, ExtPort->PORT_DLL_NAME); - 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->TNC && Port->TNC->WebWindowProc) // Has a Window - { - if (Port->UICAPABLE) - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], PortLineWithBeaconAndDriver, Port->PORTNUMBER, DLL, - Port->PORTDESCRIPTION, Port->PORTNUMBER, Port->PORTNUMBER, Port->TNC->WebWinX, Port->TNC->WebWinY, 200, 200); - else - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], PortLineWithDriver, Port->PORTNUMBER, DLL, - Port->PORTDESCRIPTION, Port->PORTNUMBER, Port->TNC->WebWinX, Port->TNC->WebWinY, 200, 200); - - continue; - } - - if (Port->PORTTYPE == 16 && Port->PROTOCOL == 10 && Port->UICAPABLE == 0) // EXTERNAL, Pactor/WINMO - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], SessionPortLine, Port->PORTNUMBER, DLL, - Port->PORTDESCRIPTION, Port->PORTNUMBER); - else - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], PortLineWithBeacon, Port->PORTNUMBER, Port->PORTNUMBER, - DLL, DLL, Port->PORTDESCRIPTION, Port->PORTNUMBER); - } - - if (RigActive) - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], RigControlLine, 64, "Rig Control", "Rig Control", 600, 350, 200, 200); - - } - - if (_stricmp(NodeURL, "/Node/Nodes.html") == 0) - { - struct DEST_LIST * Dests = DESTS; - int count, i; - char Normcall[10]; - char Alias[10]; - int Width = 5; - int x = 0, n = 0; - struct DEST_LIST * List[1000]; - char Param = 0; - - if (Context) - { - _strupr(Context); - Param = Context[0]; - } - - for (count = 0; count < MAXDESTS; count++) - { - if (Dests->DEST_CALL[0] != 0) - { - if (Param != 'T' || Dests->DEST_COUNT) - List[n++] = Dests; - - if (n > 999) - break; - } - - Dests++; - } - - if (n > 1) - { - if (Param == 'C') - qsort(List, n, sizeof(void *), CompareNode); - else - qsort(List, n, sizeof(void *), CompareAlias); - } - - Alias[6] = 0; - - if (Param == 'T') - { - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], NodeHddr, "with traffic"); - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], ""); - } - else if (Param == 'C') - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], NodeHddr, "sorted by Call"); - else - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], NodeHddr, "sorted by Alias"); - - for (i = 0; i < n; i++) - { - int len = ConvFromAX25(List[i]->DEST_CALL, Normcall); - Normcall[len]=0; - - memcpy(Alias, List[i]->DEST_ALIAS, 6); - strlop(Alias, ' '); - - if (Param == 'T') - { - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "", - Normcall, Alias, List[i]->DEST_COUNT, List[i]->DEST_RTT /16, - (List[i]->DEST_STATE & 0x40)? 'B':' ', (List[i]->DEST_STATE & 63)); - - } - else - { - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], NodeLine, Normcall, Alias, Normcall); - - if (++x == Width) - { - x = 0; - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], ""); - } - } - } - - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], ""); - } - - if (_stricmp(NodeURL, "/Node/NodeDetail") == 0) - { - UCHAR AXCall[8]; - struct DEST_LIST * Dest = DESTS; - struct NR_DEST_ROUTE_ENTRY * NRRoute; - struct ROUTE * Neighbour; - char Normcall[10]; - int i, len, count, Active; - char Alias[7]; - - Alias[6] = 0; - - _strupr(Context); - - ConvToAX25(Context, AXCall); - - for (count = 0; count < MAXDESTS; count++) - { - if (CompareCalls(Dest->DEST_CALL, AXCall)) - { - break; - } - Dest++; - } - - if (count == MAXDESTS) - { - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "

Call %s not found

", Context); - goto SendResp; - } - - memcpy(Alias, Dest->DEST_ALIAS, 6); - strlop(Alias, ' '); - - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], - "

Info for Node %s:%s

", Alias, Context); - - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "

PortDriverIDBeaconsDriver Window
%d %s%s
%d %s%s Beacons
%d%s%s
%d%s%s Driver Window
%d%s%s BeaconsDriver Window
%d%s%s Rig Control
%s%s
%s%s
%s%d%d
%s%d%d%d%d%d
%s%d%d
%s%d%d
%s%d%d%d%d
%s%d
CallFramesRTTBPQ?Hops
%s:%s%d%d%c%.0d
"); - - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "
FramesRTTBPQ?Hops
%d%d%c%.0d
", - Dest->DEST_COUNT, Dest->DEST_RTT /16, - (Dest->DEST_STATE & 0x40)? 'B':' ', (Dest->DEST_STATE & 63)); - - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "

Neighbours

"); - - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], - "" - ""); - - NRRoute = &Dest->NRROUTE[0]; - - Active = Dest->DEST_ROUTE; - - for (i = 1; i < 4; i++) - { - Neighbour = NRRoute->ROUT_NEIGHBOUR; - - if (Neighbour) - { - len = ConvFromAX25(Neighbour->NEIGHBOUR_CALL, Normcall); - Normcall[len] = 0; - - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "", - (Active == i)?'>':' ',NRRoute->ROUT_QUALITY, NRRoute->ROUT_OBSCOUNT, Neighbour->NEIGHBOUR_PORT, Normcall); - } - NRRoute++; - } - - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "
Qual Obs Port Call
%c %d%d%d%s
"); - - goto SendResp; - - } - /* - - MOV ESI,OFFSET32 NODEROUTEHDDR - MOV ECX,11 - REP MOVSB - - LEA ESI,DEST_CALL[EBX] - CALL DECODENODENAME ; CONVERT TO ALIAS:CALL - REP MOVSB - - CMP DEST_RTT[EBX],0 - JE SHORT @f ; TIMER NOT SET - DEST PROBABLY NOT USED - - MOVSB ; ADD SPACE - CALL DORTT - - @@: - MOV AL,CR - STOSB - - MOV ECX,3 - MOV DH,DEST_ROUTE[EBX] ; CURRENT ACTIVE ROUTE - MOV DL,1 - - push ebx - - PUBLIC CMDN110 - CMDN110: - - MOV ESI,ROUT1_NEIGHBOUR[EBX] - CMP ESI,0 - JE CMDN199 - - - MOV AX,' ' - CMP DH,DL - JNE SHORT CMDN112 ; NOT CURRENT DEST - MOV AX,' >' - - CMDN112: - - STOSW - - PUSH ECX - - MOV AL,ROUT1_QUALITY[EBX] - CALL CONV_DIGITS ; CONVERT AL TO DECIMAL DIGITS - - mov AL,' ' - stosb - - MOV AL,ROUT1_OBSCOUNT[EBX] - CALL CONV_DIGITS ; CONVERT AL TO DECIMAL DIGITS - - mov AL,' ' - stosb - - MOV AL,NEIGHBOUR_PORT[ESI] ; GET PORT - CALL CONV_DIGITS ; CONVERT AL TO DECIMAL DIGITS - - mov AL,' ' - stosb - - - PUSH EDI - CALL CONVFROMAX25 ; CONVERT TO CALL - POP EDI - - MOV ESI,OFFSET32 NORMCALL - REP MOVSB - - MOV AL,CR - STOSB - - ADD EBX,ROUTEVECLEN - INC DL ; ROUTE NUMBER - - POP ECX - DEC ECX - JNZ CMDN110 - - PUBLIC CMDN199 - CMDN199: - - POP EBX - - ; DISPLAY INP3 ROUTES - - MOV ECX,3 - MOV DL,4 - - PUBLIC CMDNINP3 - CMDNINP3: - - MOV ESI,INPROUT1_NEIGHBOUR[EBX] - CMP ESI,0 - JE CMDNINPEND - - MOV AX,' ' - CMP DH,DL - JNE SHORT @F ; NOT CURRENT DEST - MOV AX,' >' - - @@: - - STOSW - - PUSH ECX - - MOV AL, Hops1[EBX] - CALL CONV_DIGITS ; CONVERT AL TO DECIMAL DIGITS - - mov AL,' ' - stosb - - MOVZX EAX, SRTT1[EBX] - - MOV EDX,0 - MOV ECX, 100 - DIV ECX - CALL CONV_5DIGITS - MOV AL,'.' - STOSB - MOV EAX, EDX - CALL PRINTNUM - MOV AL,'s' - STOSB - MOV AL,' ' - STOSB - - MOV AL,NEIGHBOUR_PORT[ESI] ; GET PORT - CALL CONV_DIGITS ; CONVERT AL TO DECIMAL DIGITS - - mov AL,' ' - stosb - - PUSH EDI - CALL CONVFROMAX25 ; CONVERT TO CALL - POP EDI - - MOV ESI,OFFSET32 NORMCALL - REP MOVSB - - - MOV AL,CR - STOSB - - ADD EBX,INPROUTEVECLEN - INC DL ; ROUTE NUMBER - - POP ECX - LOOP CMDNINP3 - - CMDNINPEND: - - ret - - */ - - - if (_stricmp(NodeURL, "/Node/Routes.html") == 0) - { - struct ROUTE * Routes = NEIGHBOURS; - int MaxRoutes = MAXNEIGHBOURS; - int count; - char Normcall[10]; - char locked; - int NodeCount; - int Percent = 0; - int Iframes, Retries; - char Active[10]; - int Queued; - - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "%s", RouteHddr); - - for (count=0; countNEIGHBOUR_CALL[0] != 0) - { - int len = ConvFromAX25(Routes->NEIGHBOUR_CALL, Normcall); - Normcall[len]=0; - - if ((Routes->NEIGHBOUR_FLAG & 1) == 1) - locked = '!'; - else - locked = ' '; - - NodeCount = COUNTNODES(Routes); - - if (Routes->NEIGHBOUR_LINK) - Queued = COUNT_AT_L2(Routes->NEIGHBOUR_LINK); - else - Queued = 0; - - Iframes = Routes->NBOUR_IFRAMES; - Retries = Routes->NBOUR_RETRIES; - - if (Routes->NEIGHBOUR_LINK && Routes->NEIGHBOUR_LINK->L2STATE >= 5) - strcpy(Active, ">"); - else - strcpy(Active, " "); - - if (Iframes) - Percent = (Retries * 100) / Iframes; - else - Percent = 0; - - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], RouteLine, Active, Routes->NEIGHBOUR_PORT, Normcall, locked, - Routes->NEIGHBOUR_QUAL, NodeCount, Iframes, Retries, Percent, Routes->NBOUR_MAXFRAME, Routes->NBOUR_FRACK, - Routes->NEIGHBOUR_TIME >> 8, Routes->NEIGHBOUR_TIME & 0xff, Queued, Routes->OtherendsRouteQual); - } - Routes+=1; - } - } - - if (_stricmp(NodeURL, "/Node/Links.html") == 0) - { - struct _LINKTABLE * Links = LINKS; - int MaxLinks = MAXLINKS; - int count; - char Normcall1[10]; - char Normcall2[10]; - char State[12] = "", Type[12] = "Uplink"; - int axState; - int cctType; - - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "%s", LinkHddr); - - for (count=0; countLINKCALL[0] != 0) - { - int len = ConvFromAX25(Links->LINKCALL, Normcall1); - Normcall1[len] = 0; - - len = ConvFromAX25(Links->OURCALL, Normcall2); - Normcall2[len] = 0; - - axState = Links->L2STATE; - - if (axState == 2) - strcpy(State, "Connecting"); - else if (axState == 3) - strcpy(State, "FRMR"); - else if (axState == 4) - strcpy(State, "Closing"); - else if (axState == 5) - strcpy(State, "Active"); - else if (axState == 6) - strcpy(State, "REJ Sent"); - - cctType = Links->LINKTYPE; - - if (cctType == 1) - strcpy(Type, "Uplink"); - else if (cctType == 2) - strcpy(Type, "Downlink"); - else if (cctType == 3) - strcpy(Type, "Node-Node"); - - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], LinkLine, Normcall1, Normcall2, Links->LINKPORT->PORTNUMBER, - State, Type, 2 - Links->VER1FLAG ); - - Links+=1; - } - } - } - - if (_stricmp(NodeURL, "/Node/Users.html") == 0) - { - TRANSPORTENTRY * L4 = L4TABLE; - TRANSPORTENTRY * Partner; - int MaxLinks = MAXLINKS; - int count; - char State[12] = "", Type[12] = "Uplink"; - char LHS[50] = "", MID[10] = "", RHS[50] = ""; - - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "%s", UserHddr); - - for (count=0; count < MAXCIRCUITS; count++) - { - if (L4->L4USER[0]) - { - RHS[0] = MID[0] = 0; - - if ((L4->L4CIRCUITTYPE & UPLINK) == 0) //SHORT CMDS10A ; YES - { - // IF DOWNLINK, ONLY DISPLAY IF NO CROSSLINK - - if (L4->L4CROSSLINK == 0) //jne CMDS60 ; WILL PROCESS FROM OTHER END - { - // ITS A DOWNLINK WITH NO PARTNER - MUST BE A CLOSING SESSION - // DISPLAY TO THE RIGHT FOR NOW - - strcpy(LHS, "(Closing) "); - DISPLAYCIRCUIT(L4, RHS); - goto CMDS50; - } - else - goto CMDS60; // WILL PROCESS FROM OTHER END - } - - if (L4->L4CROSSLINK == 0) - { - // Single Entry - - DISPLAYCIRCUIT(L4, LHS); - } - else - { - DISPLAYCIRCUIT(L4, LHS); - - Partner = L4->L4CROSSLINK; - - if (Partner->L4STATE == 5) - strcpy(MID, "<-->"); - else - strcpy(MID, "<~~>"); - - DISPLAYCIRCUIT(Partner, RHS); - } -CMDS50: - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], UserLine, LHS, MID, RHS); - } -CMDS60: - L4++; - } - } - /* - PUBLIC CMDUXX_1 - CMDUXX_1: - push EBX - push ESI - PUSH ECX - push EDI - - call _FINDDESTINATION - pop EDI - - jz SHORT NODE_FOUND - - push EDI ; NET/ROM not found - call CONVFROMAX25 ; CONVERT TO CALL - pop EDI - mov ESI,OFFSET32 NORMCALL - rep movsb - - jmp SHORT END_CMDUXX - - PUBLIC NODE_FOUND - NODE_FOUND: - - lea ESI,DEST_CALL[EBX] - call DECODENODENAME - - REP MOVSB - - PUBLIC END_CMDUXX - END_CMDUXX: - - POP ECX - pop ESI - pop EBX - ret - - }}} - */ - - else if (_stricmp(NodeURL, "/Node/Terminal.html") == 0) - { - if (COOKIE && Session) - { - // Already signed in as sysop - - struct UserRec * USER = Session->USER; - - struct HTTPConnectionInfo * NewSession = AllocateSession(sock, 'T'); - - if (NewSession) - { - char AXCall[10]; - ReplyLen = sprintf(_REPLYBUFFER, TermPage, Mycall, Mycall, NewSession->Key, NewSession->Key, NewSession->Key); - strcpy(NewSession->HTTPCall, USER->Callsign); - ConvToAX25(NewSession->HTTPCall, AXCall); - ChangeSessionCallsign(NewSession->Stream, AXCall); - BPQHOSTVECTOR[NewSession->Stream -1].HOSTSESSION->Secure_Session = USER->Secure; - Session->USER = USER; - NewSession->TNC = conn->TNC; - - - // if (Appl[0]) - // { - // strcat(Appl, "\r"); - // SendMsg(Session->Stream, Appl, strlen(Appl)); - // } - - } - else - { - ReplyLen = SetupNodeMenu(_REPLYBUFFER, LOCAL); - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "%s", BusyError); - } - } - else if (LOCAL) - { - // connected to 127.0.0.1 so sign in using node call - - struct HTTPConnectionInfo * NewSession = AllocateSession(sock, 'T'); - - if (NewSession) - { - ReplyLen = sprintf(_REPLYBUFFER, TermPage, Mycall, Mycall, NewSession->Key, NewSession->Key, NewSession->Key); - strcpy(NewSession->HTTPCall, MYNODECALL); - ChangeSessionCallsign(NewSession->Stream, MYCALL); - BPQHOSTVECTOR[NewSession->Stream -1].HOSTSESSION->Secure_Session = TRUE; - NewSession->TNC = conn->TNC; - } - } - else - ReplyLen = sprintf(_REPLYBUFFER, TermSignon, Mycall, Mycall, Context); - } - - else if (_stricmp(NodeURL, "/Node/Signon.html") == 0) - { - ReplyLen = sprintf(_REPLYBUFFER, NodeSignon, Mycall, Mycall, Context); - } - - else if (_stricmp(NodeURL, "/Node/Drivers") == 0) - { - int Bufferlen = SendMessageFile(sock, "/Drivers.htm", TRUE, allowDeflate); // return -1 if not found - - if (Bufferlen != -1) - return 0; // We've sent it - } - - else if (_stricmp(NodeURL, "/Node/OutputScreen.html") == 0) - { - struct HTTPConnectionInfo * Session = FindSession(Context); - - if (Session == NULL) - { - ReplyLen = sprintf(_REPLYBUFFER, "%s", LostSession); - } - else - { - Session->sock = sock; // socket to reply on - ReplyLen = RefreshTermWindow(TCP, Session, _REPLYBUFFER); - - if (ReplyLen == 0) // Nothing new - { - // Debugprintf("GET with no data avail - response held"); - Session->ResponseTimer = 1200; // Delay response for up to a minute - } - else - { - // Debugprintf("GET - outpur sent, timer was %d, set to zero", Session->ResponseTimer); - Session->ResponseTimer = 0; - } - - Session->KillTimer = 0; - return 0; // Refresh has sent any available output - } - } - - else if (_stricmp(NodeURL, "/Node/InputLine.html") == 0) - { - struct TNCINFO * TNC = conn->TNC; - struct TCPINFO * TCP = 0; - - if (TNC) - TCP = TNC->TCPInfo; - - if (TCP && TCP->WebTermCSS) - ReplyLen = sprintf(_REPLYBUFFER, InputLine, Context, TCP->WebTermCSS); - else - ReplyLen = sprintf(_REPLYBUFFER, InputLine, Context, ""); - - } - - else if (_stricmp(NodeURL, "/Node/PTT") == 0) - { - struct TNCINFO * TNC = conn->TNC; - int x = atoi(Context); - } - - -SendResp: - - FormatTime3(TimeString, time(NULL)); - - strcpy(&_REPLYBUFFER[ReplyLen], Tail); - ReplyLen += (int)strlen(Tail); - - - if (allowDeflate) - { - Compressed = Compressit(_REPLYBUFFER, ReplyLen, &ReplyLen); - } - else - { - Encoding[0] = 0; - Compressed = _REPLYBUFFER; - } - - HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n" - "Date: %s\r\n%s\r\n", ReplyLen, TimeString, Encoding); - sendandcheck(sock, Header, HeaderLen); - sendandcheck(sock, Compressed, ReplyLen); - - if (allowDeflate) - free (Compressed); - } - return 0; - -#ifdef WIN32 - } -#include "StdExcept.c" -} -return 0; -#endif -} - -void ProcessHTTPMessage(void * conn) -{ - // conn is a malloc'ed copy to handle reused connections, so need to free it - - InnerProcessHTTPMessage((struct ConnectionInfo *)conn); - free(conn); - return; -} - -static char *month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; -static char *dat[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; - - -VOID FormatTime3(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); - -} - -// Sun, 06 Nov 1994 08:49:37 GMT - -int StatusProc(char * Buff) -{ - int i; - char callsign[12] = ""; - char flag[3]; - UINT Mask, MaskCopy; - int Flags; - int AppNumber; - int OneBits; - int Len = sprintf(Buff, "" - "Stream Status"); - - Len += sprintf(&Buff[Len], ""); - Len += sprintf(&Buff[Len], ""); - Len += sprintf(&Buff[Len], ""); - Len += sprintf(&Buff[Len], ""); - Len += sprintf(&Buff[Len], ""); - Len += sprintf(&Buff[Len], ""); - Len += sprintf(&Buff[Len], ""); - - for (i=1;i<65; i++) - { - callsign[0]=0; - - if (GetAllocationState(i)) - - strcpy(flag,"*"); - else - strcpy(flag," "); - - GetCallsign(i,callsign); - - Mask = MaskCopy = Get_APPLMASK(i); - - // if only one bit set, convert to number - - AppNumber = 0; - OneBits = 0; - - while (MaskCopy) - { - if (MaskCopy & 1) - OneBits++; - - AppNumber++; - MaskCopy = MaskCopy >> 1; - } - - Flags=GetApplFlags(i); - - if (OneBits > 1) - Len += sprintf(&Buff[Len], "" - "", - i, flag, RXCount(i), TXCount(i), MONCount(i), Mask, Flags, callsign, BPQHOSTVECTOR[i-1].PgmName); - - else - Len += sprintf(&Buff[Len], "" - "", - i, flag, RXCount(i), TXCount(i), MONCount(i), AppNumber, Flags, callsign, BPQHOSTVECTOR[i-1].PgmName); - - if ((i & 1) == 0) - Len += sprintf(&Buff[Len], ""); - - } - - Len += sprintf(&Buff[Len], "
    RX   TX   MON  App  Flg Callsign  Program    RX   TX   MON  App  Flg Callsign  Program
%d%s%d%d%d%x%x%s%s%d%s%d%d%d%d%x%s%s
"); - return Len; -} - -int ProcessNodeSignon(SOCKET sock, struct TCPINFO * TCP, char * MsgPtr, char * Appl, char * Reply, struct HTTPConnectionInfo ** Session, int LOCAL) -{ - int ReplyLen = 0; - char * input = strstr(MsgPtr, "\r\n\r\n"); // End of headers - char * user, * password, * Key; - char Header[256]; - int HeaderLen; - struct HTTPConnectionInfo *Sess; - - - if (input) - { - int i; - struct UserRec * USER; - - UndoTransparency(input); - - if (strstr(input, "Cancel=Cancel")) - { - ReplyLen = SetupNodeMenu(Reply, LOCAL); - - HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n" - "\r\n", (int)(ReplyLen + strlen(Tail))); - send(sock, Header, HeaderLen, 0); - send(sock, Reply, ReplyLen, 0); - send(sock, Tail, (int)strlen(Tail), 0); - } - user = strtok_s(&input[9], "&", &Key); - password = strtok_s(NULL, "=", &Key); - password = Key; - - for (i = 0; i < TCP->NumberofUsers; i++) - { - USER = TCP->UserRecPtr[i]; - - if (user && _stricmp(user, USER->UserName) == 0) - { - if (strcmp(password, USER->Password) == 0 && USER->Secure) - { - // ok - - Sess = *Session = AllocateSession(sock, 'N'); - Sess->USER = USER; - - ReplyLen = SetupNodeMenu(Reply, LOCAL); - - HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n" - "Set-Cookie: BPQSessionCookie=%s; Path = /\r\n\r\n", (int)(ReplyLen + strlen(Tail)), Sess->Key); - send(sock, Header, HeaderLen, 0); - send(sock, Reply, ReplyLen, 0); - send(sock, Tail, (int)strlen(Tail), 0); - - return ReplyLen; - } - } - } - } - - ReplyLen = sprintf(Reply, NodeSignon, Mycall, Mycall); - ReplyLen += sprintf(&Reply[ReplyLen], "%s", PassError); - - HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n", (int)(ReplyLen + strlen(Tail))); - send(sock, Header, HeaderLen, 0); - send(sock, Reply, ReplyLen, 0); - send(sock, Tail, (int)strlen(Tail), 0); - - return 0; - - - return ReplyLen; -} - - - - -int ProcessMailSignon(struct TCPINFO * TCP, char * MsgPtr, char * Appl, char * Reply, struct HTTPConnectionInfo ** Session, BOOL WebMail, int LOCAL) -{ - int ReplyLen = 0; - char * input = strstr(MsgPtr, "\r\n\r\n"); // End of headers - char * user, * password, * Key; - struct HTTPConnectionInfo * NewSession; - - if (input) - { - int i; - struct UserRec * USER; - - UndoTransparency(input); - - if (strstr(input, "Cancel=Cancel")) - { - ReplyLen = SetupNodeMenu(Reply, LOCAL); - return ReplyLen; - } - user = strtok_s(&input[9], "&", &Key); - password = strtok_s(NULL, "=", &Key); - password = Key; - - for (i = 0; i < TCP->NumberofUsers; i++) - { - USER = TCP->UserRecPtr[i]; - - if (user && _stricmp(user, USER->UserName) == 0) - { - if (strcmp(password, USER->Password) == 0 && (USER->Secure || WebMail)) - { - // ok - - NewSession = AllocateSession(Appl[0], 'M'); - - *Session = NewSession; - - if (NewSession) - { - - ReplyLen = 0; - strcpy(NewSession->Callsign, USER->Callsign); - } - else - { - ReplyLen = SetupNodeMenu(Reply, LOCAL); - ReplyLen += sprintf(&Reply[ReplyLen], "%s", BusyError); - } - return ReplyLen; - } - } - } - } - - ReplyLen = sprintf(Reply, MailSignon, Mycall, Mycall); - ReplyLen += sprintf(&Reply[ReplyLen], "%s", PassError); - - return ReplyLen; -} - - -int ProcessChatSignon(struct TCPINFO * TCP, char * MsgPtr, char * Appl, char * Reply, struct HTTPConnectionInfo ** Session, int LOCAL) -{ - int ReplyLen = 0; - char * input = strstr(MsgPtr, "\r\n\r\n"); // End of headers - char * user, * password, * Key; - - if (input) - { - int i; - struct UserRec * USER; - - UndoTransparency(input); - - if (strstr(input, "Cancel=Cancel")) - { - ReplyLen = SetupNodeMenu(Reply, LOCAL); - return ReplyLen; - } - - user = strtok_s(&input[9], "&", &Key); - password = strtok_s(NULL, "=", &Key); - password = Key; - - - for (i = 0; i < TCP->NumberofUsers; i++) - { - USER = TCP->UserRecPtr[i]; - - if (user && _stricmp(user, USER->UserName) == 0) - { - if (strcmp(password, USER->Password) == 0 && USER->Secure) - { - // ok - - *Session = AllocateSession(Appl[0], 'C'); - - if (Session) - { - ReplyLen = 0; - } - else - { - ReplyLen = SetupNodeMenu(Reply, LOCAL); - ReplyLen += sprintf(&Reply[ReplyLen], "%s", BusyError); - } - return ReplyLen; - } - } - } - } - - ReplyLen = sprintf(Reply, ChatSignon, Mycall, Mycall); - ReplyLen += sprintf(&Reply[ReplyLen], "%s", PassError); - - return ReplyLen; - -} - -#define SHA1_HASH_LEN 20 - -/* - -Copyright (C) 1998, 2009 -Paul E. Jones - -Freeware Public License (FPL) - -This software is licensed as "freeware." Permission to distribute -this software in source and binary forms, including incorporation -into other products, is hereby granted without a fee. THIS SOFTWARE -IS PROVIDED 'AS IS' AND WITHOUT ANY EXPRESSED OR IMPLIED WARRANTIES, -INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHOR SHALL NOT BE HELD -LIABLE FOR ANY DAMAGES RESULTING FROM THE USE OF THIS SOFTWARE, EITHER -DIRECTLY OR INDIRECTLY, INCLUDING, BUT NOT LIMITED TO, LOSS OF DATA -OR DATA BEING RENDERED INACCURATE. -*/ - -/* sha1.h - * - * Copyright (C) 1998, 2009 - * Paul E. Jones - * All Rights Reserved - * - ***************************************************************************** - * $Id: sha1.h 12 2009-06-22 19:34:25Z paulej $ - ***************************************************************************** - * - * Description: - * This class implements the Secure Hashing Standard as defined - * in FIPS PUB 180-1 published April 17, 1995. - * - * Many of the variable names in the SHA1Context, especially the - * single character names, were used because those were the names - * used in the publication. - * - * Please read the file sha1.c for more information. - * - */ - -#ifndef _SHA1_H_ -#define _SHA1_H_ - -/* - * This structure will hold context information for the hashing - * operation - */ -typedef struct SHA1Context -{ - unsigned Message_Digest[5]; /* Message Digest (output) */ - - unsigned Length_Low; /* Message length in bits */ - unsigned Length_High; /* Message length in bits */ - - unsigned char Message_Block[64]; /* 512-bit message blocks */ - int Message_Block_Index; /* Index into message block array */ - - int Computed; /* Is the digest computed? */ - int Corrupted; /* Is the message digest corruped? */ -} SHA1Context; - -/* - * Function Prototypes - */ -void SHA1Reset(SHA1Context *); -int SHA1Result(SHA1Context *); -void SHA1Input( SHA1Context *, const unsigned char *, unsigned); - -#endif - -BOOL SHA1PasswordHash(char * lpszPassword, char * Hash) -{ - SHA1Context sha; - int i; - - SHA1Reset(&sha); - SHA1Input(&sha, lpszPassword, strlen(lpszPassword)); - SHA1Result(&sha); - - // swap byte order if little endian - - for (i = 0; i < 5; i++) - sha.Message_Digest[i] = htonl(sha.Message_Digest[i]); - - memcpy(Hash, &sha.Message_Digest[0], 20); - - return TRUE; -} - -int BuildRigCtlPage(char * _REPLYBUFFER) -{ - int ReplyLen; - - struct RIGPORTINFO * PORT; - struct RIGINFO * RIG; - int p, i; - - char Page[] = - "\r\n" - // "\r\n" - "Rigcontrol\r\n" - "" - "

Rigcontrol

\r\n" - "\r\n" - "\r\n" - "\r\n" - "\r\n" - "\r\n" - "\r\n" - "\r\n" - ""; - char RigLine[] = - "\r\n" - " \r\n" - " \r\n" - " \r\n" - " \r\n" - " \r\n" - " \r\n" - " \r\n"; - char Tail[] = - "
RadioFreqModeSTPorts
%s%s%s/1%c%c%s
\r\n" - "\r\n"; - - ReplyLen = sprintf(_REPLYBUFFER, "%s", Page); - - for (p = 0; p < NumberofPorts; p++) - { - PORT = PORTInfo[p]; - - for (i=0; i< PORT->ConfiguredRigs; i++) - { - RIG = &PORT->Rigs[i]; - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], RigLine, RIG->WEB_Label, RIG->WEB_FREQ, RIG->WEB_MODE, RIG->WEB_SCAN, RIG->WEB_PTT, RIG->WEB_PORTS, RIG->Interlock); - } - } - - ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "%s", Tail); - return ReplyLen; -} - - -void SendRigWebPage() -{ - int i, n; - struct ConnectionInfo * sockptr; - struct TNCINFO * TNC; - struct TCPINFO * TCP; - - for (i = 0; i < 33; i++) - { - TNC = TNCInfo[i]; - - if (TNC && TNC->Hardware == H_TELNET) - { - TCP = TNC->TCPInfo; - - if (TCP) - { - for (n = 0; n <= TCP->MaxSessions; n++) - { - sockptr = TNC->Streams[n].ConnectionInfo; - - if (sockptr->SocketActive) - { - if (sockptr->HTTPMode && sockptr->WebSocks && strcmp(sockptr->WebURL, "RIGCTL") == 0) - { - char RigMsg[8192]; - int RigMsgLen = strlen(RigWebPage); - char* ptr; - - RigMsg[0] = 0x81; // Fin, Data - RigMsg[1] = 126; // Unmasked, Extended Len - RigMsg[2] = RigMsgLen >> 8; - RigMsg[3] = RigMsgLen & 0xff; - strcpy(&RigMsg[4], RigWebPage); - - // If secure session enable PTT button - - if (sockptr->WebSecure) - { - while (ptr = strstr(RigMsg, "hidden")) - memcpy(ptr, " ", 6); - } - - send(sockptr->socket, RigMsg, RigMsgLen + 4, 0); - } - } - } - } - } - } -} - -// Webmail web socket code - -int ProcessWebmailWebSock(char * MsgPtr, char * OutBuffer); - -void ProcessWebmailWebSockThread(void * conn) -{ - // conn is a malloc'ed copy to handle reused connections, so need to free it - - struct ConnectionInfo * sockptr = (struct ConnectionInfo *)conn; - char * URL = sockptr->WebURL; - int Loops = 0; - int Sent; - struct HTTPConnectionInfo Dummy = {0}; - int ReplyLen = 0; - int InputLen = 0; - -#ifdef LINBPQ - - char _REPLYBUFFER[250000]; - - ReplyLen = ProcessWebmailWebSock(URL, _REPLYBUFFER); - - // Send may block - - Sent = send(sockptr->socket, _REPLYBUFFER, ReplyLen, 0); - - while (Sent != ReplyLen && Loops++ < 3000) // 100 secs max - { - if (Sent > 0) // something sent - { - ReplyLen -= Sent; - memmove(_REPLYBUFFER, &_REPLYBUFFER[Sent], ReplyLen); - } - - Sleep(30); - Sent = send(sockptr->socket, _REPLYBUFFER, ReplyLen, 0); - } - -#else - // Send URL to BPQMail via Pipe. Just need a dummy session, as URL contains session key - - HANDLE hPipe; - char Reply[250000]; - - - - hPipe = CreateFile(MAILPipeFileName, GENERIC_READ | GENERIC_WRITE, - 0, // exclusive access - NULL, // no security attrs - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - NULL ); - - if (hPipe == (HANDLE)-1) - { - free(conn); - return; - } - - WriteFile(hPipe, &Dummy, sizeof (struct HTTPConnectionInfo), &InputLen, NULL); - WriteFile(hPipe, URL, strlen(URL), &InputLen, NULL); - - ReadFile(hPipe, &Dummy, sizeof (struct HTTPConnectionInfo), &InputLen, NULL); - ReadFile(hPipe, Reply, 250000, &ReplyLen, NULL); - - if (ReplyLen <= 0) - { - InputLen = GetLastError(); - } - - CloseHandle(hPipe); - - // ?? do we need a thread to handle write which may block - - Sent = send(sockptr->socket, Reply, ReplyLen, 0); - - while (Sent != ReplyLen && Loops++ < 3000) // 100 secs max - { - // Debugprintf("%d out of %d sent %d Loops", Sent, InputLen, Loops); - - if (Sent > 0) // something sent - { - InputLen -= Sent; - memmove(Reply, &Reply[Sent], ReplyLen); - } - - Sleep(30); - Sent = send(sockptr->socket, Reply, ReplyLen, 0); - } -#endif - free(conn); - return; -} - -/* - * sha1.c - * - * Copyright (C) 1998, 2009 - * Paul E. Jones - * All Rights Reserved - * - ***************************************************************************** - * $Id: sha1.c 12 2009-06-22 19:34:25Z paulej $ - ***************************************************************************** - * - * Description: - * This file implements the Secure Hashing Standard as defined - * in FIPS PUB 180-1 published April 17, 1995. - * - * The Secure Hashing Standard, which uses the Secure Hashing - * Algorithm (SHA), produces a 160-bit message digest for a - * given data stream. In theory, it is highly improbable that - * two messages will produce the same message digest. Therefore, - * this algorithm can serve as a means of providing a "fingerprint" - * for a message. - * - * Portability Issues: - * SHA-1 is defined in terms of 32-bit "words". This code was - * written with the expectation that the processor has at least - * a 32-bit machine word size. If the machine word size is larger, - * the code should still function properly. One caveat to that - * is that the input functions taking characters and character - * arrays assume that only 8 bits of information are stored in each - * character. - * - * Caveats: - * SHA-1 is designed to work with messages less than 2^64 bits - * long. Although SHA-1 allows a message digest to be generated for - * messages of any number of bits less than 2^64, this - * implementation only works with messages with a length that is a - * multiple of the size of an 8-bit character. - * - */ - -/* - * Define the circular shift macro - */ -#define SHA1CircularShift(bits,word) \ - ((((word) << (bits)) & 0xFFFFFFFF) | \ - ((word) >> (32-(bits)))) - -/* Function prototypes */ -void SHA1ProcessMessageBlock(SHA1Context *); -void SHA1PadMessage(SHA1Context *); - -/* - * SHA1Reset - * - * Description: - * This function will initialize the SHA1Context in preparation - * for computing a new message digest. - * - * Parameters: - * context: [in/out] - * The context to reset. - * - * Returns: - * Nothing. - * - * Comments: - * - */ -void SHA1Reset(SHA1Context *context) -{ - context->Length_Low = 0; - context->Length_High = 0; - context->Message_Block_Index = 0; - - context->Message_Digest[0] = 0x67452301; - context->Message_Digest[1] = 0xEFCDAB89; - context->Message_Digest[2] = 0x98BADCFE; - context->Message_Digest[3] = 0x10325476; - context->Message_Digest[4] = 0xC3D2E1F0; - - context->Computed = 0; - context->Corrupted = 0; -} - -/* - * SHA1Result - * - * Description: - * This function will return the 160-bit message digest into the - * Message_Digest array within the SHA1Context provided - * - * Parameters: - * context: [in/out] - * The context to use to calculate the SHA-1 hash. - * - * Returns: - * 1 if successful, 0 if it failed. - * - * Comments: - * - */ -int SHA1Result(SHA1Context *context) -{ - - if (context->Corrupted) - { - return 0; - } - - if (!context->Computed) - { - SHA1PadMessage(context); - context->Computed = 1; - } - - return 1; -} - -/* - * SHA1Input - * - * Description: - * This function accepts an array of octets as the next portion of - * the message. - * - * Parameters: - * context: [in/out] - * The SHA-1 context to update - * message_array: [in] - * An array of characters representing the next portion of the - * message. - * length: [in] - * The length of the message in message_array - * - * Returns: - * Nothing. - * - * Comments: - * - */ -void SHA1Input( SHA1Context *context, - const unsigned char *message_array, - unsigned length) -{ - if (!length) - { - return; - } - - if (context->Computed || context->Corrupted) - { - context->Corrupted = 1; - return; - } - - while(length-- && !context->Corrupted) - { - context->Message_Block[context->Message_Block_Index++] = - (*message_array & 0xFF); - - context->Length_Low += 8; - /* Force it to 32 bits */ - context->Length_Low &= 0xFFFFFFFF; - if (context->Length_Low == 0) - { - context->Length_High++; - /* Force it to 32 bits */ - context->Length_High &= 0xFFFFFFFF; - if (context->Length_High == 0) - { - /* Message is too long */ - context->Corrupted = 1; - } - } - - if (context->Message_Block_Index == 64) - { - SHA1ProcessMessageBlock(context); - } - - message_array++; - } -} - -/* - * SHA1ProcessMessageBlock - * - * Description: - * This function will process the next 512 bits of the message - * stored in the Message_Block array. - * - * Parameters: - * None. - * - * Returns: - * Nothing. - * - * Comments: - * Many of the variable names in the SHAContext, especially the - * single character names, were used because those were the names - * used in the publication. - * - * - */ -void SHA1ProcessMessageBlock(SHA1Context *context) -{ - const unsigned K[] = /* Constants defined in SHA-1 */ - { - 0x5A827999, - 0x6ED9EBA1, - 0x8F1BBCDC, - 0xCA62C1D6 - }; - int t; /* Loop counter */ - unsigned temp; /* Temporary word value */ - unsigned W[80]; /* Word sequence */ - unsigned A, B, C, D, E; /* Word buffers */ - - /* - * Initialize the first 16 words in the array W - */ - for(t = 0; t < 16; t++) - { - W[t] = ((unsigned) context->Message_Block[t * 4]) << 24; - W[t] |= ((unsigned) context->Message_Block[t * 4 + 1]) << 16; - W[t] |= ((unsigned) context->Message_Block[t * 4 + 2]) << 8; - W[t] |= ((unsigned) context->Message_Block[t * 4 + 3]); - } - - for(t = 16; t < 80; t++) - { - W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]); - } - - A = context->Message_Digest[0]; - B = context->Message_Digest[1]; - C = context->Message_Digest[2]; - D = context->Message_Digest[3]; - E = context->Message_Digest[4]; - - for(t = 0; t < 20; t++) - { - temp = SHA1CircularShift(5,A) + - ((B & C) | ((~B) & D)) + E + W[t] + K[0]; - temp &= 0xFFFFFFFF; - E = D; - D = C; - C = SHA1CircularShift(30,B); - B = A; - A = temp; - } - - for(t = 20; t < 40; t++) - { - temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1]; - temp &= 0xFFFFFFFF; - E = D; - D = C; - C = SHA1CircularShift(30,B); - B = A; - A = temp; - } - - for(t = 40; t < 60; t++) - { - temp = SHA1CircularShift(5,A) + - ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2]; - temp &= 0xFFFFFFFF; - E = D; - D = C; - C = SHA1CircularShift(30,B); - B = A; - A = temp; - } - - for(t = 60; t < 80; t++) - { - temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3]; - temp &= 0xFFFFFFFF; - E = D; - D = C; - C = SHA1CircularShift(30,B); - B = A; - A = temp; - } - - context->Message_Digest[0] = - (context->Message_Digest[0] + A) & 0xFFFFFFFF; - context->Message_Digest[1] = - (context->Message_Digest[1] + B) & 0xFFFFFFFF; - context->Message_Digest[2] = - (context->Message_Digest[2] + C) & 0xFFFFFFFF; - context->Message_Digest[3] = - (context->Message_Digest[3] + D) & 0xFFFFFFFF; - context->Message_Digest[4] = - (context->Message_Digest[4] + E) & 0xFFFFFFFF; - - context->Message_Block_Index = 0; -} - -/* - * SHA1PadMessage - * - * Description: - * According to the standard, the message must be padded to an even - * 512 bits. The first padding bit must be a '1'. The last 64 - * bits represent the length of the original message. All bits in - * between should be 0. This function will pad the message - * according to those rules by filling the Message_Block array - * accordingly. It will also call SHA1ProcessMessageBlock() - * appropriately. When it returns, it can be assumed that the - * message digest has been computed. - * - * Parameters: - * context: [in/out] - * The context to pad - * - * Returns: - * Nothing. - * - * Comments: - * - */ -void SHA1PadMessage(SHA1Context *context) -{ - /* - * Check to see if the current message block is too small to hold - * the initial padding bits and length. If so, we will pad the - * block, process it, and then continue padding into a second - * block. - */ - if (context->Message_Block_Index > 55) - { - context->Message_Block[context->Message_Block_Index++] = 0x80; - while(context->Message_Block_Index < 64) - { - context->Message_Block[context->Message_Block_Index++] = 0; - } - - SHA1ProcessMessageBlock(context); - - while(context->Message_Block_Index < 56) - { - context->Message_Block[context->Message_Block_Index++] = 0; - } - } - else - { - context->Message_Block[context->Message_Block_Index++] = 0x80; - while(context->Message_Block_Index < 56) - { - context->Message_Block[context->Message_Block_Index++] = 0; - } - } - - /* - * Store the message length as the last 8 octets - */ - context->Message_Block[56] = (context->Length_High >> 24) & 0xFF; - context->Message_Block[57] = (context->Length_High >> 16) & 0xFF; - context->Message_Block[58] = (context->Length_High >> 8) & 0xFF; - context->Message_Block[59] = (context->Length_High) & 0xFF; - context->Message_Block[60] = (context->Length_Low >> 24) & 0xFF; - context->Message_Block[61] = (context->Length_Low >> 16) & 0xFF; - context->Message_Block[62] = (context->Length_Low >> 8) & 0xFF; - context->Message_Block[63] = (context->Length_Low) & 0xFF; - - SHA1ProcessMessageBlock(context); -} - - - - - diff --git a/HanksRT.c b/HanksRT.c index d78c610..cfc6440 100644 --- a/HanksRT.c +++ b/HanksRT.c @@ -75,6 +75,7 @@ char ChatWelcomeMsg[1000]; char Position[81] = ""; char PopupText[260] = ""; int PopupMode = 0; +int chatPaclen = 236; char RtKnown[MAX_PATH] = "RTKnown.txt"; char RtUsr[MAX_PATH] = "STUsers.txt"; @@ -97,6 +98,7 @@ int ChatTmr = 0; BOOL NeedStatus = FALSE; + char Verstring[80]; static void node_dec(CHATNODE *node); @@ -597,7 +599,9 @@ VOID ProcessChatLine(ChatCIRCUIT * conn, struct UserInfo * user, char* OrigBuffe Buffer = BufferB; #else - int left = 65536; + size_t left = 65536; + size_t clen = len; + UCHAR * BufferBP = BufferB; struct user_t * icu = conn->u.user; @@ -605,22 +609,22 @@ VOID ProcessChatLine(ChatCIRCUIT * conn, struct UserInfo * user, char* OrigBuffe { if (icu->iconv_toUTF8 == NULL) { - icu->iconv_toUTF8 = iconv_open("UTF-8", icu->Codepage); + icu->iconv_toUTF8 = iconv_open("UTF-8//IGNORE", icu->Codepage); if (icu->iconv_toUTF8 == (iconv_t)-1) - icu->iconv_toUTF8 = iconv_open("UTF-8", "CP1252"); + icu->iconv_toUTF8 = iconv_open("UTF-8//IGNORE", "CP1252"); } iconv(icu->iconv_toUTF8, NULL, NULL, NULL, NULL); // Reset State Machine - iconv(icu->iconv_toUTF8, &Buffer, &len, (char ** __restrict__)&BufferBP, &left); + iconv(icu->iconv_toUTF8, &Buffer, &clen, (char ** __restrict__)&BufferBP, &left); } else { if (link_toUTF8 == NULL) - link_toUTF8 = iconv_open("UTF-8", "CP1252"); + link_toUTF8 = iconv_open("UTF-8//IGNORE", "CP1252"); iconv(link_toUTF8, NULL, NULL, NULL, NULL); // Reset State Machine - iconv(link_toUTF8, &Buffer, &len, (char ** __restrict__)&BufferBP, &left); + iconv(link_toUTF8, &Buffer, &clen, (char ** __restrict__)&BufferBP, &left); } len = 65536 - left; Buffer = BufferB; @@ -1121,12 +1125,12 @@ void rduser(USER *user) // Open an iconv decriptor for each conversion if (user->Codepage[0]) - user->iconv_toUTF8 = iconv_open("UTF-8", user->Codepage); + user->iconv_toUTF8 = iconv_open("UTF-8//IGNORE", user->Codepage); else user->iconv_toUTF8 = (iconv_t)-1; if (user->iconv_toUTF8 == (iconv_t)-1) - user->iconv_toUTF8 = iconv_open("UTF-8", "CP1252"); + user->iconv_toUTF8 = iconv_open("UTF-8//IGNORE", "CP1252"); if (user->Codepage[0]) @@ -1135,7 +1139,7 @@ void rduser(USER *user) user->iconv_fromUTF8 = (iconv_t)-1; if (user->iconv_fromUTF8 == (iconv_t)-1) - user->iconv_fromUTF8 = iconv_open("CP1252", "UTF-8"); + user->iconv_fromUTF8 = iconv_open("CP1252//IGNORE", "UTF-8"); #endif } } @@ -1936,7 +1940,7 @@ void put_text(ChatCIRCUIT * circuit, USER * user, UCHAR * buf) { UCHAR BufferB[4096]; - // Text is UTF-8 internally. If use doen't want UTF-8. convert to Node's locale + // Text is UTF-8 internally. If user doen't want UTF-8. convert to Node's locale if (circuit->u.user->rtflags & u_noUTF8) { @@ -1957,9 +1961,9 @@ void put_text(ChatCIRCUIT * circuit, USER * user, UCHAR * buf) BufferB[blen + 2] = 0; #else - int left = 4096; + size_t left = 4096; UCHAR * BufferBP = BufferB; - int len = strlen(buf) + 1; + size_t len = strlen(buf) + 1; struct user_t * icu = circuit->u.user; if (icu->iconv_fromUTF8 == NULL) @@ -1967,7 +1971,7 @@ void put_text(ChatCIRCUIT * circuit, USER * user, UCHAR * buf) icu->iconv_fromUTF8 = iconv_open(icu->Codepage, "UTF-8"); if (icu->iconv_fromUTF8 == (iconv_t)-1) - icu->iconv_fromUTF8 = iconv_open("CP1252", "UTF-8"); + icu->iconv_fromUTF8 = iconv_open("CP1252//IGNORE", "UTF-8"); } iconv(icu->iconv_fromUTF8, NULL, NULL, NULL, NULL); // Reset State Machine @@ -3863,7 +3867,7 @@ int ChatConnected(int Stream) if (conn->rtcflags == p_linkini) { - conn->paclen = 236; + conn->paclen = chatPaclen; // Run first line of connect script @@ -3883,6 +3887,9 @@ int ChatConnected(int Stream) if (paclen == 0) paclen = 256; + if (paclen > chatPaclen) + paclen = chatPaclen; + conn->paclen = paclen; strlop(callsign, ' '); // Remove trailing spaces @@ -4163,12 +4170,19 @@ BOOL GetChatConfig(char * ConfigName) ChatApplNum = GetIntValue(group, "ApplNum"); MaxChatStreams = GetIntValue(group, "MaxStreams"); + chatPaclen = GetIntValue(group, "chatPaclen"); GetStringValue(group, "OtherChatNodes", OtherNodesList); GetStringValue(group, "ChatWelcomeMsg", ChatWelcomeMsg); GetStringValue(group, "MapPosition", Position); GetStringValue(group, "MapPopup", PopupText); PopupMode = GetIntValue(group, "PopupMode"); + if (chatPaclen == 0) + chatPaclen = 236; + + if (chatPaclen < 60) + chatPaclen = 60; + return EXIT_SUCCESS; } @@ -4187,6 +4201,7 @@ VOID SaveChatConfigFile(char * ConfigName) SaveIntValue(group, "ApplNum", ChatApplNum); SaveIntValue(group, "MaxStreams", MaxChatStreams); + SaveIntValue(group, "chatPaclen", chatPaclen); SaveStringValue(group, "OtherChatNodes", OtherNodesList); SaveStringValue(group, "ChatWelcomeMsg", ChatWelcomeMsg); diff --git a/L2Code.c b/L2Code.c index 1b4d8f7..37a8aff 100644 --- a/L2Code.c +++ b/L2Code.c @@ -965,6 +965,11 @@ VOID ProcessXIDCommand(struct _LINKTABLE * LINK, struct PORTCONTROL * PORT, MESS L2SWAPADDRESSES(Buffer); // SWAP ADDRESSES AND SET RESP BITS + // We need to save APPLMASK and ALIASPTR so following SABM connects to application + + LINK->APPLMASK = APPLMASK; + LINK->ALIASPTR = ALIASPTR; + PUT_ON_PORT_Q(PORT, Buffer); return; } @@ -1089,6 +1094,9 @@ VOID L2LINKACTIVE(struct _LINKTABLE * LINK, struct PORTCONTROL * PORT, MESSAGE * if (LINK->L2STATE == 1) // Sent XID? { + APPLMASK = LINK->APPLMASK; + ALIASPTR = LINK->ALIASPTR; + L2SABM(LINK, PORT, Buffer, ADJBUFFER, MSGFLAG); // Process the SABM return; } @@ -1351,7 +1359,7 @@ VOID L2SABM(struct _LINKTABLE * LINK, struct PORTCONTROL * PORT, MESSAGE * Buffe { Msg->PID = 0xf0; - memcpy(Msg->L2DATA, APPL->APPLCMD, 12); + memcpy(Msg->L2DATA, ALIASPTR, 12); Msg->L2DATA[12] = 13; Msg->LENGTH = MSGHDDRLEN + 12 + 2; // 2 for PID and CR @@ -2412,6 +2420,10 @@ CheckPF: LINK->LAST_F_TIME = REALTIMETICKS; } + else + if (LINK->L2ACKREQ == 0) // Resptime is zero so send RR now + SEND_RR_RESP(LINK, 0); + } diff --git a/LinBPQ.c b/LinBPQ.c index ba6d20f..8cda726 100644 --- a/LinBPQ.c +++ b/LinBPQ.c @@ -28,6 +28,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses //#include "C:\Program Files (x86)\GnuWin32\include\iconv.h" #else #include +#include #ifndef MACBPQ #ifndef FREEBSD #include @@ -75,6 +76,8 @@ void SaveAIS(); void initAIS(); void DRATSPoll(); +extern uint64_t timeLoadedMS; + BOOL IncludesMail = FALSE; BOOL IncludesChat = FALSE; @@ -174,8 +177,15 @@ int _MYTIMEZONE = 0; /* #define F_PWD 0x1000 */ -UCHAR BPQDirectory[260]; -UCHAR LogDirectory[260]; +extern UCHAR BPQDirectory[260]; +extern UCHAR LogDirectory[260]; +extern UCHAR ConfigDirectory[260]; + +// overrides from params +UCHAR LogDir[260] = ""; +UCHAR ConfigDir[260] = ""; +UCHAR DataDir[260] = ""; + BOOL GetConfig(char * ConfigName); VOID DecryptPass(char * Encrypt, unsigned char * Pass, unsigned int len); @@ -704,8 +714,26 @@ void ConTermPoll() return; } - +#include "getopt.h" + +static struct option long_options[] = +{ + {"logdir", required_argument, 0 , 'l'}, + {"configdir", required_argument, 0 , 'c'}, + {"datadir", required_argument, 0 , 'd'}, + {"help", no_argument, 0 , 'h'}, + { NULL , no_argument , NULL , no_argument } +}; + +char HelpScreen[] = + "Usage:\n" + "Optional Paramters\n" + "-l path or --logdir path Path for log files\n" + "-c path or --configdir path Path to Config file bpq32.cfg\n" + "-d path or --datadir path Path to Data Files\n" + "-v Show version and exit\n"; + int Redirected = 0; int main(int argc, char * argv[]) @@ -715,7 +743,6 @@ int main(int argc, char * argv[]) ConnectionInfo * conn; struct stat STAT; PEXTPORTDATA PORTVEC; - UCHAR LogDir[260]; #ifdef WIN32 @@ -755,13 +782,64 @@ int main(int argc, char * argv[]) if (!isatty(STDOUT_FILENO) || !isatty(STDIN_FILENO)) Redirected = 1; + timeLoadedMS = GetTickCount(); + #endif - printf("G8BPQ AX25 Packet Switch System Version %s %s\n", TextVerstring, Datestring); - printf("%s\n", VerCopyright); + printf("G8BPQ AX25 Packet Switch System Version %s %s\n", TextVerstring, Datestring); + printf("%s\n", VerCopyright); - if (argc > 1 && _stricmp(argv[1], "-v") == 0) - return 0; + + // look for optarg format parameters + + { + int val; + UCHAR * ptr1; + UCHAR * ptr2; + int c; + + while (1) + { + int option_index = 0; + + c = getopt_long(argc, argv, "l:c:d:hv", long_options, &option_index); + + // Check for end of operation or error + + if (c == -1) + break; + + // Handle options + switch (c) + { + case 'h': + + printf(HelpScreen); + exit (0); + + case 'l': + strcpy(LogDir, optarg); + printf("cc %s\n", LogDir); + break; + + case 'c': + strcpy(ConfigDir, optarg); + break; + + case 'd': + strcpy(DataDir, optarg); + break; + + + case '?': + /* getopt_long already printed an error message. */ + break; + + case 'v': + return 0; + } + } + } sprintf(RlineVer, "LinBPQ%d.%d.%d", Ver[0], Ver[1], Ver[2]); @@ -777,22 +855,41 @@ int main(int argc, char * argv[]) #ifdef WIN32 GetCurrentDirectory(256, BPQDirectory); - GetCurrentDirectory(256, LogDirectory); #else getcwd(BPQDirectory, 256); - getcwd(LogDirectory, 256); #endif - Consoleprintf("Current Directory is %s\n", BPQDirectory); - for (i = 1; i < argc; i++) + strcpy(ConfigDirectory, BPQDirectory); + strcpy(LogDirectory, BPQDirectory); + + Consoleprintf("Current Directory is %s", BPQDirectory); + + if (LogDir[0]) + { + strcpy(LogDirectory, LogDir); + } + if (DataDir[0]) + { + strcpy(BPQDirectory, DataDir); + Consoleprintf("Working Directory is %s", BPQDirectory); + } + if (ConfigDir[0]) + { + strcpy(ConfigDirectory, ConfigDir); + Consoleprintf("Config Directory is %s", ConfigDirectory); + } + + for (i = optind; i < argc; i++) { if (_memicmp(argv[i], "logdir=", 7) == 0) { strcpy(LogDirectory, &argv[i][7]); + Consoleprintf("Log Directory is %s\n", LogDirectory); break; } } + Consoleprintf("Log Directory is %s", LogDirectory); // Make sure logs directory exists @@ -801,7 +898,13 @@ int main(int argc, char * argv[]) #ifdef WIN32 CreateDirectory(LogDir, NULL); #else - mkdir(LogDir, S_IRWXU | S_IRWXG | S_IRWXO); + printf("Making Directory %s\n", LogDir); + i = mkdir(LogDir, S_IRWXU | S_IRWXG | S_IRWXO); + if (i == -1 && errno != EEXIST) + { + perror("Couldn't create log directory\n"); + return 0; + } chmod(LogDir, S_IRWXU | S_IRWXG | S_IRWXO); #endif @@ -885,7 +988,7 @@ int main(int argc, char * argv[]) #endif - for (i = 1; i < argc; i++) + for (i = optind; i < argc; i++) { if (_stricmp(argv[i], "chat") == 0) IncludesChat = TRUE; @@ -936,7 +1039,7 @@ int main(int argc, char * argv[]) // Start Mail if requested by command line or config - for (i = 1; i < argc; i++) + for (i = optind; i < argc; i++) { if (_stricmp(argv[i], "mail") == 0) IncludesMail = TRUE; @@ -1166,7 +1269,7 @@ int main(int argc, char * argv[]) DoHouseKeeping(FALSE); } } - for (i = 1; i < argc; i++) + for (i = optind; i < argc; i++) { if (_stricmp(argv[i], "tidymail") == 0) DeleteRedundantMessages(); @@ -1799,6 +1902,8 @@ struct TNCINFO * TNC; #define CLOCK_REALTIME 0 #define CLOCK_MONOTONIC 0 + + int clock_gettime(int clk_id, struct timespec *t){ mach_timebase_info_data_t timebase; mach_timebase_info(&timebase); @@ -1813,7 +1918,8 @@ int clock_gettime(int clk_id, struct timespec *t){ #endif #endif -int GetTickCount() + +uint64_t GetTickCount() { struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); diff --git a/MailNode.ncb b/MailNode.ncb new file mode 100644 index 0000000..233beff Binary files /dev/null and b/MailNode.ncb differ diff --git a/MailNode.vcproj b/MailNode.vcproj index bfa832d..4478265 100644 --- a/MailNode.vcproj +++ b/MailNode.vcproj @@ -336,6 +336,10 @@ RelativePath=".\FreeDATA.c" > + + diff --git a/MailNode.vcproj.DESKTOP-MHE5LO8.johnw.user b/MailNode.vcproj.DESKTOP-MHE5LO8.johnw.user new file mode 100644 index 0000000..f8980b0 --- /dev/null +++ b/MailNode.vcproj.DESKTOP-MHE5LO8.johnw.user @@ -0,0 +1,65 @@ + + + + + + + + + + + diff --git a/MailNode.vcproj.DESKTOP-TGEL8RC.John.user b/MailNode.vcproj.DESKTOP-TGEL8RC.John.user index 6975522..137b905 100644 --- a/MailNode.vcproj.DESKTOP-TGEL8RC.John.user +++ b/MailNode.vcproj.DESKTOP-TGEL8RC.John.user @@ -11,7 +11,7 @@ {3766AA10-C777-4ED8-A83D-F1452DE9B666} MailNode Win32Proj + 10.0.17763.0 @@ -119,7 +120,7 @@ ProgramDatabase - kernel32.lib;WS2_32.Lib;C:\OneDrive\Dev\Source\bpq32\libconfig\x64\Release\libconfig.lib;DbgHelp.lib;setupapi.lib;C:\OneDrive\Dev\Source\miniupnpc-2.2.3\msvc\x64\Debug\miniupnpc.lib;C:\Users\johnw\Downloads\zlib-1.2.11-binaries-x64-release\zlib-1.2.11\binaries\x64\Release\zlib.lib;%(AdditionalDependencies) + kernel32.lib;WS2_32.Lib;..\lib\libconfigd.lib;DbgHelp.lib;setupapi.lib;miniupnpc.lib;zlibstat.lib;%(AdditionalDependencies) c:\LINBPQ\$(ProjectName).exe true true @@ -127,7 +128,6 @@ Console 4000000 0 - false diff --git a/MailNode.vcxproj.user b/MailNode.vcxproj.user deleted file mode 100644 index 448994b..0000000 --- a/MailNode.vcxproj.user +++ /dev/null @@ -1,8 +0,0 @@ - - - - C:\Dev\Msdev2005\projects\bpq32\BPQMail\x64\Debug\LinBPQ.exe - c:\linbpq - WindowsLocalDebugger - - \ No newline at end of file diff --git a/MailTCP-DESKTOP-MHE5LO8.c b/MailTCP-DESKTOP-MHE5LO8.c new file mode 100644 index 0000000..b26f6da --- /dev/null +++ b/MailTCP-DESKTOP-MHE5LO8.c @@ -0,0 +1,4127 @@ +/* +Copyright 2001-2018 John Wiseman G8BPQ + +This file is part of LinBPQ/BPQ32. + +LinBPQ/BPQ32 is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +LinBPQ/BPQ32 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses +*/ + +// Mail and Chat Server for BPQ32 Packet Switch +// +// TCP access module - POP and SMTP + +#include "bpqmail.h" + +VOID ReleaseSock(SOCKET sock); +void Base64EncodeAndSend(SocketConn * sockptr, UCHAR * Msg, int Len); + +#define MaxSockets 64 + +SocketConn * Sockets = NULL; + +int CurrentConnections; + +int CurrentSockets=0; + +#define MAX_PENDING_CONNECTS 4 + +#define VERSION_MAJOR 2 +#define VERSION_MINOR 0 + +static SOCKADDR_IN local_sin; /* Local socket - internet style */ +static PSOCKADDR_IN psin; + +SOCKET smtpsock, pop3sock; + +char szBuff[80]; + +int SMTPInPort; +int POP3InPort; + +BOOL RemoteEmail; // Set to listen on INADDR_ANY rather than LOCALHOST + +BOOL ISP_Gateway_Enabled; + +char MyDomain[50]; // Mail domain for BBS<>Internet Mapping + +char ISPSMTPName[50]; +char ISPEHLOName[50] = ""; + +int ISPSMTPPort; + +char ISPPOP3Name[50]; +int ISPPOP3Port; + +char ISPAccountName[50]; +char ISPAccountPass[50]; +char EncryptedISPAccountPass[100]; +int EncryptedPassLen; + +BOOL SMTPAuthNeeded; + +BOOL GMailMode = FALSE; +char GMailName[50]; + +int POP3Timer=9999; // Run on startup +int ISPPOP3Interval; + +BOOL SMTPMsgCreated=FALSE; // Set to cause SMTP client to send messages to ISP +BOOL SMTPActive=FALSE; // SO we don't try every 10 secs! + +char mycd64[256]; +static const char cb64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static const char cd64[]="|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW$$$$$$XYZ[\\]^_`abcdefghijklmnopq"; + +char sockTypes[6][12] = {"Undefined", "SMTPServer", "POP3Server", "SMTPClient", "POP3Client", "NNTPServer"}; + +void decodeblock( unsigned char in[4], unsigned char out[3] ); +VOID FormatTime(char * Time, time_t cTime); +static int Socket_Accept(SOCKET SocketId); + +int SendSock(SocketConn * sockptr, char * msg) +{ + int len = (int)strlen(msg), sent; + char * newmsg = malloc(len+10); + + WriteLogLine(NULL, '>',msg, len, LOG_TCP); + + strcpy(newmsg, msg); + + strcat(newmsg, "\r\n"); + + len+=2; + + if (sockptr->SendBuffer) + { + // Already queued, so add to end + + if ((sockptr->SendSize + len) > sockptr->SendBufferSize) + { + sockptr->SendBufferSize += (10000 + len); + sockptr->SendBuffer = realloc(sockptr->SendBuffer, sockptr->SendBufferSize); + } + + memcpy(&sockptr->SendBuffer[sockptr->SendSize], newmsg, len); + sockptr->SendSize += len; + free (newmsg); + return len; + } + + sent = send(sockptr->socket, newmsg, len, 0); + + if (sent < len) + { + int error, remains; + + // Not all could be sent - queue rest + + if (sent == SOCKET_ERROR) + { + error = WSAGetLastError(); + if (error == WSAEWOULDBLOCK) + sent=0; + + // What else?? + } + + remains = len - sent; + + sockptr->SendBufferSize += (10000 + remains); + sockptr->SendBuffer = malloc(sockptr->SendBufferSize); + + memcpy(sockptr->SendBuffer, &newmsg[sent], remains); + + sockptr->SendSize = remains; + sockptr->SendPtr = 0; + + } + + free (newmsg); + + return sent; +} + +VOID __cdecl sockprintf(SocketConn * sockptr, const char * format, ...) +{ + // printf to a socket + + char buff[1000]; + va_list(arglist); + + va_start(arglist, format); + vsprintf(buff, format, arglist); + + SendSock(sockptr, buff); +} + +extern int SMTPMsgs; + +fd_set ListenSet; +SOCKET ListenMax = 0; + +extern SOCKET nntpsock; + +int NNTP_Read(SocketConn * sockptr, SOCKET sock); + +VOID SetupListenSet() +{ + // Set up master set of fd's for checking for incoming calls + + fd_set * readfd = &ListenSet; + SOCKET sock; + + FD_ZERO(readfd); + + sock = nntpsock; + if (sock) + { + FD_SET(sock, readfd); + if (sock > ListenMax) + ListenMax = sock; + } + + sock = smtpsock; + if (sock) + { + FD_SET(sock, readfd); + if (sock > ListenMax) + ListenMax = sock; + } + + sock = pop3sock; + + if (sock) + { + FD_SET(sock, readfd); + if (sock > ListenMax) + ListenMax = sock; + } +} + +VOID Socket_Connected(SocketConn * sockptr, int error) +{ + SOCKET sock = sockptr->socket; + + if (error) + { + Logprintf(LOG_TCP, NULL, '|', "Connect Failed"); + + if (sockptr->Type == SMTPClient) + SMTPActive = FALSE; + + ReleaseSock(sock); + + return; + } + + sockptr->State = WaitingForGreeting; + + if (sockptr->Type == NNTPServer) + SendSock(sockptr, "200 BPQMail NNTP Server ready"); + + else if (sockptr->Type == SMTPServer) + SendSock(sockptr, "220 BPQMail SMTP Server ready"); + + else if (sockptr->Type == POP3SLAVE) + { + SendSock(sockptr, "+OK POP3 server ready"); + sockptr->State = GettingUser; + } +} + +VOID TCPFastTimer() +{ + // we now poll for incoming connections and data + + fd_set readfd, writefd, exceptfd; + struct timeval timeout; + int retval; + SocketConn * sockptr = Sockets; + SOCKET sock; + int Active = 0; + SOCKET maxsock; + + timeout.tv_sec = 0; + timeout.tv_usec = 0; // poll + + if (ListenMax) + { + memcpy(&readfd, &ListenSet, sizeof(fd_set)); + + retval = select((int)ListenMax + 1, &readfd, NULL, NULL, &timeout); + + if (retval == -1) + { + retval = 0; + perror("Listen select"); + } + + if (retval) + { + sock = pop3sock; + if (sock) + if (FD_ISSET(sock, &readfd)) + Socket_Accept(sock); + + sock = smtpsock; + if (sock) + if (FD_ISSET(sock, &readfd)) + Socket_Accept(sock); + + sock = nntpsock; + if (sock) + if (FD_ISSET(sock, &readfd)) + NNTP_Accept(sock); + } + } + + // look for data on any active sockets + + maxsock = 0; + + FD_ZERO(&readfd); + FD_ZERO(&writefd); + FD_ZERO(&exceptfd); + sockptr=Sockets; + + while (sockptr) + { + sockptr->Timeout++; + + if (sockptr->Timeout > 1200) // 2 mins + { + Logprintf(LOG_TCP, NULL, '|', "Timeout on Socket = %d", sockptr->socket); + shutdown(sockptr->socket, 0); + closesocket(sockptr->socket); + ReleaseSock(sockptr->socket); + + return; // We've messed with chain + } + + if (sockptr->State & Connecting) + { + // look for complete or failed + + FD_SET(sockptr->socket, &writefd); + FD_SET(sockptr->socket, &exceptfd); + } + else + FD_SET(sockptr->socket, &readfd); + + Active++; + + if (sockptr->socket > maxsock) + maxsock = sockptr->socket; + + sockptr = sockptr->Next; + } + + if (Active == 0) + return; + + retval = select((int)maxsock + 1, &readfd, &writefd, &exceptfd, &timeout); + + if (retval == -1) + { + perror("select"); + + // we need to do something or the error will recur. + // As there are unlikely to be a lot of open tcp connections perhaps + // simplest is to close all + + sockptr = Sockets; + + while (sockptr) + { + Debugprintf("MAILTCP Select Failed Active %s Socket", sockTypes[sockptr->Type]); + shutdown(sockptr->socket, 0); + closesocket(sockptr->socket); + ReleaseSock(sockptr->socket); + + sockptr = Sockets; // We've messed with chain + } + } + else + { + if (retval) + { + sockptr = Sockets; + + // see who has data + + while (sockptr) + { + sock = sockptr->socket; + + if (FD_ISSET(sock, &readfd)) + { + sockptr->Timeout = 0; + + if (sockptr->Type == NNTPServer) + { + if (NNTP_Read(sockptr, sock) == 0) + break; // We've messed with the chain + } + else + { + if (DataSocket_Read(sockptr, sock) == 0) + break; // We've messed with the chain + } + } + if (FD_ISSET(sockptr->socket, &writefd)) + Socket_Connected(sockptr, 0); + + if (FD_ISSET(sockptr->socket, &exceptfd)) + { + Socket_Connected(sockptr, 1); + return; + } + sockptr = sockptr->Next; + } + } + } +} + +VOID TCPTimer() +{ + POP3Timer+=10; + +// Debugprintf("POP3 Debug Timer = %d Interval = %d Port %d Enabled %d", +// POP3Timer, ISPPOP3Interval, ISPPOP3Port, ISP_Gateway_Enabled); + + if (POP3Timer > ISPPOP3Interval) // 5 mins + { + POP3Timer=0; + + if ((ISPSMTPPort && ISP_Gateway_Enabled)) + SendtoISP(); + + if (ISPPOP3Port && ISP_Gateway_Enabled) + { +// Debugprintf("Calling POP3 Connect"); + POP3Connect(ISPPOP3Name, ISPPOP3Port); + } + + if (SMTPMsgs && ISPSMTPPort && ISP_Gateway_Enabled) + SendtoISP(); + } + else + { + if (SMTPMsgCreated && ISPSMTPPort && ISP_Gateway_Enabled) + SendtoISP(); + } +} +BOOL InitialiseTCP() +{ + int Error; // catches return value of WSAStartup +#ifdef WIN32 + WORD VersionRequested; // passed to WSAStartup + WSADATA WsaData; // receives data from WSAStartup +#endif + int i,j; + + + for (i=0;i<64; i++) + { + j=cb64[i]; + mycd64[j]=i; + } + +#ifdef WIN32 + + VersionRequested = MAKEWORD(VERSION_MAJOR, VERSION_MINOR); + + Error = WSAStartup(VersionRequested, &WsaData); + + if (Error) + { +#ifndef LINBPQ + MessageBox(NULL, + "Could not find high enough version of WinSock", + "BPQMailChat", MB_OK | MB_ICONSTOP | MB_SETFOREGROUND); +#else + printf("Could not find high enough version of WinSock\n"); +#endif + return FALSE; + } + +#endif + +// Create listening sockets + + + if (SMTPInPort) + smtpsock = CreateListeningSocket(SMTPInPort); + + if (POP3InPort) + pop3sock = CreateListeningSocket(POP3InPort); + + if (ISP_Gateway_Enabled) + { + // See if using GMail + + char * ptr = strchr(ISPAccountName, '@'); + + if (ptr) + { + if (_stricmp(&ptr[1], "gmail.com") == 0 || _stricmp(&ptr[1], "googlemail.com") == 0) + { + strcpy(GMailName, ISPAccountName); + strlop(GMailName, '@'); + GMailMode = TRUE; + SMTPAuthNeeded = TRUE; + } + } + } + + return TRUE; + +} + + +SOCKET CreateListeningSocket(int Port) +{ + SOCKET sock; + unsigned int param = 1; + + sock = socket( AF_INET, SOCK_STREAM, 0); + + if (sock == INVALID_SOCKET) + { + sprintf(szBuff, "socket() failed error %d", WSAGetLastError()); +#ifdef LINBPQ + perror(szBuff); +#else + MessageBox(MainWnd, szBuff, "BPQMailChat", MB_OK); +#endif + return FALSE; + } + + setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, (char *)¶m,4); + + psin=&local_sin; + + psin->sin_family = AF_INET; + psin->sin_addr.s_addr = htonl(RemoteEmail ? INADDR_ANY : INADDR_LOOPBACK); // Local Host Olny + + psin->sin_port = htons(Port); /* Convert to network ordering */ + + if (bind( sock, (struct sockaddr FAR *) &local_sin, sizeof(local_sin)) == SOCKET_ERROR) + { + sprintf(szBuff, "bind(%d) failed Error %d", Port, WSAGetLastError()); +#ifdef LINBPQ + perror(szBuff); +#else + MessageBox(MainWnd, szBuff, "BPQMailChat", MB_OK); +#endif + closesocket( sock ); + return FALSE; + } + + if (listen( sock, MAX_PENDING_CONNECTS ) < 0) + { + sprintf(szBuff, "listen(%d) failed Error %d", Port, WSAGetLastError()); +#ifdef LINBPQ + perror(szBuff); +#else + MessageBox(MainWnd, szBuff, "BPQMailChat", MB_OK); +#endif + closesocket( sock ); + return FALSE; + } + + ioctl(sock, FIONBIO, ¶m); + return sock; +} + +static int Socket_Accept(SOCKET SocketId) +{ + int addrlen; + SocketConn * sockptr; + SOCKET sock; + unsigned int param = 1; + + addrlen=sizeof(struct sockaddr); + + // Allocate a Socket entry + + sockptr = malloc(sizeof(SocketConn)); + memset(sockptr, 0, sizeof (SocketConn)); + + sockptr->Next = Sockets; + Sockets = sockptr; + + sock = accept(SocketId, (struct sockaddr *)&sockptr->sin, &addrlen); + + if (sock == INVALID_SOCKET) + { + Logprintf(LOG_TCP, NULL, '|', " accept() failed Error %d", WSAGetLastError()); + + // get rid of socket record + + Sockets = sockptr->Next; + free(sockptr); + return FALSE; + } + + ioctl(sock, FIONBIO, ¶m); + + + sockptr->socket = sock; + + if (SocketId == pop3sock) + { + sockptr->Type = POP3SLAVE; + SendSock(sockptr, "+OK POP3 server ready"); + sockptr->State = GettingUser; + Logprintf(LOG_TCP, NULL, '|', "Incoming POP3 Connect Socket = %d", sock); + } + else + { + sockptr->Type = SMTPServer; + sockptr->State = WaitingForGreeting; + SendSock(sockptr, "220 BPQMail SMTP Server ready"); + Logprintf(LOG_TCP, NULL, '|', "Incoming SMTP Connect Socket = %d", sock); + } + + return 0; +} + + +VOID ReleaseSock(SOCKET sock) +{ + // remove and free the socket record + + SocketConn * sockptr, * lastptr; + + sockptr=Sockets; + lastptr=NULL; + + while (sockptr) + { + if (sockptr->socket == sock) + { + if (lastptr) + lastptr->Next=sockptr->Next; + else + Sockets=sockptr->Next; + + if (sockptr->POP3User) + sockptr->POP3User->POP3Locked = FALSE; + + if (sockptr->State == WaitingForGreeting) + { + Logprintf(LOG_TCP, NULL, '|', "Premature Close on Socket %d", sock); + + if (sockptr->Type == SMTPClient) + SMTPActive = FALSE; + } + else + Logprintf(LOG_TCP, NULL, '|', "Socket %d Closed", sock); + + + free(sockptr); + return; + } + else + { + lastptr=sockptr; + sockptr=sockptr->Next; + } + } +} + +/* +int Socket_Data(int sock, int error, int eventcode) +{ + SocketConn * sockptr; + + // Find Connection Record + + sockptr=Sockets; + + while (sockptr) + { + if (sockptr->socket == sock) + { + switch (eventcode) + { + case FD_READ: + + return DataSocket_Read(sockptr,sock); + + case FD_WRITE: + + // Either Just connected, or flow contorl cleared + + if (sockptr->SendBuffer) + // Data Queued + SendFromQueue(sockptr); + else + { + if (sockptr->Type == SMTPServer) + SendSock(sockptr, "220 BPQMail SMTP Server ready"); + else + { + if (sockptr->Type == POP3SLAVE) + { + SendSock(sockptr, "+OK POP3 server ready"); + sockptr->State = GettingUser; + } + } + } + return 0; + + case FD_OOB: + + return 0; + + case FD_ACCEPT: + + return 0; + + case FD_CONNECT: + + return 0; + + case FD_CLOSE: + + closesocket(sock); + ReleaseSock(sock); + return 0; + } + return 0; + } + else + sockptr=sockptr->Next; + } + + return 0; +} +*/ +int DataSocket_Read(SocketConn * sockptr, SOCKET sock) +{ + int InputLen, MsgLen; + char * ptr, * ptr2; + char Buffer[2000]; + + // May have several messages per packet, or message split over packets + + if (sockptr->InputLen > 1000) // Shouldnt have lines longer than this in text mode + { + sockptr->InputLen=0; + } + + InputLen=recv(sock, &sockptr->TCPBuffer[sockptr->InputLen], 1000, 0); + + if (InputLen <= 0) + { + int x = WSAGetLastError(); + + closesocket(sock); + ReleaseSock(sock); + + return 0; // Does this mean closed? + } + + sockptr->InputLen += InputLen; + +loop: + + ptr = memchr(sockptr->TCPBuffer, '\n', sockptr->InputLen); + + if (ptr) // CR in buffer + { + ptr2 = &sockptr->TCPBuffer[sockptr->InputLen]; + ptr++; // Assume LF Follows CR + + if (ptr == ptr2) + { + // Usual Case - single meg in buffer + + if (sockptr->Type == SMTPServer) + ProcessSMTPServerMessage(sockptr, sockptr->TCPBuffer, sockptr->InputLen); + else + if (sockptr->Type == POP3SLAVE) + ProcessPOP3ServerMessage(sockptr, sockptr->TCPBuffer, sockptr->InputLen); + else + if (sockptr->Type == SMTPClient) + ProcessSMTPClientMessage(sockptr, sockptr->TCPBuffer, sockptr->InputLen); + else + if (sockptr->Type == POP3Client) + ProcessPOP3ClientMessage(sockptr, sockptr->TCPBuffer, sockptr->InputLen); + + sockptr->InputLen=0; + + } + else + { + // buffer contains more that 1 message + + MsgLen = sockptr->InputLen - (int)(ptr2-ptr); + + memcpy(Buffer, sockptr->TCPBuffer, MsgLen); + + + if (sockptr->Type == SMTPServer) + ProcessSMTPServerMessage(sockptr, Buffer, MsgLen); + else + if (sockptr->Type == POP3SLAVE) + ProcessPOP3ServerMessage(sockptr, Buffer, MsgLen); + else + if (sockptr->Type == SMTPClient) + ProcessSMTPClientMessage(sockptr, Buffer, MsgLen); + else + if (sockptr->Type == POP3Client) + ProcessPOP3ClientMessage(sockptr, Buffer, MsgLen); + + + memmove(sockptr->TCPBuffer, ptr, sockptr->InputLen-MsgLen); + + sockptr->InputLen -= MsgLen; + + goto loop; + + } + } + return TRUE; +} + +char * FindPart(char ** Msg, char * Boundary, int * PartLen) +{ + char * ptr = *Msg, * ptr2; + char * Msgptr = *Msg; + int BLen = (int)strlen(Boundary); + char * Part; + + while(*ptr) // Just in case we run off end + { + ptr2 = strchr(ptr, 10); // Find LF + + if (ptr2 == NULL) return NULL; + + if (*ptr == '-' && *(ptr+1) == '-') + { + if (memcmp(&ptr[2], Boundary, BLen) == 0) + { + // Found Boundary + + int Partlen = (int)(ptr - Msgptr); + Part = malloc(Partlen + 1); + memcpy(Part, Msgptr, Partlen); + Part[Partlen] = 0; + + *Msg = ++ptr2; + + *PartLen = Partlen; + + return Part; + } + } + + ptr = ++ptr2; + } + return NULL; +} + + + + + +BOOL CheckforMIME(SocketConn * sockptr, char * Msg, char ** Body, int * MsgLen) // Will reformat message if necessary. +{ + int i; + char * ptr, * ptr2, * ptr3, * ptr4; + char Boundary[1000]; + BOOL Multipart = FALSE; + BOOL ALT = FALSE; + int Partlen; + char * Save; + BOOL Base64 = FALSE; + BOOL QuotedP = FALSE; + + char FileName[100][250] = {""}; + int FileLen[100]; + char * FileBody[100]; + char * MallocSave[100]; + UCHAR * NewMsg; + + int Files = 0; + + ptr = Msg; + + while(*ptr != 13) + { + ptr2 = strchr(ptr, 10); // Find CR + + while(ptr2[1] == ' ' || ptr2[1] == 9) // Whitespace - continuation line + { + ptr2 = strchr(&ptr2[1], 10); // Find CR + } + +// Content-Type: multipart/mixed; +// boundary="----=_NextPart_000_025B_01CAA004.84449180" +// 7.2.2 The Multipart/mixed (primary) subtype +// 7.2.3 The Multipart/alternative subtype + + + if (_memicmp(ptr, "Content-Type: ", 14) == 0) + { + char Line[1000] = ""; + char lcLine[1000] = ""; + + char * ptr3; + + memcpy(Line, &ptr[14], ptr2-ptr-14); + memcpy(lcLine, &ptr[14], ptr2-ptr-14); + _strlwr(lcLine); + + if (_memicmp(Line, "Multipart/", 10) == 0) + { + Multipart = TRUE; + + if (_memicmp(&Line[10], "alternative", 11) == 0) + { + ALT = TRUE; + } + + ptr3 = strstr(Line, "boundary"); + + if (ptr3) + { + ptr3+=9; + + if ((*ptr3) == '"') + ptr3++; + + strcpy(Boundary, ptr3); + ptr3 = strchr(Boundary, '"'); + if (ptr3) *ptr3 = 0; + ptr3 = strchr(Boundary, 13); // CR + if (ptr3) *ptr3 = 0; + + } + else + return FALSE; // Can't do anything without a boundary ?? + } + + } + + else if (_memicmp(ptr, "Content-Transfer-Encoding:", 26) == 0) + { + if (strstr(&ptr[26], "base64")) + Base64 = TRUE; + else + if (strstr(&ptr[26], "quoted-printable")) + QuotedP = TRUE; + } + + + ptr = ptr2; + ptr++; + + } + + if (Multipart == FALSE) + { + // We only have one part, but it could have an odd encoding + + if (Base64) + { + int i = 0, Len = *MsgLen, NewLen; + char * ptr2; + char * End; + + ptr = ptr2 = *Body; + End = ptr + Len; + + while (ptr < End) + { + while (*ptr < 33) + {ptr++;} + + *ptr2++ = *ptr++; + } + + *ptr2 = 0; + + ptr = *Body; + Len = (int)(ptr2 - ptr - 1); + + ptr2 = ptr; + + while (Len > 0) + { + decodeblock(ptr, ptr2); + ptr += 4; + ptr2 += 3; + Len -= 4; + } + + NewLen = (int)(ptr2 - *Body); + + if (*(ptr-1) == '=') + NewLen--; + + if (*(ptr-2) == '=') + NewLen--; + + *MsgLen = NewLen; + } + else if (QuotedP) + { + int i = 0, Len = *MsgLen; + char * ptr2; + char * End; + + ptr = ptr2 =*Body; + + End = ptr + Len; + + while (ptr < End) + { + if ((*ptr) == '=') + { + char c = *(++ptr); + char d; + + c = c - 48; + if (c < 0) + { + // = CRLF as a soft break + + ptr += 2; + continue; + } + + if (c > 9) + c -= 7; + d = *(++ptr); + d = d - 48; + if (d > 9) + d -= 7; + + *(ptr2) = c << 4 | d; + ptr2++; + ptr++; + } + else + { + *ptr2++ = *ptr++; + } + } + *ptr2 = 0; + + *MsgLen = (int)(ptr2 - *Body); + + } + + return FALSE; + } + // FindPart Returns Next Part of Message, Updates Input Pointer + // Skip to first Boundary (over the non MIME Alt Part) + + ptr = FindPart(Body, Boundary, &Partlen); + + if (ptr == NULL) + return FALSE; // Couldn't find separator + + free(ptr); + + if (ALT) + { + // Assume HTML and Plain Text Versions of the same single body. + + ptr = FindPart(Body, Boundary, &Partlen); + + Save = ptr; // For free(); + + // Should be the First (Least desireable part, but the bit we want, as we are only interested in plain text) + + // Skip any headers + + while(*ptr != 13) + { + if (_memicmp(ptr, "Content-Transfer-Encoding:", 26) == 0) + { + if (strstr(&ptr[26], "base64")) + Base64 = TRUE; + else + if (strstr(&ptr[26], "quoted-printable")) + QuotedP = TRUE; + } + + ptr2 = strchr(ptr, 10); // Find CR + + while(ptr2[1] == ' ' || ptr2[1] == 9) // Whitespace - continuation line + { + ptr2 = strchr(&ptr2[1], 10); // Find CR + } + + ptr = ++ptr2; + } + + ptr += 2; // Skip rerminating line + + // Should now have a plain text body to return; + + // But could be an odd encoding + + if (Base64) + { + int i = 0, Len = (int)strlen(ptr), NewLen; + char * ptr2; + char * End; + char * Save = ptr; + + ptr2 = ptr; + End = ptr + Len; + + while (ptr < End) + { + while (*ptr < 33) + {ptr++;} + + *ptr2++ = *ptr++; + } + + *ptr2 = 0; + + ptr = Save; + Len = (int)(ptr2 - ptr - 1); + + ptr2 = *Body; + + while (Len > 0) + { + decodeblock(ptr, ptr2); + ptr += 4; + ptr2 += 3; + Len -= 4; + } + + NewLen = (int)(ptr2 - *Body); + + if (*(ptr-1) == '=') + NewLen--; + + if (*(ptr-2) == '=') + NewLen--; + + *MsgLen = NewLen; + } + else if (QuotedP) + { + int i = 0, Len = (int)strlen(ptr); + char * ptr2; + char * End; + char * Save = ptr; + + ptr2 = *Body; + + End = ptr + Len; + + while (ptr < End) + { + if ((*ptr) == '=') + { + char c = *(++ptr); + char d; + + c = c - 48; + if (c < 0) + { + // = CRLF as a soft break + + ptr += 2; + continue; + } + + if (c > 9) + c -= 7; + d = *(++ptr); + d = d - 48; + if (d > 9) + d -= 7; + + *(ptr2) = c << 4 | d; + ptr2++; + ptr++; + } + else + { + *ptr2++ = *ptr++; + } + } + *ptr2 = 0; + + *MsgLen = (int)(ptr2 - *Body); + } + else + { + strcpy(*Body, ptr); + *MsgLen = (int)strlen(ptr); + } + free(Save); + + return FALSE; + } + + // Assume Multipart/Mixed - Message with attachments + + ptr = FindPart(Body, Boundary, &Partlen); + + if (ptr == NULL) + return FALSE; // Couldn't find separator + + while (ptr) + { + BOOL Base64 = FALSE; + BOOL QuotedP = FALSE; + + MallocSave[Files] = ptr; // For free(); + + // Should be the First (Least desireable part, but the bit we want, as we are only interested in plain text) + + // Process headers - looking for Content-Disposition: attachment; + + // The first could also be a Content-Type: multipart/alternative; - if so, feed back to mime handler + + while(*ptr != 13) + { + char lcLine[1000] = ""; + + ptr2 = strchr(ptr, 10); // Find CR + + if (ptr2 == 0) + return FALSE; + + while(ptr2[1] == ' ' || ptr2[1] == 9) // Whitespace - continuation line + { + ptr2 = strchr(&ptr2[1], 10); // Find CR + } + + memcpy(lcLine, ptr, ptr2-ptr-1); + _strlwr(lcLine); + + ptr = lcLine; + + if (_memicmp(ptr, "Content-Type: Multipart/alternative", 30) == 0) + { + // Feed Back + int MsgLen; + char * Text = malloc(Partlen+1); + + memcpy(Text, MallocSave[Files], Partlen); + + free(MallocSave[Files]); + MallocSave[Files] = Text; + + + CheckforMIME(sockptr, Text, &Text, &MsgLen); + + FileName[Files][0] = 0; + FileBody[Files] = Text; + + + FileLen[Files++] = MsgLen; + + goto NextPart; + + } + else if (_memicmp(ptr, "Content-Disposition: ", 21) == 0) + { + ptr3 = strstr(&ptr[21], "filename"); + + if (ptr3) + { + ptr3 += 9; + if (*ptr3 == '"') ptr3++; + ptr4 = strchr(ptr3, '"'); + if (ptr4) *ptr4 = 0; + + strcpy(FileName[Files], ptr3); + } + } + + else if (_memicmp(ptr, "Content-Transfer-Encoding:", 26) == 0) + { + if (strstr(&ptr[26], "base64")) + Base64 = TRUE; + else + if (strstr(&ptr[26], "quoted-printable")) + QuotedP = TRUE; + } + + ptr = ++ptr2; + } + + ptr += 2; + + // Should now have file or plain text. If file is Base64 encoded, decode it. + + FileBody[Files] = ptr; + FileLen[Files] = (int)(Partlen - 2 - (ptr - MallocSave[Files])); + + if (Base64) + { + int i = 0, Len = FileLen[Files], NewLen; + char * ptr2 = ptr; + char * End; + + End = ptr + FileLen[Files]; + + while (ptr < End) + { + while (*ptr < 33) + {ptr++;} + + *ptr2++ = *ptr++; + } + *ptr2 = 0; + + ptr = FileBody[Files]; + Len = (int)(ptr2 - ptr - 1); + + ptr2 = ptr; + + while (Len > 0) + { + decodeblock(ptr, ptr2); + ptr += 4; + ptr2 += 3; + Len -= 4; + } + + NewLen = (int)(ptr2 - FileBody[Files]); + + if (*(ptr-1) == '=') + NewLen--; + + if (*(ptr-2) == '=') + NewLen--; + + FileLen[Files] = NewLen; + } + else if (QuotedP) + { + int i = 0, Len = FileLen[Files], NewLen; + char * ptr2 = ptr; + char * End; + + End = ptr + FileLen[Files]; + + while (ptr < End) + { + if ((*ptr) == '=') + { + char c = *(++ptr); + char d; + + c = c - 48; + if (c < 0) + { + // = CRLF as a soft break + + ptr += 2; + continue; + } + + if (c > 9) + c -= 7; + d = *(++ptr); + d = d - 48; + if (d > 9) + d -= 7; + + *(ptr2) = c << 4 | d; + ptr2++; + ptr++; + } + else + { + *ptr2++ = *ptr++; + } + } + *ptr2 = 0; + + NewLen = (int)(ptr2 - FileBody[Files]); + + FileLen[Files] = NewLen; + } + + Files++; + + NextPart: + ptr = FindPart(Body, Boundary, &Partlen); + } + + // Now have all the parts - build a B2 Message. Leave the first part of header for later, + // as we may have multiple recipients. Start with the Body: Line. + + // We need to add the first part of header later, so start message part way down buffer. + // Make sure buffer is big enough. + + if ((sockptr->MailSize + 2000) > sockptr->MailBufferSize) + { + sockptr->MailBufferSize += 2000; + sockptr->MailBuffer = realloc(sockptr->MailBuffer, sockptr->MailBufferSize); + + if (sockptr->MailBuffer == NULL) + { + CriticalErrorHandler("Failed to extend Message Buffer"); + shutdown(sockptr->socket, 0); + return FALSE; + } + } + + + NewMsg = sockptr->MailBuffer + 1000; + + NewMsg += sprintf(NewMsg, "Body: %d\r\n", FileLen[0]); + + for (i = 1; i < Files; i++) + { + NewMsg += sprintf(NewMsg, "File: %d %s\r\n", FileLen[i], FileName[i]); + } + + NewMsg += sprintf(NewMsg, "\r\n"); + + for (i = 0; i < Files; i++) + { + memcpy(NewMsg, FileBody[i], FileLen[i]); + NewMsg += FileLen[i]; + free(MallocSave[i]); + NewMsg += sprintf(NewMsg, "\r\n"); + } + + *MsgLen = (int)(NewMsg - (sockptr->MailBuffer + 1000)); + *Body = sockptr->MailBuffer + 1000; + + return TRUE; // B2 Message +} + + +VOID ProcessSMTPServerMessage(SocketConn * sockptr, char * Buffer, int Len) +{ + SOCKET sock; + int i; + time_t Date = 0; + + sock=sockptr->socket; + + WriteLogLine(NULL, '<',Buffer, Len-2, LOG_TCP); + + if (sockptr->Flags == GETTINGMESSAGE) + { + if(memcmp(Buffer, ".\r\n", 3) == 0) + { + char * ptr1, * ptr2; + int linelen, MsgLen; + char Msgtitle[62]; + BOOL B2Flag; + int ToLen = 0; + char * ToString; + char * Via; + + // Scan headers for a Subject: or Date: Line (Headers end at blank line) + + ptr1 = sockptr->MailBuffer; + Loop: + ptr2 = strchr(ptr1, '\r'); + + if (ptr2 == NULL) + { + SendSock(sockptr, "500 Eh"); + return; + } + + linelen = (int)(ptr2 - ptr1); + + if (_memicmp(ptr1, "Subject:", 8) == 0) + { + if (linelen > 68) linelen = 68; + memcpy(Msgtitle, &ptr1[9], linelen-9); + Msgtitle[linelen-9]=0; + } + + if (_memicmp(ptr1, "Date:", 5) == 0) + { + struct tm rtime; + char * Context; + char seps[] = " ,\t\r"; + char Offset[10] = ""; + int i, HH, MM; + char Copy[500]=""; + + // Copy message, so original isn't messed up by strtok + + memcpy(Copy, ptr1, linelen); + + ptr1 = Copy; + + memset(&rtime, 0, sizeof(struct tm)); + + // Date: Tue, 9 Jun 2009 20:54:55 +0100 + + ptr1 = strtok_s(&ptr1[5], seps, &Context); // Skip Day + ptr1 = strtok_s(NULL, seps, &Context); // Day + + rtime.tm_mday = atoi(ptr1); + + ptr1 = strtok_s(NULL, seps, &Context); // Month + + for (i=0; i < 12; i++) + { + if (strcmp(month[i], ptr1) == 0) + { + rtime.tm_mon = i; + break; + } + } + + sscanf(Context, "%04d %02d:%02d:%02d%s", + &rtime.tm_year, &rtime.tm_hour, &rtime.tm_min, &rtime.tm_sec, Offset); + + rtime.tm_year -= 1900; + + Date = mktime(&rtime) - (time_t)_MYTIMEZONE; + + if (Date == (time_t)-1) + Date = 0; + else + { + if ((Offset[0] == '+') || (Offset[0] == '-')) + { + MM = atoi(&Offset[3]); + Offset[3] = 0; + HH = atoi(&Offset[1]); + MM = MM + (60 * HH); + + if (Offset[0] == '+') + Date -= (60*MM); + else + Date += (60*MM); + + } + } + } + + ptr1 = ptr2 + 2; // Skip crlf + + if (linelen) // Not Null line + { + goto Loop; + } + + ptr2 = ptr1; + ptr1 = sockptr->MailBuffer; + + MsgLen = (int)(sockptr->MailSize - (ptr2 - ptr1)); + + // We Just want the from call, not the full address. + + TidyString(sockptr->MailFrom); + + // Examine Message to look for html formatting and attachments. + + B2Flag = CheckforMIME(sockptr, sockptr->MailBuffer, &ptr2, &MsgLen); // Will reformat message if necessary. + + // If any recipients are via RMS, create one message for them, and separate messages for all others + + ToString = zalloc(sockptr->Recipients * 100); + + for (i=0; i < sockptr->Recipients; i++) + { + char Addr[256]; // Need copy, as we may change it then decide it isn't for RMS + + strcpy(Addr, sockptr->RecpTo[i]); + Debugprintf("To Addr %s", Addr); + + TidyString(Addr); + Debugprintf("To Addr after Tidy %s", Addr); + + if ((_memicmp (Addr, "RMS:", 4) == 0) |(_memicmp (Addr, "RMS/", 4) == 0)) + { + // Add to B2 Message for RMS + + _strlwr(Addr); + + Via = strlop(&Addr[4], '@'); + + if (Via && _stricmp(Via, "winlink.org") == 0) + { + if (CheckifLocalRMSUser(Addr)) // if local RMS - Leave Here + continue; + + ToLen = sprintf(ToString, "%sTo: %s\r\n", ToString, &Addr[4]); + *sockptr->RecpTo[i] = 0; // So we dont create individual one later + continue; + } + + ToLen = sprintf(ToString, "%sTo: %s@%s\r\n", ToString, &Addr[4], Via); + *sockptr->RecpTo[i] = 0; // So we dont create individual one later + continue; + } + + _strupr(Addr); + Debugprintf("To Addr after strupr %s", Addr); + + Via = strlop(Addr, '@'); + Debugprintf("Via %s", Via); + + if (Via && _stricmp(Via, "winlink.org") == 0) + { + if (CheckifLocalRMSUser(Addr)) // if local RMS - Leave Here + continue; + + ToLen = sprintf(ToString, "%sTo: %s\r\n", ToString, Addr); + *sockptr->RecpTo[i] = 0; // So we dont create individual one later + + continue; + } + } + + if (ToLen) // Have some RMS Addresses + { + char B2Hddr[1000]; + int B2HddrLen; + char DateString[80]; + char * NewBody; + struct tm * tm; + struct MsgInfo * Msg; + BIDRec * BIDRec; + + Msg = AllocateMsgRecord(); + + // Set number here so they remain in sequence + + Msg->number = ++LatestMsg; + MsgnotoMsg[Msg->number] = Msg; + Msg->length = MsgLen; + + sprintf_s(Msg->bid, sizeof(Msg->bid), "%d_%s", LatestMsg, BBSName); + + Msg->type = 'P'; + Msg->status = 'N'; + strcpy(Msg->to, "RMS"); + strlop(sockptr->MailFrom, '@'); + if (strlen(sockptr->MailFrom) > 6) sockptr->MailFrom[6]=0; + strcpy(Msg->from, sockptr->MailFrom); + strcpy(Msg->title, Msgtitle); + + BIDRec = AllocateBIDRecord(); + + strcpy(BIDRec->BID, Msg->bid); + BIDRec->mode = Msg->type; + BIDRec->u.msgno = LOWORD(Msg->number); + BIDRec->u.timestamp = LOWORD(time(NULL)/86400); + + Msg->datereceived = Msg->datechanged = Msg->datecreated = time(NULL); + + if (Date) + Msg->datecreated = Date; + + tm = gmtime(&Date); + + sprintf(DateString, "%04d/%02d/%02d %02d:%02d", + tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min); + + if (B2Flag) // Message has attachments, so Body: line is present + { + Msg->B2Flags = B2Msg | Attachments; + + B2HddrLen = sprintf(B2Hddr, + "MID: %s\r\nDate: %s\r\nType: %s\r\nFrom: %s\r\n%sSubject: %s\r\nMbo: %s\r\n", + Msg->bid, DateString, "Private", Msg->from, ToString, Msg->title, BBSName); + } + else + { + Msg->B2Flags = B2Msg; + B2HddrLen = sprintf(B2Hddr, + "MID: %s\r\nDate: %s\r\nType: %s\r\nFrom: %s\r\n%sSubject: %s\r\nMbo: %s\r\nBody: %d\r\n\r\n", + Msg->bid, DateString, "Private", Msg->from, ToString, Msg->title, BBSName, Msg->length); + + } + + NewBody = ptr2 - B2HddrLen; + + memcpy(NewBody, B2Hddr, B2HddrLen); + + Msg->length += B2HddrLen; + + free(ToString); + + // Set up forwarding bitmap + + MatchMessagetoBBSList(Msg, 0); + + CreateSMTPMessageFile(NewBody, Msg); + } + + for (i=0; i < sockptr->Recipients; i++) + { + if (*sockptr->RecpTo[i]) // not already sent to RMS? + CreateSMTPMessage(sockptr, i, Msgtitle, Date, ptr2, MsgLen, B2Flag); + else + free(sockptr->RecpTo[i]); + } + + free(sockptr->RecpTo); + sockptr->RecpTo = NULL; + free(sockptr->MailFrom); + free(sockptr->MailBuffer); + + sockptr->MailBufferSize=0; + sockptr->MailBuffer=0; + sockptr->MailSize = 0; + + sockptr->Flags = 0; + sockptr->Recipients = 0; + + SendSock(sockptr, "250 Ok"); + return; + } + + if ((sockptr->MailSize + Len) > sockptr->MailBufferSize) + { + sockptr->MailBufferSize += 10000; + sockptr->MailBuffer = realloc(sockptr->MailBuffer, sockptr->MailBufferSize); + + if (sockptr->MailBuffer == NULL) + { + CriticalErrorHandler("Failed to extend Message Buffer"); + shutdown(sock, 0); + return; + } + } + + memcpy(&sockptr->MailBuffer[sockptr->MailSize], Buffer, Len); + sockptr->MailSize += Len; + + return; + } + + if (sockptr->State == GettingUser) + { + char Out[30]; + + Buffer[Len-2]=0; + + decodeblock(Buffer, Out); + decodeblock(&Buffer[4], &Out[3]); + decodeblock(&Buffer[8], &Out[6]); + decodeblock(&Buffer[12], &Out[9]); + + if (strlen(Out) > 10) Out[10] = 0; + + strcpy(sockptr->CallSign, Out); + + sockptr->State = GettingPass; + SendSock(sockptr, "334 UGFzc3dvcmQ6"); + return; + } + + if (sockptr->State == GettingPass) + { + struct UserInfo * user = NULL; + char Out[30]; + + Buffer[Len-2]=0; + + decodeblock(Buffer, Out); + decodeblock(&Buffer[4], &Out[3]); + decodeblock(&Buffer[8], &Out[6]); + decodeblock(&Buffer[12], &Out[9]); + decodeblock(&Buffer[16], &Out[12]); + decodeblock(&Buffer[20], &Out[15]); + + user = LookupCall(sockptr->CallSign); + + if (user) + { + if (strcmp(user->pass, Out) == 0) + { + sockptr->State = Authenticated; + SendSock(sockptr, "235 2.0.0 OK Authenticated"); //535 authorization failed + return; + } + } + + SendSock(sockptr, "535 authorization failed"); + sockptr->State = 0; + return; + } + + + +/*AUTH LOGIN + +334 VXNlcm5hbWU6 +a4msl9ux +334 UGFzc3dvcmQ6 +ZvVx9G1hcg== +235 2.0.0 OK Authenticated +*/ + + + if(memcmp(Buffer, "AUTH LOGIN", 10) == 0) + { + sockptr->State = GettingUser; + SendSock(sockptr, "334 VXNlcm5hbWU6"); + return; + } + + if(memcmp(Buffer, "EHLO",4) == 0) + { + SendSock(sockptr, "250-BPQ Mail Server"); + SendSock(sockptr, "250 AUTH LOGIN"); + + //250-8BITMIME + + return; + } + + if(memcmp(Buffer, "AUTH LOGIN", 10) == 0) + { + sockptr->State = GettingUser; + SendSock(sockptr, "334 VXNlcm5hbWU6"); + return; + } + + + if(memcmp(Buffer, "HELO",4) == 0) + { + SendSock(sockptr, "250 Ok"); + return; + } + + if(_memicmp(Buffer, "MAIL FROM:", 10) == 0) + { + if (sockptr->State != Authenticated) + { + // Accept if from 44/8 and ends in ampr.org + + if (_memicmp(&Buffer[Len - 11], "ampr.org", 8) == 0 && + (sockptr->sin.sin_addr.s_addr & 0xff) == 44) + { + } + else + { + SendSock(sockptr, "530 Authentication required"); + return; + } + } + + sockptr->MailFrom = zalloc(Len); + memcpy(sockptr->MailFrom, &Buffer[10], Len-12); + + SendSock(sockptr, "250 Ok"); + + return; + } + + if(_memicmp(Buffer, "RCPT TO:", 8) == 0) + { + if (sockptr->State != Authenticated) + { + // Accept if from 44/8 and ends in ampr.org + + + + if (_memicmp(&Buffer[Len - 11], "ampr.org", 8) == 0 && + (sockptr->sin.sin_addr.s_addr & 0xff) == 44) + { + } + else + { + SendSock(sockptr, "530 Authentication required"); + return; + } + } + + sockptr->RecpTo=realloc(sockptr->RecpTo, (sockptr->Recipients+1) * sizeof(void *)); + sockptr->RecpTo[sockptr->Recipients] = zalloc(Len); + + memcpy(sockptr->RecpTo[sockptr->Recipients++], &Buffer[8], Len-10); + + SendSock(sockptr, "250 Ok"); + return; + } + + if(memcmp(Buffer, "DATA\r\n", 6) == 0) + { + sockptr->MailBuffer=malloc(10000); + sockptr->MailBufferSize=10000; + + if (sockptr->MailBuffer == NULL) + { + CriticalErrorHandler("Failed to create SMTP Message Buffer"); + SendSock(sockptr, "250 Failed"); + shutdown(sock, 0); + + return; + } + + sockptr->Flags |= GETTINGMESSAGE; + + SendSock(sockptr, "354 End data with ."); + return; + } + + if(memcmp(Buffer, "QUIT\r\n", 6) == 0) + { + SendSock(sockptr, "221 OK"); + Sleep(500); + shutdown(sock, 0); + return; + } + + if(memcmp(Buffer, "RSET\r\n", 6) == 0) + { + SendSock(sockptr, "250 Ok"); + + // This cancelled AUTH which I think is wrong + //sockptr->State = 0; + + if (sockptr->State != Authenticated) + sockptr->State = 0; + + sockptr->Recipients = 0; + + return; + } + + return; +} + + +int CreateSMTPMessage(SocketConn * sockptr, int i, char * MsgTitle, time_t Date, char * MsgBody, int MsgLen, BOOL B2Flag) +{ + struct MsgInfo * Msg; + BIDRec * BIDRec; + char * To; + char * via; + + // Allocate a message Record slot + + Msg = AllocateMsgRecord(); + + // Set number here so they remain in sequence + + Msg->number = ++LatestMsg; + MsgnotoMsg[Msg->number] = Msg; + Msg->length = MsgLen; + + sprintf_s(Msg->bid, sizeof(Msg->bid), "%d_%s", LatestMsg, BBSName); + + Msg->type = 'P'; + Msg->status = 'N'; + + BIDRec = AllocateBIDRecord(); + + strcpy(BIDRec->BID, Msg->bid); + BIDRec->mode = Msg->type; + BIDRec->u.msgno = LOWORD(Msg->number); + BIDRec->u.timestamp = LOWORD(time(NULL)/86400); + + Msg->datereceived = Msg->datechanged = Msg->datecreated = time(NULL); + + if (Date) + Msg->datecreated = Date; + + To = sockptr->RecpTo[i]; + + Debugprintf("To %s", To); + + TidyString(To); + + Debugprintf("To after tidy %s", To); + + if (_memicmp(To, "bull/", 5) == 0) + { + Msg->type = 'B'; + memmove(To, &To[5], strlen(&To[4])); + } + + if ((_memicmp(To, "nts/", 4) == 0) ||(_memicmp(To, "nts:", 4) == 0) || + (_memicmp(To, "nts.", 4) == 0)) + { + Msg->type = 'T'; + memmove(To, &To[4], strlen(&To[3])); + } + + if (_memicmp(To, "rms:", 4) == 0) + { + via = _strlwr(strlop(To, ':')); + } + else if (_memicmp(To, "rms/", 4) == 0) + { + via = _strlwr(strlop(To, '/')); + } + else if (_memicmp(To, "rms.", 4) == 0) + { + via = _strlwr(strlop(To, '.')); + } + else if (_memicmp(To, "smtp:", 5) == 0) + { + via = _strlwr(strlop(To, ':')); + To[0] = 0; + } + else if (_memicmp(To, "smtp/", 5) == 0) + { + via = _strlwr(strlop(To, '/')); + To[0] = 0; + } + else + { + via = strlop(To, '@'); + } + + Debugprintf("via %s", via); + + if (via) + { + int toLen; + + if (strlen(via) > 40) via[40] = 0; + + strcpy(Msg->via, via); // Save before messing with it + + // if ending in AMPR.ORG send via ISP if we have enabled forwarding AMPR + + toLen = (int)strlen(via); + + if (_memicmp(&via[toLen - 8], "ampr.org", 8) == 0) + { + // if our domain keep here. + + // if not, and SendAMPRDirect set, set as ISP, + // else set as RMS + + if (_stricmp(via, AMPRDomain) == 0) + { + // Our Message- dont forward + } + else + { + // AMPR but not us + + if (SendAMPRDirect) + { + sprintf(Msg->via,"%s@%s", To, via); + strcpy(To, "AMPR"); + } + else + { + sprintf(Msg->via,"%s@%s", To, via); + strcpy(To, "RMS"); + } + } + } + else + { + strlop(via, '.'); // Get first part of address + + if (_stricmp(via, BBSName) == 0) + { + // sent via us - clear the name + + Msg->via[0] = 0; + } + } + } + + if (strlen(To) > 6) To[6]=0; + + strcpy(Msg->to, To); + + if (strchr(sockptr->MailFrom, '@')) + { + char * FromHA = strlop(sockptr->MailFrom, '@'); + Msg->emailfrom[0] = '@'; + strcpy(&Msg->emailfrom[1], FromHA); + } + + if (strlen(sockptr->MailFrom) > 6) sockptr->MailFrom[6]=0; + + strcpy(Msg->from, sockptr->MailFrom); + + strcpy(Msg->title, MsgTitle); + + if(Msg->to[0] == 0) + SMTPMsgCreated=TRUE; + + // If NTS message (TO is numeric and AT is NTSxx or NTSxx.NTS - Outlook won't accept x@y) + + if (isdigits(Msg->to) && memcmp(Msg->via, "NTS", 3) == 0) + { + if (Msg->via[5] == 0 || strcmp(&Msg->via[5], ".NTS") == 0) + { + Msg->type = 'T'; + Msg->via[5] = 0; + } + } + + Debugprintf("Msg->Via %s", Msg->via); + + if (B2Flag) + { + char B2Hddr[1000]; + int B2HddrLen; + char B2To[80]; + char * NewBody; + char DateString[80]; + char * TypeString; + struct tm * tm; + + tm = gmtime(&Date); + + sprintf(DateString, "%04d/%02d/%02d %02d:%02d", + tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min); + + + if (strcmp(Msg->to, "RMS") == 0) // Address is in via + strcpy(B2To, Msg->via); + else + if (Msg->via[0]) + sprintf(B2To, "%s@%s", Msg->to, Msg->via); + else + strcpy(B2To, Msg->to); + + + Msg->B2Flags = B2Msg | Attachments; + + if (Msg->type == 'P') + TypeString = "Private" ; + else if (Msg->type == 'B') + TypeString = "Bulletin"; + else if (Msg->type == 'T') + TypeString = "Traffic"; + + B2HddrLen = sprintf(B2Hddr, + "MID: %s\r\nDate: %s\r\nType: %s\r\nFrom: %s\r\nTo: %s\r\nSubject: %s\r\nMbo: %s\r\n", + Msg->bid, DateString, TypeString, + Msg->from, B2To, Msg->title, BBSName); + + NewBody = MsgBody - B2HddrLen; + + memcpy(NewBody, B2Hddr, B2HddrLen); + + Msg->length += B2HddrLen; + + free(To); + + // Set up forwarding bitmap + + MatchMessagetoBBSList(Msg, 0); + + if (Msg->type == 'B' && memcmp(Msg->fbbs, zeros, NBMASK) != 0) + Msg->status = '$'; // Has forwarding + + return CreateSMTPMessageFile(NewBody, Msg); + + } + + free(To); + + // Set up forwarding bitmap + + MatchMessagetoBBSList(Msg, 0); + + if (Msg->type == 'B' && memcmp( Msg->fbbs, zeros, NBMASK) != 0) + Msg->status = '$'; // Has forwarding + + return CreateSMTPMessageFile(MsgBody, Msg); + +} + + +BOOL CreateSMTPMessageFile(char * Message, struct MsgInfo * Msg) +{ + char MsgFile[250]; + FILE * hFile; + int WriteLen=0; + char Mess[255]; + int len; + + struct UserInfo * ToUser = LookupCall(Msg->to); + + if (ToUser && ToUser->flags & F_HOLDMAIL) + { + int Length=0; + char * MailBuffer = malloc(100); + char Title[100]; + + Msg->status = 'H'; + + Length += sprintf(MailBuffer, "Message %d Held\r\n", Msg->number); + sprintf(Title, "Message %d Held - %s", Msg->number, "User has Hold Messages flag set"); + SendMessageToSYSOP(Title, MailBuffer, Length); + } + + sprintf_s(MsgFile, sizeof(MsgFile), "%s/m_%06d.mes", MailDir, Msg->number); + + hFile = fopen(MsgFile, "wb"); + + if (hFile) + { + WriteLen = (int)fwrite(Message, 1, Msg->length, hFile); + fclose(hFile); + } + + if (WriteLen != Msg->length) + { + len = sprintf_s(Mess, sizeof(Mess), "Failed to create Message File\r"); + CriticalErrorHandler(Mess); + + return FALSE; + } + + SaveMessageDatabase(); + SaveBIDDatabase(); + + return TRUE; +} + +int TidyString(char * Address) +{ + // Cleans up a From: or To: Address + + // May have leading or trailing spaces, or be enclosed by <>, or have a " " part + + // From: "John Wiseman" + + char * ptr1, * ptr2; + size_t len; + + _strupr(Address); + + ptr1 = strchr(Address, '<'); + + if (ptr1) + { + ptr1++; + ptr2 = strlop(ptr1, '>'); + len = (int)strlen(ptr1); + memmove(Address, ptr1, len); + Address[len] = 0; + + // Could have surrounding "" "" + + if (Address[0] == '"') + { + int len = (int)strlen(Address) - 1; + + if (Address[len] == '"') + { + Address[len] = 0; + memmove(Address, &Address[1], len); + return 0; + } + + // Thunderbird can put "" round part of address "rms:john.wiseman"@cantab.net + + ptr2 = strchr(&Address[1], '"'); + + if (ptr2) + { + memmove(Address, &Address[1], ptr2 - &Address[1]); + memmove(ptr2 - 1, ptr2 + 1, strlen(ptr2 + 1) + 1); + + } + + + } + + return 0; + } + + ptr1 = Address; + + while (*ptr1 == ' ') ptr1++; + + if (*ptr1 == '"') + { + ptr1++; + ptr1=strlop(ptr1, '"'); + ptr2=strlop(ptr1, ' '); + ptr1=ptr2; + } + + if (*ptr1 == '<') ptr1++; + + ptr2 = strlop(ptr1, '>'); + strlop(ptr1, ' '); + + len = strlen(ptr1); + memmove(Address, ptr1, len); + Address[len] = 0; + + return 0; +} +/* ++OK POP3 server ready +USER john.wiseman ++OK please send PASS command +PASS gb7bpq ++OK john.wiseman is welcome here +STAT ++OK 6 115834 + +UIDL ++OK 6 messages +1 <4A0DC6E0.5020504@hb9bza.net> +2 +3 <1085101c9d5d0$09b15420$16f9280a@phx.gbl> +4 +5 +6 <20090516011401.53DB013804@panix1.panix.com> +. +LIST ++OK 6 messages +1 7167 +2 10160 +3 52898 +4 4746 +5 20218 +6 20645 +. + +*/ + +VOID ProcessPOP3ServerMessage(SocketConn * sockptr, char * Buffer, int Len) +{ + SOCKET sock; + int i; + struct MsgInfo * Msg; + + sock=sockptr->socket; + + WriteLogLine(NULL, '<',Buffer, Len-2, LOG_TCP); + + if(memcmp(Buffer, "CAPA",4) == 0) + { + SendSock(sockptr, "+OK Capability list follows"); + SendSock(sockptr, "UIDL"); + SendSock(sockptr, "TOP"); + SendSock(sockptr, "EXPIRE 30"); + SendSock(sockptr, "."); + return; + } + + if(memcmp(Buffer, "AUTH",4) == 0) + { + SendSock(sockptr, "-ERR"); + return; + } + if (sockptr->State == GettingUser) + { + + Buffer[Len-2]=0; + if (Len > 15) Buffer[15]=0; + + strcpy(sockptr->CallSign, &Buffer[5]); + + sockptr->State = GettingPass; + SendSock(sockptr, "+OK please send PASS command"); + return; + } + + if (sockptr->State == GettingPass) + { + struct UserInfo * user = NULL; + + Buffer[Len-2]=0; + user = LookupCall(sockptr->CallSign); + + if (user) + { + if (strcmp(user->pass, &Buffer[5]) == 0) + { + if (user->POP3Locked) + { + SendSock(sockptr, "-ERR Mailbox Locked"); + sockptr->State = 0; + return; + } + + sockptr->State = Authenticated; + SendSock(sockptr, "+OK Authenticated"); + + sockptr->POP3User = user; + user->POP3Locked = TRUE; + + // Get Message List + + for (i=0; i<=NumberofMessages; i++) + { + Msg = MsgHddrPtr[i]; + + if ((_stricmp(Msg->to, sockptr->CallSign) == 0) || + ((_stricmp(Msg->to, "SYSOP") == 0) && (user->flags & F_SYSOP) && (Msg->type == 'P'))) + { + if (Msg->status != 'K' && Msg->status != 'H') + { + sockptr->POP3Msgs = realloc(sockptr->POP3Msgs, (sockptr->POP3MsgCount+1) * sizeof(void *)); + sockptr->POP3Msgs[sockptr->POP3MsgCount++] = MsgHddrPtr[i]; + } + } + } + + return; + } + } + + SendSock(sockptr, "-ERR Authentication failed"); + sockptr->State = 0; + return; + } + + if (memcmp(Buffer, "QUIT",4) == 0) + { + SendSock(sockptr, "+OK Finished"); + + if (sockptr->POP3User) + sockptr->POP3User->POP3Locked = FALSE; + + return; + } + + if (memcmp(Buffer, "NOOP",4) == 0) + { + SendSock(sockptr, "+OK "); + return; + } + +// if (memcmp(Buffer, "LAST",4) == 0) +// { +// SendSock(sockptr, "+OK 0"); +// return; +// } + + if (sockptr->State != Authenticated) + { + SendSock(sockptr, "-ERR Need Authentication"); + sockptr->State = 0; + return; + } + + if (memcmp(Buffer, "STAT",4) == 0) + { + char reply[40]; + int i, size=0; + + for (i=0; i< sockptr->POP3MsgCount; i++) + { + size+=sockptr->POP3Msgs[i]->length; + } + + sprintf_s(reply, sizeof(reply), "+OK %d %d", sockptr->POP3MsgCount, size); + + SendSock(sockptr, reply); + return; + } + + if (memcmp(Buffer, "UIDL",4) == 0) + { + char reply[40]; + int i, count=0, size=0; + int MsgNo=1; + + SendSock(sockptr, "+OK "); + + for (i=0; i< sockptr->POP3MsgCount; i++) + { + sprintf_s(reply, sizeof(reply), "%d %s", i+1, sockptr->POP3Msgs[i]->bid); + SendSock(sockptr, reply); + } + + SendSock(sockptr, "."); + return; + } + + if (memcmp(Buffer, "LIST", 4) == 0) + { + char reply[40]; + int i, count=0, size=0; + int MsgNo = atoi(&Buffer[4]); + + if (Buffer[4] == 13) // CR + MsgNo = 0; + + Debugprintf("%s %d", Buffer, MsgNo); + + if (MsgNo) + { + if (MsgNo > sockptr->POP3MsgCount) + sprintf(reply, "-ERR no such message, only %d messages in maildrop", sockptr->POP3MsgCount); + else + sprintf(reply, "+OK %d %d", MsgNo, sockptr->POP3Msgs[MsgNo - 1]->length); + SendSock(sockptr, reply); + return; + } + + + SendSock(sockptr, "+OK "); + + for (i=0; i< sockptr->POP3MsgCount; i++) + { + sprintf_s(reply, sizeof(reply), "%d %d", i+1, sockptr->POP3Msgs[i]->length); + SendSock(sockptr, reply); + } + + SendSock(sockptr, "."); + return; + } + + if (memcmp(Buffer, "RETR", 4) == 0 || memcmp(Buffer, "TOP", 3) == 0) + { + char * ptr; + char Header[120]; + int i, count=0, size=0; + int MsgNo=1; + char * msgbytes; + struct MsgInfo * Msg; + char B2From[80]; + struct UserInfo * FromUser; + char TimeString[64]; + BOOL TOP = FALSE; + int Len; + + if (memcmp(Buffer, "TOP", 3) == 0) + TOP = TRUE; + + ptr=strlop(Buffer, ' '); // Get Number + + i=atoi(ptr); + + if ((i > sockptr->POP3MsgCount) || (i == 0)) + { + SendSock(sockptr, "-ERR no such message"); + return; + } + + Msg = sockptr->POP3Msgs[i-1]; + + msgbytes = ReadMessageFile(Msg->number); + + if (msgbytes == NULL) + { + SendSock(sockptr, "-ERR no such message"); + return; + } + + SendSock(sockptr, "+OK "); + + // Build an RFC822 ish header + +//Received: from [69.147.65.148] by n15.bullet.sp1.yahoo.com with NNFMP; 16 May 2009 02:30:47 -0000 +//Received: from [69.147.108.192] by t11.bullet.mail.sp1.yahoo.com with NNFMP; 16 May 2009 02:30:47 -0000 + + FormatTime(TimeString, (time_t)Msg->datecreated); + + sprintf_s(Header, sizeof(Header), "Date: %s", TimeString); + SendSock(sockptr, Header); + + sprintf_s(Header, sizeof(Header), "To: %s", Msg->to); + SendSock(sockptr, Header); + + sprintf_s(Header, sizeof(Header), "Message-ID: %s", Msg->bid); + SendSock(sockptr, Header); + + if (_stricmp(Msg->from, "smtp:") == 0) + { + sprintf_s(Header, sizeof(Header), "From: smtp/%s", Msg->emailfrom); + SendSock(sockptr, Header); + sprintf_s(Header, sizeof(Header), "Replyto: smtp/%s", Msg->emailfrom); + } + else + { + if (_stricmp(Msg->from, "rms:") == 0) + { + sprintf_s(Header, sizeof(Header), "From: RMS/%s", Msg->emailfrom); + SendSock(sockptr, Header); + sprintf_s(Header, sizeof(Header), "Replyto: RMS/%s", Msg->emailfrom); + } + else + { + // If there is an adddress in Msg->emailfrom use it + + if (Msg->emailfrom[0]) + { + strcpy(B2From, Msg->from); + strcat(B2From, Msg->emailfrom); + } + else + { + // Packet Address. Mail client will need more than just a call to respond to + + strcpy(B2From, Msg->from); + + if (strcmp(Msg->from, "SMTP:") == 0) // Address is in via + strcpy(B2From, Msg->emailfrom); + else + { + FromUser = LookupCall(Msg->from); + + if (FromUser) + { + if (FromUser->HomeBBS[0]) + sprintf(B2From, "%s@%s", Msg->from, FromUser->HomeBBS); + else + sprintf(B2From, "%s@%s", Msg->from, BBSName); + } + else + { + WPRecP WP = LookupWP(Msg->from); + if (WP) + sprintf(B2From, "%s@%s", Msg->from, WP->first_homebbs); + } + } + } + sprintf_s(Header, sizeof(Header), "From: %s", B2From); + SendSock(sockptr, Header); + sprintf_s(Header, sizeof(Header), "Replyto: %s", B2From); + } + } + SendSock(sockptr, Header); + sprintf_s(Header, sizeof(Header), "Subject: %s", Msg->title); + SendSock(sockptr, Header); + + if ((Msg->B2Flags & Attachments) && TOP == FALSE) + { + // B2 Message with Attachments. Create a Mime-Encoded Multipart message + + SendMultiPartMessage(sockptr, Msg, msgbytes); + return; + } + + if (TOP) + { + // Get first i lines of message + + char * ptr1, * ptr2; + + ptr = strlop(ptr, ' '); // Get Number of lines + i = atoi(ptr); + + ptr1 = msgbytes; + ptr2 = --ptr1; // Point both to char before message + + while(i--) + { + ptr2 = strchr(++ptr1, 10); + + if (ptr2 == 0) // No more lines + i = 0; + + ptr1 = ptr2; + } + if (ptr2) + *(ptr2 + 1) = 0; + } + + // If message has characters above 7F convert to UFT8 if necessary and send as Base64 + + Len = (int)strlen(msgbytes); + + if (Is8Bit(msgbytes, Len)) + { + // 8 Bit. Will send as UFT8 + + if (WebIsUTF8(msgbytes, Len) == FALSE) + { + // Must be some other coding + + int code = TrytoGuessCode(msgbytes, Len); + UCHAR * UTF = malloc(Len * 3); + + if (code == 437) + Len = Convert437toUTF8(msgbytes, Len, UTF); + else if (code == 1251) + Len = Convert1251toUTF8(msgbytes, Len, UTF); + else + Len = Convert1252toUTF8(msgbytes, Len, UTF); + + free(msgbytes); + msgbytes = UTF; + } + + SendSock(sockptr, "Content-Type: text/plain; charset=\"utf-8\""); + SendSock(sockptr, "Content-Transfer-Encoding: base64"); + SendSock(sockptr, "Content-Disposition: inline"); + + SendSock(sockptr, ""); // Blank line before body + + Base64EncodeAndSend(sockptr, msgbytes, Len); + + } + else + { + // send as USASCII + + SendSock(sockptr, ""); // Blank line before body + SendSock(sockptr, msgbytes); + } + + SendSock(sockptr, ""); + SendSock(sockptr, "."); + + free(msgbytes); + return; + } + + + if (memcmp(Buffer, "DELE",4) == 0) + { + char * ptr; + int i; + struct MsgInfo * Msg; + + ptr=strlop(Buffer, ' '); // Get Number + + i=atoi(ptr); + + if ((i > sockptr->POP3MsgCount) || (i == 0)) + { + SendSock(sockptr, "-ERR no such message"); + return; + } + + Msg = sockptr->POP3Msgs[i-1]; + + FlagAsKilled(Msg, TRUE); + + SendSock(sockptr, "+OK "); + return; + } + + + if (memcmp(Buffer, "QUIT",4) == 0) + { + SendSock(sockptr, "+OK Finished"); + + if (sockptr->POP3User) + sockptr->POP3User->POP3Locked = FALSE; + + return; + } + + SendSock(sockptr, "-ERR Unrecognised Command"); + +} + + + +/* jer: + * This is the original file, my mods were only to change the name/semantics on the b64decode function + * and remove some dependencies. + */ +/* + LibCGI base64 manipulation functions is extremly based on the work of Bob Tower, + from its projec http://base64.sourceforge.net. The functions were a bit modicated. + Above is the MIT license from b64.c original code: + +LICENCE: Copyright (c) 2001 Bob Trower, Trantor Standard Systems Inc. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated + documentation files (the "Software"), to deal in the + Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, + sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall + be included in all copies or substantial portions of the + Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS + OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE + +*/ +void encodeblock( unsigned char in[3], unsigned char out[4], int len ) +{ + out[0] = cb64[ in[0] >> 2 ]; + out[1] = cb64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4) ]; + out[2] = (unsigned char) (len > 1 ? cb64[ ((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6) ] : '='); + out[3] = (unsigned char) (len > 2 ? cb64[ in[2] & 0x3f ] : '='); +} + +void decodeblock( unsigned char in[4], unsigned char out[3]) +{ + char Block[5]; + + Block[0]=mycd64[in[0]]; + Block[1]=mycd64[in[1]]; + Block[2]=mycd64[in[2]]; + Block[3]=mycd64[in[3]]; + + out[0] = (unsigned char ) (Block[0] << 2 | Block[1] >> 4); + out[1] = (unsigned char ) (Block[1] << 4 | Block[2] >> 2); + out[2] = (unsigned char ) (((Block[2] << 6) & 0xc0) | Block[3]); +} + +/** +* @ingroup libcgi_string +* @{ +*/ + +/** +* Encodes a given tring to its base64 form. +* +* @param *str String to convert +* @return Base64 encoded String +* @see str_base64_decode +**/ +char *str_base64_encode(char *str) +{ + unsigned int i = 0, j = 0, len = (int)strlen(str); + char *tmp = str; + char *result = (char *)zalloc((len+1) * sizeof(void *)); + + if (!result) + return NULL; + + while (len > 2 ) + { + encodeblock(&str[i], &result[j],3); + i+=3; + j+=4; + len -=3; + } + if (len) + { + encodeblock(&str[i], &result[j], len); + } + + return result; +} + +SocketConn * SMTPConnect(char * Host, int Port, BOOL AMPR, struct MsgInfo * Msg, char * MsgBody) +{ + int err; + u_long param=1; + BOOL bcopt=TRUE; + + SocketConn * sockptr; + + SOCKADDR_IN sinx; + SOCKADDR_IN destaddr; + int addrlen=sizeof(sinx); + struct hostent * HostEnt; + + // Resolve Name if needed + + destaddr.sin_family = AF_INET; + destaddr.sin_port = htons(Port); + + destaddr.sin_addr.s_addr = inet_addr(Host); + + if (destaddr.sin_addr.s_addr == INADDR_NONE) + { + // Resolve name to address + + HostEnt = gethostbyname (Host); + + if (!HostEnt) + { + Logprintf(LOG_TCP, NULL, '|', "Resolve Failed for SMTP Server %s", Host); + SMTPActive = FALSE; + return FALSE; // Resolve failed + } + memcpy(&destaddr.sin_addr.s_addr,HostEnt->h_addr,4); + } + +// Allocate a Socket entry + + sockptr=malloc(sizeof(SocketConn)); + memset(sockptr, 0, sizeof (SocketConn)); + + sockptr->Next=Sockets; + Sockets=sockptr; + + sockptr->socket=socket(AF_INET,SOCK_STREAM,0); + + if (sockptr->socket == INVALID_SOCKET) + { + return FALSE; + } + + sockptr->Type = SMTPClient; + sockptr->AMPR = AMPR; + + if (AMPR) + strcpy(sockptr->FromDomain, AMPRDomain); + else + strcpy(sockptr->FromDomain, MyDomain); + + sockptr->SMTPMsg = Msg; + sockptr->MailBuffer = MsgBody; + + ioctlsocket (sockptr->socket, FIONBIO, ¶m); + + setsockopt (sockptr->socket, SOL_SOCKET, SO_REUSEADDR, (const char FAR *)&bcopt,4); + + sinx.sin_family = AF_INET; + sinx.sin_addr.s_addr = INADDR_ANY; + sinx.sin_port = 0; + + if (bind(sockptr->socket, (LPSOCKADDR) &sinx, addrlen) != 0 ) + { + // + // Bind Failed + // + + return FALSE; + } + + if (connect(sockptr->socket,(LPSOCKADDR) &destaddr, sizeof(destaddr)) == 0) + { + // + // Connected successful + // + + sockptr->State = WaitingForGreeting; + + return sockptr; + } + else + { + err=WSAGetLastError(); + + if (err == WSAEWOULDBLOCK || err == 115 || err == 36) + { + // + // Connect in Progress + // + + sockptr->State = Connecting; + return sockptr; + } + else + { + // + // Connect failed + // + + printf("SMTP Connect failed immediately\n"); + closesocket(sockptr->socket); + ReleaseSock(sockptr->socket); + return FALSE; + + return FALSE; + } + } + return FALSE; +} + +int TryHELO = 0; // Not thread safe but taking the chance.. + +VOID ProcessSMTPClientMessage(SocketConn * sockptr, char * Buffer, int Len) +{ + SOCKET sock; + + sock=sockptr->socket; + + WriteLogLine(NULL, '<',Buffer, Len-2, LOG_TCP); + + Buffer[Len] = 0; + + if (sockptr->State == WaitingForGreeting) + { + if (memcmp(Buffer, "220 ",4) == 0) + { + TryHELO = 0; + + if (sockptr->AMPR) + sockprintf(sockptr, "EHLO %s", AMPRDomain); + else if (ISPEHLOName[0]) + sockprintf(sockptr, "EHLO %s", ISPEHLOName); + else + sockprintf(sockptr, "EHLO %s", BBSName); + + sockptr->State = WaitingForHELOResponse; + } + else + { + SendSock(sockptr, "QUIT"); + sockptr->State = 0; + } + + return; + } + + if (sockptr->State == WaitingForHELOResponse) + { +/* + if (memcmp(Buffer, "500 ",4) == 0 && TryHELO == 0) + { + TryHELO = 1; + + if (sockptr->AMPR) + sockprintf(sockptr, "HELO %s", AMPRDomain); + else if (ISPEHLOName[0]) + sockprintf(sockptr, "HELO %s", ISPEHLOName); + else + sockprintf(sockptr, "HELO %s", BBSName); + + return; + } +*/ + if (memcmp(Buffer, "250-",4) == 0) + return; + + if (memcmp(Buffer, "250 ",4) == 0) + { + if (SMTPAuthNeeded && sockptr->AMPR == FALSE) + { + sockprintf(sockptr, "AUTH LOGIN"); + sockptr->State = WaitingForAUTHResponse; + } + else + { + sockprintf(sockptr, "MAIL FROM: <%s@%s>", sockptr->SMTPMsg->from, sockptr->FromDomain); + sockptr->State = WaitingForFROMResponse; + } + } + else + { + SendSock(sockptr, "QUIT"); + sockptr->State = 0; + SMTPActive = FALSE; + + } + + return; + } + + if (sockptr->State == WaitingForAUTHResponse) + { + if (memcmp(Buffer, "334 VXN", 7) == 0) + { + char * Msg = str_base64_encode(ISPAccountName); + SendSock(sockptr, Msg); + free(Msg); + return; + } + else if (memcmp(Buffer, "334 UGF", 7) == 0) + { + char * Msg = str_base64_encode(ISPAccountPass); + SendSock(sockptr, Msg); + free(Msg); + return; + } + else if (memcmp(Buffer, "235 ", 4) == 0) + { + sockprintf(sockptr, "MAIL FROM: <%s@%s>", sockptr->SMTPMsg->from, sockptr->FromDomain); +// sockprintf(sockptr, "MAIL FROM: <%s@%s.%s>", sockptr->SMTPMsg->from, BBSName, HRoute); + sockptr->State = WaitingForFROMResponse; + } + + else + { + SendSock(sockptr, "QUIT"); + sockptr->State = 0; + SMTPActive = FALSE; + } + + return; + + } + + + if (sockptr->State == WaitingForFROMResponse) + { + if (memcmp(Buffer, "250 ",4) == 0) + { + sockprintf(sockptr, "RCPT TO: <%s>", sockptr->SMTPMsg->via); + sockptr->State = WaitingForTOResponse; + } + else + { + sockptr->SMTPMsg->status = 'H'; // Hold for review + SendSock(sockptr, "QUIT"); + sockptr->State = 0; + SMTPActive = FALSE; + } + + return; + } + + if (sockptr->State == WaitingForTOResponse) + { + if (memcmp(Buffer, "250 ",4) == 0) + { + SendSock(sockptr, "DATA"); + sockptr->State = WaitingForDATAResponse; + } + else + { + sockptr->SMTPMsg->status = 'H'; // Hold for review + SendSock(sockptr, "QUIT"); + sockptr->State = 0; + SMTPActive = FALSE; + } + + return; + } + + if (sockptr->State == WaitingForDATAResponse) + { + int Len; + UCHAR * UTF; + + if (memcmp(Buffer, "354 ",4) == 0) + { + sockprintf(sockptr, "To: %s", sockptr->SMTPMsg->via); + sockprintf(sockptr, "From: %s <%s@%s>", sockptr->SMTPMsg->from, sockptr->SMTPMsg->from, sockptr->FromDomain); + sockprintf(sockptr, "Sender: %s@%s", sockptr->SMTPMsg->from, sockptr->FromDomain); + if (GMailMode && sockptr->AMPR == FALSE) + sockprintf(sockptr, "Reply-To: %s+%s@%s", GMailName, sockptr->SMTPMsg->from, sockptr->FromDomain); + else + sockprintf(sockptr, "Reply-To: %s@%s", sockptr->SMTPMsg->from, sockptr->FromDomain); + + sockprintf(sockptr, "Subject: %s", sockptr->SMTPMsg->title); + + sockptr->State = WaitingForBodyResponse; + + if (sockptr->SMTPMsg->B2Flags & Attachments) + { + // B2 Message with Attachments. Create a Mime-Encoded Multipart message + + SendMultiPartMessage(sockptr, sockptr->SMTPMsg, sockptr->MailBuffer); + return; + } + + // If message has characters above 7F convert to UFT8 if necessary and send as Base64 + + + Len = (int)strlen(sockptr->MailBuffer); + + if (Is8Bit(sockptr->MailBuffer, Len)) + { + // 8 Bit. Will send as UFT8 + + SendSock(sockptr, "Content-Type: text/plain; charset=\"utf-8\""); + SendSock(sockptr, "Content-Transfer-Encoding: base64"); + SendSock(sockptr, "Content-Disposition: inline"); + + SendSock(sockptr, ""); // Blank line before body + + if (WebIsUTF8(sockptr->MailBuffer, Len) == FALSE) + { + // Must be some other coding + + int code = TrytoGuessCode(sockptr->MailBuffer, Len); + UTF = malloc(Len * 3); + + if (code == 437) + Len = Convert437toUTF8(sockptr->MailBuffer, Len, UTF); + else if (code == 1251) + Len = Convert1251toUTF8(sockptr->MailBuffer, Len, UTF); + else + Len = Convert1252toUTF8(sockptr->MailBuffer, Len, UTF); // Default + + Base64EncodeAndSend(sockptr, UTF, Len); + free(UTF); + } + else + Base64EncodeAndSend(sockptr, sockptr->MailBuffer, Len); + + } + else + { + // send as USASCII + + SendSock(sockptr, ""); // Blank line before body + SendSock(sockptr, sockptr->MailBuffer); + } + + SendSock(sockptr, "."); + + } + else + { + SendSock(sockptr, "QUIT"); + sockptr->State = 0; + SMTPActive = FALSE; + } + + return; + } + + if (sockptr->State == WaitingForBodyResponse) + { + struct MsgInfo * Msg = sockptr->SMTPMsg; + + if (memcmp(Buffer, "250 ", 4) == 0) + { + // if AMPR, clear forwarding bitmap + + if (sockptr->AMPR) + { + // Mark mail as sent, and look for more + + struct UserInfo * bbs = sockptr->bbs; + + clear_fwd_bit(Msg->fbbs, bbs->BBSNumber); + set_fwd_bit(Msg->forw, bbs->BBSNumber); + + // Only mark as forwarded if sent to all BBSs that should have it + + if (memcmp(Msg->fbbs, zeros, NBMASK) == 0) + { + Msg->status = 'F'; // Mark as forwarded + Msg->datechanged=time(NULL); + } + + bbs->ForwardingInfo->MsgCount--; + bbs->ForwardingInfo->Forwarding = 0; + + // See if any more + + if (bbs->ForwardingInfo->MsgCount) + bbs->ForwardingInfo->FwdTimer = bbs->ForwardingInfo->FwdInterval; // Reschdul send + + } + else + { + Msg->status = 'F'; + SMTPActive = FALSE; + SMTPMsgCreated=TRUE; // See if any more + } + } + + SendSock(sockptr, "QUIT"); + sockptr->State = 0; + + SMTPActive = FALSE; + + SMTPMsgCreated=TRUE; // See if any more + + return; + } +} + +BOOL SendtoAMPR(CIRCUIT * conn) +{ + struct MsgInfo * Msg = conn->FwdMsg; + SocketConn * sockptr; + + char * Body; + int toLen; + char * tocopy; + char * Host; + + // Make sure message exists + + Body = ReadMessageFile(Msg->number); + + if (Body == NULL) + { + FlagAsKilled(Msg, TRUE); + return FALSE; + } + + toLen = (int)strlen(Msg->via); + + tocopy = _strdup(Msg->via); + + Host = strlop(tocopy, '@'); + + if (Host == NULL) + { + Logprintf(LOG_TCP, NULL, '|', "AMPR Forward - Host Name missing from VIA %s for Msg %d", Msg->via, Msg->number); + free(tocopy); + return FALSE; + } + + Logprintf(LOG_TCP, NULL, '|', "Connecting to Server %s to send Msg %d", Host, Msg->number); + + sockptr = SMTPConnect(Host, 25, TRUE, Msg, Body); + + free(tocopy); + + if (sockptr) + { + sockptr->bbs = conn->UserPointer; + + return TRUE; + } + + return FALSE; +} + +BOOL SendtoISP() +{ + // Find a message intended for the Internet and send it + + int m = NumberofMessages; + char * Body; + + struct MsgInfo * Msg; + + if (SMTPActive) + return FALSE; + + do + { + Msg=MsgHddrPtr[m]; + + if ((Msg->status == 'N') && (Msg->to[0] == 0) && (Msg->from[0] != 0)) + { + // Make sure message exists + + Body = ReadMessageFile(Msg->number); + + if (Body == NULL) + { + FlagAsKilled(Msg, TRUE); + return FALSE; + } + + Logprintf(LOG_TCP, NULL, '|', "Connecting to Server %s to send Msg %d", ISPSMTPName, Msg->number); + + SMTPMsgCreated=FALSE; // Stop any more attempts + SMTPConnect(ISPSMTPName, ISPSMTPPort, FALSE, Msg, Body); + + SMTPActive = TRUE; + + return TRUE; + } + + m--; + + } while (m> 0); + + return FALSE; + +} + + +BOOL POP3Connect(char * Host, int Port) +{ + int err; + u_long param=1; + BOOL bcopt=TRUE; + + SocketConn * sockptr; + + SOCKADDR_IN sinx; + SOCKADDR_IN destaddr; + int addrlen=sizeof(sinx); + struct hostent * HostEnt; + + Logprintf(LOG_TCP, NULL, '|', "Connecting to POP3 Server %s", Host); + + // Resolve Name if needed + + destaddr.sin_family = AF_INET; + destaddr.sin_port = htons(Port); + + destaddr.sin_addr.s_addr = inet_addr(Host); + + if (destaddr.sin_addr.s_addr == INADDR_NONE) + { + // Resolve name to address + + HostEnt = gethostbyname (Host); + + if (!HostEnt) + { + Logprintf(LOG_TCP, NULL, '|', "Resolve Failed for POP3 Server %s", Host); + return FALSE; // Resolve failed + } + memcpy(&destaddr.sin_addr.s_addr,HostEnt->h_addr,4); + } + +// Allocate a Socket entry + + sockptr = malloc(sizeof(SocketConn)); + memset(sockptr, 0, sizeof (SocketConn)); + + sockptr->Next = Sockets; + Sockets = sockptr; + + sockptr->socket = socket(AF_INET,SOCK_STREAM,0); + + if (sockptr->socket == INVALID_SOCKET) + { + return FALSE; + } + + sockptr->Type = POP3Client; + + ioctlsocket (sockptr->socket, FIONBIO, ¶m); + + setsockopt (sockptr->socket, SOL_SOCKET, SO_REUSEADDR, (const char FAR *)&bcopt,4); + + sinx.sin_family = AF_INET; + sinx.sin_addr.s_addr = INADDR_ANY; + sinx.sin_port = 0; + + if (bind(sockptr->socket, (LPSOCKADDR) &sinx, addrlen) != 0 ) + { + // + // Bind Failed + // + + return FALSE; + } + + if (connect(sockptr->socket,(LPSOCKADDR) &destaddr, sizeof(destaddr)) == 0) + { + // + // Connected successful + // + + sockptr->State = WaitingForGreeting; + + return TRUE; + } + else + { + err=WSAGetLastError(); + + if (err == WSAEWOULDBLOCK || err == 115 || err == 36) + { + // + // Connect in Progressing + // + + sockptr->State = Connecting; + return TRUE; + } + else + { + // + // Connect failed + // + + printf("Connect failed immediately %d\n", err); + perror("POP Connect"); + closesocket(sockptr->socket); + ReleaseSock(sockptr->socket); + return FALSE; + } + } + return FALSE; +} + +VOID ProcessPOP3ClientMessage(SocketConn * sockptr, char * Buffer, int Len) +{ + SOCKET sock; + time_t Date; + BOOL B2Flag; + + sock=sockptr->socket; + + WriteLogLine(NULL, '<',Buffer, Len-2, LOG_TCP); + + if (sockptr->Flags == GETTINGMESSAGE) + { + if(memcmp(Buffer, ".\r\n", 3) == 0) + { + // File Message + + char * ptr1, * ptr2; + int linelen, MsgLen; + char MsgFrom[62], MsgTo[100], Msgtitle[62]; + + // Scan headers for From: To: and Subject: Line (Headers end at blank line) + + ptr1 = sockptr->MailBuffer; + Loop: + ptr2 = strchr(ptr1, '\r'); + + if (ptr2 == NULL) + { + SendSock(sockptr, "500 Eh"); + return; + } + + linelen = (int)(ptr2 - ptr1); + + // From: "John Wiseman" + // To: + // + + + if (_memicmp(ptr1, "From:", 5) == 0) + { + if (linelen > 65) linelen = 65; + memcpy(MsgFrom, &ptr1[5], linelen-5); + MsgFrom[linelen-5]=0; + } + else + if (_memicmp(ptr1, "To:", 3) == 0) + { + if (linelen > 99) linelen = 99; + memcpy(MsgTo, &ptr1[4], linelen-4); + MsgTo[linelen-4]=0; + } + else + if (_memicmp(ptr1, "Subject:", 8) == 0) + { + if (linelen > 68) linelen = 68; + memcpy(Msgtitle, &ptr1[9], linelen-9); + Msgtitle[linelen-9]=0; + } + else + if (_memicmp(ptr1, "Date:", 5) == 0) + { + struct tm rtime; + char * Context; + char seps[] = " ,\t\r"; + char Offset[10] = ""; + int i, HH, MM; + char Copy[500]=""; + + // Copy message, so original isn't messed up by strtok + + memcpy(Copy, ptr1, linelen); + + ptr1 = Copy; + + memset(&rtime, 0, sizeof(struct tm)); + + // Date: Tue, 9 Jun 2009 20:54:55 +0100 + + ptr1 = strtok_s(&ptr1[5], seps, &Context); // Skip Day + ptr1 = strtok_s(NULL, seps, &Context); // Day + + rtime.tm_mday = atoi(ptr1); + + ptr1 = strtok_s(NULL, seps, &Context); // Month + + for (i=0; i < 12; i++) + { + if (strcmp(month[i], ptr1) == 0) + { + rtime.tm_mon = i; + break; + } + } + + sscanf(Context, "%04d %02d:%02d:%02d%s", + &rtime.tm_year, &rtime.tm_hour, &rtime.tm_min, &rtime.tm_sec, Offset); + + rtime.tm_year -= 1900; + + Date = mktime(&rtime) - (time_t)_MYTIMEZONE; + + if (Date == (time_t)-1) + Date = 0; + else + { + if ((Offset[0] == '+') || (Offset[0] == '-')) + { + MM = atoi(&Offset[3]); + Offset[3] = 0; + HH = atoi(&Offset[1]); + MM = MM + (60 * HH); + + if (Offset[0] == '+') + Date -= (60*MM); + else + Date += (60*MM); + + + } + } + } + + + if (linelen) // Not Null line + { + ptr1 = ptr2 + 2; // Skip crlf + goto Loop; + } + + ptr1 = sockptr->MailBuffer; + + TidyString(MsgFrom); + _strlwr(MsgFrom); + + MsgLen = (int)(sockptr->MailSize - (ptr2 - ptr1)); + + B2Flag = CheckforMIME(sockptr, sockptr->MailBuffer, &ptr2, &MsgLen); // Will reformat message if necessary. + + CreatePOP3Message(MsgFrom, MsgTo, Msgtitle, Date, ptr2, MsgLen, B2Flag); + + free(sockptr->MailBuffer); + sockptr->MailBufferSize=0; + sockptr->MailBuffer=0; + sockptr->MailSize = 0; + + sockptr->Flags &= ~GETTINGMESSAGE; + + if (sockptr->POP3MsgCount > sockptr->POP3MsgNum++) + { + sockprintf(sockptr, "RETR %d", sockptr->POP3MsgNum); + + sockptr->State = WaitingForRETRResponse; + } + else + { + sockptr->POP3MsgNum = 1; + sockprintf(sockptr, "DELE %d", sockptr->POP3MsgNum);; + sockptr->State = WaitingForDELEResponse; + } + + return; + } + + if ((sockptr->MailSize + Len) > sockptr->MailBufferSize) + { + sockptr->MailBufferSize += 10000; + sockptr->MailBuffer = realloc(sockptr->MailBuffer, sockptr->MailBufferSize); + + if (sockptr->MailBuffer == NULL) + { + CriticalErrorHandler("Failed to extend Message Buffer"); + shutdown(sock, 0); + return; + } + } + + memcpy(&sockptr->MailBuffer[sockptr->MailSize], Buffer, Len); + sockptr->MailSize += Len; + + return; + } + + if (sockptr->State == WaitingForGreeting) + { + if (memcmp(Buffer, "+OK", 3) == 0) + { + sockprintf(sockptr, "USER %s", ISPAccountName); + sockptr->State = WaitingForUSERResponse; + } + else + { + SendSock(sockptr, "QUIT"); + sockptr->State = 0; + } + + return; + } + + if (sockptr->State == WaitingForUSERResponse) + { + if (memcmp(Buffer, "+OK", 3) == 0) + { + sockprintf(sockptr, "PASS %s", ISPAccountPass); + sockptr->State = WaitingForPASSResponse; + } + else + { + SendSock(sockptr, "QUIT"); + sockptr->State = WaitingForQUITResponse; + } + + return; + } + + if (sockptr->State == WaitingForPASSResponse) + { + if (memcmp(Buffer, "+OK", 3) == 0) + { + SendSock(sockptr, "STAT"); + sockptr->State = WaitingForSTATResponse; + } + else + { + shutdown(sock, 0); + sockptr->State = 0; + } + + return; + } + + if (sockptr->State == WaitingForSTATResponse) + { + if (memcmp(Buffer, "+OK", 3) == 0) + { + int Msgs = atoi(&Buffer[3]); + + if (Msgs > 0) + { + sockptr->POP3MsgCount = Msgs; + sockptr->POP3MsgNum = 1; + SendSock(sockptr, "RETR 1"); + + sockptr->State = WaitingForRETRResponse; + + } + else + { + SendSock(sockptr, "QUIT"); + sockptr->State = WaitingForQUITResponse; + } + } + else + { + SendSock(sockptr, "QUIT"); + sockptr->State = WaitingForQUITResponse; + } + + return; + } + + if (sockptr->State == WaitingForRETRResponse) + { + if (memcmp(Buffer, "+OK", 3) == 0) + { + sockptr->MailBuffer=malloc(10000); + sockptr->MailBufferSize=10000; + + if (sockptr->MailBuffer == NULL) + { + CriticalErrorHandler("Failed to create POP3 Message Buffer"); + SendSock(sockptr, "QUIT"); + sockptr->State = WaitingForQUITResponse; + shutdown(sock, 0); + + return; + } + + sockptr->Flags |= GETTINGMESSAGE; + + } + else + { + SendSock(sockptr, "QUIT"); + sockptr->State = WaitingForQUITResponse; + } + + return; + } + if (sockptr->State == WaitingForDELEResponse) + { + if (memcmp(Buffer, "+OK", 3) == 0) + { + if (sockptr->POP3MsgCount > sockptr->POP3MsgNum++) + { + sockprintf(sockptr, "DELE %d", sockptr->POP3MsgNum);; + } + else + { + SendSock(sockptr, "QUIT"); + sockptr->Flags = WaitingForQUITResponse; + } + } + else + { + shutdown(sock,0); + sockptr->State = 0; + } + return; + } + + if (sockptr->State == WaitingForQUITResponse) + { + shutdown(sock,0); + sockptr->State = 0; + return; + } + + SendSock(sockptr, "QUIT"); + shutdown(sock,0); + sockptr->State = 0; + +} + +static char Winlink[] = "WINLINK.ORG"; + +int CreatePOP3Message(char * From, char * To, char * MsgTitle, time_t Date, char * MsgBody, int MsgLen, BOOL B2Flag) +{ + struct MsgInfo * Msg; + BIDRec * BIDRec; + + // Allocate a message Record slot + + Msg = AllocateMsgRecord(); + + // Set number here so they remain in sequence + + Msg->number = ++LatestMsg; + MsgnotoMsg[Msg->number] = Msg; + Msg->length = MsgLen; + + + sprintf_s(Msg->bid, sizeof(Msg->bid), "%d_%s", LatestMsg, BBSName); + + Msg->type = 'P'; + Msg->status = 'N'; + Msg->datereceived = Msg->datechanged = Msg->datecreated = time(NULL); + + if (Date) + Msg->datecreated = Date; + + BIDRec = AllocateBIDRecord(); + + strcpy(BIDRec->BID, Msg->bid); + BIDRec->mode = Msg->type; + BIDRec->u.msgno = LOWORD(Msg->number); + BIDRec->u.timestamp = LOWORD(time(NULL)/86400); + + + TidyString(To); + strlop(To, '@'); + + // Could have surrounding "" "" + + if (To[0] == '"') + { + int len = (int)strlen(To) - 1; + + if (To[len] == '"') + { + To[len] = 0; + memmove(To, &To[1], len); + } + } + + if (GMailMode) + { + // + separates our address and the target user + + char * GMailto; + + GMailto = strlop(To,'+'); + + if (GMailto) + { + char * GmailVia = NULL; + + strcpy(To, GMailto); + GmailVia = strlop(To, '|'); + + if (GmailVia) + strcpy(Msg->via, GmailVia); + } + else + { + // Someone has sent to the GMAIL account without a +. + // This should go to the BBS Call + + strcpy(To, BBSName); + } + } + + if ((_memicmp(To, "bull/", 5) == 0) || (_memicmp(To, "bull.", 5) == 0) + || (_memicmp(To, "bull:", 5) == 0)) + { + Msg->type = 'B'; + memmove(To, &To[5], strlen(&To[4])); + } + + if ((_memicmp(To, "nts/", 4) == 0) || (_memicmp(To, "nts.", 4) == 0) + || (_memicmp(To, "nts:", 4) == 0)) + { + Msg->type = 'T'; + memmove(To, &To[4], strlen(&To[3])); + } + + if (Msg->type == 'P' && Msg->via[0] == 0) + { + // No via - add one from HomeBBS or WP + + struct UserInfo * ToUser = LookupCall(To); + + if (ToUser) + { + // Local User. If Home BBS is specified, use it + + if (ToUser->flags & F_RMSREDIRECT) + { + // sent to Winlink + + strcpy(Msg->via, Winlink); + } + else if (ToUser->HomeBBS[0]) + strcpy(Msg->via, ToUser->HomeBBS); + } + else + { + WPRec * WP = LookupWP(To); + + if (WP) + strcpy(Msg->via, WP->first_homebbs); + } + } + +/* if (_memicmp(To, "rms:", 4) == 0) + { + via = _strlwr(strlop(To, ':')); + } + else if (_memicmp(To, "rms/", 4) == 0) + { + via = _strlwr(strlop(To, '/')); + } + else if (_memicmp(To, "rms.", 4) == 0) + { + via = _strlwr(strlop(To, '.')); + } +*/ + + + if (strlen(To) > 6) To[6]=0; + + strcpy(Msg->to, To); + strcpy(Msg->from, "smtp:"); + strcpy(Msg->emailfrom, From); + strcpy(Msg->title, MsgTitle); + + if(Msg->to[0] == 0) + SMTPMsgCreated=TRUE; + + if (B2Flag) + { + char B2Hddr[1000]; + int B2HddrLen; + char B2To[80]; + char * NewBody; + char DateString[80]; + struct tm * tm; + char Type[16] = "Private"; + + // Get Type + + if (Msg->type == 'B') + strcpy(Type, "Bulletin"); + else if (Msg->type == 'T') + strcpy(Type, "Traffic"); + + + tm = gmtime(&Date); + + sprintf(DateString, "%04d/%02d/%02d %02d:%02d", + tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min); + + + if (strcmp(Msg->to, "RMS") == 0) // Address is in via + strcpy(B2To, Msg->via); + else + if (Msg->via[0]) + sprintf(B2To, "%s@%s", Msg->to, Msg->via); + else + strcpy(B2To, Msg->to); + + + Msg->B2Flags = B2Msg | Attachments; + + B2HddrLen = sprintf(B2Hddr, + "MID: %s\r\nDate: %s\r\nType: %s\r\nFrom: %s\r\nTo: %s\r\nSubject: %s\r\nMbo: %s\r\n", + Msg->bid, DateString, Type, + Msg->from, B2To, Msg->title, BBSName); + + NewBody = MsgBody - B2HddrLen; + + memcpy(NewBody, B2Hddr, B2HddrLen); + + Msg->length += B2HddrLen; + + // Set up forwarding bitmap + + MatchMessagetoBBSList(Msg, 0); + + return CreateSMTPMessageFile(NewBody, Msg); + } + + // Set up forwarding bitmap + + MatchMessagetoBBSList(Msg, 0); + + return CreateSMTPMessageFile(MsgBody, Msg); + +} + +VOID base64_encode(char *str, char * result, int len) +{ + unsigned int i = 0, j = 0; + char *tmp = str; + + + while (len > 2 ) + { + encodeblock(&str[i], &result[j],3); + i+=3; + j+=4; + len -=3; + } + if (len) + { + encodeblock(&str[i], &result[j], len); + } + + return; +} + +void Base64EncodeAndSend(SocketConn * sockptr, UCHAR * Msg, int Len) +{ + char Base64Line[80]; + int i = Len; + int j = 0; + + Base64Line[76] = 13; + Base64Line[77] = 10; + Base64Line[78] = 0; + + // Need to encode in 57 byte chunks to give 76 char lines. + + while(i > 57) + { + base64_encode(&Msg[j], Base64Line, 57); + SendSock(sockptr, Base64Line); + + j += 57; + i -= 57; + } + + memset(Base64Line, 0, 79); + + base64_encode(&Msg[j], Base64Line, i); + SendSock(sockptr, Base64Line); + SendSock(sockptr, ""); +} + +VOID SendMultiPartMessage(SocketConn * sockptr, struct MsgInfo * Msg, UCHAR * msgbytes) +{ + char * ptr; + char Header[120]; + char Separator[33]=""; + char FileName[100][250] = {""}; + int FileLen[100]; + int Files = 0; + int BodyLen; + int i; + + CreateOneTimePassword(&Separator[0], "Key", 0); + CreateOneTimePassword(&Separator[16], "Key", 1); + + SendSock(sockptr, "MIME-Version: 1.0"); + + sprintf_s(Header, sizeof(Header), "Content-Type: multipart/mixed; boundary=\"%s\"", Separator); + SendSock(sockptr, Header); + + SendSock(sockptr, ""); // Blank line before body + +// Get Part Sizes and Filenames + + ptr = msgbytes; + + while(*ptr != 13) + { + char * ptr2 = strchr(ptr, 10); // Find CR + + if (memcmp(ptr, "Body: ", 6) == 0) + { + BodyLen = atoi(&ptr[6]); + } + + if (memcmp(ptr, "File: ", 6) == 0) + { + char * ptr1 = strchr(&ptr[6], ' '); // Find Space + + FileLen[Files] = atoi(&ptr[6]); + + memcpy(FileName[Files++], &ptr1[1], (ptr2-ptr1 - 2)); + } + + ptr = ptr2; + ptr++; + } + + ptr += 2; // Over Blank Line + + // Write the none-Mime Part + + SendSock(sockptr, "This is a multi-part message in MIME format."); + SendSock(sockptr, ""); + + // Write the Body as the first part. + + sprintf_s(Header, sizeof(Header), "--%s", Separator); + SendSock(sockptr, Header); + SendSock(sockptr, "Content-Type: text/plain"); + SendSock(sockptr, ""); + + ptr[BodyLen] = 0; + + SendSock(sockptr, ptr); + + ptr += BodyLen; // to first file + ptr += 2; // Over Blank Line + + // Write Each Attachment + + for (i = 0; i < Files; i++) + { + sprintf_s(Header, sizeof(Header), "--%s", Separator); + SendSock(sockptr, Header); +// Content-Type: image/png; name="UserParams.png" + SendSock(sockptr, "Content-Transfer-Encoding: base64"); + + sprintf_s(Header, sizeof(Header), "Content-Disposition: attachment; filename=\"%s\"", FileName[i]); + SendSock(sockptr, Header); + + SendSock(sockptr, ""); + + // base64 encode and send file + + Base64EncodeAndSend(sockptr, ptr, FileLen[i]); + + ptr += FileLen[i]; + ptr +=2; // Over separator + } + + sprintf_s(Header, sizeof(Header), "--%s--", Separator); + SendSock(sockptr, Header); + + SendSock(sockptr, ""); + SendSock(sockptr, "."); + + free(msgbytes); + + return; +} + +BOOL SendAMPRSMTP(CIRCUIT * conn) +{ + struct UserInfo * bbs = conn->UserPointer; + + while (FindMessagestoForward(conn)) + { + if (SendtoAMPR(conn)) + { + bbs->ForwardingInfo->Forwarding = TRUE; + return TRUE; + } + } + + bbs->ForwardingInfo->Forwarding = FALSE; + return FALSE; +} + diff --git a/MailTCP.c b/MailTCP.c index b26f6da..74f2727 100644 --- a/MailTCP.c +++ b/MailTCP.c @@ -2207,6 +2207,7 @@ int TidyString(char * Address) size_t len; _strupr(Address); + Debugprintf(Address); ptr1 = strchr(Address, '<'); @@ -2260,6 +2261,10 @@ int TidyString(char * Address) ptr1=ptr2; } + if (ptr1 == 0) + return 0; + + if (*ptr1 == '<') ptr1++; ptr2 = strlop(ptr1, '>'); diff --git a/QtTermTCP.ini b/QtTermTCP.ini new file mode 100644 index 0000000..c82399f --- /dev/null +++ b/QtTermTCP.ini @@ -0,0 +1,120 @@ +[General] +HostParams0=|0|||| +HostParams1=|0|||| +HostParams2=|0|||| +HostParams3=|0|||| +HostParams4=|0|||| +HostParams5=|0|||| +HostParams6=|0|||| +HostParams7=|0|||| +HostParams8=|0|||| +HostParams9=|0|||| +HostParams10=|0|||| +HostParams11=|0|||| +HostParams12=|0|||| +HostParams13=|0|||| +HostParams14=|0|||| +HostParams15=|0|||| +Split=50 +ChatMode=1 +AutoTeletext=0 +Bells=1 +StripLF=1 +AlertBeep=1 +ConnectBeep=1 +AlertInterval=300 +CurrentHost=0 0 0 0 0 0 0 0 0 0 +YAPPPath= +MaxRXSize=100000 +listenPort=8015 +listenEnable=0 +listenCText= +convUTF8=0 +PTT=None +PTTBAUD=19200 +PTTMode=19200 +CATHex=1 +PTTOffString= +PTTOnString= +pttGPIOPin=17 +pttGPIOPinR=17 +CM108Addr=0xD8C:0x08 +HamLibPort=4532 +HamLibHost=127.0.0.1 +FLRigPort=12345 +FLRigHost=127.0.0.1 +AGWEnable=0 +AGWMonEnable=0 +AGWTermCall= +AGWBeaconDest= +AGWBeaconPath= +AGWBeaconInterval=0 +AGWBeaconPorts= +AGWBeaconText= +AGWHost=127.0.0.1 +AGWPort=8000 +AGWPaclen=80 +AGWToCalls= +KISSEnable=0 +MYCALL= +KISSHost=127.0.0.1 +KISSMode=0 +KISSPort=8100 +KISSSerialPort=None +KISSBAUD=19200 +VARAEnable=0 +VARATermCall= +VARAHost=127.0.0.1 +VARAPort=8300 +VARAInit= +VARAPath=C:\\VARA\\VARA.exe +VARAHostHF=127.0.0.1 +VARAPortHF=8300 +VARAPathHF=C:\\VARA\\VARA.exe +VARAHostFM=127.0.0.1 +VARAPortFM=8300 +VARAPathFM=C:\\VARA\\VARAFM.exe +VARAHostSAT=127.0.0.1 +VARAPortSAT=8300 +VARAPathSAT=C:\\VARA\\VARASAT.exe +VARA500=0 +VARA2300=1 +VARA2750=0 +VARAHF=1 +VARAFM=0 +VARASAT=0 +TabType=1 1 1 1 1 1 1 2 2 0 +AutoConnect=0 0 0 0 0 0 0 0 0 0 +monBackground=@Variant(\0\0\0\x43\x1\xff\xff\xff\xff\xff\xff\xff\xff\0\0) +monRxText=@Variant(\0\0\0\x43\x1\xff\xff\0\0\0\0\xff\xff\0\0) +monTxText=@Variant(\0\0\0\x43\x1\xff\xff\xff\xff\0\0\0\0\0\0) +monOtherText=@Variant(\0\0\0\x43\x1\xff\xff\0\0\0\0\0\0\0\0) +termBackground=@Variant(\0\0\0\x43\x1\xff\xff\xff\xff\xff\xff\xff\xff\0\0) +outputText=@Variant(\0\0\0\x43\x1\xff\xff\0\0\0\0\xff\xff\0\0) +EchoText=@Variant(\0\0\0\x43\x1\xff\xff\0\0\0\0\0\0\0\0) +WarningText=@Variant(\0\0\0\x43\x1\xff\xff\xff\xff\0\0\0\0\0\0) +inputBackground=@Variant(\0\0\0\x43\x1\xff\xff\xff\xff\xff\xff\xff\xff\0\0) +inputText=@Variant(\0\0\0\x43\x1\xff\xff\0\0\0\0\0\0\0\0) +useBeep=false +geometry=@ByteArray(\x1\xd9\xd0\xcb\0\x3\0\0\0\0\x2\x39\0\0\0\xab\0\0\x5\x45\0\0\x3\x64\0\0\x2\x39\0\0\0\xab\0\0\x5\x45\0\0\x3\x64\0\0\0\0\0\0\0\0\a\x80\0\0\x2\x39\0\0\0\xab\0\0\x5\x45\0\0\x3\x64) +windowState=@ByteArray(\0\0\0\xff\0\0\0\0\xfd\0\0\0\0\0\0\x3\r\0\0\x2\xa4\0\0\0\x4\0\0\0\x4\0\0\0\b\0\0\0\b\xfc\0\0\0\x1\0\0\0\x3\0\0\0\x1\0\0\0\x16\0m\0\x61\0i\0n\0T\0o\0o\0l\0\x62\0\x61\0r\0\0\0\0\0\xff\xff\xff\xff\0\0\0\0\0\0\0\0) +ConnectWAV=C:/OneDrive/Dev/Source/bpq32/CommonSource/Ring.wav + +[AX25_A] +Retries=10 +Maxframe=4 +Paclen=128 +FrackTime=8 +IdleTime=180 +SlotTime=100 +Persist=128 +RespTime=1500 +TXFrmMode=1 +FrameCollector=6 +ExcludeCallsigns= +ExcludeAPRSFrmType= +KISSOptimization=0 +DynamicFrack=0 +BitRecovery=0 +IPOLL=80 +MyDigiCall= diff --git a/RCa22388 b/RCa22388 deleted file mode 100644 index e5492c1..0000000 Binary files a/RCa22388 and /dev/null differ diff --git a/RigControl.c b/RigControl.c index 83be639..57761a4 100644 --- a/RigControl.c +++ b/RigControl.c @@ -125,6 +125,16 @@ VOID SetupPortRIGPointers(); VOID PTTCATThread(struct RIGINFO *RIG); VOID ConnecttoHAMLIB(struct RIGPORTINFO * PORT); +// ----- G7TAJ ---- +VOID ConnecttoSDRANGEL(struct RIGPORTINFO * PORT); +VOID SDRANGELPoll(struct RIGPORTINFO * PORT); +void ProcessSDRANGELFrame(struct RIGPORTINFO * PORT); +VOID SDRANGELSendCommand(struct RIGPORTINFO * PORT, char * Command, char * Value); +void SDRANGELProcessMessage(struct RIGPORTINFO * PORT); + +// ----- G7TAJ ---- + + int SendPTCRadioCommand(struct TNCINFO * TNC, char * Block, int Length); int GetPTCRadioCommand(struct TNCINFO * TNC, char * Block); int BuildRigCtlPage(char * _REPLYBUFFER); @@ -184,6 +194,10 @@ int HAMLIBMasterRunning = 0; int HAMLIBSlaveRunning = 0; int FLRIGRunning = 0; +// ---- G7TAJ ---- +int SDRANGELRunning = 0; +// ---- G7TAJ ---- + char * RigWebPage = 0; int RigWebPageLen = 0; @@ -796,6 +810,26 @@ static char Req[] = "\r\n" "\r\n"; +// ---- G7TAJ ---- +static char SDRANGEL_MsgHddr[] = "PATCH HTTP/1.1\r\n" + "User-Agent: BPQ32\r\n" + "Host: %s\r\n" + "accept: application/json" + "Content-Type: application/json" + "Content-length: %d\r\n" + "\r\n%s"; + +static char SDRANGEL_FREQ_DATA[] = "{" + "\"deviceHwType\": \"%s\", " + "\"direction\": 0," + "\"rtlSdrSettings\": {" + " \"centerFrequency\": \"%s\"" + "}}"; + +//freq = 10489630000 + +// ---- G7TAJ ---- + int Rig_CommandEx(struct RIGPORTINFO * PORT, struct RIGINFO * RIG, TRANSPORTENTRY * Session, char * Command) @@ -2074,7 +2108,7 @@ int Rig_CommandEx(struct RIGPORTINFO * PORT, struct RIGINFO * RIG, TRANSPORTENTR memcpy(&cmd[1], &USB, 4); else if (strcmp(Mode, "LSB") == 0) memcpy(&cmd[1], &LSB, 4); - + cmd[0] = 1; len = sendto(PORT->remoteSock, cmd, 5, 0, &PORT->remoteDest, sizeof(struct sockaddr)); } @@ -2084,7 +2118,43 @@ int Rig_CommandEx(struct RIGPORTINFO * PORT, struct RIGINFO * RIG, TRANSPORTENTR sprintf(Command, "Ok\r"); return FALSE; } +// --- G7TAJ ---- + case SDRANGEL: + { + char cmd[80]; + int len = sprintf(cmd, "%.0f", Freq); + strcpy(PORT->ScanEntry.Cmd2Msg, Mode); + strcpy(PORT->ScanEntry.Cmd3Msg, FilterString); + + if (Freq > 0.0) + { + SDRANGELSendCommand(PORT, "FREQSET", cmd); + sprintf(Command, "Ok\r"); + return FALSE; + } +//TODO +/* else if (PORT->ScanEntry.Cmd2Msg[0] && Mode[0] != '*') + { + sprintf(cmd, "%s", PORT->ScanEntry.Cmd2Msg); + FLRIGSendCommand(PORT, "rig.set_mode", cmd); + } + + else if (PORT->ScanEntry.Cmd3Msg[0] && strcmp(PORT->ScanEntry.Cmd3Msg, "0") != 0) + { + sprintf(cmd, "%s", PORT->ScanEntry.Cmd3Msg); + FLRIGSendCommand(PORT, "rig.set_bandwidth", cmd); + } +*/ + else + { + sprintf(Command, "Sorry - Nothing to do\r"); + return FALSE; + } + + PORT->AutoPoll = 0; + } +// --- G7TAJ ---- @@ -2271,6 +2341,14 @@ DllExport BOOL APIENTRY Rig_Init() } else if (PORT->PortType == RTLUDP) ConnecttoRTLUDP(PORT); +//---- G7TAJ ---- + else if (PORT->PortType == SDRANGEL) + { + SDRANGELRunning = 1; + ConnecttoSDRANGEL(PORT); + + } +//---- G7TAJ ---- else if (PORT->HIDDevice) // This is RAWHID, Not CM108 OpenHIDPort(PORT, PORT->IOBASE, PORT->SPEED); else if (PORT->PTC == 0 && _stricmp(PORT->IOBASE, "CM108") != 0) @@ -2421,7 +2499,10 @@ DllExport BOOL APIENTRY Rig_Close() HAMLIBMasterRunning = 0; // Close HAMLIB thread(s) HAMLIBSlaveRunning = 0; // Close HAMLIB thread(s) - FLRIGRunning = 0; // Close FLRIG thread(s) + FLRIGRunning = 0; // Close FLRIG thread(s) +// ---- G7TAJ ---- + SDRANGELRunning = 0; // Close SDRANGEL thread(s) +// ---- G7TAJ ---- for (p = 0; p < NumberofPorts; p++) { @@ -2544,6 +2625,10 @@ BOOL Rig_Poll() ConnecttoFLRIG(PORT); else if (PORT->PortType == RTLUDP) ConnecttoRTLUDP(PORT); +// ---- G7TAJ ---- + else if (PORT->PortType == SDRANGEL) + ConnecttoSDRANGEL(PORT); +// ---- G7TAJ ---- else if (PORT->HIDDevice) OpenHIDPort(PORT, PORT->IOBASE, PORT->SPEED); else if (PORT->PTC == 0 @@ -2632,7 +2717,12 @@ BOOL Rig_Poll() case FLRIG: FLRIGPoll(PORT); + break; +// ---- G7TAJ ---- + case SDRANGEL: + SDRANGELPoll(PORT); break; } +// ---- G7TAJ ---- } // Build page for Web Display @@ -3014,6 +3104,14 @@ BOOL RigWriteCommBlock(struct RIGPORTINFO * PORT) #ifndef WIN32 BytesWritten = write(PORT->hDevice, PORT->TXBuffer, PORT->TXLen); #else + DWORD Mask = 0; + int Err; + + Err = GetCommModemStatus(PORT->hDevice, &Mask); + + if (Mask == 0) // trap com0com other end not open + return TRUE; + fWriteStat = WriteFile(PORT->hDevice, PORT->TXBuffer, PORT->TXLen, &BytesWritten, NULL ); #endif if (PORT->TXLen != BytesWritten) @@ -5529,6 +5627,78 @@ struct RIGINFO * RigConfig(struct TNCINFO * TNC, char * buf, int Port) goto CheckOtherParams; } +// ---- G7TAJ ---- + + if (_memicmp(ptr, "sdrangel", 5) == 0) + { + // each instance (ip addr/port) of sdrangle can have one or more sampling devices (eg rltsdr) each with one ot + // more channels (eg ssb demod, ssb mod). each set of sampling device = channel(s) is a device set. + + // We poll all devices/channels at once. we one PORT record plus a RIG record for each channel + + // Need parameters - Host:Port device channel. Device and Channel will default to zero + + int device = 0, channel = 0; + char * Name; + char * nptr1; + char * nptr2; + + + ptr = strtok_s(NULL, " \t\n\r", &Context); + + if (ptr == NULL || strlen(ptr) > 79) return FALSE; + + Name = strtok_s(NULL, " \t\n\r", &Context); + nptr1 = strtok_s(NULL, " \t\n\r", &Context); + nptr2 = strtok_s(NULL, " \t\n\r", &Context); + + if (nptr1 == 0 || nptr2 == 0 || Name == NULL || strlen(Name) > 9) + return FALSE; + + device = atoi(nptr1); + channel = atoi(nptr2); + + // Have a parameter to define port. Will decode it later + + // See if already defined. PORT->IOBASE has Host:Port + + for (i = 0; i < NumberofPorts; i++) + { + PORT = PORTInfo[i]; + + if (strcmp(PORT->IOBASE, ptr) == 0) + goto AngelRigFound; + } + + // New Port + + PORT = PORTInfo[NumberofPorts++] = zalloc(sizeof(struct RIGPORTINFO)); + PORT->PortType = SDRANGEL; + PORT->ConfiguredRigs = 0; + strcpy(PORT->IOBASE, ptr); + + // Decode host + + DecodeHAMLIBAddr(PORT, ptr); + + +AngelRigFound: + + RIG = &PORT->Rigs[PORT->ConfiguredRigs++]; + RIG->RIGOK = TRUE; + RIG->PORT = PORT; + RIG->RigAddr = device; + RIG->Channel = channel; + + strcpy(RIG->RigName, Name); + + ptr = strtok_s(NULL, " \t\n\r", &Context); + + // look for scan params + + goto CheckOtherParams; + } +// ---- G7TAJ ---- if ((_memicmp(ptr, "VCOM", 4) == 0) && TNC->Hardware == H_SCS) // Using Radio Port on PTC COMPort = 0; @@ -9633,8 +9803,616 @@ VOID ConnecttoRTLUDP(struct RIGPORTINFO * PORT) PORT->Alerted = TRUE; } +char * getObjectFromArray(char * Msg); // This gets the next object from an array ({} = object, [] = array + + + +char * getArrayFromMsg(char * Msg) +{ + // This gets the next object from an array ({} = object, [] = array + // We look for the end of the object same number of { and }, teminate after } and return pointer to next object + // So we have terminated Msg, and returned next object in array + + // Only call if Msg is the next array in Msg + + + char * ptr = Msg; + char c; + + int Open = 0; + int Close = 0; + + while (c = *(ptr++)) + { + if (c == '[') Open ++; else if (c == ']') Close ++; + + if (Open == Close) + { + *(ptr++) = 0; + return ptr; + } + } + return 0; +} + + +//----- G7TAJ ----- + +void ProcessSDRANGELFrame(struct RIGPORTINFO * PORT) +{ + + int Length; + + char * msg; + char * rest; + + struct RIGINFO * RIG; + char * ptr, * ptr1, * ptr2, * ptr3, * pos; + int Len, TotalLen; + char cmd[80]; + char ReqBuf[256]; + char SendBuff[256]; + int chunklength; + int headerlen; + int i, n = 0; + char * Sets; + char * Rest; + char * Set; + int channelcount; + char * channels; + char * channel; + char * samplingDevice; + char * save; + + //Debugprintf("Process SDRANGEL Frame %d\n", PORT->RXLen); + + msg = PORT->RXBuffer; + Length = PORT->RXLen; + + msg[Length] = 0; + + ptr1 = strstr(msg, "Transfer-Encoding: chunked" ); + + if (ptr1 == NULL) + return; + + ptr2 = strstr(ptr1, "\r\n\r\n"); + + if (ptr2 == NULL) + return; + + // ptr2 +4 points to the length of the first chunk (in hex), terminated by crlf + + chunklength = (int)strtol(ptr2 + 4, &ptr3, 16); + ptr3 += 2; // pointer to first chunk data + headerlen = ptr3 - msg; + + // make sure we have first chunk + + if (chunklength + headerlen > Length) + return; + + PORT->RXLen = 0; //we have all the frame now + PORT->Timeout = 0; + + if (strstr(ptr3, "deviceSets") == 0) + { + return; + } + + // Message has info for all rigs + + // As we mess with the message, save a copy and restore for each Rig + + save = strdup(ptr3); + + for (i = 0; i < PORT->ConfiguredRigs; i++) + { + strcpy(ptr3, save); + n = 0; + + RIG = &PORT->Rigs[i]; + RIG->RIGOK = 1; + + // we can have one or more sampling devices (eg rltsdr) each with one or + // more channels (eg ssb demod, ssb mod). each set of sampling device = channel(s) is a device set. + + // Find Device Set for this device (in RIG-> + + // Message Structure is + + //{ + // "deviceSets": [...]. + // "devicesetcount": 2, + // "devicesetfocus": 0 + //} + + // Get the device sets (JSON [..] is an array + + Sets = strchr(ptr3, '['); + + if (Sets == 0) + continue; + + Rest = getArrayFromMsg(Sets); + + // Do we need to check devicesetcount ??. Maybe use to loop through sets, or just stop at end + + // get the set for our device + + while (RIG->RigAddr >= n) + { + Set = strchr(Sets, '{'); // Position to start of first Object + + if (Set == 0) + break; + + Sets = getObjectFromArray(Set); + n++; + } + + if (Set == 0) + continue; + + + // Now get the channel. looking for key "index": + + // we could have a number of sampling devices and channels but for now get sampling device freq + // and first channel freq. Channels are in an Array + + if ((ptr = strstr(Set, "channelcount")) == 0) + continue; + + channelcount = atoi(&ptr[15]); + + if ((channels = strchr(Set, '[')) == 0) + continue; + + samplingDevice = getArrayFromMsg(channels); + + while(channelcount--) + { + channel = strchr(channels, '{'); + channels = getObjectFromArray(channel); + + if ((ptr = strstr(channel, "index"))) + { + n = atoi(&ptr[7]); + if (n == RIG->Channel) + break; + } + } + + + + if (pos = strstr(samplingDevice, "centerFrequency")) //"centerFrequency": 10489630000, + { + pos += 18; + strncpy(cmd, pos, 20); + RIG->RigFreq = atof(cmd) / 1000000.0; + } + + if (pos = strstr(channel, "deltaFrequency")) + { + pos += 17; + strncpy(cmd, pos, 20); + RIG->RigFreq += (atof(cmd) + RIG->rxOffset) / 1000000.0;; + } + + + _gcvt(RIG->RigFreq, 9, RIG->Valchar); + + sprintf(RIG->WEB_FREQ,"%s", RIG->Valchar); + SetWindowText(RIG->hFREQ, RIG->WEB_FREQ); + + // we could get mode from Title line: + //"title": "SSB Demodulator", + + if (pos = strstr(channel, "title")) + { + pos += 9; + strncpy(cmd, pos, 20); + strlop(pos, ' '); + strncpy(RIG->ModeString, pos, 15); + sprintf(RIG->WEB_MODE, "%s", RIG->ModeString); + SetWindowText(RIG->hMODE, RIG->WEB_MODE); + } + + } + + + /* + while (msg && msg[0]) + { + rest = strlop(msg, ','); + + if ( pos = strstr(msg, "centerFrequency")) //"centerFrequency": 10489630000, + { + pos += 18; + strncpy(cmd, pos,20); + + RIG->RigFreq = atof(cmd) / 1000000.0; + + // printf("FREQ=%f\t%s\n", RIG->RigFreq, cmd); + + _gcvt(RIG->RigFreq, 9, RIG->Valchar); + + sprintf(RIG->WEB_FREQ,"%s", RIG->Valchar); + SetWindowText(RIG->hFREQ, RIG->WEB_FREQ); + } + + else if (memcmp(msg, "Mode:", 5) == 0) + { + if (strlen(&msg[6]) < 15) + strcpy(RIG->ModeString, &msg[6]); + } + + else if (memcmp(msg, "Passband:", 9) == 0) + { + RIG->Passband = atoi(&msg[10]); + sprintf(RIG->WEB_MODE, "%s/%d", RIG->ModeString, RIG->Passband); + SetWindowText(RIG->hMODE, RIG->WEB_MODE); + } + + msg = rest; + } + */ + free (save); +} + + + +VOID SDRANGELThread(struct RIGPORTINFO * PORT); + +VOID ConnecttoSDRANGEL(struct RIGPORTINFO * PORT) +{ + if (SDRANGELRunning) + _beginthread(SDRANGELThread, 0, (void *)PORT); + return ; +} + +VOID SDRANGELThread(struct RIGPORTINFO * PORT) +{ + // Opens sockets and looks for data + char Msg[255]; + int err, i, ret; + u_long param=1; + BOOL bcopt=TRUE; + fd_set readfs; + fd_set errorfs; + struct timeval timeout; + + if (PORT->CONNECTING) + return; + + PORT->RXLen = 0; + + PORT->CONNECTING = 1; + + if (PORT->remoteSock) + { + closesocket(PORT->remoteSock); + } + + PORT->remoteSock = 0; + PORT->remoteSock = socket(AF_INET,SOCK_STREAM,0); + + if (PORT->remoteSock == INVALID_SOCKET) + { + i=sprintf(Msg, "Socket Failed for SDRAngel socket - error code = %d\r\n", WSAGetLastError()); + WritetoConsole(Msg); + + PORT->CONNECTING = FALSE; + return; + } + + setsockopt(PORT->remoteSock, SOL_SOCKET, SO_REUSEADDR, (const char FAR *)&bcopt, 4); + setsockopt(PORT->remoteSock, IPPROTO_TCP, TCP_NODELAY, (const char FAR *)&bcopt, 4); + + if (connect(PORT->remoteSock,(LPSOCKADDR) &PORT->remoteDest,sizeof(PORT->remoteDest)) == 0) + { + // + // Connected successful + // + + ioctl(PORT->remoteSock, FIONBIO, ¶m); + } + else + { + if (PORT->Alerted == FALSE) + { + struct sockaddr_in * destaddr = (SOCKADDR_IN * )&PORT->remoteDest; + + err = WSAGetLastError(); + + sprintf(Msg, "Connect Failed for SDRAngel socket - error code = %d Port %d\r\n", + err, htons(destaddr->sin_port)); + + WritetoConsole(Msg); + PORT->Alerted = TRUE; + } + + closesocket(PORT->remoteSock); + + PORT->remoteSock = 0; + PORT->CONNECTING = FALSE; + return; + } + + PORT->CONNECTED = TRUE; + PORT->CONNECTING = 0; + + PORT->hDevice = (HANDLE)1; // simplifies check code + + PORT->Alerted = TRUE; + + while (PORT->CONNECTED && SDRANGELRunning) + { + FD_ZERO(&readfs); + FD_ZERO(&errorfs); + + FD_SET(PORT->remoteSock,&readfs); + FD_SET(PORT->remoteSock,&errorfs); + + timeout.tv_sec = 5; + timeout.tv_usec = 0; + + ret = select((int)PORT->remoteSock + 1, &readfs, NULL, &errorfs, &timeout); + + if (SDRANGELRunning == 0) + return; + + if (ret == SOCKET_ERROR) + { + Debugprintf("SDRAngel Select failed %d ", WSAGetLastError()); + goto Lost; + } + + if (ret > 0) + { + // See what happened + + if (FD_ISSET(PORT->remoteSock, &readfs)) + { + SDRANGELProcessMessage(PORT); + } + + if (FD_ISSET(PORT->remoteSock, &errorfs)) + { +Lost: + sprintf(Msg, "SDRAngel Connection lost for Port %s\r\n", PORT->IOBASE); + WritetoConsole(Msg); + + PORT->CONNECTED = FALSE; + PORT->Alerted = FALSE; + PORT->hDevice = 0; // simplifies check code + + closesocket(PORT->remoteSock); + PORT->remoteSock = 0; + return; + } + continue; + } + else + { + } + } + sprintf(Msg, "SDRAngel Thread Terminated Port %s\r\n", PORT->IOBASE); + WritetoConsole(Msg); +} + +/* +# 10489630000 + +CURL_DATA='{ + "deviceHwType": "RTLSDR", + "direction": 0, + "rtlSdrSettings": { + "centerFrequency": "'$1'" + } + +}'; + + +curl -X PATCH "http://127.0.0.1:8091/sdrangel/deviceset/0/device/settings" \ + -H "accept: application/json" \ + -H "Content-Type: application/json" \ + -d "$CURL_DATA" + + + + +*/ + + +VOID SDRANGELPoll(struct RIGPORTINFO * PORT) +{ + UCHAR * Poll = PORT->TXBuffer; + + // SDRAngel can have muliple rigs but we only need to poll once to get info for all rigs so just use first entry + + struct RIGINFO * RIG = &PORT->Rigs[0]; + int Len, i; + char ReqBuf[256]; + char SendBuff[256]; + //char * SDRANGEL_GETheader = "GET /sdrangel/deviceset/%d/device/settings " + // "HTTP/1.1\nHost: %s\nConnection: keep-alive\n\r\n"; + + char * SDRANGEL_GETheader = "GET /sdrangel/devicesets " + "HTTP/1.1\nHost: %s\nConnection: keep-alive\n\r\n"; + + + if (RIG->ScanStopped == 0) + if (RIG->ScanCounter) + RIG->ScanCounter--; + + if (PORT->Timeout) + { + PORT->Timeout--; + + if (PORT->Timeout) // Still waiting + return; + + // Loop through all Rigs + + for (i = 0; i < PORT->ConfiguredRigs; i++) + { + RIG = &PORT->Rigs[i]; + + SetWindowText(RIG->hFREQ, "------------------"); + SetWindowText(RIG->hMODE, "----------"); + strcpy(RIG->WEB_FREQ, "-----------");; + strcpy(RIG->WEB_MODE, "------"); + + RIG->RIGOK = FALSE; + } + return; + } + + // Send Data if avail, else send poll + + if (RIG->NumberofBands && RIG->RIGOK && (RIG->ScanStopped == 0)) + { + if (RIG->ScanCounter <= 0) + { + // Send Next Freq + + if (GetPermissionToChange(PORT, RIG)) + { + char cmd[80]; + double freq; + + if (RIG->RIG_DEBUG) + Debugprintf("BPQ32 Change Freq to %9.4f", PORT->FreqPtr->Freq); + + _gcvt(PORT->FreqPtr->Freq / 1000000.0, 9, RIG->Valchar); // For MH + + // Send the Set Freq here, send set mode when we get a response + + memcpy(&PORT->ScanEntry, PORT->FreqPtr, sizeof(struct ScanEntry)); + +//TODO + sprintf(cmd, "%.0f", PORT->FreqPtr->Freq); + SDRANGELSendCommand(PORT, "SETFREQ", cmd); + + + PORT->CmdSent = 1; + PORT->Retries = 0; + PORT->Timeout = 10; + PORT->AutoPoll = TRUE; + + // There isn't a response to a set command, so clear Scan Lock here + ReleasePermission(RIG); // Release Perrmission + return; + } + } + } + + if (RIG->PollCounter) + { + RIG->PollCounter--; + if (RIG->PollCounter > 1) + return; + } + + if (RIG->RIGOK && (RIG->ScanStopped == 0) && RIG->NumberofBands) + return; // no point in reading freq if we are about to change it + + RIG->PollCounter = 40; + + // Read Frequency +//TODO + + +// Len = sprintf(SendBuff, SDRANGEL_GETheader, 0, &PORT->remoteDest ); // devicenum, host:port + Len = sprintf(SendBuff, SDRANGEL_GETheader, &PORT->remoteDest ); // devicenum, host:port + + if (PORT->CONNECTED) + { + if (send(PORT->remoteSock, SendBuff, Len, 0) != Len) + { + if (PORT->remoteSock) + closesocket(PORT->remoteSock); + + PORT->remoteSock = 0; + PORT->CONNECTED = FALSE; + PORT->hDevice = 0; + return; + } + } + + PORT->Timeout = 10; + PORT->CmdSent = 0; + + PORT->AutoPoll = TRUE; + + return; +} + +VOID SDRANGELSendCommand(struct RIGPORTINFO * PORT, char * Command, char * Value) +{ + int Len, ret; + char ReqBuf[512]; + char SendBuff[512]; + char ValueString[256] =""; + char * SDRANGEL_PATCHheader = "PATCH /sdrangel/deviceset/%d/device/settings " + "HTTP/1.1\nHost: %s\n" + "accept: application/json\n" + "Content-Type: application/json\n" + "Connection: keep-alive\n" + "Content-length: %d\r\n" + "\r\n%s"; + + if (!PORT->CONNECTED) + return; + + sprintf(ValueString, SDRANGEL_FREQ_DATA, "RTLSDR", Value); + + Len = sprintf(SendBuff, SDRANGEL_PATCHheader, 0, &PORT->remoteDest, strlen(ValueString), ValueString); + + ret = send(PORT->remoteSock, SendBuff, Len, 0); + + if (ret != Len) + { + if (PORT->remoteSock) + closesocket(PORT->remoteSock); + + PORT->remoteSock = 0; + PORT->CONNECTED = FALSE; + PORT->hDevice = 0; + } + + return; +} + + +void SDRANGELProcessMessage(struct RIGPORTINFO * PORT) +{ + // Called from Background thread + + int InputLen = recv(PORT->remoteSock, &PORT->RXBuffer[PORT->RXLen], 8192 - PORT->RXLen, 0); + + if (InputLen == 0 || InputLen == SOCKET_ERROR) + { + if (PORT->remoteSock) + closesocket(PORT->remoteSock); + + PORT->remoteSock = 0; + + PORT->CONNECTED = FALSE; + PORT->hDevice = 0; + return; + } + + PORT->RXLen += InputLen; + ProcessSDRANGELFrame(PORT); +} + + + +// ---- G7TAJ ---- diff --git a/SCSPactor.c b/SCSPactor.c index 14c82c6..eff5512 100644 --- a/SCSPactor.c +++ b/SCSPactor.c @@ -1770,9 +1770,6 @@ VOID SCSPoll(int Port) Buffer[datalen] = 0; - // Buffer has an ax.25 header, which we need to pick out and set as channel 0 Connect address - // before sending the beacon - // If a Dragon with KISS over Hostmade we can just send it if (TNC->DragonKISS) @@ -1817,6 +1814,11 @@ VOID SCSPoll(int Port) return; } + // Not dragon KISS + + // Buffer has an ax.25 header, which we need to pick out and set as channel 0 Connect address + // before sending the beacon + // We also need to set Chan 0 Mycall so digi'ing can work, and put // it back after so incoming calls will work @@ -1824,7 +1826,6 @@ VOID SCSPoll(int Port) // This doesn't seem to work -/* ConvFromAX25(Buffer + 7, ICall); // Origin strlop(ICall, ' '); @@ -1867,7 +1868,7 @@ VOID SCSPoll(int Port) 1, Buffer, // Flag CmdSet as Data 2, TNC->NodeCall); // Flag as Chan 0 Command } -*/ + ReleaseBuffer((UINT *)buffptr); return; } diff --git a/TNCCode.c b/TNCCode.c index 8b73e91..d21deab 100644 --- a/TNCCode.c +++ b/TNCCode.c @@ -188,7 +188,7 @@ VOID SENDBTMSG() if (Buffer) { memcpy(Buffer->DEST, PORT->PORTUNPROTO, 7); - Buffer->DEST[6] |= 0xC0; // Set COmmand bits + Buffer->DEST[6] |= 0xC0; // Set Command bits // Send from BBSCALL unless PORTBCALL defined diff --git a/TNCEmulators.c b/TNCEmulators.c index 966b785..131bbf4 100644 --- a/TNCEmulators.c +++ b/TNCEmulators.c @@ -2223,7 +2223,7 @@ void CheckForDataFromTerminal(struct TNCDATA * TNC) resp = GetDataFromTNC(TNC, rxbuffer, 1000, &Read); if (Read) - { + { if (TNC->Mode == TNC2) { for (n = 0; n < Read; n++) @@ -3368,7 +3368,7 @@ int DEDPROCESSHOSTPACKET(struct StreamInfo * Channel, struct TNCDATA * TNC) TRANSPORTENTRY * L4 = NULL; unsigned char * MONCURSOR=0; int SaveAuthProg = 0; - + unsigned char * mcmdptr = &TNC->DEDTXBUFFER[1]; TXBUFFERPTR = &TNC->DEDTXBUFFER[0]; if (Channel->Chan_TXQ == (UCHAR *)(ptrdiff_t) -1) @@ -3522,10 +3522,8 @@ NOTDATA: Work = 0x31; else Work = 0x30; - } - PUTCHARx(TNC, '0'); PUTCHARx(TNC, ' '); PUTCHARx(TNC, Work); @@ -3546,7 +3544,12 @@ NOTDATA: // Support BPQ Extensions IUSC followed by optional port list - if (TNC->DEDTXBUFFER[1] == 'N') + TNC->DEDTXBUFFER[TNC->MSGLENGTH] = 0; + + if (*mcmdptr == ' ') + mcmdptr++; + + if (mcmdptr[0] == 'N') TNC->TRACEFLAG = 0; else { @@ -3555,12 +3558,11 @@ NOTDATA: uint64_t mask = 0; - TNC->DEDTXBUFFER[TNC->MSGLENGTH] = 0; - ptr = strlop(TNC->DEDTXBUFFER, ' '); + ptr = strlop(mcmdptr, ' '); - _strupr(TNC->DEDTXBUFFER); + _strupr(mcmdptr); - if (strchr(TNC->DEDTXBUFFER, 'U')) + if (strchr(mcmdptr, 'U')) TNC->MUIONLY = 1; @@ -3574,8 +3576,9 @@ NOTDATA: if (port) { mask |= ((uint64_t)1 << (port - 1)); - ptr = ptr2; } + ptr = ptr2; + } if (mask) diff --git a/TelnetV6.c b/TelnetV6.c index cbf8c4f..ad4c70b 100644 --- a/TelnetV6.c +++ b/TelnetV6.c @@ -780,6 +780,8 @@ scanCTEXT: } TCP->NumberofUsers += 1; } + else if (_memicmp(errbuf, "WL2KREPORT", 10) == 0) + TNC->WL2K = DecodeWL2KReportLine(errbuf); else if (_stricmp(param,"WebTermCSS") == 0) { TCP->WebTermCSS = _strdup(value); @@ -2492,7 +2494,7 @@ nosocks: { Port = atoi(P2); - if (Port > 33 || TCP->CMDPort[Port] == 0) + if (Port > MaxBPQPortNo || TCP->CMDPort[Port] == 0) { buffptr->Len = sprintf(&buffptr->Data[0], "Error - Invalid HOST Port\r"); C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr); diff --git a/UIRoutines.c b/UIRoutines.c index 014fe01..923725b 100644 --- a/UIRoutines.c +++ b/UIRoutines.c @@ -153,7 +153,7 @@ VOID QueueRaw(int Port, PMESSAGEX AXMSG, int Len) AXMSG->LENGTH = Len; AXMSG->CHAIN = 0; // Clear chain in new buffer - memcpy(AXCopy, AXMSG, Len + 10); + memcpy(AXCopy, AXMSG, Len + 11); GetSemaphore(&DGSemaphore, 0); diff --git a/Versions.h b/Versions.h index e82c30e..db6f372 100644 --- a/Versions.h +++ b/Versions.h @@ -10,14 +10,14 @@ #endif -#define KVers 6,0,24,2 -#define KVerstring "6.0.24.2\0" +#define KVers 6,0,24,15 +#define KVerstring "6.0.24.15\0" #ifdef CKernel #define Vers KVers #define Verstring KVerstring -#define Datestring "August 2023" +#define Datestring "October 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 b5d0e6b..981a60d 100644 --- a/WebMail.c +++ b/WebMail.c @@ -44,7 +44,7 @@ BOOL OkToKillMessage(BOOL SYSOP, char * Call, struct MsgInfo * Msg); int DisplayWebForm(struct HTTPConnectionInfo * Session, struct MsgInfo * Msg, char * FileName, char * XML, char * Reply, char * RawMessage, int RawLen); struct HTTPConnectionInfo * AllocateWebMailSession(); VOID SaveNewMessage(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Rest, int InputLen); -void ConvertTitletoUTF8(char * Title, char * UTF8Title); +void ConvertTitletoUTF8(WebMailInfo * WebMail, char * Title, char * UTF8Title, int Len); char *stristr (char *ch1, char *ch2); char * ReadTemplate(char * FormSet, char * DirName, char * FileName); VOID DoStandardTemplateSubsitutions(struct HTTPConnectionInfo * Session, char * txtFile); @@ -906,7 +906,7 @@ int SendWebMailHeaderEx(char * Reply, char * Key, struct HTTPConnectionInfo * Se if (Msg && CheckUserMsg(Msg, User->Call, User->flags & F_SYSOP)) { - char UTF8Title[128]; + char UTF8Title[4096]; char * EncodedTitle; // List if it is the right type and in the page range we want @@ -934,7 +934,8 @@ int SendWebMailHeaderEx(char * Reply, char * Key, struct HTTPConnectionInfo * Se EncodedTitle = doXMLTransparency(Msg->title); - ConvertTitletoUTF8(EncodedTitle, UTF8Title); + memset(UTF8Title, 0, 4096); // In case convert fails part way through + ConvertTitletoUTF8(Session->WebMail, EncodedTitle, UTF8Title, 4095); free(EncodedTitle); @@ -971,7 +972,7 @@ int ViewWebMailMessage(struct HTTPConnectionInfo * Session, char * Reply, int Nu int msgLen; char FullTo[100]; - char UTF8Title[128]; + char UTF8Title[4096]; int Index; char * crcrptr; char DownLoad[256] = ""; @@ -1009,7 +1010,8 @@ int ViewWebMailMessage(struct HTTPConnectionInfo * Session, char * Reply, int Nu // make sure title is UTF 8 encoded - ConvertTitletoUTF8(Msg->title, UTF8Title); + memset(UTF8Title, 0, 4096); // In case convert fails part way through + ConvertTitletoUTF8(Session->WebMail, Msg->title, UTF8Title, 4095); // if a B2 message diplay B2 Header instead of a locally generated one @@ -1246,17 +1248,28 @@ int ViewWebMailMessage(struct HTTPConnectionInfo * Session, char * Reply, int Nu msgLen = len - 1; // exclude NULL #else - int left = 2 * msgLen; - int len = msgLen; + size_t left = 2 * msgLen; + size_t len = msgLen; + int ret; UCHAR * BufferBP = BufferB; - iconv_t * icu = NULL; + char * orig = MsgBytes; + MsgBytes[msgLen] = 0; + iconv_t * icu = Session->WebMail->iconv_toUTF8; + if (icu == NULL) - icu = iconv_open("UTF-8", "CP1252"); - - iconv(icu, NULL, NULL, NULL, NULL); // Reset State Machine - iconv(icu, &MsgBytes, &len, (char ** __restrict__)&BufferBP, &left); + icu = Session->WebMail->iconv_toUTF8 = iconv_open("UTF-8//IGNORE", "CP1252"); + if (icu == (iconv_t) -1) + { + Session->WebMail->iconv_toUTF8 = NULL; + strcpy(BufferB, MsgBytes); + } + else + { + iconv(icu, NULL, NULL, NULL, NULL); // Reset State Machine + ret = iconv(icu, &MsgBytes, &len, (char ** __restrict__)&BufferBP, &left); + } free(Save); Save = MsgBytes = BufferB; msgLen = strlen(MsgBytes); @@ -1407,6 +1420,11 @@ void FreeWebMailFields(WebMailInfo * WebMail) SaveReply = WebMail->Reply; SaveRlen = WebMail->RLen; +#ifndef WIN32 + if (WebMail->iconv_toUTF8) + iconv_close(WebMail->iconv_toUTF8); +#endif + memset(WebMail, 0, sizeof(WebMailInfo)); WebMail->Reply = SaveReply; @@ -6098,7 +6116,7 @@ int ProcessWebmailWebSock(char * MsgPtr, char * OutBuffer) if (Msg && CheckUserMsg(Msg, User->Call, User->flags & F_SYSOP)) { - char UTF8Title[128]; + char UTF8Title[4096]; char * EncodedTitle; // List if it is the right type and in the page range we want @@ -6126,10 +6144,11 @@ int ProcessWebmailWebSock(char * MsgPtr, char * OutBuffer) EncodedTitle = doXMLTransparency(Msg->title); - ConvertTitletoUTF8(EncodedTitle, UTF8Title); + memset(UTF8Title, 0, 4096); // In case convert fails part way through + ConvertTitletoUTF8(Session->WebMail, EncodedTitle, UTF8Title, 4095); free(EncodedTitle); - + ptr += sprintf(ptr, "%6d %s %c%c %5d %-8s%-8s%-8s%s\r\n", Key, Msg->number, Msg->number, FormatDateAndTime((time_t)Msg->datecreated, TRUE), Msg->type, diff --git a/asmstrucs.h b/asmstrucs.h index 29dcb64..60f5853 100644 --- a/asmstrucs.h +++ b/asmstrucs.h @@ -689,6 +689,7 @@ typedef struct PORTCONTROL time_t LastSmartIDTime; // For SmartID - ID only if packets sent recently time_t SmartIDNeeded; // Time to send next smart ID time_t SmartIDInterval; // Smart ID Interval (Secs) + int SendtoM0LTEMap; } PORTCONTROLX, *PPORTCONTROL; @@ -890,6 +891,9 @@ typedef struct _LINKTABLE UCHAR SESSACTIVE; // SET WHEN WE ARE SURE SESSION IS UP + UINT APPLMASK; // Used when XIR processed + VOID * ALIASPTR; + USHORT KILLTIMER; // TIME TO KILL IDLE LINK VOID * CIRCUITPOINTER; // POINTER TO L4 CIRCUIT TABLE ENTRY diff --git a/bpqchat.c b/bpqchat.c index 3e0444a..06fb369 100644 --- a/bpqchat.c +++ b/bpqchat.c @@ -70,6 +70,9 @@ // Allow /History to be shortened to /Hi (45) // Fix extra r charater in Chat Config Web Page + +// Increase sise of status display buffers (7) + #include "BPQChat.h" #include "Dbghelp.h" diff --git a/bpqmail.h b/bpqmail.h index d910932..9081e19 100644 --- a/bpqmail.h +++ b/bpqmail.h @@ -22,6 +22,10 @@ #define LIBCONFIG_STATIC #include +#ifndef WIN32 +#include +#endif + #include "compatbits.h" #ifndef LINBPQ @@ -941,6 +945,23 @@ typedef struct SocketConnectionInfo } SocketConn; +// FBB reject.sys like filters + +typedef struct FBBFILTER +{ + struct FBBFILTER * Next; + char Action; + char Type; + char From[10]; + char AT[10]; + char TO[10]; + char BID[16]; + int MaxLen; + +} FBBFilter; + +extern FBBFilter * Filters; + typedef struct KEYVALUES { char * Key; @@ -994,6 +1015,11 @@ typedef struct WEBMAILINFO BOOL Packet; int CurrentMessageIndex; // Index of message currently displayed (for Prev and Next) +#ifdef WIN32 + void * iconv_toUTF8; // Used on Linux for char set conversion +#else + iconv_t * iconv_toUTF8; // Used on Linux for char set conversion +#endif }WebMailInfo; @@ -1210,8 +1236,8 @@ BOOL ConnecttoBBS (struct UserInfo * user); BOOL SetupNewBBS(struct UserInfo * user); VOID CreateRegBackup(); VOID SaveFilters(HWND hDlg); -BOOL CheckRejFilters(char * From, char * To, char * ATBBS, char * BID, char Type); -BOOL CheckHoldFilters(char * From, char * To, char * ATBBS, char * BID); +BOOL CheckRejFilters(char * From, char * To, char * ATBBS, char * BID, char Type, int Len); +BOOL CheckHoldFilters(struct MsgInfo * Msg, char * From, char * To, char * ATBBS, char * BID); BOOL CheckifLocalRMSUser(char * FullTo); VOID DoWPLookup(ConnectionInfo * conn, struct UserInfo * user, char Type, char *Context); BOOL wildcardcompare(char * Target, char * Match); diff --git a/bpqmail.h.bak b/bpqmail.h.bak deleted file mode 100644 index eb7323a..0000000 --- a/bpqmail.h.bak +++ /dev/null @@ -1,1604 +0,0 @@ -#ifndef WINVER // Allow use of features specific to Windows XP or later. -#define WINVER 0x0501 // Change this to the appropriate value to target other versions of Windows. -#endif - -#ifndef _WIN32_WINNT // Allow use of features specific to Windows XP or later. -#define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows. -#endif - -#ifndef _WIN32_WINDOWS // Allow use of features specific to Windows 98 or later. -#define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later. -#endif - -#ifndef _WIN32_IE // Allow use of features specific to IE 6.0 or later. -#define _WIN32_IE 0x0600 // Change this to the appropriate value to target other versions of IE. -#endif - - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define _CRT_SECURE_NO_DEPRECATE -#define _WINSOCK_DEPRECATED_NO_WARNINGS - -#define LIBCONFIG_STATIC -#include - -#include "compatbits.h" - -#ifndef LINBPQ -#include "bpq32.h" -#include "BPQMailrc.h" -#include "dbghelp.h" -#else -#include "CHeaders.h" -#endif - -#include "asmstrucs.h" - - -#define NEWROUTING - - - -// Standard __except handler for try/except - -VOID CheckProgramErrors(); -VOID WriteMiniDump(); - -extern int ProgramErrors; - -extern struct _EXCEPTION_POINTERS exinfox; - -#ifdef WIN32 -Dump_Process_State(struct _EXCEPTION_POINTERS * exinfo, char * Msg); - -#define My__except_Routine(Message) \ -__except(memcpy(&exinfo, GetExceptionInformation(), sizeof(struct _EXCEPTION_POINTERS)), EXCEPTION_EXECUTE_HANDLER)\ -{\ - Debugprintf("MAILCHAT *** Program Error %x at %x in %s EAX %x EBX %x ECX %x EDX %x ESI %x EDI %x",\ - exinfo.ExceptionRecord->ExceptionCode, exinfo.ExceptionRecord->ExceptionAddress, Message,\ - exinfo.ContextRecord->Eax, exinfo.ContextRecord->Ebx, exinfo.ContextRecord->Ecx,\ - exinfo.ContextRecord->Edx, exinfo.ContextRecord->Esi, exinfo.ContextRecord->Edi);\ - CheckProgramErrors();\ - WriteMiniDump();\ -} - - -/* -#define My__except_Routine(Message) \ -__except(memcpy(&exinfox, GetExceptionInformation(), sizeof(struct _EXCEPTION_POINTERS)), EXCEPTION_EXECUTE_HANDLER)\ -{\ - Dump_Process_State(&exinfox, Message);\ - CheckProgramErrors();\ -} - -#define My__except_RoutineWithDisconnect(Message) \ -__except(memcpy(&exinfo, GetExceptionInformation(), sizeof(struct _EXCEPTION_POINTERS)), EXCEPTION_EXECUTE_HANDLER)\ -{\ - Debugprintf("MAILCHAT *** Program Error %x at %x in %s EAX %x EBX %x ECX %x EDX %x ESI %x EDI %x",\ - exinfo.ExceptionRecord->ExceptionCode, exinfo.ExceptionRecord->ExceptionAddress, Message,\ - exinfo.ContextRecord->Eax, exinfo.ContextRecord->Ebx, exinfo.ContextRecord->Ecx,\ - exinfo.ContextRecord->Edx, exinfo.ContextRecord->Esi, exinfo.ContextRecord->Edi);\ - FreeSemaphore(&ChatSemaphore);\ - if (conn->BPQStream < 0)\ - CloseConsole(conn->BPQStream);\ - else\ - Disconnect(conn->BPQStream);\ -} -*/ -#define My_except_RoutineWithDiscBBS(Message) \ -__except(memcpy(&exinfo, GetExceptionInformation(), sizeof(struct _EXCEPTION_POINTERS)), EXCEPTION_EXECUTE_HANDLER)\ -{\ - Debugprintf("MAILCHAT *** Program Error %x at %x in %s EAX %x EBX %x ECX %x EDX %x ESI %x EDI %x",\ - exinfo.ExceptionRecord->ExceptionCode, exinfo.ExceptionRecord->ExceptionAddress, Message,\ - exinfo.ContextRecord->Eax, exinfo.ContextRecord->Ebx, exinfo.ContextRecord->Ecx,\ - exinfo.ContextRecord->Edx, exinfo.ContextRecord->Esi, exinfo.ContextRecord->Edi);\ - if (conn->BPQStream < 0)\ - CloseConsole(conn->BPQStream);\ - else\ - Disconnect(conn->BPQStream);\ - CheckProgramErrors();\ -} -#endif -#define MAXUSERNAMELEN 6 - -#define WSA_ACCEPT WM_USER + 1 -#define WSA_CONNECT WM_USER + 2 -#define WSA_DATA WM_USER + 3 -#define NNTP_ACCEPT WM_USER + 4 -#define NNTP_DATA WM_USER + 5 - -#ifdef _DEBUG - -VOID * _malloc_dbg_trace(int len, int type, char * file, int line); - -#define malloc(s) _malloc_dbg(s, _NORMAL_BLOCK, __FILE__, __LINE__) -#define calloc(c, s) _calloc_dbg(c, s, _NORMAL_BLOCK, __FILE__, __LINE__) -#define realloc(p, s) _realloc_dbg(p, s, _NORMAL_BLOCK, __FILE__, __LINE__) -#define _recalloc(p, c, s) _recalloc_dbg(p, c, s, _NORMAL_BLOCK, __FILE__, __LINE__) -#define _expand(p, s) _expand_dbg(p, s, _NORMAL_BLOCK, __FILE__, __LINE__) -#define free(p) _free_dbg(p, _NORMAL_BLOCK) -#define _strdup(s) _strdup_dbg(s, _NORMAL_BLOCK, __FILE__, __LINE__) - - -#define zalloc(s) _zalloc_dbg(s, _NORMAL_BLOCK, __FILE__, __LINE__) -#else -#define zalloc(s) _zalloc(s) -#endif - -#ifdef LINBPQ - -#undef zalloc -#define zalloc _zalloc - -#endif - -VOID * _zalloc_dbg(size_t len, int type, char * file, int line); - -#define LOG_BBS 0 -#define LOG_CHAT 1 -#define LOG_TCP 2 -#define LOG_DEBUG_X 3 - - -//Chat Duplicate suppression Code - -#define MAXDUPS 10 // Number to keep -#define DUPSECONDS 5 // TIme to Keep - -struct DUPINFO -{ - time_t DupTime; - char DupUser[10]; - char DupText[100]; -}; - - -struct UserRec -{ - char * Callsign; - char * UserName; - char * Password; -}; - - - -typedef struct ConnectionInfo_S -{ - struct ConnectionInfo_S *next; - PROC *proc; - UCHAR RadioOnlyMode; // T or R flag for Radio Only mode. - - int Number; // Number of record - for Connections display - BOOL Active; - int BPQStream; - int paclen; - UCHAR Callsign[11]; // Station call including SSID - BOOL GotHeader; - UCHAR InputMode; // Line by Line or Binary or YAPP - - UCHAR * InputBuffer; - int InputBufferLen; - int InputLen; // Data we have already = Offset of end of an incomplete packet; - - struct UserInfo * UserPointer; - int Retries; - int LoginState; // 1 = user ok, 2 = password ok - int Flags; - - // Data to the user is kept in a malloc'd buffer. This can be appended to, - // and data sucked out under both terminal and system flow control. PACLEN is - // enfored when sending to node. - - UCHAR * OutputQueue; // Messages to user - int OutputQueueLength; // Total Malloc'ed size. Also Put Pointer for next Message - int OutputGetPointer; // Next byte to send. When Getpointer = Queue Length all is sent - free the buffer and start again. - - int CloseAfterFlush; // Close session when all sent. Set to 100ms intervals to wait. - - int ErrorCount; // Invalid Command count - BOOL Paging; // Set if user wants paging - int LinesSent; // Count when paging - int PageLen; // Lines per page - - UCHAR * MailBuffer; // Mail Message being received - UCHAR * CopyBuffer; // Mail Message being forwarded - int MailBufferSize; // Total Malloc'ed size. Actual size in in Msg Struct - - long lastmsg; // Last Listed. Stored here, updated in user record only on clean close - BOOL sysop; // Set if user is authenticated as a sysop - BOOL Secure_Session; // Set if Local Terminal, or Telnet connect with SYSOP status - UINT BBSFlags; // Set if defined as a bbs and SID received - struct MsgInfo * TempMsg; // Header while message is being received - struct MsgInfo * FwdMsg; // Header while message is being forwarded - - char ** To; // May be several Recipients - int ToCount; - - int BBSNumber; // The BBS number (offset into bitlist of BBSes to forward a message to - int NextMessagetoForward; // Next index to check in forward cycle - BOOL BPQBBS; // Set if SID indicates other end is BPQ - char MSGTYPES[20]; // Any MSGTYPEFLAGS - BOOL SendT; // Send T messages - BOOL SendP; // Send P messages - BOOL SendB; // Send Bulls - BOOL SendWL2KFW; // send ;FW: - int MaxBLen; // Max Size for this session - int MaxPLen; // Max Size for this session - int MaxTLen; // Max Size for this session - BOOL DoReverse; // Request Reverse Forward - char LastForwardType; // Last type of messages forwarded - struct FBBHeaderLine * FBBHeaders; // The Headers from an FFB forward block - char FBBReplyChars[36]; //The +-=!nnnn chars for the 5 proposals - int FBBReplyIndex; // current Reply Pointer - int FBBIndex; // current propopsal number - int RestartFrom; // Restart position - BOOL NeedRestartHeader; // Set if waiting for 6 byte restart header - BOOL DontSaveRestartData; // Set if corrupt data received - BOOL FBBMsgsSent; // Messages need to be maked as complete when next command received - UCHAR FBBChecksum; // Header Checksum - BOOL OpenBCM; // OpenBCM mode (escape -xFF chars) - BOOL InTelnetExcape; // Last Char was 0xff - BOOL LocalMsg; // Set if current Send command is for a local user - BOOL NewUser; // Set if first time user has accessed BBS - BOOL Paclink; // Set if receiving messages from Paclink - BOOL RMSExpress; // Set if receiving messages from RMS Express - BOOL WL2K; // Set if communicating with a CMS - BOOL PAT; // Set if communicating with PAT - char ** PacLinkCalls; // Calls we are getting messages for - BOOL SkipPrompt; // Set if a remote node sends a > at the end of his CTEXT - BOOL SkipConn; // Node sends "connected" in its CTEXT - int Watchdog; // Hung Circuit Detect. - int SessType; // BPQ32 sesstype bits - -#define Sess_L2LINK 1 -#define Sess_SESSION 2 -#define Sess_UPLINK 4 -#define Sess_DOWNLINK 8 -#define Sess_BPQHOST 0x20 -#define Sess_PACTOR 0x40 - - HANDLE DebugHandle; // File Handle for session-based debugging - - char ARQFilename[256]; // Filename from ARQ:FILE:: Header - int ARQClearCount; // To make sure queues are flushed when sending - - int SIDResponseTimer; // Used to detect incomplete handshake - - char PQChallenge[20]; // Secure User logon challange - char SecureMsg[20]; // CMS Secure Signon Response - int MCastListenTime; // Time to run session for - - int YAPPLen; // Bytes sent/received of YAPP Message - long YAPPDate; // Date for received file - if set enables YAPPC - - int SyncCompressedLen; - int SyncXMLLen; - int SyncMsgLen; - char * SyncHost; // Saved so can send "request sync" - int SyncPort; - UCHAR * SyncMessage; // Compressed SYNC message to send - - // These are used to detect CRLF split over a packet boundary - int usingCR; // Session is (normally) using CR as terminator - int lastLineEnd; // Terminator for current line - - struct ConnectionInfo_S * SysopChatStream; // Stream sysop is chatting to - -} ConnectionInfo, CIRCUIT; - -// Flags Equates - -#define GETTINGUSER 1 -#define GETTINGBBS 2 -#define CHATMODE 4 -#define GETTINGTITLE 8 -#define GETTINGMESSAGE 16 -#define CHATLINK 32 // Link to another Chat Node -#define SENDTITLE 64 -#define SENDBODY 128 -#define WAITPROMPT 256 // Waiting for prompt after message -#define PROPOSINGSYNCMSG 512 // Sent proposal to SYNC, waiting response -#define SENDINGSYNCMSG 1024 // Sent message to SYNC, waiting response -#define REQUESTINGSYNC 2048 -#define GETTINGSYNCMESSAGE 4096 // Receiving body of a SYNC message - -// BBSFlags Equates - -#define BBS 1 -#define FBBForwarding 2 -#define FBBCompressed 4 -#define FBBB1Mode 8 -#define FBBB2Mode 16 -#define RunningConnectScript 32 -#define MBLFORWARDING 64 // MBL Style Frwarding- waiting for OK/NO or Prompt following message -#define TEXTFORWARDING 128 // Plain Text forwarding -#define OUTWARDCONNECT 256 // We connected to them -#define FLARQMODE 512 // Message from FLARQ -#define FLARQMAIL 1024 // Sending FLARQ Format Message -#define ARQMAILACK 2048 // Waiting for all data to be acked -#define NEEDLF 4096 // Add LF to forward script commands (fro Telnet -#define MCASTRX 8192 // Stream in Multicast RX Mode -#define DISCONNECTING 16384 // Disconnect sent to Node -#define YAPPTX 0x008000 // Sending YAPP file -#define SYSOPCHAT 0x010000 // Chatting to BBS console -#define WINLINKRO 0x020000 // WL2K RO (no J in SID) -#define SYNCMODE 0x040000 // RMS RELAY SYNC -#define MFJMODE 0x080000 // MFJ PMS -#define NEWPACCOM 0x100000 // PACCOM PMS 3.2 -#define SETCALLTOSENDER 0x200000 // Set calling call to message sender - - -struct FBBRestartData -{ - struct MsgInfo * TempMsg; // Header while message is being received - struct UserInfo * UserPointer; - UCHAR * MailBuffer; // Mail Message being received - int MailBufferSize; // Total Malloc'ed size. Actual size in in Msg Struct - int Count; // Give up if too many restarts -}; - -// We need to keep the B2Message file for B2 messages we are sending until the messages is acked, so -// we can restart it. Otherwise the file may change, resulting in a checksum error - - -struct B2RestartData -{ - int CSize; // Compresses Size (B2 proto) - UCHAR * CompressedMsg; // Compressed Body fo B2 - struct MsgInfo * FwdMsg; - struct UserInfo * UserPointer; - int Count; // Give up if too many restarts -}; - -#pragma pack(1) - -struct TempUserInfo -{ - int LastAuthCode; // Protect against playback attack - - // Fields used to allow interrupting and resuming a paged listing - - BOOL ListActive; // Doing a list - BOOL ListSuspended; // Paused doing a list - int LastListedInPagedMode; - char LastListCommand[80]; - char LastListParams[80]; - int LinesSent; - char SendFullFrom; - char ListType; - char ListDirn; - char ListStatus; - char ListSelector; // < > @ etc - - int ListRangeStart; - int ListRangeEnd; - int LLCount; // Number still to send in List Last N - int UpdateLatest; // if set, save last listed as latest - BOOL IncludeKilled; // Show Killed Messages if SYSOP - -}; - -#define PMSG 1 -#define BMSG 2 -#define TMSG 3 - -struct OldUserInfo -{ - // Old format - without message type specific traffic counts - - char Call[10]; // Connected call without SSID -// indicat relai[8]; /* 64 Digis path */ - int lastmsg; /* 4 Last L number */ - int ConnectsIn; /* 4 Number of connexions in*/ - int TimeLastConnected; //Last connexion date */ -// long lastyap __a2__ ; /* 4 Last YN date */ - ULONG flags ; /* 4 Flags */ - - UCHAR PageLen; // Lines Per Page - UCHAR lang ; /* 1 Language */ - - int Xnewbanner; /* 4 Last Banner date */ - short Xdownload ; /* 2 download size (KB) = 100 */ - char POP3Locked ; // Nonzero if POP3 server has locked this user (stops other pop3 connections, or BBS user killing messages) - char BBSNumber; // BBS Bitmap Index Number - struct BBSForwardingInfo * ForwardingInfo; - struct UserInfo * BBSNext; // links BBS record - struct TempUserInfo * Temp; // Working Fields - not saved in user file - char xfree[6]; /* 6 Spare */ - char Xtheme; /* 1 Current topic */ - - char Name[18]; /* 18 1st Name */ - char Address[61]; /* 61 Address */ - - // Stats. Was City[31]; /* 31 City */ - - int MsgsReceived; - int MsgsSent; - int MsgsRejectedIn; // Messages we reject - int MsgsRejectedOut; // Messages Rejectd by other end - int BytesForwardedIn; - int BytesForwardedOut; - int ConnectsOut; // Forwarding Connects Out - - USHORT RMSSSIDBits; // SSID's to poll in RMS - - char Spare1; - - char HomeBBS[41]; /* 41 home BBS */ - char QRA[7]; /* 7 Qth Locator */ - char pass[13]; /* 13 Password */ - char ZIP[9]; /* 9 Zipcode */ - BOOL spare; -} ; /* Total : 360 bytes */ - -struct MsgStats -{ - int ConnectsIn; /* 4 Number of connexions in*/ - int ConnectsOut; // Forwarding Connects Out - - // Stats saveed by message type - - int MsgsReceived[4]; - int MsgsSent[4]; - int MsgsRejectedIn[4]; // Messages we reject - int MsgsRejectedOut[4]; // Messages Rejectd by other end - int BytesForwardedIn[4]; - int BytesForwardedOut[4]; -}; - -struct UserInfo -{ - // New Format - with stats maintained by message type and unused fields removed. - - char Call[10]; // Connected call without SSID - - int Length; // To make subsequent format changes easier - - int lastmsg; /* 4 Last L number */ - int xTimeLastConnected; //Last connexion date */ - ULONG flags ; /* 4 Flags */ - - UCHAR PageLen; // Lines Per Page - - char POP3Locked ; // Nonzero if POP3 server has locked this user (stops other pop3 connections, or BBS user killing messages) - unsigned char BBSNumber; // BBS Bitmap Index Number - struct BBSForwardingInfo * ForwardingInfo; - struct UserInfo * BBSNext; // links BBS record - struct TempUserInfo * Temp; // Working Fields - not saved in user file - char Name[18]; /* 18 1st Name */ - char Address[61]; /* 61 Address */ - - USHORT RMSSSIDBits; // SSID's to poll in RMS - - char HomeBBS[41]; /* 41 home BBS */ - char QRA[7]; /* 7 Qth Locator */ - char pass[13]; /* 13 Password */ - char ZIP[9]; /* 9 Zipcode */ - - struct MsgStats Total; - struct MsgStats Last; - - char CMSPass[16]; // For Secure Signon - int WebSeqNo; - - long long TimeLastConnected; //Last connection date */ - - char Filler[44 - 8]; // So we can add a few fields wirhout another resize -}; - -// flags equates - -#define F_Excluded 0x0001 -#define F_GGG 0x0002 -#define F_Expert 0x0004 -#define F_SYSOP 0x0008 -#define F_BBS 0x0010 -#define F_RMSREDIRECT 0x0020 -#define F_BBB 0x0040 -#define F_CCC 0x0080 -#define F_DDD 0x0100 -#define F_EEE 0x0200 -#define F_FFF 0x0400 -#define F_PMS 0x0800 -#define F_EMAIL 0x1000 -#define F_HOLDMAIL 0x2000 -#define F_POLLRMS 0x4000 -#define F_SYSOP_IN_LM 0x8000 -#define F_Temp_B2_BBS 0x00010000 // "Winlink Express User" -#define F_NOWINLINK 0x00020000 // Don't add Winlink.org -#define F_NOBULLS 0x00040000 -#define F_NTSMPS 0x00080000 -#define F_APRSMFOR 0x00100000 // Send APRS message for new mail -#define F_APRSSSID 0xF0000000 // (Top 4 Bits - - -struct Override -{ - char * Call; - int Days; -}; - -struct ALIAS -{ - char * Alias; - char * Dest; -}; - -typedef struct _MESSAGEX -{ -// BASIC LINK LEVEL MESSAGE BUFFER LAYOUT - - struct _MESSAGEX * CHAIN; - - UCHAR PORT; - USHORT LENGTH; - - UCHAR DEST[7]; - UCHAR ORIGIN[7]; - -// MAY BE UP TO 56 BYTES OF DIGIS - - UCHAR CTL; - UCHAR PID; - UCHAR DATA[256]; - UCHAR DIGIS[56]; // Padding in case we have digis - -}MESSAGEX, *PMESSAGEX; - - -#pragma pack() - -// Message Database Entry. Designed to be compatible with FBB - -#define NBBBS 160 // Max BBSes we can forward to. Must be Multiple of 8, and must be 80 for FBB compatibliliy -#define NBMASK NBBBS/8 // Number of bytes in Forward bitlists. - -#pragma pack(1) - -struct OldMsgInfo -{ - char type ; - char status ; - int number ; - int length ; - int datereceived; - char bbsfrom[7] ; // ? BBS we got it from ? - char via[41] ; - char from[7] ; - char to[7] ; - char bid[13] ; - char title[61] ; - char bin; - int nntpnum; // Number within topic (ie Bull TO Addr) - used for nntp - - UCHAR B2Flags; - - char free[4]; - unsigned short nblu; - int theme ; - time_t datecreated ; - time_t datechanged ; - char fbbs[10] ; - char forw[10] ; - char emailfrom[41]; -} ; - - -struct MsgInfo -{ - char type; - char status; - int number; - int length; - int xdatereceived; - char bbsfrom[7]; // ? BBS we got it from ? - char via[41]; - char from[7]; - char to[7]; - char bid[13]; - char title[61]; - int nntpnum; // Number within topic (ie Bull TO Addr) - used for nntp - - UCHAR B2Flags; - - #define B2Msg 1 // Set if Message File is a formatted B2 message - #define Attachments 2 // Set if B2 message has attachments - #define FromPaclink 4 - #define FromCMS 8 - #define FromRMSExpress 16 - #define RadioOnlyMsg 32 // Received using call-T - #define RadioOnlyFwd 64 // Received using call-R - - int xdatecreated; - int xdatechanged; - UCHAR fbbs[NBMASK]; - UCHAR forw[NBMASK]; - char emailfrom[41]; - char Locked; // Set if selected for sending (NTS Pickup) - char Defered; // FBB response '=' received - UCHAR UTF8; // Set if Message is in UTF8 (ie from POP/SMTP) - -// For 64 bit time_t compatibility define as long long -// (so struct is same with 32 or 64 bit time_t) - - long long datereceived; - long long datecreated; - long long datechanged; - - char Spare[61 - 24]; // For future use -} ; - -#define MSGTYPE_B 0 -#define MSGTYPE_P 1 - -#define MSGSTATUS_N 0 -#define MSGSTATUS_Y 1 -#define MSGSTATUS_F 2 -#define MSGSTATUS_K 3 -#define MSGSTATUS_H 4 -#define MSGSTATUS_D 5 -#define MSGSTATUS_$ 6 - -struct NNTPRec -{ - // Used for NNTP access to Bulls - - struct NNTPRec * Next; // Record held in chain, so can be held sorted - char NewsGroup[64]; // = Bull TO.at field - int FirstMsg; // Lowest Number - int LastMsg; // Highest Number - int Count; // Active Msgs - time_t DateCreated; // COntains Creation Date of First Bull in Group -}; - - -typedef struct { - char mode; - char BID[13]; - union - { /* array named screen */ - struct - { - unsigned short msgno; - unsigned short timestamp; - }; - CIRCUIT * conn; - } u; -} BIDRec, *BIDRecP; - - -typedef struct WPDBASE{ /* 194 bytes */ - char callsign[7]; - char name[13]; - unsigned char Type; - unsigned char changed; - unsigned short seen; - long long last_modif; - long long last_seen; - char first_homebbs[41]; - char secnd_homebbs[41]; - char first_zip[9]; - char secnd_zip[9]; - char first_qth[31]; - char secnd_qth[31]; -} WPRec, * WPRecP; - -#pragma pack() - -struct FWDBAND -{ - time_t FWDStartBand; - time_t FWDEndBand; -}; - - - -struct BBSForwardingInfo -{ - // Holds info for forwarding - - BOOL Enabled; // Forwarding Enabled - char ** ConnectScript; // Main Connect Script - char ** TempConnectScript; // Used with FWD command. - int ScriptIndex; // Next line in script - BOOL MoreLines; // Set until script is finsihed - - char ** TOCalls; // Calls in to field - char ** ATCalls; // Calls in ATBBS field - char ** HaddressesP; // Heirarchical Addresses for Personals to forward to (as stored) - char *** HADDRSP; // Heirarchical Addresses for Personals to forward to - char ** Haddresses; // Heirarchical Addresses to forward to (as stored) - char *** HADDRS; // Heirarchical Addresses to forward to - int * HADDROffet; // Elements added to complete the HR. At least n+1 must match to forward - char ** FWDTimes; // Time bands to forward - struct FWDBAND ** FWDBands; - int MsgCount; // Messages for this BBS - BOOL ReverseFlag; // Set if BBS wants to poll for reverse forwarding - BOOL Forwarding; // Forward in progress - int MaxFBBBlockSize; - BOOL AllowBlocked; // Allow FBB Blocked - BOOL AllowCompressed; // Allow FBB Compressed - BOOL AllowB1; // Enable B1 - BOOL AllowB2; // Enable B2 - BOOL SendCTRLZ; // Send Ctrl/z instead of /ex - BOOL PersonalOnly; // Only Forward Personals - BOOL SendNew; // Forward new messages immediately - int FwdInterval; - int RevFwdInterval; - int FwdTimer; - time_t LastReverseForward; - char *BBSHA; // HA of BBS - char ** BBSHAElements; // elements of HA of BBS - int ConTimeout; -// char UserCall[10]; // User we are forwarding on behalf of (Currently only for RMS) -// int UserIndex; // index of User we are forwarding on behalf of (Currently only for RMS) -}; - - -struct FBBHeaderLine -{ - // Holds the info from the (up to) 5 headers presented at the start of a Forward Block - - char Format; // Ascii or Binary - char MsgType; // P B etc - char From[7]; // Sender - char ATBBS[41]; // BBS of recipient (@ Field) - char To[7]; // Recipient - char BID[13]; - int Size; - int CSize; // Compresses Size (B2 proto) - BOOL B2Message; // Set if an FC type - UCHAR * CompressedMsg; // Compressed Body fo B2 - struct MsgInfo * FwdMsg; // Header so we can mark as complete -}; - -#define MAXSTACK 20 -//#define MAXLINE 10000 -#define INPUTLEN 512 - -#define MAXLINES 1000 -#define LINELEN 200 - -char RTFHeader[4000]; - -int RTFHddrLen; - -struct ConsoleInfo -{ - struct ConsoleInfo * next; - CIRCUIT * Console; - int BPQStream; - WNDPROC wpOrigInputProc; - HWND hConsole; - HWND hwndInput; - HWND hwndOutput; - HMENU hMenu; // handle of menu - RECT ConsoleRect; - RECT OutputRect; - - int Height, Width, LastY; - - int ClientHeight, ClientWidth; - char kbbuf[INPUTLEN]; - int kbptr; - - char * readbuff; // Malloc'ed - int readbufflen; // Current Length - char * KbdStack[MAXSTACK]; - - int StackIndex; - - BOOL Bells; - BOOL FlashOnBell; // Flash instead of Beep - BOOL StripLF; - - BOOL WarnWrap; - BOOL FlashOnConnect; - BOOL WrapInput; - BOOL CloseWindowOnBye; - - unsigned int WrapLen; - int WarnLen; - int maxlinelen; - - int PartLinePtr; - int PartLineIndex; // Listbox index of (last) incomplete line - - DWORD dwCharX; // average width of characters - DWORD dwCharY; // height of characters - DWORD dwClientX; // width of client area - DWORD dwClientY; // height of client area - DWORD dwLineLen; // line length - int nCaretPosX; // horizontal position of caret - int nCaretPosY; // vertical position of caret - - COLORREF FGColour; // Text Colour - COLORREF BGColour; // Background Colour - COLORREF DefaultColour; // Default Text Colour - - int CurrentLine; // Line we are writing to in circular buffer. - - int Index; - BOOL SendHeader; - BOOL Finished; - - char OutputScreen[MAXLINES][LINELEN]; - - int Colourvalue[MAXLINES]; - int LineLen[MAXLINES]; - - int CurrentColour; - int Thumb; - int FirstTime; - BOOL Scrolled; // Set if scrolled back - int RTFHeight; // Height of RTF control in pixels - -}; - - -struct MSESSION -{ - struct MSESSION * Next; - unsigned int Key; - char * FileName; - char * OrigTimeStamp; - unsigned char * Message; - int MessageLen; - unsigned char * BlockList; - char * ID; - int BlockSize; - int BlockCount; - int BlocksReceived; - BOOL Completed; - time_t Created; - time_t LastUpdated; - int Index; // Line in Display -}; - -VOID __cdecl nprintf(CIRCUIT * conn, const char * format, ...); -char * strlop(char * buf, char delim); -int rt_cmd(CIRCUIT *circuit, char * Buffer); -CIRCUIT *circuit_new(CIRCUIT *circuit, int flags); -VOID BBSputs(CIRCUIT * conn, char * buf); -VOID FBBputs(CIRCUIT * conn, char * buf); -void makelinks(void); -VOID * _zalloc(size_t len); -VOID FreeChatMemory(); -VOID ChatTimer(); -VOID nputs(CIRCUIT * conn, char * buf); -VOID node_close(); -VOID removelinks(); -VOID SetupChat(); -VOID SendChatLinkStatus(); -VOID ClearChatLinkStatus(); -VOID Send_MON_Datagram(UCHAR * Msg, DWORD Len); - -#define Connect(stream) SessionControl(stream,1,0) -#define Disconnect(stream) SessionControl(stream,2,0) -#define ReturntoNode(stream) SessionControl(stream,3,0) -#define ConnectUsingAppl(stream, appl) SessionControl(stream, 0, appl) - -int EncryptPass(char * Pass, char * Encrypt); -VOID DecryptPass(char * Encrypt, unsigned char * Pass, unsigned int len); - -// TCP Connections. FOr the moment SMTP or POP3 - -typedef struct SocketConnectionInfo -{ - struct SocketConnectionInfo * Next; - int Number; // Number of record - for Connections display - SOCKET socket; - SOCKADDR_IN sin; - int Type; // SMTP or POP3 - BOOL AMPR; // Set if sending to an AMPR.ORG server - char FromDomain[50]; // Domain we are sending from - struct UserInfo * bbs; // BBS dor forwarding to AMPR - int State; // Transaction State Machine - UCHAR CallSign[10]; - UCHAR TCPBuffer[3000]; // For converting byte stream to messages - int InputLen; // Data we have alreasdy = Offset of end of an incomplete packet; - - char * MailFrom; // Envelope Sender and Receiver - char ** RecpTo; // May be several Recipients - int Recipients; - - UCHAR * MailBuffer; // Mail Message being received. malloc'ed as needed - int MailBufferSize; // Total Malloc'ed size. Actual size is in MailSize - int MailSize; - int Flags; - - struct UserInfo * POP3User; - struct MsgInfo ** POP3Msgs; // Header List of messages for this uaer - int POP3MsgCount; // No of Messages - int POP3MsgNum; // Sequence number of message being received - - struct MsgInfo * SMTPMsg; // message for this SMTP connection - - UCHAR * SendBuffer; // Message being sent if socket is busy. malloc'ed as needed - int SendBufferSize; // Total Malloc'ed size. Actual size is in MailSize - int SendSize; // Bytes in buffer - int SendPtr; // next byte to send when ready - - struct NNTPRec * NNTPGroup; // Currently Selected Group - int NNTPNum; // Currenrly Selected Msg Number - int Timeout; // Used to close a session that is open too long - -} SocketConn; - -typedef struct KEYVALUES -{ - char * Key; - char * Value; -} KeyValues; - -typedef struct WEBMAILINFO -{ - // Info for HTML Forms Processing - - struct HtmlFormDir * Dir; // HTML Directory - char * txtFileName; // Template Name for current message - char * InputHTMLName; // Template to input message - char * DisplayHTMLName; // Template to display message - char * ReplyHTMLName; // Template for replying to message - char * txtFile; // Template data - char * OrigTo; // To field when template loaded - char * OrigSubject; // Subject field when template loaded - char * OrigBody; // Msg text when template loaded - char * OrigBID; - char OrigType; - char * To; - char * CC; - char * Subject; - char * Body; - char * BID; - char Type; - struct MsgInfo * Msg; // Msg record if replying - KeyValues txtKeys[1000]; // Key/Value pairs for txt template. Used when creating or displaying - KeyValues XMLKeys[1000]; // Key/Value pairs from XML attachment - BOOL isReply; - char * XMLName; - char * XML; // XML attachment - int XMLLen; - int Files; - char * FileName[100]; // Attachments - char * FileBody[100]; - int FileLen[100]; - - char * Header; - int HeaderLen; - - char * Footer; - int FooterLen; - - char * Reply; // put in here to save passing lots of parameters - int * RLen; - - BOOL Winlink; - BOOL P2P; - BOOL Packet; - - int CurrentMessageIndex; // Index of message currently displayed (for Prev and Next) - -}WebMailInfo; - -#define SMTPServer 1 -#define POP3SLAVE 2 -#define SMTPClient 3 -#define POP3Client 4 -#define NNTPServer 5 - -// State Values - -#define GettingUser 1 -#define GettingPass 2 -#define Authenticated 4 - -#define Connecting 8 - -// SMTP Master - -#define WaitingForGreeting 16 -#define WaitingForHELOResponse 32 -#define WaitingForFROMResponse 64 -#define WaitingForTOResponse 128 -#define WaitingForDATAResponse 256 -#define WaitingForBodyResponse 512 -#define WaitingForAUTHResponse 1024 - -// POP3 Master - -#define WaitingForUSERResponse 32 -#define WaitingForPASSResponse 64 -#define WaitingForSTATResponse 128 -#define WaitingForUIDLResponse 256 -#define WaitingForLISTResponse 512 -#define WaitingForRETRResponse 512 -#define WaitingForDELEResponse 1024 -#define WaitingForQUITResponse 2048 - - -#define SE 240 // End of subnegotiation parameters -#define NOP 241 //No operation -//#define DM 242 //Data mark Indicates the position of a Synch event within the data stream. This should always be accompanied by a TCP urgent notification. -#define BRK 243 //Break Indicates that the "break" or "attention" key was hi. -#define IP 244 //Suspend Interrupt or abort the process to which the NVT is connected. -#define AO 245 //Abort output Allows the current process to run to completion but does not send its output to the user. -#define AYT 246 //Are you there Send back to the NVT some visible evidence that the AYT was received. -#define EC 247 //Erase character The receiver should delete the last preceding undeleted character from the data stream. -#define EL 248 //Erase line Delete characters from the data stream back to but not including the previous CRLF. -#define GA 249 //Go ahead Under certain circumstances used to tell the other end that it can transmit. -#define SB 250 //Subnegotiation Subnegotiation of the indicated option follows. -#define WILL 251 //will Indicates the desire to begin performing, or confirmation that you are now performing, the indicated option. -#define WONT 252 //wont Indicates the refusal to perform, or continue performing, the indicated option. -#define DOx 253 //do Indicates the request that the other party perform, or confirmation that you are expecting the other party to perform, the indicated option. -#define DONT 254 //dont Indicates the demand that the other party stop performing, or confirmation that you are no longer expecting the other party to perform, the indicated option. -#define IAC 255 - -#define suppressgoahead 3 //858 -//#define Status 5 //859 -//#define echo 1 //857 -#define timingmark 6 //860 -#define terminaltype 24 //1091 -#define windowsize 31 //1073 -#define terminalspeed 32 //1079 -#define remoteflowcontrol 33 //1372 -#define linemode 34 //1184 -#define environmentvariables 36 //1408 - -BOOL Initialise(); -#ifdef WIN32 -INT_PTR CALLBACK ConfigWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); -#endif -int DisplaySessions(); -int DoStateChange(int Stream); -int DoReceivedData(int Stream); -int DoBBSMonitorData(int Stream); -int Connected(int Stream); -int Disconnected(int Stream); -//int Socket_Accept(int SocketId); -//int Socket_Data(int SocketId,int error, int eventcode); -int DataSocket_Read(SocketConn * sockptr, SOCKET sock); -int DataSocket_Write(SocketConn * sockptr, SOCKET sock); -int DataSocket_Disconnect(SocketConn * sockptr); -int RefreshMainWindow(); -int Terminate(); -int SendtoSocket(SOCKET sock,char * Msg); -int WriteLog(char * msg); -int ConnectState(int Stream); -UCHAR * EncodeCall(UCHAR * Call); -int ParseIniFile(char * fn); -struct UserInfo * AllocateUserRecord(char * Call); -struct MsgInfo * AllocateMsgRecord(); -BIDRec * AllocateBIDRecord(); -BIDRec * AllocateTempBIDRecord(); -struct UserInfo * LookupCall(char * Call); -BIDRec * LookupBID(char * BID); -BIDRec * LookupTempBID(char * BID); -VOID RemoveTempBIDS(CIRCUIT * conn); -VOID SaveUserDatabase(); -VOID GetUserDatabase(); -VOID GetMessageDatabase(); -VOID SaveMessageDatabase(); -VOID GetBIDDatabase(); -VOID SaveBIDDatabase(); -VOID GetWPDatabase(); -VOID CopyWPDatabase(); -VOID SaveWPDatabase(); -VOID GetBadWordFile(); -WPRec * LookupWP(char * Call); -VOID SendWelcomeMsg(int Stream, ConnectionInfo * conn, struct UserInfo * user); -VOID ProcessLine(ConnectionInfo * conn, struct UserInfo * user, char* Buffer, int len); -VOID ProcessChatLine(ConnectionInfo * conn, struct UserInfo * user, char* Buffer, int len); -VOID SendPrompt(ConnectionInfo * conn, struct UserInfo * user); -int QueueMsg( ConnectionInfo * conn, char * msg, int len); -VOID SendUnbuffered(int stream, char * msg, int len); -//int GetFileList(char * Dir); -BOOL ListMessage(struct MsgInfo * Msg, ConnectionInfo * conn, struct TempUserInfo * Temp); -void DoDeliveredCommand(CIRCUIT * conn, struct UserInfo * user, char * Cmd, char * Arg1, char * Context); -void DoKillCommand(ConnectionInfo * conn, struct UserInfo * user, char * Cmd, char * Arg1, char * Context); -void DoListCommand(ConnectionInfo * conn, struct UserInfo * user, char * Cmd, char * Arg1, BOOL Resuming, char * Context); -void DoReadCommand(ConnectionInfo * conn, struct UserInfo * user, char * Cmd, char * Arg1, char * Context); -void KillMessage(ConnectionInfo * conn, struct UserInfo * user, int msgno); -int KillMessagesTo(ConnectionInfo * conn, struct UserInfo * user, char * Call); -int KillMessagesFrom(ConnectionInfo * conn, struct UserInfo * user, char * Call); -void DoUnholdCommand(CIRCUIT * conn, struct UserInfo * user, char * Cmd, char * Arg1, char * Context); - -VOID FlagAsKilled(struct MsgInfo * Msg, BOOL SaveDB); -int ListMessagesFrom(ConnectionInfo * conn, struct UserInfo * user, char * Call, BOOL SendFullFrom, int Start); -int ListMessagesTo(ConnectionInfo * conn, struct UserInfo * user, char * Call, BOOL SendFullFrom, int Start); -int ListMessagesAT(ConnectionInfo * conn, struct UserInfo * user, char * Call, BOOL SendFullFrom, int Start); -void ListMessagesInRange(ConnectionInfo * conn, struct UserInfo * user, char * Call, int Start, int End, BOOL SendFullFrom ); -void ListMessagesInRangeForwards(ConnectionInfo * conn, struct UserInfo * user, char * Call, int Start, int End, BOOL SendFullFrom ); -int GetUserMsg(int m, char * Call, BOOL SYSOP); -void Flush(ConnectionInfo * conn); -VOID ClearQueue(ConnectionInfo * conn); -void TrytoSend(); -void ReadMessage(ConnectionInfo * conn, struct UserInfo * user, int msgno); -struct MsgInfo * FindMessage(char * Call, int msgno, BOOL sysop); -char * ReadMessageFile(int msgno); -char * ReadInfoFile(char * File); -char * FormatDateAndTime(time_t Datim, BOOL DateOnly); -int CriticalErrorHandler(char * error); -BOOL DoSendCommand(ConnectionInfo * conn, struct UserInfo * user, char * Cmd, char * Arg1, char * Context); -BOOL CreateMessage(ConnectionInfo * conn, char * From, char * ToCall, char * ATBBS, char MsgType, char * BID, char * Title); -VOID ProcessMsgTitle(ConnectionInfo * conn, struct UserInfo * user, char* Buffer, int len); -VOID ProcessMsgLine(CIRCUIT * conn, struct UserInfo * user, char* Buffer, int len); -VOID CreateMessageFile(ConnectionInfo * conn, struct MsgInfo * Msg); -int ProcessConnecting(CIRCUIT * circuit, char * Buffer, int Len); -VOID SaveConfig(char * ConfigName); -BOOL GetConfig(char * ConfigName); -int GetIntValue(config_setting_t * group, char * name); -BOOL GetStringValue(config_setting_t * group, char * name, char * value); -BOOL GetConfigFromRegistry(); -VOID Parse_SID(CIRCUIT * conn, char * SID, int len); -VOID ProcessMBLLine(CIRCUIT * conn, struct UserInfo * user, UCHAR* Buffer, int len); -VOID ProcessFBBLine(ConnectionInfo * conn, struct UserInfo * user, UCHAR * Buffer, int len); -VOID SetupNextFBBMessage(CIRCUIT * conn); -BOOL DecodeSendParams(CIRCUIT * conn, char * Context, char ** From, char * To, char ** ATBBS, char ** BID); -int PrintMessages(HWND hDlg, int Count, int * Indexes); -int check_fwd_bit(char *mask, int bbsnumber); -void set_fwd_bit(char *mask, int bbsnumber); -void clear_fwd_bit (char *mask, int bbsnumber); -VOID SetupForwardingStruct(struct UserInfo * user); -BOOL Forward_Message(struct UserInfo * user, struct MsgInfo * Msg); -VOID StartForwarding (int BBSNumber, char ** TempScript); -BOOL Reverse_Forward(); -int ProcessBBSConnectScript(CIRCUIT * conn, char * Buffer, int len); -BOOL FBBDoForward(CIRCUIT * conn); -BOOL FindMessagestoForward(CIRCUIT * conn); -BOOL SeeifMessagestoForward(int BBSNumber, CIRCUIT * Conn); -int CountMessagestoForward(struct UserInfo * user); - -VOID * GetMultiLineDialogParam(HWND hDialog, int DLGItem); - -#define LIBCONFIG_STATIC -#include "libconfig.h" -VOID * GetMultiStringValue(config_setting_t * hKey, char * ValueName); -VOID * RegGetMultiStringValue(HKEY hKey, char * ValueName); - -int MultiLineDialogToREG_MULTI_SZ(HWND hWnd, int DLGItem, HKEY hKey, char * ValueName); -int Do_BBS_Sel_Changed(HWND hDlg); -VOID FreeForwardingStruct(struct UserInfo * user); -VOID FreeList(char ** Hddr); -int Do_User_Sel_Changed(HWND hDlg); -int Do_Msg_Sel_Changed(HWND hDlg); -VOID Do_Save_Msg(); -VOID Do_Add_User(HWND hDlg); -VOID Do_Delete_User(HWND hDlg); -VOID FlagSentMessages(CIRCUIT * conn, struct UserInfo * user); -VOID HoldSentMessages(CIRCUIT * conn, struct UserInfo * user); -VOID Do_Save_User(HWND hDlg, BOOL ShowBox); -VOID DeleteBBS(); -VOID AddBBS(); -VOID SaveBBSConfig(); -BOOL GetChatConfig(); -VOID SaveChatConfig(); -VOID SaveISPConfig(); -VOID SaveFWDConfig(); -VOID SaveMAINTConfig(); -VOID SaveWelcomeMsgs(); -VOID SavePrompts(); -VOID ReinitializeFWDStruct(struct UserInfo * user); -VOID CopyBIDDatabase(); -VOID CopyMessageDatabase(); -VOID CopyUserDatabase(); -VOID FWDTimerProc(); -VOID CreateMessageFromBuffer(CIRCUIT * conn); -VOID __cdecl nodeprintf(ConnectionInfo * conn, const char * format, ...); -VOID __cdecl nodeprintfEx(ConnectionInfo * conn, const char * format, ...); -VOID FreeOverrides(); -VOID SendMessageToSYSOP(char * Title, char * MailBuffer, int Length); -struct UserInfo * FindRMS(); -VOID FindNextRMSUser(struct BBSForwardingInfo * FWDInfo); -BOOL ConnecttoBBS (struct UserInfo * user); -BOOL SetupNewBBS(struct UserInfo * user); -VOID CreateRegBackup(); -VOID SaveFilters(HWND hDlg); -BOOL CheckRejFilters(char * From, char * To, char * ATBBS, char * BID, char Type); -BOOL CheckHoldFilters(char * From, char * To, char * ATBBS, char * BID); -BOOL CheckifLocalRMSUser(char * FullTo); -VOID DoWPLookup(ConnectionInfo * conn, struct UserInfo * user, char Type, char *Context); -BOOL wildcardcompare(char * Target, char * Match); -VOID SendWarningToSYSOP(struct MsgInfo * Msg); -VOID DoEditUserCmd(CIRCUIT * conn, struct UserInfo * user, char * Arg1, char * Context); -VOID DoPollRMSCmd(CIRCUIT * conn, struct UserInfo * user, char * Arg1, char * Context); -VOID DoShowRMSCmd(CIRCUIT * conn, struct UserInfo * user, char * Arg1, char * Context); -VOID DoSetIdleTime(CIRCUIT * conn, struct UserInfo * user, char * Arg1, char * Context); -VOID DoFwdCmd(CIRCUIT * conn, struct UserInfo * user, char * Arg1, char * Context); -VOID SaveFwdParams(char * Call, struct BBSForwardingInfo * ForwardingInfo); -VOID DoAuthCmd(CIRCUIT * conn, struct UserInfo * user, char * Arg1, char * Context); -VOID ProcessSuspendedListCommand(CIRCUIT * conn, struct UserInfo * user, char* Buffer, int len); -VOID DoReroute(CIRCUIT * conn, struct UserInfo * user); - -// FBB Routines - -VOID SendCompressed(CIRCUIT * conn, struct MsgInfo * FwdMsg); -VOID SendCompressedB2(CIRCUIT * conn, struct FBBHeaderLine * FBBHeader); -VOID UnpackFBBBinary(CIRCUIT * conn); -void Decode(CIRCUIT * conn, __int16 DecodeOnly); -//long Encode(char * in, char * out, long inlen, BOOL B1Protocol); - -BOOL CreateB2Message(CIRCUIT * conn, struct FBBHeaderLine * FBBHeader, char * Rline); -VOID SaveFBBBinary(CIRCUIT * conn); -BOOL LookupRestart(CIRCUIT * conn, struct FBBHeaderLine * FBBHeader); -BOOL DoWeWantIt(CIRCUIT * conn, struct FBBHeaderLine * FBBHeader); - -// Console Routines - -BOOL CreateConsole(int Stream); -int WritetoConsoleWindow(int Stream, char * Msg, int len); -int ToggleParam(HMENU hMenu, HWND hWnd, BOOL * Param, int Item); -void CopyRichTextToClipboard(HWND hWnd); -void CopyToClipboard(HWND hWnd); -VOID CloseConsole(int Stream); - -// Monitor Routines - -BOOL CreateMonitor(); -int WritetoMonitorWindow(char * Msg, int len); - -BOOL CreateDebugWindow(); -VOID WritetoDebugWindow(char * Msg, int len); -VOID ClearDebugWindow(); -int RemoveLF(char * Message, int len); - -// Utilities - -BOOL isdigits(char * string); -void GetSemaphore(struct SEM * Semaphore, int ID); -void FreeSemaphore(struct SEM * Semaphore); - -VOID __cdecl Debugprintf(const char * format, ...); -VOID __cdecl Logprintf(int LogMode, CIRCUIT * conn, int InOut, const char * format, ...); - -VOID SortBBSChain(); -VOID ExpandAndSendMessage(CIRCUIT * conn, char * Msg, int LOG); -int ImportMessages(CIRCUIT * conn, char * FN, BOOL Nopopup); - -// TCP Routines - -BOOL InitialiseTCP(); -VOID SetupListenSet(); -VOID TCPTimer(); -VOID TCPFastTimer(); -int Socket_Data(int sock, int error, int eventcode); -static int Socket_Accept(SOCKET SocketId); -int Socket_Connect(SOCKET sock, int Error); -VOID ProcessSMTPServerMessage(SocketConn * sockptr, char * Buffer, int Len); -int CreateSMTPMessage(SocketConn * sockptr, int i, char * MsgTitle, time_t Date, char * MsgBody, int Msglen, BOOL B2Flag); -BOOL CreateSMTPMessageFile(char * Message, struct MsgInfo * Msg); -SOCKET CreateListeningSocket(int Port); -int TidyString(char * MailFrom); -VOID ProcessPOP3ServerMessage(SocketConn * sockptr, char * Buffer, int Len); -char *str_base64_encode(char *str); -int b64decode(char *str); -SocketConn * SMTPConnect(char * Host, int Port, BOOL AMPR, struct MsgInfo * Msg, char * MsgBody); -BOOL POP3Connect(char * Host, int Port); -VOID ProcessSMTPClientMessage(SocketConn * sockptr, char * Buffer, int Len); -VOID ProcessPOP3ClientMessage(SocketConn * sockptr, char * Buffer, int Len); -int CreatePOP3Message(char * From, char * To, char * MsgTitle, time_t Date, char * MsgBody, int MsgLen, BOOL B2Flag); -void WriteLogLine(CIRCUIT * conn, int Flag, char * Msg, int MsgLen, int Flags); -int SendSock(SocketConn * sockptr, char * msg); -VOID __cdecl sockprintf(SocketConn * sockptr, const char * format, ...); -VOID SendFromQueue(SocketConn * sockptr); -VOID SendMultiPartMessage(SocketConn * sockptr, struct MsgInfo * Msg, UCHAR * msgbytes); -int CountMessagesTo(struct UserInfo * user, int * Unread); - -BOOL SendtoISP(); - -// NNTP ROutines - -VOID InitialiseNNTP(); -VOID BuildNNTPList(struct MsgInfo * Msg); -int NNTP_Data(int sock, int error, int eventcode); -int NNTP_Accept(SOCKET SocketId); - -VOID * GetOverrides(config_setting_t * group, char * ValueName); -VOID * RegGetOverrides(HKEY hKey, char * ValueName); - -VOID DoHouseKeeping(BOOL Mainual); -VOID ExpireMessages(); -VOID KillMsg(struct MsgInfo * Msg); -BOOL RemoveKilledMessages(); -VOID Renumber_Messages(); -BOOL ExpireBIDs(); -VOID MailHousekeepingResults(); -VOID CreateBBSTrafficReport(); -VOID CreateWPReport(); - -// WP Routines - -VOID ProcessWPMsg(char * MailBuffer, int Size, char * FisrtRLine); -VOID GetWPInfoFromRLine(char * From, char * FirstRLine, time_t RLineTime); -VOID UpdateWPWithUserInfo(struct UserInfo * user); -VOID GetWPBBSInfo(char * Rline); - -// UI Routines - -VOID SetupUIInterface(); -VOID Free_UI(); -VOID SendLatestUI(int Port); -VOID SendMsgUI(struct MsgInfo * Msg); -static VOID Send_AX_Datagram(UCHAR * Msg, DWORD Len, UCHAR Port, UCHAR * HWADDR, BOOL Queue); -VOID SeeifBBSUIFrame(struct _MESSAGEX * buff, int len); -struct MsgInfo * FindMessageByNumber(int msgno); -int CountConnectionsOnPort(int CheckPort); - -// Message Routing Routtines - -VOID SetupHAElements(struct BBSForwardingInfo * ForwardingInfo); -VOID SetupHAddreses(struct BBSForwardingInfo * ForwardingInfo); -VOID SetupHAddresesP(struct BBSForwardingInfo * ForwardingInfo); -VOID SetupMyHA(); -VOID SetupFwdAliases(); -struct Continent * FindContinent(char * Name); -int MatchMessagetoBBSList(struct MsgInfo * Msg, CIRCUIT * conn); -BOOL CheckABBS(struct MsgInfo * Msg, struct UserInfo * bbs, struct BBSForwardingInfo * ForwardingInfo, char * ATBBS, char * HRoute); -BOOL CheckBBSToList(struct MsgInfo * Msg, struct UserInfo * bbs, struct BBSForwardingInfo * ForwardingInfo); -BOOL CheckBBSAtList(struct MsgInfo * Msg, struct BBSForwardingInfo * ForwardingInfo, char * ATBBS); -BOOL CheckBBSHList(struct MsgInfo * Msg, struct UserInfo * bbs, struct BBSForwardingInfo * ForwardingInfo, char * ATBBS, char * HRoute); -BOOL CheckBBSHElements(struct MsgInfo * Msg, struct UserInfo * bbs, struct BBSForwardingInfo * ForwardingInfo, char * ATBBS, char ** HElements); -BOOL CheckBBSHElementsFlood(struct MsgInfo * Msg, struct UserInfo * bbs, struct BBSForwardingInfo * ForwardingInfo, char * ATBBS, char ** HElements); -int CheckBBSToForNTS(struct MsgInfo * Msg, struct BBSForwardingInfo * ForwardingInfo); -int CheckBBSATListWildCarded(struct MsgInfo * Msg, struct BBSForwardingInfo * ForwardingInfo, char * ATBBS); - -VOID ReRouteMessages(); - -VOID initUTF8(); -int Is8Bit(unsigned char *cpt, int len); -int IsUTF8(unsigned char *ptr, int len); -int IsUTF8(unsigned char *ptr, int len); -int WebIsUTF8(unsigned char *ptr, int len); -int Convert437toUTF8(unsigned char * MsgPtr, int len, unsigned char * UTF); -int Convert1251toUTF8(unsigned char * MsgPtr, int len, unsigned char * UTF); -int Convert1252toUTF8(unsigned char * MsgPtr, int len, unsigned char * UTF); -int TrytoGuessCode(unsigned char * Char, int Len); - - -VOID FreeWebMailMallocs(); - -extern int _MYTIMEZONE; - -extern HKEY REGTREE; -extern char * REGTREETEXT; - -extern HBRUSH bgBrush; -extern BOOL cfgMinToTray; - -extern CIRCUIT * Console; - -extern ULONG ChatApplMask; -extern char Verstring[]; - -extern char SignoffMsg[]; -extern char AbortedMsg[]; -extern char InfoBoxText[]; // Text to display in Config Info Popup - -extern int LastVer[4]; // In case we need to do somthing the first time a version is run - -extern HWND MainWnd; -extern char BaseDir[]; -extern char BaseDirRaw[]; -extern char MailDir[]; -extern char WPDatabasePath[]; -extern char RlineVer[50]; - -extern BOOL LogBBS; -extern BOOL LogCHAT; -extern BOOL LogTCP; -extern BOOL ForwardToMe; -extern BOOL OnlyKnown; - -extern BOOL AllowAnon; -extern BOOL UserCantKillT; -extern BOOL DontNeedHomeBBS; - -extern int LatestMsg; -extern char BBSName[]; -extern char SYSOPCall[]; -extern char BBSSID[]; -extern char NewUserPrompt[]; - -extern char * WelcomeMsg; -extern char * NewWelcomeMsg; -extern char * ChatWelcomeMsg; -extern char * NewChatWelcomeMsg; -extern char * ExpertWelcomeMsg; - -extern char * Prompt; -extern char * NewPrompt; -extern char * ExpertPrompt; - -// Filter Params - -extern char ** RejFrom; // Reject on FROM Call -extern char ** RejTo; // Reject on TO Call -extern char ** RejAt; // Reject on AT Call -extern char ** RejBID; - -extern char ** HoldFrom; // Hold on FROM Call -extern char ** HoldTo; // Hold on TO Call -extern char ** HoldAt; // Hold on AT Call -extern char ** HoldBID; - -// Send WP Params - -extern BOOL SendWP; -extern char SendWPVIA[81]; -extern char SendWPTO[11]; -extern int SendWPType; - -extern int Ver[4]; - -extern struct MsgInfo ** MsgHddrPtr; - -extern BIDRec ** BIDRecPtr; -extern int NumberofBIDs; - -extern struct NNTPRec * FirstNNTPRec; -//extern int NumberofNNTPRecs; - - -extern int NumberofMessages; -extern int FirstMessageIndextoForward; - -extern WPRec ** WPRecPtr; -extern int NumberofWPrecs; - -extern struct SEM AllocSemaphore; -extern struct SEM ConSemaphore; -extern struct SEM MsgNoSemaphore; - -extern struct MsgInfo * MsgnotoMsg[]; // Message Number to Message Slot List. - - -extern char hostname[]; -extern char RtUsr[]; -extern char RtUsrTemp[]; -extern char RtKnown[]; -extern int AXIPPort; -extern BOOL NeedStatus; - -extern BOOL ISP_Gateway_Enabled; -extern BOOL SMTPAuthNeeded; - - -extern int MaxMsgno; -extern int BidLifetime; -extern int MaxAge; -extern int MaintInterval; -extern int MaintTime; -extern int UserLifetime; - -extern int MaxRXSize; -extern int MaxTXSize; - -extern char OurNode[]; -extern char OurAlias[]; -extern BOOL SMTPMsgCreated; - -extern HINSTANCE hInst; -extern HWND hWnd; -extern RECT MainRect; - -extern char BBSName[]; -extern char HRoute[]; -extern char AMPRDomain[]; -extern BOOL SendAMPRDirect; -extern int BBSApplNum; -extern int SMTPInPort; -extern int POP3InPort; -extern int NNTPInPort; -extern BOOL RemoteEmail; - -extern int MaxStreams; -extern UCHAR * OtherNodes; -extern struct UserInfo * BBSChain; // Chain of users that are BBSes -extern struct UserInfo ** UserRecPtr; -extern int NumberofUsers; -extern struct MsgInfo ** MsgHddrPtr; -extern int NumberofMessages; -extern int HighestBBSNumber; -extern HMENU hFWDMenu; // Forward Menu Handle -extern char zeros[]; // For forward bitmask tests -extern BOOL EnableUI; -extern BOOL RefuseBulls; -extern BOOL SendSYStoSYSOPCall; -extern BOOL SendBBStoSYSOPCall; -extern BOOL DontHoldNewUsers; -extern BOOL DefaultNoWINLINK; -extern BOOL UIEnabled[]; -extern BOOL UINull[]; -extern BOOL UIMF[]; -extern BOOL UIHDDR[]; -extern char * UIDigi[]; -extern int MailForInterval; -extern char MailForText[]; - -extern BOOL ISP_Gateway_Enabled; - -extern char MyDomain[]; // Mail domain for BBS<>Internet Mapping - -extern char ISPSMTPName[]; -extern char ISPEHLOName[]; -extern int ISPSMTPPort; - -extern char ISPPOP3Name[]; -extern int ISPPOP3Port; -extern int ISPPOP3Interval; - -extern char ISPAccountName[]; -extern char ISPAccountPass[]; -extern char EncryptedISPAccountPass[]; -extern int EncryptedPassLen; -extern char *month[]; - -extern HWND hDebug; -extern RECT MonitorRect; -extern RECT DebugRect; -extern HWND hMonitor; -//extern HWND hConsole; -//extern RECT ConsoleRect; -extern int LogAge; -extern BOOL DeletetoRecycleBin; -extern BOOL SuppressMaintEmail; -extern BOOL SaveRegDuringMaint; -extern BOOL SendWP; -extern BOOL OverrideUnsent; -extern BOOL SendNonDeliveryMsgs; -extern BOOL GenerateTrafficReport; - -extern double PR; -extern double PUR; -extern double PF; -extern double PNF; -extern int BF; -extern int BNF; -extern int NTSD; -extern int NTSU; -extern int NTSF; -extern int AP; -extern int AB; - -extern struct Override ** LTFROM; -extern struct Override ** LTTO; -extern struct Override ** LTAT; - -extern time_t LastHouseKeepingTime; -extern time_t LastTrafficTime; - -extern char * MyElements[]; -extern char ** AliasText; -extern struct ALIAS ** Aliases; - -extern BOOL ReaddressLocal; -extern BOOL ReaddressReceived; -extern BOOL WarnNoRoute; -extern BOOL SendPtoMultiple; -extern BOOL Localtime; - -struct ConsoleInfo * ConsHeader[2]; - -extern BOOL NeedHomeBBS; -extern char ConfigName[250]; -extern BOOL UsingingRegConfig; - -extern BOOL MulticastRX; - -extern BOOL FilterWPBulls; -extern BOOL NoWPGuesses; -extern char ** SendWPAddrs; // Replacers WP To and VIA - -extern BOOL DontCheckFromCall; - -// YAPP stuff - -#define SOH 1 -#define STX 2 -#define ETX 3 -#define EOT 4 -#define ENQ 5 -#define ACK 6 -#define DLE 0x10 -#define NAK 0x15 -#define CAN 0x18 diff --git a/cMain.c b/cMain.c index 9acb24a..abab877 100644 --- a/cMain.c +++ b/cMain.c @@ -139,6 +139,7 @@ extern BOOL ADIFLogEnabled; extern UCHAR LogDirectory[260]; extern BOOL EventsEnabled; extern BOOL SaveAPRSMsgs; +BOOL M0LTEMap = FALSE; //TNCTABLE DD 0 //NUMBEROFSTREAMS DD 0 @@ -788,6 +789,8 @@ BOOL Start() ADIFLogEnabled = cfg->C_ADIF; EventsEnabled = cfg->C_EVENTS; SaveAPRSMsgs = cfg->C_SaveAPRSMsgs; + M0LTEMap = cfg->C_M0LTEMap; + // Get pointers to PASSWORD and APPL1 commands @@ -939,7 +942,8 @@ BOOL Start() PORT->QUAL_ADJUST = (UCHAR)PortRec->QUALADJUST; PORT->DIGIFLAG = PortRec->DIGIFLAG; - PORT->DIGIPORT = PortRec->DIGIPORT; + if (PortRec->DIGIPORT && CanPortDigi(PortRec->DIGIPORT)) + PORT->DIGIPORT = PortRec->DIGIPORT; PORT->DIGIMASK = PortRec->DIGIMASK; PORT->USERS = (UCHAR)PortRec->USERS; @@ -1074,6 +1078,8 @@ BOOL Start() KISS->KISSCMD = realloc(KISS->KISSCMD, KISS->KISSCMDLEN); } + PORT->SendtoM0LTEMap = PortRec->SendtoM0LTEMap; + if (PortRec->BBSFLAG) // Appl 1 not permitted - BBSFLAG=NOBBS PORT->PERMITTEDAPPLS &= 0xfffffffe; // Clear bottom bit @@ -2075,7 +2081,6 @@ VOID TIMERINTERRUPT() L3FastTimer(); L4TimerProc(); - } // SEE IF ANY FRAMES TO TRACE diff --git a/compatbits.h b/compatbits.h index 6441507..5804fc5 100644 --- a/compatbits.h +++ b/compatbits.h @@ -54,7 +54,6 @@ uintptr_t _beginthread(void(__cdecl *start_address)(void *), unsigned stack_size #else int Sleep(int ms); -int GetTickCount(); #define ioctlsocket ioctl @@ -142,6 +141,9 @@ typedef DWORD COLORREF; #define MoveFile rename #define CreateDirectory mkdir +uint64_t GetTickCount(); + + int sprintf_s(char * string, int plen, const char * format, ...); diff --git a/config.c b/config.c index 6592b51..42d85f4 100644 --- a/config.c +++ b/config.c @@ -300,7 +300,8 @@ static char *keywords[] = "APPL1QUAL", "APPL2QUAL", "APPL3QUAL", "APPL4QUAL", "APPL5QUAL", "APPL6QUAL", "APPL7QUAL", "APPL8QUAL", "BTEXT:", "NETROMCALL", "C_IS_CHAT", "MAXRTT", "MAXHOPS", // IPGATEWAY= no longer allowed -"LogL4Connects", "LogAllConnects", "SAVEMH", "ENABLEADIFLOG", "ENABLEEVENTS", "SAVEAPRSMSGS" +"LogL4Connects", "LogAllConnects", "SAVEMH", "ENABLEADIFLOG", "ENABLEEVENTS", "SAVEAPRSMSGS", +"EnableM0LTEMap" }; /* parameter keywords */ static void * offset[] = @@ -320,7 +321,8 @@ static void * offset[] = &xxcfg.C_APPL[0].ApplQual, &xxcfg.C_APPL[1].ApplQual, &xxcfg.C_APPL[2].ApplQual, &xxcfg.C_APPL[3].ApplQual, &xxcfg.C_APPL[4].ApplQual, &xxcfg.C_APPL[5].ApplQual, &xxcfg.C_APPL[6].ApplQual, &xxcfg.C_APPL[7].ApplQual, &xxcfg.C_BTEXT, &xxcfg.C_NETROMCALL, &xxcfg.C_C, &xxcfg.C_MAXRTT, &xxcfg.C_MAXHOPS, // IPGATEWAY= no longer allowed -&xxcfg.C_LogL4Connects, &xxcfg.C_LogAllConnects, &xxcfg.C_SaveMH, &xxcfg.C_ADIF, &xxcfg.C_EVENTS, &xxcfg.C_SaveAPRSMsgs}; /* offset for corresponding data in config file */ +&xxcfg.C_LogL4Connects, &xxcfg.C_LogAllConnects, &xxcfg.C_SaveMH, &xxcfg.C_ADIF, &xxcfg.C_EVENTS, &xxcfg.C_SaveAPRSMsgs, +&xxcfg.C_M0LTEMap}; /* offset for corresponding data in config file */ static int routine[] = { @@ -339,7 +341,8 @@ static int routine[] = 14, 14, 14, 14, 14, 14 ,14, 14, 15, 0, 2, 9, 9, -2, 2, 2, 2, 2, 2} ; // Routine to process param +2, 2, 2, 2, 2, 2, +2} ; // Routine to process param int PARAMLIM = sizeof(routine)/sizeof(int); //int NUMBEROFKEYWORDS = sizeof(routine)/sizeof(int); @@ -361,7 +364,7 @@ static char *pkeywords[] = "BCALL", "DIGIMASK", "NOKEEPALIVES", "COMPORT", "DRIVER", "WL2KREPORT", "UIONLY", "UDPPORT", "IPADDR", "I2CBUS", "I2CDEVICE", "UDPTXPORT", "UDPRXPORT", "NONORMALIZE", "IGNOREUNLOCKEDROUTES", "INP3ONLY", "TCPPORT", "RIGPORT", "PERMITTEDAPPLS", "HIDE", -"SMARTID", "KISSCOMMAND"}; /* parameter keywords */ +"SMARTID", "KISSCOMMAND", "SendtoM0LTEMap"}; /* parameter keywords */ static void * poffset[] = { @@ -375,7 +378,7 @@ static void * poffset[] = &xxp.BCALL, &xxp.DIGIMASK, &xxp.DefaultNoKeepAlives, &xxp.IOADDR, &xxp.DLLNAME, &xxp.WL2K, &xxp.UIONLY, &xxp.IOADDR, &xxp.IPADDR, &xxp.INTLEVEL, &xxp.IOADDR, &xxp.IOADDR, &xxp.ListenPort, &xxp.NoNormalize, &xxp.IGNOREUNLOCKED, &xxp.INP3ONLY, &xxp.TCPPORT, &xxp.RIGPORT, &xxp.PERMITTEDAPPLS, &xxp.Hide, -&xxp.SmartID, &xxp.KissParams}; /* offset for corresponding data in config file */ +&xxp.SmartID, &xxp.KissParams, &xxp.SendtoM0LTEMap}; /* offset for corresponding data in config file */ static int proutine[] = { @@ -389,7 +392,7 @@ static int proutine[] = 0, 1, 2, 18, 15, 16, 2, 1, 17, 1, 1, 1, 1, 2, 2, 2, 1, 1, 19, 2, -1, 20}; /* routine to process parameter */ +1, 20, 1}; /* routine to process parameter */ int PPARAMLIM = sizeof(proutine)/sizeof(int); @@ -427,6 +430,9 @@ char bbscall[11]; char bbsalias[11]; int bbsqual; + +extern UCHAR ConfigDirectory[260]; + BOOL LocSpecified = FALSE; /************************************************************************/ @@ -485,13 +491,13 @@ BOOL ProcessConfig() Consoleprintf("Configuration file Preprocessor."); - if (BPQDirectory[0] == 0) + if (ConfigDirectory[0] == 0) { strcpy(inputname, "bpq32.cfg"); } else { - strcpy(inputname,BPQDirectory); + strcpy(inputname,ConfigDirectory); strcat(inputname,"/"); strcat(inputname, "bpq32.cfg"); } @@ -597,6 +603,8 @@ BOOL ProcessConfig() paramok[77]=1; // ENABLEADIFLOG optional paramok[78]=1; // EnableEvents optional paramok[79]=1; // SaveAPRSMsgs optional + paramok[79]=1; // SaveAPRSMsgs optional + paramok[80]=1; // EnableM0LTEMap optional for (i=0; i < PARAMLIM; i++) { @@ -1624,6 +1632,8 @@ int ports(int i) heading = 1; } + xxp.SendtoM0LTEMap = 1; // Default to enabled + while (endport == 0 && !feof(fp1)) { GetNextLine(rec); @@ -2927,7 +2937,7 @@ BOOL ProcessAPPLDef(char * buf) Appl = atoi(Param[0]); - if (Appl < 1 || Appl > 32) return FALSE; + if (Appl < 1 || Appl > NumberofAppls) return FALSE; App = &xxcfg.C_APPL[Appl - 1]; // Recs from zero diff --git a/configstructs.h b/configstructs.h index 39fc25b..67a6fbf 100644 --- a/configstructs.h +++ b/configstructs.h @@ -73,10 +73,11 @@ struct PORTCONFIG unsigned int PERMITTEDAPPLS; // Appls allowed on this port int HavePermittedAppls; // Indicated PERMITTEDAPPLS uses int Hide; // Don't show on Ports display or AGW Connect Menu - long long txOffset; // Transverter tx offset - long long rxOffset; // Transverter rx offset ppa +// long long txOffset; // Transverter tx offset +// long long rxOffset; // Transverter rx offset ppa int SmartID; unsigned char * KissParams; + int SendtoM0LTEMap; }; struct ROUTECONFIG @@ -149,6 +150,7 @@ struct CONFIGTABLE UCHAR C_EVENTS; UCHAR C_LogAllConnects; UCHAR C_SaveAPRSMsgs; + UCHAR C_M0LTEMap; UCHAR C_VERSION; // CONFIG PROG VERSION // Reuse C_APPLICATIONS - no longer used char C_NETROMCALL[10]; diff --git a/datadefs.c b/datadefs.c index fb16c62..44d1fd0 100644 --- a/datadefs.c +++ b/datadefs.c @@ -50,6 +50,7 @@ char LOC[7] = ""; // Must be in shared mem// Maidenhead Locator for Reporting char ReportDest[7]; UCHAR BPQDirectory[260] = "."; +UCHAR ConfigDirectory[260] = "."; UCHAR LogDirectory[260] = ""; UCHAR BPQProgramDirectory[260]=""; diff --git a/getopt.c b/getopt.c new file mode 100644 index 0000000..0e74577 --- /dev/null +++ b/getopt.c @@ -0,0 +1,715 @@ +/* + * getopt.c + * + * $Id: getopt.c,v 1.9 2009/02/08 18:02:17 keithmarshall Exp $ + * + * Implementation of the `getopt', `getopt_long' and `getopt_long_only' + * APIs, for inclusion in the MinGW runtime library. + * + * This file is part of the MinGW32 package set. + * + * Contributed by Keith Marshall + * + * + * THIS SOFTWARE IS NOT COPYRIGHTED + * + * This source code is offered for use in the public domain. You may + * use, modify or distribute it freely. + * + * This code is distributed in the hope that it will be useful but + * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY + * DISCLAIMED. This includes but is not limited to warranties of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * $Revision: 1.9 $ + * $Author: keithmarshall $ + * $Date: 2009/02/08 18:02:17 $ + * + */ + +// Modified a little to compile as C code, John Wiseman 2018 + +#include +#include +#include +#include "getopt.h" + +/* Identify how to get the calling program name, for use in messages... + */ +#ifdef __CYGWIN__ +/* + * CYGWIN uses this DLL reference... + */ +# define PROGNAME __progname +extern char __declspec(dllimport) *__progname; +#else +/* + * ...while elsewhere, we simply use the first argument passed. + */ +# define PROGNAME *argv +#endif + +/* Initialise the public variables. */ + +int optind = 1; /* index for first non-option arg */ +int opterr = 1; /* enable built-in error messages */ + +char *optarg = NULL; /* pointer to current option argument */ + +#define CHAR char /* argument type selector */ + +#define getopt_switchar '-' /* option prefix character in argv */ +#define getopt_pluschar '+' /* prefix for POSIX mode in optstring */ +#define getopt_takes_argument ':' /* marker for optarg in optstring */ +#define getopt_arg_assign '=' /* longopt argument field separator */ +#define getopt_unknown '?' /* return code for unmatched option */ +#define getopt_ordered 1 /* return code for ordered non-option */ + +#define getopt_all_done -1 /* return code to indicate completion */ + +enum +{ /* All `getopt' API functions are implemented via calls to the + * common static function `getopt_parse()'; these `mode' selectors + * determine the behaviour of `getopt_parse()', to deliver the + * appropriate result in each case. + */ + getopt_mode_standard = 0, /* getopt() */ + getopt_mode_long, /* getopt_long() */ + getopt_mode_long_only /* getopt_long_only() */ +}; + +enum +{ /* When attempting to match a command line argument to a long form option, + * these indicate the status of the match. + */ + getopt_no_match = 0, /* no successful match */ + getopt_abbreviated_match, /* argument is an abbreviation for an option */ + getopt_exact_match /* argument matches the full option name */ +}; + +int optopt = getopt_unknown; /* return value for option being evaluated */ + +/* Some BSD applications expect to be able to reinitialise `getopt' parsing + * by setting a global variable called `optreset'. We provide an obfuscated + * API, which allows applications to emulate this brain damage; however, any + * use of this is non-portable, and is strongly discouraged. + */ +#define optreset __mingw_optreset +int optreset = 0; + +int getopt_missing_arg( const CHAR *optstring ) +{ + /* Helper function to determine the appropriate return value, + * for the case where a required option argument is missing. + */ + if( (*optstring == getopt_pluschar) || (*optstring == getopt_switchar) ) + ++optstring; + return (*optstring == getopt_takes_argument) + ? getopt_takes_argument + : getopt_unknown; +} + +/* `complain' macro facilitates the generation of simple built-in + * error messages, displayed on various fault conditions, provided + * `opterr' is non-zero. + */ +#define complain( MSG, ARG ) if( opterr ) \ + fprintf( stderr, "%s: "MSG"\n", PROGNAME, ARG ) + + +int getopt_argerror( int mode, char *fmt, CHAR *prog, struct option *opt, int retval ) +{ + /* Helper function, to generate more complex built-in error + * messages, for invalid arguments to long form options ... + */ + if( opterr ) + { + /* ... but, displayed only if `opterr' is non-zero. + */ + char flag[] = "--"; + if( mode != getopt_mode_long ) + /* + * only display one hyphen, for implicit long form options, + * improperly resolved by `getopt_long_only()'. + */ + flag[1] = 0; + /* + * always preface the program name ... + */ + fprintf( stderr, "%s: ", prog ); + /* + * to the appropriate, option specific message. + */ + fprintf( stderr, fmt, flag, opt->name ); + } + /* Whether displaying the message, or not, always set `optopt' + * to identify the faulty option ... + */ + optopt = opt->val; + /* + * and return the `invalid option' indicator. + */ + return retval; +} + +/* `getopt_conventions' establish behavioural options, to control + * the operation of `getopt_parse()', e.g. to select between POSIX + * and GNU style argument parsing behaviour. + */ +#define getopt_set_conventions 0x1000 +#define getopt_posixly_correct 0x0010 + + +int getopt_conventions( int flags ) +{ + static int conventions = 0; + + if( (conventions == 0) && ((flags & getopt_set_conventions) == 0) ) + { + /* default conventions have not yet been established; + * initialise them now! + */ + conventions = getopt_set_conventions; + + } + + else if( flags & getopt_set_conventions ) + /* + * default conventions may have already been established, + * but this is a specific request to augment them. + */ + conventions |= flags; + + /* in any event, return the currently established conventions. + */ + return conventions; +} + +int is_switchar( CHAR flag ) +{ + /* A simple helper function, used to identify the switch character + * introducing an optional command line argument. + */ + return flag == getopt_switchar; +} + +const CHAR *getopt_match( CHAR lookup, const CHAR *opt_string ) +{ + /* Helper function, used to identify short form options. + */ + if( (*opt_string == getopt_pluschar) || (*opt_string == getopt_switchar) ) + ++opt_string; + if( *opt_string == getopt_takes_argument ) + ++opt_string; + do if( lookup == *opt_string ) return opt_string; + while( *++opt_string ); + return NULL; +} + +int getopt_match_long( const CHAR *nextchar, const CHAR *optname ) +{ + /* Helper function, used to identify potential matches for + * long form options. + */ + CHAR matchchar; + while( (matchchar = *nextchar++) && (matchchar == *optname) ) + /* + * skip over initial substring which DOES match. + */ + ++optname; + + if( matchchar ) + { + /* did NOT match the entire argument to an initial substring + * of a defined option name ... + */ + if( matchchar != getopt_arg_assign ) + /* + * ... and didn't stop at an `=' internal field separator, + * so this is NOT a possible match. + */ + return getopt_no_match; + + /* DID stop at an `=' internal field separator, + * so this IS a possible match, and what follows is an + * argument to the possibly matched option. + */ + optarg = (char *)(nextchar); + } + return *optname + /* + * if we DIDN'T match the ENTIRE text of the option name, + * then it's a possible abbreviated match ... + */ + ? getopt_abbreviated_match + /* + * but if we DID match the entire option name, + * then it's a DEFINITE EXACT match. + */ + : getopt_exact_match; +} + +int getopt_resolved( int mode, int argc, CHAR *const *argv, int *argind, +struct option *opt, int index, int *retindex, const CHAR *optstring ) +{ + /* Helper function to establish appropriate return conditions, + * on resolution of a long form option. + */ + if( retindex != NULL ) + *retindex = index; + + /* On return, `optind' should normally refer to the argument, if any, + * which follows the current one; it is convenient to set this, before + * checking for the presence of any `optarg'. + */ + optind = *argind + 1; + + if( optarg && (opt[index].has_arg == no_argument) ) + /* + * it is an error for the user to specify an option specific argument + * with an option which doesn't expect one! + */ + return getopt_argerror( mode, "option `%s%s' doesn't accept an argument\n", + PROGNAME, opt + index, getopt_unknown ); + + else if( (optarg == NULL) && (opt[index].has_arg == required_argument) ) + { + /* similarly, it is an error if no argument is specified + * with an option which requires one ... + */ + if( optind < argc ) + /* + * ... except that the requirement may be satisfied from + * the following command line argument, if any ... + */ + optarg = argv[*argind = optind++]; + + else + /* so fail this case, only if no such argument exists! + */ + return getopt_argerror( mode, "option `%s%s' requires an argument\n", + PROGNAME, opt + index, getopt_missing_arg( optstring ) ); + } + + /* when the caller has provided a return buffer ... + */ + if( opt[index].flag != NULL ) + { + /* ... then we place the proper return value there, + * and return a status code of zero ... + */ + *(opt[index].flag) = opt[index].val; + return 0; + } + /* ... otherwise, the return value becomes the status code. + */ + return opt[index].val; +} + +static +#define getopt_std_args int argc, CHAR *const argv[], const CHAR *optstring +int getopt_parse( int mode, getopt_std_args, ... ) +{ + /* Common core implementation for ALL `getopt' functions. + */ + static int argind = 0; + static int optbase = 0; + static const CHAR *nextchar = NULL; + static int optmark = 0; + + if( (optreset |= (optind < 1)) || (optind < optbase) ) + { + /* POSIX does not prescribe any definitive mechanism for restarting + * a `getopt' scan, but some applications may require such capability. + * We will support it, by allowing the caller to adjust the value of + * `optind' downwards, (nominally setting it to zero). Since POSIX + * wants `optind' to have an initial value of one, but we want all + * of our internal place holders to be initialised to zero, when we + * are called for the first time, we will handle such a reset by + * adjusting all of the internal place holders to one less than + * the adjusted `optind' value, (but never to less than zero). + */ + if( optreset ) + { + /* User has explicitly requested reinitialisation... + * We need to reset `optind' to it's normal initial value of 1, + * to avoid a potential infinitely recursive loop; by doing this + * up front, we also ensure that the remaining place holders + * will be correctly reinitialised to no less than zero. + */ + optind = 1; + + /* We also need to clear the `optreset' request... + */ + optreset = 0; + } + + /* Now, we may safely reinitialise the internal place holders, to + * one less than `optind', without fear of making them negative. + */ + optmark = optbase = argind = optind - 1; + nextchar = NULL; + } + + /* From a POSIX perspective, the following is `undefined behaviour'; + * we implement it thus, for compatibility with GNU and BSD getopt. + */ + else if( optind > (argind + 1) ) + { + /* Some applications expect to be able to manipulate `optind', + * causing `getopt' to skip over one or more elements of `argv'; + * POSIX doesn't require us to support this brain-damaged concept; + * (indeed, POSIX defines no particular behaviour, in the event of + * such usage, so it must be considered a bug for an application + * to rely on any particular outcome); nonetheless, Mac-OS-X and + * BSD actually provide *documented* support for this capability, + * so we ensure that our internal place holders keep track of + * external `optind' increments; (`argind' must lag by one). + */ + argind = optind - 1; + + /* When `optind' is misused, in this fashion, we also abandon any + * residual text in the argument we had been parsing; this is done + * without any further processing of such abandoned text, assuming + * that the caller is equipped to handle it appropriately. + */ + nextchar = NULL; + } + + if( nextchar && *nextchar ) + { + /* we are parsing a standard, or short format, option argument ... + */ + const CHAR *optchar; + if( (optchar = getopt_match( optopt = *nextchar++, optstring )) != NULL ) + { + /* we have identified it as valid ... + */ + if( optchar[1] == getopt_takes_argument ) + { + /* and determined that it requires an associated argument ... + */ + if( ! *(optarg = (char *)(nextchar)) ) + { + /* the argument is NOT attached ... + */ + if( optchar[2] == getopt_takes_argument ) + /* + * but this GNU extension marks it as optional, + * so we don't provide one on this occasion. + */ + optarg = NULL; + + /* otherwise this option takes a mandatory argument, + * so, provided there is one available ... + */ + else if( (argc - argind) > 1 ) + /* + * we take the following command line argument, + * as the appropriate option argument. + */ + optarg = argv[++argind]; + + /* but if no further argument is available, + * then there is nothing we can do, except for + * issuing the requisite diagnostic message. + */ + else + { + complain( "option requires an argument -- %c", optopt ); + return getopt_missing_arg( optstring ); + } + } + optind = argind + 1; + nextchar = NULL; + } + else + optarg = NULL; + optind = (nextchar && *nextchar) ? argind : argind + 1; + return optopt; + } + /* if we didn't find a valid match for the specified option character, + * then we fall through to here, so take appropriate diagnostic action. + */ + if( mode == getopt_mode_long_only ) + { + complain( "unrecognised option `-%s'", --nextchar ); + nextchar = NULL; + optopt = 0; + } + else + complain( "invalid option -- %c", optopt ); + optind = (nextchar && *nextchar) ? argind : argind + 1; + return getopt_unknown; + } + + if( optmark > optbase ) + { + /* This can happen, in GNU parsing mode ONLY, when we have + * skipped over non-option arguments, and found a subsequent + * option argument; in this case we permute the arguments. + */ + int index; + /* + * `optspan' specifies the number of contiguous arguments + * which are spanned by the current option, and so must be + * moved together during permutation. + */ + int optspan = argind - optmark + 1; + /* + * we use `this_arg' to store these temporarily. + */ + CHAR *this_arg[100]; + /* + * we cannot manipulate `argv' directly, since the `getopt' + * API prototypes it as `read-only'; this cast to `arglist' + * allows us to work around that restriction. + */ + CHAR **arglist = (char **)(argv); + + /* save temporary copies of the arguments which are associated + * with the current option ... + */ + for( index = 0; index < optspan; ++index ) + this_arg[index] = arglist[optmark + index]; + + /* move all preceding non-option arguments to the right, + * overwriting these saved arguments, while making space + * to replace them in their permuted location. + */ + for( --optmark; optmark >= optbase; --optmark ) + arglist[optmark + optspan] = arglist[optmark]; + + /* restore the temporarily saved option arguments to + * their permuted location. + */ + for( index = 0; index < optspan; ++index ) + arglist[optbase + index] = this_arg[index]; + + /* adjust `optbase', to account for the relocated option. + */ + optbase += optspan; + } + + else + /* no permutation occurred ... + * simply adjust `optbase' for all options parsed so far. + */ + optbase = argind + 1; + + /* enter main parsing loop ... + */ + while( argc > ++argind ) + { + /* inspect each argument in turn, identifying possible options ... + */ + if( is_switchar( *(nextchar = argv[optmark = argind]) ) && *++nextchar ) + { + /* we've found a candidate option argument ... */ + + if( is_switchar( *nextchar ) ) + { + /* it's a double hyphen argument ... */ + + const CHAR *refchar = nextchar; + if( *++refchar ) + { + /* and it looks like a long format option ... + * `getopt_long' mode must be active to accept it as such, + * `getopt_long_only' also qualifies, but we must downgrade + * it to force explicit handling as a long format option. + */ + if( mode >= getopt_mode_long ) + { + nextchar = refchar; + mode = getopt_mode_long; + } + } + else + { + /* this is an explicit `--' end of options marker, so wrap up now! + */ + if( optmark > optbase ) + { + /* permuting the argument list as necessary ... + * (note use of `this_arg' and `arglist', as above). + */ + CHAR *this_arg = argv[optmark]; + CHAR **arglist = (CHAR **)(argv); + + /* move all preceding non-option arguments to the right ... + */ + do arglist[optmark] = arglist[optmark - 1]; + while( optmark-- > optbase ); + + /* reinstate the `--' marker, in its permuted location. + */ + arglist[optbase] = this_arg; + } + /* ... before finally bumping `optbase' past the `--' marker, + * and returning the `all done' completion indicator. + */ + optind = ++optbase; + return getopt_all_done; + } + } + else if( mode < getopt_mode_long_only ) + { + /* it's not an explicit long option, and `getopt_long_only' isn't active, + * so we must explicitly try to match it as a short option. + */ + mode = getopt_mode_standard; + } + + if( mode >= getopt_mode_long ) + { + /* the current argument is a long form option, (either explicitly, + * introduced by a double hyphen, or implicitly because we were called + * by `getopt_long_only'); this is where we parse it. + */ + int lookup; + int matched = -1; + struct option *longopts; + int *optindex; + /* we need to fetch the `extra' function arguments, which are + * specified for the `getopt_long' APIs. + */ + va_list refptr; + va_start( refptr, optstring ); + longopts = va_arg( refptr, struct option * ); + optindex = va_arg( refptr, int * ); + va_end( refptr ); + + /* ensuring that `optarg' does not inherit any junk, from parsing + * preceding arguments ... + */ + optarg = NULL; + for( lookup = 0; longopts && longopts[lookup].name; ++lookup ) + { + /* scan the list of defined long form options ... + */ + switch( getopt_match_long( nextchar, longopts[lookup].name ) ) + { + /* looking for possible matches for the current argument. + */ + case getopt_exact_match: + /* + * when an exact match is found, + * return it immediately, setting `nextchar' to NULL, + * to ensure we don't mistakenly try to match any + * subsequent characters as short form options. + */ + nextchar = NULL; + return getopt_resolved( mode, argc, argv, &argind, + longopts, lookup, optindex, optstring ); + + case getopt_abbreviated_match: + /* + * but, for a partial (initial substring) match ... + */ + if( matched >= 0 ) + { + /* if this is not the first, then we have an ambiguity ... + */ + optopt = 0; + nextchar = NULL; + optind = argind + 1; + complain( "option `%s' is ambiguous", argv[argind] ); + return getopt_unknown; + } + /* otherwise just note that we've found a possible match ... + */ + matched = lookup; + } + } + if( matched >= 0 ) + { + /* if we get to here, then we found exactly one partial match, + * so return it, as for an exact match. + */ + nextchar = NULL; + return getopt_resolved( mode, argc, argv, &argind, + longopts, matched, optindex, optstring ); + } + if( mode < getopt_mode_long_only ) + { + /* if here, then we had what SHOULD have been a long form option, + * but it is unmatched; (perversely, `mode == getopt_mode_long_only' + * allows us to still try to match it as a short form option). + */ + optopt = 0; + nextchar = NULL; + optind = argind + 1; + complain( "unrecognised option `%s'", argv[argind] ); + return getopt_unknown; + } + } + /* fall through to handle standard short form options... + * when the option argument format is neither explictly identified + * as long, nor implicitly matched as such, and the argument isn't + * just a bare hyphen, (which isn't an option), then we make one + * recursive call to explicitly interpret it as short format. + */ + if( *nextchar ) + return getopt_parse( mode, argc, argv, optstring ); + } + /* if we get to here, then we've parsed a non-option argument ... + * in GNU compatibility mode, we step over it, so we can permute + * any subsequent option arguments, but ... + */ + if( *optstring == getopt_switchar ) + { + /* if `optstring' begins with a `-' character, this special + * GNU specific behaviour requires us to return the non-option + * arguments in strict order, as pseudo-arguments to a special + * option, with return value defined as `getopt_ordered'. + */ + nextchar = NULL; + optind = argind + 1; + optarg = argv[argind]; + return getopt_ordered; + } + if( getopt_conventions( *optstring ) & getopt_posixly_correct ) + /* + * otherwise ... + * for POSIXLY_CORRECT behaviour, or if `optstring' begins with + * a `+' character, then we break out of the parsing loop, so that + * the scan ends at the current argument, with no permutation. + */ + break; + } + /* fall through when all arguments have been evaluated, + */ + optind = optbase; + return getopt_all_done; +} + +/* All three public API entry points are trivially defined, + * in terms of the internal `getopt_parse' function. + */ +int getopt( getopt_std_args ) +{ + return getopt_parse( getopt_mode_standard, argc, argv, optstring ); +} + +int getopt_long( getopt_std_args, const struct option *opts, int *index ) +{ + return getopt_parse( getopt_mode_long, argc, argv, optstring, opts, index ); +} + +int getopt_long_only( getopt_std_args, const struct option *opts, int *index ) +{ + return getopt_parse( getopt_mode_long_only, argc, argv, optstring, opts, index ); +} + +#ifdef __weak_alias +/* + * These Microsnot style uglified aliases are provided for compatibility + * with the previous MinGW implementation of the getopt API. + */ +__weak_alias( getopt, _getopt ) +__weak_alias( getopt_long, _getopt_long ) +__weak_alias( getopt_long_only, _getopt_long_only ) +#endif + +/* $RCSfile: getopt.c,v $Revision: 1.9 $: end of file */ \ No newline at end of file diff --git a/getopt.h b/getopt.h new file mode 100644 index 0000000..6cfa016 --- /dev/null +++ b/getopt.h @@ -0,0 +1,108 @@ +#ifndef __GETOPT_H__ +/* + * getopt.h + * + * $Id: getopt.h,v 1.4 2009/01/04 17:35:36 keithmarshall Exp $ + * + * Defines constants and function prototypes required to implement + * the `getopt', `getopt_long' and `getopt_long_only' APIs. + * + * This file is part of the MinGW32 package set. + * + * Contributed by Keith Marshall + * + * + * THIS SOFTWARE IS NOT COPYRIGHTED + * + * This source code is offered for use in the public domain. You may + * use, modify or distribute it freely. + * + * This code is distributed in the hope that it will be useful but + * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY + * DISCLAIMED. This includes but is not limited to warranties of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * $Revision: 1.4 $ + * $Author: keithmarshall $ + * $Date: 2009/01/04 17:35:36 $ + * + */ +#define __GETOPT_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +extern int optind; /* index of first non-option in argv */ +extern int optopt; /* single option character, as parsed */ +extern int opterr; /* flag to enable built-in diagnostics... */ + /* (user may set to zero, to suppress) */ + +extern char *optarg; /* pointer to argument of current option */ + +extern int getopt( int, char * const [], const char * ); + +#ifdef _BSD_SOURCE +/* + * BSD adds the non-standard `optreset' feature, for reinitialisation + * of `getopt' parsing. We support this feature, for applications which + * proclaim their BSD heritage, before including this header; however, + * to maintain portability, developers are advised to avoid it. + */ +# define optreset __mingw_optreset + +extern int optreset; +#endif +#ifdef __cplusplus +} +#endif +/* + * POSIX requires the `getopt' API to be specified in `unistd.h'; + * thus, `unistd.h' includes this header. However, we do not want + * to expose the `getopt_long' or `getopt_long_only' APIs, when + * included in this manner. Thus, close the standard __GETOPT_H__ + * declarations block, and open an additional __GETOPT_LONG_H__ + * specific block, only when *not* __UNISTD_H_SOURCED__, in which + * to declare the extended API. + */ +#endif /* !defined(__GETOPT_H__) */ +#if !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) +#define __GETOPT_LONG_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +struct option /* specification for a long form option... */ +{ + const char *name; /* option name, without leading hyphens */ + int has_arg; /* does it take an argument? */ + int *flag; /* where to save its status, or NULL */ + int val; /* its associated status value */ +}; + +enum /* permitted values for its `has_arg' field... */ +{ + no_argument = 0, /* option never takes an argument */ + required_argument, /* option always requires an argument */ + optional_argument /* option may take an argument */ +}; + +extern int getopt_long( int, char * const [], const char *, const struct option *, int * ); +extern int getopt_long_only( int, char * const [], const char *, const struct option *, int * ); +/* + * Previous MinGW implementation had... + */ +#ifndef HAVE_DECL_GETOPT +/* + * ...for the long form API only; keep this for compatibility. + */ +# define HAVE_DECL_GETOPT 1 +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) */ +/* $RCSfile: getopt.h,v $Revision: 1.4 $: end of file */ \ No newline at end of file diff --git a/linether.c~ b/linether.c~ deleted file mode 100644 index 57248cf..0000000 --- a/linether.c~ +++ /dev/null @@ -1,498 +0,0 @@ -/* -Copyright 2001-2015 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 -*/ - -// -// DLL to provide BPQEther support for G8BPQ switch in a Linux environment, - -// Normally uses a Raw socket, but that can't send to other apps on same machine. -// so can use a TAP device instead (or maybe as well??) - -#include - -#include "CHeaders.h" - -#include -#include -#include -#include - -extern char * PortConfig[33]; - -extern int tap_fd; - -typedef struct PCAPStruct -{ - UCHAR EthSource[6]; - UCHAR EthDest[6]; - short EtherType; - BOOL RLITX; - BOOL RLIRX; - BOOL Promiscuous; - - int s; /*socketdescriptor*/ - struct sockaddr_ll socket_address; /*target address*/ - -} PCAPINFO, *PPCAPINFO ; - -PCAPINFO PCAPInfo[32]; - -// on linux default to broadcast - -short udpport=0; - -unsigned int OurInst = 0; - -BOOL GotMsg; - -DWORD n; - -char Adapter[256]; - -static BOOL ReadConfigFile(int Port); -static int ProcessLine(char * buf,int Port, BOOL CheckPort); -int WritetoConsoleLocal(char * buff); - -int ExtProc(int fn, int port,unsigned char * buff) -{ - int len,txlen=0,res; - char txbuff[500]; - unsigned char rxbuff[1600]; - PCAPINFO * IF = &PCAPInfo[port]; - - if (IF->s == 0) - return 0; - - switch (fn) - { - case 1: // poll - - res = recvfrom(IF->s, rxbuff, ETH_FRAME_LEN, 0, NULL, NULL); - - if (res == -1) - { - if (errno == 11) - return 0; //Resource temporarily unavailable - - perror("Eth RX"); - return 0; - } - - if (res == 0) - /* Timeout elapsed */ - return 0; - - if (rxbuff[13] != 0xff) - return 0; - - if (IF->RLIRX) - - // RLI MODE - An extra 3 bytes before len, seem to be 00 00 41 - - { - len=rxbuff[18]*256 + rxbuff[17]; - - if ((len < 16) || (len > 320)) return 0; // Probably BPQ Mode Frame - - len-=3; - - memcpy(&buff[7],&rxbuff[19],len); - - len+=5; - } - else - { - len=rxbuff[15]*256 + rxbuff[14]; - - if ((len < 16) || (len > 320)) return 0; // Probably RLI Mode Frame - - len-=3; - - memcpy(&buff[7],&rxbuff[16],len); - - len+=5; - } - - buff[5]=(len & 0xff); - buff[6]=(len >> 8); - - return 1; - - - case 2: // send - - if (IF->RLITX) - - // RLI MODE - An extra 3 bytes before len, seem to be 00 00 41 - - { - txlen=(buff[6]<<8) + buff[5]; // BPQEther is DOS-based - chain word is 2 bytes - - txlen-=2; - txbuff[16]=0x41; - txbuff[17]=(txlen & 0xff); - txbuff[18]=(txlen >> 8); - - if (txlen < 1 || txlen > 400) - return 0; - - memcpy(&txbuff[19],&buff[7],txlen); - - } - else - { - txlen=(buff[6]<<8) + buff[5]; // BPQEther is DOS-based - chain word is 2 bytes - - txlen-=2; - - txbuff[14]=(txlen & 0xff); - txbuff[15]=(txlen >> 8); - - if (txlen < 1 || txlen > 400) - return 0; - - - memcpy(&txbuff[16],&buff[7],txlen); - } - - memcpy(&txbuff[0], &IF->EthDest[0],6); - memcpy(&txbuff[6], &IF->EthSource[0],6); - memcpy(&txbuff[12], &IF->EtherType,2); - - txlen+=14; - - if (txlen < 60) txlen = 60; - - // Send down the packet - - res = sendto(IF->s, txbuff, txlen, 0, - (const struct sockaddr *)&IF->socket_address, sizeof(struct sockaddr_ll)); - - if (res < 0) - { - perror("Eth Send"); - return 3; - } - -// if (tap_fd) -// write(tap_fd, txbuff, txlen); - - return (0); - - case 3: // CHECK IF OK TO SEND - - return (0); // OK - - case 4: // reinit - - return 0; - - case 5: // reinit - - return 0; - } - - return (0); -} - - -UINT ETHERExtInit(struct PORTCONTROL * PortEntry) -{ - // Can have multiple ports, each mapping to a different Ethernet Adapter - - // The Adapter number is in IOADDR - // - - int i=0; - u_int netmask; - char buf[256]; - int n; - struct ifreq ifr; - size_t if_name_len; - PCAPINFO * IF; - int port = PortEntry->PORTNUMBER; - u_long param=1; - struct ifreq buffer; - - WritetoConsoleLocal("BPQEther "); - - // - // Read config - // - - if (!ReadConfigFile(port)) - return (FALSE); - - if_name_len = strlen(Adapter); - - IF = &PCAPInfo[port]; - - IF->s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_BPQ)); - - if (IF->s == -1) - { - perror("Open Ether Socket"); - IF->s = 0; - } - else - { - ioctl(IF->s, FIONBIO, ¶m); - memcpy(ifr.ifr_name, Adapter, if_name_len); - ifr.ifr_name[if_name_len] = 0; - - if (ioctl(IF->s, SIOCGIFINDEX,&ifr) == -1) - perror("Get IF Number"); - - // Get MAC Address - - memset(&buffer, 0x00, sizeof(buffer)); - - strcpy(buffer.ifr_name, Adapter); - ioctl(IF->s, SIOCGIFHWADDR, &buffer); - memcpy(IF->EthSource, buffer.ifr_hwaddr.sa_data, 6); - } - - n=sprintf(buf,"Using %s = Interface %d\n", Adapter, ifr.ifr_ifindex); - WritetoConsoleLocal(buf); - - /*prepare sockaddr_ll*/ - - /*RAW communication*/ - IF->socket_address.sll_family = PF_PACKET; - - /*we don't use a protocoll above ethernet layer ->just use anything here*/ - IF->socket_address.sll_protocol = htons(ETH_P_IP); - - //index of the network device - - IF->socket_address.sll_ifindex = ifr.ifr_ifindex; - - /*ARP hardware identifier is ethernet*/ - IF->socket_address.sll_hatype = ARPHRD_ETHER; - - /*target is another host*/ - IF->socket_address.sll_pkttype = PACKET_BROADCAST; - - /*address length*/ - IF->socket_address.sll_halen = ETH_ALEN; - /*MAC - begin*/ - - memcpy(IF->socket_address.sll_addr, IF->EthDest, 6); - IF->socket_address.sll_addr[6] = 0x00;/*not used*/ - IF->socket_address.sll_addr[7] = 0x00;/*not used*/ - - -// n=sprintf(buf,"Using %s Adapter = Interface %d\r", ifr.ifr_ifindex); -// WritetoConsole(buf); - - return ((int) ExtProc); -} - - - -static BOOL ReadConfigFile(int Port) -{ -//TYPE 1 08FF # Ethernet Type -//ETH 1 FF:FF:FF:FF:FF:FF # Target Ethernet AddrMAP G8BPQ-7 10.2.77.1 # IP 93 for compatibility -//ADAPTER 1 \Device\NPF_{21B601E8-8088-4F7D-96 29-EDE2A9243CF4} # Adapter Name - - char buf[256],errbuf[256]; - char * Config; - - Config = PortConfig[Port]; - - PCAPInfo[Port].Promiscuous = 1; // Default - PCAPInfo[Port].EtherType=htons(0x08FF); // Default - memset(PCAPInfo[Port].EthDest, 0xff, 6); - - - if (Config) - { - // Using config from bpq32.cfg - - char * ptr1 = Config, * ptr2; - - ptr2 = strchr(ptr1, 13); - while(ptr2) - { - memcpy(buf, ptr1, ptr2 - ptr1); - buf[ptr2 - ptr1] = 0; - ptr1 = ptr2 + 2; - ptr2 = strchr(ptr1, 13); - - strcpy(errbuf,buf); // save in case of error - - if (!ProcessLine(buf, Port, FALSE)) - { - WritetoConsoleLocal("BPQEther - Bad config record "); - WritetoConsoleLocal(errbuf); - WritetoConsoleLocal("\n"); - } - } - return (TRUE); - } - - n=sprintf(buf,"No config info found in bpq32.cfg\n"); - WritetoConsoleLocal(buf); - - return (FALSE); -} - - -static int ProcessLine(char * buf, int Port, BOOL CheckPort) -{ - char * ptr; - char * p_port; - char * p_mac; - char * p_Adapter; - char * p_type; - - int port; - int a,b,c,d,e,f,num; - - ptr = strtok(buf, " \t\n\r"); - - if(ptr == NULL) return (TRUE); - - if(*ptr =='#') return (TRUE); // comment - - if(*ptr ==';') return (TRUE); // comment - - if (CheckPort) - { - p_port = strtok(NULL, " \t\n\r"); - - if (p_port == NULL) return (FALSE); - - port = atoi(p_port); - - if (Port != port) return TRUE; // Not for us - } - - if(_stricmp(ptr,"ADAPTER") == 0) - { - p_Adapter = strtok(NULL, " \t\n\r"); - - strcpy(Adapter,p_Adapter); - return (TRUE); - } - - if(_stricmp(ptr,"TYPE") == 0) - { - p_type = strtok(NULL, " \t\n\r"); - - if (p_type == NULL) return (FALSE); - - num=sscanf(p_type,"%x",&a); - - if (num != 1) return FALSE; - - PCAPInfo[Port].EtherType=htons(a); - return (TRUE); - - } - - if(_stricmp(ptr,"promiscuous") == 0) - { - ptr = strtok(NULL, " \t\n\r"); - - if (ptr == NULL) return (FALSE); - - PCAPInfo[Port].Promiscuous = atoi(ptr); - - return (TRUE); - - } - - if(_stricmp(ptr,"RXMODE") == 0) - { - p_port = strtok(NULL, " \t\n\r"); - - if (p_port == NULL) return (FALSE); - - if(_stricmp(p_port,"RLI") == 0) - { - PCAPInfo[Port].RLIRX=TRUE; - return (TRUE); - } - - if(_stricmp(p_port,"BPQ") == 0) - { - PCAPInfo[Port].RLIRX=FALSE; - return (TRUE); - } - - return FALSE; - - } - - if(_stricmp(ptr,"TXMODE") == 0) - { - p_port = strtok(NULL, " \t\n\r"); - - if (p_port == NULL) return (FALSE); - - if(_stricmp(p_port,"RLI") == 0) - { - PCAPInfo[Port].RLITX=TRUE; - return (TRUE); - } - - if(_stricmp(p_port,"BPQ") == 0) - { - PCAPInfo[Port].RLITX=FALSE; - return (TRUE); - } - - return FALSE; - - } - - if(_stricmp(ptr,"DEST") == 0) - { - p_mac = strtok(NULL, " \t\n\r"); - - if (p_mac == NULL) return (FALSE); - - num=sscanf(p_mac,"%x-%x-%x-%x-%x-%x",&a,&b,&c,&d,&e,&f); - - if (num != 6) return FALSE; - - PCAPInfo[Port].EthDest[0]=a; - PCAPInfo[Port].EthDest[1]=b; - PCAPInfo[Port].EthDest[2]=c; - PCAPInfo[Port].EthDest[3]=d; - PCAPInfo[Port].EthDest[4]=e; - PCAPInfo[Port].EthDest[5]=f; - - - // strcpy(Adapter,p_Adapter); - - return (TRUE); - } - - if(_stricmp(ptr,"SOURCE") == 0) // not used, but ignore - return (TRUE); - - // - // Bad line - // - return (FALSE); - -} - diff --git a/rigcontrol.h b/rigcontrol.h index e762ea4..2868704 100644 --- a/rigcontrol.h +++ b/rigcontrol.h @@ -74,10 +74,11 @@ struct RIGINFO int ICF8101; // ICOM Land Mobile IC-F8101 char * CM108Device; // Device to open for CM108 GPIO PTT - struct _EXTPORTDATA * PortRecord[32]; // BPQ32 port record(s) for this rig (null terminated list) + struct _EXTPORTDATA * PortRecord[64]; // BPQ32 port record(s) for this rig (null terminated list) UCHAR RigAddr; - uint64_t ScanStopped; // Scanning enabled if zero. Bits used for interlocked scanning (eg winmor/pactor on same port + int Channel; // For sdrangel + uint64_t ScanStopped; // Scanning enabled if zero. Bits used for interlocked scanning (eg winmor/pactor on same port int ScanCounter; int PollCounter; // Don't poll too often; int ScanFreq; // Scan Rate @@ -198,6 +199,9 @@ struct RIGINFO #define RTLUDP 16 #define FLRIG 17 #define SDRRADIO 18 +//G7TAJ +#define SDRANGEL 19 +//G7TAJ // Yease seem to have lots of variants of the same model @@ -234,7 +238,9 @@ struct RIGPORTINFO HANDLE hPTTDevice; // May use a different port for PTT UCHAR TXBuffer[500]; // Last message sent - saved for Retry int TXLen; // Len of last sent - UCHAR RXBuffer[500]; // Message being received - may not arrive all at once +// ---- G7TAJ ---- + UCHAR RXBuffer[8192]; // Message being received - may not arrive all at once. SDRANGLE needs a lot +// ---- G7TAJ ---- int RXLen; // Data in RXBUffer BOOL AutoPoll; // set if last command was a Timer poll // Local ScanStruct for Interactive Commands diff --git a/templatedefs.c b/templatedefs.c index 4dba3d7..72f1c8b 100644 --- a/templatedefs.c +++ b/templatedefs.c @@ -420,6 +420,7 @@ char * MainConfigtxt() "" "