linbpq/lzhuf32.c

1801 lines
47 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
//
// lzhuf Routines
#include "bpqmail.h"
BOOL isAMPRMsg(char * Addr);
struct Country * FindCountry(char * Name);
struct UserInfo * FindAMPR();
/**************************************************************
lzhuf.c
written by Haruyasu Yoshizaki 1988/11/20
some minor changes 1989/04/06
comments translated by Haruhiko Okumura 1989/04/07
getbit and getbyte modified 1990/03/23 by Paul Edwards
so that they would work on machines where integers are
not necessarily 16 bits (although ANSI guarantees a
minimum of 16). This program has compiled and run with
no errors under Turbo C 2.0, Power C, and SAS/C 4.5
(running on an IBM mainframe under MVS/XA 2.2). Could
people please use YYYY/MM/DD date format so that everyone
in the world can know what format the date is in?
external storage of filesize changed 1990/04/18 by Paul Edwards to
Intel's "little endian" rather than a machine-dependant style so
that files produced on one machine with lzhuf can be decoded on
any other. "little endian" style was chosen since lzhuf
originated on PC's, and therefore they should dictate the
standard.
initialization of something predicting spaces changed 1990/04/22 by
Paul Edwards so that when the compressed file is taken somewhere
else, it will decode properly, without changing ascii spaces to
ebcdic spaces. This was done by changing the ' ' (space literal)
to 0x20 (which is the far most likely character to occur, if you
don't know what environment it will be running on.
**************************************************************/
int ReformatSyncMessage(CIRCUIT * conn);
#define int __int16
/* crctab calculated by Mark G. Mendel, Network Systems Corporation */
UCHAR *infile, *outfile, * endinfile;
short Get()
{
if (infile == endinfile)
return -1;
else
return *(infile++);
}
static unsigned short crctab[256] = {
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
};
#define updcrc(cp, crc) ((crc << 8) ^ crctab[(cp & 0xff) ^ (crc >> 8)])
uint32_t textsize = 0, codesize = 0;
unsigned short crc;
int version_1;
char wterr[] = "Can't write.";
void Error(char *message)
{
printf("\n%s\n", message);
exit(EXIT_FAILURE);
}
/********** LZSS compression **********/
#define N 2048 /* buffer size */
#define F 60 /* lookahead buffer size */
#define THRESHOLD 2
#define NIL N /* leaf of tree */
unsigned char
text_buf[N + F - 1];
static int match_position, match_length,
lson[N + 1], rson[N + 257], dad[N + 1];
static int crc_fputc(unsigned short c)
{
crc = updcrc(c, crc);
*(outfile++) = (unsigned char)c;
return 0;
}
short crc_fgetc()
{
short retour = *(infile++);
return(retour);
}
void InitTree(void) /* initialize trees */
{
int i;
for (i = N + 1; i <= N + 256; i++)
rson[i] = NIL; /* root */
for (i = 0; i < N; i++)
dad[i] = NIL; /* node */
}
static void InsertNode(int r) /* insert to tree */
{
int i, p, cmp;
unsigned char *key;
unsigned c;
cmp = 1;
key = &text_buf[r];
p = N + 1 + key[0];
rson[r] = lson[r] = NIL;
match_length = 0;
for ( ; ; ) {
if (cmp >= 0) {
if (rson[p] != NIL)
p = rson[p];
else {
rson[p] = r;
dad[r] = p;
return;
}
} else {
if (lson[p] != NIL)
p = lson[p];
else {
lson[p] = r;
dad[r] = p;
return;
}
}
for (i = 1; i < F; i++)
if ((cmp = key[i] - text_buf[p + i]) != 0)
break;
if (i > THRESHOLD) {
if (i > match_length) {
match_position = ((r - p) & (N - 1)) - 1;
if ((match_length = i) >= F)
break;
}
if (i == match_length) {
if ((c = ((r - p) & (N-1)) - 1) < (unsigned)match_position) {
match_position = c;
}
}
}
}
dad[r] = dad[p];
lson[r] = lson[p];
rson[r] = rson[p];
dad[lson[p]] = r;
dad[rson[p]] = r;
if (rson[dad[p]] == p)
rson[dad[p]] = r;
else
lson[dad[p]] = r;
dad[p] = NIL; /* remove p */
}
static void DeleteNode(int p) /* remove from tree */
{
int q;
if (dad[p] == NIL)
return; /* not registered */
if (rson[p] == NIL)
q = lson[p];
else
if (lson[p] == NIL)
q = rson[p];
else {
q = lson[p];
if (rson[q] != NIL) {
do {
q = rson[q];
} while (rson[q] != NIL);
rson[dad[q]] = lson[q];
dad[lson[q]] = dad[q];
lson[q] = lson[p];
dad[lson[p]] = q;
}
rson[q] = rson[p];
dad[rson[p]] = q;
}
dad[q] = dad[p];
if (rson[dad[p]] == p)
rson[dad[p]] = q;
else
lson[dad[p]] = q;
dad[p] = NIL;
}
/* Huffman coding */
#define N_CHAR (256 - THRESHOLD + F)
/* kinds of characters (character code = 0..N_CHAR-1) */
#define T (N_CHAR * 2 - 1) /* size of table */
#define R (T - 1) /* position of root */
#define MAX_FREQ 0x8000 /* updates tree when the */
/* root frequency comes to this value. */
typedef unsigned char uchar;
/* table for encoding and decoding the upper 6 bits of position */
/* for encoding */
uchar p_len[64] = {
0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06,
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08
};
uchar p_code[64] = {
0x00, 0x20, 0x30, 0x40, 0x50, 0x58, 0x60, 0x68,
0x70, 0x78, 0x80, 0x88, 0x90, 0x94, 0x98, 0x9C,
0xA0, 0xA4, 0xA8, 0xAC, 0xB0, 0xB4, 0xB8, 0xBC,
0xC0, 0xC2, 0xC4, 0xC6, 0xC8, 0xCA, 0xCC, 0xCE,
0xD0, 0xD2, 0xD4, 0xD6, 0xD8, 0xDA, 0xDC, 0xDE,
0xE0, 0xE2, 0xE4, 0xE6, 0xE8, 0xEA, 0xEC, 0xEE,
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
};
/* for decoding */
uchar d_code[256] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B,
0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D,
0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F,
0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11,
0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13,
0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15,
0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17,
0x18, 0x18, 0x19, 0x19, 0x1A, 0x1A, 0x1B, 0x1B,
0x1C, 0x1C, 0x1D, 0x1D, 0x1E, 0x1E, 0x1F, 0x1F,
0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23,
0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27,
0x28, 0x28, 0x29, 0x29, 0x2A, 0x2A, 0x2B, 0x2B,
0x2C, 0x2C, 0x2D, 0x2D, 0x2E, 0x2E, 0x2F, 0x2F,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
};
uchar d_len[256] = {
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
};
unsigned int freq[T + 1]; /* frequency table */
int prnt[T + N_CHAR]; /* pointers to parent nodes, except for the */
/* elements [T..T + N_CHAR - 1] which are used to get */
/* the positions of leaves corresponding to the codes. */
int son[T]; /* pointers to child nodes (son[], son[] + 1) */
unsigned int getbuf = 0;
uchar getlen = 0;
static int GetBit(void) /* get one bit */
{
unsigned int i;
while (getlen <= 8) {
if ((i = crc_fgetc()) < 0) i = 0;
getbuf |= i << (8 - getlen);
getlen += 8;
}
i = getbuf;
getbuf <<= 1;
getlen--;
return (int)((i & 0x8000) >> 15);
}
static int GetByte(void) /* get one byte */
{
unsigned int i;
while (getlen <= 8) {
if ((i = crc_fgetc()) == 0xffff) i = 0;
getbuf |= i << (8 - getlen);
getlen += 8;
}
i = getbuf;
getbuf <<= 8;
getlen -= 8;
return (int)((i & 0xff00) >> 8);
}
unsigned int putbuf = 0;
uchar putlen = 0;
static void Putcode(int l, unsigned c) /* output c bits of code */
{
putbuf |= c >> putlen;
if ((putlen += l) >= 8) {
if (crc_fputc(putbuf >> 8) == EOF) {
Error(wterr);
}
if ((putlen -= 8) >= 8) {
if (crc_fputc(putbuf) == EOF) {
Error(wterr);
}
codesize += 2;
putlen -= 8;
putbuf = c << (l - putlen);
} else {
putbuf <<= 8;
codesize++;
}
}
}
/* initialization of tree */
int StartHuff(void)
{
int i, j;
for (i = 0; i < N_CHAR; i++) {
freq[i] = 1;
son[i] = i + T;
prnt[i + T] = i;
}
i = 0; j = N_CHAR;
while (j <= R) {
freq[j] = freq[i] + freq[i + 1];
son[j] = i;
prnt[i] = prnt[i + 1] = j;
i += 2; j++;
}
freq[T] = 0xffff;
prnt[R] = 0;
return 0;
}
/* reconstruction of tree */
static void reconst(void)
{
int i, j, k;
unsigned int f, l;
/* collect leaf nodes in the first half of the table */
/* and replace the freq by (freq + 1) / 2. */
j = 0;
for (i = 0; i < T; i++) {
if (son[i] >= T) {
freq[j] = (freq[i] + 1) / 2;
son[j] = son[i];
j++;
}
}
/* begin constructing tree by connecting sons */
for (i = 0, j = N_CHAR; j < T; i += 2, j++) {
k = i + 1;
f = freq[j] = freq[i] + freq[k];
for (k = j - 1; f < freq[k]; k--);
k++;
l = (j - k) * 2;
memmove(&freq[k + 1], &freq[k], l);
freq[k] = f;
memmove(&son[k + 1], &son[k], l);
son[k] = i;
}
/* connect prnt */
for (i = 0; i < T; i++) {
if ((k = son[i]) >= T) {
prnt[k] = i;
} else {
prnt[k] = prnt[k + 1] = i;
}
}
}
/* increment frequency of given code by one, and update tree */
static void update(int c)
{
int i, j, l;
unsigned int k;
if (freq[R] == MAX_FREQ) {
reconst();
}
c = prnt[c + T];
do {
k = ++freq[c];
/* if the order is disturbed, exchange nodes */
l = c + 1;
if ((unsigned)k > freq[l])
{
while ((unsigned)k > freq[++l]);
l--;
freq[c] = freq[l];
freq[l] = k;
i = son[c];
prnt[i] = l;
if (i < T) prnt[i + 1] = l;
j = son[l];
son[l] = i;
prnt[j] = c;
if (j < T) prnt[j + 1] = c;
son[c] = j;
c = l;
}
} while ((c = prnt[c]) != 0); /* repeat up to root */
}
unsigned code, len;
static void EncodeChar(unsigned int c)
{
unsigned int i;
int j, k;
i = 0;
j = 0;
k = prnt[c + T];
/* travel from leaf to root */
do {
i >>= 1;
/* if node's address is odd-numbered, choose bigger brother node */
if (k & 1) i += 0x8000;
j++;
} while ((k = prnt[k]) != R);
Putcode(j, i);
code = i;
len = j;
update(c);
}
static void EncodePosition(unsigned int c)
{
unsigned int i;
/* output upper 6 bits by table lookup */
i = c >> 6;
Putcode(p_len[i], (unsigned)p_code[i] << 8);
/* output lower 6 bits verbatim */
Putcode(6, (c & 0x3f) << 10);
}
static void EncodeEnd(void)
{
if (putlen) {
if (crc_fputc(putbuf >> 8) == EOF) {
Error(wterr);
}
codesize++;
}
}
int DecodeChar(void)
{
unsigned int c;
c = son[R];
/* travel from root to leaf, */
/* choosing the smaller child node (son[]) if the read bit is 0, */
/* the bigger (son[]+1} if 1 */
while (c < T) {
c += GetBit();
c = son[c];
}
c -= T;
update(c);
return (int)c;
}
int DecodePosition(void)
{
unsigned int i, j, c;
/* recover upper 6 bits from table */
i = GetByte();
c = (unsigned)d_code[i] << 6;
j = d_len[i];
/* read lower 6 bits verbatim */
j -= 2;
while (j--) {
i = (i << 1) + GetBit();
}
return (int)(c | (i & 0x3f));
}
/* compression */
int32_t Encode(char * in, char * out, int32_t inlen, BOOL B1Protocol, int Compress)
{
int i, c, len, r, s, last_match_length;
unsigned char *ptr;
putbuf = 0;
putlen = 0;
textsize = 0;
codesize = 0;
crc = 0;
outfile = out;
if (B1Protocol)
outfile+=2; // Space for CRC
// infile = &conn->MailBuffer[2];
textsize = inlen;
ptr = (char *)&textsize;
#ifdef __BIG_ENDIAN__
crc_fputc(*(ptr+3));
crc_fputc(*(ptr+2));
crc_fputc(*(ptr+1));
crc_fputc(*(ptr));
#else
crc_fputc(*(ptr++));
crc_fputc(*(ptr++));
crc_fputc(*(ptr++));
crc_fputc(*(ptr++));
#endif
if (textsize == 0)
return 0;
infile = in;
endinfile = infile + inlen;
textsize = 0; /* rewind and re-read */
// if using uncompressed just copy in to out
// may not be optimum but is simple!
if (Compress)
{
StartHuff();
InitTree();
s = 0;
r = N - F;
for (i = s; i < r; i++)
text_buf[i] = 0x20;
for (len = 0; len < F && (c = Get()) != EOF; len++)
text_buf[r + len] = (unsigned char)c;
textsize = len;
for (i = 1; i <= F; i++)
InsertNode(r - i);
InsertNode(r);
do
{
if (match_length > len)
match_length = len;
if (match_length <= THRESHOLD)
{
match_length = 1;
EncodeChar(text_buf[r]);
}
else
{
EncodeChar(255 - THRESHOLD + match_length);
EncodePosition(match_position);
}
last_match_length = match_length;
for (i = 0; i < last_match_length && (c = Get()) != EOF; i++)
{
DeleteNode(s);
text_buf[s] = (unsigned char)c;
if (s < F - 1)
text_buf[s + N] = (unsigned char)c;
s = (s + 1) & (N - 1);
r = (r + 1) & (N - 1);
InsertNode(r);
}
while (i++ < last_match_length)
{
DeleteNode(s);
s = (s + 1) & (N - 1);
r = (r + 1) & (N - 1);
if (--len) InsertNode(r);
}
}
while (len > 0);
EncodeEnd();
}
else
{
int32_t n = inlen;
while (n--)
crc_fputc(*(infile++));
codesize += inlen;
}
if (B1Protocol)
{
out[0] = crc & 0xff;
out[1]= crc >> 8;
codesize+=2;
}
codesize += 4;
if (Compress)
Logprintf(LOG_BBS, NULL, '|', "Compressed Message Comp Len %d Msg Len %d CRC %x",
codesize, inlen, crc);
else
Logprintf(LOG_BBS, NULL, '|', "Uncompressed Message Sent Len %d Msg Len %d CRC %x",
codesize, inlen, crc);
return codesize;
}
BOOL CheckifPacket(char * Via)
{
char * ptr1, * ptr2;
// Message addressed to a non-winlink address
// Need to see if real smtp, or a packet address
// No . in address assume Packet - g8bpq@g8bpq
ptr1 = strchr(Via, '.');
if (ptr1 == NULL)
return TRUE; // Packet
// Find Last Element
ptr2 = strchr(++ptr1, '.');
while (ptr2)
{
ptr1 = ptr2;
ptr2 = strchr(++ptr1, '.');
}
if (ptr1[0] == 0)
return TRUE; // Packet
// ptr1 is last element. If a valid continent, it is a packet message
if (FindContinent(ptr1))
return TRUE; // Packet
if (FindCountry(ptr1))
return TRUE; // Packet
if ((_stricmp(ptr1, "MARS") == 0) || (_stricmp(ptr1, "USA") == 0)) // MARS used both
return TRUE; // Packet
return FALSE;
}
void Decode(CIRCUIT * conn, int FromSync)
{
unsigned char *ptr;
char * StartofMsg;
short i, j, k, r;
short c;
uint32_t count;
unsigned short crc_read;
int Index = 0;
struct FBBHeaderLine * FBBHeader= &conn->FBBHeaders[0]; // The Headers from an FFB forward block
BOOL NTS = FALSE;
getbuf = 0;
getlen = 0;
textsize = 0;
codesize = 0;
infile = &conn->MailBuffer[0];
crc = 0;
if (conn->BBSFlags & FBBB1Mode)
{
short val;
uint32_t n;
crc_read = infile[0];
crc_read |= infile[1] << 8;
for (n = 2; n < conn->TempMsg->length; n++)
{
val = infile[n];
crc = updcrc(val, crc);
}
if (crc != crc_read)
{
nodeprintf(conn, "*** Message CRC Error File %x Calc %x\r", crc_read, crc);
free(conn->MailBuffer);
conn->MailBufferSize=0;
conn->MailBuffer=0;
conn->CloseAfterFlush = 20; // 2 Secs
return;
}
infile+=2;
}
textsize = 0;
ptr = (char *)&textsize;
#ifdef __BIG_ENDIAN__
ptr[3] = (unsigned char)crc_fgetc();
ptr[2] = (unsigned char)crc_fgetc();
ptr[1] = (unsigned char)crc_fgetc();
ptr[0] = (unsigned char)crc_fgetc();
#else
for (i = 0 ; i < sizeof(textsize) ; i++)
ptr[i] = (unsigned char)crc_fgetc();
#endif
// Temp fix for duff MACBPQ (Message Length sent big-endian)
if (textsize > 500000)
{
char x[4];
char y[4];
memcpy(x, &textsize, 4);
y[0] = x[3];
y[1] = x[2];
y[2] = x[1];
y[3] = x[0];
memcpy(&textsize, y, 4);
if (textsize > 5000000)
{
nodeprintf(conn, "*** Message Size Invalid %d\r", textsize);
Debugprintf("*** Message Size Invalid %d\r", textsize);
free(conn->MailBuffer);
conn->MailBufferSize=0;
conn->MailBuffer=0;
conn->CloseAfterFlush = 20; // 2 Secs
return;
}
}
Logprintf(LOG_BBS, conn, '|', "Uncompressing Message Comp Len %d Msg Len %d CRC %x",
conn->TempMsg->length, textsize, crc);
outfile = zalloc(textsize + 10000); // Lots of space for B2 header manipulations
if (textsize == 0)
return;
// If compressed, decompress
if (conn->BBSFlags & FBBCompressed)
{
StartHuff();
for (i = 0; i < N - F; i++)
text_buf[i] = 0x20;
r = N - F;
for (count = 0; count < textsize; )
{
c = DecodeChar();
if (c < 256)
{
*(outfile++) = (unsigned char)c;
text_buf[r++] = (unsigned char)c;
r &= (N - 1);
count++;
}
else
{
i = (r - DecodePosition() - 1) & (N - 1);
j = c - 255 + THRESHOLD;
for (k = 0; k < j; k++)
{
c = text_buf[(i + k) & (N - 1)];
*(outfile++) = (unsigned char)c;
text_buf[r++] = (unsigned char)c;
r &= (N - 1);
count++;
}
}
}
outfile -=count;
}
else
{
count = textsize;
memcpy(outfile, infile, textsize);
}
free(conn->MailBuffer);
conn->MailBuffer = outfile;
conn->TempMsg->length = count;
if (FromSync)
{
// Refomat Sync message as if from WLE
if (ReformatSyncMessage(conn) == 0)
return;
FBBHeader->B2Message = TRUE;
FBBHeader->MsgType = 'P';
}
if (!FBBHeader->B2Message)
{
// With B2 the Type is specified in the body, so can't update stats now
if (FBBHeader->MsgType == 'P')
Index = PMSG;
else if (FBBHeader->MsgType == 'B')
Index = BMSG;
else if (FBBHeader->MsgType == 'T')
Index = TMSG;
conn->UserPointer->Total.MsgsReceived[Index]++;
conn->UserPointer->Total.BytesForwardedIn[Index] += count;
}
if (FBBHeader->B2Message)
{
// Parse the Message for B2 From and To info
/*
MID: A3EDD4P00P55
Date: 2009/07/25 10:08
Type: Private
From: SMTP:john.wiseman@ntlworld.com
To: G8BPQ
Subject: RE: RMS Test Messaage
Mbo: SMTP
Body: 214
File: 3556 NOLA.XLS
File: 5566 NEWBOAT.HOMEPORT.JPG
*/
UCHAR * ptr1, * ptr2, * ptr3;
__int32 linelen, MsgLen = 0;
struct MsgInfo * Msg = conn->TempMsg;
time_t Date;
char FullTo[100];
char FullFrom[100];
char ** RecpTo = NULL; // May be several Recipients
char ** HddrTo = NULL; // May be several Recipients
char ** Via = NULL; // May be several Recipients
__int32 LocalMsg[1000]; // Set if Recipient is a local wl2k address
char Type[1000]; // Message Type for each dest
__int32 B2To; // Offset to To: fields in B2 header
__int32 Recipients = 0;
__int32 RMSMsgs = 0, BBSMsgs = 0;
#ifndef LINBPQ
struct _EXCEPTION_POINTERS exinfo;
__try {
#endif
Msg->B2Flags |= B2Msg;
// Display the whole header for debugging
/*
ptr1 = strstr(outfile, "\r\n\r\n");
if (ptr1)
{
*ptr1 = 0;
Debugprintf("B2 Header = %s", outfile);
*ptr1 = '\r';
}
*/
if (_stricmp(conn->Callsign, "RMS") == 0)
Msg->B2Flags |= FromCMS;
if (conn->RadioOnlyMode == 'T')
Msg->B2Flags |= RadioOnlyMsg;
else if (conn->RadioOnlyMode == 'R')
Msg->B2Flags |= RadioOnlyFwd;
ptr1 = outfile;
Loop:
ptr2 = strchr(ptr1, '\r');
linelen = (int)(ptr2 - ptr1);
if (_memicmp(ptr1, "From:", 5) == 0)
{
memcpy(FullFrom, ptr1, linelen);
FullFrom[linelen] = 0;
if (conn->Paclink || (conn->RMSExpress && (conn->UserPointer->flags & F_NOWINLINK) == 0))
{
// Messages just have the call - need to add @winlink.org
strcpy(Msg->emailfrom, "@winlink.org");
}
if (_memicmp(&ptr1[6], "smtp:", 5) == 0)
{
if (_stricmp(conn->Callsign, "RMS") == 0)
{
// Swap smtp: to rms: and save originator so we can reply via RMS
strcpy(Msg->from, "RMS:");
memcpy(Msg->emailfrom, &ptr1[11], linelen - 11);
}
else
{
strcpy(Msg->from, "SMTP:");
memcpy(Msg->emailfrom, &ptr1[11], linelen - 11);
}
}
else
{
char SaveFrom[100];
char * FromHA;
// B2 From may now contain an @BBS
strcpy(SaveFrom, FullFrom);
FromHA = strlop(SaveFrom, '@');
// If it has an @ it could be an internet address - if it has a dot or longer than
// 6 chars assume it is.
// No, could also be packet
// I don't think you can have an Internet message without a . in @field
// Why not just use checkifpacket ??
if (FromHA && !CheckifPacket(FromHA))
{
// Internet address - set from empty and full email in
// emailfrom
strcpy(Msg->from, "SMTP:");
if (strlen(FullFrom) > 46)
FullFrom[46] = 0;
strcpy(Msg->emailfrom, &FullFrom[6]);
}
else
{
// Not an Internet Address so must be a callsign and therefore <= 6 chars
if (strlen(SaveFrom) > 12)
SaveFrom[12] = 0;
strcpy(Msg->from, &SaveFrom[6]);
if (FromHA)
{
if (strlen(FromHA) > 39) FromHA[39] = 0;
Msg->emailfrom[0] = '@';
strcpy(&Msg->emailfrom[1], _strupr(FromHA));
}
}
// Remove any SSID
ptr3 = strchr(Msg->from, '-');
if (ptr3) *ptr3 = 0;
}
// If from a CMS, and no @ in message, append @winlink.org to the B2 Header.
// so messages passed via B2 know it is from Winlink
if ((Msg->B2Flags & FromCMS) && strchr(FullFrom, '@') == NULL)
{
// Move Message down buffer - ptr2 is the insertion point
memmove(ptr2+12, ptr2, count);
memcpy(ptr2, "@winlink.org", 12);
count += 12;
conn->TempMsg->length += 12;
// Also set Emailfrom, in case read on BBS (eg by outpost)
strcat(Msg->emailfrom, "@winlink.org");
}
}
else if (_memicmp(ptr1, "To:", 3) == 0 || _memicmp(ptr1, "cc:", 3) == 0)
{
int toLen;
HddrTo=realloc(HddrTo, (Recipients+1) * sizeof(void *));
HddrTo[Recipients] = zalloc(100);
memset(FullTo, 0, 99);
memcpy(FullTo, &ptr1[4], linelen-4);
memcpy(HddrTo[Recipients], ptr1, linelen+2);
LocalMsg[Recipients] = FALSE;
Type[Recipients] = Msg->type; // Default to Type from Header
Logprintf(LOG_BBS, conn, '?', "B2 Msg To: %s", FullTo);
conn->TempMsg->length -= (int)strlen(HddrTo[Recipients]);
B2To = (int)(ptr1 - outfile);
// if ending in AMPR.ORG send via ISP if we have enabled forwarding AMPR
toLen = (int)strlen(FullTo);
if (_memicmp(&FullTo[toLen - 8], "ampr.org", 8) == 0)
{
// if our domain keep here.
// if not, and SendAMPRDirect set, set as ISP,
// else set as RMS
memcpy(Msg->via, FullTo, toLen);
ptr3 = strchr(FullTo, '@');
if (ptr3)
{
ptr3++;
if (_stricmp(ptr3, AMPRDomain) == 0)
{
// Our Message
strcpy(Msg->via, FullTo);
BBSMsgs ++;
goto BBSMsg;
}
}
if (SendAMPRDirect && FindAMPR())
{
strcpy(Msg->via, FullTo);
strcpy(FullTo,"AMPR");
BBSMsgs ++;
goto BBSMsg;
}
strcpy(FullTo,"RMS");
RMSMsgs ++;
}
if (conn->BPQBBS && !CheckifPacket(FullTo)) // May be an message for RMS being passed to an intermediate BBS
{
// Internet address - send via RMS
strcpy(Msg->via, FullTo);
strcpy(FullTo,"RMS");
RMSMsgs ++;
}
else
{
ptr3 = strchr(FullTo, '@');
if (ptr3)
{
*ptr3++ = 0;
strcpy(Msg->via, ptr3);
}
else
Msg->via[0] = 0;
}
if (conn->Paclink)
{
Msg->B2Flags |= FromPaclink;
// Message from paclink
// Messages to WL2K just have call.
// Messages to email or BBS addresses have smtp:
if (_memicmp(&ptr1[4], "SMTP:", 5) == 0)
{
// See if Packet or SMTP
if (CheckifPacket(Msg->via)) // If no RMS, don't check for routing to it)
{
// Packet Message
memmove(FullTo, &FullTo[5], strlen(FullTo) - 4);
_strupr(FullTo);
_strupr(Msg->via);
// Update the saved to: line (remove the smtp:)
strcpy(&HddrTo[Recipients][4], &HddrTo[Recipients][9]);
BBSMsgs++;
}
else
{
// Internet address - do we send via RMS??
// ??? Need to see if RMS is available
memcpy(Msg->via, &ptr1[9], linelen);
Msg->via[linelen-9] = 0;
strcpy(FullTo,"RMS");
RMSMsgs ++;
}
}
else
{
if (conn->RadioOnlyMode == 0 && (conn->UserPointer->flags & F_NOWINLINK) == 0) // treat as Packet Address?
{
strcpy(Msg->via, "winlink.org"); // Message for WL2K - add via
RMSMsgs ++;
LocalMsg[Recipients] = CheckifLocalRMSUser(FullTo);
}
else
{
BBSMsgs++;
}
}
}
// else if (conn->RMSExpress && FindRMS()) // If no RMS, don't check for routing to it
else if (conn->RMSExpress)
{
Msg->B2Flags |= FromRMSExpress;
// Message from RMS Express
// Messages to WL2K just have call.
// Messages to email or BBS addresses don't have smtp:
if (Msg->via[0])
{
// Has an @ - See if Packet or SMTP. If to our AMPR address, treat as packet
if (CheckifPacket(Msg->via) || _stricmp(Msg->via, AMPRDomain) == 0)
{
// Packet Message
_strupr(FullTo);
_strupr(Msg->via);
BBSMsgs++;
}
else
{
// Internet address - do we send via RMS??
if (_memicmp(FullTo, "smtp/", 5) == 0 && ISP_Gateway_Enabled)
{
memcpy(Msg->via, &ptr1[9], linelen - 9);
Msg->via[linelen-9] = 0;
FullTo[0] = Msg->to[0] = 0;
}
else if (FindRMS()) // have RMS
{
memcpy(Msg->via, &ptr1[4], linelen);
Msg->via[linelen-4] = 0;
strcpy(FullTo,"RMS");
RMSMsgs ++;
}
else if (ISP_Gateway_Enabled)
{
memcpy(Msg->via, &ptr1[4], linelen);
Msg->via[linelen-4] = 0;
FullTo[0] = Msg->to[0] = 0;
}
else if (isAMPRMsg(Msg->via))
strcpy(Msg->to, "RMS"); // Routing will redirect it
}
}
else
{
if (conn->RadioOnlyMode == 0 && (conn->UserPointer->flags & F_NOWINLINK) == 0) // Dont default to winlink.org
{
strcpy(Msg->via, "winlink.org"); // Message for WL2K - add via
RMSMsgs ++;
LocalMsg[Recipients] = CheckifLocalRMSUser(FullTo);
}
else
goto BBSMsg;
}
}
else // Not Paclink or RMS Express (or no RMS)
{
if (_memicmp(&ptr1[4], "SMTP:", 5) == 0)
{
// Airmail Sends MARS messages as SMTP
if (CheckifPacket(Msg->via))
{
// Packet Message
memmove(FullTo, &FullTo[5], strlen(FullTo) - 4);
_strupr(FullTo);
_strupr(Msg->via);
// Update the saved to: line (remove the smtp:)
strcpy(&HddrTo[Recipients][4], &HddrTo[Recipients][9]);
BBSMsgs++;
goto BBSMsg;
}
// If a winlink.org address we need to convert to call
if (_stricmp(Msg->via, "winlink.org") == 0)
{
memmove(FullTo, &FullTo[5], strlen(FullTo) - 4);
_strupr(FullTo);
LocalMsg[Recipients] = CheckifLocalRMSUser(FullTo);
}
else
{
memcpy(Msg->via, &ptr1[9], linelen);
Msg->via[linelen - 9] = 0;
strcpy(FullTo,"RMS");
}
// FullTo[0] = 0;
}
else
{
BBSMsg:
_strupr(FullTo);
_strupr(Msg->via);
}
}
if (memcmp(FullTo, "RMS:", 4) == 0)
{
// remove RMS and add @winlink.org
memmove(FullTo, &FullTo[4], strlen(FullTo) - 3);
strcpy(Msg->via, "winlink.org");
sprintf(HddrTo[Recipients], "To: %s\r\n", FullTo);
}
else if (memcmp(FullTo, "NTS:", 4) == 0)
{
// remove NTS and set type 'T'
memmove(FullTo, &FullTo[4], strlen(FullTo) - 3);
Type[Recipients] = 'T'; // NTS
memmove(HddrTo[Recipients] + 4, HddrTo[Recipients] + 8, 91);
// Replace Type: Private with Type: Traffic
}
else if ((_memicmp(FullTo, "bull/", 5) == 0) || (_memicmp(FullTo, "bull:", 5) == 0))
{
// remove bull/ and set type 'B'
memmove(FullTo, &FullTo[5], strlen(FullTo) - 4);
Type[Recipients] = 'B'; // Bulletin
memmove(HddrTo[Recipients] + 4, HddrTo[Recipients] + 9, 90);
// Replace Type: Private with Type: Bulletin
// Have to move rest of header down to make space
}
if (strcmp(Msg->via, "RMS") == 0)
{
// replace RMS with @winlink.org
strcpy(Msg->via, "winlink.org");
sprintf(HddrTo[Recipients], "To: %s@winlink.org\r\n", FullTo);
}
if (strlen(FullTo) > 6)
FullTo[6] = 0;
strlop(FullTo, '-');
strcpy(Msg->to, FullTo);
if (SendBBStoSYSOPCall)
if (_stricmp(FullTo, BBSName) == 0)
strcpy(Msg->to, SYSOPCall);
if ((Msg->via[0] == 0 || strcmp(Msg->via, "BPQ") == 0 || strcmp(Msg->via, "BBS") == 0)
&& (conn->Paclink || conn->RMSExpress))
{
// No routing - check @BBS and WP
struct UserInfo * ToUser = LookupCall(FullTo);
Msg->via[0] = 0; // In case BPQ and not found
if (ToUser)
{
// Local User. If Home BBS is specified, use it
if (ToUser->HomeBBS[0])
{
strcpy(Msg->via, ToUser->HomeBBS);
}
}
else
{
WPRecP WP = LookupWP(FullTo);
if (WP)
{
strcpy(Msg->via, WP->first_homebbs);
}
}
// Fix To: address in B2 Header
if (Msg->via[0])
sprintf(HddrTo[Recipients], "To: %s@%s\r\n", FullTo, Msg->via);
else
sprintf(HddrTo[Recipients], "To: %s\r\n", FullTo);
}
RecpTo=realloc(RecpTo, (Recipients+1) * sizeof(void *));
RecpTo[Recipients] = zalloc(10);
Via=realloc(Via, (Recipients+1) * sizeof(void *));
Via[Recipients] = zalloc(50);
strcpy(Via[Recipients], Msg->via);
strcpy(RecpTo[Recipients++], FullTo);
// Remove the To: Line from the buffer
memmove(ptr1, ptr2+2, count);
goto Loop;
}
else if (_memicmp(ptr1, "Type:", 4) == 0)
{
if (ptr1[6] == 'N')
Msg->type = 'T'; // NTS
else
Msg->type = ptr1[6];
}
else if (_memicmp(ptr1, "Body:", 4) == 0)
{
MsgLen = atoi(&ptr1[5]);
StartofMsg = ptr1;
}
else if (_memicmp(ptr1, "File:", 5) == 0)
{
Msg->B2Flags |= Attachments;
}
else if (_memicmp(ptr1, "Date:", 5) == 0)
{
struct tm rtime;
char seps[] = " ,\t\r";
memset(&rtime, 0, sizeof(struct tm));
// Date: 2009/07/25 10:08
sscanf(&ptr1[5], "%04d/%02d/%02d %02d:%02d",
&rtime.tm_year, &rtime.tm_mon, &rtime.tm_mday, &rtime.tm_hour, &rtime.tm_min);
rtime.tm_year -= 1900;
Date = mktime(&rtime) - (time_t)_MYTIMEZONE;
if (Date == (time_t)-1)
Date = time(NULL);
}
if (linelen) // Not Null line
{
ptr1 = ptr2 + 2; // Skip crlf
goto Loop;
}
// Processed all headers
// If multiple recipents, create one copy for each BBS address, and one for all others (via RMS)
if (Recipients == 0 || HddrTo == NULL)
{
Debugprintf("B2 Message with no recipients from %s", conn->Callsign);
Logprintf(LOG_BBS, conn, '!', "B2 Message with no recipients from %s", conn->Callsign);
SetupNextFBBMessage(conn);
return;
}
else
{
__int32 i;
struct MsgInfo * SaveMsg;
char * SaveBody;
__int32 SaveMsgLen = count;
BOOL SentToRMS = FALSE;
__int32 ToLen;
char * ToString = malloc(Recipients * 100);
char * bang;
SaveMsg = Msg;
SaveBody = conn->MailBuffer;
// If from WL2K, create one message for each to: or cc: that is a local user
if (Msg->B2Flags & FromCMS)
{
struct UserInfo * user;
char Call[10];
char * ptr;
for (i = 0; i < Recipients; i++)
{
memcpy(Call, &HddrTo[i][4], 9);
ptr = strchr(Call, 13);
if (ptr)
*ptr = 0;
strlop(Call, '-');
user = LookupCall(Call);
if (user == 0)
continue;
if (strcmp(Call, BBSName) != 0) // always accept to bbs call
if ((user->flags & F_POLLRMS) == 0)
continue;
conn->TempMsg = Msg = malloc(sizeof(struct MsgInfo));
memcpy(Msg, SaveMsg, sizeof(struct MsgInfo));
conn->MailBuffer = malloc(SaveMsgLen + 1000);
memcpy(conn->MailBuffer, SaveBody, SaveMsgLen);
// Add our To:
ToLen = (int)strlen(HddrTo[i]);
if (_memicmp(HddrTo[i], "CC", 2) == 0) // Replace CC: with TO:
memcpy(HddrTo[i], "To", 2);
memmove(&conn->MailBuffer[B2To + ToLen], &conn->MailBuffer[B2To], count);
memcpy(&conn->MailBuffer[B2To], HddrTo[i], ToLen);
conn->TempMsg->length += ToLen;
strcpy(Msg->to, RecpTo[i]);
strcpy(Msg->via, Via[i]);
Msg->type = Type[i];
if (Recipients > 1)
Msg->bid[0] = 0;
CreateMessageFromBuffer(conn);
}
}
else
{
// From a client - Create one copy with all RMS recipients, and one for each packet recipient
// Merge all RMS To: lines
// If don't add Winlink.org or no RMS BBS keep separate
ToLen = 0;
ToString[0] = 0;
for (i = 0; i < Recipients; i++)
{
if (conn->RadioOnlyMode || LocalMsg[i] || (conn->UserPointer->flags & F_NOWINLINK) || FindRMS()== NULL)
{
LocalMsg[i] = TRUE; // Make sure local copy is created
continue; // For a local RMS user
}
// ?? Should a Bang Path override this ?? - I think so!
if (strchr(Via[i], '!'))
continue;
if (_stricmp(Via[i], "WINLINK.ORG") == 0 || _memicmp (&HddrTo[i][4], "SMTP:", 5) == 0 ||
_stricmp(RecpTo[i], "RMS") == 0)
{
if (ToLen == 0) // First Addr
memcpy(HddrTo[i], "To", 2); // In Case CC
ToLen += (int)strlen(HddrTo[i]);
strcat(ToString, HddrTo[i]);
}
}
if (ToLen)
{
conn->TempMsg = Msg = malloc(sizeof(struct MsgInfo));
memcpy(Msg, SaveMsg, sizeof(struct MsgInfo));
conn->MailBuffer = malloc(SaveMsgLen + 1000);
memcpy(conn->MailBuffer, SaveBody, SaveMsgLen);
// Add all the To: lines back to message
memmove(&conn->MailBuffer[B2To + ToLen], &conn->MailBuffer[B2To], count);
memcpy(&conn->MailBuffer[B2To], ToString, ToLen);
conn->TempMsg->length += ToLen;
if (Recipients > 1)
{
strcpy(Msg->via, "winlink.org");
strcpy(Msg->to, "RMS");
Msg->bid[0] = 0; // Must Change the BID
}
// Don't change type, as we don't change the B2 Header for messages to RMS
//Msg->type = Type[0];
CreateMessageFromBuffer(conn);
}
free(ToString);
for (i = 0; i < Recipients; i++)
{
// Only Process Non - RMS Dests or local RMS Users
// ?? Should a Bang Path override this ?? - I think so!
if (strchr(Via[i], '!') == 0)
if (LocalMsg[i] == 0)
if (_stricmp (Via[i], "WINLINK.ORG") == 0 ||
_memicmp (&HddrTo[i][4], "SMTP:", 5) == 0 ||
_stricmp(RecpTo[i], "RMS") == 0)
continue;
conn->TempMsg = Msg = malloc(sizeof(struct MsgInfo));
memcpy(Msg, SaveMsg, sizeof(struct MsgInfo));
conn->MailBuffer = malloc(SaveMsgLen + 1000);
memcpy(conn->MailBuffer, SaveBody, SaveMsgLen);
// Add our To:
ptr = HddrTo[i];
// We removed any nts: or bull: earlier on,
// and saved type. We need to set type here, as
// may be sending to more than one type
// If message contains Type: Private and not 'P',
// need to changes to Traffic or Bulletin
// But we need to remove last bang path if any
if (strchr(ptr, '!'))
{
bang = ptr + strlen(ptr);
while (*(--bang) != '!'); // Find last !
*(bang++) = 13; // Need CR;
*(bang++) = 10; // Need LF;
*(bang) = 0; // remove it;
}
ToLen = (int)strlen(ptr);
// if (_memicmp(HddrTo[i], "CC", 2) == 0) // Replace CC: with TO:
memcpy(HddrTo[i], "To", 2);
memmove(&conn->MailBuffer[B2To + ToLen], &conn->MailBuffer[B2To], count);
memcpy(&conn->MailBuffer[B2To], HddrTo[i], ToLen);
conn->TempMsg->length += ToLen;
Msg->type = Type[i];
ptr = strstr(conn->MailBuffer, "\nType: ");
if (ptr)
{
char * ptrx;
ptr += 7;
// This handles a message arriving with bull/ or nts/ overrides
if (_memicmp(ptr, "Private", 7) == 0 && Msg->type != 'P')
{
if (Msg->type == 'T')
memcpy(ptr, "Traffic", 7);
else
if (Msg->type == 'B')
{
// have to make space
memmove(ptr + 1, ptr, count);
conn->TempMsg->length++;
memcpy(ptr, "Bulletin", 8);
}
// remove //wl2k from subject
ptrx = strstr(conn->MailBuffer, "Subject: ");
if (ptrx && _memicmp(ptrx + 9, "//WL2K ", 7) == 0)
{
memmove(ptrx + 9, ptrx + 16, count);
conn->TempMsg->length -= 7;
memmove(conn->TempMsg->title, &conn->TempMsg->title[7], strlen(conn->TempMsg->title) - 6);
}
}
// if we are receiving from another BBS rather
// than WLE or PAT we need to set msgtype from Type:
Msg->type = ptr[0]; // I think it is safe to do it always
if (Msg->type == 'N')
Msg->type = 'T';
}
strcpy(Msg->to, RecpTo[i]);
strcpy(Msg->via, Via[i]);
if (i > 0 && Msg->type != 'B') // Must Change the BID
Msg->bid[0] = 0;
// Update Stats
if (Msg->type == 'P')
Index = PMSG;
else if (Msg->type == 'B')
Index = BMSG;
else if (Msg->type == 'T')
Index = TMSG;
conn->UserPointer->Total.MsgsReceived[Index]++;
conn->UserPointer->Total.BytesForwardedIn[Index] += MsgLen;
CreateMessageFromBuffer(conn);
}
} // End not from RMS
free(SaveMsg);
free(SaveBody);
conn->MailBuffer = NULL;
conn->MailBufferSize=0;
if (FromSync)
return;
SetupNextFBBMessage(conn);
return;
}
#ifndef LINBPQ
}
#define EXCEPTMSG "Error Decoding B2 Message"
#include "StdExcept.c"
BBSputs(conn, "*** Program Error Decoding B2 Message\r");
Flush(conn);
conn->CloseAfterFlush = 20; // 2 Secs
return;
}
#endif
} // end if B2Msg
CreateMessageFromBuffer(conn);
SetupNextFBBMessage(conn);
}