linbpq/MBLRoutines.c

434 lines
9.4 KiB
C

/*
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
//
// MBL-Style Forwarding Routines
#include "bpqmail.h"
void SendMessageReadEvent(char * call, struct MsgInfo * Msg);
void MQTTMessageEvent(void* message);
VOID ProcessMBLLine(CIRCUIT * conn, struct UserInfo * user, UCHAR* Buffer, int len)
{
Buffer[len] = 0;
// Winpack can send a second SID to switch to upload mode
if (Buffer[0] == '[' && Buffer[len-2] == ']') // SID
{
if (user->flags & (F_PMS))
{
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;
}
if (Buffer[0] == 6 && Buffer[1] == 5)
{
// ?? Sally send these after a failed tranfer
memmove(Buffer, &Buffer[2], len);
len-=2;
}
if (_memicmp(Buffer, "F< ", 3) == 0)
{
// FBB Compressed request from system using UI Messages
int Number = atoi(&Buffer[3]);
struct MsgInfo * Msg = FindMessageByNumber(Number);
char ErrMsg[80];
int ErrLen;
if (Msg == 0)
{
ErrLen = sprintf(&ErrMsg[2], "Msg $%d does not exist!\r>", Number);
ErrMsg[0] = 0x18;
ErrMsg[1] = ErrLen;
BBSputs(conn, ErrMsg);
FBBputs(conn, ">\r");
return;
}
Msg = FindMessage(user->Call, Number, conn->sysop);
if (Msg)
{
conn->BBSFlags |= FBBCompressed; // Needs compression
SendCompressed(conn, Msg);
FBBputs(conn, ">\r");
Msg->status = 'Y'; // Mark as read
SaveMessageDatabase();
SendMessageReadEvent(user->Call, Msg);
}
else
{
ErrLen = sprintf(&ErrMsg[2], "Msg $%d not available to you!\r>", Number);
ErrMsg[0] = 0x18;
ErrMsg[1] = ErrLen;
BBSputs(conn, ErrMsg);
FBBputs(conn, ">\r");
}
return;
}
if (Buffer[0] == 'S') //Send
{
// SB WANT @ ALLCAN < N6ZFJ $4567_N0ARY
char * Cmd;
char * To = NULL;
char * From = NULL;
char * BID = NULL;
char * ATBBS = NULL;
char * ptr, * Context;
char seps[] = " \t\r";
Cmd = strtok_s(Buffer, seps, &Context);
if (Cmd[1] == 0) Cmd[1] = 'P';
if (RefuseBulls && Cmd[1] == 'B')
{
nodeprintfEx(conn, "NO - BULLS NOT ACCEPTED\r");
if (conn->BBSFlags & OUTWARDCONNECT)
nodeprintfEx(conn, "F>\r"); // if Outward connect must be reverse forward
else
nodeprintfEx(conn, ">\r");
return;
}
To = strtok_s(NULL, seps, &Context);
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
{
nodeprintfEx(conn, "*** Error: Invalid Format\r");
return;
}
ptr = strtok_s(NULL, seps, &Context);
}
if (!From)
{
nodeprintfEx(conn, "*** Error: Invalid Format\r");
return;
}
if (BID && LookupTempBID(BID))
{
// Being received from another BBS
nodeprintfEx(conn, "NO - BID\r");
if (conn->BBSFlags & OUTWARDCONNECT)
nodeprintfEx(conn, "F>\r"); // if Outward connect must be reverse forward
else
nodeprintfEx(conn, ">\r");
return;
}
CreateMessage(conn, From, To, ATBBS, toupper(Cmd[1]), BID, NULL);
return;
}
if (Buffer[0] == 'N') // Not wanted
{
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
#ifndef NOMQTT
if (MQTT)
MQTTMessageEvent(conn->FwdMsg);
#endif
}
return;
}
if (Buffer[0] == 'O') // Need it (OK)
{
struct tm * tm;
time_t now;
char * MsgBytes;
char * MsgPtr; // In case updated for B2
int MsgLen;
if (!conn->FwdMsg)
return;
nodeprintfEx(conn, "%s\r", conn->FwdMsg->title);
MsgBytes = ReadMessageFile(conn->FwdMsg->number);
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;
}
MsgLen = RemoveLF(MsgPtr, MsgLen);
now = time(NULL);
tm = gmtime(&now);
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
BBSputs(conn, "\r");
QueueMsg(conn, MsgPtr, MsgLen);
if (user->ForwardingInfo->SendCTRLZ)
nodeprintf(conn, "\rx1a");
else
nodeprintf(conn, "\r/ex\r");
free(MsgBytes);
conn->FBBMsgsSent = TRUE;
return;
}
if (_stricmp(Buffer, "F>\r") == 0)
{
// Reverse forward request
// If we have just sent a message, Flag it as sent
if (conn->FBBMsgsSent)
{
conn->FBBMsgsSent = FALSE;
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->FwdMsg->Locked = 0; // Unlock
#ifndef NOMQTT
if (MQTT)
MQTTMessageEvent(conn->FwdMsg);
#endif
conn->UserPointer->ForwardingInfo->MsgCount--;
}
// Send Message or Disconnect
if (FindMessagestoForward(conn))
{
struct MsgInfo * Msg;
// Send S line and wait for response - SB WANT @ USA < W8AAA $1029_N0XYZ
Msg = conn->FwdMsg;
if (conn->BBSFlags & MFJMODE)
{
// No @ BBS to MFJ TNC
nodeprintfEx(conn, "S%c %s < %s $%s\r", Msg->type, Msg->to, Msg->from, Msg->bid);
}
else
nodeprintfEx(conn, "S%c %s @ %s < %s $%s\r", Msg->type, Msg->to,
(Msg->via[0]) ? Msg->via : conn->UserPointer->Call,
Msg->from, Msg->bid);
conn->BBSFlags |= MBLFORWARDING;
return;
}
BBSputs(conn, "*** DONE\r");
Flush(conn);
Sleep(400);
Disconnect(conn->BPQStream);
return;
}
if (Buffer[len-2] == '>')
{
// If we have just sent a message, Flag it as sent
if (conn->FBBMsgsSent)
{
conn->FBBMsgsSent = FALSE;
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);
}
#ifndef NOMQTT
if (MQTT)
MQTTMessageEvent(conn->FwdMsg);
#endif
conn->UserPointer->ForwardingInfo->MsgCount--;
}
// Send Message or request reverse using MBL-style forwarding
if (FindMessagestoForward(conn))
{
struct MsgInfo * Msg;
// Send S line and wait for response - SB WANT @ USA < W8AAA $1029_N0XYZ
Msg = conn->FwdMsg;
nodeprintfEx(conn, "S%c %s @ %s < %s $%s\r", Msg->type, Msg->to,
(Msg->via[0]) ? Msg->via : conn->UserPointer->Call,
Msg->from, Msg->bid);
return;
}
else
{
FBBputs(conn, "F>\r");
return;
}
}
// Winpack after doing ocmpressed downloads sends KM or B
if (_stricmp(Buffer, "*** DONE\r") == 0 || _stricmp(Buffer, "*** What?\r") == 0
|| _stricmp(Buffer, "B\r") == 0)
{
Disconnect(conn->BPQStream);
return;
}
if (_stricmp(Buffer, "KM\r") == 0)
{
int i;
struct MsgInfo * Msg;
for (i = NumberofMessages; i > 0; i--)
{
Msg = MsgHddrPtr[i];
if ((_stricmp(Msg->to, user->Call) == 0))
{
if (Msg->type == 'P' && Msg->status == 'Y')
{
FlagAsKilled(Msg, TRUE);
nodeprintfEx(conn, "Message #%d Killed\r", Msg->number);
}
}
}
SendPrompt(conn, user);
return;
}
}