Category : C Source Code
Archive   : QWKREP.ZIP
Filename : QWK.C

 
Output of file : QWK.C contained in archive : QWKREP.ZIP

/*
* qwk.c - main module for qwk
*/

#include
#include
#include
#include

FILE *cfp;
FILE *mfp;
FILE *ifp;
struct tm *tmp;
int num;
char **args;

char buff[1024];
char *lines[100];
int numline;

char subject[26];
char from[26];
char to[26];
char confname[11];
char m_date[9];
char m_time[6];
char bbsname[9];
char bbstitle[40];
char bbsuser[25];
int msgnum;
int type;

char o_date[11];
char o_time[6];

int lmsgnum;

#pragma pack(1)

/*
* QWK packet message header
*/
struct _header_
{
char _status;
char _msgnum[7];
char _date[8];
char _time[5];
char _to[25];
char _from[25];
char _subject[25];
char _passwd[12];
char _refer[8];
char _size[6];
char _alive;
int _conf;
char _filler[3];
} header;

/*
* storage for 100 index entries
*/
struct _index_
{
struct _index_ *_next;
char _data[500];
int _count;
} *personal = (struct _index_ *) NULL;

/*
* linked list chain of conference structures
*/
struct _conf_
{
struct _conf_ *_next;
char _name[11];
struct _index_ *_indices;
} *confs = (struct _conf_ *) NULL;

int numconf;

/*
* 128 byte "Sparkyheader"
*/
char *msghdr =
"Produced by Qmail...Copyright (c) 1987 by Sparkware. All Rights Reserved\
Above for Compatibility with Qmail ";

long msgpos;
int msgsize;
int thispos;
int inmsg;

/*
* needed to do msbin <--> ieee fp format conversion
*/
union converter
{
unsigned char _uc[10];
unsigned int _ui[5];
unsigned long _ul[2];
float _f[2];
double _d[1];
};

/*
* known splitter modules
*/
extern int geni_split(char *, int);
extern int mail_split(char *, int);

/*
* placed in an array of function pointers
*/
int (* split_funcs[])(char *, int) =
{
geni_split,
mail_split,
};

/*
* now, how many of them were there?
*/
#define NUM_SPLIT (sizeof(split_funcs) / sizeof(split_funcs[0]))

/*
* fp conversion routine
*/
float ieeetomsbin(f)
float f;
{
union converter t;
int sign, exp;

t._f[0] = f;
sign = t._uc[3] / 0x80;
exp = ((t._ui[1] >> 7) - 0x7f + 0x81) & 0xff;
t._ui[1] = (t._ui[1] & 0x7f) | (sign << 7) | (exp << 8);
return(t._f[0]);
}

/*
* need a void type unlink for scnwld
*/
void delete(s)
char *s;
{
unlink(s);
}

/*
* mkqwk does the work, but all it does is to call out to the split routines
* these in turn call back into code here when they find messages
*/
void mkqwk(s)
char *s;
{
int i;

if ((ifp = fopen(s, "r")) == (FILE *) NULL)
{
printf("Can't open %s\n", s);
return;
}
/*
* no-one's claimed it yet
*/
type = -1;

/*
* keep on getting lines
*/
while (fgets(buff, 1022, ifp) != (char *) NULL)
{
strip(buff);
/*
* if it's unclaimed, pass it to everyone
*/
if (type == -1)
{
for (i = 0; i < NUM_SPLIT; i++)
(* split_funcs[i])(buff, i);
}
else
/*
* otherwise just pass it to the owner
*/
(* split_funcs[type])(buff, type);
}
fclose(ifp);
/*
* final cleanup
*/
if (inmsg)
finish_msg();
reset();
}

main(n, a)
char **a;
{
int x;
time_t now;

/*
* get the current date and time
*/
time(&now);
tmp = localtime(&now);

if (n < 2)
usage();
/*
* try to make control.dat
*/
if ((cfp = fopen("control.dat", "w")) == (FILE *) NULL)
{
printf("Can't create CONTROL.DAT\n");
exit(3);
}
/*
* and messages.dat
*/
if ((mfp = fopen("messages.dat", "w+b")) == (FILE *) NULL)
{
fclose(cfp);
printf("Can't create MESSAGES.DAT\n");
exit(4);
}
/*
* current position is at start of file
*/
msgpos = 0L;
/*
* write the "Sparkyheader"
*/
msgwrt(msghdr, 128);
/*
* build current date and time as strings
*/
sprintf(o_date, "%02d-%02d-%04d", tmp->tm_mon + 1, tmp->tm_mday,
tmp->tm_year + 1900);
sprintf(o_time, "%02d:%02d", tmp->tm_hour, tmp->tm_min);

numconf = numline = lmsgnum = msgsize = 0;
reset();

++a;
num = n - 2;
args = &a[1];

/*
* XXX it occurs to me that using scnwld is not that bright an idea
* since we only ever make one QWK packet per run
*/
if (scnwld(*a, mkqwk, 0) == 0)
printf("Warning: no text files matched\n");

/*
* clean up: dump the control info into control.dat
*/
dump_ctrl();
/*
* close the files
*/
fclose(mfp);
fclose(cfp);
fclose(ifp);
/*
* figure the PKZIP command and execute it
*/
sprintf(buff, "pkzip -a %s.qwk *.dat *.ndx", bbsname);
system(buff);
/*
* and toss the files we just put in the zip
*/
scnwld("*.dat", delete, 0);
scnwld("*.ndx", delete, 0);
return(0);
}

usage()
{
printf("Usage: MKQWK textfiles .....\n");
exit(1);
}

/*
* make everything clean
*/
reset()
{
padcpy(subject, "", 25);
padcpy(from, "", 25);
padcpy(to, "", 25);
sprintf(m_date, "%02d-%02d-%02d", tmp->tm_mon + 1, tmp->tm_mday,
tmp->tm_year % 100);
sprintf(m_time, "%02d:%02d", tmp->tm_hour, tmp->tm_min);
msgnum = -1;
}

/*
* external entry to dump a line
*/
writemsg(buff)
char *buff;
{
/*
* add the line
*/
addline(buff);
if (numline == 97)
{
/*
* split a message at 100 lines
*/
addline(">>> Continued in next message");
finish_msg();
addline(">>> Continued from last message");
}
}

/*
* external entry to complete a message
*/
finish_msg()
{
int i;
int j;
int x;
int y;
struct _conf_ *work;
char ndx[10];

/*
* not in a message any more
*/
inmsg = 0;
/*
* add the conference name, and get back the conf number
*/
j = addconf(confname);
/*
* sataus is unread
*/
header._status = ' ';
/*
* update message number
*/
lmsgnum++;
if (msgnum == -1)
msgnum = lmsgnum;
sprintf(header._msgnum, "%-7d", ++msgnum);
/*
* set up fields for header
*/
upper(from);
upper(to);
m_date[2] = m_date[5] = '-';
m_time[2] = ':';
strcpy(header._date, m_date);
strcpy(header._time, m_time);
padcpy(header._to, to, 25);
padcpy(header._from, from, 25);
padcpy(header._subject, subject, 25);
padcpy(header._passwd, "", 12);
padcpy(header._refer, "", 8);
sprintf(header._size, "%-6d", x = (msgsize + 255) / 128);
header._alive = 0xe1;
header._conf = j;
padcpy(header._filler, "", 3);
/*
* and write it
*/
msgwrt((char *) &header, 128);

/*
* save current position
*/
y = thispos + x;
/*
* output all the text, and release the buffers
*/
for (i = 0; i < numline; i++)
{
msgwrt(lines[i], strlen(lines[i]));
free(lines[i]);
msgwrt("\xe3", 1);
}
/*
* pad with spaces to 128 byte boundary
*/
while (msgpos & 127L)
msgwrt(" ", 1);
/*
* internal check - this better not ever happen!
*/
if (msgpos / 128 != y)
printf("WARNING: possible corruption in created MESSAGES.DAT");
/*
* go find the conf again
*/
for (i = 0, work = confs; work != (struct _conf_ *) NULL && i < j; i++)
work = work->_next;
if (work == (struct _conf_ *) NULL)
/*
* another internal error
*/
printf("Internal error: conference list corrupt\n");
else
{
/*
* add the position to the current index
*/
wrtndx(&work->_indices, thispos, j);
if (strcmp(bbsuser, to) == 0)
/*
* and to the personal index if it's for us
*/
wrtndx(&personal, thispos, j);
/*
* save next message position
*/
thispos = y;
/*
* and reset
*/
numline = 0;
msgsize = 0;
}
}

/*
* external entry to start a new message
*/
newmsg()
{
/*
* save the sector number
*/
thispos = msgpos / 128L;
/*
* upper case the bbs name and user
*/
upper(bbsname);
upper(bbsuser);
/*
* flag we're in a message
*/
inmsg = 1;
}

/*
* external entry for a splitter module to claim the text file
*/
mine(n)
{
type = n;
}

/*
* output the entire CONTROL.DAT file
*/
dump_ctrl()
{
struct _conf_ *work;
int i;
char cxdat[20];
FILE *cxfp;

if (numconf == 0)
{
/*
* barf and exit if we didn't find anything
*/
printf("No messages found\n");
exit(0);
}
/*
* output the BBS title and some fillers
*/
fprintf(cfp, "%s\nx\ny\nz\n", bbstitle);
/*
* and the bbs name
*/
fprintf(cfp, "00000,%s\n", bbsname);
/*
* date and time
*/
fprintf(cfp, "%s,%s:00\n", o_date, o_time);
/*
* user name, and number of confs
*/
fprintf(cfp, "%s\n\n0\n0\n%d\n", bbsuser, numconf - 1);
/*
* build the .INF file at the same time so that REP can do the
* reverse conversion from conference number to name
*/
sprintf(cxdat, "%s.INF", bbsname);
if ((cxfp = fopen(cxdat, "w")) == (FILE *) NULL)
printf("Warning - couldn't create %s, REP processing may fail\n", cxdat);
/*
* now run down the conferences
*/
for (i = 0, work = confs; work != (struct _conf_ *) NULL;
work = work->_next, i++)
{
/*
* output name and number to CONTROL.DAT
*/
fprintf(cfp, "%d\n%s\n", i, work->_name);
if (cxfp != (FILE *) NULL)
/*
* and name to .INF file
*/
fprintf(cxfp, "%s\n", work->_name);
/*
* lastly dump index info to the appropriate index filename
*/
sprintf(cxdat, "%03d.NDX", i);
dumpndx(cxdat, work->_indices);
}
/*
* and the personal index data
*/
dumpndx("personal.ndx", personal);
if (cxfp != (FILE *) NULL)
fclose(cxfp);
}

/*
* write a buffer to MESSAGES.DAT
*/
msgwrt(buff, size)
char *buff;
{
while (size--)
{
putc(*buff++, mfp);
msgpos++;
}
}

/*
* save a line of text for later writing to MESSAGES.DAT
*/
addline(bp)
char *bp;
{
char *work;

/*
* grab some memory
*/
if ((work = malloc(strlen(bp) + 1)) == (char *) NULL)
{
printf("ERROR: out of memory");
exit(101);
}
/*
* save text in line array
*/
lines[numline++] = work;
strcpy(work, bp);
msgsize += strlen(work) + 1;
}

/*
* write an entry to an index chain
*/
wrtndx(ndxp, pos, conf)
struct _index_ **ndxp;
/*
* double indirect pointer in case we have to add an entry
*/
{
int i;
float x;
char *cp;
struct _index_ *ndx;
struct _ixentry_
{
float _pos;
char _iconf;
} ixentry;

/*
* find the end of the chain
*/
while ((ndx = *ndxp) != (struct _index_ *) NULL && ndx->_count == 100)
ndxp = &(ndx->_next);
if (ndx == (struct _index_ *) NULL)
{
/*
* no data in chain, or last entry is full
* so grab some memory
*/
if ((ndx = (struct _index_ *) malloc(sizeof(struct _index_))) ==
(struct _index_ *) NULL)
{
printf("ERROR: out of memory");
exit(101);
}
/*
* and make a new link
*/
ndx->_next = (struct _index_ *) NULL;
ndx->_count = 0;
*ndxp = ndx;
}
/*
* convert to the dreaded msbin format
*/
x = pos + 1;
x = ieeetomsbin(x);
/*
* drop the data into the index entry structure
*/
ixentry._pos = x;
ixentry._iconf = conf;
cp = (char *) &ixentry;
/*
* and copy to the correct place in the index link list node
*/
for (i = 0; i < 5; i++)
ndx->_data[ndx->_count * 5 + i] = *cp++;
ndx->_count++;
}

/*
* copy from src to dest, exactly len bytes, pad with spaces if needed
*/
padcpy(dest, src, len)
char *dest, *src;
{
while (*src && len)
{
*dest++ = *src++;
len--;
}
while (len--)
*dest++ = ' ';
}

/*
* get the conference number for this conf, add it to chain if it doesn't
* already exist
*/
addconf(conf)
char *conf;
{
int j;
struct _conf_ *work;
struct _conf_ **workp;

work = confs;
workp = &confs;
/*
* look for the entry
*/
for (j = 0; work != (struct _conf_ *) NULL; j++)
{
if (strcmp(work->_name, conf) == 0)
break;
workp = &work->_next;
work = work->_next;
}
/*
* didn't find it
*/
if (work == (struct _conf_ *) NULL)
{
/*
* get some memory
*/
if ((work = (struct _conf_ *) malloc(sizeof(struct _conf_))) ==
(struct _conf_ *) NULL)
{
printf("ERROR: out of memory");
exit(102);
}
/*
* one more conf
*/
numconf++;
/*
* save the name
*/
strcpy(work->_name, conf);
/*
* drop it in the linked list
*/
*workp = work;
work->_next = (struct _conf_ *) NULL;
/*
* no index entries yet
*/
work->_indices = (struct _index_ *) NULL;
}
/*
* return it's number
*/
return(j);
}

/*
* dump a chain of index structures to a file
*/
dumpndx(file, indices)
char *file;
struct _index_ *indices;
{
int i;
FILE *fp;

/*
* only do it if there really is data
*/
if (indices != (struct _index_ *) NULL)
{
/*
* open the file, and barf if we failed
*/
if ((fp = fopen(file, "wb")) == (FILE *) NULL)
printf("Can't create %s, .QWK will probably be corrupt.\n", file);
else
{
/*
* run down the index chain, writing the data
*/
while (indices != (struct _index_ *) NULL)
{
for (i = 0; i < indices->_count * 5; i++)
putc(indices->_data[i], fp);
indices = indices->_next;
}
fclose(fp);
}
}
}