linbpq/ChatUtils.c

759 lines
16 KiB
C
Raw Permalink Normal View History

2022-08-28 09:35:46 +01:00
// Chat Server for BPQ32 Packet Switch
//
//
// Based on MailChat Version 1.4.48.1
#define _CRT_SECURE_NO_DEPRECATE
#include "BPQChat.h"
#include <new.h>
#define MaxSockets 64
extern ChatCIRCUIT ChatConnections[MaxSockets+1];
extern int NumberofChatStreams;
extern char ChatConfigName[MAX_PATH];
extern char Session[20];
2023-10-10 22:07:04 +01:00
extern int chatPaclen;
2022-08-28 09:35:46 +01:00
extern struct SEM ChatSemaphore;
extern struct SEM AllocSemaphore;
extern struct SEM ConSemaphore;
extern struct SEM OutputSEM;
extern char OtherNodesList[1000];
extern int MaxChatStreams;
extern char Position[81];
extern char PopupText[260];
extern int PopupMode;
extern int Bells, FlashOnBell, StripLF, WarnWrap, WrapInput, FlashOnConnect, CloseWindowOnBye;
extern char Version[32];
extern char ConsoleSize[32];
extern char MonitorSize[32];
extern char DebugSize[32];
extern char WindowSize[32];
extern int RunningConnectScript;
INT_PTR CALLBACK InfoDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
int GetMultiLineDialog(HWND hDialog, int DLGItem);
BOOL ProcessChatConnectScript(ChatCIRCUIT * conn, char * Buffer, int len);
2022-11-18 17:03:39 +00:00
VOID WriteMiniDump();
2022-08-28 09:35:46 +01:00
int Connected(int Stream)
{
int n;
ChatCIRCUIT * conn;
struct UserInfo * user = NULL;
char callsign[10];
int port, paclen, maxframe, l4window;
char ConnectedMsg[] = "*** CONNECTED ";
char Msg[100];
LINK *link;
KNOWNNODE *node;
for (n = 0; n < NumberofChatStreams; n++)
{
conn = &ChatConnections[n];
if (Stream == conn->BPQStream)
{
if (conn->Active)
{
// Probably an outgoing connect
if (conn->rtcflags == p_linkini)
{
2023-10-10 22:07:04 +01:00
conn->paclen = chatPaclen;
2022-08-28 09:35:46 +01:00
// Run first line of connect script
ProcessChatConnectScript(conn, ConnectedMsg, 15);
return 0;
// nprintf(conn, "c %s\r", conn->u.link->call);
}
return 0;
}
memset(conn, 0, sizeof(ChatCIRCUIT)); // Clear everything
conn->Active = TRUE;
conn->BPQStream = Stream;
conn->Secure_Session = GetConnectionInfo(Stream, callsign,
&port, &conn->SessType, &paclen, &maxframe, &l4window);
2023-10-10 22:07:04 +01:00
if (paclen > chatPaclen || paclen == 0)
paclen = chatPaclen;
2022-08-28 09:35:46 +01:00
2023-10-10 22:07:04 +01:00
conn->paclen = paclen;
2022-08-28 09:35:46 +01:00
strlop(callsign, ' '); // Remove trailing spaces
memcpy(conn->Callsign, callsign, 10);
strlop(callsign, '-'); // Remove any SSID
user = zalloc(sizeof(struct UserInfo));
strcpy(user->Call, callsign);
conn->UserPointer = user;
n=sprintf_s(Msg, sizeof(Msg), "Incoming Connect from %s", user->Call);
// Send SID and Prompt
ChatWriteLogLine(conn, '|',Msg, n, LOG_CHAT);
conn->Flags |= CHATMODE;
nodeprintf(conn, ChatSID, Ver[0], Ver[1], Ver[2], Ver[3]);
// See if from a defined node
for (link = link_hd; link; link = link->next)
{
if (matchi(conn->Callsign, link->call))
{
conn->rtcflags = p_linkwait;
return 0; // Wait for *RTL
}
}
// See if from a previously known node
// I'm not sure this is safe. If it really is from a node the *RTL will be rejected
// Actually this protects against repeated attempts from a node that isn't configured. Maybe leave as is
node = knownnode_find(conn->Callsign);
if (node)
{
// A node is trying to link, but we don't have it defined - close
Logprintf(LOG_CHAT, conn, '!', "Node %s connected, but is not defined as a Node - closing",
conn->Callsign);
nodeprintf(conn, "Node %s does not have %s defined as a node to link to - closing.\r",
OurNode, conn->Callsign);
ChatFlush(conn);
Sleep(500);
conn->rtcflags = p_nil;
Disconnect(conn->BPQStream);
return 0;
}
if (user->Name[0] == 0)
{
char * Name = lookupuser(user->Call);
if (Name)
{
if (strlen(Name) > 17)
Name[17] = 0;
strcpy(user->Name, Name);
free(Name);
}
else
{
conn->Flags |= GETTINGUSER;
nputs(conn, NewUserPrompt);
return TRUE;
}
}
SendWelcomeMsg(Stream, conn, user);
RefreshMainWindow();
ChatFlush(conn);
return 0;
}
}
return 0;
}
int Disconnected (int Stream)
{
struct UserInfo * user = NULL;
ChatCIRCUIT * conn;
int n;
char Msg[255];
int len;
struct _EXCEPTION_POINTERS exinfo;
for (n = 0; n <= NumberofChatStreams-1; n++)
{
conn=&ChatConnections[n];
if (Stream == conn->BPQStream)
{
if (conn->Active == FALSE)
{
return 0;
}
ChatClearQueue(conn);
conn->Active = FALSE;
if (conn->Flags & CHATMODE)
{
if (conn->Flags & CHATLINK && conn->u.link)
{
// if running connect script, clear script active
if (conn->u.link->flags & p_linkini)
{
RunningConnectScript = 0;
conn->u.link->scriptRunning = 0;
}
len = sprintf_s(Msg, sizeof(Msg), "Chat Node %s Disconnected", conn->u.link->call);
ChatWriteLogLine(conn, '|',Msg, len, LOG_CHAT);
__try {link_drop(conn);} My__except_Routine("link_drop");
}
else
{
len=sprintf_s(Msg, sizeof(Msg), "Chat User %s Disconnected", conn->Callsign);
ChatWriteLogLine(conn, '|',Msg, len, LOG_CHAT);
__try
{
logout(conn);
}
#define EXCEPTMSG "logout"
#include "StdExcept.c"
}
}
conn->Flags = 0;
conn->u.link = NULL;
conn->UserPointer = NULL;
}
// RefreshMainWindow();
return 0;
}
}
return 0;
}
int DoReceivedData(int Stream)
{
int count, InputLen;
UINT MsgLen;
int n;
ChatCIRCUIT * conn;
struct UserInfo * user;
char * ptr, * ptr2;
char Buffer[10000];
int Written;
for (n = 0; n < NumberofChatStreams; n++)
{
conn = &ChatConnections[n];
if (Stream == conn->BPQStream)
{
do
{
// May have several messages per packet, or message split over packets
if (conn->InputLen + 1000 > 10000) // Shouldnt have lines longer than this in text mode
conn->InputLen = 0; // discard
GetMsg(Stream, &conn->InputBuffer[conn->InputLen], &InputLen, &count);
if (InputLen == 0) return 0;
if (conn->DebugHandle) // Receiving a Compressed Message
WriteFile(conn->DebugHandle, &conn->InputBuffer[conn->InputLen],
InputLen, &Written, NULL);
conn->Watchdog = 900; // 15 Minutes
conn->InputLen += InputLen;
{
loop:
if (conn->InputLen == 1 && conn->InputBuffer[0] == 0) // Single Null
{
conn->InputLen = 0;
if (conn->u.user->circuit && conn->u.user->circuit->rtcflags & p_user) // Local User
conn->u.user->lastmsgtime = time(NULL);
return 0;
}
ptr = memchr(conn->InputBuffer, '\r', conn->InputLen);
if (ptr) // CR in buffer
{
user = conn->UserPointer;
ptr2 = &conn->InputBuffer[conn->InputLen];
if (++ptr == ptr2)
{
// Usual Case - single meg in buffer
__try
{
if (conn->rtcflags == p_linkini) // Chat Connect
ProcessChatConnectScript(conn, conn->InputBuffer, conn->InputLen);
else
ProcessLine(conn, user, conn->InputBuffer, conn->InputLen);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
conn->InputBuffer[conn->InputLen] = 0;
Debugprintf("CHAT *** Program Error Processing input %s ", conn->InputBuffer);
Disconnect(conn->BPQStream);
conn->InputLen=0;
CheckProgramErrors();
return 0;
}
conn->InputLen=0;
}
else
{
// buffer contains more that 1 message
MsgLen = conn->InputLen - (ptr2-ptr);
memcpy(Buffer, conn->InputBuffer, MsgLen);
__try
{
if (conn->rtcflags == p_linkini)
ProcessChatConnectScript(conn, Buffer, MsgLen);
else
ProcessLine(conn, user, Buffer, MsgLen);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
Buffer[MsgLen] = 0;
Debugprintf("CHAT *** Program Error Processing input %s ", Buffer);
Disconnect(conn->BPQStream);
conn->InputLen=0;
CheckProgramErrors();
return 0;
}
if (*ptr == 0 || *ptr == '\n')
{
/// CR LF or CR Null
ptr++;
conn->InputLen--;
}
memmove(conn->InputBuffer, ptr, conn->InputLen-MsgLen);
conn->InputLen -= MsgLen;
goto loop;
}
}
else
{
// no cr - testing..
// Debugprintf("Test");
}
}
} while (count > 0);
return 0;
}
}
// Socket not found
return 0;
}
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 SendWelcomeMsg(int Stream, ChatCIRCUIT * conn, struct UserInfo * user)
{
if (!rtloginu (conn, TRUE))
{
// Already connected - close
ChatFlush(conn);
Sleep(1000);
Disconnect(conn->BPQStream);
}
return;
}
VOID SendPrompt(ChatCIRCUIT * conn, struct UserInfo * user)
{
nodeprintf(conn, "de %s>\r", OurNode);
}
VOID ProcessLine(ChatCIRCUIT * conn, struct UserInfo * user, char* Buffer, int len)
{
char seps[] = " \t\r";
struct _EXCEPTION_POINTERS exinfo;
{
GetSemaphore(&ChatSemaphore, 0);
__try
{
ProcessChatLine(conn, user, Buffer, len);
}
#define EXCEPTMSG "ProcessChatLine"
#include "StdExcept.c"
FreeSemaphore(&ChatSemaphore);
if (conn->BPQStream < 0)
CloseConsole(conn->BPQStream);
else
Disconnect(conn->BPQStream);
return;
}
FreeSemaphore(&ChatSemaphore);
return;
}
// Send if possible
ChatFlush(conn);
}
VOID SendUnbuffered(int stream, char * msg, int len)
{
if (stream < 0)
WritetoConsoleWindow(stream, msg, len);
else
SendMsg(stream, msg, len);
}
void TrytoSend()
{
// call Flush on any connected streams with queued data
ChatCIRCUIT * conn;
struct ConsoleInfo * Cons;
int n;
for (n = 0; n < NumberofChatStreams; n++)
{
conn = &ChatConnections[n];
if (conn->Active == TRUE)
ChatFlush(conn);
}
for (Cons = ConsHeader[0]; Cons; Cons = Cons->next)
{
if (Cons->Console)
ChatFlush(Cons->Console);
}
}
/*
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;
}
*/
VOID FreeList(char ** Hddr)
{
VOID ** Save;
if (Hddr)
{
Save = Hddr;
while(Hddr[0])
{
free(Hddr[0]);
Hddr++;
}
free(Save);
}
}
#define LIBCONFIG_STATIC
#include "libconfig.h"
2023-06-21 08:21:04 +01:00
static config_t cfg;
static config_setting_t * group;
2022-08-28 09:35:46 +01:00
extern char ChatWelcomeMsg[1000];
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 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);
}
int GetIntValue(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;
}
return FALSE;
}
BOOL GetChatConfig(char * ConfigName)
{
config_init(&cfg);
/* Read the file. If there is an error, report it and exit. */
if(! config_read_file(&cfg, ConfigName))
{
fprintf(stderr, "%d - %s\n",
config_error_line(&cfg), config_error_text(&cfg));
config_destroy(&cfg);
return(EXIT_FAILURE);
}
group = config_lookup (&cfg, "Chat");
if (group == NULL)
return EXIT_FAILURE;
ChatApplNum = GetIntValue(group, "ApplNum", 0);
MaxChatStreams = GetIntValue(group, "MaxStreams", 0);
GetStringValue(group, "OtherChatNodes", OtherNodesList);
GetStringValue(group, "ChatWelcomeMsg", ChatWelcomeMsg);
GetStringValue(group, "MapPosition", Position);
GetStringValue(group, "MapPopup", PopupText);
PopupMode = GetIntValue(group, "PopupMode", 0);
Bells = GetIntValue(group, "Bells", 0);
FlashOnBell = GetIntValue(group, "FlashOnBell",0 );
StripLF = GetIntValue(group, "StripLF", 0);
WarnWrap = GetIntValue(group, "WarnWrap", 0);
WrapInput = GetIntValue(group, "WrapInput",0 );
FlashOnConnect = GetIntValue(group, "FlashOnConnect", 0);
CloseWindowOnBye = GetIntValue(group, "CloseWindowOnBye", 0);
GetStringValue(group, "ConsoleSize", ConsoleSize);
GetStringValue(group, "MonitorSize", MonitorSize);
GetStringValue(group, "DebugSize", DebugSize);
GetStringValue(group, "WindowSize", WindowSize);
GetStringValue(group, "Version", Version);
return EXIT_SUCCESS;
}
VOID SaveChatConfigFile(char * File)
{
config_setting_t *root, *group;
// Get rid of old config before saving
config_init(&cfg);
root = config_root_setting(&cfg);
group = config_setting_add(root, "Chat", CONFIG_TYPE_GROUP);
SaveIntValue(group, "ApplNum", ChatApplNum);
SaveIntValue(group, "MaxStreams", MaxChatStreams);
SaveStringValue(group, "OtherChatNodes", OtherNodesList);
SaveStringValue(group, "ChatWelcomeMsg", ChatWelcomeMsg);
SaveStringValue(group, "MapPosition", Position);
SaveStringValue(group, "MapPopup", PopupText);
SaveIntValue(group, "PopupMode", PopupMode);
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);
SaveStringValue(group, "ConsoleSize", ConsoleSize);
SaveStringValue(group, "MonitorSize", MonitorSize);
SaveStringValue(group, "DebugSize", DebugSize);
SaveStringValue(group, "WindowSize",WindowSize );
SaveStringValue(group, "Version",Version );
if(! config_write_file(&cfg, File))
{
fprintf(stderr, "Error while writing file.\n");
config_destroy(&cfg);
return;
}
config_destroy(&cfg);
}
VOID SaveChatConfig(HWND hDlg)
{
BOOL OK1;
HKEY hKey=0;
int OldChatAppl;
char * ptr1;
char * Save, * Context;
OldChatAppl = ChatApplNum;
ChatApplNum = GetDlgItemInt(hDlg, ID_CHATAPPL, &OK1, FALSE);
MaxChatStreams = GetDlgItemInt(hDlg, ID_STREAMS, &OK1, FALSE);
if (ChatApplNum)
{
ptr1=GetApplCall(ChatApplNum);
if (ptr1 && (*ptr1 < 0x21))
{
MessageBox(NULL, "WARNING - There is no APPLCALL in BPQCFG matching the confgured ChatApplNum. Chat will not work",
"BPQMailChat", MB_ICONINFORMATION);
}
}
GetMultiLineDialog(hDlg, IDC_ChatNodes);
// Show dialog box now - gives time for links to close
// reinitialise other nodes list. rtlink messes with the string so pass copy
node_close();
if (ChatApplNum == OldChatAppl)
wsprintf(InfoBoxText, "Configuration Changes Saved and Applied");
else
wsprintf(InfoBoxText, "Warning Program must be restarted to change Chat Appl Num");
DialogBox(hInst, MAKEINTRESOURCE(IDD_USERADDED_BOX), hWnd, InfoDialogProc);
Sleep(2);
// Dont call removelinks - they may still be attached to a circuit. Just clear header
link_hd = NULL;
// Set up other nodes list. rtlink messes with the string so pass copy
Save = ptr1 = strtok_s(_strdup(OtherNodesList), "\r\n", &Context);
while (ptr1 && ptr1[0])
{
rtlink(ptr1);
ptr1 = strtok_s(NULL, "\r\n", &Context);
}
// if (strchr(ptr1, '|') == 0) // No script
// while (*ptr1)
// {
// if (*ptr1 == '\r')
// {
// while (*(ptr1+2) == '\r') // Blank line
// ptr1+=2;
// *++ptr1 = 32;
// }
// *ptr2++=*ptr1++;
// }
// *ptr2++ = 0;
free(Save);
if (user_hd) // Any Users?
makelinks(); // Bring up links
SaveChatConfigFile(ChatConfigName); // Commit to file
GetChatConfig(ChatConfigName);
}