home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume36 / uqwk / part01 < prev    next >
Encoding:
Text File  |  1993-03-10  |  58.0 KB  |  2,459 lines

  1. Newsgroups: comp.sources.misc
  2. From: seb3@gte.com (Steve Belczyk)
  3. Subject: v36i008:  uqwk - a QWK "door" for Unix, Part01/01
  4. Message-ID: <1993Mar12.033225.12237@sparky.imd.sterling.com>
  5. X-Md4-Signature: b060000bfb06487be8ac1dbab0414ea9
  6. Date: Fri, 12 Mar 1993 03:32:25 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: seb3@gte.com (Steve Belczyk)
  10. Posting-number: Volume 36, Issue 8
  11. Archive-name: uqwk/part01
  12. Environment: UNIX
  13.  
  14. Uqwk is a program which collects all a user's unread mail or news
  15. and formats it into something called a "QWK" packet, which is then
  16. downloaded.  Mail and News can then be read offline, saving phone
  17. charges.  QWK readers exist for almost every machine.
  18. -------------
  19. #! /bin/sh
  20. # This is a shell archive.  Remove anything before this line, then feed it
  21. # into a shell via "sh file" or similar.  To overwrite existing files,
  22. # type "sh file -c".
  23. # Contents:  README Makefile close.c init.c mail.c misc.c news.c
  24. #   offline.c options.c reply.c uqwk.c uqwk.h uqwk.man
  25. # Wrapped by kent@sparky on Thu Mar 11 21:28:15 1993
  26. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
  27. echo If this archive is complete, you will see the following message:
  28. echo '          "shar: End of archive 1 (of 1)."'
  29. if test -f 'README' -a "${1}" != "-c" ; then 
  30.   echo shar: Will not clobber existing file \"'README'\"
  31. else
  32.   echo shar: Extracting \"'README'\" \(3070 characters\)
  33.   sed "s/^X//" >'README' <<'END_OF_FILE'
  34. XUQWK
  35. X
  36. XCopyright 1993, steve belczyk
  37. X
  38. XUqwk is a program which collects all a user's unread mail or news
  39. Xand formats it into something called a "QWK" packet, which is then
  40. Xdownloaded.  Mail and News can then be read offline, saving phone
  41. Xcharges.  QWK readers exist for almost every machine.
  42. X
  43. XUqwk also accepts reply packets, so replies can be mailed (if your
  44. Xmailer understands "mail -s"), or posted (if you have a B-news type
  45. Xof inews that understands -n and -t), depending whether the message
  46. Xis marked private (email) or public (news).
  47. X
  48. XUqwk also supports a small offline command language, so the contents
  49. Xof the user's .newsrc file can be viewed and manipulated offline.
  50. X
  51. XINSTALLATION
  52. X
  53. X1.  Create a directory for the uqwk source code.
  54. X
  55. X    mkdir /usr/local/src/uqwk
  56. X
  57. X2.  Move the uqwk tar file to that directory.
  58. X
  59. X    mv uqwk.tar.Z /usr/local/src/uqwk
  60. X
  61. X3.  Change to that directory, and unpack the tar file.
  62. X
  63. X    cd /usr/local/src/uqwk; zcat uqwk.tar | tar xvf -
  64. X
  65. X4.  Compile the software.
  66. X
  67. X    make
  68. X
  69. X    If this doesn't work you may have to twiddle with the Makefile,
  70. X    or, heaven forbid, the actual source code.
  71. X
  72. X5.  Move the binary and man pages to some public place.
  73. X
  74. X    mv uqwk /usr/local/bin
  75. X    mv uqwk.man /usr/man/man1/uqwk.1
  76. X    mv uqwk.cat /usr/man/cat1/uqwk.1
  77. X
  78. X6.  The QWK specification allows for the name, location, etc., of
  79. X    the BBS from which messages are being downloaded.  You should
  80. X    configure this information.  The best way is probably to use
  81. X    environment variables.  If you are using a Bourne shell, you
  82. X    should add something like this to /etc/profile or .profile:
  83. X
  84. X        UQ_BBS_NAME="My Super BBS"
  85. X    UQ_BBS_CITY="Somewhere, PA"
  86. X    UQ_BBS_PHONE="+1 215 555 1212"
  87. X    UQ_BBS_SYSOP="Joe Shmoe"
  88. X    UQ_BBS_ID="0,MYBBS"
  89. X    export UQ_BBS_NAME UQ_BBS_CITY UQ_BBS_PHONE
  90. X    export UQ_BBS_SYSOP UQ_BBS_ID
  91. X
  92. X    If you use a C type shell, try something like this in your
  93. X    .cshrc or .login:
  94. X
  95. X        setenv UQ_BBS_NAME "My Super BBS"
  96. X    setenv UQ_BBS_CITY "Somewhere, PA"
  97. X    setenv UQ_BBS_PHONE "+1 215 555 1212"
  98. X    setenv UQ_BBS_SYSOP "Joe Shmoe"
  99. X    setenv UQ_BBS_ID "0,MYBBS"
  100. X
  101. X    In both cases, the last entry, the "BBS ID", is the most important.
  102. X    It always consists of an integer, a comma, and a string less than
  103. X    nine characters, with no intervening spaces.  The string will be
  104. X    used to identify reply packets.
  105. X
  106. X7.  Now you can try it.  Log in as a normal user who has some mail,
  107. X    and issue:
  108. X
  109. X    uqwk +r
  110. X
  111. X    (The "+r" stops uqwk from clearing the user's mail spool file.)
  112. X    This should create three new files in the current directory named
  113. X    messages.dat, control.dat, and personal.ndx.  These are the files
  114. X    which the offline reader will need.  (Not all readers need the
  115. X    *.ndx files.  Also, some readers expect these files to have been
  116. X    archived using an archiver like zip, lharc, or arj.  You may need
  117. X    to obtain Unix versions of these archivers.)
  118. X
  119. X8.  Now it would be a good idea to read the man page.
  120. X
  121. XPlease inform me of any problems you run into:
  122. X
  123. X    steve belczyk
  124. X    steve1@genesis.nred.ma.us
  125. X    seb3@gte.com
  126. X    BBS: +1 508 664 0149
  127. X
  128. END_OF_FILE
  129.   if test 3070 -ne `wc -c <'README'`; then
  130.     echo shar: \"'README'\" unpacked with wrong size!
  131.   fi
  132.   # end of 'README'
  133. fi
  134. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  135.   echo shar: Will not clobber existing file \"'Makefile'\"
  136. else
  137.   echo shar: Extracting \"'Makefile'\" \(637 characters\)
  138.   sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  139. X#
  140. X#  Makefile for uqwk
  141. X#
  142. X#  steve belczyk  02/93
  143. X#
  144. XCFLAGS=
  145. X#
  146. X#  Use this for SGI:
  147. X#CFLAGS=-cckr
  148. X
  149. Xuqwk:    uqwk.o options.o init.o mail.o misc.o close.o news.o reply.o offline.o
  150. X    cc -o uqwk uqwk.o options.o init.o mail.o misc.o close.o news.o reply.o offline.o
  151. X
  152. Xuqwk.o:    uqwk.c uqwk.h
  153. X
  154. Xoptions.o:    options.c uqwk.h
  155. X
  156. Xinit.o:    init.c uqwk.h
  157. X
  158. Xmail.o:    mail.c uqwk.h
  159. X
  160. Xmisc.o:    misc.c uqwk.h
  161. X
  162. Xclose.o:    close.c uqwk.h
  163. X
  164. Xnews.o:    news.c uqwk.h
  165. X
  166. Xreply.o:    reply.c uqwk.h
  167. X
  168. Xoffline.o:    offline.c uqwk.h
  169. X
  170. Xclean:
  171. X    rm -f *.o uqwk
  172. X
  173. Xtar:
  174. X    tar cvf uqwk.tar *.[ch] Makefile README uqwk.man uqwk.cat
  175. X    compress -v uqwk.tar
  176. X
  177. Xuu:
  178. X    uuencode uqwk.tar.Z uqwk.tar.Z >uqwk.uu
  179. END_OF_FILE
  180.   if test 637 -ne `wc -c <'Makefile'`; then
  181.     echo shar: \"'Makefile'\" unpacked with wrong size!
  182.   fi
  183.   # end of 'Makefile'
  184. fi
  185. if test -f 'close.c' -a "${1}" != "-c" ; then 
  186.   echo shar: Will not clobber existing file \"'close.c'\"
  187. else
  188.   echo shar: Extracting \"'close.c'\" \(2070 characters\)
  189.   sed "s/^X//" >'close.c' <<'END_OF_FILE'
  190. X#include <stdio.h>
  191. X#include <string.h>
  192. X#include <time.h>
  193. X#include "uqwk.h"
  194. X
  195. X/*
  196. X *  Wrap things up
  197. X */
  198. X
  199. XCloseStuff()
  200. X{
  201. X    fclose (msg_fd);
  202. X
  203. X    WriteControl();
  204. X    if (do_news && (!read_only) ) WriteNewsrc();
  205. X
  206. X    if (blk_cnt >= max_blks)
  207. X    {
  208. X        fprintf (stderr,
  209. X            "%s: block count exceeded; some articles not packed\n",
  210. X            progname);
  211. X    }
  212. X
  213. X    /* Remove reply packet */
  214. X    if ( (!read_only) && (strcmp (rep_file, DEF_REP_FILE)))
  215. X    {
  216. X        unlink (rep_file);
  217. X    }
  218. X}
  219. X
  220. XWriteControl()
  221. X/*
  222. X *  Create the CONTROL.DAT file
  223. X */
  224. X{
  225. X    struct conf_ent *cp;
  226. X    struct tm *t;
  227. X    char ctl_fname[PATH_LEN];
  228. X    int clock;
  229. X
  230. X    strcpy (ctl_fname, home_dir);
  231. X    strcpy (ctl_fname, "/");
  232. X    strcpy (ctl_fname, "control.dat");
  233. X
  234. X    if (NULL == (ctl_fd = fopen (ctl_fname, "w")))
  235. X    {
  236. X        fprintf (stderr, "%s: can't open %s\n", progname, ctl_fname);
  237. X        exit (0);
  238. X    }
  239. X
  240. X    fprintf (ctl_fd, "%s\r\n%s\r\n%s\r\n%s\r\n%s\r\n",
  241. X        bbs_name, bbs_city, bbs_phone, bbs_sysop, bbs_id);
  242. X
  243. X    /* Date */
  244. X    clock = time (NULL);
  245. X    t = gmtime (&clock);
  246. X    fprintf (ctl_fd, "%02d\-%02d\-%04d,%02d\:%02d\:%02d\r\n",
  247. X        t->tm_mon+1, t->tm_mday, t->tm_year+1900,
  248. X        t->tm_hour, t->tm_min, t->tm_sec);
  249. X
  250. X    fprintf (ctl_fd, "%s\r\n \r\n0\r\n", user_name);
  251. X    fprintf (ctl_fd, "%d\r\n%d\r\n", msg_cnt, conf_cnt-1);
  252. X
  253. X    /* List of conferences */
  254. X    cp = conf_list;
  255. X    while (cp != NULL)
  256. X    {
  257. X        fprintf (ctl_fd, "%d\r\n%s\r\n", cp->number, cp->name);
  258. X        cp = cp->next;
  259. X    }
  260. X
  261. X    fprintf (ctl_fd, "WELCOME.DAT\r\nNEWS.DAT\r\nLOGOFF.DAT\r\n");
  262. X    fprintf (ctl_fd, "\032");
  263. X    fclose (ctl_fd);
  264. X}
  265. X
  266. XWriteNewsrc()
  267. X/*
  268. X *  Rewrite the updated .newsrc file
  269. X */
  270. X{
  271. X    if (read_only) return (0);
  272. X
  273. X    if (NULL == (nrc_fd = fopen (nrc_file, "w")))
  274. X    {
  275. X        fprintf (stderr, "%s: can't write %s\n",
  276. X            progname, nrc_file);
  277. X        return (0);
  278. X    }
  279. X
  280. X    /* We do this recursively to preserve the order of the .newsrc */
  281. X    wn (nrc_list);
  282. X
  283. X    fclose (nrc_fd);
  284. X}
  285. X
  286. Xwn (np)
  287. Xstruct nrc_ent *np;
  288. X{
  289. X    if (np == NULL) return (0);
  290. X
  291. X    /* Write the rest of them */
  292. X    wn (np->next);
  293. X
  294. X    /* Write this one */
  295. X    if (np->subscribed)
  296. X    {
  297. X        fprintf (nrc_fd, "%s: 1-%d\n", np->name, np->hi);
  298. X    }
  299. X    else
  300. X    {
  301. X        fprintf (nrc_fd, "%s! 1-%d\n", np->name, np->hi);
  302. X    }
  303. X}
  304. X
  305. END_OF_FILE
  306.   if test 2070 -ne `wc -c <'close.c'`; then
  307.     echo shar: \"'close.c'\" unpacked with wrong size!
  308.   fi
  309.   # end of 'close.c'
  310. fi
  311. if test -f 'init.c' -a "${1}" != "-c" ; then 
  312.   echo shar: Will not clobber existing file \"'init.c'\"
  313. else
  314.   echo shar: Extracting \"'init.c'\" \(832 characters\)
  315.   sed "s/^X//" >'init.c' <<'END_OF_FILE'
  316. X#include <stdio.h>
  317. X#include <string.h>
  318. X#include "uqwk.h"
  319. X
  320. X#define QWK_MAGIC "Produced by Qmail...Copyright (c) 1987 by Sparkware.  All rights Reserved"
  321. X
  322. XInitStuff()
  323. X/*
  324. X *  Initialize stuff
  325. X */
  326. X{
  327. X    char msg_fname[PATH_LEN];
  328. X    int n;
  329. X
  330. X    /* Mail, conference, etc. lists */
  331. X    mail_list = NULL;
  332. X    conf_list = NULL;
  333. X    last_conf = NULL;
  334. X    act_list = NULL;
  335. X    nrc_list = NULL;
  336. X
  337. X    /* Message and conference counts */
  338. X    msg_cnt = 0;
  339. X    conf_cnt = 0;
  340. X
  341. X    /* Open MESSAGES.DAT */
  342. X    strcpy (msg_fname, home_dir);
  343. X    strcat (msg_fname, "/");
  344. X    strcat (msg_fname, "messages.dat");
  345. X
  346. X    if (NULL == (msg_fd = fopen (msg_fname, "w")))
  347. X    {
  348. X        fprintf (stderr, "%s: can't open %s\n", progname, msg_fname);
  349. X        exit (0);
  350. X    }
  351. X
  352. X    /* Write magic string to MESSAGES.DAT */
  353. X    fprintf (msg_fd, QWK_MAGIC);
  354. X    n = 128 - strlen (QWK_MAGIC);
  355. X    while (n--) fputc (' ', msg_fd);
  356. X    blk_cnt = 2;
  357. X}
  358. END_OF_FILE
  359.   if test 832 -ne `wc -c <'init.c'`; then
  360.     echo shar: \"'init.c'\" unpacked with wrong size!
  361.   fi
  362.   # end of 'init.c'
  363. fi
  364. if test -f 'mail.c' -a "${1}" != "-c" ; then 
  365.   echo shar: Will not clobber existing file \"'mail.c'\"
  366. else
  367.   echo shar: Extracting \"'mail.c'\" \(4079 characters\)
  368.   sed "s/^X//" >'mail.c' <<'END_OF_FILE'
  369. X#include <stdio.h>
  370. X#include "uqwk.h"
  371. X
  372. X/*
  373. X *  All sorts of stuff to do mail processing
  374. X */
  375. X
  376. XFILE *mail_fd;            /* For mail spool */
  377. Xstruct mail_ent *last_mp;    /* Points to last mail list entry */
  378. X
  379. XDoMail ()
  380. X/*
  381. X *  Process mail into QWK packet
  382. X */
  383. X{
  384. X    struct mail_ent *mailp;
  385. X
  386. X    /* Open the mail spool */
  387. X    if (NULL == (mail_fd = fopen (mail_file, "r")))
  388. X    {
  389. X        fprintf (stderr, "%s: can't open %s\n", progname, mail_file);
  390. X        perror (progname);
  391. X        return (0);
  392. X    }
  393. X
  394. X    /* Define the mail "conference" */
  395. X    NewConference (MAIL_CONF_NAME);
  396. X
  397. X    /* Construct the mail linked list */
  398. X    MakeMailList ();
  399. X
  400. X    /* Walk through all the messages */
  401. X    mailp = mail_list;
  402. X
  403. X    while (mailp != NULL)
  404. X    {
  405. X        DoMessage (mailp);
  406. X        mailp = mailp->next;
  407. X    }
  408. X
  409. X    fclose (mail_fd);
  410. X    fclose (ndx_fd);
  411. X
  412. X    /* Now empty the mail box */
  413. X    if (!read_only)
  414. X    {
  415. X        if (NULL == (mail_fd = fopen (mail_file, "w")))
  416. X        {
  417. X            fprintf (stderr, "%s: can't write %s\n", progname,
  418. X                                mail_file);
  419. X        }
  420. X        else
  421. X        {
  422. X            fclose (mail_fd);
  423. X        }
  424. X    }
  425. X}
  426. X
  427. XMakeMailList ()
  428. X/*
  429. X *  Construct linked list of pointers to individual messages in
  430. X *  the mail spool.
  431. X */
  432. X{
  433. X    long offset;
  434. X
  435. X    last_mp = NULL;
  436. X
  437. X    /* Read through, looking for "From" lines */
  438. X    offset = ftell (mail_fd);
  439. X    while (NULL != Fgets (buf, BUF_LEN, mail_fd))
  440. X    {
  441. X        if (!strncmp (buf, "From ",  5))
  442. X        {
  443. X            DoFromLine (offset);
  444. X        }
  445. X        offset = ftell (mail_fd);
  446. X    }
  447. X    if (last_mp != NULL) last_mp->end = offset;
  448. X}
  449. X
  450. XDoFromLine (offset)
  451. Xlong offset;
  452. X{
  453. X    struct mail_ent *mp;
  454. X
  455. X    /* Get space for new mail list entry */
  456. X    if (NULL==(mp=(struct mail_ent *) malloc(sizeof(struct mail_ent))))
  457. X    {
  458. X        fprintf (stderr, "%s: out of memory\n", progname);
  459. X        exit (0);
  460. X    }
  461. X
  462. X    /* Fill in offset */
  463. X    mp->begin = offset;
  464. X
  465. X    if (last_mp == NULL)
  466. X    {
  467. X        /* This is first message */
  468. X        mail_list = mp;
  469. X    }
  470. X    else
  471. X    {
  472. X        /* Add to end of list */
  473. X        last_mp->next = mp;
  474. X        last_mp->end = offset;
  475. X    }
  476. X
  477. X    mp->next = NULL;
  478. X    last_mp = mp;
  479. X}
  480. X
  481. XDoMessage (mp)
  482. Xstruct mail_ent *mp;
  483. X/*
  484. X *  Convert a message to QWK format
  485. X */
  486. X{
  487. X    struct qwk_hdr hdr;
  488. X    char c[PATH_LEN], *eof, ndx[5];
  489. X    int out_bytes, n;
  490. X
  491. X    /* Write the ndx file entry */
  492. X    inttoms (blk_cnt, ndx);
  493. X    ndx[4] = conf_cnt-1;
  494. X    fwrite (ndx, 5, 1, ndx_fd);
  495. X
  496. X    Spaces (&hdr, 128);
  497. X
  498. X    /* Fill in the header fields we can do now */
  499. X    hdr.status = QWK_PRIVATE;
  500. X    PadNum (msg_cnt, hdr.number, 7);
  501. X    Spaces (hdr.password, 12);
  502. X    Spaces (hdr.refer, 8);
  503. X    hdr.flag = QWK_ACT_FLAG;
  504. X    IntNum (conf_cnt-1, hdr.conference);
  505. X    IntNum (msg_cnt+1, hdr.msg_num);
  506. X    hdr.tag = ' ';
  507. X
  508. X    msg_cnt++;
  509. X
  510. X    /* Seek to start of message */
  511. X    fseek (mail_fd, mp->begin, 0);
  512. X
  513. X    /* Read the From line */
  514. X    Fgets (buf, BUF_LEN, mail_fd);
  515. X
  516. X    /* The second field of the From line is assumed to be who
  517. X       sent the message */
  518. X    sscanf (&buf[5], "%s", c);
  519. X    PadString (c, hdr.from, 25);
  520. X
  521. X    /* Now read through header lines, looking for ones we need */
  522. X    eof = Fgets (buf, BUF_LEN, mail_fd);
  523. X    while ( (0 != strlen(buf)) && (eof != NULL) )
  524. X    {
  525. X        if (!strncmp (buf, "Date: ", 6))
  526. X        {
  527. X            ParseDate (&buf[6], &hdr);
  528. X        }
  529. X        else if (!strncmp (buf, "To: ", 4))
  530. X        {
  531. X            PadString (&buf[4], hdr.to, 25);
  532. X        }
  533. X        else if (!strncmp (buf, "Subject: ", 9))
  534. X        {
  535. X            PadString (&buf[9], hdr.subject, 25);
  536. X        }
  537. X/*
  538. X        else if (!strncmp (buf, "From: ", 6))
  539. X        {
  540. X            PadString (&buf[6], hdr.from, 25);
  541. X        }
  542. X*/
  543. X
  544. X        eof = Fgets (buf, BUF_LEN, mail_fd);
  545. X    }
  546. X    mp->text = ftell (mail_fd);
  547. X
  548. X    /* Fill in block count */
  549. X    if (inc_hdrs)
  550. X    {
  551. X        PadNum (2+(mp->end-mp->begin)/128, hdr.blocks, 6);
  552. X        blk_cnt += (1+(mp->end - mp->begin)/128);
  553. X    }
  554. X    else
  555. X    {
  556. X        PadNum (2+(mp->end-mp->text)/128, hdr.blocks, 6);
  557. X        blk_cnt += (1+(mp->end - mp->text)/128);
  558. X    }
  559. X
  560. X    /* Write out the message header */
  561. X    fwrite (&hdr, 128, 1, msg_fd);
  562. X    blk_cnt++;
  563. X
  564. X    /* Now write the message text */
  565. X    if (inc_hdrs) fseek (mail_fd, mp->begin, 0);
  566. X    out_bytes = 0;
  567. X
  568. X    eof = Fgets (buf, BUF_LEN, mail_fd);
  569. X    do
  570. X    {
  571. X        n = strlen (buf);
  572. X        fwrite (buf, n, 1, msg_fd);
  573. X        out_bytes += n;
  574. X        if (n < BUF_LEN-1)
  575. X        {
  576. X            fputc (QWK_EOL, msg_fd);
  577. X            out_bytes++;
  578. X        }
  579. X        eof = Fgets (buf, BUF_LEN, mail_fd);
  580. X    } while ( (strncmp(buf,"From ", 5)) && (NULL != eof) );
  581. X
  582. X    /* Pad block as necessary */
  583. X    n = out_bytes % 128;
  584. X    for (;n<128;n++) fputc (' ', msg_fd);
  585. X}
  586. X
  587. END_OF_FILE
  588.   if test 4079 -ne `wc -c <'mail.c'`; then
  589.     echo shar: \"'mail.c'\" unpacked with wrong size!
  590.   fi
  591.   # end of 'mail.c'
  592. fi
  593. if test -f 'misc.c' -a "${1}" != "-c" ; then 
  594.   echo shar: Will not clobber existing file \"'misc.c'\"
  595. else
  596.   echo shar: Extracting \"'misc.c'\" \(4685 characters\)
  597.   sed "s/^X//" >'misc.c' <<'END_OF_FILE'
  598. X#include <stdio.h>
  599. X#include <string.h>
  600. X#include "uqwk.h"
  601. X
  602. X/*
  603. X *  Miscellaneous uqwk routines
  604. X */
  605. X
  606. XNewConference (name)
  607. Xchar *name;
  608. X{
  609. X    struct conf_ent *cp, *tmp_cp;
  610. X    char *c, ndx_fname[PATH_LEN];
  611. X
  612. X    /* Get space for new conference */
  613. X    if (NULL == (tmp_cp = (struct conf_ent *) malloc
  614. X                    (sizeof (struct conf_ent))))
  615. X    {
  616. X        fprintf (stderr, "%s: out of memory\n", progname);
  617. X        exit (0);
  618. X    }
  619. X
  620. X    /* Get space for name */
  621. X    if (NULL == (c = (char *) malloc (1+strlen(name))))
  622. X    {
  623. X        fprintf (stderr, "%s: out of memory\n", progname);
  624. X        exit (0);
  625. X    }
  626. X
  627. X    /* Fill in conference name */
  628. X    tmp_cp->name = c;
  629. X    strcpy (tmp_cp->name, name);
  630. X
  631. X    /* Fill in conference number */
  632. X    tmp_cp->number = conf_cnt;
  633. X
  634. X    /* Add to end of conference list */
  635. X    if (last_conf == NULL)
  636. X    {
  637. X        /* This is first conference */
  638. X        conf_list = tmp_cp;
  639. X    }
  640. X    else
  641. X    {
  642. X        last_conf->next = tmp_cp;
  643. X    }
  644. X    tmp_cp->next = NULL;
  645. X    last_conf = tmp_cp;
  646. X
  647. X    /* Open new index file */
  648. X    if (!strcmp (name, MAIL_CONF_NAME))
  649. X    {
  650. X        strcpy (ndx_fname, home_dir);
  651. X        strcat (ndx_fname, "/");
  652. X        strcat (ndx_fname, "personal.ndx");
  653. X    }
  654. X    else
  655. X    {
  656. X        sprintf (ndx_fname, "%s/%03d.ndx", home_dir, conf_cnt);
  657. X    }
  658. X
  659. X    if (NULL == (ndx_fd = fopen (ndx_fname, "w")))
  660. X    {
  661. X        fprintf (stderr, "%s: can't open %s\n", progname, ndx_fname);
  662. X        exit (0);
  663. X    }
  664. X
  665. X    conf_cnt++;
  666. X}
  667. X
  668. XPadString (s, c, n)
  669. Xchar *s, *c;
  670. Xint n;
  671. X/*
  672. X *  Take a null-terminated string s and copy it, space-padded or
  673. X *  truncated if necessary, into field c of n characters
  674. X */
  675. X{
  676. X    int len, i;
  677. X    len = strlen (s);
  678. X    if (len >= n)
  679. X    {
  680. X        strncpy (c, s, n);
  681. X    }
  682. X    else
  683. X    {
  684. X        strcpy (c, s);
  685. X        Spaces (&c[len], n-len);
  686. X    }
  687. X}
  688. X
  689. XSpaces (c, n)
  690. Xchar *c;
  691. Xint n;
  692. X/*
  693. X *  Fill field of n characters with spaces
  694. X */
  695. X{
  696. X    int i;
  697. X    for (i=0; i<n; i++) c[i]=' ';
  698. X}
  699. X
  700. XPadNum (i, c, n)
  701. Xint i, n;
  702. Xchar *c;
  703. X/*
  704. X *  Format an integer i and place it, space filled, in
  705. X *  field c of n characters
  706. X */
  707. X{
  708. X    sprintf (buf, "%d", i);
  709. X    PadString (buf, c, n);
  710. X}
  711. X
  712. XIntNum (i, c)
  713. Xint i;
  714. Xchar c[2];
  715. X/*
  716. X *  Put binary integer i into two bytes
  717. X */
  718. X{
  719. X    c[0] = i % 256;
  720. X    c[1] = (i / 256) % 256;
  721. X}
  722. X
  723. Xchar *Fgets (c, n, fd)
  724. Xchar *c;
  725. Xint n;
  726. XFILE *fd;
  727. X/*
  728. X *  Same as fgets, but changes trailing linefeed to a null
  729. X */
  730. X{
  731. X    int i;
  732. X
  733. X    if (NULL == fgets (c, n, fd)) return (NULL);
  734. X    i = strlen (c);
  735. X    if ( (i > 0) && (c[i-1]=='\n') ) c[i-1] = 0;
  736. X
  737. X    return (c);
  738. X}
  739. X
  740. Xinttoms (i, c)
  741. Xint i;
  742. Xchar c[4];
  743. X/*
  744. X *  Convert an integer into the Microsoft Basic floating format.
  745. X *  This is the dumbest thing in the whole QWK standard.  Why in
  746. X *  the world store block offsets as floating point numbers?
  747. X *  Stupid!
  748. X */
  749. X{
  750. X    int m, e;
  751. X
  752. X    if (i == 0)
  753. X    {
  754. X        c[0] = c[1] = c[2] = 0;
  755. X        c[3] = 0x80;
  756. X        return;
  757. X    }
  758. X
  759. X    e = 152;
  760. X    m = 0x7fffff & i;
  761. X
  762. X    while (!(0x800000 & m))
  763. X    {
  764. X        m <<= 1;
  765. X        e--;
  766. X    }
  767. X    c[0] = 0xff & m;
  768. X    c[1] = 0xff & (m >> 8);
  769. X    c[2] = 0x7f & (m >> 16);
  770. X    c[3] = 0xff & e;
  771. X}
  772. X
  773. Xint LastInt (line)
  774. Xchar *line;
  775. X/*
  776. X * Find last integer on line
  777. X */
  778. X{
  779. X        int i, last_delim, n;
  780. X        n = strlen (line);
  781. X
  782. X        /* Find last delimiter */
  783. X        for (i=0; i<n; i++)
  784. X        {
  785. X                if ( (line[i] == ' ') || (line[i] == '-') ||
  786. X                     (line[i] == ',') || (line[i] == ':') )
  787. X                        last_delim = i;
  788. X        }
  789. X
  790. X        i = atoi (&line[last_delim+1]);
  791. X        return (i);
  792. X}
  793. X
  794. XParseDate (c, hp)
  795. Xchar *c;
  796. Xstruct qwk_hdr *hp;
  797. X{
  798. X        char s[PATH_LEN];
  799. X        int day, mon, year, hour, minute;
  800. X        char month[4];
  801. X
  802. X        /* Dates come in two flavors:  with the weekday, and without.
  803. X           we simply look for the comma which follows the weekday */
  804. X        if (c[3] == ',')
  805. X        {
  806. X                sscanf (&c[4], "%d %s %d %d:%d", &day, month, &year,
  807. X                                                &hour, &minute);
  808. X        }
  809. X        else
  810. X        {
  811. X                sscanf (c, "%d %s %d %d:%d", &day, month, &year,
  812. X                                                &hour, &minute);
  813. X        }
  814. X
  815. X        /* Convert alphabetic month name to integer */
  816. X        if (!strncmp (month, "Jan", 3)) mon = 1;
  817. X        if (!strncmp (month, "Feb", 3)) mon = 2;
  818. X        if (!strncmp (month, "Mar", 3)) mon = 3;
  819. X        if (!strncmp (month, "Apr", 3)) mon = 4;
  820. X        if (!strncmp (month, "May", 3)) mon = 5;
  821. X        if (!strncmp (month, "Jun", 3)) mon = 6;
  822. X        if (!strncmp (month, "Jul", 3)) mon = 7;
  823. X        if (!strncmp (month, "Aug", 3)) mon = 8;
  824. X        if (!strncmp (month, "Sep", 3)) mon = 9;
  825. X        if (!strncmp (month, "Oct", 3)) mon = 10;
  826. X        if (!strncmp (month, "Nov", 3)) mon = 11;
  827. X        if (!strncmp (month, "Dec", 3)) mon = 12;
  828. X
  829. X        /* Convert date */
  830. X        sprintf (s, "%02d-%02d-%02d", mon, day, year);
  831. X        PadString (s, hp->date, 8);
  832. X
  833. X        /* Time */
  834. X        sprintf (s, "%02d:%02d", hour, minute);
  835. X        PadString (s, hp->time, 5);
  836. X}
  837. X
  838. END_OF_FILE
  839.   if test 4685 -ne `wc -c <'misc.c'`; then
  840.     echo shar: \"'misc.c'\" unpacked with wrong size!
  841.   fi
  842.   # end of 'misc.c'
  843. fi
  844. if test -f 'news.c' -a "${1}" != "-c" ; then 
  845.   echo shar: Will not clobber existing file \"'news.c'\"
  846. else
  847.   echo shar: Extracting \"'news.c'\" \(6294 characters\)
  848.   sed "s/^X//" >'news.c' <<'END_OF_FILE'
  849. X#include <stdio.h>
  850. X#include <sys/types.h>
  851. X#include <sys/stat.h>
  852. X#include <string.h>
  853. X#include "uqwk.h"
  854. X/*
  855. X *  All sorts of stuff to do news processing
  856. X */
  857. X
  858. XDoNews ()
  859. X/*
  860. X *  Collect unread news into QWK packet
  861. X */
  862. X{
  863. X    struct act_ent *ap;
  864. X    struct nrc_ent *np;
  865. X
  866. X    /* Read .newsrc file */
  867. X    if (!ReadNewsrc()) return (0);
  868. X
  869. X    /* And active file */
  870. X    if (!ReadActive()) return (0);
  871. X
  872. X    /* Look through the newsrc file */
  873. X    np = nrc_list;
  874. X    while (np != NULL)
  875. X    {
  876. X        /* Check if too many blocks already */
  877. X        if ( (blk_cnt >= max_blks) && (max_blks > 0) )
  878. X        {
  879. X            return (0);
  880. X        }
  881. X
  882. X        if ( (np->subscribed) &&
  883. X             (NULL != (ap = FindActive (np->name))) )
  884. X        {
  885. X            /* Do this group */
  886. X            DoGroup (np, ap);
  887. X        }
  888. X        np = np->next;
  889. X    }
  890. X}
  891. X
  892. Xint ReadNewsrc()
  893. X/*
  894. X *  Read the .newsrc file
  895. X */
  896. X{
  897. X    char group_name[PATH_LEN];
  898. X    struct nrc_ent *np;
  899. X    int n, c;
  900. X
  901. X    /* Don't bother if we've alread read it */
  902. X    if (nrc_list != NULL) return (1);
  903. X
  904. X    /* Open it */
  905. X    if (NULL == (nrc_fd = fopen (nrc_file, "r")))
  906. X    {
  907. X        fprintf (stderr, "%s: can't open %s\n", progname, nrc_file);
  908. X        return (0);
  909. X    }
  910. X
  911. X    /* Read through */
  912. X    while (NULL != Fgets (buf, BUF_LEN, nrc_fd))
  913. X    {
  914. X        /* Allocate a new nrc entry */
  915. X        np = (struct nrc_ent *) malloc (sizeof (struct nrc_ent));
  916. X        if (np == NULL) OutOfMemory();
  917. X
  918. X        /* Parse group name */
  919. X        sscanf (buf, "%s", group_name);
  920. X        n = strlen (group_name);
  921. X
  922. X        if (group_name[n-1] == ':')
  923. X        {
  924. X            np->subscribed = 1;
  925. X        }
  926. X        else
  927. X        {
  928. X            np->subscribed = 0;
  929. X        }
  930. X
  931. X        group_name[n-1] = 0;
  932. X        np->name = (char *) malloc (n);
  933. X        if (np->name == NULL) OutOfMemory();
  934. X        strcpy (np->name, group_name);
  935. X
  936. X        /* Hi article number */
  937. X        np->hi = LastInt (buf);
  938. X
  939. X        /* Add to nrc list */
  940. X        np->next = nrc_list;
  941. X        nrc_list = np;
  942. X    }
  943. X
  944. X    /* Walk through the nrc list, assign conference numbers */
  945. X    np = nrc_list;
  946. X    c = 0;
  947. X    while (np != NULL)
  948. X    {
  949. X        np->conf = c;
  950. X        c++;
  951. X        np = np->next;
  952. X    }
  953. X
  954. X    fclose (nrc_fd);
  955. X    return (1);
  956. X}
  957. X
  958. Xint ReadActive()
  959. X/*
  960. X *  Read active file
  961. X */
  962. X{
  963. X    char group_name[PATH_LEN];
  964. X    struct act_ent *ap;
  965. X    int n;
  966. X
  967. X    /* Don't bother if it's already here */
  968. X    if (act_list != NULL) return (1);
  969. X
  970. X    /* Open the active file */
  971. X    if (NULL == (act_fd = fopen (act_file, "r")))
  972. X    {
  973. X        fprintf (stderr, "%s: can't open %s\n", progname, act_file);
  974. X        return (0);
  975. X    }
  976. X
  977. X    /* Read through it */
  978. X    while (NULL != Fgets (buf, BUF_LEN, act_fd))
  979. X    {
  980. X        /* Get new act entry */
  981. X        ap = (struct act_ent *) malloc (sizeof (struct act_ent));
  982. X        if (ap == NULL) OutOfMemory();
  983. X
  984. X        /* Parse name, message numbers */
  985. X        sscanf (buf, "%s %d %d", group_name, &ap->hi, &ap->lo);
  986. X        ap->name = (char *) malloc (1+strlen(group_name));
  987. X        if (ap->name == NULL) OutOfMemory();
  988. X        strcpy (ap->name, group_name);
  989. X
  990. X        /* Add to list */
  991. X        ap->next = act_list;
  992. X        act_list = ap;
  993. X    }
  994. X
  995. X    fclose (act_fd);
  996. X    return (1);
  997. X}
  998. X
  999. Xstruct act_ent *FindActive (c)
  1000. Xchar *c;
  1001. X/*
  1002. X *  Look for group's active entry given group name
  1003. X */
  1004. X{
  1005. X    struct act_ent *ap;
  1006. X
  1007. X    ap = act_list;
  1008. X    while (NULL != ap)
  1009. X    {
  1010. X        if (!strcmp (c, ap->name)) return (ap);
  1011. X        ap = ap->next;
  1012. X    }
  1013. X    return (NULL);
  1014. X}
  1015. X
  1016. XDoGroup (np, ap)
  1017. Xstruct nrc_ent *np;
  1018. Xstruct act_ent *ap;
  1019. X/*
  1020. X *  Process given group
  1021. X */
  1022. X{
  1023. X    char news_path[PATH_LEN];
  1024. X    char art_file[PATH_LEN];
  1025. X    int i, n;
  1026. X
  1027. X    printf ("%s: %s\n", progname, np->name);
  1028. X
  1029. X    /* Make a new conference with this name */
  1030. X    NewConference (np->name);
  1031. X
  1032. X    /* Construct path name for articles in this group */
  1033. X    strcpy (news_path, news_dir);
  1034. X    strcat (news_path, "/");
  1035. X    strcat (news_path, np->name);
  1036. X    strcat (news_path, "/");
  1037. X    n = strlen (news_path);
  1038. X    for (i=0; i<n; i++) if (news_path[i] == '.') news_path[i] = '/';
  1039. X
  1040. X    /* If highest read article is greater than highest available
  1041. X       article, assume group has been reset */
  1042. X    if (np->hi > ap->hi) np->hi = ap->lo;
  1043. X
  1044. X    /* Look through unread articles */
  1045. X    for (i=np->hi+1; i<=ap->hi; i++)
  1046. X    {
  1047. X        /* Check max block count */
  1048. X        if ( (blk_cnt >= max_blks) && (max_blks > 0) )
  1049. X        {
  1050. X            fclose (ndx_fd);
  1051. X            np->hi = i;
  1052. X            return (0);
  1053. X        }
  1054. X
  1055. X        /* Construct article's file name */
  1056. X        sprintf (art_file, "%s%d", news_path, i);
  1057. X
  1058. X        /* Process this article */
  1059. X        DoArticle (art_file);
  1060. X    }
  1061. X    fclose (ndx_fd);
  1062. X
  1063. X    /* Reset hi article number */
  1064. X    np->hi = ap->hi;
  1065. X}
  1066. X
  1067. XDoArticle (art_file)
  1068. Xchar *art_file;
  1069. X{
  1070. X    struct qwk_hdr hdr;
  1071. X    struct stat stat_buf;
  1072. X    long txt_offset, end_offset;
  1073. X    int n, out_bytes;
  1074. X    char ndx[5], *eof, from[PATH_LEN];
  1075. X    FILE *art_fd;
  1076. X
  1077. X    /* Forget it if we can't open the article */
  1078. X    if (NULL == (art_fd = fopen (art_file, "r"))) return (0);
  1079. X
  1080. X    /* stat() the article to get file size */
  1081. X    if (0 != stat (art_file, &stat_buf))
  1082. X    {
  1083. X        fclose (art_fd);
  1084. X        return (0);
  1085. X    }
  1086. X    end_offset = stat_buf.st_size;
  1087. X
  1088. X    /* Skip empty articles */
  1089. X    if (end_offset == 0)
  1090. X    {
  1091. X        fclose (art_fd);
  1092. X        return (0);
  1093. X    }
  1094. X
  1095. X    /* Write the index file entry */
  1096. X    inttoms (blk_cnt, ndx);
  1097. X    ndx[4] = conf_cnt - 1;
  1098. X    fwrite (ndx, 5, 1, ndx_fd);
  1099. X
  1100. X    Spaces (&hdr, 128);
  1101. X
  1102. X    /* Fill in some header fields */
  1103. X    hdr.status = QWK_PUBLIC;
  1104. X    PadNum (msg_cnt, hdr.number, 7);
  1105. X    Spaces (hdr.password, 12);
  1106. X    Spaces (hdr.refer, 8);
  1107. X    hdr.flag = QWK_ACT_FLAG;
  1108. X    IntNum (conf_cnt-1, hdr.conference);
  1109. X    IntNum (msg_cnt+1, hdr.msg_num);
  1110. X    hdr.tag = ' ';
  1111. X    PadString ("ALL", hdr.to, 25);
  1112. X
  1113. X    msg_cnt++;
  1114. X
  1115. X    /* Process header lines */
  1116. X    eof = Fgets (buf, BUF_LEN, art_fd);
  1117. X    while ( (0 != strlen(buf)) && (eof != NULL) )
  1118. X    {
  1119. X        if (!strncmp (buf, "Date: ", 6))
  1120. X        {
  1121. X            ParseDate (&buf[6], &hdr);
  1122. X        }
  1123. X        else if (!strncmp (buf, "Subject: ", 9))
  1124. X        {
  1125. X            PadString (&buf[9], hdr.subject, 25);
  1126. X        }
  1127. X        else if (!strncmp (buf, "From: ", 6))
  1128. X        {
  1129. X            sscanf (&buf[6], "%s", from);
  1130. X            PadString (from, hdr.from, 25);
  1131. X        }
  1132. X
  1133. X        eof = Fgets (buf, BUF_LEN, art_fd);
  1134. X    }
  1135. X
  1136. X    txt_offset = ftell (art_fd);
  1137. X
  1138. X    /* Compute block count */
  1139. X    if (inc_hdrs)
  1140. X    {
  1141. X        PadNum (2+end_offset/128, hdr.blocks, 6);
  1142. X        blk_cnt += 1+end_offset/128;
  1143. X    }
  1144. X    else
  1145. X    {
  1146. X        PadNum (2+(end_offset-txt_offset)/128, hdr.blocks, 6);
  1147. X        blk_cnt += 1+(end_offset-txt_offset)/128;
  1148. X    }
  1149. X
  1150. X    /* Write the message header */
  1151. X    fwrite (&hdr, 128, 1, msg_fd);
  1152. X    blk_cnt++;
  1153. X
  1154. X    /* Now write the article's text */
  1155. X    if (inc_hdrs) fseek (art_fd, 0, 0);
  1156. X    out_bytes = 0;
  1157. X
  1158. X    while (NULL != Fgets (buf, BUF_LEN, art_fd))
  1159. X    {
  1160. X        n = strlen (buf);
  1161. X        fwrite (buf, n, 1, msg_fd);
  1162. X        out_bytes += n;
  1163. X
  1164. X        if (n < BUF_LEN-1)
  1165. X        {
  1166. X            fputc (QWK_EOL, msg_fd);
  1167. X            out_bytes++;
  1168. X        }
  1169. X    }
  1170. X
  1171. X    /* Pad block as necessary */
  1172. X    n = out_bytes % 128;
  1173. X    for (;n<128;n++) fputc (' ', msg_fd);
  1174. X
  1175. X    fclose (art_fd);
  1176. X}
  1177. X
  1178. XOutOfMemory()
  1179. X{
  1180. X    fprintf (stderr, "%s: out of memory\n", progname);
  1181. X    exit (0);
  1182. X}
  1183. END_OF_FILE
  1184.   if test 6294 -ne `wc -c <'news.c'`; then
  1185.     echo shar: \"'news.c'\" unpacked with wrong size!
  1186.   fi
  1187.   # end of 'news.c'
  1188. fi
  1189. if test -f 'offline.c' -a "${1}" != "-c" ; then 
  1190.   echo shar: Will not clobber existing file \"'offline.c'\"
  1191. else
  1192.   echo shar: Extracting \"'offline.c'\" \(5379 characters\)
  1193.   sed "s/^X//" >'offline.c' <<'END_OF_FILE'
  1194. X#include <stdio.h>
  1195. X#include <string.h>
  1196. X#include "uqwk.h"
  1197. X/*
  1198. X *  Process offline commands
  1199. X */
  1200. X
  1201. XOffLine (bytes)
  1202. Xint bytes;
  1203. X/*
  1204. X *  Process offline commands.  Message is open on rep_fd.  We
  1205. X *  must be careful to leave the file pointer ready for the
  1206. X *  next message.
  1207. X */
  1208. X{
  1209. X    FILE *pfd;
  1210. X    char c, cmd[PATH_LEN];
  1211. X
  1212. X    /* Open mail pipe to send results back to user */
  1213. X    sprintf (buf, "%s -s 'Results of your request' %s",
  1214. X            MAILER_PATH, user_name);
  1215. X    if (NULL == (pfd = popen (buf, "w")))
  1216. X    {
  1217. X        fprintf (stderr, "%s: can't popen() mail\n", progname);
  1218. X        while (bytes--) fread (&c, 1, 1, rep_fd);
  1219. X        return (0);
  1220. X    }
  1221. X
  1222. X    fprintf (pfd, "Here are the results of your mail to UQWK:\n");
  1223. X
  1224. X    /* Get lines, process them */
  1225. X    while (GetLine(&bytes))
  1226. X    {
  1227. X        /* Echo command */
  1228. X        fprintf (pfd, "\nCommand: %s\n", buf);
  1229. X
  1230. X        /* Extract command */
  1231. X        if (1 != sscanf (buf, "%s", cmd))
  1232. X        {
  1233. X            fprintf (pfd, "Malformed command.\n");
  1234. X        }
  1235. X        else
  1236. X        {
  1237. X            /* Look up command */
  1238. X            if ( (!strcmp (cmd, "help")) ||
  1239. X                 (!strcmp (cmd, "HELP")) )
  1240. X            {
  1241. X                Help(pfd);
  1242. X            }
  1243. X            else if ( (!strcmp (cmd, "subscribe")) ||
  1244. X                  (!strcmp (cmd, "SUBSCRIBE")) )
  1245. X            {
  1246. X                Subscribe(pfd);
  1247. X            }
  1248. X            else if ( (!strcmp (cmd, "unsubscribe")) ||
  1249. X                  (!strcmp (cmd, "UNSUBSCRIBE")) )
  1250. X            {
  1251. X                Unsubscribe(pfd);
  1252. X            }
  1253. X            else if ( (!strcmp (cmd, "groups")) ||
  1254. X                      (!strcmp (cmd, "GROUPS")) )
  1255. X            {
  1256. X                Groups(pfd);
  1257. X            }
  1258. X            else if ( (!strcmp (cmd, "allgroups")) ||
  1259. X                      (!strcmp (cmd, "ALLGROUPS")) )
  1260. X            {
  1261. X                Allgroups(pfd);
  1262. X            }
  1263. X            else
  1264. X            {
  1265. X                fprintf (pfd, "No such command.  ");
  1266. X                fprintf (pfd, "Send HELP for help.\n");
  1267. X            }
  1268. X        }
  1269. X    }
  1270. X
  1271. X    fprintf (pfd, "\nEnd of commands.\n");
  1272. X    pclose (pfd);
  1273. X}
  1274. X
  1275. Xint GetLine (bytes)
  1276. Xint *bytes;
  1277. X/*
  1278. X *  Get a line from rep_fd, put it in buf, check for end of message
  1279. X */
  1280. X{
  1281. X    int i;
  1282. X    i = 0;
  1283. X
  1284. X    /* Read bytes until EOL or end of message */
  1285. X    while (*bytes)
  1286. X    {
  1287. X        fread (&buf[i], 1, 1, rep_fd);
  1288. X        (*bytes)--;
  1289. X
  1290. X        if ( (buf[i] == QWK_EOL) || (i == BUF_LEN-1) )
  1291. X        {
  1292. X            buf[i] = 0;
  1293. X            return (1);
  1294. X        }
  1295. X        i++;
  1296. X    }
  1297. X
  1298. X    /* If we got here, we ran out of bytes */
  1299. X    return (0);
  1300. X}
  1301. X
  1302. XHelp (pfd)
  1303. XFILE *pfd;
  1304. X{
  1305. X    fprintf (pfd, "\nAvailable commands:\n\n");
  1306. X    fprintf (pfd, "HELP - This message.\n");
  1307. X    fprintf (pfd, "SUBSCRIBE newsgroup - Subscribe to named newsgroup.\n");
  1308. X    fprintf (pfd, "UNSUBSCRIBE newsgroup - Unsubscribe from newsgroup.\n");
  1309. X    fprintf (pfd, "UNSUBSCRIBE ALL - Unsubscribe from all newsgroups.\n");
  1310. X    fprintf (pfd, "GROUPS - List all subscribed newsgroups.\n");
  1311. X    fprintf (pfd, "ALLGROUPS - List all available newsgroups.\n\n");
  1312. X}
  1313. X
  1314. XSubscribe (pfd)
  1315. XFILE *pfd;
  1316. X{
  1317. X    struct act_ent *ap;
  1318. X    struct nrc_ent *np;
  1319. X    char group[PATH_LEN];
  1320. X
  1321. X    /* Extract group name */
  1322. X    if (1 != sscanf (buf, "%*s %s", group))
  1323. X    {
  1324. X        fprintf (pfd, "Usage: SUBSCRIBE newsgroup\n");
  1325. X        return (0);
  1326. X    }
  1327. X
  1328. X    /* We will need active file and .newsrc */
  1329. X    if (!ReadActive() || !ReadNewsrc())
  1330. X    {
  1331. X        fprintf (pfd, "Sorry, couldn't read system files.\n");
  1332. X        return (0);
  1333. X    }
  1334. X
  1335. X    /* Already subscribed? */
  1336. X    np = nrc_list;
  1337. X    while (np != NULL)
  1338. X    {
  1339. X        if (!strcmp (group, np->name))
  1340. X        {
  1341. X            if (np->subscribed)
  1342. X            {
  1343. X                fprintf (pfd, "Already subscribed to %s.\n",
  1344. X                    group);
  1345. X                return (0);
  1346. X            }
  1347. X            else
  1348. X            {
  1349. X                np->subscribed = 1;
  1350. X                fprintf (pfd, "Okay, re-subscribed to %s.\n",
  1351. X                    group);
  1352. X                WriteNewsrc();
  1353. X                return (0);
  1354. X            }
  1355. X        }
  1356. X        np = np->next;
  1357. X    }
  1358. X
  1359. X    /* Find group in active file */
  1360. X    if (NULL == (ap = FindActive (group)))
  1361. X    {
  1362. X        fprintf (pfd, "No such newsgroup: %s\n", group);
  1363. X        return (0);
  1364. X    }
  1365. X
  1366. X    /* Okay already, add to .newsrc */
  1367. X    np = (struct nrc_ent *) malloc (sizeof (struct nrc_ent));
  1368. X    if (np == NULL) OutOfMemory();
  1369. X    np->name = (char *) malloc (1+strlen(group));
  1370. X    if (np->name == NULL) OutOfMemory();
  1371. X    strcpy (np->name, group);
  1372. X    np->subscribed = 1;
  1373. X    np->hi = ap->hi;
  1374. X    np->next = nrc_list;
  1375. X    nrc_list = np;
  1376. X
  1377. X    WriteNewsrc();
  1378. X    fprintf (pfd, "Okay, you are now subscribed to %s.\n", group);
  1379. X}
  1380. X
  1381. XUnsubscribe (pfd)
  1382. XFILE *pfd;
  1383. X{
  1384. X    struct nrc_ent *np;
  1385. X    char group[PATH_LEN];
  1386. X
  1387. X    /* Parse group name */
  1388. X    if (1 != sscanf (buf, "%*s %s", group))
  1389. X    {
  1390. X        fprintf (pfd, "Usage: UNSUBSCRIBE newsgroup\n");
  1391. X        return (0);
  1392. X    }
  1393. X
  1394. X    /* Check for ALL */
  1395. X    if ( (!strcmp (group, "ALL")) || (!strcmp (group, "all")) )
  1396. X    {
  1397. X        nrc_list = NULL;
  1398. X        WriteNewsrc();
  1399. X        fprintf (pfd,
  1400. X          "Okay, you are now unsubscribed from all newsgroups.\n");
  1401. X        return (0);
  1402. X    }
  1403. X
  1404. X    /* We need the .newsrc file */
  1405. X    if (!ReadNewsrc())
  1406. X    {
  1407. X        fprintf (pfd, "Sorry, couldn't read .newsrc\n");
  1408. X        return (0);
  1409. X    }
  1410. X
  1411. X    /* Look for group in newsrc */
  1412. X    np = nrc_list;
  1413. X    while (np != NULL)
  1414. X    {
  1415. X        if (!strcmp (group, np->name)) break;
  1416. X        np = np->next;
  1417. X    }
  1418. X
  1419. X    if (np == NULL)
  1420. X    {
  1421. X        fprintf (pfd, "You are not currently subscribed to %s.\n",
  1422. X                 group);
  1423. X        return (0);
  1424. X    }
  1425. X
  1426. X    np->subscribed = 0;
  1427. X
  1428. X    WriteNewsrc();
  1429. X    fprintf (pfd, "Okay, you are unsubscribed from %s.\n", group);
  1430. X}
  1431. X
  1432. XGroups (pfd)
  1433. XFILE *pfd;
  1434. X{
  1435. X    struct nrc_ent *np;
  1436. X
  1437. X    if (!ReadNewsrc())
  1438. X    {
  1439. X        fprintf (pfd, "Sorry, couldn't read .newsrc\n");
  1440. X        return (0);
  1441. X    }
  1442. X
  1443. X    fprintf (pfd, "Newsgroups to which you are subscribed:\n\n");
  1444. X
  1445. X    np = nrc_list;
  1446. X    while (np != NULL)
  1447. X    {
  1448. X        fprintf (pfd, "    %s\n", np->name);
  1449. X        np = np->next;
  1450. X    }
  1451. X}
  1452. X
  1453. XAllgroups (pfd)
  1454. XFILE *pfd;
  1455. X{
  1456. X    struct act_ent *ap;
  1457. X
  1458. X    if (!ReadActive())
  1459. X    {
  1460. X        fprintf (pfd, "Sorry, no newsgroups are available.\n");
  1461. X        return (0);
  1462. X    }
  1463. X
  1464. X    fprintf (pfd, "List of available newsgroups:\n\n");
  1465. X
  1466. X    ap = act_list;
  1467. X    while (ap != NULL)
  1468. X    {
  1469. X        fprintf (pfd, "    %s (%d articles)\n",
  1470. X            ap->name, ap->hi - ap->lo);
  1471. X        ap = ap->next;
  1472. X    }
  1473. X}
  1474. END_OF_FILE
  1475.   if test 5379 -ne `wc -c <'offline.c'`; then
  1476.     echo shar: \"'offline.c'\" unpacked with wrong size!
  1477.   fi
  1478.   # end of 'offline.c'
  1479. fi
  1480. if test -f 'options.c' -a "${1}" != "-c" ; then 
  1481.   echo shar: Will not clobber existing file \"'options.c'\"
  1482. else
  1483.   echo shar: Extracting \"'options.c'\" \(5212 characters\)
  1484.   sed "s/^X//" >'options.c' <<'END_OF_FILE'
  1485. X#include <stdio.h>
  1486. X#include <sys/types.h>
  1487. X#include <pwd.h>
  1488. X#include <string.h>
  1489. X#include "uqwk.h"
  1490. X
  1491. X/*
  1492. X *  Determine runtime options
  1493. X */
  1494. X
  1495. XDefaultOptions()
  1496. X/*
  1497. X *  Set up default options
  1498. X */
  1499. X{
  1500. X    struct passwd *pw;
  1501. X
  1502. X    /* Do user-specific stuff*/
  1503. X    if (NULL == (pw = getpwuid(getuid())))
  1504. X    {
  1505. X        fprintf (stderr, "%s: warning: you don't exist\n", progname);
  1506. X        strcpy (user_name, DEF_USER_NAME);
  1507. X        strcpy (home_dir, DEF_HOME_DIR);
  1508. X    }
  1509. X    else
  1510. X    {
  1511. X        strcpy (user_name, pw->pw_name);
  1512. X        strcpy (home_dir, pw->pw_dir);
  1513. X    }
  1514. X
  1515. X    /* Dinky misc options */
  1516. X    do_mail = DEF_DO_MAIL;
  1517. X    do_news = DEF_DO_NEWS;
  1518. X    inc_hdrs = DEF_INC_HDRS;
  1519. X    prt_opts = DEF_PRT_OPTS;
  1520. X    read_only = DEF_READ_ONLY;
  1521. X    max_blks = DEF_MAX_BLKS;
  1522. X
  1523. X    strcpy (mail_dir, DEF_MAIL_DIR);
  1524. X    strcpy (mail_file, DEF_MAIL_FILE);
  1525. X    strcpy (act_file, DEF_ACT_FILE);
  1526. X    strcpy (nrc_file, DEF_NRC_FILE);
  1527. X    strcpy (news_dir, DEF_NEWS_DIR);
  1528. X
  1529. X    strcpy (bbs_name, DEF_BBS_NAME);
  1530. X    strcpy (bbs_city, DEF_BBS_CITY);
  1531. X    strcpy (bbs_phone, DEF_BBS_PHONE);
  1532. X    strcpy (bbs_sysop, DEF_BBS_SYSOP);
  1533. X    strcpy (bbs_id, DEF_BBS_ID);
  1534. X    strcpy (rep_file, DEF_REP_FILE);
  1535. X}
  1536. X
  1537. XEnvOptions()
  1538. X/*
  1539. X *  Override options from environment variables
  1540. X */
  1541. X{
  1542. X    char *c;
  1543. X
  1544. X    if (NULL != (c = getenv ("UQ_DO_MAIL"))) do_mail = atoi (c);
  1545. X    if (NULL != (c = getenv ("UQ_DO_NEWS"))) do_news = atoi (c);
  1546. X    if (NULL != (c = getenv ("UQ_INC_HDRS"))) inc_hdrs = atoi (c);
  1547. X    if (NULL != (c = getenv ("UQ_PRT_OPTS"))) prt_opts = atoi (c);
  1548. X    if (NULL != (c = getenv ("UQ_READ_ONLY"))) read_only = atoi (c);
  1549. X    if (NULL != (c = getenv ("UQ_MAX_BLKS"))) max_blks = atoi (c);
  1550. X
  1551. X    if (NULL != (c = getenv ("UQ_HOME_DIR"))) strcpy (home_dir, c);
  1552. X    if (NULL != (c = getenv ("UQ_MAIL_FILE"))) strcpy (mail_file, c);
  1553. X    if (NULL != (c = getenv ("UQ_MAIL_DIR"))) strcpy (mail_dir, c);
  1554. X    if (NULL != (c = getenv ("UQ_USER_NAME"))) strcpy (user_name, c);
  1555. X    if (NULL != (c = getenv ("UQ_NEWS_DIR"))) strcpy (news_dir, c);
  1556. X
  1557. X    if (NULL != (c = getenv ("UQ_BBS_NAME"))) strcpy (bbs_name, c);
  1558. X    if (NULL != (c = getenv ("UQ_BBS_CITY"))) strcpy (bbs_city, c);
  1559. X    if (NULL != (c = getenv ("UQ_BBS_PHONE"))) strcpy (bbs_phone, c);
  1560. X    if (NULL != (c = getenv ("UQ_BBS_SYSOP"))) strcpy (bbs_sysop, c);
  1561. X    if (NULL != (c = getenv ("UQ_BBS_ID"))) strcpy (bbs_id, c);
  1562. X
  1563. X    if (NULL != (c = getenv ("UQ_ACT_FILE"))) strcpy (act_file, c);
  1564. X    if (NULL != (c = getenv ("UQ_NRC_FILE"))) strcpy (nrc_file, c);
  1565. X
  1566. X    if (NULL != (c = getenv ("UQ_REP_FILE"))) strcpy (rep_file, c);
  1567. X}
  1568. X
  1569. XCommandOptions (argc, argv)
  1570. Xint argc;
  1571. Xchar *argv[];
  1572. X/*
  1573. X *  Override options from command line
  1574. X */
  1575. X{
  1576. X    int i;
  1577. X
  1578. X    for (i=1; i<argc; i++)
  1579. X    {
  1580. X        switch (argv[i][0])
  1581. X        {
  1582. X        case '+':
  1583. X            switch (argv[i][1])
  1584. X            {
  1585. X            case 'm':    do_mail = 1;
  1586. X                    break;
  1587. X
  1588. X            case 'n':    do_news = 1;
  1589. X                    break;
  1590. X
  1591. X            case 'h':    inc_hdrs = 1;
  1592. X                    break;
  1593. X
  1594. X            case 'r':    read_only = 1;
  1595. X                    break;
  1596. X
  1597. X            default:    BadFlag (argv[i]);
  1598. X                    break;
  1599. X            }
  1600. X            break;
  1601. X
  1602. X        case '-':
  1603. X            switch (argv[i][1])
  1604. X            {
  1605. X            case 'm':    do_mail = 0;
  1606. X                    break;
  1607. X
  1608. X            case 'n':    do_news = 0;
  1609. X                    break;
  1610. X
  1611. X            case 'h':    inc_hdrs = 0;
  1612. X                    break;
  1613. X
  1614. X            case 'r':    read_only = 0;
  1615. X                    break;
  1616. X
  1617. X            case 'p':    prt_opts = 1;
  1618. X                    break;
  1619. X
  1620. X            case 'M':    strcpy (mail_dir, &argv[i][2]);
  1621. X                    break;
  1622. X
  1623. X            case 'f':    strcpy (mail_file, &argv[i][2]);
  1624. X                    break;
  1625. X
  1626. X            case 'u':    strcpy (user_name, &argv[i][2]);
  1627. X                    break;
  1628. X
  1629. X            case 'H':    strcpy (home_dir, &argv[i][2]);
  1630. X                    break;
  1631. X
  1632. X            case 'b':    strcpy (bbs_name, &argv[i][2]);
  1633. X                    break;
  1634. X
  1635. X            case 'c':    strcpy (bbs_city, &argv[i][2]);
  1636. X                    break;
  1637. X
  1638. X            case 'P':    strcpy (bbs_phone, &argv[i][2]);
  1639. X                    break;
  1640. X
  1641. X            case 's':    strcpy (bbs_sysop, &argv[i][2]);
  1642. X                    break;
  1643. X
  1644. X            case 'i':    strcpy (bbs_id, &argv[i][2]);
  1645. X                    break;
  1646. X
  1647. X            case 'a':    strcpy (act_file, &argv[i][2]);
  1648. X                    break;
  1649. X
  1650. X            case 'N':    strcpy (nrc_file, &argv[i][2]);
  1651. X                    break;
  1652. X
  1653. X            case 'S':    strcpy (news_dir, &argv[i][2]);
  1654. X                    break;
  1655. X
  1656. X            case 'B':    max_blks = atoi (&argv[i][2]);
  1657. X                    break;
  1658. X
  1659. X            case 'R':    strcpy (rep_file, &argv[i][2]);
  1660. X                    break;
  1661. X
  1662. X            default:    BadFlag (argv[i]);
  1663. X                    break;
  1664. X            }
  1665. X            break;
  1666. X
  1667. X        default:
  1668. X            BadFlag (argv[i]);
  1669. X            break;
  1670. X        }
  1671. X    }
  1672. X
  1673. X    /* If mail file has not been overridden, set it */
  1674. X    if (!strcmp (mail_file, DEF_MAIL_FILE))
  1675. X    {
  1676. X        strcpy (mail_file, mail_dir);
  1677. X        strcat (mail_file, "/");
  1678. X        strcat (mail_file, user_name);
  1679. X    }
  1680. X
  1681. X    /* If .newsrc file has not been overridden, set it */
  1682. X    if (!strcmp (nrc_file, DEF_NRC_FILE))
  1683. X    {
  1684. X        strcpy (nrc_file, home_dir);
  1685. X        strcat (nrc_file, "/.newsrc");
  1686. X    }
  1687. X
  1688. X    if (prt_opts)
  1689. X    {
  1690. X        PrintOptions();
  1691. X        exit (0);
  1692. X    }
  1693. X}
  1694. X
  1695. XBadFlag (c)
  1696. Xchar *c;
  1697. X{
  1698. X    fprintf (stderr, "%s: bad flag: %s\n", progname, c);
  1699. X    exit (0);
  1700. X}
  1701. X
  1702. XPrintOptions ()
  1703. X{
  1704. X    printf ("Do mail: %d\n", do_mail);
  1705. X    printf ("Do news: %d\n", do_news);
  1706. X    printf ("Include headers: %d\n", inc_hdrs);
  1707. X    printf ("Read only: %d\n", read_only);
  1708. X    printf ("Maximum blocks: %d\n", max_blks);
  1709. X    printf ("Mail directory: %s\n", mail_dir);
  1710. X    printf ("News directory: %s\n", news_dir);
  1711. X    printf ("Mail file: %s\n", mail_file);
  1712. X    printf ("User name: %s\n", user_name);
  1713. X    printf ("Home directory: %s\n", home_dir);
  1714. X    printf ("BBS name: %s\n", bbs_name);
  1715. X    printf ("BBS city: %s\n", bbs_city);
  1716. X    printf ("BBS phone: %s\n", bbs_phone);
  1717. X    printf ("BBS sysop: %s\n", bbs_sysop);
  1718. X    printf ("BBS id: %s\n", bbs_id);
  1719. X    printf ("Active file: %s\n", act_file);
  1720. X    printf (".newsrc file: %s\n", nrc_file);
  1721. X    printf ("Reply file: %s\n", rep_file);
  1722. X}
  1723. END_OF_FILE
  1724.   if test 5212 -ne `wc -c <'options.c'`; then
  1725.     echo shar: \"'options.c'\" unpacked with wrong size!
  1726.   fi
  1727.   # end of 'options.c'
  1728. fi
  1729. if test -f 'reply.c' -a "${1}" != "-c" ; then 
  1730.   echo shar: Will not clobber existing file \"'reply.c'\"
  1731. else
  1732.   echo shar: Extracting \"'reply.c'\" \(5123 characters\)
  1733.   sed "s/^X//" >'reply.c' <<'END_OF_FILE'
  1734. X#include <stdio.h>
  1735. X#include <string.h>
  1736. X#include "uqwk.h"
  1737. X/*
  1738. X *  Process a reply packet
  1739. X */
  1740. X
  1741. XDoReply ()
  1742. X{
  1743. X    int n, rep_cnt;
  1744. X    char bbs[PATH_LEN];
  1745. X
  1746. X    rep_cnt = 0;
  1747. X
  1748. X    /* Open the packet */
  1749. X    if (NULL == (rep_fd = fopen (rep_file, "r")))
  1750. X    {
  1751. X        fprintf (stderr, "%s: can't open %s\n", progname, rep_file);
  1752. X        return (0);
  1753. X    }
  1754. X
  1755. X    /* Get the first block, the BBS ID */
  1756. X    if (1 != fread (buf, 128, 1, rep_fd))
  1757. X    {
  1758. X        fprintf (stderr, "%s: reply packet read error\n", progname);
  1759. X        fclose (rep_fd);
  1760. X        return (0);
  1761. X    }
  1762. X
  1763. X    /* Extract bbs id and check */
  1764. X    sscanf (bbs_id, "%*d,%s", bbs);
  1765. X    n = strlen (bbs);
  1766. X    buf[n] = 0;
  1767. X    if (strcmp (bbs, buf))
  1768. X    {
  1769. X        fprintf (stderr, "%s: reply BBS ID mismatch: %s != %s\n",
  1770. X            progname, buf, bbs);
  1771. X        fclose (rep_fd);
  1772. X        return (0);
  1773. X    }
  1774. X
  1775. X    /* Read the .newsrc file; we will need the list of conferences */
  1776. X    ReadNewsrc();
  1777. X
  1778. X    /* Read the next message header and process it */
  1779. X    while (1 == fread (&rep_hdr, 128, 1, rep_fd))
  1780. X    {
  1781. X        SendReply ();
  1782. X        rep_cnt++;
  1783. X    }
  1784. X
  1785. X    fclose (rep_fd);
  1786. X    printf ("%s: sent %d replies\n", progname, rep_cnt);
  1787. X}
  1788. X
  1789. XSendReply ()
  1790. X/*
  1791. X *  Pipe a reply to the mailer or inews
  1792. X */
  1793. X{
  1794. X    FILE *pfd;
  1795. X    unsigned char c, to[PATH_LEN], subject[PATH_LEN], group[PATH_LEN];
  1796. X    int i, n, blocks, bytes, conf;
  1797. X    struct nrc_ent *np;
  1798. X
  1799. X    /* Extract recipient */
  1800. X    strncpy (buf, rep_hdr.to, 25);
  1801. X    buf[25] = 0;
  1802. X    sscanf (buf, "%s", to);
  1803. X
  1804. X    /* Extract conference number */
  1805. X    strncpy (buf, rep_hdr.number, 7);
  1806. X    buf[7] = 0;
  1807. X    sscanf (buf, "%d", &conf);
  1808. X
  1809. X    /* Extract subject */
  1810. X    strncpy (buf, rep_hdr.subject, 25);
  1811. X    buf[25] = 0;
  1812. X    strcpy (subject, buf);
  1813. X
  1814. X    /* Get rid of single quotes in subject */
  1815. X    n = strlen (subject);
  1816. X    for (i=0; i<n; i++) if (subject[i] == '\'') subject[i] = '`';
  1817. X
  1818. X    /* Find newsgroup with this conference number */
  1819. X    np = nrc_list;
  1820. X    while (np != NULL)
  1821. X    {
  1822. X        if (np->conf == conf) break;
  1823. X        np = np->next;
  1824. X    }
  1825. X
  1826. X    /* Get newsgroup name */
  1827. X    if (np == NULL)
  1828. X    {
  1829. X        /* Bet this generates lots of email for "ALL" */
  1830. X        rep_hdr.status = QWK_PRIVATE;
  1831. X    }
  1832. X    else
  1833. X    {
  1834. X        strcpy (group, np->name);
  1835. X    }
  1836. X
  1837. X    /* Extract block count */
  1838. X    strncpy (buf, rep_hdr.blocks, 6);
  1839. X    buf[6] = 0;
  1840. X    sscanf (buf, "%d", &blocks);
  1841. X    blocks -= 1;
  1842. X    bytes = 128 * blocks;
  1843. X
  1844. X    /* Check for off-line command message */
  1845. X    if ( (!strcmp (to, "uqwk")) || (!strcmp (to, "UQWK")) )
  1846. X    {
  1847. X        OffLine (bytes);
  1848. X        return (0);
  1849. X    }
  1850. X
  1851. X    /* Check for a configuration message intended for some
  1852. X       other QWK "door" */
  1853. X    if ( (!strcmp (to, "MARKMAIL")) || (!strcmp (to, "QMAIL"))   ||
  1854. X         (!strcmp (to, "markmail")) || (!strcmp (to, "qmail"))   ||
  1855. X         (!strcmp (to, "ROSEMAIL")) || (!strcmp (to, "KMAIL"))   ||
  1856. X         (!strcmp (to, "rosemail")) || (!strcmp (to, "kmail"))   ||
  1857. X         (!strcmp (to, "MAINMAIL")) || (!strcmp (to, "CMPMAIL")) ||
  1858. X         (!strcmp (to, "mainmail")) || (!strcmp (to, "cmpmail")) ||
  1859. X         (!strcmp (to, "ULTRABBS")) || (!strcmp (to, "BGQWK"))   ||
  1860. X         (!strcmp (to, "ultrabbs")) || (!strcmp (to, "bgqwk"))   ||
  1861. X         (!strcmp (to, "CAM-MAIL")) || (!strcmp (to, "TRIMAIL")) ||
  1862. X         (!strcmp (to, "cam-mail")) || (!strcmp (to, "trimail")) ||
  1863. X         (!strcmp (to, "QSO")) || (!strcmp (to, "qso")) )
  1864. X    {
  1865. X        /* Send warning to user */
  1866. X        SendWarning (to);
  1867. X
  1868. X        /* Skip the rest of the message */
  1869. X        while (bytes--) fread (&c, 1, 1, rep_fd);
  1870. X
  1871. X        return (0);
  1872. X    }
  1873. X
  1874. X    /* Open pipe to proper program */
  1875. X    pfd = NULL;
  1876. X
  1877. X    if ( (rep_hdr.status == QWK_PUBLIC) ||
  1878. X         (rep_hdr.status == QWK_PUBLIC2) )
  1879. X    {
  1880. X        /* Public message, open pipe to inews */
  1881. X        sprintf (buf, "%s -t '%s' -n %s", INEWS_PATH, subject, group);
  1882. X        printf ("%s\n", buf);
  1883. X        if (NULL == (pfd = popen (buf, "w")))
  1884. X        {
  1885. X            fprintf (stderr, "%s: can't popen() inews\n",
  1886. X                    progname);
  1887. X        }
  1888. X    }
  1889. X    else if ( (rep_hdr.status == QWK_PRIVATE) ||
  1890. X              (rep_hdr.status == QWK_PRIVATE2) )
  1891. X    {
  1892. X        /* Open pipe to mail */
  1893. X        sprintf (buf, "%s -s '%s' %s", MAILER_PATH, subject, to);
  1894. X        printf ("%s\n", buf);
  1895. X        if (NULL == (pfd = popen (buf, "w")))
  1896. X        {
  1897. X            fprintf (stderr, "%s: can't popen() mail\n", progname);
  1898. X        }
  1899. X    }
  1900. X
  1901. X    /* Read and send all bytes of message */
  1902. X    for (i=0; i<bytes; i++)
  1903. X    {
  1904. X        fread (&c, 1, 1, rep_fd);
  1905. X        if (c == QWK_EOL) c = 012;
  1906. X        if (pfd != NULL) fwrite (&c, 1, 1, pfd);
  1907. X    }
  1908. X
  1909. X    if (pfd != NULL) pclose (pfd);
  1910. X}
  1911. X
  1912. XSendWarning (to)
  1913. Xchar *to;
  1914. X/*
  1915. X *  Mail a warning to the user if the reply packet
  1916. X *  contains a message apparently for some other QWK
  1917. X *  "door" program.
  1918. X */
  1919. X{
  1920. X    FILE *pfd;
  1921. X
  1922. X    /* Open pipe to mailer */
  1923. X    sprintf (buf, "%s -s 'UQWK Error Message' %s",
  1924. X            MAILER_PATH, user_name);
  1925. X    if (NULL == (pfd = popen (buf, "w")))
  1926. X    {
  1927. X        fprintf (stderr, "%s: can't popen() mail\n", progname);
  1928. X        return (0);
  1929. X    }
  1930. X
  1931. X    /* Send the message */
  1932. X
  1933. X    fprintf (pfd,
  1934. X"Hello. You sent a message to the username %s, presumably to\n", to);
  1935. X    fprintf (pfd,
  1936. X"perform some sort of offline configuration. This QWK processor,\n");
  1937. X    fprintf (pfd,
  1938. X"called UQWK, cannot process this message. To perform offline\n");
  1939. X    fprintf (pfd,
  1940. X"configuration using UQWK, you must send a message to the username\n");
  1941. X    fprintf (pfd,
  1942. X"UQWK. Commands are to be included in the body of the message.\n");
  1943. X    fprintf (pfd,
  1944. X"For a list of commands, send a message to UQWK with the word\n");
  1945. X    fprintf (pfd,
  1946. X"HELP in the body of the message (not the subject). Thanks!\n");
  1947. X
  1948. X    pclose (pfd);
  1949. X}
  1950. END_OF_FILE
  1951.   if test 5123 -ne `wc -c <'reply.c'`; then
  1952.     echo shar: \"'reply.c'\" unpacked with wrong size!
  1953.   fi
  1954.   # end of 'reply.c'
  1955. fi
  1956. if test -f 'uqwk.c' -a "${1}" != "-c" ; then 
  1957.   echo shar: Will not clobber existing file \"'uqwk.c'\"
  1958. else
  1959.   echo shar: Extracting \"'uqwk.c'\" \(597 characters\)
  1960.   sed "s/^X//" >'uqwk.c' <<'END_OF_FILE'
  1961. X#include <stdio.h>
  1962. X#include <string.h>
  1963. X#include "uqwk.h"
  1964. X
  1965. X/*
  1966. X *  Try to make QWK packets from a mail and/or news spool
  1967. X */
  1968. X
  1969. Xmain (argc, argv)
  1970. Xint argc;
  1971. Xchar *argv[];
  1972. X{
  1973. X    progname = argv[0];
  1974. X
  1975. X    /* Set up defaults */
  1976. X    DefaultOptions();
  1977. X
  1978. X    /* Look for environment variable overrides */
  1979. X    EnvOptions();
  1980. X
  1981. X    /* Look for command line overrides */
  1982. X    CommandOptions (argc, argv);
  1983. X
  1984. X    /* Initialize files, etc. */
  1985. X    InitStuff();
  1986. X
  1987. X    /* Do reply packet? */
  1988. X    if (strcmp (rep_file, DEF_REP_FILE)) DoReply();
  1989. X
  1990. X    /* Do news? */
  1991. X    if (do_news) DoNews();
  1992. X
  1993. X    /* Mail? */
  1994. X    if (do_mail) DoMail();
  1995. X
  1996. X    /* All done */
  1997. X    CloseStuff();
  1998. X}
  1999. END_OF_FILE
  2000.   if test 597 -ne `wc -c <'uqwk.c'`; then
  2001.     echo shar: \"'uqwk.c'\" unpacked with wrong size!
  2002.   fi
  2003.   # end of 'uqwk.c'
  2004. fi
  2005. if test -f 'uqwk.h' -a "${1}" != "-c" ; then 
  2006.   echo shar: Will not clobber existing file \"'uqwk.h'\"
  2007. else
  2008.   echo shar: Extracting \"'uqwk.h'\" \(4189 characters\)
  2009.   sed "s/^X//" >'uqwk.h' <<'END_OF_FILE'
  2010. X/*
  2011. X *  Header for uqwk
  2012. X */
  2013. X
  2014. X#define    PATH_LEN    (128)    /* Length for file names, etc. */
  2015. X#define BUF_LEN        (1024)    /* Length of general purpose buffer */
  2016. X
  2017. X#define QWK_EOL        (227)    /* QWK end-of-line */
  2018. X#define QWK_ACT_FLAG    (225)    /* Active message flag */
  2019. X#define QWK_PUBLIC    ' '    /* Public message flags */
  2020. X#define QWK_PUBLIC2    '-'
  2021. X#define QWK_PRIVATE    '+'    /* Private message flags */
  2022. X#define QWK_PRIVATE2    '*'
  2023. X
  2024. X#define MAILER_PATH    "mail"    /* Where to find mailer */
  2025. X#define INEWS_PATH    "/usr/lib/news/inews"    /* Where to find inews */
  2026. X
  2027. X#define MAIL_CONF_NAME  "Email"
  2028. X
  2029. X/* Defaults */
  2030. X#define    DEF_MAIL_DIR    "/usr/spool/mail"
  2031. X#define DEF_DO_MAIL    (1)
  2032. X#define DEF_DO_NEWS    (0)
  2033. X#define DEF_INC_HDRS    (1)
  2034. X#define DEF_PRT_OPTS    (0)
  2035. X#define DEF_READ_ONLY    (0)
  2036. X#define DEF_MAX_BLKS    (4000)    /* That's half a megabyte */
  2037. X#define DEF_HOME_DIR    "."
  2038. X#define DEF_USER_NAME    "unknown"
  2039. X#define DEF_MAIL_FILE    "unknown"
  2040. X#define DEF_BBS_NAME    "unknown BBS"
  2041. X#define DEF_BBS_CITY    "Anytown, USA"
  2042. X#define DEF_BBS_PHONE    "555-1212"
  2043. X#define DEF_BBS_SYSOP    "Joe Sysop"
  2044. X#define DEF_BBS_ID    "0,SOMEBBS"
  2045. X#define DEF_ACT_FILE    "/usr/lib/news/active"
  2046. X#define DEF_NRC_FILE    "unknown"
  2047. X#define DEF_NEWS_DIR    "/usr/spool/news"
  2048. X#define DEF_REP_FILE    "none"
  2049. X
  2050. X/* Runtime options */
  2051. Xint do_mail;            /* Process mail? */
  2052. Xint do_news;            /* Process news? */
  2053. Xint inc_hdrs;            /* Include headers in messages? */
  2054. Xint prt_opts;            /* Just display options; no processing */
  2055. Xint read_only;            /* Don't rewrite mail spool and .newsrc */
  2056. Xint max_blks;            /* Maximum blocks per QWK packet */
  2057. X
  2058. Xchar mail_file[PATH_LEN];    /* mail spool */
  2059. Xchar mail_dir[PATH_LEN];    /* dir for mail spool */
  2060. Xchar home_dir[PATH_LEN];    /* home directory */
  2061. Xchar user_name[PATH_LEN];    /* user's login name */
  2062. Xchar bbs_name[PATH_LEN];    /* BBS name */
  2063. Xchar bbs_city[PATH_LEN];    /* BBS city */
  2064. Xchar bbs_phone[PATH_LEN];    /* BBS phone number */
  2065. Xchar bbs_sysop[PATH_LEN];    /* BBS sysop name */
  2066. Xchar bbs_id[PATH_LEN];        /* BBS ID */
  2067. Xchar act_file[PATH_LEN];    /* Active file */
  2068. Xchar nrc_file[PATH_LEN];    /* .newsrc file */
  2069. Xchar news_dir[PATH_LEN];    /* News spool dir */
  2070. Xchar rep_file[PATH_LEN];    /* Reply packet file name */
  2071. X
  2072. Xchar *getenv();
  2073. Xchar *Fgets();
  2074. Xstruct act_ent *FindActive();
  2075. X
  2076. X/* Various globals */
  2077. Xchar *progname;            /* Program name */
  2078. Xint msg_cnt;            /* Total number of messages */
  2079. Xint conf_cnt;            /* Total number of conferences */
  2080. XFILE *msg_fd;            /* MESSAGES.DAT file desc */
  2081. XFILE *ctl_fd;            /* CONTROL.DAT file desc */
  2082. XFILE *ndx_fd;            /* xxx.NDX file desc */
  2083. XFILE *act_fd;            /* Active file file desc */
  2084. XFILE *nrc_fd;            /* .newsrc file desc */
  2085. XFILE *rep_fd;            /* Reply packet file desc */
  2086. Xunsigned char buf[BUF_LEN];    /* General purpose buffer */
  2087. Xint blk_cnt;            /* Blocks written to messages.dat */
  2088. X
  2089. X/* This is the stuff we remember about each spooled mail message */
  2090. Xstruct mail_ent
  2091. X{
  2092. X    long begin;        /* Offset of start of header */
  2093. X    long text;        /* Offset to end of header, start of text */
  2094. X    long end;        /* Offset to start of next message */
  2095. X    struct mail_ent *next;    /* Pointer to next */
  2096. X} *mail_list;
  2097. X
  2098. X/* This is stuff we remember about each "conference" */
  2099. Xstruct conf_ent
  2100. X{
  2101. X    char *name;        /* Conference name */
  2102. X    int number;        /* Conference number */
  2103. X    struct conf_ent *next;    /* Pointer to next */
  2104. X} *conf_list, *last_conf;
  2105. X
  2106. X/* This is the QWK message header format */
  2107. Xstruct qwk_hdr
  2108. X{
  2109. X    unsigned char status;
  2110. X    unsigned char number[7];
  2111. X    unsigned char date[8];
  2112. X    unsigned char time[5];
  2113. X    unsigned char to[25];
  2114. X    unsigned char from[25];
  2115. X    unsigned char subject[25];
  2116. X    unsigned char password[12];
  2117. X    unsigned char refer[8];
  2118. X    unsigned char blocks[6];
  2119. X    unsigned char flag;
  2120. X    unsigned char conference[2];
  2121. X    unsigned char msg_num[2];
  2122. X    unsigned char tag;
  2123. X};
  2124. X
  2125. Xstruct qwk_hdr rep_hdr;        /* Header for replies */
  2126. X
  2127. X/* Stuff we remember about each active newsgroup */
  2128. Xstruct act_ent
  2129. X{
  2130. X    char *name;        /* Newsgroup name */
  2131. X    int hi;            /* High article number */
  2132. X    int lo;            /* Low article number */
  2133. X    struct act_ent *next;    /* Pointer to next */
  2134. X} *act_list;
  2135. X
  2136. X/* Stuff we remember about the .newsrc file */
  2137. Xstruct nrc_ent
  2138. X{
  2139. X    char *name;        /* Newsgroup name */
  2140. X    int subscribed;        /* Subscribed flag */
  2141. X    int hi;            /* High article number */
  2142. X    int conf;        /* Corresponding conference number */
  2143. X    struct nrc_ent *next;    /* Pointer to next */
  2144. X} *nrc_list;
  2145. X
  2146. END_OF_FILE
  2147.   if test 4189 -ne `wc -c <'uqwk.h'`; then
  2148.     echo shar: \"'uqwk.h'\" unpacked with wrong size!
  2149.   fi
  2150.   # end of 'uqwk.h'
  2151. fi
  2152. if test -f 'uqwk.man' -a "${1}" != "-c" ; then 
  2153.   echo shar: Will not clobber existing file \"'uqwk.man'\"
  2154. else
  2155.   echo shar: Extracting \"'uqwk.man'\" \(8779 characters\)
  2156.   sed "s/^X//" >'uqwk.man' <<'END_OF_FILE'
  2157. X.TH UQWK 1
  2158. X.IX uqwk
  2159. X.IX qwk
  2160. X.SH NAME
  2161. Xuqwk - Collect news and mail into QWK packet
  2162. X.SH SYNOPSIS
  2163. X.B
  2164. Xuqwk
  2165. X.RB [options]
  2166. X.SH DESCRIPTION
  2167. X.B uqwk
  2168. Xis a program which collects all a user's unread mail or news
  2169. Xand formats it into something called a "QWK" packet, which is then
  2170. Xdownloaded.  Mail and News can then be read offline, saving phone
  2171. Xcharges.  QWK readers exist for almost every machine.
  2172. X.PP
  2173. X.B uqwk
  2174. Xalso accepts reply packets, so replies can be mailed (if your
  2175. Xmailer understands "mail -s"), or posted (if you have a B-news type
  2176. Xof
  2177. X.IR inews
  2178. Xthat understands -n and -t), depending whether
  2179. Xthe message is marked private (email) or public (news).
  2180. X.PP
  2181. X.B uqwk
  2182. Xalso supports a small offline command language, so the contents
  2183. Xof the user's .newsrc file can be viewed and manipulated offline.
  2184. X.SH OPTIONS
  2185. X.TP
  2186. X.B +m
  2187. XDo mail.
  2188. X.B uqwk
  2189. Xwill process all mail in the user's mail spool file and convert
  2190. Xit into a QWK packet.  This is the default.
  2191. X.TP
  2192. X.B -m
  2193. XDon't do mail.
  2194. X.TP
  2195. X.B +n
  2196. XDo news.  Using the user's .newsrc file and the news system's
  2197. Xactive file,
  2198. X.B uqwk
  2199. Xwill collect all unread news articles in all subscribed newsgroups
  2200. Xinto the QWK packet.  This can generate a large number of messages
  2201. Xand large QWK files.
  2202. X.TP
  2203. X.B -n
  2204. XDon't do news.  This is the default.
  2205. X.TP
  2206. X.B +h
  2207. XInclude headers.  Since the QWK specification places limits on
  2208. Xthe sizes of certain header fields such as To:, From:, and Subject:,
  2209. X.B uqwk
  2210. Xcan include all message and article headers in the body of the
  2211. Xmessage so all fields are visible.  This does not, however, make
  2212. Xit possible to successfully send a message to an email address
  2213. Xwhich consists of more that 25 characters.  This is the default.
  2214. X.TP
  2215. X.B -h
  2216. XDo not include headers in messages.
  2217. X.TP
  2218. X.B -p
  2219. XPrint options.
  2220. X.B uqwk
  2221. Xwill examine all appropriate environment variables and command
  2222. Xline options, print the values of all run-time options, then exit.  This
  2223. Xis useful to see what
  2224. X.B uqwk
  2225. Xthinks it is going to do before you actually run it.
  2226. X.TP
  2227. X.B +r
  2228. XRead only.  Normally,
  2229. X.B uqwk
  2230. Xwill empty the user's mail spool file and update the user's .newsrc
  2231. Xfile to reflect the fact that mail and news have been
  2232. Xread.  If this switch is specified,
  2233. X.B uqwk
  2234. Xwill not touch these files.  This is useful for testing.
  2235. X.TP
  2236. X.B -r
  2237. XDo not execute in read-only mode.  This is the default.
  2238. X.TP
  2239. X.B -M\fImaildir\fR
  2240. XLook in the directory \fImaildir\fR for the mail spool file.  The
  2241. Xdefault is /usr/spool/mail.
  2242. X.TP
  2243. X.B -f\fImailfile\fR
  2244. XLook for mail in the file \fImailfile\fR.  The default is a file
  2245. Xwith the same name as the user's login name in \fImaildir\fR.
  2246. XThis switch overrides the
  2247. X.B -M
  2248. Xswitch.
  2249. X.TP
  2250. X.B -u\fIusername\fR
  2251. XBy default
  2252. X.B uqwk
  2253. Xuses the getpwuid() system call to determine the proper user
  2254. Xname to use.  This switch overrides the results of that call.
  2255. X.TP
  2256. X.B -H\fIhomedir\fR
  2257. XBy default,
  2258. X.B uqwk
  2259. Xuses the getpwuid() system call to determine the user's home
  2260. Xdirectory.  The home directory is where the files comprising
  2261. Xthe QWK packet will be created.  It is also where
  2262. X.B uqwk
  2263. Xlooks for the .newsrc file.  This switch may be used to
  2264. Xoverride the results of the getpwuid() call.
  2265. X.TP
  2266. X.B -b\fIbbsname\fR
  2267. XSpecify the BBS Name to be entered into the QWK packet.  The default
  2268. Xis "unknown BBS".
  2269. X.TP
  2270. X.B -c\fIcity\fR
  2271. XSpecify the BBS City to be entered into the QWK packet.  The default
  2272. Xis "Anytown, USA".
  2273. X.TP
  2274. X.B -P\fIphone\fR
  2275. XSpecify the BBS Phone Number to be entered into the QWK packet.
  2276. XThe default is "555-1212".
  2277. X.TP
  2278. X.B -s\fIsysop\fR
  2279. XSpecify the BBS Sysop Name to be entered into the QWK packet.  The
  2280. Xdefault is "Joe Sysop".
  2281. X.TP
  2282. X.B -i\fIbbsid\fR
  2283. XSpecify the BBS ID to be entered into the QWK packet.  The BBS ID
  2284. Xis important since it will be checked against the BBS ID string
  2285. Xin any incoming reply packets.  If the two do not match, the reply
  2286. Xpacket will not be processed.  The BBS ID consists of an integer,
  2287. Xa comma, and a string of less than nine characters, with no spaces.
  2288. XThe default is "0,SOMEBBS".
  2289. X.TP
  2290. X.B -a\fIactivefile\fR
  2291. XUse \fIactivefile\fR for the list of all available newsgroups and
  2292. Xarticle numbers.  The default is /usr/lib/news/active.
  2293. X.TP
  2294. X.B -N\fInewsrcfile\fR
  2295. XUse \fInewsrcfile\fR for the list of all newsgroups to which the
  2296. Xuser is subscribed and the list of article numbers which have been
  2297. Xread.  The default is a file called ".newsrc" in the user's home
  2298. Xdirectory.
  2299. X.TP
  2300. X.B -S\fInewsdir\fR
  2301. XLook for news articles in the directory \fInewsdir\fR.  The default
  2302. Xis /usr/spool/news.
  2303. X.TP
  2304. X.B -B\fImaxblocks\fR
  2305. XStop processing news articles if the size of the QWK packet
  2306. X(specifically, messages.dat) exceeds \fImaxblocks\fR 128-byte blocks.
  2307. XThis is useful since large amounts of unread news can create large
  2308. XQWK files.  Use a \fImaxblocks\fR value of zero to suppress this
  2309. Xcheck.  The default is 4000 blocks (half a megabyte).
  2310. X.TP
  2311. X.B -R\fIreplyfile\fR
  2312. XProcess \fIreplyfile\fR as a reply packet.  Messages and articles
  2313. Xcreated by the offline reader must be uploaded as a reply packet
  2314. Xand then processed by this switch to be mailed or posted.
  2315. X.B uqwk
  2316. Xwill remove \fIreplyfile\fR when it has been processed unless
  2317. Xit is running in read-only mode.
  2318. X.SH "ENVIRONMENT VARIABLES"
  2319. XMost of the run-time options can also be controlled by
  2320. Xenvironment variables.  If an option is specified by both
  2321. Xan environment variable and a command-line option, the
  2322. Xcommand-line option is honored.
  2323. X.TP
  2324. X.B UQ_DO_MAIL
  2325. XDetermines whether or not to process mail.  Should be set to
  2326. X"1" (do mail) or "0" (don't do mail).
  2327. X.TP
  2328. X.B UQ_DO_NEWS
  2329. XDetermines whether or not to process news.  Should be set to
  2330. X"1" (do news) or "0" (don't do news).
  2331. X.TP
  2332. X.B UQ_INC_HDRS
  2333. XDetermines whether or not to include headers in messages.
  2334. XShould be set to "1" (include headers) or "0" (don't include
  2335. Xheaders).
  2336. X.TP
  2337. X.B UQ_PRT_OPTS
  2338. XDetermines whether or not to just print the values of run-time
  2339. Xoptions and stop.  Should be set to "1" (print options) or
  2340. X"0" (don't print options).
  2341. X.TP
  2342. X.B UQ_READ_ONLY
  2343. XDetermines whether or not to run in read-only mode.  Should be
  2344. Xset to "1" (read-only) or "0" (not read-only).
  2345. X.TP
  2346. X.B UQ_MAIL_DIR
  2347. XSpecifies the directory where the mail spool file resides.
  2348. X.TP
  2349. X.B UQ_MAIL_FILE
  2350. XSpecifies the mail spool file.
  2351. X.TP
  2352. X.B UQ_USER_NAME
  2353. XSpecifies the username of the person running
  2354. X.B uqwk.
  2355. X.TP
  2356. X.B UQ_HOME_DIR
  2357. XSpecifies the home directory, where the QWK files will be
  2358. Xcreated, and where
  2359. X.B uqwk
  2360. Xexpects to find the .newsrc file.
  2361. X.TP
  2362. X.B UQ_BBS_NAME
  2363. XSpecifies the BBS name to be entered into the QWK packet.
  2364. X.TP
  2365. X.B UQ_BBS_CITY
  2366. XSpecifies the BBS city to be entered into the QWK packet.
  2367. X.TP
  2368. X.B UQ_BBS_PHONE
  2369. XSpecifies the BBS phone number to be entered into the QWK packet.
  2370. X.TP
  2371. X.B UQ_BBS_SYSOP
  2372. XSpecifies the BBS sysop name to be entered into the QWK packet.
  2373. X.TP
  2374. X.B UQ_BBS_ID
  2375. XSpecifies the BBS ID to be entered into the QWK packet.
  2376. X.TP
  2377. X.B UQ_ACT_FILE
  2378. XSpecifies the name of the news system's active file.
  2379. X.TP
  2380. X.B UQ_NRC_FILE
  2381. XSpecifies the name of the user's .newsrc file.
  2382. X.TP
  2383. X.B UQ_REP_FILE
  2384. XSpecifies the name of the reply packet, if any.
  2385. X.SH "COMMAND LANGUAGE"
  2386. XIf, while processing a reply packet,
  2387. X.B uqwk
  2388. Xencounters a message to the username "UQWK", the body of the
  2389. Xmessage will be interpreted as a small command language, used
  2390. Xto display newsgroup names and subscribe or unsubscribe to
  2391. Xnewsgroups.  The results of the execution of the commands will
  2392. Xbe mailed back to the originating user.
  2393. X.PP
  2394. XThis is what the command language looks like:
  2395. X.TP
  2396. X.B HELP
  2397. XList all the available commands.
  2398. X.TP
  2399. X.B SUBSCRIBE newsgroup
  2400. XSubscribe to the named newsgroup.
  2401. X.TP
  2402. X.B UNSUBSCRIBE newsgroup
  2403. XUnsubscribe from the named newsgroup.  UNSUBSCRIBE ALL may be used to
  2404. Xunsubscribe from all newsgroups.  UNSUBSCRIBE ALL is also the only way
  2405. Xto create a new .newsrc if it does not already exist.
  2406. X.TP
  2407. X.B GROUPS
  2408. XList all newsgroups to which the user is currently subscribed.
  2409. X.TP
  2410. X.B ALLGROUPS
  2411. XList all the available newsgroups and the number of articles in
  2412. Xeach one.
  2413. X.SH BUGS
  2414. XKarl J. Vesterling reported that some .newsrc files cause a core dump.
  2415. XThis may be related to the size of the .newsrc file or to long
  2416. Xlines in the file.  I was unable to reproduce the problem.  Increasing
  2417. XBUF_LEN in uqwk.h may help.
  2418. X.SH "SEE ALSO"
  2419. X.PD
  2420. X.BR mail(1),
  2421. X.BR inews(8)
  2422. X.SH ACKNOWLEDGEMENTS
  2423. XThanks to Patrick Y. Lee (patlee@panix.com) for the QWK documentation.
  2424. XMany thanks also to the beta-testers:  Karl J. Vesterling
  2425. X(kjv@exucom.com) and Brian J. Coan (brian@igc.apc.org).
  2426. X.SH AUTHOR
  2427. XSteve Belczyk, steve1@genesis.nred.ma.us, seb3@gte.com.
  2428. X.PP
  2429. XCopyright (C) 1993 by Steve Belczyk.
  2430. XPermission to use, copy, modify and distribute this software and its
  2431. Xdocumentation for any purpose and without fee is hereby granted, provided
  2432. Xthat the above copyright notice appear in all copies and that both that
  2433. Xcopyright notice and this permission notice appear in supporting
  2434. Xdocumentation.  This software is provided "as is" without express or
  2435. Ximplied warranty.
  2436. END_OF_FILE
  2437.   if test 8779 -ne `wc -c <'uqwk.man'`; then
  2438.     echo shar: \"'uqwk.man'\" unpacked with wrong size!
  2439.   fi
  2440.   # end of 'uqwk.man'
  2441. fi
  2442. echo shar: End of archive 1 \(of 1\).
  2443. cp /dev/null ark1isdone
  2444. MISSING=""
  2445. for I in 1 ; do
  2446.     if test ! -f ark${I}isdone ; then
  2447.     MISSING="${MISSING} ${I}"
  2448.     fi
  2449. done
  2450. if test "${MISSING}" = "" ; then
  2451.     echo You have the archive.
  2452.     rm -f ark[1-9]isdone
  2453. else
  2454.     echo You still must unpack the following archives:
  2455.     echo "        " ${MISSING}
  2456. fi
  2457. exit 0
  2458. exit 0 # Just in case...
  2459.