linbpq/UIRoutines.c

637 lines
12 KiB
C
Raw Normal View History

2022-08-28 09:35:46 +01:00
/*
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
//
// UI Handling Routines
#include "bpqmail.h"
char UIDEST[10] = "FBB";
char UIMAIL[10] = "MAIL";
char AXDEST[7];
char AXMAIL[7];
static char MAILMYCALL[7];
#pragma pack(1)
UINT UIPortMask = 0;
BOOL UIEnabled[33];
BOOL UIMF[33];
BOOL UIHDDR[33];
BOOL UINull[33];
char * UIDigi[33];
char * UIDigiAX[33]; // ax.25 version of digistring
int UIDigiLen[33]; // Length of AX string
#pragma pack()
PMESSAGEX DG_Q; // Queue of messages to be sent to node
struct SEM DGSemaphore = {0, 0}; // For locking access to DG_Q;
VOID UnQueueRaw(void * Param);
static VOID Send_AX_Datagram(UCHAR * Msg, DWORD Len, UCHAR Port, UCHAR * HWADDR, BOOL Queue);
DllExport char * APIENTRY GetApplName(int Appl);
int APIENTRY SendRaw(int port, char * msg, int len);
int APIENTRY GetNumberofPorts();
VOID SetupUIInterface()
{
int i, NumPorts = GetNumberofPorts();
#ifndef LINBPQ
struct _EXCEPTION_POINTERS exinfo;
#endif
ConvToAX25(GetApplCall(BBSApplNum), MAILMYCALL);
ConvToAX25(UIDEST, AXDEST);
ConvToAX25(UIMAIL, AXMAIL);
UIPortMask = 0;
for (i = 1; i <= NumPorts; i++)
{
if (UIEnabled[i])
{
char DigiString[100], * DigiLeft;
UIPortMask |= 1 << (i-1);
UIDigiLen[i] = 0;
if (UIDigi[i])
{
UIDigiAX[i] = zalloc(100);
strcpy(DigiString, UIDigi[i]);
DigiLeft = strlop(DigiString,',');
while(DigiString[0])
{
ConvToAX25(DigiString, &UIDigiAX[i][UIDigiLen[i]]);
UIDigiLen[i] += 7;
if (DigiLeft)
{
memmove(DigiString, DigiLeft, strlen(DigiLeft) + 1);
DigiLeft = strlop(DigiString,',');
}
else
DigiString[0] = 0;
}
}
}
}
_beginthread(UnQueueRaw, 0, NULL);
if (EnableUI)
#ifdef LINBPQ
SendLatestUI(0);
#else
__try
{
SendLatestUI(0);
}
My__except_Routine("SendLatestUI");
#endif
}
VOID Free_UI()
{
int i;
PMESSAGEX AXMSG;
for (i = 1; i <= 32; i++)
{
if (UIDigi[i])
{
free(UIDigi[i]);
UIDigi[i] = NULL;
}
if (UIDigiAX[i])
{
free(UIDigiAX[i]);
UIDigiAX[i] = NULL;
}
}
if (DG_Q)
{
AXMSG = DG_Q;
DG_Q = AXMSG->CHAIN;
free(AXMSG);
}
}
VOID QueueRaw(int Port, PMESSAGEX AXMSG, int Len)
{
PMESSAGEX AXCopy = zalloc(400);
PMESSAGEX AXNext;
AXMSG->PORT = Port;
AXMSG->LENGTH = Len;
AXMSG->CHAIN = 0; // Clear chain in new buffer
memcpy(AXCopy, AXMSG, Len + 10);
GetSemaphore(&DGSemaphore, 0);
if (DG_Q == 0) // Empty
{
DG_Q = AXCopy;
FreeSemaphore(&DGSemaphore);
return;
}
AXNext = DG_Q;
while (AXNext->CHAIN)
AXNext = AXNext->CHAIN; // Chain to end of queue
AXNext->CHAIN = AXCopy; // New one on end
FreeSemaphore(&DGSemaphore);
}
VOID SendMsgUI(struct MsgInfo * Msg)
{
char msg[200];
int len, i;
int Mask = UIPortMask;
int NumPorts = GetNumberofPorts();
//12345 B 2053 TEST@ALL F6FBB 920325 This is the subject
struct tm *tm = gmtime((time_t *)&Msg->datecreated);
len = 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);
for (i=1; i <= NumPorts; i++)
{
if ((Mask & 1) && UIHDDR[i])
Send_AX_Datagram(msg, len, i, AXDEST, TRUE);
Mask>>=1;
}
}
VOID SendHeaders(int Number, int Port)
{
// Send headers in response to a resync request
char msg[256];
unsigned len=0;
struct tm *tm;
struct MsgInfo * Msg;
//12345 B 2053 TEST@ALL F6FBB 920325 This is the subject
while (Number <= LatestMsg)
{
Msg = FindMessageByNumber(Number);
if (Msg)
{
if (len > (200 - strlen(Msg->title)))
{
Send_AX_Datagram(msg, len, Port, AXDEST, FALSE);
len=0;
}
tm = gmtime((time_t *)&Msg->datecreated);
len += sprintf(&msg[len], "%-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);
}
else
{
if (len > 230)
{
Send_AX_Datagram(msg, len, Port, AXDEST, FALSE);
len=0;
}
len += sprintf(&msg[len], "%-6d #\r", Number);
}
Number++;
}
Send_AX_Datagram(msg, len, Port, AXDEST, FALSE);
}
VOID SendDummyUI(int num)
{
char msg[100];
int len, i;
int Mask = UIPortMask;
int NumPorts = GetNumberofPorts()
;
len = sprintf_s(msg, sizeof(msg),"%-6d #\r", num);
for (i=1; i <= NumPorts; i++)
{
if (Mask & 1)
Send_AX_Datagram(msg, len, i, AXDEST, TRUE);
Mask>>=1;
}
}
VOID SendLatestUI(int Port)
{
char msg[20];
int len, i;
int Mask = UIPortMask;
int NumPorts = GetNumberofPorts();
len = sprintf_s(msg, sizeof(msg),"%-6d !!\r", LatestMsg);
if (Port)
{
Send_AX_Datagram(msg, len, Port, AXDEST, FALSE);
return;
}
for (i=1; i <= NumPorts; i++)
{
if ((Mask & 1) && UIHDDR[i])
Send_AX_Datagram(msg, len, i, AXDEST, TRUE);
Mask>>=1;
}
}
static VOID Send_AX_Datagram(UCHAR * Msg, DWORD Len, UCHAR Port, UCHAR * HWADDR, BOOL Queue)
{
MESSAGEX AXMSG;
PMESSAGEX AXPTR = &AXMSG;
// Block includes the Msg Header (7 bytes), Len Does not!
memcpy(AXPTR->DEST, HWADDR, 7);
memcpy(AXPTR->ORIGIN, MAILMYCALL, 7);
AXPTR->DEST[6] &= 0x7e; // Clear End of Call
AXPTR->DEST[6] |= 0x80; // set Command Bit
if (UIDigi[Port] && UIDigiAX[Port])
{
// This port has a digi string
int DigiLen = UIDigiLen[Port];
UCHAR * ptr;
memcpy(&AXPTR->CTL, UIDigiAX[Port], DigiLen);
ptr = (UCHAR *)AXPTR;
ptr += DigiLen;
AXPTR = (PMESSAGEX)ptr;
Len += DigiLen;
}
AXPTR->ORIGIN[6] |= 1; // Set End of Call
AXPTR->CTL = 3; //UI
AXPTR->PID = 0xf0;
memcpy(AXPTR->DATA, Msg, Len);
if (Queue)
QueueRaw(Port, &AXMSG, Len + 16);
else
SendRaw(Port, (char *)&AXMSG.DEST, Len + 16);
return;
}
VOID UnQueueRaw(void * Param)
{
PMESSAGEX AXMSG;
while (TRUE)
{
GetSemaphore(&DGSemaphore, 0);
if (DG_Q)
{
AXMSG = DG_Q;
DG_Q = AXMSG->CHAIN;
SendRaw(AXMSG->PORT, (char *)&AXMSG->DEST, AXMSG->LENGTH);
free(AXMSG);
}
FreeSemaphore(&DGSemaphore);
Sleep(5000);
}
}
VOID ProcessUItoMe(char * msg, int len)
{
msg[len] = 0;
return;
}
VOID ProcessUItoFBB(char * msg, int len, int Port)
{
// ? 0000006464
// The first 8 digits are the hexadecimal number of the requested start of the list
// (here 00002EE0 -> 12000) and the last two digits are the sum of the four bytes anded with FF (0E).
int Number, Sum, Sent = 0;
char cksum[3];
if (msg[0] == '?')
{
memcpy(cksum, &msg[10], 2);
msg[10]=0;
sscanf(&msg[1], "%X", &Number);
sscanf(cksum, "%X", &Sum);
if (Number >= LatestMsg)
{
SendLatestUI(Port);
return;
}
SendHeaders(Number+1, Port);
}
return;
}
UCHAR * AdjustForDigis(PMESSAGEX * buff, int * len)
{
PMESSAGEX buff1 = *(buff);
UCHAR * ptr, * ptr1;
if ((buff1->ORIGIN[6] & 1) == 1)
{
// End of Call Set
return 0; // No Digis
}
ptr1 = &buff1->ORIGIN[6]; // End of add
ptr = (UCHAR *)*buff;
while((*ptr1 & 1) == 0) // End of address bit
{
ptr1 += 7;
ptr+= 7;
}
*buff = (PMESSAGEX)ptr;
return (&buff1->CTL); // Start of Digi String
}
VOID SeeifBBSUIFrame(PMESSAGEX buff, int len)
{
UCHAR * Digis;
UCHAR From[7], To[7];
int Port = buff->PORT;
if (Port > 128)
return; // Only look at received frames
memcpy(From, buff->ORIGIN, 7); // Save Origin and Dest before adjucting for Digis
memcpy(To, buff->DEST, 7);
Digis = AdjustForDigis(&buff, &len);
if (Digis)
{
// Make sure all are actioned
DigiLoop:
if ((Digis[6] & 0x80) == 0)
return; // Not repeated
if ((Digis[6] & 1) == 0) // Not end of list
{
Digis +=7;
goto DigiLoop;
}
}
if (buff->CTL != 3)
return;
if (buff->PID != 0xf0)
return;
// if (memcmp(buff->ORIGIN, MAILMYCALL,6) == 0) // From me?
// if (buff->ORIGIN[6] == (MAILMYCALL[6] | 1)) // Set End of Call
// return;
From[6] &= 0x7e;
To[6] &= 0x7e;
if (memcmp(To, MAILMYCALL, 7) == 0)
{
ProcessUItoFBB(buff->DATA, len-23, Port);
return;
}
if (memcmp(To, AXDEST, 7) == 0)
{
ProcessUItoFBB(buff->DATA, len-23, Port);
return;
}
len++;
return;
}
// ConvToAX25(MYNODECALL, MAILMYCALL);
// len=ConvFromAX25(Routes->NEIGHBOUR_DIGI1,Portcall);
// Portcall[len]=0;
char MailForHeader[] = "Mail For:";
char MailForExpanded[100];
VOID ExpandMailFor()
{
char * OldP = MailForText;
char * NewP = MailForExpanded;
char * ptr, * pptr;
size_t len;
char Dollar[] = "\\";
char CR[] = "\r";
ptr = strchr(OldP, '\\');
while (ptr)
{
len = ptr - OldP; // Chars before Backslash
memcpy(NewP, OldP, len);
NewP += len;
switch (*++ptr)
{
case 'r': // Inserts a carriage return.
case 'R': // Inserts a carriage return.
pptr = CR;
break;
default:
pptr = Dollar; // Just Copy Backslash
}
len = strlen(pptr);
memcpy(NewP, pptr, len);
NewP += len;
OldP = ++ptr;
ptr = strchr(OldP, '\\');
}
strcpy(NewP, OldP);
}
VOID SendMailFor(char * Msg, BOOL HaveCalls)
{
int Mask = UIPortMask;
int NumPorts = GetNumberofPorts();
int i;
if (!HaveCalls)
strcat(Msg, "None ");
Sleep(1000);
for (i=1; i <= NumPorts; i++)
{
if (Mask & 1)
{
if (UIMF[i] && (HaveCalls || UINull[i]))
{
Send_AX_Datagram(Msg, (int)strlen(Msg) - 1, i, AXMAIL, TRUE);
}
}
Mask>>=1;
}
}
VOID SendMailForThread(VOID * Param)
{
struct UserInfo * user;
char MailForMessage[256] = "";
BOOL HaveMailFor;
struct UserInfo * ptr = NULL;
int i, Unread;
while (MailForInterval)
{
ExpandMailFor();
if (MailForText[0]) // User supplied header
strcpy(MailForMessage, MailForExpanded);
else
strcpy(MailForMessage, MailForHeader);
HaveMailFor = FALSE;
for (i=1; i <= NumberofUsers; i++)
{
user = UserRecPtr[i];
CountMessagesTo(user, &Unread);
if (Unread)
{
if (strlen(MailForMessage) > 240)
{
SendMailFor(MailForMessage, TRUE);
if (MailForText[0]) // User supplied header
strcpy(MailForMessage, MailForExpanded);
else
strcpy(MailForMessage, MailForHeader);
}
strcat(MailForMessage, user->Call);
strcat(MailForMessage, " ");
HaveMailFor = TRUE;
}
}
SendMailFor(MailForMessage, HaveMailFor);
Sleep(MailForInterval * 60000);
}
}
/*
20:09:00R GM8BPQ-10>FBB Port=1 <UI C>:
103 !!
20:10:06R GM8BPQ-10>FBB Port=1 <UI C>:
19-Jul 21:08 <<< Mailbox GM8BPQ Skigersta >>> 2 active messages.
Messages for
ALL
20:11:11R GM8BPQ-10>FBB Port=1 <UI C>:
104 P 5 G8BPQ GM8BPQ 090719 ***
20:12:17R GM8BPQ-10>FBB Port=1 <UI C>:
105 B 5 ALL GM8BPQ 090719 test
12345 B 2053 TEST@ALL F6FBB 920325 This is the subject
20:13:23R GM8BPQ-10>FBB Port=1 <UI C>:
? 0000006464
20:15:34R GM8BPQ-10>FBB Port=1 <UI C>:
105 !!
20:15:45T GM8BPQ-10>MAIL Port=2 <UI C>:
20:16:40R GM8BPQ-10>FBB Port=1 <UI C>:
19-Jul 21:15 <<< Mailbox GM8BPQ Skigersta >>> 4 active messages.
Messages for
ALL G8BPQ
20:17:46R GM8BPQ-10>FBB Port=1 <UI C>:
106 P 5 GM8BPQ GM8BPQ 090719 ***
20:20:54R GM8BPQ-10>FBB Port=1 <UI C>:
? 0000006464
20:21:05T GM8BPQ-10>FBB Port=2 <UI C>:
? 0000006464
*/