674 lines
14 KiB
C
674 lines
14 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
|
||
|
*/
|
||
|
|
||
|
// DRATS support code
|
||
|
|
||
|
#define _CRT_SECURE_NO_DEPRECATE
|
||
|
|
||
|
#include "CHeaders.h"
|
||
|
|
||
|
#include "bpq32.h"
|
||
|
#include "telnetserver.h"
|
||
|
|
||
|
|
||
|
/*
|
||
|
The header is the first 23 bytes of of the frame. The payload is the rest of the frame.
|
||
|
|
||
|
Byte 1 is a "magic" number. It is 0xDD if the payload is zlib compressed before being yencoded.
|
||
|
Bytes 2 and 3 is a 16 bit sequence number.
|
||
|
Byte 4 is a session number.
|
||
|
Byte 5 is a type. Still don't know the types.
|
||
|
Bytes 6 and 7, 16 bits, is the checksum of the data after any compression.
|
||
|
Bytes 8 and 9, 16 bits, is the length of the data.
|
||
|
bytes 10-18, 8 bits, are the source call sign.
|
||
|
bytes 19-25, 8 bits, are the destination call sign.
|
||
|
If a call sign is less than 8 characters, it is padded to fill the space with the "~" tilde character.
|
||
|
|
||
|
Frame types: (Some from sessions/chat.py)
|
||
|
|
||
|
0 - T_DEF
|
||
|
1 - T_PING_REQ - Ping request (Used in Test frame)
|
||
|
2 - T_PING_RSP - Ping response
|
||
|
3 - T_PING_ERS - Ping error status?
|
||
|
4 - T_STATUS - Status frame
|
||
|
5 - File Transfer
|
||
|
8 - Used in Test frame
|
||
|
254 - Apparently a warm up frame.
|
||
|
|
||
|
T_DEF = 0
|
||
|
T_PNG_REQ = 1
|
||
|
T_PNG_RSP = 2
|
||
|
T_PNG_ERQ = 3
|
||
|
T_PNG_ERS = 4
|
||
|
T_STATUS = 5
|
||
|
For a station status frame, the first byte of the message is an ASCII station status value.
|
||
|
|
||
|
'0' - Unknown
|
||
|
'1' - Online
|
||
|
'2' - Unattended
|
||
|
'9' - Offline
|
||
|
*/
|
||
|
|
||
|
#define T_DEF 0
|
||
|
#define T_PNG_REQ 1
|
||
|
#define T_PNG_RSP 2
|
||
|
#define T_PNG_ERQ 3
|
||
|
#define T_PNG_ERS 4
|
||
|
#define T_STATUS 5
|
||
|
|
||
|
#pragma pack(1)
|
||
|
|
||
|
// shorts are big-endian
|
||
|
|
||
|
struct DRATSHeader
|
||
|
{
|
||
|
unsigned char Magic;
|
||
|
unsigned short Seq;
|
||
|
unsigned char Sessno;
|
||
|
unsigned char Type;
|
||
|
unsigned short CheckSum;
|
||
|
unsigned short Length;
|
||
|
char CallFrom[8];
|
||
|
char CallTo[8];
|
||
|
unsigned char Message[2048];
|
||
|
};
|
||
|
|
||
|
#pragma pack()
|
||
|
|
||
|
struct DRATSSession
|
||
|
{
|
||
|
struct ConnectionInfo * sockptr;
|
||
|
unsigned int Seq;
|
||
|
unsigned int Sessno;
|
||
|
char CallFrom[8];
|
||
|
char CallTo[8];
|
||
|
int Stream; // BPQ Stream
|
||
|
int StreamState;
|
||
|
struct DRATSQueue * Queue;
|
||
|
struct DRATSSession * Next;
|
||
|
};
|
||
|
|
||
|
struct DRATSQueue
|
||
|
{
|
||
|
// Queue of messages to be sent to node from background (ie not under semaphore)
|
||
|
|
||
|
int Stream;
|
||
|
int Len;
|
||
|
unsigned char * Msg;
|
||
|
struct DRATSQueue * Next;
|
||
|
};
|
||
|
|
||
|
|
||
|
struct DRATSSession * DRATSSessions = NULL;
|
||
|
|
||
|
|
||
|
char peer0_2[] = { /* Packet 17 */
|
||
|
0x5b, 0x53, 0x4f, 0x42, 0x5d, 0xdd, 0x3d, 0x40,
|
||
|
0x3d, 0x40, 0x01, 0x05, 0x45, 0x78, 0x3d, 0x40,
|
||
|
0x18, 0x47, 0x38, 0x42, 0x50, 0x51, 0x7e, 0x7e,
|
||
|
0x7e, 0x43, 0x51, 0x43, 0x51, 0x43, 0x51, 0x7e,
|
||
|
0x7e, 0x78, 0xda, 0x33, 0xf4, 0xcf, 0xcb, 0xc9,
|
||
|
0xcc, 0x4b, 0x55, 0xd0, 0x70, 0xd1, 0x0d, 0x72,
|
||
|
0x0c, 0x09, 0xd6, 0x04, 0x3d, 0x40, 0x2a, 0x8c,
|
||
|
0x04, 0xb3, 0x5b, 0x45, 0x4f, 0x42, 0x5d };
|
||
|
|
||
|
|
||
|
void processDRATSFrame(unsigned char * Message, int Len, struct ConnectionInfo * sockptr);
|
||
|
|
||
|
int testDRATS()
|
||
|
{
|
||
|
// processDRATSFrame(peer0_1, sizeof(peer0_1), 0);
|
||
|
// processDRATSFrame(peer0_2, sizeof(peer0_2), 0);
|
||
|
// processDRATSFrame(peer1_1, sizeof(peer1_1), 0);
|
||
|
// processDRATSFrame(peer1_20, sizeof(peer1_20));
|
||
|
// processDRATSFrame(peer0_20, sizeof(peer0_20));
|
||
|
// processDRATSFrame(peer1_21, sizeof(peer1_21));
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
extern char pgm[256];
|
||
|
extern char TextVerstring[50];
|
||
|
|
||
|
int HeaderLen = offsetof(struct DRATSHeader, Message);
|
||
|
|
||
|
int doinflate(unsigned char * source, unsigned char * dest, int Len, int destlen, int * outLen);
|
||
|
int dratscrc(unsigned char *ptr, int count);
|
||
|
int FindFreeStreamNoSem();
|
||
|
void sendDRATSFrame(struct ConnectionInfo * sockptr, struct DRATSHeader * Header);
|
||
|
int yEncode(unsigned char * in, unsigned char * out, int len, unsigned char * Banned);
|
||
|
|
||
|
|
||
|
int AllocateDRATSStream(struct DRATSSession * Sess)
|
||
|
{
|
||
|
int Stream;
|
||
|
|
||
|
strcpy(pgm, "DRATS");
|
||
|
|
||
|
Stream = FindFreeStreamNoSem();
|
||
|
|
||
|
strcpy(pgm, "bpq32.exe");
|
||
|
|
||
|
if (Stream == 255) return 0;
|
||
|
|
||
|
if (memcmp(Sess->CallTo, "NODE", 6) == 0)
|
||
|
{
|
||
|
// Just connect to command level on switch
|
||
|
}
|
||
|
|
||
|
return Stream;
|
||
|
}
|
||
|
|
||
|
void ProcessDRATSPayload(struct DRATSHeader * Header, struct DRATSSession * Sess)
|
||
|
{
|
||
|
struct DRATSQueue * QEntry;
|
||
|
BPQVECSTRUC * HOST;
|
||
|
|
||
|
if (Sess->Stream == 0)
|
||
|
{
|
||
|
Sess->Stream = AllocateDRATSStream(Sess);
|
||
|
}
|
||
|
|
||
|
if (Sess->StreamState == 0)
|
||
|
{
|
||
|
unsigned char AXCall[10];
|
||
|
|
||
|
Connect(Sess->Stream); // Connect
|
||
|
ConvToAX25(Sess->CallFrom, AXCall);
|
||
|
ChangeSessionCallsign(Sess->Stream, AXCall); // Prevent triggering incoming connect code
|
||
|
|
||
|
// Clear State Changed bits (cant use SessionState under semaphore)
|
||
|
|
||
|
HOST = &BPQHOSTVECTOR[Sess->Stream -1]; // API counts from 1
|
||
|
HOST->HOSTFLAGS &= 0xFC; // Clear Change Bits
|
||
|
Sess->StreamState = 1;
|
||
|
}
|
||
|
|
||
|
strcat(Header->Message, "\r");
|
||
|
|
||
|
// Need to Queue to Background as we can't use SendMsg under semaphore
|
||
|
|
||
|
QEntry = zalloc(sizeof(struct DRATSQueue));
|
||
|
QEntry->Len = strlen(Header->Message);
|
||
|
QEntry->Msg = malloc(QEntry->Len);
|
||
|
memcpy(QEntry->Msg, Header->Message, QEntry->Len);
|
||
|
|
||
|
// Add to queue
|
||
|
|
||
|
if (Sess->Queue)
|
||
|
{
|
||
|
struct DRATSQueue * End = Sess->Queue;
|
||
|
|
||
|
// Add on end
|
||
|
while (End->Next)
|
||
|
End = End->Next;
|
||
|
|
||
|
End->Next = QEntry;
|
||
|
}
|
||
|
else
|
||
|
Sess->Queue = QEntry;
|
||
|
|
||
|
}
|
||
|
|
||
|
// Called under semaphore
|
||
|
|
||
|
|
||
|
void processDRATSFrame(unsigned char * Message, int Len, struct ConnectionInfo * sockptr)
|
||
|
{
|
||
|
unsigned char * Payload;
|
||
|
unsigned char * ptr;
|
||
|
unsigned char dest[2048];
|
||
|
struct DRATSHeader * Header;
|
||
|
int outLen;
|
||
|
struct DRATSSession * Sess = DRATSSessions;
|
||
|
unsigned short crc, savecrc;
|
||
|
char CallFrom[10] = "";
|
||
|
char CallTo[10] = "";
|
||
|
|
||
|
Message[Len] = 0;
|
||
|
Debugprintf(Message);
|
||
|
|
||
|
Payload = strstr(Message, "[SOB]");
|
||
|
|
||
|
if (Payload == 0)
|
||
|
return;
|
||
|
|
||
|
ptr = strstr(Message, "[EOB]");
|
||
|
|
||
|
if (ptr == 0)
|
||
|
return;
|
||
|
|
||
|
ptr[0] = 0;
|
||
|
|
||
|
Payload += 5;
|
||
|
|
||
|
Header = (struct DRATSHeader *)Payload;
|
||
|
|
||
|
// Undo = transparency
|
||
|
|
||
|
ptr = Payload;
|
||
|
|
||
|
while (ptr = strchr(ptr, '='))
|
||
|
{
|
||
|
memmove(ptr, ptr + 1, Len);
|
||
|
ptr[0] -= 64;
|
||
|
ptr++;
|
||
|
}
|
||
|
|
||
|
// Check CRC
|
||
|
|
||
|
savecrc = htons(Header->CheckSum);
|
||
|
Header->CheckSum = 0;
|
||
|
|
||
|
crc = dratscrc(Payload, htons(Header->Length) + HeaderLen);
|
||
|
|
||
|
if (crc != savecrc)
|
||
|
{
|
||
|
Debugprintf(" DRARS CRC Error %x %x", crc, savecrc); // Good CRC
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
Header->Length = htons(Header->Length); // convert to machine order
|
||
|
|
||
|
if (Header->Magic == 0xdd) // Zlib compressed
|
||
|
{
|
||
|
doinflate(Header->Message, dest, Header->Length, 2048, &outLen);
|
||
|
memcpy(Header->Message, dest, outLen + 1);
|
||
|
Header->Length = outLen;
|
||
|
}
|
||
|
Debugprintf(Header->Message);
|
||
|
|
||
|
// Look for a matching From/To/Session
|
||
|
|
||
|
memcpy(CallFrom, Header->CallFrom, 8);
|
||
|
memcpy(CallTo, Header->CallTo, 8);
|
||
|
|
||
|
strlop(CallFrom, '~');
|
||
|
strlop(CallTo, '~');
|
||
|
|
||
|
if (Header->Type == T_STATUS)
|
||
|
{
|
||
|
// Status frame ?? What to do with it ??
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (Header->Type == T_PNG_REQ)
|
||
|
{
|
||
|
// "Ping Request"
|
||
|
|
||
|
// if to "NODE" reply to it
|
||
|
|
||
|
if (strcmp(CallTo, "NODE") == 0)
|
||
|
{
|
||
|
// Reuse incoming message
|
||
|
|
||
|
strcpy(Header->CallFrom, CallTo);
|
||
|
strcpy(Header->CallTo, CallFrom);
|
||
|
Header->Type = T_PNG_RSP;
|
||
|
Header->Length = sprintf(Header->Message, "Running BPQ32 Version %s", TextVerstring);
|
||
|
|
||
|
sendDRATSFrame(sockptr, Header);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Not to us - do we route it ??
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (Header->Type == T_PNG_RSP)
|
||
|
{
|
||
|
// Reponse is PNG_RSP then Status - 1Online (D-RATS)
|
||
|
// "Running D-RATS 0.3.9 (Windows 8->10 (6, 2, 9200, 2, ''))"
|
||
|
// "Running D-RATS 0.3.10 beta 4 (Linux - Raspbian GNU/Linux 9)"
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (Header->Type != T_DEF)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// ?? Normal Data
|
||
|
|
||
|
if (strcmp(CallTo, "NODE") != 0)
|
||
|
{
|
||
|
// Not not Node - should we route it ??
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
while (Sess)
|
||
|
{
|
||
|
if (Sess->Sessno == Header->Sessno && memcmp(Sess->CallFrom, CallFrom, 8) == 0
|
||
|
&& memcmp(Sess->CallTo, CallTo, 8) == 0 && Sess->sockptr == sockptr)
|
||
|
{
|
||
|
ProcessDRATSPayload(Header, Sess);
|
||
|
return;
|
||
|
}
|
||
|
Sess = Sess->Next;
|
||
|
}
|
||
|
|
||
|
// Allocate a new one
|
||
|
|
||
|
Sess = zalloc(sizeof(struct DRATSSession));
|
||
|
|
||
|
Sess->Sessno = Header->Sessno;
|
||
|
memcpy(Sess->CallFrom, CallFrom, 8);
|
||
|
memcpy(Sess->CallTo, CallTo, 8);
|
||
|
Sess->sockptr = sockptr;
|
||
|
|
||
|
if (DRATSSessions)
|
||
|
{
|
||
|
// Add to front of Chain
|
||
|
|
||
|
Sess->Next = DRATSSessions;
|
||
|
}
|
||
|
|
||
|
DRATSSessions = Sess;
|
||
|
|
||
|
ProcessDRATSPayload(Header, Sess);
|
||
|
return;
|
||
|
|
||
|
}
|
||
|
|
||
|
void DRATSPoll()
|
||
|
{
|
||
|
struct DRATSSession * Sess = DRATSSessions;
|
||
|
int Stream, state, change;
|
||
|
int count;
|
||
|
struct DRATSHeader Header;
|
||
|
struct DRATSQueue * QEntry;
|
||
|
struct DRATSQueue * Save;
|
||
|
|
||
|
while (Sess)
|
||
|
{
|
||
|
Stream = Sess->Stream;
|
||
|
SessionState(Stream, &state, &change);
|
||
|
|
||
|
if (change == 1)
|
||
|
{
|
||
|
if (state == 1)
|
||
|
{
|
||
|
// Connected - do we need anything ??
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Send a disconnected message
|
||
|
|
||
|
char From[10] = "~~~~~~~~~";
|
||
|
char To[10] = "~~~~~~~~~";
|
||
|
|
||
|
Sess->StreamState = 0;
|
||
|
|
||
|
Header.Length = sprintf(Header.Message, "*** Disconnected from Node");
|
||
|
|
||
|
|
||
|
memcpy(To, Sess->CallFrom, strlen(Sess->CallFrom));
|
||
|
memcpy(From, Sess->CallTo, strlen(Sess->CallTo));
|
||
|
|
||
|
memcpy(Header.CallFrom, From, 8);
|
||
|
memcpy(Header.CallTo, To, 8);
|
||
|
|
||
|
Header.Magic = 0x22;
|
||
|
Header.Type = 0;
|
||
|
Header.Seq = 0;
|
||
|
Header.Sessno = Sess->Sessno;
|
||
|
|
||
|
sendDRATSFrame(Sess->sockptr, &Header);
|
||
|
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
do
|
||
|
{
|
||
|
int Len;
|
||
|
|
||
|
GetMsg(Stream, (char *)Header.Message, &Len, &count);
|
||
|
Header.Length = Len;
|
||
|
|
||
|
if (Header.Length)
|
||
|
{
|
||
|
char From[10] = "~~~~~~~~~";
|
||
|
char To[10] = "~~~~~~~~~";
|
||
|
|
||
|
memcpy(To, Sess->CallFrom, strlen(Sess->CallFrom));
|
||
|
memcpy(From, Sess->CallTo, strlen(Sess->CallTo));
|
||
|
|
||
|
memcpy(Header.CallFrom, From, 8);
|
||
|
memcpy(Header.CallTo, To, 8);
|
||
|
|
||
|
Header.Magic = 0x22;
|
||
|
Header.Type = 0;
|
||
|
Header.Seq = 0;
|
||
|
Header.Sessno = Sess->Sessno;
|
||
|
|
||
|
sendDRATSFrame(Sess->sockptr, &Header);
|
||
|
}
|
||
|
}
|
||
|
while (count > 0);
|
||
|
|
||
|
// See if anything to send to node
|
||
|
|
||
|
QEntry = Sess->Queue;
|
||
|
|
||
|
while (QEntry)
|
||
|
{
|
||
|
SendMsg(Sess->Stream, QEntry->Msg, QEntry->Len);
|
||
|
Save = QEntry;
|
||
|
QEntry = QEntry->Next;
|
||
|
free(Save->Msg);
|
||
|
free(Save);
|
||
|
}
|
||
|
|
||
|
Sess->Queue = 0;
|
||
|
Sess = Sess->Next;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
unsigned char BANNED[] = {'=', 0x11, 0x13, 0x1A, 0xFD, 0xFE, 0xFF, 0};
|
||
|
|
||
|
|
||
|
void sendDRATSFrame(struct ConnectionInfo * sockptr, struct DRATSHeader * Header)
|
||
|
{
|
||
|
unsigned short crc;
|
||
|
int len;
|
||
|
unsigned char out[2048] = "[SOB]";
|
||
|
int packetLen = Header->Length + HeaderLen;
|
||
|
|
||
|
// Length is in host order
|
||
|
|
||
|
Header->Length = htons(Header->Length);
|
||
|
|
||
|
Header->CheckSum = 0;
|
||
|
|
||
|
crc = dratscrc((unsigned char *)Header, packetLen);
|
||
|
Header->CheckSum = htons(crc);
|
||
|
|
||
|
len = yEncode((unsigned char *)Header, out + 5, packetLen, BANNED);
|
||
|
|
||
|
memcpy(&out[len + 5], "[EOB]", 5);
|
||
|
Debugprintf(out);
|
||
|
send(sockptr->socket, out, len + 10, 0);
|
||
|
}
|
||
|
|
||
|
void DRATSConnectionLost(struct ConnectionInfo * sockptr)
|
||
|
{
|
||
|
// Disconnect any sessions, then free Stream and Sess record
|
||
|
|
||
|
struct DRATSSession * Sess = DRATSSessions;
|
||
|
struct DRATSSession * Save = 0;
|
||
|
BPQVECSTRUC * HOST;
|
||
|
|
||
|
while (Sess)
|
||
|
{
|
||
|
if (Sess->sockptr == sockptr)
|
||
|
{
|
||
|
if (Sess->StreamState == 1) // COnnected
|
||
|
{
|
||
|
Disconnect(Sess->Stream);
|
||
|
HOST = &BPQHOSTVECTOR[Sess->Stream -1]; // API counts from 1
|
||
|
HOST->HOSTFLAGS &= 0xFC; // Clear Change Bits
|
||
|
}
|
||
|
DeallocateStream(Sess->Stream);
|
||
|
|
||
|
// We must unhook from chain
|
||
|
|
||
|
if (Save)
|
||
|
Save->Next = Sess->Next;
|
||
|
else
|
||
|
DRATSSessions = Sess->Next;
|
||
|
|
||
|
// Should really Free any Queue, but unlikely to be any
|
||
|
|
||
|
free(Sess);
|
||
|
|
||
|
if (Save)
|
||
|
Sess = Save->Next;
|
||
|
else
|
||
|
Sess = DRATSSessions;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Save = Sess;
|
||
|
Sess = Sess->Next;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
#ifdef WIN32
|
||
|
#define ZEXPORT __stdcall
|
||
|
#endif
|
||
|
|
||
|
#include "zlib.h"
|
||
|
|
||
|
|
||
|
int doinflate(unsigned char * source, unsigned char * dest, int Len, int destlen, int * outLen)
|
||
|
{
|
||
|
int ret;
|
||
|
z_stream strm;
|
||
|
|
||
|
strm.zalloc = Z_NULL;
|
||
|
strm.zfree = Z_NULL;
|
||
|
strm.opaque = Z_NULL;
|
||
|
strm.avail_in = 0;
|
||
|
strm.next_in = Z_NULL;
|
||
|
|
||
|
ret = inflateInit(&strm);
|
||
|
if (ret != Z_OK)
|
||
|
return ret;
|
||
|
|
||
|
strm.avail_in = Len;
|
||
|
strm.next_in = source;
|
||
|
|
||
|
strm.avail_out = destlen;
|
||
|
strm.next_out = dest;
|
||
|
|
||
|
ret = inflate(&strm, Z_NO_FLUSH);
|
||
|
|
||
|
inflateEnd(&strm);
|
||
|
|
||
|
dest[strm.total_out] = 0;
|
||
|
|
||
|
*outLen = strm.total_out;
|
||
|
|
||
|
return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
|
||
|
}
|
||
|
|
||
|
// No idea what this CRC is, but it works! (converted from DRATS python code)
|
||
|
|
||
|
int update_crc(int c, int crc)
|
||
|
{
|
||
|
int i;
|
||
|
int v;
|
||
|
|
||
|
for (i = 0; i < 8; i++)
|
||
|
{
|
||
|
if ((c & 0x80))
|
||
|
v = 1;
|
||
|
else
|
||
|
v = 0;
|
||
|
|
||
|
if (crc & 0x8000)
|
||
|
{
|
||
|
crc <<= 1;
|
||
|
crc += v;
|
||
|
crc ^= 0x1021;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
crc <<= 1;
|
||
|
crc += v;
|
||
|
}
|
||
|
|
||
|
c <<= 1;
|
||
|
}
|
||
|
|
||
|
crc &= 0xFFFF;
|
||
|
return crc;
|
||
|
|
||
|
}
|
||
|
|
||
|
int dratscrc(unsigned char *ptr, int count)
|
||
|
{
|
||
|
int i;
|
||
|
int checksum = 0;
|
||
|
|
||
|
for (i = 0; i < count; i++)
|
||
|
checksum = update_crc(ptr[i], checksum);
|
||
|
|
||
|
checksum = update_crc(0, checksum);
|
||
|
checksum = update_crc(0, checksum);
|
||
|
return checksum;
|
||
|
}
|
||
|
|
||
|
#define OFFSET 64
|
||
|
|
||
|
int yEncode(unsigned char * in, unsigned char * out, int len, unsigned char * Banned)
|
||
|
{
|
||
|
unsigned char * ptr = out;
|
||
|
unsigned char c;
|
||
|
|
||
|
while (len--)
|
||
|
{
|
||
|
c = *(in++);
|
||
|
|
||
|
if (strchr(&Banned[0], c))
|
||
|
{
|
||
|
*(out++) = '=';
|
||
|
*(out++) = (c + OFFSET) & 0xFF;
|
||
|
}
|
||
|
else
|
||
|
*(out++) = c;
|
||
|
}
|
||
|
|
||
|
return (out - ptr);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|