759 lines
16 KiB
C
759 lines
16 KiB
C
// 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];
|
|
extern int chatPaclen;
|
|
|
|
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);
|
|
VOID WriteMiniDump();
|
|
|
|
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)
|
|
{
|
|
conn->paclen = chatPaclen;
|
|
|
|
// 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);
|
|
|
|
if (paclen > chatPaclen || paclen == 0)
|
|
paclen = chatPaclen;
|
|
|
|
conn->paclen = paclen;
|
|
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"
|
|
|
|
|
|
static config_t cfg;
|
|
static config_setting_t * group;
|
|
|
|
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);
|
|
|
|
}
|