Category : C Source Code
Archive   : UQWK.ZIP
Filename : UQWK.TAR

 
Output of file : UQWK.TAR contained in archive : UQWK.ZIP
Makefile 644 150 144 1175 5350007632 10761 0ustar mloewenvm#
# Makefile for uqwk
#
# steve belczyk 02/93
#
CFLAGS=
#
# Use this for SGI:
#CFLAGS=-cckr

uqwk: uqwk.o options.o init.o mail.o misc.o close.o news.o reply.o offline.o
cc -o uqwk uqwk.o options.o init.o mail.o misc.o close.o news.o reply.o offline.o

uqwk.o: uqwk.c uqwk.h

options.o: options.c uqwk.h

init.o: init.c uqwk.h

mail.o: mail.c uqwk.h

misc.o: misc.c uqwk.h

close.o: close.c uqwk.h

news.o: news.c uqwk.h

reply.o: reply.c uqwk.h

offline.o: offline.c uqwk.h

clean:
rm -f *.o uqwk

tar:
tar cvf uqwk.tar *.[ch] Makefile README uqwk.man uqwk.cat
compress -v uqwk.tar

uu:
uuencode uqwk.tar.Z uqwk.tar.Z >uqwk.uu
README 644 150 144 5776 5350007631 10213 0ustar mloewenvmUQWK

Copyright 1993, steve belczyk

Uqwk is a program which collects all a user's unread mail or news
and formats it into something called a "QWK" packet, which is then
downloaded. Mail and News can then be read offline, saving phone
charges. QWK readers exist for almost every machine.

Uqwk also accepts reply packets, so replies can be mailed (if your
mailer understands "mail -s"), or posted (if you have a B-news type
of inews that understands -n and -t), depending whether the message
is marked private (email) or public (news).

Uqwk also supports a small offline command language, so the contents
of the user's .newsrc file can be viewed and manipulated offline.

INSTALLATION

1. Create a directory for the uqwk source code.

mkdir /usr/local/src/uqwk

2. Move the uqwk tar file to that directory.

mv uqwk.tar.Z /usr/local/src/uqwk

3. Change to that directory, and unpack the tar file.

cd /usr/local/src/uqwk; zcat uqwk.tar | tar xvf -

4. Compile the software.

make

If this doesn't work you may have to twiddle with the Makefile,
or, heaven forbid, the actual source code.

5. Move the binary and man pages to some public place.

mv uqwk /usr/local/bin
mv uqwk.man /usr/man/man1/uqwk.1
mv uqwk.cat /usr/man/cat1/uqwk.1

6. The QWK specification allows for the name, location, etc., of
the BBS from which messages are being downloaded. You should
configure this information. The best way is probably to use
environment variables. If you are using a Bourne shell, you
should add something like this to /etc/profile or .profile:

UQ_BBS_NAME="My Super BBS"
UQ_BBS_CITY="Somewhere, PA"
UQ_BBS_PHONE="+1 215 555 1212"
UQ_BBS_SYSOP="Joe Shmoe"
UQ_BBS_ID="0,MYBBS"
export UQ_BBS_NAME UQ_BBS_CITY UQ_BBS_PHONE
export UQ_BBS_SYSOP UQ_BBS_ID

If you use a C type shell, try something like this in your
.cshrc or .login:

setenv UQ_BBS_NAME "My Super BBS"
setenv UQ_BBS_CITY "Somewhere, PA"
setenv UQ_BBS_PHONE "+1 215 555 1212"
setenv UQ_BBS_SYSOP "Joe Shmoe"
setenv UQ_BBS_ID "0,MYBBS"

In both cases, the last entry, the "BBS ID", is the most important.
It always consists of an integer, a comma, and a string less than
nine characters, with no intervening spaces. The string will be
used to identify reply packets.

7. Now you can try it. Log in as a normal user who has some mail,
and issue:

uqwk +r

(The "+r" stops uqwk from clearing the user's mail spool file.)
This should create three new files in the current directory named
messages.dat, control.dat, and personal.ndx. These are the files
which the offline reader will need. (Not all readers need the
*.ndx files. Also, some readers expect these files to have been
archived using an archiver like zip, lharc, or arj. You may need
to obtain Unix versions of these archivers.)

8. Now it would be a good idea to read the man page.

Please inform me of any problems you run into:

steve belczyk
[email protected]
[email protected]
BBS: +1 508 664 0149

close.c 644 150 144 4026 5350007632 10570 0ustar mloewenvm#include
#include
#include
#include "uqwk.h"

/*
* Wrap things up
*/

CloseStuff()
{
fclose (msg_fd);

WriteControl();
if (do_news && (!read_only) ) WriteNewsrc();

if (blk_cnt >= max_blks)
{
fprintf (stderr,
"%s: block count exceeded; some articles not packed\n",
progname);
}

/* Remove reply packet */
if ( (!read_only) && (strcmp (rep_file, DEF_REP_FILE)))
{
unlink (rep_file);
}
}

WriteControl()
/*
* Create the CONTROL.DAT file
*/
{
struct conf_ent *cp;
struct tm *t;
char ctl_fname[PATH_LEN];
int clock;

strcpy (ctl_fname, home_dir);
strcpy (ctl_fname, "/");
strcpy (ctl_fname, "control.dat");

if (NULL == (ctl_fd = fopen (ctl_fname, "w")))
{
fprintf (stderr, "%s: can't open %s\n", progname, ctl_fname);
exit (0);
}

fprintf (ctl_fd, "%s\r\n%s\r\n%s\r\n%s\r\n%s\r\n",
bbs_name, bbs_city, bbs_phone, bbs_sysop, bbs_id);

/* Date */
clock = time (NULL);
t = gmtime (&clock);
fprintf (ctl_fd, "%02d\-%02d\-%04d,%02d\:%02d\:%02d\r\n",
t->tm_mon+1, t->tm_mday, t->tm_year+1900,
t->tm_hour, t->tm_min, t->tm_sec);

fprintf (ctl_fd, "%s\r\n \r\n0\r\n", user_name);
fprintf (ctl_fd, "%d\r\n%d\r\n", msg_cnt, conf_cnt-1);

/* List of conferences */
cp = conf_list;
while (cp != NULL)
{
fprintf (ctl_fd, "%d\r\n%s\r\n", cp->number, cp->name);
cp = cp->next;
}

fprintf (ctl_fd, "WELCOME.DAT\r\nNEWS.DAT\r\nLOGOFF.DAT\r\n");
fprintf (ctl_fd, "\032");
fclose (ctl_fd);
}

WriteNewsrc()
/*
* Rewrite the updated .newsrc file
*/
{
if (read_only) return (0);

if (NULL == (nrc_fd = fopen (nrc_file, "w")))
{
fprintf (stderr, "%s: can't write %s\n",
progname, nrc_file);
return (0);
}

/* We do this recursively to preserve the order of the .newsrc */
wn (nrc_list);

fclose (nrc_fd);
}

wn (np)
struct nrc_ent *np;
{
if (np == NULL) return (0);

/* Write the rest of them */
wn (np->next);

/* Write this one */
if (np->subscribed)
{
fprintf (nrc_fd, "%s: 1-%d\n", np->name, np->hi);
}
else
{
fprintf (nrc_fd, "%s! 1-%d\n", np->name, np->hi);
}
}

init.c 644 150 144 1500 5350007633 10421 0ustar mloewenvm#include
#include
#include "uqwk.h"

#define QWK_MAGIC "Produced by Qmail...Copyright (c) 1987 by Sparkware. All rights Reserved"

InitStuff()
/*
* Initialize stuff
*/
{
char msg_fname[PATH_LEN];
int n;

/* Mail, conference, etc. lists */
mail_list = NULL;
conf_list = NULL;
last_conf = NULL;
act_list = NULL;
nrc_list = NULL;

/* Message and conference counts */
msg_cnt = 0;
conf_cnt = 0;

/* Open MESSAGES.DAT */
strcpy (msg_fname, home_dir);
strcat (msg_fname, "/");
strcat (msg_fname, "messages.dat");

if (NULL == (msg_fd = fopen (msg_fname, "w")))
{
fprintf (stderr, "%s: can't open %s\n", progname, msg_fname);
exit (0);
}

/* Write magic string to MESSAGES.DAT */
fprintf (msg_fd, QWK_MAGIC);
n = 128 - strlen (QWK_MAGIC);
while (n--) fputc (' ', msg_fd);
blk_cnt = 2;
}
mail.c 644 150 144 7757 5350007633 10424 0ustar mloewenvm#include
#include "uqwk.h"

/*
* All sorts of stuff to do mail processing
*/

FILE *mail_fd; /* For mail spool */
struct mail_ent *last_mp; /* Points to last mail list entry */

DoMail ()
/*
* Process mail into QWK packet
*/
{
struct mail_ent *mailp;

/* Open the mail spool */
if (NULL == (mail_fd = fopen (mail_file, "r")))
{
fprintf (stderr, "%s: can't open %s\n", progname, mail_file);
perror (progname);
return (0);
}

/* Define the mail "conference" */
NewConference (MAIL_CONF_NAME);

/* Construct the mail linked list */
MakeMailList ();

/* Walk through all the messages */
mailp = mail_list;

while (mailp != NULL)
{
DoMessage (mailp);
mailp = mailp->next;
}

fclose (mail_fd);
fclose (ndx_fd);

/* Now empty the mail box */
if (!read_only)
{
if (NULL == (mail_fd = fopen (mail_file, "w")))
{
fprintf (stderr, "%s: can't write %s\n", progname,
mail_file);
}
else
{
fclose (mail_fd);
}
}
}

MakeMailList ()
/*
* Construct linked list of pointers to individual messages in
* the mail spool.
*/
{
long offset;

last_mp = NULL;

/* Read through, looking for "From" lines */
offset = ftell (mail_fd);
while (NULL != Fgets (buf, BUF_LEN, mail_fd))
{
if (!strncmp (buf, "From ", 5))
{
DoFromLine (offset);
}
offset = ftell (mail_fd);
}
if (last_mp != NULL) last_mp->end = offset;
}

DoFromLine (offset)
long offset;
{
struct mail_ent *mp;

/* Get space for new mail list entry */
if (NULL==(mp=(struct mail_ent *) malloc(sizeof(struct mail_ent))))
{
fprintf (stderr, "%s: out of memory\n", progname);
exit (0);
}

/* Fill in offset */
mp->begin = offset;

if (last_mp == NULL)
{
/* This is first message */
mail_list = mp;
}
else
{
/* Add to end of list */
last_mp->next = mp;
last_mp->end = offset;
}

mp->next = NULL;
last_mp = mp;
}

DoMessage (mp)
struct mail_ent *mp;
/*
* Convert a message to QWK format
*/
{
struct qwk_hdr hdr;
char c[PATH_LEN], *eof, ndx[5];
int out_bytes, n;

/* Write the ndx file entry */
inttoms (blk_cnt, ndx);
ndx[4] = conf_cnt-1;
fwrite (ndx, 5, 1, ndx_fd);

Spaces (&hdr, 128);

/* Fill in the header fields we can do now */
hdr.status = QWK_PRIVATE;
PadNum (msg_cnt, hdr.number, 7);
Spaces (hdr.password, 12);
Spaces (hdr.refer, 8);
hdr.flag = QWK_ACT_FLAG;
IntNum (conf_cnt-1, hdr.conference);
IntNum (msg_cnt+1, hdr.msg_num);
hdr.tag = ' ';

msg_cnt++;

/* Seek to start of message */
fseek (mail_fd, mp->begin, 0);

/* Read the From line */
Fgets (buf, BUF_LEN, mail_fd);

/* The second field of the From line is assumed to be who
sent the message */
sscanf (&buf[5], "%s", c);
PadString (c, hdr.from, 25);

/* Now read through header lines, looking for ones we need */
eof = Fgets (buf, BUF_LEN, mail_fd);
while ( (0 != strlen(buf)) && (eof != NULL) )
{
if (!strncmp (buf, "Date: ", 6))
{
ParseDate (&buf[6], &hdr);
}
else if (!strncmp (buf, "To: ", 4))
{
PadString (&buf[4], hdr.to, 25);
}
else if (!strncmp (buf, "Subject: ", 9))
{
PadString (&buf[9], hdr.subject, 25);
}
/*
else if (!strncmp (buf, "From: ", 6))
{
PadString (&buf[6], hdr.from, 25);
}
*/

eof = Fgets (buf, BUF_LEN, mail_fd);
}
mp->text = ftell (mail_fd);

/* Fill in block count */
if (inc_hdrs)
{
PadNum (2+(mp->end-mp->begin)/128, hdr.blocks, 6);
blk_cnt += (1+(mp->end - mp->begin)/128);
}
else
{
PadNum (2+(mp->end-mp->text)/128, hdr.blocks, 6);
blk_cnt += (1+(mp->end - mp->text)/128);
}

/* Write out the message header */
fwrite (&hdr, 128, 1, msg_fd);
blk_cnt++;

/* Now write the message text */
if (inc_hdrs) fseek (mail_fd, mp->begin, 0);
out_bytes = 0;

eof = Fgets (buf, BUF_LEN, mail_fd);
do
{
n = strlen (buf);
fwrite (buf, n, 1, msg_fd);
out_bytes += n;
if (n < BUF_LEN-1)
{
fputc (QWK_EOL, msg_fd);
out_bytes++;
}
eof = Fgets (buf, BUF_LEN, mail_fd);
} while ( (strncmp(buf,"From ", 5)) && (NULL != eof) );

/* Pad block as necessary */
n = out_bytes % 128;
for (;n<128;n++) fputc (' ', msg_fd);
}

misc.c 644 150 144 11115 5350007634 10435 0ustar mloewenvm#include
#include
#include "uqwk.h"

/*
* Miscellaneous uqwk routines
*/

NewConference (name)
char *name;
{
struct conf_ent *cp, *tmp_cp;
char *c, ndx_fname[PATH_LEN];

/* Get space for new conference */
if (NULL == (tmp_cp = (struct conf_ent *) malloc
(sizeof (struct conf_ent))))
{
fprintf (stderr, "%s: out of memory\n", progname);
exit (0);
}

/* Get space for name */
if (NULL == (c = (char *) malloc (1+strlen(name))))
{
fprintf (stderr, "%s: out of memory\n", progname);
exit (0);
}

/* Fill in conference name */
tmp_cp->name = c;
strcpy (tmp_cp->name, name);

/* Fill in conference number */
tmp_cp->number = conf_cnt;

/* Add to end of conference list */
if (last_conf == NULL)
{
/* This is first conference */
conf_list = tmp_cp;
}
else
{
last_conf->next = tmp_cp;
}
tmp_cp->next = NULL;
last_conf = tmp_cp;

/* Open new index file */
if (!strcmp (name, MAIL_CONF_NAME))
{
strcpy (ndx_fname, home_dir);
strcat (ndx_fname, "/");
strcat (ndx_fname, "personal.ndx");
}
else
{
sprintf (ndx_fname, "%s/%03d.ndx", home_dir, conf_cnt);
}

if (NULL == (ndx_fd = fopen (ndx_fname, "w")))
{
fprintf (stderr, "%s: can't open %s\n", progname, ndx_fname);
exit (0);
}

conf_cnt++;
}

PadString (s, c, n)
char *s, *c;
int n;
/*
* Take a null-terminated string s and copy it, space-padded or
* truncated if necessary, into field c of n characters
*/
{
int len, i;
len = strlen (s);
if (len >= n)
{
strncpy (c, s, n);
}
else
{
strcpy (c, s);
Spaces (&c[len], n-len);
}
}

Spaces (c, n)
char *c;
int n;
/*
* Fill field of n characters with spaces
*/
{
int i;
for (i=0; i }

PadNum (i, c, n)
int i, n;
char *c;
/*
* Format an integer i and place it, space filled, in
* field c of n characters
*/
{
sprintf (buf, "%d", i);
PadString (buf, c, n);
}

IntNum (i, c)
int i;
char c[2];
/*
* Put binary integer i into two bytes
*/
{
c[0] = i % 256;
c[1] = (i / 256) % 256;
}

char *Fgets (c, n, fd)
char *c;
int n;
FILE *fd;
/*
* Same as fgets, but changes trailing linefeed to a null
*/
{
int i;

if (NULL == fgets (c, n, fd)) return (NULL);
i = strlen (c);
if ( (i > 0) && (c[i-1]=='\n') ) c[i-1] = 0;

return (c);
}

inttoms (i, c)
int i;
char c[4];
/*
* Convert an integer into the Microsoft Basic floating format.
* This is the dumbest thing in the whole QWK standard. Why in
* the world store block offsets as floating point numbers?
* Stupid!
*/
{
int m, e;

if (i == 0)
{
c[0] = c[1] = c[2] = 0;
c[3] = 0x80;
return;
}

e = 152;
m = 0x7fffff & i;

while (!(0x800000 & m))
{
m <<= 1;
e--;
}
c[0] = 0xff & m;
c[1] = 0xff & (m >> 8);
c[2] = 0x7f & (m >> 16);
c[3] = 0xff & e;
}

int LastInt (line)
char *line;
/*
* Find last integer on line
*/
{
int i, last_delim, n;
n = strlen (line);

/* Find last delimiter */
for (i=0; i {
if ( (line[i] == ' ') || (line[i] == '-') ||
(line[i] == ',') || (line[i] == ':') )
last_delim = i;
}

i = atoi (&line[last_delim+1]);
return (i);
}

ParseDate (c, hp)
char *c;
struct qwk_hdr *hp;
{
char s[PATH_LEN];
int day, mon, year, hour, minute;
char month[4];

/* Dates come in two flavors: with the weekday, and without.
we simply look for the comma which follows the weekday */
if (c[3] == ',')
{
sscanf (&c[4], "%d %s %d %d:%d", &day, month, &year,
&hour, &minute);
}
else
{
sscanf (c, "%d %s %d %d:%d", &day, month, &year,
&hour, &minute);
}

/* Convert alphabetic month name to integer */
if (!strncmp (month, "Jan", 3)) mon = 1;
if (!strncmp (month, "Feb", 3)) mon = 2;
if (!strncmp (month, "Mar", 3)) mon = 3;
if (!strncmp (month, "Apr", 3)) mon = 4;
if (!strncmp (month, "May", 3)) mon = 5;
if (!strncmp (month, "Jun", 3)) mon = 6;
if (!strncmp (month, "Jul", 3)) mon = 7;
if (!strncmp (month, "Aug", 3)) mon = 8;
if (!strncmp (month, "Sep", 3)) mon = 9;
if (!strncmp (month, "Oct", 3)) mon = 10;
if (!strncmp (month, "Nov", 3)) mon = 11;
if (!strncmp (month, "Dec", 3)) mon = 12;

/* Convert date */
sprintf (s, "%02d-%02d-%02d", mon, day, year);
PadString (s, hp->date, 8);

/* Time */
sprintf (s, "%02d:%02d", hour, minute);
PadString (s, hp->time, 5);
}

news.c 644 150 144 14226 5350007634 10464 0ustar mloewenvm#include
#include
#include
#include
#include "uqwk.h"
/*
* All sorts of stuff to do news processing
*/

DoNews ()
/*
* Collect unread news into QWK packet
*/
{
struct act_ent *ap;
struct nrc_ent *np;

/* Read .newsrc file */
if (!ReadNewsrc()) return (0);

/* And active file */
if (!ReadActive()) return (0);

/* Look through the newsrc file */
np = nrc_list;
while (np != NULL)
{
/* Check if too many blocks already */
if ( (blk_cnt >= max_blks) && (max_blks > 0) )
{
return (0);
}

if ( (np->subscribed) &&
(NULL != (ap = FindActive (np->name))) )
{
/* Do this group */
DoGroup (np, ap);
}
np = np->next;
}
}

int ReadNewsrc()
/*
* Read the .newsrc file
*/
{
char group_name[PATH_LEN];
struct nrc_ent *np;
int n, c;

/* Don't bother if we've alread read it */
if (nrc_list != NULL) return (1);

/* Open it */
if (NULL == (nrc_fd = fopen (nrc_file, "r")))
{
fprintf (stderr, "%s: can't open %s\n", progname, nrc_file);
return (0);
}

/* Read through */
while (NULL != Fgets (buf, BUF_LEN, nrc_fd))
{
/* Allocate a new nrc entry */
np = (struct nrc_ent *) malloc (sizeof (struct nrc_ent));
if (np == NULL) OutOfMemory();

/* Parse group name */
sscanf (buf, "%s", group_name);
n = strlen (group_name);

if (group_name[n-1] == ':')
{
np->subscribed = 1;
}
else
{
np->subscribed = 0;
}

group_name[n-1] = 0;
np->name = (char *) malloc (n);
if (np->name == NULL) OutOfMemory();
strcpy (np->name, group_name);

/* Hi article number */
np->hi = LastInt (buf);

/* Add to nrc list */
np->next = nrc_list;
nrc_list = np;
}

/* Walk through the nrc list, assign conference numbers */
np = nrc_list;
c = 0;
while (np != NULL)
{
np->conf = c;
c++;
np = np->next;
}

fclose (nrc_fd);
return (1);
}

int ReadActive()
/*
* Read active file
*/
{
char group_name[PATH_LEN];
struct act_ent *ap;
int n;

/* Don't bother if it's already here */
if (act_list != NULL) return (1);

/* Open the active file */
if (NULL == (act_fd = fopen (act_file, "r")))
{
fprintf (stderr, "%s: can't open %s\n", progname, act_file);
return (0);
}

/* Read through it */
while (NULL != Fgets (buf, BUF_LEN, act_fd))
{
/* Get new act entry */
ap = (struct act_ent *) malloc (sizeof (struct act_ent));
if (ap == NULL) OutOfMemory();

/* Parse name, message numbers */
sscanf (buf, "%s %d %d", group_name, &ap->hi, &ap->lo);
ap->name = (char *) malloc (1+strlen(group_name));
if (ap->name == NULL) OutOfMemory();
strcpy (ap->name, group_name);

/* Add to list */
ap->next = act_list;
act_list = ap;
}

fclose (act_fd);
return (1);
}

struct act_ent *FindActive (c)
char *c;
/*
* Look for group's active entry given group name
*/
{
struct act_ent *ap;

ap = act_list;
while (NULL != ap)
{
if (!strcmp (c, ap->name)) return (ap);
ap = ap->next;
}
return (NULL);
}

DoGroup (np, ap)
struct nrc_ent *np;
struct act_ent *ap;
/*
* Process given group
*/
{
char news_path[PATH_LEN];
char art_file[PATH_LEN];
int i, n;

printf ("%s: %s\n", progname, np->name);

/* Make a new conference with this name */
NewConference (np->name);

/* Construct path name for articles in this group */
strcpy (news_path, news_dir);
strcat (news_path, "/");
strcat (news_path, np->name);
strcat (news_path, "/");
n = strlen (news_path);
for (i=0; i
/* If highest read article is greater than highest available
article, assume group has been reset */
if (np->hi > ap->hi) np->hi = ap->lo;

/* Look through unread articles */
for (i=np->hi+1; i<=ap->hi; i++)
{
/* Check max block count */
if ( (blk_cnt >= max_blks) && (max_blks > 0) )
{
fclose (ndx_fd);
np->hi = i;
return (0);
}

/* Construct article's file name */
sprintf (art_file, "%s%d", news_path, i);

/* Process this article */
DoArticle (art_file);
}
fclose (ndx_fd);

/* Reset hi article number */
np->hi = ap->hi;
}

DoArticle (art_file)
char *art_file;
{
struct qwk_hdr hdr;
struct stat stat_buf;
long txt_offset, end_offset;
int n, out_bytes;
char ndx[5], *eof, from[PATH_LEN];
FILE *art_fd;

/* Forget it if we can't open the article */
if (NULL == (art_fd = fopen (art_file, "r"))) return (0);

/* stat() the article to get file size */
if (0 != stat (art_file, &stat_buf))
{
fclose (art_fd);
return (0);
}
end_offset = stat_buf.st_size;

/* Skip empty articles */
if (end_offset == 0)
{
fclose (art_fd);
return (0);
}

/* Write the index file entry */
inttoms (blk_cnt, ndx);
ndx[4] = conf_cnt - 1;
fwrite (ndx, 5, 1, ndx_fd);

Spaces (&hdr, 128);

/* Fill in some header fields */
hdr.status = QWK_PUBLIC;
PadNum (msg_cnt, hdr.number, 7);
Spaces (hdr.password, 12);
Spaces (hdr.refer, 8);
hdr.flag = QWK_ACT_FLAG;
IntNum (conf_cnt-1, hdr.conference);
IntNum (msg_cnt+1, hdr.msg_num);
hdr.tag = ' ';
PadString ("ALL", hdr.to, 25);

msg_cnt++;

/* Process header lines */
eof = Fgets (buf, BUF_LEN, art_fd);
while ( (0 != strlen(buf)) && (eof != NULL) )
{
if (!strncmp (buf, "Date: ", 6))
{
ParseDate (&buf[6], &hdr);
}
else if (!strncmp (buf, "Subject: ", 9))
{
PadString (&buf[9], hdr.subject, 25);
}
else if (!strncmp (buf, "From: ", 6))
{
sscanf (&buf[6], "%s", from);
PadString (from, hdr.from, 25);
}

eof = Fgets (buf, BUF_LEN, art_fd);
}

txt_offset = ftell (art_fd);

/* Compute block count */
if (inc_hdrs)
{
PadNum (2+end_offset/128, hdr.blocks, 6);
blk_cnt += 1+end_offset/128;
}
else
{
PadNum (2+(end_offset-txt_offset)/128, hdr.blocks, 6);
blk_cnt += 1+(end_offset-txt_offset)/128;
}

/* Write the message header */
fwrite (&hdr, 128, 1, msg_fd);
blk_cnt++;

/* Now write the article's text */
if (inc_hdrs) fseek (art_fd, 0, 0);
out_bytes = 0;

while (NULL != Fgets (buf, BUF_LEN, art_fd))
{
n = strlen (buf);
fwrite (buf, n, 1, msg_fd);
out_bytes += n;

if (n < BUF_LEN-1)
{
fputc (QWK_EOL, msg_fd);
out_bytes++;
}
}

/* Pad block as necessary */
n = out_bytes % 128;
for (;n<128;n++) fputc (' ', msg_fd);

fclose (art_fd);
}

OutOfMemory()
{
fprintf (stderr, "%s: out of memory\n", progname);
exit (0);
}
offline.c 644 150 144 12403 5350007635 11126 0ustar mloewenvm#include
#include
#include "uqwk.h"
/*
* Process offline commands
*/

OffLine (bytes)
int bytes;
/*
* Process offline commands. Message is open on rep_fd. We
* must be careful to leave the file pointer ready for the
* next message.
*/
{
FILE *pfd;
char c, cmd[PATH_LEN];

/* Open mail pipe to send results back to user */
sprintf (buf, "%s -s 'Results of your request' %s",
MAILER_PATH, user_name);
if (NULL == (pfd = popen (buf, "w")))
{
fprintf (stderr, "%s: can't popen() mail\n", progname);
while (bytes--) fread (&c, 1, 1, rep_fd);
return (0);
}

fprintf (pfd, "Here are the results of your mail to UQWK:\n");

/* Get lines, process them */
while (GetLine(&bytes))
{
/* Echo command */
fprintf (pfd, "\nCommand: %s\n", buf);

/* Extract command */
if (1 != sscanf (buf, "%s", cmd))
{
fprintf (pfd, "Malformed command.\n");
}
else
{
/* Look up command */
if ( (!strcmp (cmd, "help")) ||
(!strcmp (cmd, "HELP")) )
{
Help(pfd);
}
else if ( (!strcmp (cmd, "subscribe")) ||
(!strcmp (cmd, "SUBSCRIBE")) )
{
Subscribe(pfd);
}
else if ( (!strcmp (cmd, "unsubscribe")) ||
(!strcmp (cmd, "UNSUBSCRIBE")) )
{
Unsubscribe(pfd);
}
else if ( (!strcmp (cmd, "groups")) ||
(!strcmp (cmd, "GROUPS")) )
{
Groups(pfd);
}
else if ( (!strcmp (cmd, "allgroups")) ||
(!strcmp (cmd, "ALLGROUPS")) )
{
Allgroups(pfd);
}
else
{
fprintf (pfd, "No such command. ");
fprintf (pfd, "Send HELP for help.\n");
}
}
}

fprintf (pfd, "\nEnd of commands.\n");
pclose (pfd);
}

int GetLine (bytes)
int *bytes;
/*
* Get a line from rep_fd, put it in buf, check for end of message
*/
{
int i;
i = 0;

/* Read bytes until EOL or end of message */
while (*bytes)
{
fread (&buf[i], 1, 1, rep_fd);
(*bytes)--;

if ( (buf[i] == QWK_EOL) || (i == BUF_LEN-1) )
{
buf[i] = 0;
return (1);
}
i++;
}

/* If we got here, we ran out of bytes */
return (0);
}

Help (pfd)
FILE *pfd;
{
fprintf (pfd, "\nAvailable commands:\n\n");
fprintf (pfd, "HELP - This message.\n");
fprintf (pfd, "SUBSCRIBE newsgroup - Subscribe to named newsgroup.\n");
fprintf (pfd, "UNSUBSCRIBE newsgroup - Unsubscribe from newsgroup.\n");
fprintf (pfd, "UNSUBSCRIBE ALL - Unsubscribe from all newsgroups.\n");
fprintf (pfd, "GROUPS - List all subscribed newsgroups.\n");
fprintf (pfd, "ALLGROUPS - List all available newsgroups.\n\n");
}

Subscribe (pfd)
FILE *pfd;
{
struct act_ent *ap;
struct nrc_ent *np;
char group[PATH_LEN];

/* Extract group name */
if (1 != sscanf (buf, "%*s %s", group))
{
fprintf (pfd, "Usage: SUBSCRIBE newsgroup\n");
return (0);
}

/* We will need active file and .newsrc */
if (!ReadActive() || !ReadNewsrc())
{
fprintf (pfd, "Sorry, couldn't read system files.\n");
return (0);
}

/* Already subscribed? */
np = nrc_list;
while (np != NULL)
{
if (!strcmp (group, np->name))
{
if (np->subscribed)
{
fprintf (pfd, "Already subscribed to %s.\n",
group);
return (0);
}
else
{
np->subscribed = 1;
fprintf (pfd, "Okay, re-subscribed to %s.\n",
group);
WriteNewsrc();
return (0);
}
}
np = np->next;
}

/* Find group in active file */
if (NULL == (ap = FindActive (group)))
{
fprintf (pfd, "No such newsgroup: %s\n", group);
return (0);
}

/* Okay already, add to .newsrc */
np = (struct nrc_ent *) malloc (sizeof (struct nrc_ent));
if (np == NULL) OutOfMemory();
np->name = (char *) malloc (1+strlen(group));
if (np->name == NULL) OutOfMemory();
strcpy (np->name, group);
np->subscribed = 1;
np->hi = ap->hi;
np->next = nrc_list;
nrc_list = np;

WriteNewsrc();
fprintf (pfd, "Okay, you are now subscribed to %s.\n", group);
}

Unsubscribe (pfd)
FILE *pfd;
{
struct nrc_ent *np;
char group[PATH_LEN];

/* Parse group name */
if (1 != sscanf (buf, "%*s %s", group))
{
fprintf (pfd, "Usage: UNSUBSCRIBE newsgroup\n");
return (0);
}

/* Check for ALL */
if ( (!strcmp (group, "ALL")) || (!strcmp (group, "all")) )
{
nrc_list = NULL;
WriteNewsrc();
fprintf (pfd,
"Okay, you are now unsubscribed from all newsgroups.\n");
return (0);
}

/* We need the .newsrc file */
if (!ReadNewsrc())
{
fprintf (pfd, "Sorry, couldn't read .newsrc\n");
return (0);
}

/* Look for group in newsrc */
np = nrc_list;
while (np != NULL)
{
if (!strcmp (group, np->name)) break;
np = np->next;
}

if (np == NULL)
{
fprintf (pfd, "You are not currently subscribed to %s.\n",
group);
return (0);
}

np->subscribed = 0;

WriteNewsrc();
fprintf (pfd, "Okay, you are unsubscribed from %s.\n", group);
}

Groups (pfd)
FILE *pfd;
{
struct nrc_ent *np;

if (!ReadNewsrc())
{
fprintf (pfd, "Sorry, couldn't read .newsrc\n");
return (0);
}

fprintf (pfd, "Newsgroups to which you are subscribed:\n\n");

np = nrc_list;
while (np != NULL)
{
fprintf (pfd, " %s\n", np->name);
np = np->next;
}
}

Allgroups (pfd)
FILE *pfd;
{
struct act_ent *ap;

if (!ReadActive())
{
fprintf (pfd, "Sorry, no newsgroups are available.\n");
return (0);
}

fprintf (pfd, "List of available newsgroups:\n\n");

ap = act_list;
while (ap != NULL)
{
fprintf (pfd, " %s (%d articles)\n",
ap->name, ap->hi - ap->lo);
ap = ap->next;
}
}
options.c 644 150 144 12134 5350007635 11200 0ustar mloewenvm#include
#include
#include
#include
#include "uqwk.h"

/*
* Determine runtime options
*/

DefaultOptions()
/*
* Set up default options
*/
{
struct passwd *pw;

/* Do user-specific stuff*/
if (NULL == (pw = getpwuid(getuid())))
{
fprintf (stderr, "%s: warning: you don't exist\n", progname);
strcpy (user_name, DEF_USER_NAME);
strcpy (home_dir, DEF_HOME_DIR);
}
else
{
strcpy (user_name, pw->pw_name);
strcpy (home_dir, pw->pw_dir);
}

/* Dinky misc options */
do_mail = DEF_DO_MAIL;
do_news = DEF_DO_NEWS;
inc_hdrs = DEF_INC_HDRS;
prt_opts = DEF_PRT_OPTS;
read_only = DEF_READ_ONLY;
max_blks = DEF_MAX_BLKS;

strcpy (mail_dir, DEF_MAIL_DIR);
strcpy (mail_file, DEF_MAIL_FILE);
strcpy (act_file, DEF_ACT_FILE);
strcpy (nrc_file, DEF_NRC_FILE);
strcpy (news_dir, DEF_NEWS_DIR);

strcpy (bbs_name, DEF_BBS_NAME);
strcpy (bbs_city, DEF_BBS_CITY);
strcpy (bbs_phone, DEF_BBS_PHONE);
strcpy (bbs_sysop, DEF_BBS_SYSOP);
strcpy (bbs_id, DEF_BBS_ID);
strcpy (rep_file, DEF_REP_FILE);
}

EnvOptions()
/*
* Override options from environment variables
*/
{
char *c;

if (NULL != (c = getenv ("UQ_DO_MAIL"))) do_mail = atoi (c);
if (NULL != (c = getenv ("UQ_DO_NEWS"))) do_news = atoi (c);
if (NULL != (c = getenv ("UQ_INC_HDRS"))) inc_hdrs = atoi (c);
if (NULL != (c = getenv ("UQ_PRT_OPTS"))) prt_opts = atoi (c);
if (NULL != (c = getenv ("UQ_READ_ONLY"))) read_only = atoi (c);
if (NULL != (c = getenv ("UQ_MAX_BLKS"))) max_blks = atoi (c);

if (NULL != (c = getenv ("UQ_HOME_DIR"))) strcpy (home_dir, c);
if (NULL != (c = getenv ("UQ_MAIL_FILE"))) strcpy (mail_file, c);
if (NULL != (c = getenv ("UQ_MAIL_DIR"))) strcpy (mail_dir, c);
if (NULL != (c = getenv ("UQ_USER_NAME"))) strcpy (user_name, c);
if (NULL != (c = getenv ("UQ_NEWS_DIR"))) strcpy (news_dir, c);

if (NULL != (c = getenv ("UQ_BBS_NAME"))) strcpy (bbs_name, c);
if (NULL != (c = getenv ("UQ_BBS_CITY"))) strcpy (bbs_city, c);
if (NULL != (c = getenv ("UQ_BBS_PHONE"))) strcpy (bbs_phone, c);
if (NULL != (c = getenv ("UQ_BBS_SYSOP"))) strcpy (bbs_sysop, c);
if (NULL != (c = getenv ("UQ_BBS_ID"))) strcpy (bbs_id, c);

if (NULL != (c = getenv ("UQ_ACT_FILE"))) strcpy (act_file, c);
if (NULL != (c = getenv ("UQ_NRC_FILE"))) strcpy (nrc_file, c);

if (NULL != (c = getenv ("UQ_REP_FILE"))) strcpy (rep_file, c);
}

CommandOptions (argc, argv)
int argc;
char *argv[];
/*
* Override options from command line
*/
{
int i;

for (i=1; i {
switch (argv[i][0])
{
case '+':
switch (argv[i][1])
{
case 'm': do_mail = 1;
break;

case 'n': do_news = 1;
break;

case 'h': inc_hdrs = 1;
break;

case 'r': read_only = 1;
break;

default: BadFlag (argv[i]);
break;
}
break;

case '-':
switch (argv[i][1])
{
case 'm': do_mail = 0;
break;

case 'n': do_news = 0;
break;

case 'h': inc_hdrs = 0;
break;

case 'r': read_only = 0;
break;

case 'p': prt_opts = 1;
break;

case 'M': strcpy (mail_dir, &argv[i][2]);
break;

case 'f': strcpy (mail_file, &argv[i][2]);
break;

case 'u': strcpy (user_name, &argv[i][2]);
break;

case 'H': strcpy (home_dir, &argv[i][2]);
break;

case 'b': strcpy (bbs_name, &argv[i][2]);
break;

case 'c': strcpy (bbs_city, &argv[i][2]);
break;

case 'P': strcpy (bbs_phone, &argv[i][2]);
break;

case 's': strcpy (bbs_sysop, &argv[i][2]);
break;

case 'i': strcpy (bbs_id, &argv[i][2]);
break;

case 'a': strcpy (act_file, &argv[i][2]);
break;

case 'N': strcpy (nrc_file, &argv[i][2]);
break;

case 'S': strcpy (news_dir, &argv[i][2]);
break;

case 'B': max_blks = atoi (&argv[i][2]);
break;

case 'R': strcpy (rep_file, &argv[i][2]);
break;

default: BadFlag (argv[i]);
break;
}
break;

default:
BadFlag (argv[i]);
break;
}
}

/* If mail file has not been overridden, set it */
if (!strcmp (mail_file, DEF_MAIL_FILE))
{
strcpy (mail_file, mail_dir);
strcat (mail_file, "/");
strcat (mail_file, user_name);
}

/* If .newsrc file has not been overridden, set it */
if (!strcmp (nrc_file, DEF_NRC_FILE))
{
strcpy (nrc_file, home_dir);
strcat (nrc_file, "/.newsrc");
}

if (prt_opts)
{
PrintOptions();
exit (0);
}
}

BadFlag (c)
char *c;
{
fprintf (stderr, "%s: bad flag: %s\n", progname, c);
exit (0);
}

PrintOptions ()
{
printf ("Do mail: %d\n", do_mail);
printf ("Do news: %d\n", do_news);
printf ("Include headers: %d\n", inc_hdrs);
printf ("Read only: %d\n", read_only);
printf ("Maximum blocks: %d\n", max_blks);
printf ("Mail directory: %s\n", mail_dir);
printf ("News directory: %s\n", news_dir);
printf ("Mail file: %s\n", mail_file);
printf ("User name: %s\n", user_name);
printf ("Home directory: %s\n", home_dir);
printf ("BBS name: %s\n", bbs_name);
printf ("BBS city: %s\n", bbs_city);
printf ("BBS phone: %s\n", bbs_phone);
printf ("BBS sysop: %s\n", bbs_sysop);
printf ("BBS id: %s\n", bbs_id);
printf ("Active file: %s\n", act_file);
printf (".newsrc file: %s\n", nrc_file);
printf ("Reply file: %s\n", rep_file);
}
reply.c 644 150 144 12003 5350007636 10634 0ustar mloewenvm#include
#include
#include "uqwk.h"
/*
* Process a reply packet
*/

DoReply ()
{
int n, rep_cnt;
char bbs[PATH_LEN];

rep_cnt = 0;

/* Open the packet */
if (NULL == (rep_fd = fopen (rep_file, "r")))
{
fprintf (stderr, "%s: can't open %s\n", progname, rep_file);
return (0);
}

/* Get the first block, the BBS ID */
if (1 != fread (buf, 128, 1, rep_fd))
{
fprintf (stderr, "%s: reply packet read error\n", progname);
fclose (rep_fd);
return (0);
}

/* Extract bbs id and check */
sscanf (bbs_id, "%*d,%s", bbs);
n = strlen (bbs);
buf[n] = 0;
if (strcmp (bbs, buf))
{
fprintf (stderr, "%s: reply BBS ID mismatch: %s != %s\n",
progname, buf, bbs);
fclose (rep_fd);
return (0);
}

/* Read the .newsrc file; we will need the list of conferences */
ReadNewsrc();

/* Read the next message header and process it */
while (1 == fread (&rep_hdr, 128, 1, rep_fd))
{
SendReply ();
rep_cnt++;
}

fclose (rep_fd);
printf ("%s: sent %d replies\n", progname, rep_cnt);
}

SendReply ()
/*
* Pipe a reply to the mailer or inews
*/
{
FILE *pfd;
unsigned char c, to[PATH_LEN], subject[PATH_LEN], group[PATH_LEN];
int i, n, blocks, bytes, conf;
struct nrc_ent *np;

/* Extract recipient */
strncpy (buf, rep_hdr.to, 25);
buf[25] = 0;
sscanf (buf, "%s", to);

/* Extract conference number */
strncpy (buf, rep_hdr.number, 7);
buf[7] = 0;
sscanf (buf, "%d", &conf);

/* Extract subject */
strncpy (buf, rep_hdr.subject, 25);
buf[25] = 0;
strcpy (subject, buf);

/* Get rid of single quotes in subject */
n = strlen (subject);
for (i=0; i
/* Find newsgroup with this conference number */
np = nrc_list;
while (np != NULL)
{
if (np->conf == conf) break;
np = np->next;
}

/* Get newsgroup name */
if (np == NULL)
{
/* Bet this generates lots of email for "ALL" */
rep_hdr.status = QWK_PRIVATE;
}
else
{
strcpy (group, np->name);
}

/* Extract block count */
strncpy (buf, rep_hdr.blocks, 6);
buf[6] = 0;
sscanf (buf, "%d", &blocks);
blocks -= 1;
bytes = 128 * blocks;

/* Check for off-line command message */
if ( (!strcmp (to, "uqwk")) || (!strcmp (to, "UQWK")) )
{
OffLine (bytes);
return (0);
}

/* Check for a configuration message intended for some
other QWK "door" */
if ( (!strcmp (to, "MARKMAIL")) || (!strcmp (to, "QMAIL")) ||
(!strcmp (to, "markmail")) || (!strcmp (to, "qmail")) ||
(!strcmp (to, "ROSEMAIL")) || (!strcmp (to, "KMAIL")) ||
(!strcmp (to, "rosemail")) || (!strcmp (to, "kmail")) ||
(!strcmp (to, "MAINMAIL")) || (!strcmp (to, "CMPMAIL")) ||
(!strcmp (to, "mainmail")) || (!strcmp (to, "cmpmail")) ||
(!strcmp (to, "ULTRABBS")) || (!strcmp (to, "BGQWK")) ||
(!strcmp (to, "ultrabbs")) || (!strcmp (to, "bgqwk")) ||
(!strcmp (to, "CAM-MAIL")) || (!strcmp (to, "TRIMAIL")) ||
(!strcmp (to, "cam-mail")) || (!strcmp (to, "trimail")) ||
(!strcmp (to, "QSO")) || (!strcmp (to, "qso")) )
{
/* Send warning to user */
SendWarning (to);

/* Skip the rest of the message */
while (bytes--) fread (&c, 1, 1, rep_fd);

return (0);
}

/* Open pipe to proper program */
pfd = NULL;

if ( (rep_hdr.status == QWK_PUBLIC) ||
(rep_hdr.status == QWK_PUBLIC2) )
{
/* Public message, open pipe to inews */
sprintf (buf, "%s -t '%s' -n %s", INEWS_PATH, subject, group);
printf ("%s\n", buf);
if (NULL == (pfd = popen (buf, "w")))
{
fprintf (stderr, "%s: can't popen() inews\n",
progname);
}
}
else if ( (rep_hdr.status == QWK_PRIVATE) ||
(rep_hdr.status == QWK_PRIVATE2) )
{
/* Open pipe to mail */
sprintf (buf, "%s -s '%s' %s", MAILER_PATH, subject, to);
printf ("%s\n", buf);
if (NULL == (pfd = popen (buf, "w")))
{
fprintf (stderr, "%s: can't popen() mail\n", progname);
}
}

/* Read and send all bytes of message */
for (i=0; i {
fread (&c, 1, 1, rep_fd);
if (c == QWK_EOL) c = 012;
if (pfd != NULL) fwrite (&c, 1, 1, pfd);
}

if (pfd != NULL) pclose (pfd);
}

SendWarning (to)
char *to;
/*
* Mail a warning to the user if the reply packet
* contains a message apparently for some other QWK
* "door" program.
*/
{
FILE *pfd;

/* Open pipe to mailer */
sprintf (buf, "%s -s 'UQWK Error Message' %s",
MAILER_PATH, user_name);
if (NULL == (pfd = popen (buf, "w")))
{
fprintf (stderr, "%s: can't popen() mail\n", progname);
return (0);
}

/* Send the message */

fprintf (pfd,
"Hello. You sent a message to the username %s, presumably to\n", to);
fprintf (pfd,
"perform some sort of offline configuration. This QWK processor,\n");
fprintf (pfd,
"called UQWK, cannot process this message. To perform offline\n");
fprintf (pfd,
"configuration using UQWK, you must send a message to the username\n");
fprintf (pfd,
"UQWK. Commands are to be included in the body of the message.\n");
fprintf (pfd,
"For a list of commands, send a message to UQWK with the word\n");
fprintf (pfd,
"HELP in the body of the message (not the subject). Thanks!\n");

pclose (pfd);
}
uqwk.c 644 150 144 1125 5350007636 10453 0ustar mloewenvm#include
#include
#include "uqwk.h"

/*
* Try to make QWK packets from a mail and/or news spool
*/

main (argc, argv)
int argc;
char *argv[];
{
progname = argv[0];

/* Set up defaults */
DefaultOptions();

/* Look for environment variable overrides */
EnvOptions();

/* Look for command line overrides */
CommandOptions (argc, argv);

/* Initialize files, etc. */
InitStuff();

/* Do reply packet? */
if (strcmp (rep_file, DEF_REP_FILE)) DoReply();

/* Do news? */
if (do_news) DoNews();

/* Mail? */
if (do_mail) DoMail();

/* All done */
CloseStuff();
}
uqwk.h 644 150 144 10135 5350007637 10502 0ustar mloewenvm/*
* Header for uqwk
*/

#define PATH_LEN (128) /* Length for file names, etc. */
#define BUF_LEN (1024) /* Length of general purpose buffer */

#define QWK_EOL (227) /* QWK end-of-line */
#define QWK_ACT_FLAG (225) /* Active message flag */
#define QWK_PUBLIC ' ' /* Public message flags */
#define QWK_PUBLIC2 '-'
#define QWK_PRIVATE '+' /* Private message flags */
#define QWK_PRIVATE2 '*'

#define MAILER_PATH "mail" /* Where to find mailer */
#define INEWS_PATH "/usr/lib/news/inews" /* Where to find inews */

#define MAIL_CONF_NAME "Email"

/* Defaults */
#define DEF_MAIL_DIR "/usr/spool/mail"
#define DEF_DO_MAIL (1)
#define DEF_DO_NEWS (0)
#define DEF_INC_HDRS (1)
#define DEF_PRT_OPTS (0)
#define DEF_READ_ONLY (0)
#define DEF_MAX_BLKS (4000) /* That's half a megabyte */
#define DEF_HOME_DIR "."
#define DEF_USER_NAME "unknown"
#define DEF_MAIL_FILE "unknown"
#define DEF_BBS_NAME "unknown BBS"
#define DEF_BBS_CITY "Anytown, USA"
#define DEF_BBS_PHONE "555-1212"
#define DEF_BBS_SYSOP "Joe Sysop"
#define DEF_BBS_ID "0,SOMEBBS"
#define DEF_ACT_FILE "/usr/lib/news/active"
#define DEF_NRC_FILE "unknown"
#define DEF_NEWS_DIR "/usr/spool/news"
#define DEF_REP_FILE "none"

/* Runtime options */
int do_mail; /* Process mail? */
int do_news; /* Process news? */
int inc_hdrs; /* Include headers in messages? */
int prt_opts; /* Just display options; no processing */
int read_only; /* Don't rewrite mail spool and .newsrc */
int max_blks; /* Maximum blocks per QWK packet */

char mail_file[PATH_LEN]; /* mail spool */
char mail_dir[PATH_LEN]; /* dir for mail spool */
char home_dir[PATH_LEN]; /* home directory */
char user_name[PATH_LEN]; /* user's login name */
char bbs_name[PATH_LEN]; /* BBS name */
char bbs_city[PATH_LEN]; /* BBS city */
char bbs_phone[PATH_LEN]; /* BBS phone number */
char bbs_sysop[PATH_LEN]; /* BBS sysop name */
char bbs_id[PATH_LEN]; /* BBS ID */
char act_file[PATH_LEN]; /* Active file */
char nrc_file[PATH_LEN]; /* .newsrc file */
char news_dir[PATH_LEN]; /* News spool dir */
char rep_file[PATH_LEN]; /* Reply packet file name */

char *getenv();
char *Fgets();
struct act_ent *FindActive();

/* Various globals */
char *progname; /* Program name */
int msg_cnt; /* Total number of messages */
int conf_cnt; /* Total number of conferences */
FILE *msg_fd; /* MESSAGES.DAT file desc */
FILE *ctl_fd; /* CONTROL.DAT file desc */
FILE *ndx_fd; /* xxx.NDX file desc */
FILE *act_fd; /* Active file file desc */
FILE *nrc_fd; /* .newsrc file desc */
FILE *rep_fd; /* Reply packet file desc */
unsigned char buf[BUF_LEN]; /* General purpose buffer */
int blk_cnt; /* Blocks written to messages.dat */

/* This is the stuff we remember about each spooled mail message */
struct mail_ent
{
long begin; /* Offset of start of header */
long text; /* Offset to end of header, start of text */
long end; /* Offset to start of next message */
struct mail_ent *next; /* Pointer to next */
} *mail_list;

/* This is stuff we remember about each "conference" */
struct conf_ent
{
char *name; /* Conference name */
int number; /* Conference number */
struct conf_ent *next; /* Pointer to next */
} *conf_list, *last_conf;

/* This is the QWK message header format */
struct qwk_hdr
{
unsigned char status;
unsigned char number[7];
unsigned char date[8];
unsigned char time[5];
unsigned char to[25];
unsigned char from[25];
unsigned char subject[25];
unsigned char password[12];
unsigned char refer[8];
unsigned char blocks[6];
unsigned char flag;
unsigned char conference[2];
unsigned char msg_num[2];
unsigned char tag;
};

struct qwk_hdr rep_hdr; /* Header for replies */

/* Stuff we remember about each active newsgroup */
struct act_ent
{
char *name; /* Newsgroup name */
int hi; /* High article number */
int lo; /* Low article number */
struct act_ent *next; /* Pointer to next */
} *act_list;

/* Stuff we remember about the .newsrc file */
struct nrc_ent
{
char *name; /* Newsgroup name */
int subscribed; /* Subscribed flag */
int hi; /* High article number */
int conf; /* Corresponding conference number */
struct nrc_ent *next; /* Pointer to next */
} *nrc_list;

uqwk.man 644 150 144 21113 5350007637 11024 0ustar mloewenvm.TH UQWK 1
.IX uqwk
.IX qwk
.SH NAME
uqwk - Collect news and mail into QWK packet
.SH SYNOPSIS
.B
uqwk
.RB [options]
.SH DESCRIPTION
.B uqwk
is a program which collects all a user's unread mail or news
and formats it into something called a "QWK" packet, which is then
downloaded. Mail and News can then be read offline, saving phone
charges. QWK readers exist for almost every machine.
.PP
.B uqwk
also accepts reply packets, so replies can be mailed (if your
mailer understands "mail -s"), or posted (if you have a B-news type
of
.IR inews
that understands -n and -t), depending whether
the message is marked private (email) or public (news).
.PP
.B uqwk
also supports a small offline command language, so the contents
of the user's .newsrc file can be viewed and manipulated offline.
.SH OPTIONS
.TP
.B +m
Do mail.
.B uqwk
will process all mail in the user's mail spool file and convert
it into a QWK packet. This is the default.
.TP
.B -m
Don't do mail.
.TP
.B +n
Do news. Using the user's .newsrc file and the news system's
active file,
.B uqwk
will collect all unread news articles in all subscribed newsgroups
into the QWK packet. This can generate a large number of messages
and large QWK files.
.TP
.B -n
Don't do news. This is the default.
.TP
.B +h
Include headers. Since the QWK specification places limits on
the sizes of certain header fields such as To:, From:, and Subject:,
.B uqwk
can include all message and article headers in the body of the
message so all fields are visible. This does not, however, make
it possible to successfully send a message to an email address
which consists of more that 25 characters. This is the default.
.TP
.B -h
Do not include headers in messages.
.TP
.B -p
Print options.
.B uqwk
will examine all appropriate environment variables and command
line options, print the values of all run-time options, then exit. This
is useful to see what
.B uqwk
thinks it is going to do before you actually run it.
.TP
.B +r
Read only. Normally,
.B uqwk
will empty the user's mail spool file and update the user's .newsrc
file to reflect the fact that mail and news have been
read. If this switch is specified,
.B uqwk
will not touch these files. This is useful for testing.
.TP
.B -r
Do not execute in read-only mode. This is the default.
.TP
.B -M\fImaildir\fR
Look in the directory \fImaildir\fR for the mail spool file. The
default is /usr/spool/mail.
.TP
.B -f\fImailfile\fR
Look for mail in the file \fImailfile\fR. The default is a file
with the same name as the user's login name in \fImaildir\fR.
This switch overrides the
.B -M
switch.
.TP
.B -u\fIusername\fR
By default
.B uqwk
uses the getpwuid() system call to determine the proper user
name to use. This switch overrides the results of that call.
.TP
.B -H\fIhomedir\fR
By default,
.B uqwk
uses the getpwuid() system call to determine the user's home
directory. The home directory is where the files comprising
the QWK packet will be created. It is also where
.B uqwk
looks for the .newsrc file. This switch may be used to
override the results of the getpwuid() call.
.TP
.B -b\fIbbsname\fR
Specify the BBS Name to be entered into the QWK packet. The default
is "unknown BBS".
.TP
.B -c\fIcity\fR
Specify the BBS City to be entered into the QWK packet. The default
is "Anytown, USA".
.TP
.B -P\fIphone\fR
Specify the BBS Phone Number to be entered into the QWK packet.
The default is "555-1212".
.TP
.B -s\fIsysop\fR
Specify the BBS Sysop Name to be entered into the QWK packet. The
default is "Joe Sysop".
.TP
.B -i\fIbbsid\fR
Specify the BBS ID to be entered into the QWK packet. The BBS ID
is important since it will be checked against the BBS ID string
in any incoming reply packets. If the two do not match, the reply
packet will not be processed. The BBS ID consists of an integer,
a comma, and a string of less than nine characters, with no spaces.
The default is "0,SOMEBBS".
.TP
.B -a\fIactivefile\fR
Use \fIactivefile\fR for the list of all available newsgroups and
article numbers. The default is /usr/lib/news/active.
.TP
.B -N\fInewsrcfile\fR
Use \fInewsrcfile\fR for the list of all newsgroups to which the
user is subscribed and the list of article numbers which have been
read. The default is a file called ".newsrc" in the user's home
directory.
.TP
.B -S\fInewsdir\fR
Look for news articles in the directory \fInewsdir\fR. The default
is /usr/spool/news.
.TP
.B -B\fImaxblocks\fR
Stop processing news articles if the size of the QWK packet
(specifically, messages.dat) exceeds \fImaxblocks\fR 128-byte blocks.
This is useful since large amounts of unread news can create large
QWK files. Use a \fImaxblocks\fR value of zero to suppress this
check. The default is 4000 blocks (half a megabyte).
.TP
.B -R\fIreplyfile\fR
Process \fIreplyfile\fR as a reply packet. Messages and articles
created by the offline reader must be uploaded as a reply packet
and then processed by this switch to be mailed or posted.
.B uqwk
will remove \fIreplyfile\fR when it has been processed unless
it is running in read-only mode.
.SH "ENVIRONMENT VARIABLES"
Most of the run-time options can also be controlled by
environment variables. If an option is specified by both
an environment variable and a command-line option, the
command-line option is honored.
.TP
.B UQ_DO_MAIL
Determines whether or not to process mail. Should be set to
"1" (do mail) or "0" (don't do mail).
.TP
.B UQ_DO_NEWS
Determines whether or not to process news. Should be set to
"1" (do news) or "0" (don't do news).
.TP
.B UQ_INC_HDRS
Determines whether or not to include headers in messages.
Should be set to "1" (include headers) or "0" (don't include
headers).
.TP
.B UQ_PRT_OPTS
Determines whether or not to just print the values of run-time
options and stop. Should be set to "1" (print options) or
"0" (don't print options).
.TP
.B UQ_READ_ONLY
Determines whether or not to run in read-only mode. Should be
set to "1" (read-only) or "0" (not read-only).
.TP
.B UQ_MAIL_DIR
Specifies the directory where the mail spool file resides.
.TP
.B UQ_MAIL_FILE
Specifies the mail spool file.
.TP
.B UQ_USER_NAME
Specifies the username of the person running
.B uqwk.
.TP
.B UQ_HOME_DIR
Specifies the home directory, where the QWK files will be
created, and where
.B uqwk
expects to find the .newsrc file.
.TP
.B UQ_BBS_NAME
Specifies the BBS name to be entered into the QWK packet.
.TP
.B UQ_BBS_CITY
Specifies the BBS city to be entered into the QWK packet.
.TP
.B UQ_BBS_PHONE
Specifies the BBS phone number to be entered into the QWK packet.
.TP
.B UQ_BBS_SYSOP
Specifies the BBS sysop name to be entered into the QWK packet.
.TP
.B UQ_BBS_ID
Specifies the BBS ID to be entered into the QWK packet.
.TP
.B UQ_ACT_FILE
Specifies the name of the news system's active file.
.TP
.B UQ_NRC_FILE
Specifies the name of the user's .newsrc file.
.TP
.B UQ_REP_FILE
Specifies the name of the reply packet, if any.
.SH "COMMAND LANGUAGE"
If, while processing a reply packet,
.B uqwk
encounters a message to the username "UQWK", the body of the
message will be interpreted as a small command language, used
to display newsgroup names and subscribe or unsubscribe to
newsgroups. The results of the execution of the commands will
be mailed back to the originating user.
.PP
This is what the command language looks like:
.TP
.B HELP
List all the available commands.
.TP
.B SUBSCRIBE newsgroup
Subscribe to the named newsgroup.
.TP
.B UNSUBSCRIBE newsgroup
Unsubscribe from the named newsgroup. UNSUBSCRIBE ALL may be used to
unsubscribe from all newsgroups. UNSUBSCRIBE ALL is also the only way
to create a new .newsrc if it does not already exist.
.TP
.B GROUPS
List all newsgroups to which the user is currently subscribed.
.TP
.B ALLGROUPS
List all the available newsgroups and the number of articles in
each one.
.SH BUGS
Karl J. Vesterling reported that some .newsrc files cause a core dump.
This may be related to the size of the .newsrc file or to long
lines in the file. I was unable to reproduce the problem. Increasing
BUF_LEN in uqwk.h may help.
.SH "SEE ALSO"
.PD
.BR mail(1),
.BR inews(8)
.SH ACKNOWLEDGEMENTS
Thanks to Patrick Y. Lee ([email protected]) for the QWK documentation.
Many thanks also to the beta-testers: Karl J. Vesterling
([email protected]) and Brian J. Coan ([email protected]).
.SH AUTHOR
Steve Belczyk, [email protected], [email protected].
.PP
Copyright (C) 1993 by Steve Belczyk.
Permission to use, copy, modify and distribute this software and its
documentation for any purpose and without fee is hereby granted, provided
that the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation. This software is provided "as is" without express or
implied warranty.


  3 Responses to “Category : C Source Code
Archive   : UQWK.ZIP
Filename : UQWK.TAR

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/