/*
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, "\r\x1a");
		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;
	}
}

