diff --git a/APRSCode.c b/APRSCode.c index 468b00f..6734ff2 100644 --- a/APRSCode.c +++ b/APRSCode.c @@ -241,6 +241,7 @@ char SYMSET = '/'; BOOL TraceDigi = FALSE; // Add Trace to packets relayed on Digi Calls BOOL SATGate = FALSE; // Delay Gating to IS directly heard packets +BOOL RXOnly = FALSE; // Run as RX only IGATE, ie don't gate anything to RF BOOL DefaultLocalTime = FALSE; BOOL DefaultDistKM = FALSE; @@ -1272,7 +1273,7 @@ Dll VOID APIENTRY Poll_APRS() || memcmp(AdjBuff->ORIGIN, axRFONLY, 6) == 0 || DigisUsed > MaxDigisforIS) - // TOo many digis or Last digis is NOGATE or RFONLY - dont send to IS + // Too many digis or Last digis is NOGATE or RFONLY - dont send to IS NoGate = TRUE; } @@ -1418,7 +1419,7 @@ Dll VOID APIENTRY Poll_APRS() MH->IGate = TRUE; // if we've seen msgs to TCPIP, it must be an Igate } - if (NoGate) + if (NoGate || RXOnly) goto NoIS; // I think all PID F0 UI frames go to APRS-IS, @@ -1452,7 +1453,23 @@ Dll VOID APIENTRY Poll_APRS() if (APRSISOpen && CrossPortMap[Port][0]) // No point if not open { -// was done above len = sprintf(ISMsg, "%s>%s,qAR,%s:%s", ptr1, ptr4, APRSCall, Payload); + // was done above len = sprintf(ISMsg, "%s>%s,qAR,%s:%s", ptr1, ptr4, APRSCall, Payload); + + if (BeacontoIS == 0) + { + // Don't send anything we've received as an echo + + char SaveCall[7]; + memcpy(SaveCall, &monbuff->ORIGIN, 7); + SaveCall[6] &= 0x7e; // Mask End of address bit + + if (memcmp(SaveCall, AXCall, 7) == 0) // We sent it + { + // Should we check for being received via digi? - not for now + + goto NoIS; + } + } if (SATGate && (DigisUsed == 0)) { @@ -1471,7 +1488,7 @@ Dll VOID APIENTRY Poll_APRS() } ISSend(sock, ISMsg, len, 0); - + ptr1 = strchr(ISMsg, 13); if (ptr1) *ptr1 = 0; // Debugprintf(">%s", ISMsg); @@ -1988,6 +2005,12 @@ static int APRSProcessLine(char * buf) return TRUE; } + if (_stricmp(ptr, "RXOnly") == 0) + { + RXOnly = TRUE; + return TRUE; + } + if (_stricmp(ptr, "DISTKM") == 0) { DefaultDistKM = TRUE; @@ -2794,7 +2817,7 @@ VOID SendIStatus() IStatusCounter = 3600; // One per hour - if (APRSISOpen && BeacontoIS) + if (APRSISOpen && BeacontoIS && RXOnly == 0) { Msg.PID = 0xf0; Msg.CTL = 3; @@ -3740,7 +3763,7 @@ void PollGPSIn() GPSMsg[len] = 0; if (Check0183CheckSum(GPSMsg, len)) - if (memcmp(&GPSMsg[1], "GPRMC", 5) == 0) + if (memcmp(&GPSMsg[3], "RMC", 3) == 0) DecodeRMC(GPSMsg, len); portptr->gpsinptr -= (int)len; // bytes left @@ -4174,7 +4197,7 @@ static VOID ProcessReceivedData(SOCKET TCPSock) } else { - if (memcmp(UDPMsg, "$GPRMC", 6) == 0) + if (memcmp(&UDPMsg[3], "RMC", 3) == 0) DecodeRMC(UDPMsg, Len); else if (memcmp(UDPMsg, "!AIVDM", 6) == 0) diff --git a/BBSUtilities.c b/BBSUtilities.c index 4d04579..0bf600b 100644 --- a/BBSUtilities.c +++ b/BBSUtilities.c @@ -43,6 +43,9 @@ RECT ConsoleRect; BOOL OpenConsole; BOOL OpenMon; +int reportNewMesageEvents = 0; + + extern struct ConsoleInfo BBSConsole; extern char LOC[7]; @@ -199,6 +202,14 @@ 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 @@ -4796,7 +4807,7 @@ char * ReadInfoFile(char * File) FILE * hFile; char * MsgBytes; struct stat STAT; - char * ptr1 = 0; + char * ptr1 = 0, * ptr2; sprintf_s(MsgFile, sizeof(MsgFile), "%s/%s", BaseDir, File); @@ -4816,13 +4827,20 @@ char * ReadInfoFile(char * File) fclose(hFile); - MsgBytes[FileSize]=0; + MsgBytes[FileSize] = 0; -#ifndef WIN32 + ptr1 = MsgBytes; - // Replace LF with CR + // Replace LF or CRLF with CR - // Remove lf chars + // First remove cr from crlf + + while(ptr2 = strstr(ptr1, "\r\n")) + { + memmove(ptr2, ptr2 + 1, strlen(ptr2)); + } + + // Now replace lf with cr ptr1 = MsgBytes; @@ -4833,7 +4851,6 @@ char * ReadInfoFile(char * File) ptr1++; } -#endif return MsgBytes; } @@ -6295,6 +6312,33 @@ nextline: 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); diff --git a/BPQChat.vcproj b/BPQChat.vcproj index 0baae76..c3b8993 100644 --- a/BPQChat.vcproj +++ b/BPQChat.vcproj @@ -357,18 +357,6 @@ Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > - - - - - - OutputQueue == NULL) - { - // Nothing to send. If Close after Flush is set, disconnect - - if (conn->CloseAfterFlush) - { - conn->CloseAfterFlush--; - - if (conn->CloseAfterFlush) - return; - - Disconnect(conn->BPQStream); - } - - return; // Nothing to send - } - tosend = conn->OutputQueueLength - conn->OutputGetPointer; - - sent=0; - - while (tosend > 0) - { - if (TXCount(conn->BPQStream) > 4) - return; // Busy - - if (tosend <= conn->paclen) - len=tosend; - else - len=conn->paclen; - - GetSemaphore(&OutputSEM, 0); - - SendUnbuffered(conn->BPQStream, &conn->OutputQueue[conn->OutputGetPointer], len); - - conn->OutputGetPointer+=len; - - FreeSemaphore(&OutputSEM); - - tosend-=len; - sent++; - - if (sent > 4) - return; - } - - // All Sent. Free buffers and reset pointers - - ChatClearQueue(conn); -} - -VOID ChatClearQueue(ChatCIRCUIT * conn) -{ - GetSemaphore(&OutputSEM, 0); - - conn->OutputGetPointer=0; - conn->OutputQueueLength=0; - - FreeSemaphore(&OutputSEM); -} - /* char * FormatDateAndTime(time_t Datim, BOOL DateOnly) { diff --git a/Cmd.c b/Cmd.c index 71fbd11..31dd130 100644 --- a/Cmd.c +++ b/Cmd.c @@ -169,6 +169,9 @@ VOID FLMSG(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * Us 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, ...) { @@ -4205,6 +4208,7 @@ CMDX COMMANDS[] = "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, @@ -5496,6 +5500,93 @@ BOOL isSYSOP(TRANSPORTENTRY * Session, char * Bufferptr) 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/CommonCode.c b/CommonCode.c index a60f4fe..c2f6e75 100644 --- a/CommonCode.c +++ b/CommonCode.c @@ -2407,9 +2407,6 @@ HANDLE OpenCOMPort(VOID * pPort, int speed, BOOL SetDTR, BOOL SetRTS, BOOL Quiet struct termios term; struct speed_struct *s; - // As Serial ports under linux can have all sorts of odd names, the code assumes that - // they are symlinked to a com1-com255 in the BPQ Directory (normally the one it is started from - if ((UINT)pPort < 256) sprintf(Port, "%s/com%d", BPQDirectory, (int)pPort); else diff --git a/HanksRT.c b/HanksRT.c index 7885c11..d01852b 100644 --- a/HanksRT.c +++ b/HanksRT.c @@ -118,9 +118,71 @@ time_t RunningConnectScript = 0; //#define free(p) +struct HistoryRec * History = NULL; +int HistoryCount = 0; + + typedef int (WINAPI FAR *FARPROCX)(); extern FARPROCX pRunEventProgram; +int AddtoHistory(struct user_t * user, char * text) +{ + struct HistoryRec * Rec; + struct HistoryRec * ptr; + int n = 1; + char buf[512]; + char Stamp[16]; + struct tm * tm; + time_t Now = time(NULL); + + // Don't want to grow indefinitely and fill memory. We only allow display upt 24 hours back, so if first record is older that that + // remove and reuse it + + if (History && History->Time < Now - 86400) + { + Rec = History; + History = Rec->next; // Remove from front of chain + } + else + Rec = malloc(sizeof (struct HistoryRec)); + + memset(Rec, 0, sizeof (struct HistoryRec)); + + tm = gmtime(&Now); + + sprintf(Stamp,"%02d:%02d ", tm->tm_hour, tm->tm_min); + sprintf(buf, "%s%-6.6s %s %c %s\r", Stamp, user->call, user->name, ':', text); + + Rec->Time = Now; + + Rec->Topic = _strdup(user->topic->name); + Rec->Message = _strdup(buf); + + if (History == NULL) + History = Rec; + + else + { + ptr = History; + + while (ptr && ptr->next) + { + n++; + ptr = ptr->next; + } + + n++; + ptr->next = Rec; + } + + return n; +} + + + + + + int ChatIsUTF8(unsigned char *ptr, int len) { int n; @@ -221,7 +283,6 @@ VOID * _zalloc_dbg(int len, int type, char * file, int line) return ptr; } - #endif VOID __cdecl nprintf(ChatCIRCUIT * conn, const char * format, ...) @@ -268,22 +329,18 @@ int ChatQueueMsg(ChatCIRCUIT * conn, char * msg, int len) // 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. + // int OutputGetPointer; // Next byte to send. When Getpointer = Queue Length all is sent - free the buffer and start again. // Create or extend buffer GetSemaphore(&OutputSEM, 0); - if (conn->OutputQueueLength + len > 9999) + while (conn->OutputQueueLength + len > conn->OutputQueueSize) { - Debugprintf("Output Queue Overflow %d", conn->OutputQueueLength); + // Extend Queue - // Shouldn't clear buffer as this will corrupt any partly recevied message - just drop it - -// conn->OutputQueueLength = 0; -// conn->OutputGetPointer = 0; - FreeSemaphore(&OutputSEM); - return 0; // or we will send a partial message + conn->OutputQueueSize += 4096; + conn->OutputQueue = realloc(conn->OutputQueue, conn->OutputQueueSize); } memcpy(&conn->OutputQueue[conn->OutputQueueLength], msg, len); @@ -702,6 +759,52 @@ VOID ProcessChatLine(ChatCIRCUIT * conn, struct UserInfo * user, char* OrigBuffe return; } + if (_memicmp(&Buffer[1], "History", 7) == 0) + { + // Param is number of minutes to go back (max 24 hours) + + struct HistoryRec * ptr = History; + int interval = atoi(&Buffer[9]) * 60; + time_t start = time(NULL) - interval; + int n = HistoryCount; + + if (interval < 1) + { + nprintf(conn, "Format is /history n, where n is history time in minutes\r"); + conn->u.user->lastsendtime = time(NULL); + return; + } + + if (interval > 1440) + { + nprintf(conn, "History is only held for 24 Hours (1440 Minutes)\r"); + interval = 1440; // Limit to 1 day + } + + // Find first record to send + + while (ptr) + { + if (ptr->Time > start) + break; + n--; + ptr = ptr->next; + } + + // n is records found + + while (ptr) + { + nprintf(conn, ptr->Message); + ptr = ptr->next; + } + + conn->u.user->lastsendtime = time(NULL); + return; + } + + + if (_memicmp(&Buffer[1], "Keepalive", 4) == 0) { conn->u.user->rtflags ^= u_keepalive; @@ -843,6 +946,8 @@ VOID ProcessChatLine(ChatCIRCUIT * conn, struct UserInfo * user, char* OrigBuffe text_tellu(conn->u.user, Buffer, NULL, o_topic); // To local users. + HistoryCount = AddtoHistory(conn->u.user, Buffer); + conn->u.user->lastrealmsgtime = conn->u.user->lastmsgtime = time(NULL); // Send to Linked nodes @@ -2938,6 +3043,7 @@ int rt_cmd(ChatCIRCUIT *circuit, char * Buffer) nputs(circuit, "/S CALL Text - Send Text to that station only.\r"); nputs(circuit, "/F - Force all links to be made.\r/K - Show Known nodes.\r"); nputs(circuit, "/B - Leave Chat and return to node.\r/QUIT - Leave Chat and disconnect from node.\r"); + nputs(circuit, "/History nn - Display chat messages received in last nn minutes.\r"); } } return TRUE; @@ -4165,6 +4271,7 @@ BOOL ChatInit() return TRUE; } +#endif void ChatFlush(ChatCIRCUIT * conn) { @@ -4181,22 +4288,6 @@ void ChatFlush(ChatCIRCUIT * conn) // 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); - } - - return; // Nothing to send - } tosend = conn->OutputQueueLength - conn->OutputGetPointer; sent = 0; @@ -4233,9 +4324,6 @@ void ChatFlush(ChatCIRCUIT * conn) VOID ChatClearQueue(ChatCIRCUIT * conn) { - if (conn->OutputQueue == NULL) - return; - GetSemaphore(&OutputSEM, 0); conn->OutputGetPointer = 0; @@ -4244,6 +4332,7 @@ VOID ChatClearQueue(ChatCIRCUIT * conn) FreeSemaphore(&OutputSEM); } +#ifdef LINBPQ void ChatTrytoSend() { // call Flush on any connected streams with queued data diff --git a/RTKnown.txt b/RTKnown.txt index 2e0220a..74d3f7d 100644 --- a/RTKnown.txt +++ b/RTKnown.txt @@ -1,25 +1,26 @@ -G8BPQ-1 1661431645 -GM8BPQ-4 1661431604 -OH5RM-8 1661431604 -G0BMH-4 1661431604 -AE5E-2 1661431604 -MS0HFI-4 1661431604 -PE1RRR-4 1661431604 -WA3WLH-14 1661431604 -WA3WLH-11 1661431604 -W9IKU-11 1661431604 -N2UEM-11 1661431604 -K5DAT-11 1661431604 -N3MEL-3 1661431604 -N0NJY-11 1661431604 -KB9PVH-11 1661431604 -K8OPG-14 1661431604 -PI1LAP-4 1661431604 -PE1NNZ-5 1661431604 -IZ4FVW-10 1661431604 -EI2GYB-4 1661431604 -G8BPQ-4 1661431604 -W8BAP-6 1661431604 -KF8MZ-6 1661431604 -N8BHL-6 1661431604 -KB8UVN-6 1661431604 +G8BPQ-1 1669106746 +GM8BPQ-3 1669106749 +KB8UVN-6 1669106746 +N8BHL-6 1669106746 +KF8MZ-6 1669106746 +W8BAP-6 1669106746 +G8BPQ-4 1669106746 +EI2GYB-4 1669106746 +IZ4FVW-10 1669106746 +PE1NNZ-5 1669106746 +PI1LAP-4 1669106746 +K8OPG-14 1669106746 +KB9PVH-11 1669106746 +N0NJY-11 1669106746 +N3MEL-3 1669106746 +K5DAT-11 1669106746 +N2UEM-11 1669106746 +W9IKU-11 1669106746 +WA3WLH-11 1669106746 +WA3WLH-14 1669106746 +PE1RRR-4 1669106746 +MS0HFI-4 1669106746 +AE5E-2 1669106746 +G0BMH-4 1669106746 +OH5RM-8 1669106746 +GM8BPQ-4 1669106746 diff --git a/Versions.h b/Versions.h index cdb6ac8..00b0edd 100644 --- a/Versions.h +++ b/Versions.h @@ -10,8 +10,8 @@ #endif -#define KVers 6,0,23,27 -#define KVerstring "6.0.23.27\0" +#define KVers 6,0,23,29 +#define KVerstring "6.0.23.29\0" #ifdef CKernel diff --git a/bpqchat.c b/bpqchat.c index fe3c3d0..904a5dd 100644 --- a/bpqchat.c +++ b/bpqchat.c @@ -63,7 +63,7 @@ // Restore CMD_TO_APPL flag to Applflags (13) // Check for and remove names set to *RTL // Add option to run user program when chat user connects (27) - +// Add History (28) #include "BPQChat.h" #include "Dbghelp.h" diff --git a/bpqchat.h b/bpqchat.h index 69cfb47..db46fd3 100644 --- a/bpqchat.h +++ b/bpqchat.h @@ -400,11 +400,10 @@ typedef struct ChatConnectionInfo_S // and data sucked out under both terminal and system flow control. PACLEN is // enfored when sending to node. - UCHAR OutputQueue[10000]; // Messages to user - int OutputQueueLength; // Total Malloc'ed size. Also Put Pointer for next Message + UCHAR * OutputQueue; // Messages to user + int OutputQueueSize; // Total Malloc'ed size. + int OutputQueueLength; // 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. BOOL sysop; // Set if user is authenticated as a sysop BOOL Secure_Session; // Set if Local Terminal, or Telnet connect with SYSOP status @@ -550,6 +549,16 @@ struct ConsoleInfo }; +struct HistoryRec +{ + struct HistoryRec * next; + time_t Time; + char * Topic; + char * Message; +}; + +extern struct HistoryRec * History; +extern int HistoryCount; extern USER *user_hd; diff --git a/chatconfig.cfg b/chatconfig.cfg index cfd3942..9a144ca 100644 --- a/chatconfig.cfg +++ b/chatconfig.cfg @@ -14,9 +14,9 @@ Chat : WrapInput = 0; FlashOnConnect = 0; CloseWindowOnBye = 0; - ConsoleSize = "122,930,359,969"; + ConsoleSize = "821,1629,283,893"; MonitorSize = "828,1644,148,770"; DebugSize = "0,0,0,0"; - WindowSize = "608,1212,163,511"; - Version = "6,0,23,16"; + WindowSize = "714,1318,165,513"; + Version = "6,0,23,28"; };