1092 lines
21 KiB
C++
1092 lines
21 KiB
C++
|
#include <string.h>
|
|||
|
#include <stdio.h>
|
|||
|
#include <stdlib.h>
|
|||
|
#include <sys/stat.h>
|
|||
|
#include <time.h>
|
|||
|
|
|||
|
#include "QtTermTCP.h"
|
|||
|
|
|||
|
#define _CRT_SECURE_NO_WARNINGS
|
|||
|
|
|||
|
#define TRUE 1
|
|||
|
#define FALSE 0
|
|||
|
#define UCHAR unsigned char
|
|||
|
#define MAX_PATH 256
|
|||
|
#define WCHAR char
|
|||
|
|
|||
|
#ifndef WIN32
|
|||
|
#define strtok_s strtok_r
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
typedef unsigned long DWORD;
|
|||
|
typedef int BOOL;
|
|||
|
typedef unsigned char BYTE;
|
|||
|
typedef unsigned short WORD;
|
|||
|
|
|||
|
#define MAXHOSTS 16
|
|||
|
|
|||
|
#define TCHAR char
|
|||
|
|
|||
|
void QueueMsg(Ui_ListenSession * Sess, char * Msg, int Len);
|
|||
|
int ProcessYAPPMessage(Ui_ListenSession * Sess, UCHAR * Msg, int Len);
|
|||
|
void SetPortMonLine(int i, char * Text, int visible, int enabled);
|
|||
|
void AGW_AX25_data_in(void * Sess, UCHAR * data, int Len);
|
|||
|
int checkUTF8(unsigned char * Msg, int Len, unsigned char * out);
|
|||
|
|
|||
|
int Bells = TRUE;
|
|||
|
int StripLF = FALSE;
|
|||
|
int LogMonitor = FALSE;
|
|||
|
int LogOutput = FALSE;
|
|||
|
int SendDisconnected = TRUE;
|
|||
|
int ChatMode = TRUE;
|
|||
|
int MonPorts = 1;
|
|||
|
int ListenOn = FALSE;
|
|||
|
|
|||
|
time_t LastWrite = 0xffffffff;
|
|||
|
int AlertInterval = 300;
|
|||
|
int AlertBeep = TRUE;
|
|||
|
int AlertFreq = 600;
|
|||
|
int AlertDuration = 250;
|
|||
|
TCHAR AlertFileName[256] = { 0 };
|
|||
|
int ConnectBeep = TRUE;
|
|||
|
int UseKeywords = TRUE;
|
|||
|
|
|||
|
char KeyWordsName[MAX_PATH] = "Keywords.sys";
|
|||
|
char ** KeyWords = NULL;
|
|||
|
int NumberofKeyWords = 0;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
// YAPP stuff
|
|||
|
|
|||
|
#define SOH 1
|
|||
|
#define STX 2
|
|||
|
#define ETX 3
|
|||
|
#define EOT 4
|
|||
|
#define ENQ 5
|
|||
|
#define ACK 6
|
|||
|
#define DLE 0x10
|
|||
|
#define NAK 0x15
|
|||
|
#define CAN 0x18
|
|||
|
|
|||
|
#define YAPPTX 32768 // Sending YAPP file
|
|||
|
|
|||
|
int MaxRXSize = 100000;
|
|||
|
char BaseDir[256] = "";
|
|||
|
|
|||
|
unsigned char InputBuffer[1024];
|
|||
|
|
|||
|
char YAPPPath[MAX_PATH] = ""; // Path for saving YAPP Files
|
|||
|
|
|||
|
int paclen = 128;
|
|||
|
|
|||
|
int InputLen; // Data we have already = Offset of end of an incomplete packet;
|
|||
|
|
|||
|
unsigned char * MailBuffer; // Yapp Message being received
|
|||
|
int MailBufferSize;
|
|||
|
int YAPPLen; // Bytes sent/received of YAPP Message
|
|||
|
long YAPPDate; // Date for received file - if set enables YAPPC
|
|||
|
char ARQFilename[200]; // Filename from YAPP Header
|
|||
|
|
|||
|
unsigned char SavedData[8192]; // Max receive is 4096 is should never get more that 8k
|
|||
|
int SaveLen = 0;
|
|||
|
|
|||
|
void YAPPSendData(Ui_ListenSession * Sess);
|
|||
|
|
|||
|
|
|||
|
char * strlop(char * buf, char delim)
|
|||
|
{
|
|||
|
// Terminate buf at delim, and return rest of string
|
|||
|
|
|||
|
char * ptr = strchr(buf, delim);
|
|||
|
|
|||
|
if (ptr == NULL) return NULL;
|
|||
|
|
|||
|
*(ptr)++ = 0;
|
|||
|
|
|||
|
return ptr;
|
|||
|
}
|
|||
|
|
|||
|
int CheckKeyWord(char * Word, char * Msg)
|
|||
|
{
|
|||
|
char * ptr1 = Msg, *ptr2;
|
|||
|
int len = (int)strlen(Word);
|
|||
|
|
|||
|
while (*ptr1) // Stop at end
|
|||
|
{
|
|||
|
ptr2 = strstr(ptr1, Word);
|
|||
|
|
|||
|
if (ptr2 == NULL)
|
|||
|
return FALSE; // OK
|
|||
|
|
|||
|
// Only bad if it ia not part of a longer word
|
|||
|
|
|||
|
if ((ptr2 == Msg) || !(isalpha(*(ptr2 - 1)))) // No alpha before
|
|||
|
if (!(isalpha(*(ptr2 + len)))) // No alpha after
|
|||
|
return TRUE; // Bad word
|
|||
|
|
|||
|
// Keep searching
|
|||
|
|
|||
|
ptr1 = ptr2 + len;
|
|||
|
}
|
|||
|
|
|||
|
return FALSE; // OK
|
|||
|
}
|
|||
|
|
|||
|
int CheckKeyWords(UCHAR * Msg, int len)
|
|||
|
{
|
|||
|
char dupMsg[2048];
|
|||
|
int i;
|
|||
|
|
|||
|
if (UseKeywords == 0 || NumberofKeyWords == 0)
|
|||
|
return FALSE;
|
|||
|
|
|||
|
memcpy(dupMsg, Msg, len);
|
|||
|
dupMsg[len] = 0;
|
|||
|
//_strlwr(dupMsg);
|
|||
|
|
|||
|
for (i = 1; i <= NumberofKeyWords; i++)
|
|||
|
{
|
|||
|
if (CheckKeyWord(KeyWords[i], dupMsg))
|
|||
|
{
|
|||
|
// Beep(660, 250);
|
|||
|
return TRUE; // Alert
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return FALSE; // OK
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void ProcessReceivedData(Ui_ListenSession * Sess, unsigned char * Buffer, int len)
|
|||
|
{
|
|||
|
int MonLen = 0;
|
|||
|
unsigned char * ptr;
|
|||
|
unsigned char * Buffptr;
|
|||
|
unsigned char * FEptr = 0;
|
|||
|
|
|||
|
if (Sess->InputMode == 'Y') // Yapp
|
|||
|
{
|
|||
|
ProcessYAPPMessage(Sess, Buffer, len);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// mbstowcs(Buffer, BufferB, len);
|
|||
|
|
|||
|
// Look for MON delimiters (FF/FE)
|
|||
|
|
|||
|
|
|||
|
Buffptr = Buffer;
|
|||
|
|
|||
|
if (Sess->MonData)
|
|||
|
{
|
|||
|
// Already in MON State
|
|||
|
|
|||
|
FEptr = (UCHAR *)memchr(Buffptr, 0xfe, len);
|
|||
|
|
|||
|
if (!FEptr)
|
|||
|
{
|
|||
|
// no FE - so send all to monitor
|
|||
|
|
|||
|
WritetoMonWindow(Sess, Buffer, len);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
Sess->MonData = FALSE;
|
|||
|
|
|||
|
MonLen = FEptr - Buffptr; // Mon Data, Excluding the FE
|
|||
|
|
|||
|
WritetoMonWindow(Sess, Buffptr, MonLen);
|
|||
|
|
|||
|
Buffptr = ++FEptr; // Char following FE
|
|||
|
|
|||
|
if (++MonLen < len)
|
|||
|
{
|
|||
|
len -= MonLen;
|
|||
|
goto MonLoop; // See if next in MON or Data
|
|||
|
}
|
|||
|
|
|||
|
// Nothing Left
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
MonLoop:
|
|||
|
|
|||
|
ptr = (UCHAR *)memchr(Buffptr, 0xff, len);
|
|||
|
|
|||
|
if (ptr)
|
|||
|
{
|
|||
|
unsigned char telcmd[] = "\xff\xfb\x03\xff\xfb\x01";
|
|||
|
|
|||
|
// Try to trap connect to normal Telnet Port
|
|||
|
|
|||
|
if (memcmp(ptr, telcmd, 6) == 0)
|
|||
|
return;
|
|||
|
|
|||
|
// Buffer contains Mon Data
|
|||
|
|
|||
|
if (ptr > Buffptr)
|
|||
|
{
|
|||
|
// Some Normal Data before the FF
|
|||
|
|
|||
|
int NormLen = ptr - Buffptr; // Before the FF
|
|||
|
|
|||
|
if (NormLen == 1 && Buffptr[0] == 0)
|
|||
|
{
|
|||
|
// Keepalive
|
|||
|
}
|
|||
|
|
|||
|
else
|
|||
|
{
|
|||
|
CheckKeyWords(Buffptr, NormLen);
|
|||
|
WritetoOutputWindow(Sess, Buffptr, NormLen);
|
|||
|
}
|
|||
|
|
|||
|
len -= NormLen;
|
|||
|
Buffptr = ptr;
|
|||
|
goto MonLoop;
|
|||
|
}
|
|||
|
|
|||
|
if (ptr[1] == 0xff)
|
|||
|
{
|
|||
|
// Port Definition String
|
|||
|
|
|||
|
int NumberofPorts = atoi((char *)&ptr[2]);
|
|||
|
char *p, *Context;
|
|||
|
int i = 1;
|
|||
|
TCHAR msg[80];
|
|||
|
int portnum;
|
|||
|
char delim[] = "|";
|
|||
|
int m;
|
|||
|
|
|||
|
// Save for changes of Window
|
|||
|
|
|||
|
if (len < 1024)
|
|||
|
memcpy(Sess->PortMonString, ptr, len);
|
|||
|
|
|||
|
|
|||
|
// Remove old menu
|
|||
|
|
|||
|
for (i = 0; i < 33; i++)
|
|||
|
{
|
|||
|
SetPortMonLine(i, (char *)"", 0, 0);
|
|||
|
}
|
|||
|
|
|||
|
p = strtok_s((char *)&ptr[2], delim, &Context);
|
|||
|
|
|||
|
while (NumberofPorts--)
|
|||
|
{
|
|||
|
p = strtok_s(NULL, delim, &Context);
|
|||
|
if (p == NULL)
|
|||
|
break;
|
|||
|
|
|||
|
m = portnum = atoi(p);
|
|||
|
sprintf(msg, "Port %s", p);
|
|||
|
|
|||
|
if (m == 0)
|
|||
|
m = 33;
|
|||
|
|
|||
|
if (Sess->portmask & (1ll << (m - 1)))
|
|||
|
SetPortMonLine(portnum, msg, 1, 1);
|
|||
|
else
|
|||
|
SetPortMonLine(portnum, msg, 1, 0);
|
|||
|
}
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
Sess->MonData = 1;
|
|||
|
|
|||
|
FEptr = (UCHAR *)memchr(Buffptr, 0xfe, len);
|
|||
|
|
|||
|
if (FEptr)
|
|||
|
{
|
|||
|
Sess->MonData = 0;
|
|||
|
|
|||
|
MonLen = FEptr + 1 - Buffptr; // MonLen includes FF and FE
|
|||
|
|
|||
|
WritetoMonWindow(Sess, Buffptr + 1, MonLen - 2);
|
|||
|
|
|||
|
len -= MonLen;
|
|||
|
Buffptr += MonLen; // Char Following FE
|
|||
|
|
|||
|
if (len <= 0)
|
|||
|
{
|
|||
|
return;
|
|||
|
}
|
|||
|
goto MonLoop;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// No FE, so rest of buffer is MON Data
|
|||
|
|
|||
|
if (MonLen)
|
|||
|
WritetoMonWindow(Sess, Buffptr + 1, MonLen - 1);
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// No FF, so must be session data
|
|||
|
|
|||
|
if (Sess->InputMode == 'Y') // Yapp
|
|||
|
{
|
|||
|
ProcessYAPPMessage(Sess, Buffer, len);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
if (len == 1 && Buffptr[0] == 0)
|
|||
|
return; // Keepalive
|
|||
|
|
|||
|
// Could be a YAPP Header
|
|||
|
|
|||
|
if (len == 2 && Buffptr[0] == ENQ && Buffptr[1] == 1) // YAPP Send_Init
|
|||
|
{
|
|||
|
char YAPPRR[2];
|
|||
|
|
|||
|
// Turn off monitoring
|
|||
|
|
|||
|
setTraceOff(Sess);
|
|||
|
|
|||
|
Sess->InputMode = 'Y';
|
|||
|
|
|||
|
YAPPRR[0] = ACK;
|
|||
|
YAPPRR[1] = 1;
|
|||
|
|
|||
|
SocketFlush(Sess); // To give Monitor Msg time to be sent
|
|||
|
mySleep(1000);
|
|||
|
QueueMsg(Sess, YAPPRR, 2);
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
// Check UTF8
|
|||
|
{
|
|||
|
CheckKeyWords(Buffptr, len);
|
|||
|
WritetoOutputWindow(Sess, Buffptr, len);
|
|||
|
}
|
|||
|
Sess->SlowTimer = 0;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
extern myTcpSocket * VARASock;
|
|||
|
extern myTcpSocket * VARADataSock;
|
|||
|
extern "C" void SendtoAX25(void * conn, unsigned char * Msg, int Len);
|
|||
|
|
|||
|
int SendMsg(Ui_ListenSession * Sess, TCHAR * Buffer, int len)
|
|||
|
{
|
|||
|
if (Sess->KISSSession)
|
|||
|
{
|
|||
|
// Send to ax.25 code
|
|||
|
|
|||
|
SendtoAX25(Sess->KISSSession, (unsigned char *)Buffer, len);
|
|||
|
return len;
|
|||
|
}
|
|||
|
else if (Sess->AGWSession)
|
|||
|
{
|
|||
|
// Terminal is in AGWPE mode - send as AGW frame
|
|||
|
|
|||
|
AGW_AX25_data_in(Sess->AGWSession, (unsigned char *)Buffer, len);
|
|||
|
return len;
|
|||
|
}
|
|||
|
else if (VARASock && VARASock->Sess == Sess)
|
|||
|
{
|
|||
|
VARADataSock->write(Buffer, len);
|
|||
|
return len;
|
|||
|
}
|
|||
|
|
|||
|
return SocketSend(Sess, Buffer, len);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
void QueueMsg(Ui_ListenSession * Sess, char * Msg, int len)
|
|||
|
{
|
|||
|
int Sent = SendMsg(Sess, Msg, len);
|
|||
|
|
|||
|
if (Sent != len)
|
|||
|
Sent = 0;
|
|||
|
}
|
|||
|
|
|||
|
int InnerProcessYAPPMessage(Ui_ListenSession * Sess, UCHAR * Msg, int Len);
|
|||
|
|
|||
|
int ProcessYAPPMessage(Ui_ListenSession * Sess, UCHAR * Msg, int Len)
|
|||
|
{
|
|||
|
// may have saved data
|
|||
|
|
|||
|
memcpy(&SavedData[SaveLen], Msg, Len);
|
|||
|
|
|||
|
SaveLen += Len;
|
|||
|
|
|||
|
while (SaveLen && Sess->InputMode == 'Y')
|
|||
|
{
|
|||
|
int Used = InnerProcessYAPPMessage(Sess, SavedData, SaveLen);
|
|||
|
|
|||
|
if (Used == 0)
|
|||
|
return 0; // Waiting for more
|
|||
|
|
|||
|
SaveLen -= Used;
|
|||
|
|
|||
|
if (SaveLen)
|
|||
|
memmove(SavedData, &SavedData[Used], SaveLen);
|
|||
|
}
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
extern int VARAEnable;
|
|||
|
|
|||
|
int InnerProcessYAPPMessage(Ui_ListenSession * Sess, UCHAR * Msg, int Len)
|
|||
|
{
|
|||
|
int pktLen = Msg[1];
|
|||
|
char Reply[2] = { ACK };
|
|||
|
size_t NameLen, SizeLen, OptLen;
|
|||
|
char * ptr;
|
|||
|
int FileSize;
|
|||
|
WCHAR MsgFile[MAX_PATH];
|
|||
|
FILE * hFile;
|
|||
|
char Mess[255];
|
|||
|
int len;
|
|||
|
UCHAR Buffer[2000];
|
|||
|
struct stat STAT;
|
|||
|
|
|||
|
switch (Msg[0])
|
|||
|
{
|
|||
|
case ENQ: // YAPP Send_Init
|
|||
|
|
|||
|
// Shouldn't occur in session. Reset state and process
|
|||
|
|
|||
|
if (MailBuffer)
|
|||
|
{
|
|||
|
free(MailBuffer);
|
|||
|
MailBufferSize = 0;
|
|||
|
MailBuffer = 0;
|
|||
|
}
|
|||
|
|
|||
|
Mess[0] = ACK;
|
|||
|
Mess[1] = 1;
|
|||
|
|
|||
|
Sess->InputMode = 'Y';
|
|||
|
QueueMsg(Sess, Mess, 2);
|
|||
|
|
|||
|
// Turn off monitoring
|
|||
|
|
|||
|
mySleep(1000); // To give YAPP Msg time to be sent
|
|||
|
|
|||
|
setTraceOff(Sess);
|
|||
|
|
|||
|
return Len;
|
|||
|
|
|||
|
case SOH:
|
|||
|
|
|||
|
// HD Send_Hdr SOH len (Filename) NUL (File Size in ASCII) NUL (Opt)
|
|||
|
|
|||
|
// YAPPC has date/time in dos format
|
|||
|
|
|||
|
if (Len < Msg[1] + 1)
|
|||
|
return 0; // Wait till we have it all
|
|||
|
|
|||
|
NameLen = strlen((char *)&Msg[2]);
|
|||
|
strcpy(ARQFilename, (char *)&Msg[2]);
|
|||
|
|
|||
|
ptr = (char *)&Msg[3 + NameLen];
|
|||
|
SizeLen = strlen(ptr);
|
|||
|
FileSize = atoi(ptr);
|
|||
|
|
|||
|
OptLen = pktLen - (NameLen + SizeLen + 2);
|
|||
|
|
|||
|
YAPPDate = 0;
|
|||
|
|
|||
|
if (OptLen >= 8) // We have a Date/Time for YAPPC
|
|||
|
{
|
|||
|
ptr = ptr + SizeLen + 1;
|
|||
|
YAPPDate = strtol(ptr, NULL, 16);
|
|||
|
}
|
|||
|
|
|||
|
// Check Size
|
|||
|
|
|||
|
if (FileSize > MaxRXSize && VARAEnable == 0)
|
|||
|
{
|
|||
|
Mess[0] = NAK;
|
|||
|
Mess[1] = sprintf(&Mess[2], "File %s size %d larger than limit %d\r", ARQFilename, FileSize, MaxRXSize);
|
|||
|
mySleep(1000); // To give YAPP Msg tome to be sent
|
|||
|
QueueMsg(Sess, Mess, Mess[1] + 2);
|
|||
|
|
|||
|
len = sprintf((char *)Buffer, "YAPP File %s size %d larger than limit %d\r", ARQFilename, FileSize, MaxRXSize);
|
|||
|
WritetoOutputWindow(Sess, Buffer, len);
|
|||
|
|
|||
|
Sess->InputMode = 0;
|
|||
|
SendTraceOptions(Sess);
|
|||
|
|
|||
|
return Len;
|
|||
|
}
|
|||
|
|
|||
|
// Check that Path is set
|
|||
|
|
|||
|
if (YAPPPath[0] == 0)
|
|||
|
{
|
|||
|
Mess[0] = NAK;
|
|||
|
Mess[1] = sprintf(&Mess[2], "%s", "YAPP Receive directory not set");
|
|||
|
mySleep(1000); // To give YAPP Msg time to be sent
|
|||
|
QueueMsg(Sess, Mess, Mess[1] + 2);
|
|||
|
len = sprintf((char *)Buffer, "YAPP File Receive Failed - YAPP Receive directory not set\r");
|
|||
|
WritetoOutputWindow(Sess, Buffer, len);
|
|||
|
|
|||
|
Sess->InputMode = 0;
|
|||
|
SendTraceOptions(Sess);
|
|||
|
|
|||
|
return Len;
|
|||
|
}
|
|||
|
|
|||
|
// Make sure file does not exist
|
|||
|
|
|||
|
sprintf(MsgFile, "%s/%s", YAPPPath, ARQFilename);
|
|||
|
|
|||
|
if (stat(MsgFile, &STAT) == 0)
|
|||
|
{
|
|||
|
FileSize = STAT.st_size;
|
|||
|
|
|||
|
Mess[0] = NAK;
|
|||
|
Mess[1] = sprintf(&Mess[2], "%s", "File Already Exists");
|
|||
|
mySleep(1000); // To give YAPP Msg time to be sent
|
|||
|
QueueMsg(Sess, Mess, Mess[1] + 2);
|
|||
|
len = sprintf((char *)Buffer, "YAPP File Receive Failed - %s already exists\r", MsgFile);
|
|||
|
WritetoOutputWindow(Sess, Buffer, len);
|
|||
|
|
|||
|
Sess->InputMode = 0;
|
|||
|
SendTraceOptions(Sess);
|
|||
|
|
|||
|
return Len;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
MailBufferSize = FileSize;
|
|||
|
MailBuffer = (UCHAR *)malloc(FileSize);
|
|||
|
YAPPLen = 0;
|
|||
|
|
|||
|
if (YAPPDate) // If present use YAPPC
|
|||
|
Reply[1] = ACK; //Receive_TPK
|
|||
|
else
|
|||
|
Reply[1] = 2; //Rcv_File
|
|||
|
|
|||
|
QueueMsg(Sess, Reply, 2);
|
|||
|
|
|||
|
len = sprintf((char *)Buffer, "YAPP Receving File %s size %d\r", ARQFilename, FileSize);
|
|||
|
WritetoOutputWindow(Sess, Buffer, len);
|
|||
|
|
|||
|
return Len;
|
|||
|
|
|||
|
case STX:
|
|||
|
|
|||
|
// Data Packet
|
|||
|
|
|||
|
// Check we have it all
|
|||
|
|
|||
|
if (YAPPDate) // If present use YAPPC so have checksum
|
|||
|
{
|
|||
|
if (pktLen > (Len - 3)) // -2 for header and checksum
|
|||
|
return 0; // Wait for rest
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (pktLen > (Len - 2)) // -2 for header
|
|||
|
return 0; // Wait for rest
|
|||
|
}
|
|||
|
|
|||
|
// Save data and remove from buffer
|
|||
|
|
|||
|
// if YAPPC check checksum
|
|||
|
|
|||
|
if (YAPPDate)
|
|||
|
{
|
|||
|
UCHAR Sum = 0;
|
|||
|
int i;
|
|||
|
UCHAR * uptr = &Msg[2];
|
|||
|
|
|||
|
i = pktLen;
|
|||
|
|
|||
|
while (i--)
|
|||
|
Sum += *(uptr++);
|
|||
|
|
|||
|
if (Sum != *uptr)
|
|||
|
{
|
|||
|
// Checksum Error
|
|||
|
|
|||
|
Mess[0] = CAN;
|
|||
|
Mess[1] = sprintf(&Mess[2], "YAPPC Checksum Error");
|
|||
|
QueueMsg(Sess, Mess, Mess[1] + 2);
|
|||
|
|
|||
|
len = sprintf((char *)Buffer, "YAPPC Checksum Error on file %s\r", MsgFile);
|
|||
|
WritetoOutputWindow(Sess, Buffer, len);
|
|||
|
|
|||
|
Sess->InputMode = 0;
|
|||
|
SendTraceOptions(Sess);
|
|||
|
return Len;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ((YAPPLen) + pktLen > MailBufferSize)
|
|||
|
{
|
|||
|
// Too Big ??
|
|||
|
|
|||
|
Mess[0] = CAN;
|
|||
|
Mess[1] = sprintf(&Mess[2], "YAPP Too much data received");
|
|||
|
QueueMsg(Sess, Mess, Mess[1] + 2);
|
|||
|
|
|||
|
len = sprintf((char *)Buffer, "YAPP Too much data received on file %s\r", MsgFile);
|
|||
|
WritetoOutputWindow(Sess, Buffer, len);
|
|||
|
|
|||
|
Sess->InputMode = 0;
|
|||
|
SendTraceOptions(Sess);
|
|||
|
return Len;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
memcpy(&MailBuffer[YAPPLen], &Msg[2], pktLen);
|
|||
|
YAPPLen += pktLen;
|
|||
|
|
|||
|
if (YAPPDate)
|
|||
|
++pktLen; // Add Checksum
|
|||
|
|
|||
|
// if (YAPPLen == MailBufferSize)
|
|||
|
// pktLen = pktLen;
|
|||
|
|
|||
|
return pktLen + 2;
|
|||
|
|
|||
|
case ETX:
|
|||
|
|
|||
|
// End Data
|
|||
|
|
|||
|
if (YAPPLen == MailBufferSize)
|
|||
|
{
|
|||
|
// All received
|
|||
|
|
|||
|
int Written = 0;
|
|||
|
|
|||
|
sprintf(MsgFile, "%s/%s", YAPPPath, ARQFilename);
|
|||
|
|
|||
|
hFile = fopen(MsgFile, "wb");
|
|||
|
|
|||
|
if (hFile)
|
|||
|
{
|
|||
|
Written = (int)fwrite(MailBuffer, 1, YAPPLen, hFile);
|
|||
|
fclose(hFile);
|
|||
|
|
|||
|
if (YAPPDate)
|
|||
|
{
|
|||
|
// struct tm TM;
|
|||
|
// struct timeval times[2];
|
|||
|
/*
|
|||
|
The MS-DOS date. The date is a packed value with the following format.
|
|||
|
|
|||
|
cant use DosDateTimeToFileTime on Linux
|
|||
|
|
|||
|
Bits Description
|
|||
|
0-4 Day of the month (1<EFBFBD>31)
|
|||
|
5-8 Month (1 = January, 2 = February, and so on)
|
|||
|
9-15 Year offset from 1980 (add 1980 to get actual year)
|
|||
|
wFatTime
|
|||
|
The MS-DOS time. The time is a packed value with the following format.
|
|||
|
Bits Description
|
|||
|
0-4 Second divided by 2
|
|||
|
5-10 Minute (0<EFBFBD>59)
|
|||
|
11-15 Hour (0<EFBFBD>23 on a 24-hour clock)
|
|||
|
*/
|
|||
|
/*
|
|||
|
|
|||
|
memset(&TM, 0, sizeof(TM));
|
|||
|
|
|||
|
TM.tm_sec = (YAPPDate & 0x1f) << 1;
|
|||
|
TM.tm_min = ((YAPPDate >> 5) & 0x3f);
|
|||
|
TM.tm_hour = ((YAPPDate >> 11) & 0x1f);
|
|||
|
|
|||
|
TM.tm_mday = ((YAPPDate >> 16) & 0x1f);
|
|||
|
TM.tm_mon = ((YAPPDate >> 21) & 0xf) - 1;
|
|||
|
TM.tm_year = ((YAPPDate >> 25) & 0x7f) + 80;
|
|||
|
|
|||
|
Debugprintf("%d %d %d %d %d %d", TM.tm_year, TM.tm_mon, TM.tm_mday, TM.tm_hour, TM.tm_min, TM.tm_sec);
|
|||
|
|
|||
|
times[0].tv_sec = times[1].tv_sec = mktime(&TM);
|
|||
|
times[0].tv_usec = times[1].tv_usec = 0;
|
|||
|
*/
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
free(MailBuffer);
|
|||
|
MailBufferSize = 0;
|
|||
|
MailBuffer = 0;
|
|||
|
|
|||
|
if (Written != YAPPLen)
|
|||
|
{
|
|||
|
Mess[0] = CAN;
|
|||
|
Mess[1] = sprintf(&Mess[2], "Failed to save YAPP File");
|
|||
|
QueueMsg(Sess, Mess, Mess[1] + 2);
|
|||
|
|
|||
|
len = sprintf((char *)Buffer, "Failed to save YAPP File %s\r", MsgFile);
|
|||
|
WritetoOutputWindow(Sess, Buffer, len);
|
|||
|
|
|||
|
Sess->InputMode = 0;
|
|||
|
SendTraceOptions(Sess);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
Reply[1] = 3; //Ack_EOF
|
|||
|
QueueMsg(Sess, Reply, 2);
|
|||
|
|
|||
|
len = sprintf((char *)Buffer, "Reception of file %s complete\r", MsgFile);
|
|||
|
WritetoOutputWindow(Sess, Buffer, len);
|
|||
|
|
|||
|
return Len;
|
|||
|
|
|||
|
case EOT:
|
|||
|
|
|||
|
// End Session
|
|||
|
|
|||
|
Reply[1] = 4; // Ack_EOT
|
|||
|
QueueMsg(Sess, Reply, 2);
|
|||
|
SocketFlush(Sess);
|
|||
|
Sess->InputMode = 0;
|
|||
|
|
|||
|
SendTraceOptions(Sess);
|
|||
|
return Len;
|
|||
|
|
|||
|
case CAN:
|
|||
|
|
|||
|
// Abort
|
|||
|
|
|||
|
Mess[0] = ACK;
|
|||
|
Mess[1] = 5; // CAN Ack
|
|||
|
QueueMsg(Sess, Mess, 2);
|
|||
|
|
|||
|
if (MailBuffer)
|
|||
|
{
|
|||
|
free(MailBuffer);
|
|||
|
MailBufferSize = 0;
|
|||
|
MailBuffer = 0;
|
|||
|
}
|
|||
|
|
|||
|
// May have an error message
|
|||
|
|
|||
|
len = Msg[1];
|
|||
|
|
|||
|
if (len)
|
|||
|
{
|
|||
|
len = sprintf((char *)Buffer, "YAPP Transfer cancelled - %s\r", &Msg[2]);
|
|||
|
}
|
|||
|
else
|
|||
|
len = sprintf(Mess, "YAPP Transfer cancelled\r");
|
|||
|
|
|||
|
Sess->InputMode = 0;
|
|||
|
SendTraceOptions(Sess);
|
|||
|
|
|||
|
return Len;
|
|||
|
|
|||
|
case ACK:
|
|||
|
|
|||
|
switch (Msg[1])
|
|||
|
{
|
|||
|
char * ptr;
|
|||
|
|
|||
|
case 1: // Rcv_Rdy
|
|||
|
|
|||
|
// HD Send_Hdr SOH len (Filename) NUL (File Size in ASCII) NUL (Opt)
|
|||
|
|
|||
|
// Remote only needs filename so remove path
|
|||
|
|
|||
|
ptr = ARQFilename;
|
|||
|
|
|||
|
while (strchr(ptr, '/'))
|
|||
|
ptr = strchr(ptr, '/') + 1;
|
|||
|
|
|||
|
len = (int)strlen(ptr) + 3;
|
|||
|
|
|||
|
strcpy(&Mess[2], ptr);
|
|||
|
len += sprintf(&Mess[len], "%d", MailBufferSize);
|
|||
|
len++; // include null
|
|||
|
// len += sprintf(&Mess[len], "%8X", YAPPDate);
|
|||
|
// len++; // include null
|
|||
|
Mess[0] = SOH;
|
|||
|
Mess[1] = len - 2;
|
|||
|
|
|||
|
QueueMsg(Sess, Mess, len);
|
|||
|
|
|||
|
return Len;
|
|||
|
|
|||
|
case 2:
|
|||
|
|
|||
|
YAPPDate = 0; // Switch to Normal (No Checksum) Mode
|
|||
|
|
|||
|
case 6: // Send using YAPPC
|
|||
|
|
|||
|
// Start sending message
|
|||
|
|
|||
|
YAPPSendData(Sess);
|
|||
|
return Len;
|
|||
|
|
|||
|
case 3:
|
|||
|
|
|||
|
// ACK EOF - Send EOT
|
|||
|
|
|||
|
Mess[0] = EOT;
|
|||
|
Mess[1] = 1;
|
|||
|
QueueMsg(Sess, Mess, 2);
|
|||
|
|
|||
|
return Len;
|
|||
|
|
|||
|
case 4:
|
|||
|
|
|||
|
// ACK EOT
|
|||
|
|
|||
|
Sess->InputMode = 0;
|
|||
|
SendTraceOptions(Sess);
|
|||
|
|
|||
|
len = sprintf((char *)Buffer, "File transfer complete\r");
|
|||
|
WritetoOutputWindow(Sess, Buffer, len);
|
|||
|
|
|||
|
|
|||
|
return Len;
|
|||
|
|
|||
|
default:
|
|||
|
return Len;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
case NAK:
|
|||
|
|
|||
|
// Either Reject or Restart
|
|||
|
|
|||
|
// RE Resume NAK len R NULL (File size in ASCII) NULL
|
|||
|
|
|||
|
if (Len > 2 && Msg[2] == 'R' && Msg[3] == 0)
|
|||
|
{
|
|||
|
int posn = atoi((char *)&Msg[4]);
|
|||
|
|
|||
|
YAPPLen += posn;
|
|||
|
MailBufferSize -= posn;
|
|||
|
|
|||
|
YAPPSendData(Sess);
|
|||
|
return Len;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
// May have an error message
|
|||
|
|
|||
|
len = Msg[1];
|
|||
|
|
|||
|
if (len)
|
|||
|
{
|
|||
|
char ws[256];
|
|||
|
|
|||
|
Msg[len + 2] = 0;
|
|||
|
|
|||
|
strcpy(ws, (char *)&Msg[2]);
|
|||
|
|
|||
|
len = sprintf((char *)Buffer, "File rejected - %s\r", ws);
|
|||
|
}
|
|||
|
else
|
|||
|
len = sprintf((char *)Buffer, "File rejected\r");
|
|||
|
|
|||
|
WritetoOutputWindow(Sess, Buffer, len);
|
|||
|
|
|||
|
|
|||
|
Sess->InputMode = 0;
|
|||
|
SendTraceOptions(Sess);
|
|||
|
|
|||
|
return Len;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
len = sprintf((char *)Buffer, "Unexpected message during YAPP Transfer. Transfer cancelled\r");
|
|||
|
WritetoOutputWindow(Sess, Buffer, len);
|
|||
|
|
|||
|
Sess->InputMode = 0;
|
|||
|
SendTraceOptions(Sess);
|
|||
|
|
|||
|
return Len;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
void YAPPSendFile(Ui_ListenSession * Sess, WCHAR * FN)
|
|||
|
{
|
|||
|
int FileSize = 0;
|
|||
|
char MsgFile[MAX_PATH];
|
|||
|
FILE * hFile;
|
|||
|
struct stat STAT;
|
|||
|
UCHAR Buffer[2000];
|
|||
|
int Len;
|
|||
|
|
|||
|
strcpy(MsgFile, FN);
|
|||
|
|
|||
|
if (MsgFile[0] == 0)
|
|||
|
{
|
|||
|
Len = sprintf((char *)Buffer, "Filename missing\r");
|
|||
|
WritetoOutputWindow(Sess, Buffer, Len);
|
|||
|
|
|||
|
SendTraceOptions(Sess);
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
if (stat(MsgFile, &STAT) != -1)
|
|||
|
{
|
|||
|
FileSize = STAT.st_size;
|
|||
|
|
|||
|
hFile = fopen(MsgFile, "rb");
|
|||
|
|
|||
|
if (hFile)
|
|||
|
{
|
|||
|
char Mess[255];
|
|||
|
// time_t UnixTime = STAT.st_mtime;
|
|||
|
|
|||
|
// FILETIME ft;
|
|||
|
// long long ll;
|
|||
|
// SYSTEMTIME st;
|
|||
|
// WORD FatDate;
|
|||
|
// WORD FatTime;
|
|||
|
// struct tm TM;
|
|||
|
|
|||
|
strcpy(ARQFilename, MsgFile);
|
|||
|
|
|||
|
if (MailBuffer)
|
|||
|
{
|
|||
|
free(MailBuffer);
|
|||
|
MailBufferSize = 0;
|
|||
|
MailBuffer = 0;
|
|||
|
}
|
|||
|
|
|||
|
MailBuffer = (UCHAR *)malloc(FileSize);
|
|||
|
MailBufferSize = FileSize;
|
|||
|
YAPPLen = 0;
|
|||
|
fread(MailBuffer, 1, FileSize, hFile);
|
|||
|
|
|||
|
// Get Date and Time for YAPPC Mode
|
|||
|
|
|||
|
/* The MS-DOS date. The date is a packed value with the following format.
|
|||
|
|
|||
|
cant use DosDateTimeToFileTime on Linux
|
|||
|
|
|||
|
Bits Description
|
|||
|
0-4 Day of the month (1<EFBFBD>31)
|
|||
|
5-8 Month (1 = January, 2 = February, and so on)
|
|||
|
9-15 Year offset from 1980 (add 1980 to get actual year)
|
|||
|
wFatTime
|
|||
|
The MS-DOS time. The time is a packed value with the following format.
|
|||
|
Bits Description
|
|||
|
0-4 Second divided by 2
|
|||
|
5-10 Minute (0<EFBFBD>59)
|
|||
|
11-15 Hour (0<EFBFBD>23 on a 24-hour clock)
|
|||
|
|
|||
|
memset(&TM, 0, sizeof(TM));
|
|||
|
|
|||
|
TM.tm_sec = (YAPPDate & 0x1f) << 1;
|
|||
|
TM.tm_min = ((YAPPDate >> 5) & 0x3f);
|
|||
|
TM.tm_hour = ((YAPPDate >> 11) & 0x1f);
|
|||
|
|
|||
|
TM.tm_mday = ((YAPPDate >> 16) & 0x1f);
|
|||
|
TM.tm_mon = ((YAPPDate >> 21) & 0xf) - 1;
|
|||
|
TM.tm_year = ((YAPPDate >> 25) & 0x7f) + 80;
|
|||
|
|
|||
|
|
|||
|
// Note that LONGLONG is a 64-bit value
|
|||
|
|
|||
|
ll = Int32x32To64(UnixTime, 10000000) + 116444736000000000;
|
|||
|
ft.dwLowDateTime = (DWORD)ll;
|
|||
|
ll >>= 32;
|
|||
|
ft.dwHighDateTime = (DWORD)ll;
|
|||
|
|
|||
|
FileTimeToSystemTime(&ft, &st);
|
|||
|
FileTimeToDosDateTime(&ft, &FatDate, &FatTime);
|
|||
|
|
|||
|
YAPPDate = (FatDate << 16) + FatTime;
|
|||
|
|
|||
|
memset(&TM, 0, sizeof(TM));
|
|||
|
|
|||
|
TM.tm_sec = (YAPPDate & 0x1f) << 1;
|
|||
|
TM.tm_min = ((YAPPDate >> 5) & 0x3f);
|
|||
|
TM.tm_hour = ((YAPPDate >> 11) & 0x1f);
|
|||
|
|
|||
|
TM.tm_mday = ((YAPPDate >> 16) & 0x1f);
|
|||
|
TM.tm_mon = ((YAPPDate >> 21) & 0xf) - 1;
|
|||
|
TM.tm_year = ((YAPPDate >> 25) & 0x7f) + 80;
|
|||
|
*/
|
|||
|
fclose(hFile);
|
|||
|
|
|||
|
Mess[0] = ENQ;
|
|||
|
Mess[1] = 1;
|
|||
|
|
|||
|
QueueMsg(Sess, Mess, 2);
|
|||
|
Sess->InputMode = 'Y';
|
|||
|
|
|||
|
Len = sprintf((char *)Buffer, "Sending File %s ...\r", FN);
|
|||
|
WritetoOutputWindow(Sess, Buffer, Len);
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
Len = sprintf((char *)Buffer, "File %s not found\r", FN);
|
|||
|
WritetoOutputWindow(Sess, Buffer, Len);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
void YAPPSendData(Ui_ListenSession * Sess)
|
|||
|
{
|
|||
|
char Mess[258];
|
|||
|
|
|||
|
while (1)
|
|||
|
{
|
|||
|
int Left = MailBufferSize;
|
|||
|
|
|||
|
if (Left == 0)
|
|||
|
{
|
|||
|
// Finished - send End Data
|
|||
|
|
|||
|
Mess[0] = ETX;
|
|||
|
Mess[1] = 1;
|
|||
|
|
|||
|
QueueMsg(Sess, Mess, 2);
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
if (Left > paclen - 3) // two bytes header and possible checksum
|
|||
|
Left = paclen - 3;
|
|||
|
|
|||
|
memcpy(&Mess[2], &MailBuffer[YAPPLen], Left);
|
|||
|
|
|||
|
YAPPLen += Left;
|
|||
|
MailBufferSize -= Left;
|
|||
|
|
|||
|
// if YAPPC add checksum
|
|||
|
|
|||
|
if (YAPPDate)
|
|||
|
{
|
|||
|
UCHAR Sum = 0;
|
|||
|
int i;
|
|||
|
UCHAR * uptr = (UCHAR *)&Mess[2];
|
|||
|
|
|||
|
i = Left;
|
|||
|
|
|||
|
while (i--)
|
|||
|
Sum += *(uptr++);
|
|||
|
|
|||
|
*(uptr) = Sum;
|
|||
|
|
|||
|
Mess[0] = STX;
|
|||
|
Mess[1] = Left;
|
|||
|
|
|||
|
QueueMsg(Sess, Mess, Left + 3);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Mess[0] = STX;
|
|||
|
Mess[1] = Left;
|
|||
|
|
|||
|
QueueMsg(Sess, Mess, Left + 2);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|