home *** CD-ROM | disk | FTP | other *** search
- /*
- * qwk.c - main module for qwk
- */
-
- #include <stdio.h>
- #include <time.h>
- #include <malloc.h>
- #include <clib.h>
-
- 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);
- }
- }
- }
-