home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / snews-20.zip / PATCHES.OS2 < prev    next >
Text File  |  1992-08-09  |  160KB  |  5,668 lines

  1. diff -cb orig/active.c new/active.c
  2. *** orig/active.c    Thu Jun 11 22:48:12 1992
  3. --- new/active.c    Sun Aug 09 01:39:15 1992
  4. ***************
  5. *** 1,5 ****
  6.   /*
  7. !     SNEWS 1.0
  8.   
  9.       active.c - routines to manipulate the active and ng files
  10.   
  11. --- 1,5 ----
  12.   /*
  13. !     SNEWS 2.0
  14.   
  15.       active.c - routines to manipulate the active and ng files
  16.   
  17. ***************
  18. *** 122,127 ****
  19. --- 122,128 ----
  20.       }
  21.   
  22.       this->next = NULL;
  23. +     head->groups = ct;
  24.   
  25.       local_head = head;
  26.   
  27. ***************
  28. *** 181,187 ****
  29.        *  of the linked list.
  30.        */
  31.       char        fn[80], buf[81], *p;
  32. !     POST_GROUPS *this, *head = NULL ;
  33.       int         ct = 0;
  34.       FILE        *ngf;
  35.   
  36. --- 182,188 ----
  37.        *  of the linked list.
  38.        */
  39.       char        fn[80], buf[81], *p;
  40. !     POST_GROUPS *this = NULL, *head = NULL ;
  41.       int         ct = 0;
  42.       FILE        *ngf;
  43.   
  44. ***************
  45. *** 215,221 ****
  46.                   exit(1);
  47.               }
  48.   
  49.               if ((p = strtok(buf, " \n\r\t")) == NULL) {
  50.                   fprintf(stderr, "newsgroup 'ng' file corrupt at line %d\n", ct);
  51.                   exit(1);
  52. --- 216,221 ----
  53. ***************
  54. *** 222,231 ****
  55. --- 222,234 ----
  56.               }
  57.   
  58.               strcpy(this->group, p);
  59. +             this -> local = isupper(*this -> group);
  60. +             strlwr(this -> group);
  61.           }
  62.   
  63.       }
  64.   
  65. +     if ( this )
  66.           this->next = NULL;
  67.   
  68.       fclose(ngf);
  69. ***************
  70. *** 281,286 ****
  71. --- 284,305 ----
  72.   }
  73.   
  74.   
  75. + int is_local_group(char *ng)
  76. + {
  77. +     POST_GROUPS *this;
  78. +     this = pg;
  79. +     while (this != NULL) {
  80. +         if (strcmp(ng, this->group) == 0)
  81. +             return(this->local);
  82. +         this = this->next;
  83. +     }
  84. +     return (TRUE);
  85. + }
  86.   
  87.   
  88.   /*-------------------- find a newsgroup in active list ----------------------*/
  89. ***************
  90. *** 481,486 ****
  91. --- 500,506 ----
  92.   
  93.               ct = 0;
  94.   
  95. +             if (act->read_list)
  96.                   for (i = 0; i < articles; i++) {
  97.                       if(*((act->read_list)+i)) {
  98.                           ct++;
  99. ***************
  100. *** 515,521 ****
  101.   
  102.       int  res = 0;
  103.       int  i;
  104. !     char buf[256];
  105.       char *fn, *p, *v;
  106.       FILE *tmp;
  107.   
  108. --- 535,541 ----
  109.   
  110.       int  res = 0;
  111.       int  i;
  112. !     char buf[256], confdir[256];
  113.       char *fn, *p, *v;
  114.       FILE *tmp;
  115.   
  116. ***************
  117. *** 531,538 ****
  118.       if (my_stuff.news_dir[ strlen(my_stuff.news_dir)-1 ] != '\\')
  119.           strcat(my_stuff.news_dir, "\\");
  120.   
  121.       /* read the system file first */
  122.       for (i = 0; i < 2; i++) {
  123.   
  124. --- 551,556 ----
  125. ***************
  126. *** 554,563 ****
  127.   
  128.               while (fgets(buf, 255, tmp)) {
  129.                   p = strtok(buf, " =\r\n");
  130. !                 if (*p != '#') {
  131.   
  132.                       v = strtok(NULL, " =\r\n");
  133.   
  134.                       if (stricmp(p, "mailserv") == 0) {
  135.                           strcpy(my_stuff.mail_server, v);
  136.                           res++;
  137. --- 572,584 ----
  138.   
  139.               while (fgets(buf, 255, tmp)) {
  140.                   p = strtok(buf, " =\r\n");
  141. !                 if (p && *p != '#') {
  142.   
  143.                       v = strtok(NULL, " =\r\n");
  144.   
  145. +                     if (stricmp(p, "confdir") == 0)
  146. +                         strcpy(confdir, v);
  147.                       if (stricmp(p, "mailserv") == 0) {
  148.                           strcpy(my_stuff.mail_server, v);
  149.                           res++;
  150. ***************
  151. *** 572,577 ****
  152. --- 593,604 ----
  153.                               strcat(my_stuff.incoming_dir, "\\");
  154.                           res++;
  155.                       }
  156. +                     if (stricmp(p, "spooldir") == 0) {
  157. +                         strcpy(my_stuff.spool_dir, v);
  158. +                         if (my_stuff.spool_dir[ strlen(my_stuff.spool_dir)-1 ] != '\\')
  159. +                             strcat(my_stuff.spool_dir, "\\");
  160. +                         res++;
  161. +                     }
  162.                       if (stricmp(p, "domain") == 0) {
  163.                           strcpy(my_stuff.my_domain, v);
  164.                           res++;
  165. ***************
  166. *** 578,584 ****
  167.                       }
  168.                       if (stricmp(p, "tempdir") == 0) {
  169.                           strcpy(my_stuff.temp_name, v);
  170. -                         strcat(my_stuff.temp_name, "\\$unbatch");
  171.                           res++;
  172.                       }
  173.                       if (stricmp(p, "mailbox") == 0) {
  174. --- 605,610 ----
  175. ***************
  176. *** 634,640 ****
  177.           }
  178.       }
  179.   
  180. !     return(res == 11);
  181.   }
  182.   
  183.   
  184. --- 660,677 ----
  185.           }
  186.       }
  187.   
  188. !     if ( (p = getenv("LOGNAME")) != NULL ) {
  189. !         struct passwd *pwd;
  190. !         if ( (pwd = getpwnam(p, confdir)) != NULL ) {
  191. !             strcpy(my_stuff.user, pwd -> pw_name);
  192. !             strcpy(my_stuff.home, pwd -> pw_dir);
  193. !             strcpy(my_stuff.my_name, pwd -> pw_gecos);
  194. !             if (my_stuff.home[ strlen(my_stuff.home)-1 ] != '\\')
  195. !                 strcat(my_stuff.home, "\\");
  196. !         }
  197. !     }
  198. !     return(res >= 12);
  199.   }
  200.   
  201.   
  202. ***************
  203. *** 657,663 ****
  204.       (gp->hi_num)++;
  205.       update_active_entry(gp);
  206.   
  207. !     if ((tmp = fopen(fn, "r+b")) == NULL) {
  208.           fprintf(stderr,"active: cannot open text file %s\n", fn);
  209.           exit(1);
  210.       }
  211. --- 694,700 ----
  212.       (gp->hi_num)++;
  213.       update_active_entry(gp);
  214.   
  215. !     if ((tmp = flockopen(fn, "r+b")) == NULL) {
  216.           fprintf(stderr,"active: cannot open text file %s\n", fn);
  217.           exit(1);
  218.       }
  219. ***************
  220. *** 664,671 ****
  221.       fseek(tmp, 0, SEEK_END);
  222.   
  223.       return(tmp);
  224.   }
  225.   
  226.   
  227. --- 701,706 ----
  228. ***************
  229. *** 685,691 ****
  230.       fn = make_news_group_name(gp->group);
  231.       sprintf(fnx, "%s.IDX", fn);
  232.   
  233. !     if((tmp = fopen(fnx, "r+b")) == NULL) {
  234.           fprintf(stderr, "active: cannot open index file %s\n", fn);
  235.           exit(1);
  236.       }
  237. --- 720,726 ----
  238.       fn = make_news_group_name(gp->group);
  239.       sprintf(fnx, "%s.IDX", fn);
  240.   
  241. !     if((tmp = flockopen(fnx, "r+b")) == NULL) {
  242.           fprintf(stderr, "active: cannot open index file %s\n", fn);
  243.           exit(1);
  244.       }
  245. ***************
  246. *** 692,698 ****
  247.       fseek(tmp, 0, SEEK_END);
  248.   
  249.       return(tmp);
  250.   }
  251.   
  252.   
  253. --- 727,732 ----
  254. ***************
  255. *** 712,724 ****
  256.       strcpy(fn, my_stuff.news_dir);
  257.       strcat(fn, "nseq");
  258.   
  259. !     if ((seq_file = fopen(fn, "r+")) != NULL) {
  260.           fscanf(seq_file, "%d", &seq);
  261.           seq++;
  262.           rewind(seq_file);
  263.       } else {
  264.           seq = 0;
  265. !         seq_file = fopen(fn, "wt");
  266.       }
  267.   
  268.       fprintf(seq_file, "%d", seq);
  269. --- 746,758 ----
  270.       strcpy(fn, my_stuff.news_dir);
  271.       strcat(fn, "nseq");
  272.   
  273. !     if ((seq_file = flockopen(fn, "r+t")) != NULL) {
  274.           fscanf(seq_file, "%d", &seq);
  275.           seq++;
  276.           rewind(seq_file);
  277.       } else {
  278.           seq = 0;
  279. !         seq_file = flockopen(fn, "wt");
  280.       }
  281.   
  282.       fprintf(seq_file, "%d", seq);
  283. ***************
  284. *** 733,739 ****
  285.   {
  286.       void *p;
  287.       if ((p = malloc(size)) == NULL) {
  288. -         gotoxy(1,25);
  289.           fprintf(stderr, "\n\nSORRY - NO MEMORY LEFT \n");
  290.           exit(1);
  291.       }
  292. --- 767,772 ----
  293. diff -cb orig/addgroup.c new/addgroup.c
  294. *** orig/addgroup.c    Thu Jun 11 22:48:13 1992
  295. --- new/addgroup.c    Sun Aug 02 20:34:18 1992
  296. ***************
  297. *** 1,5 ****
  298.   /*
  299. !     SNEWS 1.0
  300.   
  301.       addgroup - add a new newsgroup
  302.   
  303. --- 1,5 ----
  304.   /*
  305. !     SNEWS 2.0
  306.   
  307.       addgroup - add a new newsgroup
  308.   
  309. ***************
  310. *** 46,51 ****
  311. --- 46,53 ----
  312.       FILE   *active_file, *new_active_file;
  313.   
  314.   
  315. +     fprintf(stderr, "ADDGROUP: (%s)\n\n", VERSION);
  316.       if (argc > 1) {
  317.   
  318.           if (!load_stuff()) {
  319. ***************
  320. *** 74,81 ****
  321.                   fprintf(stderr, "addgroup: cannot create file %s\n", buf);
  322.                   exit(1);
  323.               }
  324. -         }
  325.               fclose(tmp);
  326.           sprintf(buf, "%snewsbase\\00000000.idx", my_stuff.news_dir);
  327.           if (access(buf, 0) != 0) {
  328.               if ((tmp = fopen(buf, "wb")) == NULL) {
  329. --- 76,83 ----
  330.                   fprintf(stderr, "addgroup: cannot create file %s\n", buf);
  331.                   exit(1);
  332.               }
  333.               fclose(tmp);
  334. +         }
  335.           sprintf(buf, "%snewsbase\\00000000.idx", my_stuff.news_dir);
  336.           if (access(buf, 0) != 0) {
  337.               if ((tmp = fopen(buf, "wb")) == NULL) {
  338. ***************
  339. *** 82,89 ****
  340.                   fprintf(stderr, "addgroup: cannot create file %s\n", buf);
  341.                   exit(1);
  342.               }
  343. -         }
  344.               fclose(tmp);
  345.   
  346.           load_active_file();
  347.           close_active();
  348. --- 84,91 ----
  349.                   fprintf(stderr, "addgroup: cannot create file %s\n", buf);
  350.                   exit(1);
  351.               }
  352.               fclose(tmp);
  353. +         }
  354.   
  355.           load_active_file();
  356.           close_active();
  357. ***************
  358. *** 180,186 ****
  359.   
  360.   
  361.               } else {
  362. !                 fprintf(stderr, "addgroup: newsgroup %s already exists\n", argv[1]);
  363.               }
  364.   
  365.           }
  366. --- 182,188 ----
  367.   
  368.   
  369.               } else {
  370. !                 fprintf(stderr, "addgroup: newsgroup %s already exists\n", argv[i]);
  371.               }
  372.   
  373.           }
  374. ***************
  375. *** 188,194 ****
  376.           close_active_file();
  377.   
  378.       } else {
  379. !         printf("USAGE: addgroup  newsgroup names....\n");
  380.       }
  381.   
  382.   }
  383. --- 190,196 ----
  384.           close_active_file();
  385.   
  386.       } else {
  387. !         printf("usage: addgroup  newsgroup names....\n");
  388.       }
  389.   
  390.   }
  391. Only in new: amatch.c
  392. diff -cb orig/article.c new/article.c
  393. *** orig/article.c    Thu Jun 11 22:48:13 1992
  394. --- new/article.c    Sun Aug 02 20:34:18 1992
  395. ***************
  396. *** 1,6 ****
  397.   /*
  398.   
  399. !     SNEWS 1.0
  400.   
  401.       news - routines to read and display an article
  402.   
  403. --- 1,6 ----
  404.   /*
  405.   
  406. !     SNEWS 2.0
  407.   
  408.       news - routines to read and display an article
  409.   
  410. ***************
  411. *** 24,33 ****
  412.    */
  413.   
  414.   
  415.   #include "defs.h"
  416.   #include "snews.h"
  417.   
  418. ! #include <io.h>
  419.   
  420.   /*------------------------- read in an article -----------------------------*/
  421.   TEXT *load_article(char *fnx, long offset)
  422. --- 24,74 ----
  423.    */
  424.   
  425.   
  426. + #include <process.h>
  427.   #include "defs.h"
  428.   #include "snews.h"
  429.   
  430. ! /*------------------------- recognize address ------------------------------*/
  431. ! char *plain_address(char *raw)
  432. ! {
  433. !   char *ptr = raw, *end;
  434. !   while (*ptr && !isalnum(*ptr)) {
  435. !     while (isspace(*ptr)) ptr++;
  436. !     if (isalnum(*ptr))
  437. !       break;
  438. !     if (*ptr == '(') {
  439. !       for (ptr++; *ptr && *ptr != ')'; ptr++);
  440. !       if (*ptr == ')') ptr++;
  441. !     }
  442. !     else if (*ptr == '"') {
  443. !       for (ptr++; *ptr && *ptr != '"'; ptr++);
  444. !       if (*ptr == '"') ptr++;
  445. !     }
  446. !     else if (*ptr == '<') {
  447. !       ptr++;
  448. !       if ((end = strchr(ptr, '>')) != NULL)
  449. !     *end = 0;
  450. !     }
  451. !     else
  452. !       ptr++;
  453. !   }
  454. !   if ((end = strchr(ptr, ' ')) != NULL)
  455. !     *end = 0;
  456. !   if ((end = strchr(ptr, '\t')) != NULL)
  457. !     *end = 0;
  458. !   if ((end = strchr(ptr, '\n')) != NULL)
  459. !     *end = 0;
  460. !   return ptr;
  461. ! }
  462.   
  463.   /*------------------------- read in an article -----------------------------*/
  464.   TEXT *load_article(char *fnx, long offset)
  465. ***************
  466. *** 38,44 ****
  467.        */
  468.   
  469.       FILE *tmp_file;
  470. !     char buf[256], lnbuf[256], *p;
  471.       TEXT *tx;
  472.       LINE *ln, *lz;
  473.       int  ct, i;
  474. --- 79,85 ----
  475.        */
  476.   
  477.       FILE *tmp_file;
  478. !     char lnbuf[MAXLINE];
  479.       TEXT *tx;
  480.       LINE *ln, *lz;
  481.       int  ct, i;
  482. ***************
  483. *** 46,91 ****
  484.       tx = NULL;
  485.       ct = 0;
  486.   
  487. !     if ((tmp_file = fopen(fnx, "rb")) != NULL) {
  488.   
  489.           fseek(tmp_file, offset, SEEK_SET);
  490.   
  491.           tx = xmalloc(sizeof(TEXT));
  492.           tx->top = NULL;
  493.           tx->start = NULL;
  494. !         strcpy(tx->follow_up, "");
  495. !         strcpy(tx->author, " ** none ** ");
  496. !         strcpy(tx->organisation, " ** none ** ");
  497. !         while (fgets(buf, 255, tmp_file) != NULL) {
  498.   
  499. !             if (strncmp(buf, "@@@@END", 7) == 0) break;
  500.   
  501. !             expand_tabs(buf, 255);
  502.   
  503. !             /*
  504. !              *  We now have a line of input.  If the line is two long
  505. !              *  it is wrapped at spaces or '!'.  The lines of text are
  506. !              *  stored in LINE structures
  507. !              */
  508. !             p = &buf[0];
  509. !             while (strlen(p) > 0) {
  510. !                 strcpy(lnbuf, p);
  511. !                 if (strlen(p) <= 80) {
  512. !                     strcpy(lnbuf, p);
  513. !                     *p = '\x00';
  514. !                 } else {
  515. !                     p += 79;
  516. !                     for (i = 79; i > 50; i--) {
  517. !                         if ((lnbuf[i] == ' ') || (lnbuf[i] == '!'))
  518. !                             break;
  519. !                         p--;
  520. !                     }
  521. !                     lnbuf[i] = '\x00';
  522. !                 }
  523.   
  524. !                 /* is it the first line - if so int the TEXT structure */
  525.                   if (ct == 0) {
  526.                       ln = xmalloc(sizeof(LINE));
  527.                       ln->last = NULL;
  528. --- 87,112 ----
  529.       tx = NULL;
  530.       ct = 0;
  531.   
  532. !     if ((tmp_file = flockopen(fnx, "rb")) != NULL) {
  533.   
  534. +         setvbuf(tmp_file, iobuf, _IOFBF, IOBUFSIZE);
  535.           fseek(tmp_file, offset, SEEK_SET);
  536.   
  537.           tx = xmalloc(sizeof(TEXT));
  538.           tx->top = NULL;
  539.           tx->start = NULL;
  540. !         tx->subject = NULL;
  541. !         tx->follow_up = NULL;
  542. !         tx->author = NULL;
  543. !         tx->organisation = NULL;
  544.   
  545. !         while (fgets(lnbuf, sizeof(lnbuf) - 1, tmp_file) != NULL) {
  546.   
  547. !             lnbuf[sizeof(lnbuf) -1] = 0;
  548.   
  549. !             if (strncmp(lnbuf, "@@@@END", 7) == 0) break;
  550.   
  551. !             /* is it the first line - if so init the TEXT structure */
  552.               if (ct == 0) {
  553.                   ln = xmalloc(sizeof(LINE));
  554.                   ln->last = NULL;
  555. ***************
  556. *** 97,104 ****
  557.                       ln->last = lz;
  558.                   }
  559.   
  560. -                 lnbuf[79] = '\x00';
  561.                   ln->index = ct;
  562.                   strcpy(ln->data, lnbuf);
  563.   
  564.                   if ((strlen(lnbuf) == 1) && (tx->start == NULL))
  565. --- 118,125 ----
  566.                   ln->last = lz;
  567.               }
  568.   
  569.               ln->index = ct;
  570. +             ln->data = xmalloc(strlen(lnbuf) + 1);
  571.               strcpy(ln->data, lnbuf);
  572.   
  573.               if ((strlen(lnbuf) == 1) && (tx->start == NULL))
  574. ***************
  575. *** 108,130 ****
  576.   
  577.                   /* save the header info */
  578.                   if ((tx->start == NULL) && (strncmp("From:", lnbuf, 5) == 0)) {
  579. !                     eat_gunk(lnbuf);
  580. !                     lnbuf[WHO_LENGTH-1] = '\x00';
  581.                       strcpy(tx->author, lnbuf);
  582.                   }
  583.                   if ((tx->start == NULL) &&
  584.                     ((strncmp("Organisation:", lnbuf, 13) == 0) ||
  585.                     (strncmp("Organization:", lnbuf, 13) == 0))) {
  586. !                     eat_gunk(lnbuf);
  587. !                     lnbuf[WHO_LENGTH-1] = '\x00';
  588. !                     strcpy(tx->organisation, lnbuf);
  589.                   }
  590.   
  591. !                 if ((tx->start == NULL) && (strncmp("Followup-To:", lnbuf, 12) == 0)) {
  592. !                     eat_gunk(lnbuf);
  593. !                     lnbuf[79] = '\x00';
  594. !                     strcpy(tx->follow_up, lnbuf);
  595.                   }
  596.               }
  597.   
  598.           }
  599. --- 129,156 ----
  600.   
  601.               /* save the header info */
  602.               if ((tx->start == NULL) && (strncmp("From:", lnbuf, 5) == 0)) {
  603. !                 strcpy(lnbuf, plain_address(lnbuf + 5));
  604. !                 tx->author = xmalloc(strlen(lnbuf) + 1);
  605.                   strcpy(tx->author, lnbuf);
  606.               }
  607.               if ((tx->start == NULL) &&
  608.                 ((strncmp("Organisation:", lnbuf, 13) == 0) ||
  609.                  (strncmp("Organization:", lnbuf, 13) == 0))) {
  610. !                 lnbuf[strlen(lnbuf) - 1] = 0;
  611. !                 tx->organisation = xmalloc(strlen(lnbuf + 14) + 1);
  612. !                 strcpy(tx->organisation, lnbuf + 14);
  613.               }
  614.   
  615. !             if ((tx->start == NULL) && (strncmp("Subject:", lnbuf, 8) == 0)) {
  616. !                 lnbuf[strlen(lnbuf) - 1] = 0;
  617. !                 tx->subject = xmalloc(strlen(lnbuf + 9) + 1);
  618. !                 strcpy(tx->subject, lnbuf + 9);
  619.               }
  620. +             if ((tx->start == NULL) && (strncmp("Followup-To:", lnbuf, 12) == 0)) {
  621. +                 lnbuf[strlen(lnbuf) - 1] = 0;
  622. +                 tx->follow_up = xmalloc(strlen(lnbuf + 13) + 1);
  623. +                 strcpy(tx->follow_up, lnbuf + 13);
  624.               }
  625.   
  626.           }
  627. ***************
  628. *** 150,165 ****
  629.       while (l != NULL) {
  630.           k = l;
  631.           l = l->next;
  632.           free(k);
  633.       }
  634.   
  635.       free(t);
  636.   }
  637.   
  638.   
  639.   
  640.   /*---------------------------- read an article ----------------------------*/
  641. ! int read_article(ACTIVE *gp, TEXT *tx, char *subject, int a_ct, int of_ct)
  642.   {
  643.       /*
  644.        *  This routine alloas the user to read an article
  645. --- 176,222 ----
  646.       while (l != NULL) {
  647.           k = l;
  648.           l = l->next;
  649. +         free(k->data);
  650.           free(k);
  651.       }
  652.   
  653. +     if (t->subject)
  654. +         free(t->subject);
  655. +     if (t->follow_up)
  656. +         free(t->follow_up);
  657. +     if (t->author)
  658. +         free(t->author);
  659. +     if (t->organisation)
  660. +         free(t->organisation);
  661.       free(t);
  662.   }
  663.   
  664.   
  665. + /*---------------------------- display a line -----------------------------*/
  666. + void putline(char *line, int margin)
  667. + {
  668. +     char buf[MAXLINE];
  669. +     int length;
  670. +     strcpy(buf, line);
  671. +     expand_tabs(buf, MAXLINE);
  672. +     length = strlen(buf);
  673. +     if ( length > margin ) {
  674. +         if ( length > margin + _columns )
  675. +             printf("%-*.*s$", _columns - 1, _columns - 1, buf + margin);
  676. +         else {
  677. +             puts(buf + margin);
  678. +         if ( length - margin < _columns )
  679. +           clreol();
  680. +         }
  681. +     }
  682. +     else
  683. +         clreol();
  684. + }
  685.   
  686.   /*---------------------------- read an article ----------------------------*/
  687. ! int read_article(ACTIVE *gp, TEXT *tx, int a_ct, int of_ct)
  688.   {
  689.       /*
  690.        *  This routine alloas the user to read an article
  691. ***************
  692. *** 167,179 ****
  693.   
  694.       LINE   *this, *tmp;   /* current thread                    */
  695.       int    exit_code;     /* why we are exiting the loop      */
  696. !     char   sub_tmp[80];
  697. !     int    ch, i;
  698.   
  699.       this = tx->start;
  700.       exit_code = 0;
  701. !     show_article(gp, tx, subject, this, a_ct, of_ct);
  702.   
  703.       while ((exit_code == 0) || (exit_code == EX_DUMMY)) {
  704.   
  705. --- 224,239 ----
  706.   
  707.       LINE   *this, *tmp;   /* current thread                    */
  708.       int    exit_code;     /* why we are exiting the loop      */
  709. !     char   buf[MAXLINE];
  710. !     int    ch, i, maxx, margin, newmargin;
  711.   
  712.       this = tx->start;
  713. +     if (this->next != NULL)
  714. +         this = this->next;
  715.       exit_code = 0;
  716. !     margin = 0;
  717. !     show_article(gp, tx, this, a_ct, of_ct, margin);
  718.   
  719.       while ((exit_code == 0) || (exit_code == EX_DUMMY)) {
  720.   
  721. ***************
  722. *** 182,211 ****
  723.           switch (ch) {
  724.   
  725.               case 0      :
  726. !                 ch = getch();
  727.               
  728.                   switch (ch) {
  729.   
  730.                       case UP_ARR :
  731.                           if (this->last != NULL) {
  732.                               this = this->last;
  733. -                             gotoxy(1,TEXT_LINE+PAGE_LENGTH-1);
  734. -                             delline();
  735.                               gotoxy(1,TEXT_LINE);
  736.                               insline();
  737. !                             clreol();
  738. !                             cputs(this->data);
  739. !                             exit_code = EX_DUMMY;
  740.                           }
  741.                           break;
  742.   
  743.                       case DN_ARR :
  744. !                         if (this->next != NULL) {
  745.                               this = this->next;
  746.                               gotoxy(1,TEXT_LINE);
  747.                               delline();
  748.                               gotoxy(1,TEXT_LINE+PAGE_LENGTH-1);
  749. -                             insline();
  750.   
  751.                               tmp = this;
  752.                               for (i = 0; i < PAGE_LENGTH-1; i++) {
  753. --- 242,321 ----
  754.           switch (ch) {
  755.   
  756.               case 0      :
  757. !             case 0xE0   :
  758.               
  759. +                 ch = getch();
  760.                   switch (ch) {
  761.   
  762. +                     case F1     :
  763. +                         show_help(HELP_ARTICLES);
  764. +                         break;
  765. +                     case L_ARR  :
  766. +                         if ( margin == 0 )
  767. +                             exit_code = EX_DUMMY;
  768. +                         else
  769. +                             margin = max(0, margin - 4);
  770. +                         break;
  771. +                     case C_L_ARR  :
  772. +                         if ( margin == 0 )
  773. +                             exit_code = EX_DUMMY;
  774. +                         else
  775. +                             margin = 0;
  776. +                         break;
  777. +                     case R_ARR  :
  778. +                         tmp = this;
  779. +                         newmargin = margin;
  780. +                         for (i = 0; i < PAGE_LENGTH-1; i++) {
  781. +                             strcpy(buf, tmp->data);
  782. +                             expand_tabs(buf, MAXLINE);
  783. +                             newmargin = max(newmargin, strlen(buf));
  784. +                             tmp = tmp->next;
  785. +                             if (tmp == NULL) break;
  786. +                         }
  787. +                         if ( margin >= newmargin - _columns )
  788. +                             exit_code = EX_DUMMY;
  789. +                         else
  790. +                             margin += 4;
  791. +                         break;
  792. +                     case C_R_ARR  :
  793. +                         tmp = this;
  794. +                         newmargin = margin;
  795. +                         for (i = 0; i < PAGE_LENGTH-1; i++) {
  796. +                             strcpy(buf, tmp->data);
  797. +                             expand_tabs(buf, MAXLINE);
  798. +                             newmargin = max(newmargin, strlen(buf));
  799. +                             tmp = tmp->next;
  800. +                             if (tmp == NULL) break;
  801. +                         }
  802. +                         newmargin = ((newmargin - 1) / 4 + 1) * 4;
  803. +                         if ( newmargin == margin + _columns )
  804. +                             exit_code = EX_DUMMY;
  805. +                         else
  806. +                             margin = newmargin - _columns;
  807. +                         break;
  808.                       case UP_ARR :
  809.                           if (this->last != NULL) {
  810.                               this = this->last;
  811.                               gotoxy(1,TEXT_LINE);
  812.                               insline();
  813. !                             putline(this->data, margin);
  814.                           }
  815. +                         exit_code = EX_DUMMY;
  816.                           break;
  817.   
  818.                       case DN_ARR :
  819. !                         if (this->next != NULL &&
  820. !                             (this->index + PAGE_LENGTH < tx->lines ||
  821. !                              this->index <= tx->start->index)) {
  822.                               this = this->next;
  823.                               gotoxy(1,TEXT_LINE);
  824.                               delline();
  825.                               gotoxy(1,TEXT_LINE+PAGE_LENGTH-1);
  826.   
  827.                               tmp = this;
  828.                               for (i = 0; i < PAGE_LENGTH-1; i++) {
  829. ***************
  830. *** 213,225 ****
  831.                                   if (tmp == NULL) break;
  832.                               }
  833.   
  834. !                             clreol();
  835. !                             cputs(tmp->data);
  836.                               exit_code = EX_DUMMY;
  837.                           }
  838.                           break;
  839.   
  840.                       case PGUP   :
  841.                               for (i = 0; i < PAGE_LENGTH-1; i++) {
  842.                                   if (this->last == NULL) break;
  843.                                   this = this->last;
  844. --- 323,362 ----
  845.                                   if (tmp == NULL) break;
  846.                               }
  847.   
  848. !                             if (tmp)
  849. !                                 putline(tmp->data, margin);
  850. !                         }
  851. !                         exit_code = EX_DUMMY;
  852. !                         break;
  853. !                     case HOME   :
  854. !                         tmp = this;
  855. !                         this = tx->start;
  856. !                         if (this->next != NULL)
  857. !                             this = this->next;
  858. !                         if (this == tmp)
  859.                               exit_code = EX_DUMMY;
  860. +                         break;
  861. +                     case END    :
  862. +                         tmp = this;
  863. +                         this = tx->start;
  864. +                         while (this->next != NULL)
  865. +                             this = this->next;
  866. +                         for (i = 0; i < PAGE_LENGTH-1; i++) {
  867. +                             if (this->last == NULL) break;
  868. +                             if (tx->start->next && this == tx->start->next)
  869. +                                 break;
  870. +                             this = this->last;
  871.                           }
  872. +                         if (this == tmp)
  873. +                             exit_code = EX_DUMMY;
  874.                           break;
  875.   
  876.                       case PGUP   :
  877. +                         if ( this->last == NULL )
  878. +                             exit_code = EX_DUMMY;
  879. +                         else
  880.                               for (i = 0; i < PAGE_LENGTH-1; i++) {
  881.                                   if (this->last == NULL) break;
  882.                                   this = this->last;
  883. ***************
  884. *** 227,280 ****
  885.                           break;
  886.   
  887.                       case PGDN   :
  888. !                         for (i = 0; i < PAGE_LENGTH-2; i++) {
  889.                                       if (this->next == NULL) break;
  890.                                       this = this->next;
  891.                                   }
  892.                           break;
  893.   
  894. !                     case HOME   :
  895. !                         this = tx->start;
  896. !                         break;
  897. !                     case END    :
  898. !                         this = tx->start;
  899. !                         while (this->next != NULL)
  900. !                             this = this->next;
  901.                           break;
  902.                   }
  903.                   break;
  904.   
  905.               case 'p'    :
  906. !                 strcpy(sub_tmp, "");
  907. !                 post(NULL, gp->group, sub_tmp);
  908.                   break;
  909.   
  910.               case 'f'    :
  911. !                 if (strcmp(tx->follow_up, "") == 0)
  912. !                     post(tx, gp->group, subject);
  913.                   else
  914. !                     post(tx, tx->follow_up, subject);
  915.                   break;
  916.   
  917.               case 'r'    :
  918. !                 reply_to_article(tx, subject);
  919.                   break;
  920.   
  921.               case 'm'    :
  922.                   mail_to_someone(tx);
  923.                   break;
  924.   
  925.               case 's'    :
  926.                   save_to_disk(tx);
  927. -                 message("-- Done --");
  928.                   break;
  929.   
  930.               case 'x'    :
  931.                   rot13(tx);
  932.                   break;
  933.   
  934. -             case '?'    :
  935.               case 'h'    :
  936.                   show_help(HELP_ARTICLES);
  937.                   break;
  938.   
  939. --- 364,427 ----
  940.                           break;
  941.   
  942.                       case PGDN   :
  943. !                         if ( this->next == NULL )
  944. !                             exit_code = EX_DUMMY;
  945. !                         else {
  946. !                             maxx = tx->lines - this->index - PAGE_LENGTH;
  947. !                             maxx = min(maxx, PAGE_LENGTH - 1);
  948. !                             maxx = max(maxx, tx->start->index + 1 - this->index);
  949. !                             if ( maxx <= 0 )
  950. !                                 exit_code = EX_DUMMY;
  951. !                             else
  952. !                                 for (i = 0; i < maxx; i++) {
  953.                                       if (this->next == NULL) break;
  954.                                       this = this->next;
  955.                                   }
  956. +                         }
  957.                           break;
  958.   
  959. !                     default:
  960. !                         exit_code = EX_DUMMY;
  961.                           break;
  962.                   }
  963.                   break;
  964.   
  965.               case 'p'    :
  966. !             case 'P'    :
  967. !                 post(NULL, gp->group);
  968.                   break;
  969.   
  970.               case 'f'    :
  971. !             case 'F'    :
  972. !                 if (!tx->follow_up || strcmp(tx->follow_up, "") == 0)
  973. !                     post(tx, gp->group);
  974.                   else
  975. !                     post(tx, tx->follow_up);
  976.                   break;
  977.   
  978.               case 'r'    :
  979. !             case 'R'    :
  980. !                 reply_to_article(tx);
  981.                   break;
  982.   
  983.               case 'm'    :
  984. +             case 'M'    :
  985.                   mail_to_someone(tx);
  986.                   break;
  987.   
  988.               case 's'    :
  989. +             case 'S'    :
  990.                   save_to_disk(tx);
  991.                   break;
  992.   
  993.               case 'x'    :
  994. +             case 'X'    :
  995.                   rot13(tx);
  996.                   break;
  997.   
  998.               case 'h'    :
  999. +             case 'H'    :
  1000.                   show_help(HELP_ARTICLES);
  1001.                   break;
  1002.   
  1003. ***************
  1004. *** 286,297 ****
  1005.                   exit_code = EX_NEXT;
  1006.                   break;
  1007.   
  1008.               case ESCAPE :
  1009.                   exit_code = EX_QUIT;
  1010.                   break;
  1011.           };
  1012.           if (exit_code == 0)
  1013. !             show_article(gp, tx, subject, this, a_ct, of_ct);
  1014.       }
  1015.   
  1016.       return(exit_code);
  1017. --- 433,470 ----
  1018.                   exit_code = EX_NEXT;
  1019.                   break;
  1020.   
  1021. +             case BACKSP :
  1022. +                 exit_code = EX_PREVIOUS;
  1023. +                 break;
  1024. +         case '+'    :
  1025. +         case '/'    :
  1026. +                 exit_code = EX_SEARCH_FORW;
  1027. +         break;
  1028. +         case '-'    :
  1029. +         case '?'    :
  1030. +                 exit_code = EX_SEARCH_BACKW;
  1031. +         break;
  1032.               case ESCAPE :
  1033.                   exit_code = EX_QUIT;
  1034.                   break;
  1035. +             default:
  1036. +                 exit_code = EX_DUMMY;
  1037. +                 break;
  1038.           };
  1039.           if (exit_code == 0)
  1040. !             show_article(gp, tx, this, a_ct, of_ct, margin);
  1041. !         else {
  1042. !             gotoxy(_columns - 16,2);
  1043. !             textbackground(LIGHTGRAY);  textcolor(BLACK);
  1044. !             sprintf(buf, "Line %d of %d", this->index + 1, tx->lines);
  1045. !             printf("%17s", buf);
  1046. !             textbackground(BLACK);  textcolor(LIGHTGRAY);
  1047. !         }
  1048.       }
  1049.   
  1050.       return(exit_code);
  1051. ***************
  1052. *** 300,346 ****
  1053.   
  1054.   
  1055.   /*-------------------- show the list of active groups -----------------------*/
  1056. ! void show_article(ACTIVE *gp, TEXT *tx, char *subject, LINE *this, int a_ct,
  1057. !                   int of_ct)
  1058.   {
  1059.       /*
  1060.        *  This routine show a page of an article
  1061.        */
  1062.   
  1063. !     int    i;
  1064. !     char   buf[60];
  1065. !     clrscr();
  1066. !     strcpy(buf, subject);
  1067. !     buf[49] = '\x00';
  1068.   
  1069.       textbackground(LIGHTGRAY);  textcolor(BLACK);
  1070. !     clreol();
  1071. !     cprintf("Group: %-30s                         Article: %2d of %2d\r\n",
  1072. !            gp->group, a_ct, of_ct);
  1073. !     clreol();
  1074. !     cprintf("Subject: %-50s          %4d lines\r\n", buf, tx->lines);
  1075. !     clreol();
  1076. !     cprintf("From: %s; %s", tx->author, tx->organisation);
  1077.       textbackground(BLACK);  textcolor(LIGHTGRAY);
  1078.   
  1079. -     gotoxy(1, TEXT_LINE);
  1080.       for (i = 0; i < PAGE_LENGTH; i++) {
  1081.           gotoxy(1, i+TEXT_LINE);
  1082. !         cputs(this->data);
  1083.           this = this->next;
  1084. -         if (this == NULL) break;
  1085.       }
  1086.   
  1087. !     command("ESC=select thread   TAB=next unread   ENTER=next   ?=help");
  1088. ! }
  1089.   
  1090.   
  1091.   
  1092.   /*-------------------------- save article --------------------------------*/
  1093. --- 473,521 ----
  1094.   
  1095.   
  1096.   /*-------------------- show the list of active groups -----------------------*/
  1097. ! void show_article(ACTIVE *gp, TEXT *tx, LINE *this, int a_ct,
  1098. !                   int of_ct, int margin)
  1099.   {
  1100.       /*
  1101.        *  This routine show a page of an article
  1102.        */
  1103.   
  1104. !     int    i, length;
  1105. !     char   buf[256], buf2[32];
  1106.   
  1107. +     gotoxy(1,1);
  1108.       textbackground(LIGHTGRAY);  textcolor(BLACK);
  1109. !     sprintf(buf2, "Article %d of %d", a_ct, of_ct);
  1110. !     printf("Group: %-*.*s  %18s", _columns - 27, _columns - 27,
  1111. !            gp->group, buf2);
  1112. !     gotoxy(1,2);
  1113. !     strcpy(buf, tx->author ? tx->author : "<unknown>");
  1114. !     if (tx->organisation) {
  1115. !         strcat(buf, "; ");
  1116. !         strcat(buf, tx->organisation);
  1117. !     }
  1118. !     sprintf(buf2, "Line %d of %d", this->index + 1, tx->lines);
  1119. !     printf("From: %-*.*s  %17s", _columns - 25, _columns - 25, buf, buf2);
  1120. !     gotoxy(1,3);
  1121. !     sprintf(buf2, margin ? ">%d" : "", margin);
  1122. !     printf("Subject: %-*.*s %4s", _columns - 14, _columns - 14,
  1123. !            tx->subject, buf2);
  1124.       textbackground(BLACK);  textcolor(LIGHTGRAY);
  1125.   
  1126.       for (i = 0; i < PAGE_LENGTH; i++) {
  1127. +         if (this == NULL) break;
  1128.           gotoxy(1, i+TEXT_LINE);
  1129. !         putline(this->data, margin);
  1130.           this = this->next;
  1131.       }
  1132.   
  1133. !     if ( i < PAGE_LENGTH ) {
  1134. !         gotoxy(1, i+TEXT_LINE);
  1135. !         clreos();
  1136. !     }
  1137.   
  1138. +     message("ESC=select thread   TAB=next unread   ENTER=next   F1=help");
  1139. + }
  1140.   
  1141.   
  1142.   /*-------------------------- save article --------------------------------*/
  1143. ***************
  1144. *** 352,363 ****
  1145.   
  1146.       FILE *tmp = NULL;
  1147.       LINE *ln;
  1148. !     char fn[80];
  1149.       int  ch;
  1150. !     message("Enter filename? ");
  1151.   
  1152.       gets(fn);
  1153.   
  1154.       if (access(fn, 0) == 0) {
  1155. --- 527,539 ----
  1156.   
  1157.       FILE *tmp = NULL;
  1158.       LINE *ln;
  1159. !     char fn[256];
  1160.       int  ch;
  1161. !     time_t now;
  1162. !     struct tm *tmnow;
  1163. !     char timestr[64];
  1164.   
  1165. +     lmessage("Enter filename? ");
  1166.       gets(fn);
  1167.   
  1168.       if (access(fn, 0) == 0) {
  1169. ***************
  1170. *** 366,373 ****
  1171.           while (((ch = getch()) != 'y') && (ch != 'n'));
  1172.           if (ch == 'y') {
  1173.               if ((tmp = fopen(fn, "at")) == NULL) {
  1174. !                 message("*** Cannot open file for appending - "
  1175. !                         "please any key to continue ***");
  1176.                   getch();
  1177.               }
  1178.           }
  1179. --- 542,549 ----
  1180.           while (((ch = getch()) != 'y') && (ch != 'n'));
  1181.           if (ch == 'y') {
  1182.               if ((tmp = fopen(fn, "at")) == NULL) {
  1183. !                 message("*** cannot open file for appending - "
  1184. !                         "press any key ***");
  1185.                   getch();
  1186.               }
  1187.           }
  1188. ***************
  1189. *** 375,388 ****
  1190.       } else {
  1191.   
  1192.           if ((tmp = fopen(fn, "wt")) == NULL) {
  1193. !             message("*** Cannot open file for output - press a key to continue ***");
  1194.               getch();
  1195.           }
  1196.   
  1197.       }
  1198.   
  1199.       if (tmp != NULL) {
  1200.   
  1201.           ln = tx->top;
  1202.           while (ln != NULL) {
  1203.               fputs(ln->data, tmp);
  1204. --- 551,578 ----
  1205.       } else {
  1206.   
  1207.           if ((tmp = fopen(fn, "wt")) == NULL) {
  1208. !             message("*** cannot open file for output - press any key  ***");
  1209.               getch();
  1210.           }
  1211.   
  1212. +     setvbuf(tmp, iobuf, _IOFBF, IOBUFSIZE);
  1213.       }
  1214.   
  1215.       if (tmp != NULL) {
  1216.   
  1217. +         time(&now);
  1218. +     tmnow = localtime(&now);
  1219. +     strftime(timestr, sizeof(timestr), "%a %b %d %H:%M:%S %z %Y", tmnow);
  1220. +         ln = tx->top;
  1221. +         while (ln != NULL && strncmp(ln->data, "Path: ", 6)) {
  1222. +             ln = ln->next;
  1223. +         }
  1224. +     strcpy(fn, ln->data + 6);
  1225. +     for ( ch = strlen(fn); fn[ch - 1] == '\n' || fn[ch - 1] == '\r'; ch--)
  1226. +         fn[ch - 1] = 0;
  1227. +     fprintf(tmp, "From %s %s\n", fn, timestr);
  1228.           ln = tx->top;
  1229.           while (ln != NULL) {
  1230.               fputs(ln->data, tmp);
  1231. ***************
  1232. *** 398,404 ****
  1233.   
  1234.   
  1235.   /*-------------------------- reply to article ---------------------------*/
  1236. ! void reply_to_article(TEXT *tx, char *subject)
  1237.   {
  1238.       /*
  1239.        *  Mail reply to article
  1240. --- 588,594 ----
  1241.   
  1242.   
  1243.   /*-------------------------- reply to article ---------------------------*/
  1244. ! void reply_to_article(TEXT *tx)
  1245.   {
  1246.       /*
  1247.        *  Mail reply to article
  1248. ***************
  1249. *** 405,411 ****
  1250.        */
  1251.   
  1252.   #ifdef INCLUDE_SIG
  1253. !     FILE *sig
  1254.       char sig_fn[80];
  1255.   #endif
  1256.   
  1257. --- 595,601 ----
  1258.        */
  1259.   
  1260.   #ifdef INCLUDE_SIG
  1261. !     FILE *sig;
  1262.       char sig_fn[80];
  1263.   #endif
  1264.   
  1265. ***************
  1266. *** 412,424 ****
  1267.       FILE *tmp;
  1268.       LINE *ln;
  1269.       int  ch;
  1270. !     char fn[80];
  1271.       char buf[256];
  1272. !     char author[80], msg_id[80];
  1273.   
  1274. !     strcpy(fn, "reply.tmp");
  1275.   
  1276. !     if ((tmp= fopen(fn, "wt")) != NULL) {
  1277.   
  1278.           get_his_stuff(tx, author, msg_id);
  1279.   
  1280. --- 602,620 ----
  1281.       FILE *tmp;
  1282.       LINE *ln;
  1283.       int  ch;
  1284. !     char fn[256];
  1285.       char buf[256];
  1286. !     char author[80], msg_id[MAXLINE];
  1287. !     char *mailer = getenv("MAILER");
  1288.   
  1289. !     if (mailer == NULL)
  1290. !         mailer = "mail";
  1291.   
  1292. !     strcpy(fn, my_stuff.news_dir);
  1293. !     strcat(fn, "letter");
  1294. !     unlink(fn);
  1295. !     if ((tmp = fopen(fn, "wt")) != NULL) {
  1296.   
  1297.           get_his_stuff(tx, author, msg_id);
  1298.   
  1299. ***************
  1300. *** 427,436 ****
  1301.           while (((ch = getch()) != 'y') && (ch != 'n'));
  1302.   
  1303.           if (ch == 'y') {
  1304. !             fprintf(tmp, "\nIn article %s you write:\n\n", msg_id);
  1305.               ln = tx->start;
  1306.               while (ln != NULL) {
  1307. !                 fprintf(tmp, "  > %s", ln->data);
  1308.                   ln = ln->next;
  1309.               }
  1310.           }
  1311. --- 623,632 ----
  1312.           while (((ch = getch()) != 'y') && (ch != 'n'));
  1313.   
  1314.           if (ch == 'y') {
  1315. !             fprintf(tmp, "In article %s you write:\n", msg_id);
  1316.               ln = tx->start;
  1317.               while (ln != NULL) {
  1318. !                 fprintf(tmp, "> %s", ln->data);
  1319.                   ln = ln->next;
  1320.               }
  1321.           }
  1322. ***************
  1323. *** 443,451 ****
  1324.           if ((sig= fopen(sig_fn, "rt")) != NULL) {
  1325.               while (fgets(buf, 79, sig) != NULL)
  1326.                   fputs(buf, tmp);
  1327. -         }
  1328.               fclose(sig);
  1329.   #endif
  1330.           fclose(tmp);
  1331.   
  1332. --- 639,646 ----
  1333.           if ((sig= fopen(sig_fn, "rt")) != NULL) {
  1334.               while (fgets(buf, 79, sig) != NULL)
  1335.                   fputs(buf, tmp);
  1336.               fclose(sig);
  1337. +         }
  1338.   #endif
  1339.           fclose(tmp);
  1340.   
  1341. ***************
  1342. *** 455,470 ****
  1343.           sprintf(buf, "Send message to %s (y/n)? ", author);
  1344.           message(buf);
  1345.           while (((ch = getch()) != 'y') && (ch != 'n'));
  1346.           if (ch == 'y') {
  1347. !             sprintf(buf, "mail -s \"Re: %s\" %s <%s", subject, author, fn);
  1348.               system(buf);
  1349.           }
  1350. !         unlink(fn);
  1351. !         message("-- Press any key to continue --");
  1352. !         getch();
  1353.   
  1354.       } else {
  1355. !         message("*** Cannot open temp file - press any key to continue ***");
  1356.           getch();
  1357.       }
  1358.   
  1359. --- 650,671 ----
  1360.           sprintf(buf, "Send message to %s (y/n)? ", author);
  1361.           message(buf);
  1362.           while (((ch = getch()) != 'y') && (ch != 'n'));
  1363. +         gotoxy(1,PAGE_SIZE);
  1364. +         clreol();
  1365. +         strcpy(msg_id, tx->subject);
  1366. +         eat_gunk(msg_id);
  1367.           if (ch == 'y') {
  1368. !             sprintf(buf, "%s -s \"Re: %s\" %s <%s >nul 2>&1",
  1369. !                     mailer, msg_id, author, fn);
  1370.               system(buf);
  1371.           }
  1372. !         /* unlink(fn); /* keep it around like rn */
  1373.   
  1374.       } else {
  1375. !         message("*** cannot open temp file - press any key ***");
  1376.           getch();
  1377.       }
  1378.   
  1379. ***************
  1380. *** 484,530 ****
  1381.       FILE *tmp;
  1382.       LINE *ln;
  1383.       int  ch;
  1384. !     char fn[80];
  1385.       char buf[256], who[80];
  1386. !     char author[80], msg_id[80];
  1387.   
  1388. !     strcpy(fn, "reply.tmp");
  1389.   
  1390.       if ((tmp= fopen(fn, "wt")) != NULL) {
  1391.   
  1392. !         get_his_stuff(tx, author, msg_id);
  1393. !         /* add the quoted message */
  1394. !         command("");
  1395. !         lmessage("Who do you want to mail this article to? ");
  1396.           gets(who);
  1397.   
  1398. !         fprintf(tmp, "\nThis article was forwarded to you by %s@%s (%s):\n\n",
  1399.               my_stuff.user, my_stuff.my_domain, my_stuff.my_name);
  1400. !         fprintf(tmp,"--------------------------------- cut here -----------------------------\n\n");
  1401.           ln = tx->top;
  1402.           while (ln != NULL) {
  1403. !             fprintf(tmp, "%s", ln->data);
  1404.               ln = ln->next;
  1405.           }
  1406.   
  1407. -         fprintf(tmp,"--------------------------------- cut here -----------------------------\n\n");
  1408.           fclose(tmp);
  1409.   
  1410. !         sprintf(buf, "Send message to %s (y/n)? ", who);
  1411.           message(buf);
  1412.           while (((ch = getch()) != 'y') && (ch != 'n'));
  1413.           if (ch == 'y') {
  1414. !             sprintf(buf, "mail %s <%s", who, fn);
  1415.               system(buf);
  1416.           }
  1417.           unlink(fn);
  1418. -         message("-- Press any key to continue --");
  1419. -         getch();
  1420.   
  1421.       } else {
  1422. !         message("*** Cannot open temp file - press any key to continue ***");
  1423.           getch();
  1424.       }
  1425.   
  1426. --- 685,733 ----
  1427.       FILE *tmp;
  1428.       LINE *ln;
  1429.       int  ch;
  1430. !     char fn[256];
  1431.       char buf[256], who[80];
  1432. !     char *subj = tx->subject ? tx->subject : "No subject";
  1433.   
  1434. !     sprintf(fn, "%s\\snews.tmp", my_stuff.temp_name);
  1435.   
  1436.       if ((tmp= fopen(fn, "wt")) != NULL) {
  1437.   
  1438. !         lmessage("Mail this article to? ");
  1439.           gets(who);
  1440.   
  1441. !     fprintf(tmp, "Resent-From: %s@%s (%s)\n",
  1442.           my_stuff.user, my_stuff.my_domain, my_stuff.my_name);
  1443. !     fprintf(tmp, "Resent-To: %s\n", who);
  1444.           ln = tx->top;
  1445.           while (ln != NULL) {
  1446. !             fputs(ln->data, tmp);
  1447.               ln = ln->next;
  1448.           }
  1449.   
  1450.           fclose(tmp);
  1451.   
  1452. !         message("Edit outgoing message (y/n)? ");
  1453. !         while (((ch = getch()) != 'y') && (ch != 'n'));
  1454. !         if (ch == 'y') {
  1455. !       sprintf(buf, my_stuff.editor, fn);
  1456. !       system(buf);
  1457. !     }
  1458. !         sprintf(buf, "Mail article to %s (y/n)? ", who);
  1459.           message(buf);
  1460.           while (((ch = getch()) != 'y') && (ch != 'n'));
  1461.           if (ch == 'y') {
  1462. !             sprintf(buf, "rmail -t <%s 2>nul", fn);
  1463.               system(buf);
  1464.           }
  1465.           unlink(fn);
  1466.   
  1467.       } else {
  1468. !         message("*** cannot open temp file - press any key ***");
  1469.           getch();
  1470.       }
  1471.   
  1472. ***************
  1473. *** 541,547 ****
  1474.   
  1475.       LINE *ln;
  1476.       char *p;
  1477. !     char buf[100];
  1478.       char *null_name = {" ** none ** "};
  1479.   
  1480.       strcpy(author, null_name);
  1481. --- 744,750 ----
  1482.   
  1483.       LINE *ln;
  1484.       char *p;
  1485. !     char buf[MAXLINE];
  1486.       char *null_name = {" ** none ** "};
  1487.   
  1488.       strcpy(author, null_name);
  1489. ***************
  1490. *** 549,554 ****
  1491. --- 752,759 ----
  1492.   
  1493.       ln = tx->top;
  1494.       while (ln != NULL) {
  1495. +         if (strlen(ln->data) < 2) break;
  1496.           strcpy(buf, ln->data);
  1497.           p = strtok(buf, " :\n\r");
  1498.           p = strtok(NULL, " :\n\r");
  1499. ***************
  1500. *** 558,571 ****
  1501.   
  1502.           if ((strnicmp(ln->data, "From:", 5) == 0) &&
  1503.             (strcmp(author, null_name) == 0)) {
  1504. !             strcpy(author, p);
  1505.           }
  1506.   
  1507. !         if (strnicmp(ln->data, "Reply-To:", 5) == 0) {
  1508. !             strcpy(author, p);
  1509.           }
  1510.   
  1511. -         if (strlen(ln->data) < 2) break;
  1512.           ln = ln->next;
  1513.       }
  1514.   }
  1515. --- 763,775 ----
  1516.   
  1517.           if ((strnicmp(ln->data, "From:", 5) == 0) &&
  1518.             (strcmp(author, null_name) == 0)) {
  1519. !             strcpy(author, plain_address(ln->data+5));
  1520.           }
  1521.   
  1522. !         if (strnicmp(ln->data, "Reply-to:", 9) == 0) {
  1523. !             strcpy(author, plain_address(ln->data+9));
  1524.           }
  1525.   
  1526.           ln = ln->next;
  1527.       }
  1528.   }
  1529. ***************
  1530. *** 600,606 ****
  1531.   void expand_tabs(char *buf, int max_len)
  1532.   {
  1533.       int  l, k;
  1534. !     char tmp[256], *p, *t;
  1535.   
  1536.       p = buf;
  1537.       t = &tmp[0];
  1538. --- 804,810 ----
  1539.   void expand_tabs(char *buf, int max_len)
  1540.   {
  1541.       int  l, k;
  1542. !     char tmp[MAXLINE], *p, *t;
  1543.   
  1544.       p = buf;
  1545.       t = &tmp[0];
  1546. ***************
  1547. *** 625,628 ****
  1548. --- 829,836 ----
  1549.   
  1550.       *t = '\x00';
  1551.       strcpy(buf, tmp);
  1552. +     l = strlen(buf);
  1553. +     
  1554. +     if (buf[l - 1] == '\n')
  1555. +       buf[l - 1] = 0;
  1556.   }
  1557. diff -cb orig/defs.h new/defs.h
  1558. *** orig/defs.h    Thu Jun 11 22:48:14 1992
  1559. --- new/defs.h    Sun Aug 02 20:34:18 1992
  1560. ***************
  1561. *** 1,5 ****
  1562.   /*
  1563. !     SNEWS 1.0
  1564.   
  1565.       General public decls
  1566.   
  1567. --- 1,5 ----
  1568.   /*
  1569. !     SNEWS 2.0
  1570.   
  1571.       General public decls
  1572.   
  1573. ***************
  1574. *** 22,28 ****
  1575.   
  1576.    */
  1577.   
  1578. ! #include <alloc.h>
  1579.   #include <time.h>
  1580.   #include <string.h>
  1581.   #include <conio.h>
  1582. --- 22,28 ----
  1583.   
  1584.    */
  1585.   
  1586. ! #include <malloc.h>
  1587.   #include <time.h>
  1588.   #include <string.h>
  1589.   #include <conio.h>
  1590. ***************
  1591. *** 30,41 ****
  1592.   #include <stdio.h>
  1593.   #include <stdlib.h>
  1594.   #include <string.h>
  1595.   #include <sys/stat.h>
  1596. ! #include <dir.h>
  1597.   
  1598.   
  1599. - #define VERSION      "Simple NEWS 1.12"
  1600.   
  1601.   #define HIST_MEM_LIMIT  75000l  /* leave this much meme free loading history */
  1602.   
  1603.   #define ACTIVE_NUM_LEN   8      /* length of the numbers in the active file */
  1604. --- 30,47 ----
  1605.   #include <stdio.h>
  1606.   #include <stdlib.h>
  1607.   #include <string.h>
  1608. + #include <io.h>
  1609. + #include <sys/types.h>
  1610.   #include <sys/stat.h>
  1611. ! #include <direct.h>
  1612.   
  1613. + #include "os2defs.h"
  1614.   
  1615.   
  1616. + #define VERSION      "SNEWS /2 2.0"
  1617. + #define COPYRIGHT    "(c) 1991 John McCombs, (c) 1992 Kai Uwe Rommel"
  1618.   #define HIST_MEM_LIMIT  75000l  /* leave this much meme free loading history */
  1619.   
  1620.   #define ACTIVE_NUM_LEN   8      /* length of the numbers in the active file */
  1621. ***************
  1622. *** 43,63 ****
  1623.   #define TRUE     1
  1624.   #define FALSE    0
  1625.   
  1626.   
  1627.   /* this is the data we get from the UUPC .rc files */
  1628.   typedef struct {
  1629. !     char temp_name[80];           /* unbatch temp file             */
  1630. !     char news_dir[80];            /* news base directory           */
  1631. !     char incoming_dir[80];        /* incoming news spool directory */
  1632. !     char user[80];                /* current user id               */
  1633. !     char my_name[80];             /* my full name                  */
  1634. !     char my_domain[80];           /* our domain                    */
  1635. !     char my_site[80];             /* site name                     */
  1636. !     char my_organisation[80];     /* organisation                  */
  1637. !     char mail_server[80];         /* where posts are routed to     */
  1638. !     char editor[80];              /* system editor                 */
  1639. !     char home[80];                /* home mail directory           */
  1640. !     char signature[80];           /* signature file                */
  1641.   } INFO;
  1642.   
  1643.   
  1644. --- 49,73 ----
  1645.   #define TRUE     1
  1646.   #define FALSE    0
  1647.   
  1648. + #define IOBUFSIZE 32000
  1649. + extern char iobuf[IOBUFSIZE];
  1650.   
  1651.   /* this is the data we get from the UUPC .rc files */
  1652.   typedef struct {
  1653. !     char temp_name[256];           /* unbatch temp file             */
  1654. !     char news_dir[256];            /* news base directory           */
  1655. !     char incoming_dir[256];        /* incoming news spool directory */
  1656. !     char spool_dir[256];           /* spool directory, log files    */
  1657. !     char user[256];                /* current user id               */
  1658. !     char my_name[256];             /* my full name                  */
  1659. !     char my_domain[256];           /* our domain                    */
  1660. !     char my_site[256];             /* site name                     */
  1661. !     char my_organisation[256];     /* organisation                  */
  1662. !     char mail_server[256];         /* where posts are routed to     */
  1663. !     char editor[256];              /* system editor                 */
  1664. !     char home[256];                /* home mail directory           */
  1665. !     char signature[256];           /* signature file                */
  1666.   } INFO;
  1667.   
  1668.   
  1669. ***************
  1670. *** 64,73 ****
  1671.   extern INFO my_stuff;
  1672.   
  1673.   
  1674.   /* NOTE - if hi_num and lo_num are the same there are no articles */
  1675.   typedef struct active {
  1676.       char   group[60];           /* group name                               */
  1677. !     char   gp_file[9];          /* name of the file that the data is in     */
  1678.       long   lo_num;              /* lowest number less one                   */
  1679.       long   hi_num;              /* highest number                           */
  1680.       long   num_pos;             /* file offset of the numbers               */
  1681. --- 74,96 ----
  1682.   extern INFO my_stuff;
  1683.   
  1684.   
  1685. + /*
  1686. +  *  This structure is a linked list of lines that make up an article. The
  1687. +  *  file is read in and the linked list is built
  1688. +  */
  1689. + typedef struct line {
  1690. +     char   *data;               /* line of text                */
  1691. +     struct line *next;          /* next line                   */
  1692. +     struct line *last;          /* last line                   */
  1693. +     int    index;               /* line number from start      */
  1694. + } LINE;
  1695.   /* NOTE - if hi_num and lo_num are the same there are no articles */
  1696.   typedef struct active {
  1697.       char   group[60];           /* group name                               */
  1698. !     char   gp_file[60];         /* name of the file that the data is in     */
  1699.       long   lo_num;              /* lowest number less one                   */
  1700.       long   hi_num;              /* highest number                           */
  1701.       long   num_pos;             /* file offset of the numbers               */
  1702. ***************
  1703. *** 75,80 ****
  1704. --- 98,105 ----
  1705.       struct active *last;        /* last entry                               */
  1706.       int    index;               /* which number in the list, from 0         */
  1707.       char   *read_list;          /* array hi_num-lo_num long. TRUE=read it   */
  1708. +     int    groups;              /* filled in by load_active_file() in head  */
  1709. +     int    threads;             /* filled in by get_headers()               */
  1710.   } ACTIVE;
  1711.   
  1712.   
  1713. ***************
  1714. *** 85,90 ****
  1715. --- 110,116 ----
  1716.    */
  1717.   typedef struct post_groups {
  1718.       char   group[60];           /* group name                               */
  1719. +     int    local;               /* local news group                         */
  1720.       struct post_groups *next;   /* next entry                               */
  1721.   } POST_GROUPS;
  1722.   
  1723. Only in new: exe
  1724. diff -cb orig/expire.c new/expire.c
  1725. *** orig/expire.c    Thu Jun 11 22:48:14 1992
  1726. --- new/expire.c    Sun Aug 02 20:34:18 1992
  1727. ***************
  1728. *** 1,5 ****
  1729.   /*
  1730. !                               Simple NEWS
  1731.   
  1732.       EXPIRE - expire news database articles by number of days since rx'd
  1733.   
  1734. --- 1,5 ----
  1735.   /*
  1736. !     SNEWS 2.0
  1737.   
  1738.       EXPIRE - expire news database articles by number of days since rx'd
  1739.   
  1740. ***************
  1741. *** 30,36 ****
  1742.   
  1743.   INFO my_stuff;
  1744.   
  1745.   /*------------------------------- main --------------------------------*/
  1746.   void main(int argc, char *argv[])
  1747.   {
  1748. --- 30,35 ----
  1749. ***************
  1750. *** 51,56 ****
  1751. --- 50,57 ----
  1752.       long   secs, i, offset;
  1753.       int    days;
  1754.       int    no_space;
  1755. +     int    cnt;
  1756. +     int    matches;
  1757.       long   art_time;
  1758.       long   where;
  1759.   
  1760. ***************
  1761. *** 59,102 ****
  1762.       FILE   *text;
  1763.       FILE   *old_text;
  1764.   
  1765. !     int    articles;
  1766. !     int    articles_deleted;
  1767. !     int    gp_art;
  1768. !     int    gp_art_deleted;
  1769.   
  1770. !     long   total_bytes;
  1771. !     long   total_bytes_deleted;
  1772.       long   gp_bytes;
  1773.       long   gp_bytes_deleted;
  1774.   
  1775.   
  1776. !     articles = 0;
  1777. !     articles_deleted = 0;
  1778.   
  1779. !     total_bytes = 0;
  1780. !     total_bytes_deleted = 0;
  1781.   
  1782.   
  1783. !     fprintf(stderr, "EXPIRE: (%s)\n\n", VERSION);
  1784.   
  1785. !     if (argc == 2) {
  1786.   
  1787.           if (!load_stuff()) {
  1788.               fprintf(stderr, "Couldn't read rc info\n");
  1789.           }
  1790.   
  1791.           head = load_active_file();
  1792. -         time(¤t);
  1793. -         days = atoi(argv[1]);
  1794. -         secs = days * 86400l;
  1795.           gp = head;
  1796.   
  1797. !         printf("NEWSGROUP                           :      ARTICLES         DELETED\n\n");
  1798.   
  1799. !         while (gp != NULL) {
  1800.   
  1801.               no_space = FALSE;
  1802.   
  1803. --- 60,109 ----
  1804.       FILE   *text;
  1805.       FILE   *old_text;
  1806.   
  1807. !     long   articles = 0;
  1808. !     long   articles_deleted = 0;
  1809. !     long   gp_art;
  1810. !     long   gp_art_deleted;
  1811.   
  1812. !     long   total_bytes = 0;
  1813. !     long   total_bytes_deleted = 0;
  1814.       long   gp_bytes;
  1815.       long   gp_bytes_deleted;
  1816.   
  1817.   
  1818. !     fprintf(stderr, "EXPIRE: (%s)\n\n", VERSION);
  1819.   
  1820. !     if (argc < 2) {
  1821. !         fprintf(stderr, "usage: expire -<days> [group-pattern ...]\n");
  1822. !     exit(1);
  1823. !     }
  1824.   
  1825. +     argc--;
  1826. +     argv++;
  1827.   
  1828. !     time(¤t);
  1829.   
  1830. !     if ( **argv == '-' ) {
  1831. !         days = atoi(*argv + 1);
  1832. !         secs = days * 86400l;
  1833. !     argc--;
  1834. !     argv++;
  1835. !     } else {
  1836. !         fprintf(stderr, "usage: expire -<days> [group-pattern ...]\n");
  1837. !     exit(1);
  1838. !     }
  1839.   
  1840.       if (!load_stuff()) {
  1841.       fprintf(stderr, "Couldn't read rc info\n"); 
  1842. +     exit(1);
  1843.       }
  1844.   
  1845.       head = load_active_file();
  1846.       gp = head;
  1847.   
  1848. !     printf("%-40s :      ARTICLES         DELETED\n\n", "NEWSGROUP");
  1849.   
  1850. !     for (gp = head; gp != NULL; gp = gp->next) {
  1851.   
  1852.       no_space = FALSE;
  1853.   
  1854. ***************
  1855. *** 107,130 ****
  1856.   
  1857.               if ((gp->hi_num - gp->lo_num) > 0) {
  1858.   
  1859.                   /*
  1860.                    *  Open all the files.  First the old ones, then the new
  1861.                    */
  1862. -                 fn = make_news_group_name(gp->group);
  1863.   
  1864.                   stat(fn, &st);
  1865. -                 gp_bytes_deleted = st.st_size;
  1866.   
  1867. !                 if ((old_text = fopen(fn, "rb")) == NULL) crash("can't open old text", fn);
  1868. !                 setvbuf(old_text, NULL, _IOFBF, 16384);
  1869. !                 sprintf(buf, "%s.IDX", fn);
  1870. !                 if ((old_index = fopen(buf, "rb")) == NULL) crash("can't open old index", buf);
  1871.   
  1872. !                 sprintf(buf, "%s.NEW", fn);
  1873. !                 if ((text = fopen(buf, "wb")) == NULL) crash("can't create new text", buf);
  1874. !                 setvbuf(text, NULL, _IOFBF, 16384);
  1875. !                 sprintf(buf, "%s.NDX", fn);
  1876. !                 if ((index = fopen(buf, "wb")) == NULL) crash("can't create new index", buf);
  1877.   
  1878.                   /* numbers go chronologically */
  1879.                   for (i = (gp->lo_num)+1; i <= gp->hi_num; i++) {
  1880. --- 114,164 ----
  1881.   
  1882.       if ((gp->hi_num - gp->lo_num) > 0) {
  1883.   
  1884. +           printf("%-40s :  ", gp->group);
  1885. +           fflush(stdout);
  1886. +           
  1887.           /*
  1888.            *  Open all the files.  First the old ones, then the new
  1889.            */
  1890.   
  1891. +         fn = make_news_group_name(gp->group);
  1892.           stat(fn, &st);
  1893.   
  1894. !         if (argc) {
  1895. !         matches = FALSE;
  1896. !         for (cnt = 0; cnt < argc; cnt++)
  1897. !           if (amatch(argv[cnt], gp->group))
  1898. !             matches = TRUE;
  1899. !         } 
  1900. !         else
  1901. !           matches = TRUE;
  1902. !         if (!matches) {
  1903. !         gp_art = gp->hi_num - gp->lo_num;
  1904. !         printf("%4ld %5ld k\n", gp_art, (st.st_size+500)/1000);
  1905. !         articles += gp_art;
  1906. !         total_bytes += st.st_size;
  1907. !         continue;
  1908. !         }
  1909. !         gp_bytes_deleted = st.st_size;
  1910.   
  1911. !         if ((old_text = fopen(fn, "rb")) == NULL) 
  1912. !           crash("can't open old text", fn);
  1913. !         setvbuf(old_text, NULL, _IOFBF, IOBUFSIZE);
  1914. !         sprintf(buf, "%s.idx", fn);
  1915. !         if ((old_index = fopen(buf, "rb")) == NULL) 
  1916. !           crash("can't open old index", buf);
  1917. !         setvbuf(old_index, NULL, _IOFBF, IOBUFSIZE);
  1918. !         sprintf(buf, "%s.new", fn);
  1919. !         if ((text = fopen(buf, "wb")) == NULL) 
  1920. !           crash("can't create new text", buf);
  1921. !         setvbuf(text, NULL, _IOFBF, IOBUFSIZE);
  1922. !         sprintf(buf, "%s.ndx", fn);
  1923. !         if ((index = fopen(buf, "wb")) == NULL) 
  1924. !           crash("can't create new index", buf);
  1925. !         setvbuf(index, NULL, _IOFBF, IOBUFSIZE);
  1926.   
  1927.           /* numbers go chronologically */
  1928.           for (i = (gp->lo_num)+1; i <= gp->hi_num; i++) {
  1929. ***************
  1930. *** 138,143 ****
  1931. --- 172,179 ----
  1932.   
  1933.           /* get the time the article was processed */
  1934.           art_time = atol(buf+18);
  1935. +         /* and the subject */
  1936. +         strcpy(subject, buf+28);
  1937.   
  1938.           if ((current - art_time) > secs) {
  1939.   
  1940. ***************
  1941. *** 160,175 ****
  1942.                           /* copy to new file */
  1943.                           offset = atol(buf);
  1944.                           fseek(old_text, offset, SEEK_SET);
  1945. -                         while (fgets(buf, 255, old_text)) {
  1946.   
  1947. !                             if (strnicmp(buf,"Subject:",8) == 0) {
  1948. !                                 strcpy(subject, buf+8);
  1949. !                             }
  1950.   
  1951.                               if (fputs(buf, text) == EOF) {
  1952.                                   no_space = TRUE;
  1953.                                   break;
  1954.                               }
  1955.                               if (strnicmp(buf, "@@@@END", 7) == 0) break;
  1956.                           }
  1957.   
  1958. --- 196,209 ----
  1959.               /* copy to new file */
  1960.               offset = atol(buf);
  1961.               fseek(old_text, offset, SEEK_SET);
  1962.                 
  1963. !             while (fgets(buf, 255, old_text)) {
  1964.   
  1965.               if (fputs(buf, text) == EOF) {
  1966.                   no_space = TRUE;
  1967.                   break;
  1968.               }
  1969. +             
  1970.               if (strnicmp(buf, "@@@@END", 7) == 0) break;
  1971.               }
  1972.   
  1973. ***************
  1974. *** 190,198 ****
  1975.                   fclose(text);
  1976.                   fclose(index);
  1977.   
  1978. -                 fn = make_news_group_name(gp->group);
  1979.                   /* out of disk on expire, delete the temp files */
  1980.                   if (no_space) {
  1981.                       fprintf(stderr, "expire: no room to expire %s\n", gp->group);
  1982. --- 224,229 ----
  1983. ***************
  1984. *** 215,221 ****
  1985.   
  1986.                   /* print all groups with articles */
  1987.   
  1988. !                 gp_art = (int)(gp->hi_num - gp->lo_num);
  1989.                   gp_bytes_deleted -= gp_bytes;
  1990.   
  1991.                   articles += gp_art;
  1992. --- 246,252 ----
  1993.   
  1994.           /* print all groups with articles */
  1995.   
  1996. !         gp_art = gp->hi_num - gp->lo_num;
  1997.           gp_bytes_deleted -= gp_bytes;
  1998.   
  1999.           articles += gp_art;
  2000. ***************
  2001. *** 226,261 ****
  2002.                   if ((gp_art > 0) || (gp_art_deleted > 0)) {
  2003.   
  2004.                       if (gp_art_deleted > 0)
  2005. !                         printf("%-35s :  %4d %5ldKb     %4d %5ldKb\n",
  2006. !                             gp->group,
  2007.                               gp_art, (gp_bytes+500)/1000,
  2008.                               gp_art_deleted, (gp_bytes_deleted+500)/1000);
  2009.                       else
  2010. !                         printf("%-35s :  %4d %5ldKb\n",
  2011. !                             gp->group,
  2012.                               gp_art, (gp_bytes+500)/1000);
  2013.   
  2014.                   }
  2015.               }
  2016. !             gp = gp->next;
  2017.           }
  2018.   
  2019.           close_active_file();
  2020.           expire_history(current, secs);
  2021.   
  2022. !         printf("\n%7d articles deleted\n"
  2023. !                "%7ld Kb deleted\n"
  2024. !                "%7d articles remaining\n"
  2025. !                "%7ld Kb of text remaining\n",
  2026.                  articles_deleted,
  2027.                  (total_bytes_deleted+500)/1000,
  2028.                  articles,
  2029.                  (total_bytes+500)/1000);
  2030.   
  2031. !     } else {
  2032. !         fprintf(stderr, "usage:  expire <days>\n");
  2033. !     }
  2034.   }
  2035.   
  2036.   
  2037. --- 257,287 ----
  2038.           if ((gp_art > 0) || (gp_art_deleted > 0)) {
  2039.   
  2040.           if (gp_art_deleted > 0)
  2041. !           printf("%4ld %5ld k     %4ld %5ld k\n",
  2042.                gp_art, (gp_bytes+500)/1000,
  2043.                gp_art_deleted, (gp_bytes_deleted+500)/1000);
  2044.           else
  2045. !           printf("%4ld %5ld k\n",
  2046.                gp_art, (gp_bytes+500)/1000);
  2047.   
  2048.           }
  2049.       }
  2050.       }
  2051.   
  2052.       close_active_file();
  2053.       expire_history(current, secs);
  2054.   
  2055. !     printf("\n%7ld articles deleted\n"
  2056. !        "%7ld k of text deleted\n"
  2057. !        "%7ld articles remaining\n"
  2058. !        "%7ld k of text remaining\n",
  2059.          articles_deleted,
  2060.          (total_bytes_deleted+500)/1000,
  2061.          articles,
  2062.          (total_bytes+500)/1000);
  2063.   
  2064. !     exit(0);
  2065.   }
  2066.   
  2067.   
  2068. ***************
  2069. *** 285,295 ****
  2070. --- 311,323 ----
  2071.           fprintf(stderr, "expire: cannot open file %s for input\n", buf);
  2072.           exit(1);
  2073.       }
  2074. +     setvbuf(hist_file, NULL, _IOFBF, IOBUFSIZE);
  2075.       sprintf(buf, "%shistory.new", my_stuff.news_dir);
  2076.       if ((new_hist_file = fopen(buf, "wb")) == NULL) {
  2077.           fprintf(stderr, "expire: cannot open file %s for output\n", buf);
  2078.           exit(1);
  2079.       }
  2080. +     setvbuf(new_hist_file, NULL, _IOFBF, IOBUFSIZE);
  2081.   
  2082.       while (fgets(buf, 255, hist_file) != NULL) {
  2083.           sscanf(buf, "%*s %ld", &age);
  2084. ***************
  2085. *** 309,313 ****
  2086.       rename(buf, buf2);
  2087.       sprintf(buf, "%shistory.bak", my_stuff.news_dir);
  2088.       unlink(buf);
  2089.   }
  2090. --- 337,340 ----
  2091. Only in new: FILES
  2092. diff -cb orig/history.c new/history.c
  2093. *** orig/history.c    Thu Jun 11 22:48:14 1992
  2094. --- new/history.c    Sun Aug 02 20:34:18 1992
  2095. ***************
  2096. *** 1,5 ****
  2097.   /*
  2098. !     SNEWS 1.0
  2099.   
  2100.       History routines
  2101.   
  2102. --- 1,5 ----
  2103.   /*
  2104. !     SNEWS 2.0
  2105.   
  2106.       History routines
  2107.   
  2108. ***************
  2109. *** 143,149 ****
  2110.       }
  2111.   
  2112.       where = 0;
  2113. !     hlist = NULL;
  2114.   
  2115.       while (fgets(buf, 511, hist)) {
  2116.   
  2117. --- 143,149 ----
  2118.       }
  2119.   
  2120.       where = 0;
  2121. !     hlist = h = NULL;
  2122.   
  2123.       while (fgets(buf, 511, hist)) {
  2124.   
  2125. ***************
  2126. *** 160,172 ****
  2127.           h->mid = hash_msg_id(p);
  2128.           h->offset = where;
  2129.   
  2130. -         /* leave some memory for other things */
  2131. -         if (farcoreleft() < HIST_MEM_LIMIT) break;
  2132.           where = ftell(hist);
  2133.       }
  2134.   
  2135.           h->next = NULL;
  2136.   
  2137.       return(hlist);
  2138. --- 160,169 ----
  2139.           h->mid = hash_msg_id(p);
  2140.           h->offset = where;
  2141.   
  2142.           where = ftell(hist);
  2143.       }
  2144.   
  2145. +     if ( h )
  2146.           h->next = NULL;
  2147.   
  2148.       return(hlist);
  2149. ***************
  2150. *** 256,262 ****
  2151.   
  2152.       /* now look up the history file */
  2153.       cx = NULL;
  2154. !     if (h->mid == hid) {
  2155.           fseek(hist, h->offset, SEEK_SET);
  2156.           if (fgets(buf, 511, hist) != NULL) {
  2157.   
  2158. --- 253,259 ----
  2159.   
  2160.       /* now look up the history file */
  2161.       cx = NULL;
  2162. !     if (h && h->mid == hid) {
  2163.           fseek(hist, h->offset, SEEK_SET);
  2164.           if (fgets(buf, 511, hist) != NULL) {
  2165.   
  2166. ***************
  2167. *** 287,299 ****
  2168.                           strcpy(c->group, p);
  2169.                           p = strtok(NULL, " \t\n\r");
  2170.                           c->art_num = atol(p);
  2171.   
  2172.                       } else {
  2173.                           /* eat article number */
  2174.                           p = strtok(NULL, " \t\n\r");
  2175.                       }
  2176. -                     c->next = NULL;
  2177.   
  2178.                       p = strtok(NULL, " \t\n\r");
  2179.                   }
  2180. --- 284,295 ----
  2181.                           strcpy(c->group, p);
  2182.                           p = strtok(NULL, " \t\n\r");
  2183.                           c->art_num = atol(p);
  2184. +                         c->next = NULL;
  2185.   
  2186.                       } else {
  2187.                           /* eat article number */
  2188.                           p = strtok(NULL, " \t\n\r");
  2189.                       }
  2190.   
  2191.                       p = strtok(NULL, " \t\n\r");
  2192.                   }
  2193. Only in new: lock.c
  2194. Only in new: Makefile
  2195. Only in new: os2defs.h
  2196. Only in new: os2util.c
  2197. Only in new: patches.os2
  2198. Only in new: pipe.c
  2199. diff -cb orig/post.c new/post.c
  2200. *** orig/post.c    Thu Jun 11 22:48:14 1992
  2201. --- new/post.c    Sun Aug 02 20:34:18 1992
  2202. ***************
  2203. *** 1,5 ****
  2204.   /*
  2205. !     SNEWS 1.0
  2206.   
  2207.       snews - posting stuff
  2208.   
  2209. --- 1,5 ----
  2210.   /*
  2211. !     SNEWS 2.0
  2212.   
  2213.       snews - posting stuff
  2214.   
  2215. ***************
  2216. *** 34,40 ****
  2217.   
  2218.   
  2219.   /*------------------------------- post an article --------------------------*/
  2220. ! void post(TEXT *tx, char *gx, char *subject)
  2221.   {
  2222.       /*
  2223.        *  Ask for the data we are not given in the arguments,
  2224. --- 34,40 ----
  2225.   
  2226.   
  2227.   /*------------------------------- post an article --------------------------*/
  2228. ! void post(TEXT *tx, char *gx)
  2229.   {
  2230.       /*
  2231.        *  Ask for the data we are not given in the arguments,
  2232. ***************
  2233. *** 43,62 ****
  2234.   
  2235.       FILE *article, *sig;
  2236.       LINE *ln;
  2237. !     char buf[80];
  2238. !     char newsgroups[256];
  2239.       char sig_fn[80];
  2240. !     char author[80], msg_id[80];
  2241.       int  ch;
  2242.   
  2243.       strcpy(newsgroups, gx);
  2244.   
  2245.       strcpy(author, "");
  2246.       strcpy(msg_id, "");
  2247.   
  2248. !     if ((article = fopen("post.tmp", "w+")) != NULL) {
  2249.   
  2250. -         command("");
  2251.           if (strlen(newsgroups) == 0) {
  2252.   
  2253.               /* if no groups ask for them */
  2254. --- 43,64 ----
  2255.   
  2256.       FILE *article, *sig;
  2257.       LINE *ln;
  2258. !     char buf[MAXLINE];
  2259. !     char fn[256], newsgroups[256], subject[256];
  2260.       char sig_fn[80];
  2261. !     char author[80], msg_id[256];
  2262.       int  ch;
  2263.   
  2264. +     strcpy(fn, my_stuff.news_dir);
  2265. +     strcat(fn, "article");
  2266. +     unlink(fn);
  2267.       strcpy(newsgroups, gx);
  2268.   
  2269.       strcpy(author, "");
  2270.       strcpy(msg_id, "");
  2271.   
  2272. !     if ((article = fopen(fn, "w+")) != NULL) {
  2273.   
  2274.           if (strlen(newsgroups) == 0) {
  2275.   
  2276.               /* if no groups ask for them */
  2277. ***************
  2278. *** 80,94 ****
  2279.           /* check for a valid newsgroups line */
  2280.           if (newsgroups_valid(newsgroups)) {
  2281.   
  2282. -             if (strlen(subject) == 0) {
  2283. -                 lmessage("Subject? ");
  2284. -                 gets(subject);
  2285. -             }
  2286.               /* add the quoted message */
  2287.               /* are we quoting */
  2288.               if (tx != NULL) {
  2289.   
  2290.                   message("Quote article (y/n)? ");
  2291.                   while (((ch = getch()) != 'y') && (ch != 'n'));
  2292.   
  2293. --- 82,101 ----
  2294.           /* check for a valid newsgroups line */
  2295.           if (newsgroups_valid(newsgroups)) {
  2296.   
  2297.               /* add the quoted message */
  2298.               /* are we quoting */
  2299.               if (tx != NULL) {
  2300.   
  2301. +                 if (strlen(tx->subject) == 0) {
  2302. +                     lmessage("Subject? ");
  2303. +                     gets(subject);
  2304. +                 }
  2305. +                 else
  2306. +                     if ( strnicmp(tx->subject, "Re: ", 4) != 0 )
  2307. +                         sprintf(subject, "Re: %s", tx->subject);
  2308. +                     else
  2309. +                         strcpy(subject, tx->subject);
  2310.                   message("Quote article (y/n)? ");
  2311.                   while (((ch = getch()) != 'y') && (ch != 'n'));
  2312.   
  2313. ***************
  2314. *** 95,108 ****
  2315.                   if (ch == 'y') {
  2316.   
  2317.                       get_his_stuff(tx, author, msg_id);
  2318. !                     fprintf(article, "\nIn article %s %s writes:\n\n", msg_id, author);
  2319.                       ln = tx->start;
  2320.                       while (ln != NULL) {
  2321. !                         fprintf(article, "  > %s", ln->data);
  2322.                           ln = ln->next;
  2323.                       }
  2324.                   }
  2325.               }
  2326.   
  2327.               /* append the signature if there is one */
  2328.               strcpy(sig_fn, my_stuff.home);
  2329. --- 102,119 ----
  2330.                   if (ch == 'y') {
  2331.   
  2332.                       get_his_stuff(tx, author, msg_id);
  2333. !                     fprintf(article, "%s writes in article %s:\n", author, msg_id);
  2334.                       ln = tx->start;
  2335.                       while (ln != NULL) {
  2336. !                         fprintf(article, "> %s", ln->data);
  2337.                           ln = ln->next;
  2338.                       }
  2339.                   }
  2340.               }
  2341. +             else {
  2342. +                 lmessage("Subject? ");
  2343. +                 gets(subject);
  2344. +             }
  2345.   
  2346.               /* append the signature if there is one */
  2347.               strcpy(sig_fn, my_stuff.home);
  2348. ***************
  2349. *** 110,127 ****
  2350.               if ((sig = fopen(sig_fn, "rt")) != NULL) {
  2351.                   while (fgets(buf, 79, sig) != NULL)
  2352.                       fputs(buf, article);
  2353.               }
  2354.   
  2355.   
  2356.               fclose(article);
  2357. !             sprintf(buf, my_stuff.editor, "post.tmp");
  2358.               system(buf);
  2359. !             article = fopen("post.tmp", "rt");
  2360.   
  2361.               sprintf(buf, "Post this article to %s (y/n)? ", newsgroups);
  2362.               message(buf);
  2363.               while (((ch = getch()) != 'y') && (ch != 'n'));
  2364. !             gotoxy(1,24);
  2365.   
  2366.               if (ch == 'y')
  2367.                   post_it(article, newsgroups, subject, "world", msg_id);
  2368. --- 121,139 ----
  2369.               if ((sig = fopen(sig_fn, "rt")) != NULL) {
  2370.                   while (fgets(buf, 79, sig) != NULL)
  2371.                       fputs(buf, article);
  2372. +                 fclose(sig);
  2373.               }
  2374.   
  2375.   
  2376.               fclose(article);
  2377. !             sprintf(buf, my_stuff.editor, fn);
  2378.               system(buf);
  2379. !             article = fopen(fn, "rt");
  2380.   
  2381.               sprintf(buf, "Post this article to %s (y/n)? ", newsgroups);
  2382.               message(buf);
  2383.               while (((ch = getch()) != 'y') && (ch != 'n'));
  2384. !             gotoxy(1,PAGE_SIZE);
  2385.   
  2386.               if (ch == 'y')
  2387.                   post_it(article, newsgroups, subject, "world", msg_id);
  2388. ***************
  2389. *** 129,135 ****
  2390.           }
  2391.   
  2392.           fclose(article);
  2393. !         unlink("post.tmp");
  2394.   
  2395.       } else {
  2396.           message("*** couldn't open temp article file - press any key ***");
  2397. --- 141,147 ----
  2398.           }
  2399.   
  2400.           fclose(article);
  2401. !         /* unlink(fn); /* keep it around like rn */
  2402.   
  2403.       } else {
  2404.           message("*** couldn't open temp article file - press any key ***");
  2405. ***************
  2406. *** 152,163 ****
  2407.   
  2408.       FILE   *tmp, *local, *log;
  2409.       char   buf[256], *p;
  2410. !     char   ng[256];
  2411.       char   d_name[20], x_name[20];
  2412.       char   short_d_name[20], short_x_name[20];
  2413.       int    ct, seq;
  2414.       time_t t;
  2415. !     struct tm *gmt;
  2416.       long   where;
  2417.       ACTIVE *gp;
  2418.   
  2419. --- 164,176 ----
  2420.   
  2421.       FILE   *tmp, *local, *log;
  2422.       char   buf[256], *p;
  2423. !     char   ng[256], timestr[64];
  2424.       char   d_name[20], x_name[20];
  2425.       char   short_d_name[20], short_x_name[20];
  2426. +     char   remotegroups[256];
  2427.       int    ct, seq;
  2428.       time_t t;
  2429. !     struct tm *gmt, *tmnow;
  2430.       long   where;
  2431.       ACTIVE *gp;
  2432.   
  2433. ***************
  2434. *** 183,189 ****
  2435.       while (fgets(buf, 255, article) != NULL)
  2436.           ct++;
  2437.   
  2438.       /*
  2439.        *  Make the final article file.  This posting stuff is a horrible
  2440.        *  kludge (blush).  If you get a around to fixing this, please
  2441. --- 196,201 ----
  2442. ***************
  2443. *** 191,202 ****
  2444.        */
  2445.       if ((tmp = fopen(short_d_name, "w+b")) != NULL) {
  2446.   
  2447.           fprintf(tmp, "Path: %s!%s\n", my_stuff.my_site, my_stuff.user);
  2448.           fprintf(tmp, "From: %s@%s (%s)\n", my_stuff.user, my_stuff.my_domain,
  2449.               my_stuff.my_name);
  2450.           fprintf(tmp, "Newsgroups: %s\n", newsgroups);
  2451.           fprintf(tmp, "Subject: %s\n", subject);
  2452. !         fprintf(tmp, "Distribution: %s\n", dist);
  2453.   
  2454.           fprintf(tmp, "Message-ID: <%ldsnx@%s>\n", time(&t), my_stuff.my_domain);
  2455.   
  2456. --- 203,226 ----
  2457.        */
  2458.       if ((tmp = fopen(short_d_name, "w+b")) != NULL) {
  2459.   
  2460. +         remotegroups[0] = 0;
  2461. +         strcpy(ng, newsgroups);
  2462. +         p = strtok(ng, " ,");
  2463. +         while (p != NULL) {
  2464. +             if (!is_local_group(p)) {
  2465. +                 if (remotegroups[0])
  2466. +                     strcat(remotegroups, ",");
  2467. +                 strcat(remotegroups, p);
  2468. +             }
  2469. +             p = strtok(NULL, " ,");
  2470. +         }
  2471.           fprintf(tmp, "Path: %s!%s\n", my_stuff.my_site, my_stuff.user);
  2472.           fprintf(tmp, "From: %s@%s (%s)\n", my_stuff.user, my_stuff.my_domain,
  2473.               my_stuff.my_name);
  2474.           fprintf(tmp, "Newsgroups: %s\n", newsgroups);
  2475.           fprintf(tmp, "Subject: %s\n", subject);
  2476. !         fprintf(tmp, "Distribution: %s\n", remotegroups[0] ? dist : "local");
  2477.   
  2478.           fprintf(tmp, "Message-ID: <%ldsnx@%s>\n", time(&t), my_stuff.my_domain);
  2479.   
  2480. ***************
  2481. *** 211,217 ****
  2482.                   gmt->tm_hour, gmt->tm_min, gmt->tm_sec);
  2483.   
  2484.           fprintf(tmp, "Organization: %s\n", my_stuff.my_organisation);
  2485. !         fprintf(tmp, "Lines: %d\n\n", ct);
  2486.   
  2487.           /* copy the rest */
  2488.           rewind(article);
  2489. --- 235,251 ----
  2490.                   gmt->tm_hour, gmt->tm_min, gmt->tm_sec);
  2491.   
  2492.           fprintf(tmp, "Organization: %s\n", my_stuff.my_organisation);
  2493. !         fprintf(tmp, "Lines: %d\n", ct);
  2494. !         strcpy(buf, my_stuff.news_dir);
  2495. !         strcat(buf, "headers");
  2496. !     if ((local = fopen(buf, "r")) != NULL) {
  2497. !             while (fgets(buf, 255, local) != NULL)
  2498. !                 fputs(buf, tmp);
  2499. !         fclose(local);
  2500. !     }
  2501. !     fputs("\n", tmp);
  2502.   
  2503.           /* copy the rest */
  2504.           rewind(article);
  2505. ***************
  2506. *** 251,259 ****
  2507.           /* finally log it */
  2508.           strcpy(buf, my_stuff.news_dir);
  2509.           strcat(buf, "post.log");
  2510. !         if ((log = fopen(buf, "at")) != NULL) {
  2511.               fprintf(log, "\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01"
  2512.                            "\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\n");
  2513.   
  2514.               fseek(tmp, 0L, SEEK_SET);
  2515.               while (fgets(buf, 255, tmp) != NULL)  {
  2516. --- 285,297 ----
  2517.           /* finally log it */
  2518.           strcpy(buf, my_stuff.news_dir);
  2519.           strcat(buf, "post.log");
  2520. !         if ((log = flockopen(buf, "at")) != NULL) {
  2521.               fprintf(log, "\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01"
  2522.                            "\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\n");
  2523. +         tmnow = localtime(&t);
  2524. +         strftime(timestr, sizeof(timestr), "%a %b %d %H:%M:%S %z %Y", gmt);
  2525. +         fprintf(log, "From %s!%s %s\n", my_stuff.my_site, my_stuff.user, 
  2526. +             timestr);
  2527.   
  2528.               fseek(tmp, 0L, SEEK_SET);
  2529.               while (fgets(buf, 255, tmp) != NULL)  {
  2530. ***************
  2531. *** 265,272 ****
  2532.   
  2533.           fclose(tmp);
  2534.   
  2535.           /* now the the X... file */
  2536.               if ((tmp = fopen(short_x_name, "wb")) != NULL) {
  2537.                   fprintf(tmp, "U news %s\n", my_stuff.my_site);
  2538.                   fprintf(tmp, "Z\n");
  2539. --- 303,310 ----
  2540.   
  2541.           fclose(tmp);
  2542.   
  2543.           /* now the the X... file */
  2544. +         if (remotegroups[0])
  2545.               if ((tmp = fopen(short_x_name, "wb")) != NULL) {
  2546.                   fprintf(tmp, "U news %s\n", my_stuff.my_site);
  2547.                   fprintf(tmp, "Z\n");
  2548. ***************
  2549. *** 275,287 ****
  2550.                   fprintf(tmp, "C rnews\n");
  2551.                   fclose(tmp);
  2552.   
  2553. !             sprintf(buf, "uucp -C %s %s!%s ", short_d_name, my_stuff.mail_server,
  2554. !                         d_name);
  2555. !             gotoxy(1,24); clreol();
  2556.                   system(buf);
  2557. !             sprintf(buf, "uucp -C %s %s!%s ", short_x_name, my_stuff.mail_server,
  2558. !                         x_name);
  2559. !             gotoxy(1,24); clreol();
  2560.                   system(buf);
  2561.   
  2562.               } else {
  2563. --- 313,325 ----
  2564.                   fprintf(tmp, "C rnews\n");
  2565.                   fclose(tmp);
  2566.   
  2567. !                 sprintf(buf, "uucp -C %s %s!%s 2>nul", short_d_name, 
  2568. !             my_stuff.mail_server, d_name);
  2569. !                 gotoxy(1,PAGE_SIZE); clreol();
  2570.                   system(buf);
  2571. !                 sprintf(buf, "uucp -C %s %s!%s 2>nul", short_x_name, 
  2572. !             my_stuff.mail_server, x_name);
  2573. !                 gotoxy(1,PAGE_SIZE); clreol();
  2574.                   system(buf);
  2575.   
  2576.               } else {
  2577. ***************
  2578. *** 317,325 ****
  2579.   
  2580.       while (p != NULL) {
  2581.           if (!check_valid_post_group(p)) {
  2582. !             sprintf(msg, "** Can't post to %s **", p);
  2583.               message(msg);
  2584. -             command("-- Press any key to continue --");
  2585.               getch();
  2586.               return(FALSE);
  2587.           }
  2588. --- 355,362 ----
  2589.   
  2590.       while (p != NULL) {
  2591.           if (!check_valid_post_group(p)) {
  2592. !             sprintf(msg, "*** can't post to %s - press any key ***", p);
  2593.               message(msg);
  2594.               getch();
  2595.               return(FALSE);
  2596.           }
  2597. Only in new: pwd.c
  2598. Only in new: pwd.h
  2599. Only in new: README.OS2
  2600. diff -cb orig/rmgroup.c new/rmgroup.c
  2601. *** orig/rmgroup.c    Thu Jun 11 22:48:15 1992
  2602. --- new/rmgroup.c    Sun Aug 02 20:34:18 1992
  2603. ***************
  2604. *** 1,5 ****
  2605.   /*
  2606. !     SNEWS 1.0
  2607.   
  2608.       rmgroup - remove newsgroups from the active file, and delete the files
  2609.   
  2610. --- 1,5 ----
  2611.   /*
  2612. !     SNEWS 2.0
  2613.   
  2614.       rmgroup - remove newsgroups from the active file, and delete the files
  2615.   
  2616. ***************
  2617. *** 49,54 ****
  2618. --- 49,56 ----
  2619.       FILE   *active_file, *new_active_file;
  2620.   
  2621.   
  2622. +     fprintf(stderr, "RMGROUP: (%s)\n\n", VERSION);
  2623.       if (argc > 1) {
  2624.   
  2625.           if (!load_stuff()) {
  2626. ***************
  2627. *** 68,74 ****
  2628.   
  2629.                   /* form the directory name */
  2630.                   dir = make_news_group_name(argv[i]);
  2631. !                 unlink(buf);
  2632.                   sprintf(buf, "%s.IDX", dir);
  2633.                   unlink(buf);
  2634.   
  2635. --- 70,76 ----
  2636.   
  2637.                   /* form the directory name */
  2638.                   dir = make_news_group_name(argv[i]);
  2639. !                 unlink(dir);
  2640.                   sprintf(buf, "%s.IDX", dir);
  2641.                   unlink(buf);
  2642.   
  2643. ***************
  2644. *** 113,119 ****
  2645.   
  2646.   
  2647.               } else {
  2648. !                 fprintf(stderr, "rmgroup: newsgroup %s not found\n", argv[1]);
  2649.               }
  2650.   
  2651.           }
  2652. --- 115,121 ----
  2653.   
  2654.   
  2655.               } else {
  2656. !                 fprintf(stderr, "rmgroup: newsgroup %s not found\n", argv[i]);
  2657.               }
  2658.   
  2659.           }
  2660. ***************
  2661. *** 121,127 ****
  2662.           close_active_file();
  2663.   
  2664.       } else {
  2665. !         printf("USAGE: rmgroup  newsgroup names....\n");
  2666.       }
  2667.   
  2668.   }
  2669. --- 123,129 ----
  2670.           close_active_file();
  2671.   
  2672.       } else {
  2673. !         printf("usage: rmgroup  newsgroup names....\n");
  2674.       }
  2675.   
  2676.   }
  2677. Only in new: rnews.c
  2678. Only in new: rnews.h
  2679. diff -cb orig/snews.c new/snews.c
  2680. *** orig/snews.c    Thu Jun 11 22:48:16 1992
  2681. --- new/snews.c    Sun Aug 09 01:29:29 1992
  2682. ***************
  2683. *** 1,5 ****
  2684.   /*
  2685. !     SNEWS 1.0
  2686.   
  2687.       snews - a simple threaded news reader
  2688.   
  2689. --- 1,5 ----
  2690.   /*
  2691. !     SNEWS 2.0
  2692.   
  2693.       snews - a simple threaded news reader
  2694.   
  2695. ***************
  2696. *** 27,32 ****
  2697. --- 27,34 ----
  2698.   
  2699.   
  2700.   INFO my_stuff;
  2701. + char iobuf[IOBUFSIZE];
  2702. + char search_text[256];
  2703.   
  2704.   
  2705.   /*------------------------------- main --------------------------------*/
  2706. ***************
  2707. *** 35,50 ****
  2708.       ACTIVE *gp, *head;
  2709.       int    done;
  2710.   
  2711. !     printf("loading config... ");
  2712.       if (load_stuff()) {
  2713.   
  2714. !         printf("loading active... ");
  2715.           head = load_active_file();
  2716. !         printf("loading read list... ");
  2717.           load_read_list();
  2718. !         printf("loading history... ");
  2719.           load_history_list();
  2720.   
  2721.           done = FALSE;
  2722.           gp = NULL;
  2723.   
  2724. --- 37,57 ----
  2725.       ACTIVE *gp, *head;
  2726.       int    done;
  2727.   
  2728. !     ignore_signals();
  2729. !     
  2730. !     printf("loading config...\n");
  2731.       if (load_stuff()) {
  2732.   
  2733. !         printf("loading active...\n");
  2734.           head = load_active_file();
  2735. !         printf("loading read list...\n");
  2736.           load_read_list();
  2737. !         printf("loading history...\n");
  2738.           load_history_list();
  2739.   
  2740. +         scrinit();
  2741. +         clrscr();
  2742.           done = FALSE;
  2743.           gp = NULL;
  2744.   
  2745. ***************
  2746. *** 56,68 ****
  2747.               }
  2748.           }
  2749.   
  2750.           clrscr();
  2751.   
  2752.           free_hist_list();
  2753.           save_read_list();
  2754.           close_active_file();
  2755.       } else {
  2756. !         fprintf(stderr, "Couldn't fine neccessary item in the .rc files\n");
  2757.       }
  2758.   }
  2759.   
  2760. --- 63,77 ----
  2761.               }
  2762.           }
  2763.   
  2764. +         screxit();
  2765.           clrscr();
  2766.   
  2767.           free_hist_list();
  2768.           save_read_list();
  2769.           close_active_file();
  2770.       } else {
  2771. !         fprintf(stderr, "Couldn't find necessary item in the .rc files\n");
  2772.       }
  2773.   }
  2774.   
  2775. ***************
  2776. *** 74,80 ****
  2777.   {
  2778.       /*
  2779.        *  Present the list of groups, and allow him to move up and down with
  2780. !      *  the arrow and PgUp and PgDn keys.  'h' for help, -/+ for searches
  2781.        */
  2782.   
  2783.       ACTIVE *top;        /* newsgroup at the top of the page */
  2784. --- 83,89 ----
  2785.   {
  2786.       /*
  2787.        *  Present the list of groups, and allow him to move up and down with
  2788. !      *  the arrow and PgUp and PgDn keys.
  2789.        */
  2790.   
  2791.       ACTIVE *top;        /* newsgroup at the top of the page */
  2792. ***************
  2793. *** 81,87 ****
  2794.       ACTIVE *this;       /* current newsgroup                */
  2795.       ACTIVE *tmp_ng;
  2796.       int    exit_code;   /* why we are exiting the loop      */
  2797. -     char   sub_tmp[80];
  2798.   
  2799.       int    ch, i, j, articles, unread;
  2800.   
  2801. --- 90,95 ----
  2802. ***************
  2803. *** 90,96 ****
  2804.       top = head;
  2805.       exit_code = 0;
  2806.   
  2807. !     show_groups(&top, this, TRUE);
  2808.   
  2809.       while (exit_code == 0) {
  2810.   
  2811. --- 98,104 ----
  2812.       top = head;
  2813.       exit_code = 0;
  2814.   
  2815. !     show_groups(&top, this, TRUE, head);
  2816.   
  2817.       while (exit_code == 0) {
  2818.   
  2819. ***************
  2820. *** 98,107 ****
  2821.           switch (ch) {
  2822.   
  2823.               case 0      :
  2824. !                 ch = getch();
  2825.               
  2826.                   switch (ch) {
  2827.   
  2828.                       case UP_ARR :
  2829.                           if (this->last != NULL) this = this->last;
  2830.                           break;
  2831. --- 106,121 ----
  2832.           switch (ch) {
  2833.   
  2834.               case 0      :
  2835. !             case 0xE0   :
  2836.               
  2837. +                 ch = getch();
  2838.                   switch (ch) {
  2839.   
  2840. +                     case F1     :
  2841. +                         show_help(HELP_GROUP);
  2842. +                         show_groups(&top, this, TRUE, head);
  2843. +                         break;
  2844. +                         
  2845.                       case UP_ARR :
  2846.                           if (this->last != NULL) this = this->last;
  2847.                           break;
  2848. ***************
  2849. *** 126,133 ****
  2850.   
  2851.                       case HOME   :
  2852.                           top = this = head;
  2853. !                         show_groups(&top, this, TRUE);
  2854.                           break;
  2855.                       case END    :
  2856.                           this = head;
  2857.                           while (this->next != NULL)
  2858. --- 140,148 ----
  2859.   
  2860.                       case HOME   :
  2861.                           top = this = head;
  2862. !                         show_groups(&top, this, TRUE, head);
  2863.                           break;
  2864.                       case END    :
  2865.                           this = head;
  2866.                           while (this->next != NULL)
  2867. ***************
  2868. *** 137,156 ****
  2869.                   break;
  2870.   
  2871.               case 'p'    :
  2872. !                 strcpy(sub_tmp, "");
  2873. !                 post(NULL, this->group, sub_tmp);
  2874. !                 show_groups(&top, this, TRUE);
  2875.                   break;
  2876.   
  2877. -             case '?'    :
  2878.               case 'h'    :
  2879.                   show_help(HELP_GROUP);
  2880. !                 show_groups(&top, this, TRUE);
  2881.                   break;
  2882.   
  2883.               case 'c'    :
  2884.                   mark_group_as_read(this);
  2885. !                 show_groups(&top, this, TRUE);
  2886.                   break;
  2887.   
  2888.               case TAB    :
  2889. --- 152,172 ----
  2890.                   break;
  2891.   
  2892.               case 'p'    :
  2893. !             case 'P'    :
  2894. !                 post(NULL, this->group);
  2895. !                 show_groups(&top, this, TRUE, head);
  2896.                   break;
  2897.   
  2898.               case 'h'    :
  2899. +             case 'H'    :
  2900.                   show_help(HELP_GROUP);
  2901. !                 show_groups(&top, this, TRUE, head);
  2902.                   break;
  2903.   
  2904.               case 'c'    :
  2905. +             case 'C'    :
  2906.                   mark_group_as_read(this);
  2907. !                 show_groups(&top, this, TRUE, head);
  2908.                   break;
  2909.   
  2910.               case TAB    :
  2911. ***************
  2912. *** 181,187 ****
  2913.                   break;
  2914.           };
  2915.           if (exit_code == 0)
  2916. !             show_groups(&top, this, FALSE);
  2917.       }
  2918.   
  2919.       if (exit_code == EX_DONE)
  2920. --- 197,203 ----
  2921.                   break;
  2922.           };
  2923.           if (exit_code == 0)
  2924. !             show_groups(&top, this, FALSE, head);
  2925.       }
  2926.   
  2927.       if (exit_code == EX_DONE)
  2928. ***************
  2929. *** 194,247 ****
  2930.   
  2931.   
  2932.   /*---------------------------- help screen ----------------------------------*/
  2933. ! void show_help(int h)
  2934.   {
  2935.   
  2936. !     char *type[] = {"New Group",  "Thread",  "Article"};
  2937.   
  2938. !     clrscr();
  2939.       textbackground(LIGHTGRAY);  textcolor(BLACK);
  2940.       clreol();
  2941. -     cprintf("                      %s Help  (%s)\r\n", type[h], VERSION);
  2942. -     clreol();
  2943.       textbackground(BLACK);  textcolor(LIGHTGRAY);
  2944.   
  2945. !     printf("\n\n");
  2946. !     printf("          PgUp  - move display up one page\n");
  2947. !     printf("          PgDn  - move display down one page\n");
  2948. !     printf("          Home  - move to top of list/article\n");
  2949. !     printf("          End   - move to bottom of list/article\n");
  2950. !     printf("          \x18     - move up one line\n");
  2951. !     printf("          \x19     - move down one line\n\n");
  2952.   
  2953.       switch (h) {
  2954.           case HELP_GROUP   :
  2955. !             printf("          TAB   - go to next newgroup with unread articles\n");
  2956. !             printf("          ENTER - enter selected newsgroup\n\n");
  2957. !             printf("          p     - post article in selected newsgroup\n");
  2958. !             printf("          c     - mark all articles in this newsgroup as read\n");
  2959.               break;
  2960.   
  2961.           case HELP_THREAD  :
  2962. !             printf("          TAB   - go to next unread article\n");
  2963. !             printf("          ENTER - read the selected thread from the begining\n\n");
  2964. !             printf("          p     - post article in selected newsgroup\n");
  2965. !             printf("          c     - mark all articles in this newsgroup as read\n");
  2966. !             printf("          s     - save thread to disk\n");
  2967.               break;
  2968.   
  2969.           case HELP_ARTICLES:
  2970. !             printf("          TAB   - go to next unread article\n");
  2971. !             printf("          ENTER - go to next article in thread\n\n");
  2972. !             printf("          p     - Post article in selected newsgroup\n");
  2973. !             printf("          f     - post Followup to this article\n\n");
  2974. !             printf("          r     - mail a Reply to this article\n\n");
  2975. !             printf("          m     - mail this article to someone\n\n");
  2976. !             printf("          c     - mark all articles in this newsgroup as read\n");
  2977. !             printf("          s     - save article to disk\n");
  2978.               break;
  2979.       };
  2980.   
  2981.       message("-- Press any key to continue --");
  2982.       getch();
  2983.   
  2984. --- 210,291 ----
  2985.   
  2986.   
  2987.   /*---------------------------- help screen ----------------------------------*/
  2988. ! void help(char *text)
  2989.   {
  2990. +     printf("%*s", _columns / 2 - 40, "");
  2991.   
  2992. !     while (*text) {
  2993. !         if (*text == '\n')
  2994. !             clreol(), _line++;
  2995. !         putch(*text++);
  2996. !     }
  2997. ! }
  2998.   
  2999. ! void show_help(int h)
  3000. ! {
  3001. !     char *type[] = {"Group Help",  "Thread Help",  "Article Help"};
  3002. !     char *msg = COPYRIGHT;
  3003. !     int x;
  3004. !     gotoxy(1,1);
  3005.       textbackground(LIGHTGRAY);  textcolor(BLACK);
  3006. +     printf("%-18s %*s", type[h], _columns - 19, VERSION);
  3007. +     gotoxy(1,2);
  3008. +     x = _columns / 2 - strlen(msg) / 2;
  3009. +     printf("%*s%s", x, "", msg);
  3010.       clreol();
  3011.       textbackground(BLACK);  textcolor(LIGHTGRAY);
  3012. +     putch('\n');
  3013.   
  3014. !     help("\n");
  3015. !     help("         PageUp - move display up one page\n");
  3016. !     help("         PageDn - move display down one page\n");
  3017. !     help("           Home - move to top of list/article\n");
  3018. !     help("            End - move to bottom of list/article\n");
  3019. !     help("             Up - move up one line\n");
  3020. !     help("           Down - move down one line\n");
  3021.   
  3022.       switch (h) {
  3023.           case HELP_GROUP   :
  3024. !             help("\n");
  3025. !             help("            Tab - go to next newgroup with unread articles\n");
  3026. !             help("          Enter - enter selected newsgroup\n\n");
  3027. !             help("              c - mark all articles in selected group as read\n");
  3028. !             help("              p - post article to selected group\n");
  3029.               break;
  3030.   
  3031.           case HELP_THREAD  :
  3032. !             help("\n");
  3033. !             help("            Tab - go to next thread with unread articles or\n");
  3034. !             help("                  enter this thread if it is already selected\n");
  3035. !             help("                  and move to the first unread article in the thread\n");
  3036. !             help("          Enter - read the selected thread from the beginning\n");
  3037. !             help("      Backspace - go to the last article in the selected thread\n\n");
  3038. !             help("              c - mark all articles in selected thread as read\n");
  3039. !             help("              s - save selected thread to disk\n");
  3040. !             help("              p - post article to this group\n\n");
  3041. !         help("              + - search for text in subjects\n");
  3042. !         help("              / - search for text in article bodies\n");
  3043.               break;
  3044.   
  3045.           case HELP_ARTICLES:
  3046. !             help("           Left - scroll right\n");
  3047. !             help("          Right - scroll left\n\n");
  3048. !             help("            Tab - go to next unread article\n");
  3049. !             help("          Enter - go to next article in thread\n");
  3050. !             help("      Backspace - go to previous article in thread\n\n");
  3051. !             help("              s - save this article to disk\n");
  3052. !             help("              p - post new article to current group\n");
  3053. !             help("              f - post follow-up to this article\n");
  3054. !             help("              r - reply to sender of this article via e-mail\n");
  3055. !             help("              m - mail this article to someone\n");
  3056. !         help("            + / - search for text in following articles\n");
  3057. !         help("            - ? - search for text in preceding articles\n");
  3058.               break;
  3059.       };
  3060.   
  3061. +     clreos();
  3062.       message("-- Press any key to continue --");
  3063.       getch();
  3064.   
  3065. ***************
  3066. *** 251,257 ****
  3067.   
  3068.   
  3069.   /*-------------------- show the list of active groups -----------------------*/
  3070. ! void show_groups(ACTIVE **top, ACTIVE *this, int force)
  3071.   {
  3072.       /*
  3073.        *  This routine takes 'top', a pointer to the first line on the screen
  3074. --- 295,301 ----
  3075.   
  3076.   
  3077.   /*-------------------- show the list of active groups -----------------------*/
  3078. ! void show_groups(ACTIVE **top, ACTIVE *this, int force, ACTIVE *head)
  3079.   {
  3080.       /*
  3081.        *  This routine takes 'top', a pointer to the first line on the screen
  3082. ***************
  3083. *** 264,269 ****
  3084. --- 308,314 ----
  3085.       static last_index;
  3086.       int    i, ur;
  3087.       ACTIVE *that;
  3088. +     char buf[32];
  3089.   
  3090.       /*
  3091.        *  If 'this' is above the 'top' or it is more than a screen length below,
  3092. ***************
  3093. *** 276,289 ****
  3094.           ((*top)->index > this->index) ||
  3095.           (this->index - (*top)->index) > PAGE_LENGTH-1) {
  3096.   
  3097. !         clrscr();
  3098.           textbackground(LIGHTGRAY);  textcolor(BLACK);
  3099. !         clreol();
  3100. !         cprintf("                         Select Newsgroup  (%s)  [%ldk]\r\n",
  3101. !                VERSION,  farcoreleft()/1000);
  3102.           clreol();
  3103. -         cprintf("\r\n");
  3104. -         clreol();
  3105.           textbackground(BLACK);  textcolor(LIGHTGRAY);
  3106.   
  3107.           /* now adjust the top */
  3108. --- 321,332 ----
  3109.           ((*top)->index > this->index) ||
  3110.           (this->index - (*top)->index) > PAGE_LENGTH-1) {
  3111.   
  3112. !         gotoxy(1,1);
  3113.           textbackground(LIGHTGRAY);  textcolor(BLACK);
  3114. !         sprintf(buf, "Group %d of %d", last_index + 1, head->groups);
  3115. !         printf("Select Group %*s", _columns - 13, buf);
  3116. !     gotoxy(1,2);
  3117.           clreol();
  3118.           textbackground(BLACK);  textcolor(LIGHTGRAY);
  3119.   
  3120.           /* now adjust the top */
  3121. ***************
  3122. *** 294,333 ****
  3123.           }
  3124.   
  3125.           that = *top;
  3126. !         for (i = 0; i < PAGE_LENGTH; i++) {
  3127.               ur = count_unread_in_group(that);
  3128. !             gotoxy(7, i+4);
  3129. !             printf("%4d. %-50s", ((*top)->index)+i, that->group);
  3130. !             if (ur == 0)
  3131. !                 printf("     ", ur);
  3132.               else
  3133. !                 printf(" %4d", ur);
  3134. !             printf(" (%d)\n", that->hi_num - that->lo_num);
  3135.               that = that->next;
  3136. -             if (that == NULL) break;
  3137.           }
  3138.   
  3139.           last_y = this->index - (*top)->index;
  3140. !         gotoxy(5, last_y + PAGE_HEADER);
  3141. !         putch('>');
  3142.           last_index = this->index;
  3143.   
  3144.       } else {
  3145.   
  3146. !         gotoxy(5, last_y + PAGE_HEADER);
  3147. !         putch(' ');
  3148.   
  3149.           last_y += (this->index - last_index);
  3150. !         gotoxy(5, last_y + PAGE_HEADER);
  3151. !         putch('>');
  3152.           last_index = this->index;
  3153.   
  3154.       }
  3155.   
  3156. !     command("ESC=quit   TAB=next unread group   ENTER=read group   '?'=help");
  3157. ! }
  3158.   
  3159.   
  3160.   
  3161.   /*--------------------------- process message -------------------------------*/
  3162. --- 337,382 ----
  3163.           }
  3164.   
  3165.           that = *top;
  3166. !         for (i = 0; i < PAGE_LENGTH+1; i++) {
  3167. !             gotoxy(1, i+PAGE_HEADER);
  3168. !             if (that == NULL) break;
  3169.               ur = count_unread_in_group(that);
  3170. !             if (ur > 0)
  3171. !                 printf("    %4d %4ld %s", ur,
  3172. !                        that->hi_num - that->lo_num, that->group);
  3173.               else
  3174. !                 printf("         %4ld %s",
  3175. !                        that->hi_num - that->lo_num, that->group);
  3176. !             clreol();
  3177.               that = that->next;
  3178.           }
  3179.   
  3180. +         clreos();
  3181.           last_y = this->index - (*top)->index;
  3182. !         gotoxy(2, last_y + PAGE_HEADER);
  3183. !         puts("->");
  3184.           last_index = this->index;
  3185.   
  3186.       } else {
  3187.   
  3188. !         gotoxy(2, last_y + PAGE_HEADER);
  3189. !         puts("  ");
  3190.   
  3191.           last_y += (this->index - last_index);
  3192. !         gotoxy(2, last_y + PAGE_HEADER);
  3193. !         puts("->");
  3194.           last_index = this->index;
  3195.   
  3196.       }
  3197.   
  3198. !     gotoxy(_columns - 16,1);
  3199. !     textbackground(LIGHTGRAY);  textcolor(BLACK);
  3200. !     sprintf(buf, "Group %d of %d", last_index + 1, head->groups);
  3201. !     printf("%17s", buf);
  3202. !     textbackground(BLACK);  textcolor(LIGHTGRAY);
  3203.   
  3204. +     message("ESC=quit   TAB=next unread group   ENTER=read group   F1=help");
  3205. + }
  3206.   
  3207.   
  3208.   /*--------------------------- process message -------------------------------*/
  3209. ***************
  3210. *** 341,356 ****
  3211.       ARTICLE *start;
  3212.   
  3213.       if (gp->lo_num < gp->hi_num) {
  3214. -         clrscr();
  3215. -         printf("                   Select Thread  (%s)  [%ldk]\n", VERSION,
  3216. -                farcoreleft()/1000);
  3217. -         printf("Group: %s ", gp->group);
  3218.           start = get_headers(gp);
  3219.           select_thread(gp, start);
  3220.           free_header(start);
  3221.       }
  3222.   
  3223. --- 390,397 ----
  3224. ***************
  3225. *** 359,365 ****
  3226.   
  3227.   
  3228.   /*-------------------- show the list of active groups -----------------------*/
  3229. ! void show_threads(ACTIVE *gp, ARTICLE **top, ARTICLE *this, int force)
  3230.   {
  3231.       /*
  3232.        *  This routine takes 'top', a pointer to the first line on the screen
  3233. --- 400,407 ----
  3234.   
  3235.   
  3236.   /*-------------------- show the list of active groups -----------------------*/
  3237. ! void show_threads(ACTIVE *gp, ARTICLE **top, ARTICLE *this, int force,
  3238. !                   ARTICLE *head)
  3239.   {
  3240.       /*
  3241.        *  This routine takes 'top', a pointer to the first line on the screen
  3242. ***************
  3243. *** 372,378 ****
  3244.       static last_index;
  3245.       int    i;
  3246.       ARTICLE *that;
  3247. !     int    unread;
  3248.   
  3249.       /*
  3250.        *  If 'this' is above the 'top' or it is more than a screen length below,
  3251. --- 414,421 ----
  3252.       static last_index;
  3253.       int    i;
  3254.       ARTICLE *that;
  3255. !     int    ur;
  3256. !     char buf[32];
  3257.   
  3258.       /*
  3259.        *  If 'this' is above the 'top' or it is more than a screen length below,
  3260. ***************
  3261. *** 385,398 ****
  3262.           ((*top)->index > this->index) ||
  3263.           (this->index - (*top)->index) > PAGE_LENGTH-1) {
  3264.   
  3265. !         clrscr();
  3266.           textbackground(LIGHTGRAY);  textcolor(BLACK);
  3267. !         clreol();
  3268. !         cprintf("                  Select Thread  (%s) [%ldk]\r\n", VERSION,
  3269. !                farcoreleft()/1000);
  3270. !         clreol();
  3271. !         cprintf("Group: %s\r\n", gp->group);
  3272. !         clreol();
  3273.           textbackground(BLACK);  textcolor(LIGHTGRAY);
  3274.   
  3275.           /* now adjust the top */
  3276. --- 428,445 ----
  3277.           ((*top)->index > this->index) ||
  3278.           (this->index - (*top)->index) > PAGE_LENGTH-1) {
  3279.   
  3280. !         for (that = head, ur = 0; that; that = that->next)
  3281. !             ur += count_unread_in_thread(gp, that);
  3282. !         gotoxy(1,1);
  3283.           textbackground(LIGHTGRAY);  textcolor(BLACK);
  3284. !         sprintf(buf, "Thread %d of %d", last_index + 1, gp->threads);
  3285. !         printf("Select Thread %*s", _columns - 14, buf);
  3286. !     gotoxy(1,2);
  3287. !         sprintf(buf, "%ld Articles, %d unread",
  3288. !                 gp->hi_num - gp->lo_num, ur);
  3289. !         printf("Group: %-*.*s %26s", _columns - 34, _columns - 34,
  3290. !                gp->group, buf);
  3291.           textbackground(BLACK);  textcolor(LIGHTGRAY);
  3292.   
  3293.           /* now adjust the top */
  3294. ***************
  3295. *** 403,452 ****
  3296.           }
  3297.   
  3298.           that = *top;
  3299. !         for (i = 0; i < PAGE_LENGTH; i++) {
  3300. !             unread = count_unread_in_thread(gp, that),
  3301. !             gotoxy(7, i+4);
  3302. !             if (unread > 0) {
  3303. !                 printf("%4d. %4d %4d %s", ((*top)->index)+i,
  3304. !                        unread,
  3305.                          that->num_articles, that->header);
  3306. !             } else {
  3307. !                 printf("%4d.      %4d %s", ((*top)->index)+i,
  3308.                          that->num_articles, that->header);
  3309. !             }
  3310.               that = that->next;
  3311. -             if (that == NULL) break;
  3312.           }
  3313.   
  3314.           last_y = this->index - (*top)->index;
  3315. !         gotoxy(5, last_y + PAGE_HEADER);
  3316. !         putch('>');
  3317.           last_index = this->index;
  3318.   
  3319.       } else {
  3320.   
  3321. !         gotoxy(5, last_y + PAGE_HEADER);
  3322. !         putch(' ');
  3323.   
  3324.           last_y += (this->index - last_index);
  3325. !         gotoxy(5, last_y + PAGE_HEADER);
  3326. !         putch('>');
  3327.           last_index = this->index;
  3328.   
  3329.       }
  3330.   
  3331. !     command("ESC=select group   TAB=next unread   ENTER=next article   '?'=help");
  3332.   }
  3333.   
  3334.   
  3335.   
  3336.   
  3337. ! /*-------------------------- find which group to read -----------------------*/
  3338.   void select_thread(ACTIVE *gp, ARTICLE *head)
  3339.   {
  3340.       /*
  3341.        *  Present the list of threads, and allow him to move up and down with
  3342. !      *  the arrow and PgUp and PgDn keys.  'h' for help, -/+ for searches
  3343.        */
  3344.   
  3345.       ARTICLE *top;        /* thread at the top of the page    */
  3346. --- 450,589 ----
  3347.           }
  3348.   
  3349.           that = *top;
  3350. !         for (i = 0; i < PAGE_LENGTH+1; i++) {
  3351. !             gotoxy(1, i+PAGE_HEADER);
  3352. !             if (that == NULL) break;
  3353. !             ur = count_unread_in_thread(gp, that);
  3354. !             if (ur > 0)
  3355. !                 printf("    %4d %4d  %s", ur,
  3356.                          that->num_articles, that->header);
  3357. !             else
  3358. !                 printf("         %4d  %s",
  3359.                          that->num_articles, that->header);
  3360. !             clreol();
  3361.               that = that->next;
  3362.           }
  3363.   
  3364. +         clreos();
  3365.           last_y = this->index - (*top)->index;
  3366. !         gotoxy(2, last_y + PAGE_HEADER);
  3367. !         puts("->");
  3368.           last_index = this->index;
  3369.   
  3370.       } else {
  3371.   
  3372. !         gotoxy(2, last_y + PAGE_HEADER);
  3373. !         puts("  ");
  3374.   
  3375.           last_y += (this->index - last_index);
  3376. !         gotoxy(2, last_y + PAGE_HEADER);
  3377. !         puts("->");
  3378.           last_index = this->index;
  3379.   
  3380. +         gotoxy(_columns - 17,1);
  3381. +         textbackground(LIGHTGRAY);  textcolor(BLACK);
  3382. +         sprintf(buf, "Thread %d of %d", last_index + 1, gp->threads);
  3383. +         printf("%18s", buf);
  3384. +         textbackground(BLACK);  textcolor(LIGHTGRAY);
  3385.       }
  3386.   
  3387. !     message("ESC=select group   TAB=next unread   ENTER=next article   F1=help");
  3388.   }
  3389.   
  3390.   
  3391.   
  3392. + /*--------------- search through threads ------------------------------------*/
  3393. + ARTICLE *search_thread(ACTIVE *gp, ARTICLE *head, int search_body)
  3394. + {
  3395. +     int offset = 0, found = FALSE, irq = FALSE;
  3396. +     ARTICLE *this;
  3397. +     ART_ID *art;
  3398. +     TEXT *tx;
  3399. +     LINE *text;
  3400. +     char *fn;
  3401. +     char prompt[128], pattern[128];
  3402. +     if (head == NULL || head->next == NULL)
  3403. +       return head;
  3404.   
  3405. !     sprintf(prompt, "Search %s for? [%s] ",
  3406. !         search_body ? "articles" : "subjects", search_text);
  3407. !     lmessage(prompt);
  3408. !     if (gets(pattern) == NULL)
  3409. !       return head;
  3410. !     if (strlen(pattern) > 0)
  3411. !       strcpy(search_text, pattern);
  3412. !     else
  3413. !       strcpy(pattern, search_text);
  3414. !     strlwr(pattern);
  3415. !     if (search_body) {
  3416. !     message("*** searching - please wait (press ESC to abort) ***");
  3417. !     tflush();
  3418. !     for (this = head->next; this != NULL; this = this->next) {
  3419. !         /* for each article */
  3420. !         for (art = this->art_num; art != NULL; art = art->next_art) {
  3421. !         
  3422. !         fn = make_news_group_name(gp->group);
  3423. !         tx = load_article(fn, art->art_off);
  3424. !         for (text = tx->start; !found && text != NULL; 
  3425. !              text = text->next) {
  3426. !             strlwr(text->data);
  3427. !             found = (strstr(text->data, pattern) != NULL);
  3428. !         }
  3429. !     
  3430. !         free_article(tx);
  3431. !         if (kbhit())
  3432. !           irq = (getch() == 27);
  3433. !         if (found || irq)
  3434. !           break;
  3435. !         }
  3436. !         if (found || irq) 
  3437. !           break;
  3438. !     }
  3439. !     } else {
  3440. !     for (this = head->next; this != NULL; this = this->next) {
  3441. !         strcpy(prompt, this->header);
  3442. !         strlwr(prompt);
  3443. !         found = (strstr(prompt, pattern) != NULL);
  3444. !         if (found)
  3445. !           break;
  3446. !     }
  3447. !     }
  3448. !     if (!found && !irq) {
  3449. !     sprintf(prompt, "*** '%s' not found - press any key  ***", pattern);
  3450. !     message(prompt);
  3451. !     getch();
  3452. !     }
  3453. !     return found ? this : head;
  3454. ! }
  3455. ! /*-------------------------- find which thread to read ----------------------*/
  3456.   void select_thread(ACTIVE *gp, ARTICLE *head)
  3457.   {
  3458.       /*
  3459.        *  Present the list of threads, and allow him to move up and down with
  3460. !      *  the arrow and PgUp and PgDn keys.
  3461.        */
  3462.   
  3463.       ARTICLE *top;        /* thread at the top of the page    */
  3464. ***************
  3465. *** 454,469 ****
  3466.       ARTICLE *th;
  3467.       ART_ID  *art;
  3468.       int    exit_code;    /* why we are exiting the loop      */
  3469. -     char   sub_tmp[80];
  3470.   
  3471.       int    ch, i, idx, hit, a_ct;
  3472.   
  3473.       this = head;
  3474.       top = head;
  3475.       exit_code = 0;
  3476.   
  3477. !     show_threads(gp, &top, this, TRUE);
  3478.   
  3479.       while (exit_code == 0) {
  3480.   
  3481. --- 591,604 ----
  3482.       ARTICLE *th;
  3483.       ART_ID  *art;
  3484.       int    exit_code;    /* why we are exiting the loop      */
  3485.   
  3486.       int    ch, i, idx, hit, a_ct;
  3487.   
  3488.       this = head;
  3489.       top = head;
  3490.       exit_code = 0;
  3491.   
  3492. !     show_threads(gp, &top, this, TRUE, head);
  3493.   
  3494.       while (exit_code == 0) {
  3495.   
  3496. ***************
  3497. *** 471,480 ****
  3498. --- 606,621 ----
  3499.           switch (ch) {
  3500.   
  3501.               case 0      :
  3502. +             case 0xE0   :
  3503.                   ch = getch();
  3504.   
  3505.                   switch (ch) {
  3506.   
  3507. +                     case F1     :
  3508. +                     show_help(HELP_THREAD);
  3509. +                     show_threads(gp, &top, this, TRUE, head);
  3510. +                         break;
  3511. +                         
  3512.                       case UP_ARR :
  3513.                           if (this->last != NULL) this = this->last;
  3514.                           break;
  3515. ***************
  3516. *** 499,505 ****
  3517.   
  3518.                       case HOME   :
  3519.                           top = this = head;
  3520. !                         show_threads(gp, &top, this, TRUE);
  3521.                           break;
  3522.                       case END    :
  3523.                           this = head;
  3524. --- 640,646 ----
  3525.   
  3526.                       case HOME   :
  3527.                           top = this = head;
  3528. !                         show_threads(gp, &top, this, TRUE, head);
  3529.                           break;
  3530.                       case END    :
  3531.                           this = head;
  3532. ***************
  3533. *** 510,527 ****
  3534.                   break;
  3535.   
  3536.               case 's'    :
  3537.                   save_thread_to_disk(gp, this);
  3538.                   break;
  3539.   
  3540.               case 'p'    :
  3541. !                 strcpy(sub_tmp, "");
  3542. !                 post(NULL, gp->group, sub_tmp);
  3543. !                 show_threads(gp, &top, this, TRUE);
  3544.                   break;
  3545.   
  3546. -             case '?'    :
  3547.               case 'h'    :
  3548.                   show_help(HELP_THREAD);
  3549.                   break;
  3550.   
  3551.               case TAB    :
  3552. --- 651,670 ----
  3553.                   break;
  3554.   
  3555.               case 's'    :
  3556. +             case 'S'    :
  3557.                   save_thread_to_disk(gp, this);
  3558.                   break;
  3559.   
  3560.               case 'p'    :
  3561. !             case 'P'    :
  3562. !                 post(NULL, gp->group);
  3563. !                 show_threads(gp, &top, this, TRUE, head);
  3564.                   break;
  3565.   
  3566.               case 'h'    :
  3567. +             case 'H'    :
  3568.                   show_help(HELP_THREAD);
  3569. +                 show_threads(gp, &top, this, TRUE, head);
  3570.                   break;
  3571.   
  3572.               case TAB    :
  3573. ***************
  3574. *** 554,575 ****
  3575.                   }
  3576.   
  3577.                   if (hit) {
  3578. !                     this = th;
  3579.                       read_thread(gp, this, art, a_ct);
  3580. !                     show_threads(gp, &top, this, TRUE);
  3581. !                 } else {
  3582. !                     message("-- No more articles to read --");
  3583.                   }
  3584.                   break;
  3585.   
  3586.               case 'c'    :
  3587. !                 mark_group_as_read(gp);
  3588. !                 show_threads(gp, &top, this, TRUE);
  3589.                   break;
  3590.   
  3591.               case ENTER  :
  3592.                   read_thread(gp, this, this->art_num, 1);
  3593. !                 show_threads(gp, &top, this, TRUE);
  3594.                   break;
  3595.   
  3596.               case ESCAPE :
  3597. --- 697,735 ----
  3598.                   }
  3599.   
  3600.                   if (hit) {
  3601. !                     if (this == th )
  3602.                           read_thread(gp, this, art, a_ct);
  3603. !                     this = th;
  3604. !                     show_threads(gp, &top, this, TRUE, head);
  3605.                   }
  3606.                   break;
  3607.   
  3608.               case 'c'    :
  3609. !             case 'C'    :
  3610. !                 mark_thread_as_read(gp, this);
  3611. !                 show_threads(gp, &top, this, TRUE, head);
  3612.                   break;
  3613.   
  3614.               case ENTER  :
  3615.                   read_thread(gp, this, this->art_num, 1);
  3616. !                 show_threads(gp, &top, this, TRUE, head);
  3617. !                 break;
  3618. !             case BACKSP :
  3619. !             art = this->art_num;
  3620. !         a_ct = 1;
  3621. !         while (art->next_art != NULL) {
  3622. !             a_ct++;
  3623. !             art = art->next_art;
  3624. !         }
  3625. !                 read_thread(gp, this, art, a_ct);
  3626. !                 show_threads(gp, &top, this, TRUE, head);
  3627. !                 break;
  3628. !         case '+'    :
  3629. !         case '/'    :
  3630. !             this = search_thread(gp, this, ch == '/');
  3631. !                 show_threads(gp, &top, this, TRUE, head);
  3632.                   break;
  3633.   
  3634.               case ESCAPE :
  3635. ***************
  3636. *** 577,583 ****
  3637.                   break;
  3638.           };
  3639.           if (exit_code == 0)
  3640. !             show_threads(gp, &top, this, FALSE);
  3641.       }
  3642.   
  3643.   
  3644. --- 737,743 ----
  3645.                   break;
  3646.           };
  3647.           if (exit_code == 0)
  3648. !             show_threads(gp, &top, this, FALSE, head);
  3649.       }
  3650.   
  3651.   
  3652. ***************
  3653. *** 586,592 ****
  3654.   
  3655.   
  3656.   
  3657. ! /*------------------------ read a thread ------------------------------*/
  3658.   void save_thread_to_disk(ACTIVE *gp, ARTICLE *this)
  3659.   {
  3660.       ART_ID *id;
  3661. --- 746,761 ----
  3662.   
  3663.   
  3664.   
  3665. ! /*------------------------ save a thread ------------------------------*/
  3666. ! int cmp(TEXT **art1, TEXT **art2)
  3667. ! {
  3668. !     char *subj1 = (*art1) -> subject, *subj2 = (*art2) -> subject;
  3669. !     while (isspace(*subj1)) subj1++;
  3670. !     while (isspace(*subj2)) subj2++;
  3671. !     return strcmp(subj1, subj2);
  3672. ! }
  3673.   void save_thread_to_disk(ACTIVE *gp, ARTICLE *this)
  3674.   {
  3675.       ART_ID *id;
  3676. ***************
  3677. *** 593,607 ****
  3678.       char   *fn;
  3679.       TEXT   *tx;
  3680.       LINE   *ln;
  3681. !     int    a_ct;
  3682. !     char   fnx[80];
  3683. !     int    ch;
  3684. !     FILE   *tmp;
  3685.       
  3686. !     message("Enter filename? ");
  3687.       gets(fnx);
  3688.   
  3689. -     tmp = NULL;
  3690.       if (access(fnx, 0) == 0) {
  3691.   
  3692.           message("File exists - append(y/n)? ");
  3693. --- 762,778 ----
  3694.       char   *fn;
  3695.       TEXT   *tx;
  3696.       LINE   *ln;
  3697. !     char   fnx[256];
  3698. !     int    ch, art, idx;
  3699. !     TEXT   *text[MAXART];
  3700. !     FILE   *tmp = NULL;
  3701. !     time_t now;
  3702. !     struct tm *tmnow;
  3703. !     char timestr[64];
  3704.       
  3705. !     lmessage("Enter filename? ");
  3706.       gets(fnx);
  3707.   
  3708.       if (access(fnx, 0) == 0) {
  3709.   
  3710.           message("File exists - append(y/n)? ");
  3711. ***************
  3712. *** 608,615 ****
  3713.           while (((ch = getch()) != 'y') && (ch != 'n'));
  3714.           if (ch == 'y') {
  3715.               if ((tmp = fopen(fnx, "at")) == NULL) {
  3716. !                 message("*** Cannot open file for appending - "
  3717. !                         "please any key to continue ***");
  3718.                   getch();
  3719.               }
  3720.           }
  3721. --- 779,786 ----
  3722.           while (((ch = getch()) != 'y') && (ch != 'n'));
  3723.           if (ch == 'y') {
  3724.               if ((tmp = fopen(fnx, "at")) == NULL) {
  3725. !                 message("*** cannot open file for appending - "
  3726. !                         "please any key ***");
  3727.                   getch();
  3728.               }
  3729.           }
  3730. ***************
  3731. *** 617,641 ****
  3732.       } else {
  3733.   
  3734.           if ((tmp = fopen(fnx, "wt")) == NULL) {
  3735. !             message("*** Cannot open file for output - press a key to continue ***");
  3736.               getch();
  3737.           }
  3738.   
  3739.       }
  3740.   
  3741.       if (tmp != NULL) {
  3742.   
  3743.           fn = make_news_group_name(gp->group);
  3744.   
  3745.           id = this->art_num;
  3746. !         a_ct = 0;
  3747.       
  3748. !         while (id != NULL) {
  3749.   
  3750. !             tx = load_article(fn, id->art_off);
  3751.           
  3752.               ln = tx->top;
  3753.               while (ln != NULL) {
  3754. --- 788,830 ----
  3755.       } else {
  3756.   
  3757.           if ((tmp = fopen(fnx, "wt")) == NULL) {
  3758. !             message("*** cannot open file for output - press any key ***");
  3759.               getch();
  3760.           }
  3761.       
  3762. +     setvbuf(tmp, iobuf, _IOFBF, IOBUFSIZE);
  3763.       }
  3764.   
  3765.       if (tmp != NULL) {
  3766.   
  3767.           fn = make_news_group_name(gp->group);
  3768.   
  3769.           id = this->art_num;
  3770. !     idx = 0;
  3771.       
  3772. !         while (id != NULL && idx < MAXART) {
  3773. !         text[idx++] = load_article(fn, id->art_off);
  3774. !             id = id->next_art;
  3775. !         }
  3776.   
  3777. !     qsort(text, idx, sizeof(TEXT *), cmp);
  3778. !     
  3779. !         time(&now);
  3780. !     tmnow = localtime(&now);
  3781. !     strftime(timestr, sizeof(timestr), "%a %b %d %H:%M:%S %z %Y", tmnow);
  3782. !     for ( art = 0; art < idx; art++ ) {
  3783. !         
  3784. !             tx = text[art];
  3785. !         ln = tx->top;
  3786. !         while (ln != NULL && strncmp(ln->data, "Path: ", 6)) {
  3787. !              ln = ln->next;
  3788. !         }
  3789. !         strcpy(fn, ln->data + 6);
  3790. !         for ( ch = strlen(fn); fn[ch - 1] == '\n' || fn[ch - 1] == '\r'; ch--)
  3791. !             fn[ch - 1] = 0;
  3792. !         fprintf(tmp, "From %s %s\n", fn, timestr);
  3793.   
  3794.               ln = tx->top;
  3795.               while (ln != NULL) {
  3796. ***************
  3797. *** 642,664 ****
  3798.                   fputs(ln->data, tmp);
  3799.                   ln = ln->next;
  3800.               }
  3801.               fputs("\n\n", tmp);
  3802.   
  3803. !             a_ct++;
  3804. !             id = id->next_art;
  3805.   
  3806.               free_article(tx);
  3807.   
  3808.       }
  3809.       
  3810. !         fclose(tmp);
  3811.       }
  3812.   
  3813. !     message("");
  3814.   }
  3815.   
  3816.   
  3817.   /*------------------------ read a thread ------------------------------*/
  3818.   int read_thread(ACTIVE *gp, ARTICLE *this, ART_ID *first, int a_ct)
  3819.   {
  3820. --- 831,898 ----
  3821.                   fputs(ln->data, tmp);
  3822.                   ln = ln->next;
  3823.               }
  3824.               fputs("\n\n", tmp);
  3825. +             free_article(tx);
  3826. +     }
  3827.       
  3828. !         fclose(tmp);
  3829. !     }
  3830. ! }
  3831.   
  3832. + /*------------------------ search through articles --------------------*/
  3833. + int search_message(char *fn, ART_ID *current, int forward)
  3834. + {
  3835. +     int offset = 0, found = FALSE;
  3836. +     TEXT *tx;
  3837. +     LINE *text;
  3838. +     char prompt[128], pattern[128];
  3839. +     sprintf(prompt, "Search %s for? [%s] ",
  3840. +         forward ? "forward" : "backward", search_text);
  3841. +     lmessage(prompt);
  3842. +     if (gets(pattern) == NULL)
  3843. +       return 0;
  3844. +     if (strlen(pattern) > 0)
  3845. +       strcpy(search_text, pattern);
  3846. +     else
  3847. +       strcpy(pattern, search_text);
  3848. +     strlwr(pattern);
  3849. +     for (;;) {
  3850. +     current = forward ? current->next_art : current->last_art;
  3851. +     if (current == NULL)
  3852. +       break;
  3853. +     offset++;
  3854. +         tx = load_article(fn, current->art_off);
  3855. +     for (text = tx->start; !found && text != NULL; text = text->next) {
  3856. +         strlwr(text->data);
  3857. +         found = (strstr(text->data, pattern) != NULL);
  3858. +     }
  3859. +     
  3860.           free_article(tx);
  3861.   
  3862. +     if (found)
  3863. +       break;
  3864.       }
  3865.   
  3866. !     if (!found) {
  3867. !     sprintf(prompt, "*** '%s' not found - press any key  ***", pattern);
  3868. !     message(prompt);
  3869. !     getch();
  3870.       }
  3871.   
  3872. !     return found ? offset : 0;
  3873.   }
  3874.   
  3875.   
  3876.   /*------------------------ read a thread ------------------------------*/
  3877.   int read_thread(ACTIVE *gp, ARTICLE *this, ART_ID *first, int a_ct)
  3878.   {
  3879. ***************
  3880. *** 679,689 ****
  3881.   
  3882.           tx = load_article(fn, id->art_off);
  3883.   
  3884. !         res = read_article(gp, tx, this->header, a_ct, this->num_articles);
  3885.   
  3886.           /* mark this article as read */
  3887.           idx = (int) ((id->id) - gp->lo_num - 1);
  3888. !         *((gp->read_list)+idx) = TRUE;
  3889.   
  3890.           /* mark the crossposts */
  3891.           get_his_stuff(tx, author, msg_id);
  3892. --- 913,923 ----
  3893.   
  3894.           tx = load_article(fn, id->art_off);
  3895.   
  3896. !         res = read_article(gp, tx, a_ct, this->num_articles);
  3897.   
  3898.           /* mark this article as read */
  3899.           idx = (int) ((id->id) - gp->lo_num - 1);
  3900. !         (gp->read_list)[idx] = TRUE;
  3901.   
  3902.           /* mark the crossposts */
  3903.           get_his_stuff(tx, author, msg_id);
  3904. ***************
  3905. *** 693,699 ****
  3906.               while (h != NULL) {
  3907.                   gx = find_news_group(h->group);
  3908.                   idx = (int) ((h->art_num) - gx->lo_num - 1);
  3909. !                 *((gx->read_list)+idx) = TRUE;
  3910.                   h = h->next;
  3911.               }
  3912.   
  3913. --- 927,934 ----
  3914.               while (h != NULL) {
  3915.                   gx = find_news_group(h->group);
  3916.                   idx = (int) ((h->art_num) - gx->lo_num - 1);
  3917. !                 if ( 0 <= idx && idx < gx->hi_num )
  3918. !                   (gx->read_list)[idx] = TRUE;
  3919.                   h = h->next;
  3920.               }
  3921.   
  3922. ***************
  3923. *** 700,705 ****
  3924. --- 935,942 ----
  3925.               free_cross_post_list(h0);
  3926.           }
  3927.   
  3928. +         free_article(tx);
  3929.           if (res == EX_QUIT) break;
  3930.   
  3931.           if (res == EX_NEXT_UNREAD) {
  3932. ***************
  3933. *** 713,728 ****
  3934.                   id = id->next_art;
  3935.               }
  3936.   
  3937. !             if (id == NULL)
  3938. !                 message("-- No more articles in thread --");
  3939.           } else {
  3940.               a_ct++;
  3941.               id = id->next_art;
  3942.           }
  3943. -         free_article(tx);
  3944.       }
  3945.   
  3946.       return(res);
  3947. --- 950,974 ----
  3948.                   id = id->next_art;
  3949.               }
  3950.   
  3951. !         } else if (res == EX_SEARCH_FORW) {
  3952. !         res = search_message(fn, id, 1);
  3953. !         while (res--) {
  3954. !         a_ct++;
  3955. !                 id = id->next_art;
  3956. !         }
  3957. !         } else if (res == EX_SEARCH_BACKW) {
  3958. !         res = search_message(fn, id, 0);
  3959. !         while (res--) {
  3960. !         a_ct--;
  3961. !         id = id->last_art;
  3962. !         }
  3963. !         } else if (res == EX_PREVIOUS) {
  3964. !             a_ct--;
  3965. !             id = id->last_art;
  3966.           } else {
  3967.               a_ct++;
  3968.               id = id->next_art;
  3969.           }
  3970.       }
  3971.   
  3972.       return(res);
  3973. ***************
  3974. *** 732,737 ****
  3975. --- 978,1114 ----
  3976.   
  3977.   
  3978.   /*------------------------- read the headers --------------------------*/
  3979. + int strip_off_part(char *str)
  3980. + {
  3981. +   char *ptr = str + strlen(str);
  3982. +   /* strip off (case-insensitive) things like:
  3983. +      - "Part01/10"
  3984. +      - "Part 01/10"
  3985. +      - "Part 01 of 10"
  3986. +      - "[1/10]"
  3987. +      - "(1 of 10)"
  3988. +      - "1 of 10"
  3989. +      - "Patch02a/04"
  3990. +      - "Patch20"
  3991. +    */
  3992. +   while ( ptr > str && ptr[-1] == ' ' )
  3993. +     ptr--;
  3994. +   if ( ptr > str && (ptr[-1] == ')' || ptr[-1] == ']') )
  3995. +     ptr--;
  3996. +   while ( ptr > str && isdigit(ptr[-1]) )
  3997. +     ptr--;
  3998. +   if ( !isdigit(*ptr) )
  3999. +     return 0;
  4000. +   if ( ptr > str && ptr[-1] == '/' )
  4001. +     ptr--;
  4002. +   else if ( ptr > str + 3 && strnicmp(ptr - 4, " of ", 4) == 0 )
  4003. +     ptr -= 4;
  4004. +   else if ( ptr > str + 4 && strnicmp(ptr - 5, "Patch", 5) == 0 )
  4005. +   {
  4006. +     ptr -= 5;
  4007. +     goto label;
  4008. +   }
  4009. +   else if ( ptr > str + 5 && strnicmp(ptr - 6, "Patch ", 6) == 0 )
  4010. +   {
  4011. +     ptr -= 6;
  4012. +     goto label;
  4013. +   }
  4014. +   else
  4015. +     return 0;
  4016. +   if ( ptr > str && 'a' <= ptr[-1] && ptr[-1] <= 'z' )
  4017. +     ptr--;
  4018. +   while ( ptr > str && isdigit(ptr[-1]) )
  4019. +     ptr--;
  4020. +   if ( !isdigit(*ptr) )
  4021. +     return 0;
  4022. +   if ( ptr > str && (ptr[-1] == '(' || ptr[-1] == '[') )
  4023. +     ptr--;
  4024. +   while ( ptr > str && ptr[-1] == ' ' )
  4025. +     ptr--;
  4026. +   if ( ptr > str + 3 && strnicmp(ptr - 4, "Part", 4) == 0 )
  4027. +     ptr -= 4;
  4028. + label:    
  4029. +   while ( ptr > str && ptr[-1] == ' ' )
  4030. +     ptr--;
  4031. +   if ( ptr > str && ptr[-1] == ',' )
  4032. +     ptr--;
  4033. +   else if ( ptr > str && ptr[-1] == ':' )
  4034. +     ptr--;
  4035. +   *ptr = 0;
  4036. +   return 1;
  4037. + }
  4038. + char *skip_vi(char *str)
  4039. + {
  4040. +   char *ptr = str;
  4041. +   /* skip things like "v02i0027: " */
  4042. +   while ( isspace(*ptr) )
  4043. +     ptr++;
  4044. +   if ( *ptr++ != 'v' )
  4045. +     return str;
  4046. +   if ( !isdigit(*ptr) )
  4047. +     return str;
  4048. +   while ( isdigit(*ptr) )
  4049. +     ptr++;
  4050. +   if ( *ptr++ != 'i' )
  4051. +     return str;
  4052. +   if ( !isdigit(*ptr) )
  4053. +     return str;
  4054. +   while ( isdigit(*ptr) )
  4055. +     ptr++;
  4056. +   if ( *ptr++ != ':' )
  4057. +     return str;
  4058. +   if ( *ptr++ != ' ' )
  4059. +     return str;
  4060. +   while ( isspace(*ptr) )
  4061. +     ptr++;
  4062. +   return ptr;
  4063. + }
  4064. + int smartcmp(char *str1, char *str2)
  4065. + {
  4066. +   char s1[256], s2[256];
  4067. +   strcpy(s1, str1);
  4068. +   strcpy(s2, str2);
  4069. +   if ( strip_off_part(s1) && strip_off_part(s2) )
  4070. +   {
  4071. +     str1 = skip_vi(s1);
  4072. +     str2 = skip_vi(s2);
  4073. +   }
  4074. +   return stricmp(str1, str2);
  4075. + }
  4076.   ARTICLE *get_headers(ACTIVE *gp)
  4077.   {
  4078.       /*
  4079. ***************
  4080. *** 739,751 ****
  4081.        */
  4082.   
  4083.       char *fn;
  4084. !     char buf[256], fnx[256], *buf_p;
  4085.       long g, n_read;
  4086.       FILE *tmp_file;
  4087.   
  4088.       ARTICLE *start, *that, *tmp;
  4089.       ART_ID  *art_this, *new;
  4090. !     int     ct_art;
  4091.   
  4092.       n_read = 0;
  4093.       ct_art = 0;
  4094. --- 1116,1129 ----
  4095.        */
  4096.   
  4097.       char *fn;
  4098. !     char buf[MAXLINE], fnx[256], *buf_p;
  4099.       long g, n_read;
  4100.       FILE *tmp_file;
  4101.   
  4102.       ARTICLE *start, *that, *tmp;
  4103. +     ARTICLE **ptr;
  4104.       ART_ID  *art_this, *new;
  4105. !     int     ct_art, cmp;
  4106.   
  4107.       n_read = 0;
  4108.       ct_art = 0;
  4109. ***************
  4110. *** 754,766 ****
  4111.       fn = make_news_group_name(gp->group);
  4112.       sprintf(fnx, "%s.IDX", fn);
  4113.   
  4114. !     if ((tmp_file = fopen(fnx, "rb")) != NULL) {
  4115.   
  4116.           for (g = gp->lo_num+1; g <= gp->hi_num; g++) {
  4117.   
  4118. !             if ((n_read++ %10) == 0) {
  4119. !                 gotoxy(1,25);
  4120.                   printf("%d articles processed", n_read-1);
  4121.               }
  4122.   
  4123.               /*
  4124. --- 1132,1150 ----
  4125.       fn = make_news_group_name(gp->group);
  4126.       sprintf(fnx, "%s.IDX", fn);
  4127.   
  4128. !     if ((tmp_file = flockopen(fnx, "rb")) != NULL) {
  4129.   
  4130. +         setvbuf(tmp_file, iobuf, _IOFBF, IOBUFSIZE);
  4131.           for (g = gp->lo_num+1; g <= gp->hi_num; g++) {
  4132.   
  4133. !             if ((n_read++ % 100) == 0) {
  4134. !                 gotoxy(1,PAGE_SIZE);
  4135. !                 textbackground(LIGHTGRAY);  textcolor(BLACK);
  4136.                   printf("%d articles processed", n_read-1);
  4137. +                 clreol();
  4138. +                 textbackground(BLACK);  textcolor(LIGHTGRAY);
  4139. +                 tflush();
  4140.               }
  4141.   
  4142.               /*
  4143. ***************
  4144. *** 770,777 ****
  4145.                *    - add to the existing list
  4146.                */
  4147.   
  4148. !             if (fgets(buf, 255, tmp_file) == NULL) {
  4149. !                 gotoxy(1,25);
  4150.                   fprintf(stderr, "\nsnews: index file is corrupt\n");
  4151.                   exit(1);
  4152.               }
  4153. --- 1154,1161 ----
  4154.                *    - add to the existing list
  4155.                */
  4156.   
  4157. !             if (fgets(buf, sizeof(buf), tmp_file) == NULL) {
  4158. !                 gotoxy(1,PAGE_SIZE);
  4159.                   fprintf(stderr, "\nsnews: index file is corrupt\n");
  4160.                   exit(1);
  4161.               }
  4162. ***************
  4163. *** 778,784 ****
  4164.   
  4165.               /* check all is in sync */
  4166.               if (g != atol(buf+9)) {
  4167. !                 gotoxy(1,25);
  4168.                   fprintf(stderr, "\nsnews: article %ld found when %ld"
  4169.                       "expected\n", atol(buf+9), g);
  4170.                   exit(1);
  4171. --- 1162,1168 ----
  4172.   
  4173.               /* check all is in sync */
  4174.               if (g != atol(buf+9)) {
  4175. !                 gotoxy(1,PAGE_SIZE);
  4176.                   fprintf(stderr, "\nsnews: article %ld found when %ld"
  4177.                       "expected\n", atol(buf+9), g);
  4178.                   exit(1);
  4179. ***************
  4180. *** 786,808 ****
  4181.   
  4182.               /* skip the two eight digit numbers and the 9 and the spaces */
  4183.               buf_p = buf+28;
  4184.               eat_gunk(buf_p);
  4185. !             tmp = start;
  4186. !             while (tmp != NULL) {
  4187. !                 if (stricmp(buf_p, tmp->header) == 0)
  4188.               break;
  4189. -                 tmp = tmp->next;
  4190.               }
  4191. !             if (tmp != NULL) {
  4192.           
  4193.               /* allocate new article number */
  4194.               new = xmalloc(sizeof (ART_ID));
  4195.               new->id = g;
  4196.               new->art_off = atol(buf);
  4197. -                 new->next_art = NULL;
  4198. -                 tmp->num_articles++;
  4199.   
  4200.               /* place it at the end */
  4201.               art_this = tmp->art_num;
  4202. --- 1170,1207 ----
  4203.   
  4204.               /* skip the two eight digit numbers and the 9 and the spaces */
  4205.               buf_p = buf+28;
  4206.               eat_gunk(buf_p);
  4207. !             for ( tmp = start; tmp != NULL; ) {
  4208. !         cmp = smartcmp(buf_p, tmp->header);
  4209. !                 if (cmp > 0) {
  4210. !             if (tmp->left)
  4211. !                 tmp = tmp->left;
  4212. !             else {
  4213. !             ptr = &(tmp->left);
  4214. !             tmp = NULL;
  4215.               break;
  4216.               }
  4217. !         }
  4218. !         else if (cmp < 0) {
  4219. !             if (tmp->right)
  4220. !                 tmp = tmp->right;
  4221. !             else {
  4222. !             ptr = &(tmp->right);
  4223. !             tmp = NULL;
  4224. !             break;
  4225. !             }
  4226. !         }
  4227. !         else {
  4228. !             /* found this subject */
  4229. !              tmp->num_articles++;
  4230.   
  4231.               /* allocate new article number */
  4232.               new = xmalloc(sizeof (ART_ID));
  4233.               new->id = g;
  4234.               new->art_off = atol(buf);
  4235.   
  4236.               /* place it at the end */
  4237.               art_this = tmp->art_num;
  4238. ***************
  4239. *** 809,858 ****
  4240.               while (art_this->next_art != NULL) {
  4241.               art_this = art_this->next_art;
  4242.               }
  4243.               art_this->next_art = new;
  4244.               
  4245. !             } else {
  4246.   
  4247.                   /* not found - allocate new thread */
  4248.                   if (start == NULL) {
  4249. !                     start = that = xmalloc(sizeof (ARTICLE));
  4250. !                     start->last = NULL;
  4251. !                     start->next = NULL;
  4252. !                     start->index = ct_art;
  4253.                   } else {
  4254.                       ct_art++;
  4255.                       that->next = xmalloc(sizeof (ARTICLE));
  4256.                       that->next->last = that;
  4257.                       that = that->next;
  4258.           that->next = NULL;
  4259.           that->index = ct_art;
  4260. !                 }
  4261.   
  4262.                   /* store article data */
  4263.                   strcpy(that->header, buf_p);
  4264.                   that->num_articles = 1;
  4265.                   that->art_num = xmalloc(sizeof (ART_ID));
  4266.                   that->art_num->next_art = NULL;
  4267.                   that->art_num->id = g;
  4268.                   that->art_num->art_off = atol(buf);
  4269.   
  4270.               }
  4271. -             that->next = NULL;
  4272.           }
  4273.   
  4274.           fclose(tmp_file);
  4275.   
  4276.       } else {
  4277. !         gotoxy(1,25);
  4278.           fprintf(stderr, "\nsnews: can't open index file %s\n", fnx);
  4279.           exit(1);
  4280.       }
  4281.   
  4282. !     return(start);
  4283.   
  4284.   }
  4285.   
  4286.   
  4287. --- 1208,1267 ----
  4288.               while (art_this->next_art != NULL) {
  4289.               art_this = art_this->next_art;
  4290.               }
  4291.               art_this->next_art = new;
  4292.   
  4293. !             new->last_art = art_this;
  4294. !             new->next_art = NULL;
  4295. !             break;
  4296. !         }
  4297.   
  4298. +             }
  4299. +             if (tmp == NULL) {
  4300.                   /* not found - allocate new thread */
  4301.                   if (start == NULL) {
  4302. !                     start = xmalloc(sizeof (ARTICLE));
  4303. !             that = start;
  4304. !                     that->last = NULL;
  4305.                   } else {
  4306.                       ct_art++;
  4307.                       that->next = xmalloc(sizeof (ARTICLE));
  4308.                       that->next->last = that;
  4309.                       that = that->next;
  4310. +             *ptr = that;
  4311. +                 }
  4312.           that->next = NULL;
  4313.           that->index = ct_art;
  4314. !         that->left = that->right = NULL;
  4315.   
  4316.                   /* store article data */
  4317. +                 that->header = xmalloc(strlen(buf_p) + 1);
  4318.                   strcpy(that->header, buf_p);
  4319.                   that->num_articles = 1;
  4320.                   that->art_num = xmalloc(sizeof (ART_ID));
  4321. +                 that->art_num->last_art = NULL;
  4322.                   that->art_num->next_art = NULL;
  4323.                   that->art_num->id = g;
  4324.                   that->art_num->art_off = atol(buf);
  4325.   
  4326.               }
  4327.           }
  4328.   
  4329.           fclose(tmp_file);
  4330.   
  4331.       } else {
  4332. !         gotoxy(1,PAGE_SIZE);
  4333.           fprintf(stderr, "\nsnews: can't open index file %s\n", fnx);
  4334.           exit(1);
  4335.       }
  4336.   
  4337. !     gp->threads = ct_art + 1;
  4338.   
  4339. +     return(start);
  4340.   }
  4341.   
  4342.   
  4343. ***************
  4344. *** 862,877 ****
  4345.   {
  4346.       /*
  4347.        *  This routine take the header line, and strips the
  4348. !      *  word header word, 'Re:', and any extra blanks, trim to 59 chars
  4349.        */
  4350.   
  4351. !     char *p, tmp[256];
  4352. !     buf[58] = 0;
  4353.   
  4354.       /* strip the Subject: etc off the front */
  4355. !     while ((strstr(buf, "Re:") != NULL) ||
  4356.           (strnicmp(buf, "From:", 5) == 0) ||
  4357.           (strnicmp(buf, "Path:", 5) == 0) ||
  4358.           (strnicmp(buf, "Subject:", 8) == 0) ||
  4359. --- 1271,1283 ----
  4360.   {
  4361.       /*
  4362.        *  This routine take the header line, and strips the
  4363. !      *  word header word, 'Re:', and any extra blanks
  4364.        */
  4365.   
  4366. !     char *p, tmp[MAXLINE];
  4367.   
  4368.       /* strip the Subject: etc off the front */
  4369. !     while ( /*(strstr(buf, "Re:") != NULL) ||*/
  4370.           (strnicmp(buf, "From:", 5) == 0) ||
  4371.           (strnicmp(buf, "Path:", 5) == 0) ||
  4372.           (strnicmp(buf, "Subject:", 8) == 0) ||
  4373. ***************
  4374. *** 878,884 ****
  4375.           (strnicmp(buf, "Organization:", 13) == 0) ||
  4376.           (strnicmp(buf, "Organisation:", 13) == 0) ||
  4377.           (strnicmp(buf, "Followup-To:", 12) == 0)) {
  4378. !         p = strstr(buf, ":");
  4379.           strcpy(buf, p+1);
  4380.       }
  4381.   
  4382. --- 1284,1290 ----
  4383.           (strnicmp(buf, "Organization:", 13) == 0) ||
  4384.           (strnicmp(buf, "Organisation:", 13) == 0) ||
  4385.           (strnicmp(buf, "Followup-To:", 12) == 0)) {
  4386. !         p = strchr(buf, ':');
  4387.           strcpy(buf, p+1);
  4388.       }
  4389.   
  4390. ***************
  4391. *** 925,930 ****
  4392. --- 1331,1337 ----
  4393.           }
  4394.   
  4395.           t = a->next;
  4396. +         free(a->header);
  4397.           free(a);
  4398.           a = t;
  4399.       }
  4400. ***************
  4401. *** 970,975 ****
  4402. --- 1377,1383 ----
  4403.       ct = 0;
  4404.       articles = (int)(gp->hi_num - gp->lo_num);
  4405.   
  4406. +     if (gp->read_list)
  4407.           for (i = 0; i < articles; i++) {
  4408.               if (*((gp->read_list)+i) == FALSE)
  4409.                   ct++;
  4410. ***************
  4411. *** 980,986 ****
  4412.   
  4413.   
  4414.   
  4415. ! /*------------------- count unread articles in a group --------------------*/
  4416.   void mark_group_as_read(ACTIVE *gp)
  4417.   {
  4418.       /*
  4419. --- 1388,1394 ----
  4420.   
  4421.   
  4422.   
  4423. ! /*------------------- mark articles as read ---------------------------------*/
  4424.   void mark_group_as_read(ACTIVE *gp)
  4425.   {
  4426.       /*
  4427. ***************
  4428. *** 990,996 ****
  4429.   
  4430.       int articles, i, ch;
  4431.   
  4432. !     message("Mark all articles as read (y/n)? ");
  4433.       while (((ch = getch()) != 'y') && (ch != 'n') && (ch != ESCAPE));
  4434.   
  4435.       if (ch == 'y') {
  4436. --- 1398,1404 ----
  4437.   
  4438.       int articles, i, ch;
  4439.   
  4440. !     message("Mark all articles in this group as read (y/n)? ");
  4441.       while (((ch = getch()) != 'y') && (ch != 'n') && (ch != ESCAPE));
  4442.   
  4443.       if (ch == 'y') {
  4444. ***************
  4445. *** 1005,1050 ****
  4446.   }
  4447.   
  4448.   
  4449. ! /*-------------------------- status message ---------------------------------*/
  4450. ! void message(char *msg)
  4451.   {
  4452. !     int x;
  4453.   
  4454. !     x = 40 - (strlen(msg)/2);
  4455.   
  4456. !     gotoxy(1,24);
  4457. !     textbackground(LIGHTGRAY);  textcolor(BLACK);
  4458. !     clreol();
  4459. !     gotoxy(x,24);
  4460. !     cprintf("%s", msg);
  4461. !     textbackground(BLACK);  textcolor(LIGHTGRAY);
  4462.   }
  4463.   
  4464.   
  4465.   /*-------------------------- status message ---------------------------------*/
  4466. ! void lmessage(char *msg)
  4467.   {
  4468. !     gotoxy(1,24);
  4469.       textbackground(LIGHTGRAY);  textcolor(BLACK);
  4470.       clreol();
  4471. -     cprintf("%s", msg);
  4472.       textbackground(BLACK);  textcolor(LIGHTGRAY);
  4473.   }
  4474.   
  4475.   
  4476.   /*-------------------------- status message ---------------------------------*/
  4477. ! void command(char *msg)
  4478.   {
  4479. !     int x;
  4480. !     x = 40 - (strlen(msg)/2);
  4481. !     gotoxy(1,25);
  4482.       textbackground(LIGHTGRAY);  textcolor(BLACK);
  4483.       clreol();
  4484. -     gotoxy(x,25);
  4485. -     cprintf(msg);
  4486.       textbackground(BLACK);  textcolor(LIGHTGRAY);
  4487.   }
  4488. --- 1413,1465 ----
  4489.   }
  4490.   
  4491.   
  4492. ! void mark_thread_as_read(ACTIVE *gp, ARTICLE *a)
  4493.   {
  4494. !     /*
  4495. !      *  Take the thread 'a' for the given group 'gp' and return the number
  4496. !      *  of unread articles
  4497. !      */
  4498.   
  4499. !     ART_ID *id;
  4500. !     int idx, ch;
  4501.   
  4502. !     message("Mark all articles in this thread as read (y/n)? ");
  4503. !     while (((ch = getch()) != 'y') && (ch != 'n') && (ch != ESCAPE));
  4504. !     if (ch == 'y') {
  4505. !         id = a->art_num;
  4506. !         while (id != NULL) {
  4507. !             idx = (int)(id->id - gp->lo_num - 1);
  4508. !             *((gp->read_list)+idx) = TRUE;
  4509. !             id = id->next_art;
  4510. !         }
  4511. !     }
  4512.   }
  4513.   
  4514.   
  4515.   /*-------------------------- status message ---------------------------------*/
  4516. ! void message(char *msg)
  4517.   {
  4518. !     int x;
  4519. !     x = _columns / 2 - (strlen(msg)/2);
  4520. !     gotoxy(1,PAGE_SIZE);
  4521.       textbackground(LIGHTGRAY);  textcolor(BLACK);
  4522. +     printf("%*s%s", x, "", msg);
  4523.       clreol();
  4524.       textbackground(BLACK);  textcolor(LIGHTGRAY);
  4525.   }
  4526.   
  4527.   
  4528.   /*-------------------------- status message ---------------------------------*/
  4529. ! void lmessage(char *msg)
  4530.   {
  4531. !     gotoxy(1,PAGE_SIZE);
  4532.       textbackground(LIGHTGRAY);  textcolor(BLACK);
  4533. +     printf("%s", msg);
  4534.       clreol();
  4535.       textbackground(BLACK);  textcolor(LIGHTGRAY);
  4536.   }
  4537. Only in new: snews.def
  4538. diff -cb orig/snews.doc new/snews.doc
  4539. *** orig/snews.doc    Fri Nov 08 06:50:18 1991
  4540. --- new/snews.doc    Sun Aug 02 18:28:08 1992
  4541. ***************
  4542. *** 1,4 ****
  4543. --- 1,7 ----
  4544. + NOTE: This documentation is somewhat out of date. Read README.OS2 for
  4545. + changes in the OS/2 (SNEWS /2) releases.
  4546.   
  4547. + -----------
  4548.                               Simple NEWS 1.0
  4549.                               ===============
  4550.   
  4551. diff -cb orig/snews.h new/snews.h
  4552. *** orig/snews.h    Thu Jun 11 22:48:16 1992
  4553. --- new/snews.h    Sun Aug 02 20:34:18 1992
  4554. ***************
  4555. *** 1,5 ****
  4556.   /*
  4557. !     SNEWS 1.0
  4558.   
  4559.       Private decls the SNEWS news reader
  4560.   
  4561. --- 1,5 ----
  4562.   /*
  4563. !     SNEWS 2.0
  4564.   
  4565.       Private decls the SNEWS news reader
  4566.   
  4567. ***************
  4568. *** 22,41 ****
  4569.   
  4570.    */
  4571.   
  4572. - #include <alloc.h>
  4573. - #include <process.h>
  4574. - #include <io.h>
  4575.   
  4576. ! /* #define INCLUDE_SIG */   /* enable this to have the reply function put */
  4577.                               /* your sig on the reply - mail ususally does */
  4578.                               /* this                                       */
  4579.   
  4580.   
  4581.   #define ENTER               0x0D
  4582.   #define ESCAPE              0x1B
  4583.   #define TAB                 0x09
  4584.   
  4585.   #define EX_DONE             1
  4586.   #define EX_QUIT             2
  4587. --- 22,39 ----
  4588.   
  4589.    */
  4590.   
  4591.   
  4592. ! #define INCLUDE_SIG        /* enable this to have the reply function put */
  4593.                               /* your sig on the reply - mail ususally does */
  4594.                               /* this                                       */
  4595.   
  4596. ! #define MAXLINE             1024
  4597. ! #define MAXART              256
  4598.   
  4599.   #define ENTER               0x0D
  4600.   #define ESCAPE              0x1B
  4601.   #define TAB                 0x09
  4602. + #define BACKSP              0x08
  4603.   
  4604.   #define EX_DONE             1
  4605.   #define EX_QUIT             2
  4606. ***************
  4607. *** 44,56 ****
  4608.   #define EX_NEXT_UNREAD      5
  4609.   #define EX_ROT13            6
  4610.   #define EX_DUMMY            7
  4611.   
  4612. - #define TEXT_LINE           5
  4613.   
  4614.   
  4615. ! #define PAGE_HEADER         4
  4616. ! #define PAGE_LENGTH         19
  4617.   
  4618.   /* if you change these see show_help */
  4619.   #define HELP_GROUP          0
  4620.   #define HELP_THREAD         1
  4621. --- 42,60 ----
  4622.   #define EX_NEXT_UNREAD      5
  4623.   #define EX_ROT13            6
  4624.   #define EX_DUMMY            7
  4625. + #define EX_PREVIOUS         8
  4626. + #define EX_SEARCH_FORW      9
  4627. + #define EX_SEARCH_BACKW     10
  4628.   
  4629.   
  4630. + /* screen size */
  4631. + #define TEXT_LINE           4
  4632. + #define PAGE_HEADER         3
  4633.   
  4634. ! #define PAGE_LENGTH         (_lines - 4)
  4635. ! #define PAGE_SIZE           _lines
  4636.   
  4637.   /* if you change these see show_help */
  4638.   #define HELP_GROUP          0
  4639.   #define HELP_THREAD         1
  4640. ***************
  4641. *** 58,67 ****
  4642. --- 62,76 ----
  4643.   
  4644.   #define  UP_ARR             'H'
  4645.   #define  DN_ARR             'P'
  4646. + #define  L_ARR              'K'
  4647. + #define  R_ARR              'M'
  4648. + #define  C_L_ARR            's'
  4649. + #define  C_R_ARR            't'
  4650.   #define  PGUP               'I'
  4651.   #define  PGDN               'Q'
  4652.   #define  HOME               'G'
  4653.   #define  END                'O'
  4654. + #define  F1                 ';'
  4655.   
  4656.   
  4657.   
  4658. ***************
  4659. *** 72,79 ****
  4660. --- 81,90 ----
  4661.       long   id;                  /* article number                 */
  4662.       long   art_off;             /* offset of the article          */
  4663.       struct art_id *next_art;    /* pointer to next article number */
  4664. +     struct art_id *last_art;    /* pointer to previous article number */
  4665.   } ART_ID;
  4666.   
  4667.   /*
  4668.    *  This structure is a doubly linked list of the unique article headers.  The
  4669.    *  linked list of article numbers is built on 'art_num'.  This system
  4670. ***************
  4671. *** 82,139 ****
  4672.    *  But hey, it's simple
  4673.    */
  4674.   typedef struct article {
  4675. !     char   header[60];          /* article header              */
  4676.       int    num_articles;        /* number with this header     */
  4677.       ART_ID *art_num;            /* pointer to list of articles */
  4678.       struct article *next;       /* next topic                  */
  4679.       struct article *last;       /* last topic                  */
  4680.       int    index;               /* topic number from start     */
  4681.   } ARTICLE;
  4682.   
  4683.   
  4684.   /*
  4685. -  *  This structure is a linked list of lines that make up an article. The
  4686. -  *  file is read in and the linked list is built
  4687. -  */
  4688. - typedef struct line {
  4689. -     char   data[80];            /* line of text                */
  4690. -     struct line *next;          /* next line                   */
  4691. -     struct line *last;          /* last line                   */
  4692. -     int    index;               /* line number from start      */
  4693. - } LINE;
  4694. - /*
  4695.    *  This structure is the handle for an article in ram.  The file
  4696.    *  is read in and the linked list built.
  4697.    */
  4698. - #define WHO_LENGTH 35
  4699.   typedef struct {
  4700. !     char  author[WHO_LENGTH];           /* truncated author              */
  4701. !     char  organisation[WHO_LENGTH];     /* truncated organisation        */
  4702. !     char  follow_up[80];      /* group for follow-up article             */
  4703. !     int   lines;              /* total lines in file                     */
  4704.       LINE  *top;               /* points to start of article, incl header */
  4705. !     LINE  *start;             /* ponts to start of text                  */
  4706.   } TEXT;
  4707.   
  4708.   
  4709.   ACTIVE *select_group(ACTIVE *head, ACTIVE *current);
  4710.   void show_help(int h);
  4711.   int read_group(ACTIVE *gp);
  4712. ! void show_groups(ACTIVE **top, ACTIVE *this, int force);
  4713.   ARTICLE *get_headers(ACTIVE *gp);
  4714.   void eat_gunk(char *buf);
  4715.   void free_header(ARTICLE *start);
  4716.   
  4717.   
  4718. ! void show_threads(ACTIVE *gp, ARTICLE **top, ARTICLE *this, int force);
  4719.   void select_thread(ACTIVE *gp, ARTICLE *head);
  4720.   int read_thread(ACTIVE *gp, ARTICLE *this, ART_ID *first, int a_ct);
  4721.   
  4722. --- 93,135 ----
  4723.    *  But hey, it's simple
  4724.    */
  4725.   typedef struct article {
  4726. !     char   *header;             /* article header              */
  4727.       int    num_articles;        /* number with this header     */
  4728.       ART_ID *art_num;            /* pointer to list of articles */
  4729.       struct article *next;       /* next topic                  */
  4730.       struct article *last;       /* last topic                  */
  4731.       int    index;               /* topic number from start     */
  4732. +     struct article *left;       /* for tree structure          */
  4733. +     struct article *right;
  4734.   } ARTICLE;
  4735.   
  4736.   
  4737.   /*
  4738.    *  This structure is the handle for an article in ram.  The file
  4739.    *  is read in and the linked list built.
  4740.    */
  4741.   typedef struct {
  4742. !     char  *subject;           /* header              */
  4743. !     char  *author;            /* author              */
  4744. !     char  *organisation;      /* organisation        */
  4745. !     char  *follow_up;         /* group for follow-up article             */
  4746. !     int   lines;              /* total lines in article                  */
  4747. !     int   startline;          /* first text line in article              */
  4748.       LINE  *top;               /* points to start of article, incl header */
  4749. !     LINE  *start;             /* points to start of text                 */
  4750.   } TEXT;
  4751.   
  4752.   
  4753.   ACTIVE *select_group(ACTIVE *head, ACTIVE *current);
  4754.   void show_help(int h);
  4755.   int read_group(ACTIVE *gp);
  4756. ! void show_groups(ACTIVE **top, ACTIVE *this, int force, ACTIVE *head);
  4757.   ARTICLE *get_headers(ACTIVE *gp);
  4758.   void eat_gunk(char *buf);
  4759.   void free_header(ARTICLE *start);
  4760.   
  4761.   
  4762. ! void show_threads(ACTIVE *gp, ARTICLE **top, ARTICLE *this, int force, ARTICLE *head);
  4763.   void select_thread(ACTIVE *gp, ARTICLE *head);
  4764.   int read_thread(ACTIVE *gp, ARTICLE *this, ART_ID *first, int a_ct);
  4765.   
  4766. ***************
  4767. *** 140,145 ****
  4768. --- 136,142 ----
  4769.   int count_unread_in_thread(ACTIVE *gp, ARTICLE *a);
  4770.   int count_unread_in_group(ACTIVE *gp);
  4771.   void mark_group_as_read(ACTIVE *gp);
  4772. + void mark_thread_as_read(ACTIVE *gp, ARTICLE *a);
  4773.   
  4774.   void command(char *msg);
  4775.   void message(char *msg);
  4776. ***************
  4777. *** 149,165 ****
  4778.   void free_article(TEXT *t);
  4779.   
  4780.   
  4781. ! int read_article(ACTIVE *gp, TEXT *tx, char *subject, int a_ct, int of_ct);
  4782. ! void show_article(ACTIVE *gp, TEXT *tx, char *subject, LINE *this, int a_ct,
  4783. !                   int of_ct);
  4784.   
  4785.   
  4786.   void save_to_disk(TEXT *tx);
  4787. ! void reply_to_article(TEXT *tx, char *subject);
  4788.   void get_his_stuff(TEXT *tx, char *author, char *msg_id);
  4789.   
  4790.   
  4791. ! void post(TEXT *tx, char *newsgroups, char *subject);
  4792.   void post_it(FILE *article, char *newsgroups, char *subject, char *dist,
  4793.                     char *msg_id);
  4794.   
  4795. --- 146,162 ----
  4796.   void free_article(TEXT *t);
  4797.   
  4798.   
  4799. ! int read_article(ACTIVE *gp, TEXT *tx, int a_ct, int of_ct);
  4800. ! void show_article(ACTIVE *gp, TEXT *tx, LINE *this, int a_ct,
  4801. !                   int of_ct, int margin);
  4802.   
  4803.   
  4804.   void save_to_disk(TEXT *tx);
  4805. ! void reply_to_article(TEXT *tx);
  4806.   void get_his_stuff(TEXT *tx, char *author, char *msg_id);
  4807.   
  4808.   
  4809. ! void post(TEXT *tx, char *newsgroups);
  4810.   void post_it(FILE *article, char *newsgroups, char *subject, char *dist,
  4811.                     char *msg_id);
  4812.   
  4813. Only in new: termcap.c
  4814. Only in new: termcap.dat
  4815. Only in new: termcap.h
  4816. diff -cb orig/unbatch.c new/unbatch.c
  4817. *** orig/unbatch.c    Thu Jun 11 22:48:16 1992
  4818. --- new/unbatch.c    Sun Aug 02 20:34:18 1992
  4819. ***************
  4820. *** 1,5 ****
  4821.   /*
  4822. !     SNEWS 1.0
  4823.   
  4824.       unbatch - quick and dirty news toss, no feeding of other sites
  4825.   
  4826. --- 1,5 ----
  4827.   /*
  4828. !     SNEWS 2.0
  4829.   
  4830.       unbatch - quick and dirty news toss, no feeding of other sites
  4831.   
  4832. ***************
  4833. *** 35,42 ****
  4834. --- 35,47 ----
  4835.   unsigned _stklen = 16384;
  4836.   
  4837.   INFO my_stuff;
  4838. + char iobuf[IOBUFSIZE];
  4839.   
  4840. + #ifdef system
  4841. + #undef system
  4842. + #endif
  4843.   
  4844.   /*------------------------------- main --------------------------------*/
  4845.   void main(int argc, char *argv[])
  4846.   {
  4847. ***************
  4848. *** 70,88 ****
  4849.           printf("unbatch: processing %s\n", name);
  4850.   
  4851.           /*
  4852. !          *  Check for enough room.  We need:
  4853. !          *
  4854. !          *     - more than twice the size of the batch for uncompressed
  4855. !          *       batch, say 2.8
  4856. !          *
  4857. !          *     - space for the articles.
  4858. !          *
  4859. !          *       For example a 100k batch may require 280kb for the uncompressed
  4860. !          *       batch, then another 280 kb for the articles.
  4861.            */
  4862.           stat(name, &st);
  4863.   
  4864. !         required_disk = (st.st_size*2.8) * 2;
  4865.   
  4866.           drive = getdisk();
  4867.           getdfree(drive+1, &df);
  4868. --- 75,94 ----
  4869.           printf("unbatch: processing %s\n", name);
  4870.   
  4871.           /*
  4872. !          Check for enough room. First, the batch in copied without
  4873. !          the header. Thus, the same space is needed again. Then,
  4874. !          the copied batch is uncompressed and read in over a pipe
  4875. !          which doesn't need extra space. Only space for the
  4876. !          articles is needed, slightly more than the uncompressed
  4877. !          size of the batch, say 3 times as much. We need a total
  4878. !          space of about four times the size of the original batch.
  4879. !      And this is only if no different device is used for the 
  4880. !      temp files.
  4881.            */
  4882.           stat(name, &st);
  4883.   
  4884. !         required_disk = st.st_size * 4L;
  4885.   
  4886.           drive = getdisk();
  4887.           getdfree(drive+1, &df);
  4888. ***************
  4889. *** 93,112 ****
  4890.               exit(1);
  4891.           }
  4892.   
  4893.   
  4894. -         /* uncompress the news batch and return a pointer to the temp file */
  4895. -         if ((tmp_file = decode_batches(name, no_toss)) != NULL) {
  4896.               open_hist_file();
  4897.               toss(tmp_file);
  4898.               close_hist_file();
  4899.               fclose(tmp_file);
  4900.   
  4901.               unlink(name);
  4902. -             sprintf(name, "%s", my_stuff.temp_name);
  4903. -             unlink(name);
  4904.   
  4905. !         } else {
  4906.               printf("could not unpack compressed news batch %s\n", name);
  4907.               exit(1);
  4908.           }
  4909. --- 99,121 ----
  4910.               exit(1);
  4911.           }
  4912.   
  4913. +         /* uncompress the news batch and return a pointer to the pipe */
  4914. +         if ((tmp_file = decode_batch(name, in_name, no_toss)) != NULL) {
  4915.   
  4916.               open_hist_file();
  4917.               toss(tmp_file);
  4918.               close_hist_file();
  4919. +             if (in_name[0]) {
  4920. +           pclose(tmp_file);
  4921. +               unlink(in_name);
  4922. +         } 
  4923. +         else 
  4924.                 fclose(tmp_file);
  4925.   
  4926.               unlink(name);
  4927.   
  4928. !         } else if (!no_toss) {
  4929.               printf("could not unpack compressed news batch %s\n", name);
  4930.               exit(1);
  4931.           }
  4932. ***************
  4933. *** 119,206 ****
  4934.   }
  4935.   
  4936.   
  4937.   /*--------------------------- unpack the batch ------------------------*/
  4938. ! void toss(FILE *tmp_file)
  4939.   {
  4940.       /*
  4941. !      *  Toss it into the appropriate files.
  4942. !      *
  4943. !      *  TODO:
  4944. !      *    - badly structured, sort it out
  4945.        */
  4946.       FILE *out_file = NULL;
  4947. !     FILE *spool_file = NULL;
  4948. !     char buf[512], msg[256], subject[256], msg_id[256], *p;
  4949. !     char newsgroups[256], nglist[256];
  4950. !     long where;
  4951.       ACTIVE *gp;
  4952.       time_t t;
  4953. !     int  already_junked, in_header;
  4954. !     strcpy(msg_id, "");
  4955. !     strcpy(subject, "-- no subject --\n");
  4956. !     strcpy(newsgroups, "");
  4957.   
  4958. -     rewind(tmp_file);
  4959.       time(&t);
  4960. !     in_header = TRUE;
  4961. !     /* read the file */
  4962. !     while (fgets(buf, 511, tmp_file) != NULL) {
  4963. !         if (strstr(buf, "#! rnews") != NULL) {
  4964.   
  4965. -             if (strlen(newsgroups) != 0) {
  4966. -                 strcpy(nglist,  newsgroups+11);
  4967.                   p = strtok(newsgroups, " \r\n,:");
  4968.                   p = strtok(NULL, " \r\n,:");
  4969.   
  4970. !                 /*
  4971. !                  *  For each newsgroup
  4972. !                  *    - open the text file
  4973. !                  *    - save the file pointer
  4974. !                  *    - append the message to it
  4975. !                  *    - close the file
  4976. !                  *    - open the index file
  4977. !                  *    - save the file pointer and the subject line
  4978. !                  */
  4979.   
  4980. !                 while (p != '\x00') {
  4981.   
  4982. !                     out_file = open_out_file(p);
  4983.   
  4984.                       where = ftell(out_file);
  4985. !                     rewind(spool_file);
  4986. !                     while (fgets(buf, 511, spool_file) != NULL)
  4987. !                         fputs(buf, out_file);
  4988.                       fprintf(out_file, "\n@@@@END\n");
  4989.                       fclose(out_file);
  4990.   
  4991. !                     out_file = open_index_file(p);
  4992. !                     gp = find_news_group(p);
  4993.                       fprintf(out_file,"%08ld %08ld %09ld %s", where,
  4994.                           gp->hi_num, t, subject);
  4995.                       fclose(out_file);
  4996.   
  4997. !                     p = strtok(NULL, " \r\n,:");
  4998.                   }
  4999. !                 add_hist_record(msg_id, nglist);
  5000. !                 fclose(spool_file);
  5001.               }
  5002.   
  5003.               strcpy(subject, "-- no subject --\n");
  5004.               in_header = TRUE;
  5005.   
  5006. !             if ((spool_file = fopen("$$item", "w+b")) == NULL) {
  5007. !                 fprintf(stderr, "can't open temp article file %s\n", "$$item");
  5008. !                 exit(1);
  5009. !             }
  5010.   
  5011.           } else {
  5012.               /* flag the end of the header */
  5013. --- 128,235 ----
  5014.   }
  5015.   
  5016.   
  5017.   /*--------------------------- unpack the batch ------------------------*/
  5018. ! void save_message(LINE *spool, char *newsgroups, 
  5019. !           char *subject, char *msg_id)
  5020.   {
  5021.       /*
  5022. !      *  For each newsgroup
  5023. !      *    - open the text file
  5024. !      *    - save the file pointer
  5025. !      *    - append the message to it
  5026. !      *    - close the file
  5027. !      *    - open the index file
  5028. !      *    - save the file pointer and the subject line
  5029.        */
  5030. !     char buf[512], nglist[256], *group, *p;
  5031.       FILE *out_file = NULL;
  5032. !     LINE *help;
  5033.       ACTIVE *gp;
  5034. +     long where;
  5035.       time_t t;
  5036. !     int saved = FALSE;
  5037.   
  5038.       time(&t);
  5039. !     nglist[0] = 0;
  5040.   
  5041.       p = strtok(newsgroups, " \r\n,:");
  5042.       p = strtok(NULL, " \r\n,:");
  5043.   
  5044. !     while (p != NULL) {
  5045.   
  5046. !     group = p;
  5047. !     p = strtok(NULL, " \r\n,:");
  5048.   
  5049. !     gp = find_news_group(group);
  5050. !     if (stricmp(gp->group, "junk") == 0 && (p != NULL || saved))
  5051. !       continue;
  5052.   
  5053. +     out_file = open_out_file(group);
  5054.       where = ftell(out_file);
  5055. !     help = spool;
  5056. !     setvbuf(out_file, iobuf, _IOFBF, IOBUFSIZE);
  5057. !     for (help = spool; help != NULL; help = help->next)
  5058. !         fputs(help->data, out_file);
  5059.       fprintf(out_file, "\n@@@@END\n");
  5060.       fclose(out_file);
  5061.     
  5062. !     out_file = open_index_file(group);
  5063.       fprintf(out_file,"%08ld %08ld %09ld %s", where,
  5064.           gp->hi_num, t, subject);
  5065.       fclose(out_file);
  5066.   
  5067. !     saved = TRUE;
  5068. !         if ( nglist[0] )
  5069. !           strcat(nglist, ",");
  5070. !         strcat(nglist, group);
  5071.       }
  5072. !     while (spool) {
  5073. !         help = spool;
  5074. !     spool = spool->next;
  5075. !     free(help->data);
  5076. !     free(help);
  5077.       }
  5078.   
  5079. +     add_hist_record(msg_id, nglist);
  5080. + }
  5081. + void toss(FILE *tmp_file)
  5082. + {
  5083. +     /*
  5084. +      *  Toss it into the appropriate files.
  5085. +      */
  5086. +     LINE *spool = NULL, *help;
  5087. +     char buf[512], buf2[512], *p;
  5088. +     char newsgroups[256], subject[256], msg_id[256];
  5089. +     int  in_header, control;
  5090. +     strcpy(msg_id, "");
  5091.       strcpy(subject, "-- no subject --\n");
  5092. +     strcpy(newsgroups, "");
  5093. +     rewind(tmp_file);
  5094.       in_header = TRUE;
  5095. +     control = FALSE;
  5096.   
  5097. !     /* read the file */
  5098. !     while (fgets(buf, 511, tmp_file) != NULL) {
  5099. !         if (strstr(buf, "#! rnews") != NULL) {
  5100. !             if (control)
  5101. !                 strcpy(newsgroups, "Newsgroups: control"); /* kludge */
  5102. !         if (spool != NULL)
  5103. !             save_message(spool, newsgroups, subject, msg_id);
  5104. !             strcpy(subject, "-- no subject --\n");
  5105. !             in_header = TRUE;
  5106. !             control = FALSE;
  5107. !         spool = NULL;
  5108.   
  5109.           } else {
  5110.               /* flag the end of the header */
  5111. ***************
  5112. *** 210,262 ****
  5113.               /* save the newsgroups line */
  5114.               if (in_header) {
  5115.                   if (strnicmp(buf,"Message-ID:",11) == 0) {
  5116. !                     strcpy(msg, buf);
  5117. !                     p = strtok(msg, " \t\r\n");  p = strtok(NULL, " \t\r\n");
  5118.                       strcpy(msg_id, p);
  5119.                   }
  5120. !                 if (strnicmp(buf,"Newsgroups:",11) == 0) strcpy(newsgroups,buf);
  5121. !                 if (strnicmp(buf,"Subject:",8) == 0) {
  5122.                       strcpy(subject, buf+8);
  5123. !             }
  5124. !             }
  5125.               /* add our system name to the path list */
  5126.               if (strnicmp(buf, "Path:", 5) == 0) {
  5127.                   p = strtok(buf, " \t");
  5128.                   p = strtok(NULL, " \t");
  5129. !                 fprintf(spool_file, "Path: %s!%s", my_stuff.my_site, p);
  5130. !             } else {
  5131. !                 fprintf(spool_file, "%s", buf);
  5132.               }
  5133.           }
  5134.   
  5135.       }
  5136.   
  5137. !     /* process the last one */
  5138. !     if (strlen(newsgroups) != 0) {
  5139. !         strcpy(nglist, newsgroups+11);
  5140. !         p = strtok(newsgroups, " \r\n,:");
  5141. !         p = strtok(NULL, " \r\n,:");
  5142. !         while (p != '\x00') {
  5143.   
  5144. !             out_file = open_out_file(p);
  5145. !             where = ftell(out_file);
  5146. !             rewind(spool_file);
  5147. !             while (fgets(buf, 511, spool_file) != NULL)
  5148. !                 fputs(buf, out_file);
  5149. !             fprintf(out_file, "\n@@@@END\n");
  5150. !             fclose(out_file);
  5151.   
  5152. !             out_file = open_index_file(p);
  5153. !             gp = find_news_group(p);
  5154. !             fprintf(out_file,"%08ld %08ld %09ld %s", where, gp->hi_num, t, subject);
  5155. !             fclose(out_file);
  5156.   
  5157. !             p = strtok(NULL, " \r\n,:");
  5158. !         }
  5159. !         add_hist_record(msg_id, nglist);
  5160. !         fclose(spool_file);
  5161. !         unlink("$$item");
  5162. !     }
  5163.   }
  5164.   
  5165.   
  5166. --- 239,283 ----
  5167.               /* save the newsgroups line */
  5168.               if (in_header) {
  5169.                   if (strnicmp(buf,"Message-ID:",11) == 0) {
  5170. !                     strcpy(buf2, buf);
  5171. !                     p = strtok(buf2, " \t\r\n");  p = strtok(NULL, " \t\r\n");
  5172.                       strcpy(msg_id, p);
  5173.                   }
  5174. !                 if (strnicmp(buf,"Newsgroups:",11) == 0)
  5175. !                     strcpy(newsgroups,buf);
  5176. !                 if (strnicmp(buf,"Subject:",8) == 0)
  5177.                       strcpy(subject, buf+8);
  5178. !                 if (strnicmp(buf,"Control:",8) == 0)
  5179. !                     control = TRUE;
  5180.                   /* add our system name to the path list */
  5181.                   if (strnicmp(buf, "Path:", 5) == 0) {
  5182.                       p = strtok(buf, " \t");
  5183.                       p = strtok(NULL, " \t");
  5184. !             strcpy(buf2, p);
  5185. !                     sprintf(buf, "Path: %s!%s", my_stuff.my_site, buf2);
  5186.                   }
  5187.               }
  5188.   
  5189. +         if (spool == NULL)
  5190. +         spool = help = (LINE *) xmalloc(sizeof(LINE));
  5191. +         else {
  5192. +             help->next = (LINE *) xmalloc(sizeof(LINE));
  5193. +         help = help->next;
  5194.           }
  5195. +         help->next = NULL;
  5196. +         help->data = (char *) xmalloc(strlen(buf) + 1);
  5197. +         strcpy(help->data, buf);
  5198. +         }
  5199.   
  5200. !     }
  5201.   
  5202. !     /* process the last one */
  5203.   
  5204. !     if (control)
  5205. !         strcpy(newsgroups, "Newsgroups: control"); /* kludge */
  5206.   
  5207. !     if (spool != NULL)
  5208. !     save_message(spool, newsgroups, subject, msg_id);
  5209.   }
  5210.   
  5211.   
  5212. ***************
  5213. *** 264,270 ****
  5214.   
  5215.   
  5216.   /*--------------------------- unpack the batch ------------------------*/
  5217. ! FILE *decode_batches(char *fn, int no_toss)
  5218.   {
  5219.       /*
  5220.        *  take the batch, strip off the !cunbatch, and feed the file to
  5221. --- 285,291 ----
  5222.   
  5223.   
  5224.   /*--------------------------- unpack the batch ------------------------*/
  5225. ! FILE *decode_batch(char *fn, char *tn, int no_toss)
  5226.   {
  5227.       /*
  5228.        *  take the batch, strip off the !cunbatch, and feed the file to
  5229. ***************
  5230. *** 272,300 ****
  5231.        */
  5232.   
  5233.       FILE *in_file, *out_file;
  5234. !     int res, buf_cnt;
  5235. !     char buf[1025];
  5236. !     char name[128];
  5237.   
  5238.       buf_cnt = 0;
  5239.   
  5240.       /* open the batch file */
  5241. !     strcpy(name, fn);
  5242. !     if ((in_file = fopen(name, "rb")) == NULL) {
  5243. !         printf("batchfile %s could not be opened\n", name);
  5244.           return(NULL);
  5245.       }
  5246.   
  5247.       /* open the compressed */
  5248. !     sprintf(name, "%s.z", my_stuff.temp_name);
  5249. !     if ((out_file = fopen(name, "wb")) == NULL) {
  5250. !         printf("cannot open output file %s\n", name);
  5251.           return(NULL);
  5252.       }
  5253.   
  5254.       while ((res = fread(buf, 1, 1024, in_file)) > 0) {
  5255. !         fwrite(buf_cnt == 0 ? buf+12 : buf, 1,
  5256. !                buf_cnt == 0 ? res-12 : res, out_file);
  5257.           buf_cnt++;
  5258.       }
  5259.   
  5260. --- 293,354 ----
  5261.        */
  5262.   
  5263.       FILE *in_file, *out_file;
  5264. !     int res, buf_cnt, header;
  5265. !     char buf[1025], out[256];
  5266. !     char compr[16];
  5267. !     long pos;
  5268. !     short magic;
  5269.   
  5270.       buf_cnt = 0;
  5271. +     header = FALSE;
  5272. +     *tn = 0;
  5273.   
  5274.       /* open the batch file */
  5275. !     if ((in_file = fopen(fn, "rb")) == NULL) {
  5276. !         printf("batchfile %s could not be opened\n", fn);
  5277. !         return(NULL);
  5278. !     }
  5279. !     if (fread(buf, 1, 12, in_file) == 0) {
  5280. !         printf("batch %s is inexplicably too small\n", fn);
  5281. !         return(NULL);
  5282. !     }
  5283. !     if (memcmp(buf, "#! rnews ", 9) == 0) {
  5284. !         rewind(in_file);
  5285. !     return(in_file);
  5286. !     }
  5287. !     if (memcmp(buf, "#! cunbatch\n", 12) == 0)
  5288. !         header = TRUE;
  5289. !     else if (memcmp(buf, "#! funbatch\n", 12) == 0)
  5290. !         header = TRUE;
  5291. !     else
  5292. !         rewind(in_file);
  5293. !     pos = ftell(in_file);
  5294. !     fread(&magic, 1, sizeof(short), in_file);
  5295. !     fseek(in_file, pos, SEEK_SET);
  5296. !     if (magic == COMPRESS)
  5297. !         strcpy(compr, "compress");
  5298. !     else if (magic == FREEZE)
  5299. !         strcpy(compr, "freeze");
  5300. !     else {
  5301. !         printf("batch %s has unknown compression type\n", fn);
  5302.       return(NULL);
  5303.       }
  5304.   
  5305. +     if (header) {
  5306.       /* open the compressed */
  5307. !     sprintf(tn, "%s\\unbatch.tmp", my_stuff.temp_name);
  5308. !     if ((out_file = fopen(tn, "wb")) == NULL) {
  5309. !         printf("cannot open output file %s\n", buf);
  5310.           return(NULL);
  5311.       }
  5312.   
  5313.       while ((res = fread(buf, 1, 1024, in_file)) > 0) {
  5314. !         fwrite(buf, 1, res, out_file);
  5315.           buf_cnt++;
  5316.       }
  5317.   
  5318. ***************
  5319. *** 301,320 ****
  5320.       fclose(in_file);
  5321.       fclose(out_file);
  5322.   
  5323. !     unlink(my_stuff.temp_name);
  5324. !     sprintf(name, "compress -d %s.z", my_stuff.temp_name);
  5325. !     /* printf("unbatch: decompressing batch (%s)\n", name); */
  5326. !     system(name);
  5327.         
  5328. !     if (no_toss) return(NULL);
  5329.   
  5330.       /* open the uncompressed */
  5331. !     sprintf(name, "%s", my_stuff.temp_name);
  5332. !     if ((out_file = fopen(name, "rb")) == NULL) {
  5333. !         printf("cannot open uncompressed file %s\n", name);
  5334.           return(NULL);
  5335.       }
  5336.   
  5337.       return(out_file);
  5338.   }
  5339. --- 355,395 ----
  5340.       fclose(in_file);
  5341.       fclose(out_file);
  5342.   
  5343. !     if (no_toss) {
  5344. !         sprintf(out, "%s\\n_XXXXXX", my_stuff.temp_name);
  5345. !         mktemp(out);
  5346. !         sprintf(buf, "%s -d <%s >%s", compr, tn, out);
  5347. !         system(buf);
  5348. !         unlink(tn);
  5349. !         return(NULL);
  5350. !     }
  5351. !     /* open the uncompressed */
  5352. !     sprintf(buf, "%s -d <%s", compr, tn);
  5353. !     if ((out_file = popen(buf, "rb")) == NULL) {
  5354. !         printf("cannot open pipe to \"%s\"\n", buf);
  5355. !         return(NULL);
  5356. !     }
  5357. !     }
  5358. !     else {
  5359. !         fclose(in_file);
  5360. !     *tn = 0;
  5361.         
  5362. !     if (no_toss) {
  5363. !         sprintf(out, "%s\\n_XXXXXX", my_stuff.temp_name);
  5364. !         mktemp(out);
  5365. !         sprintf(buf, "%s -d <%s >%s", compr, fn, out);
  5366. !         system(buf);
  5367. !         return(NULL);
  5368. !     }
  5369.   
  5370.       /* open the uncompressed */
  5371. !     sprintf(buf, "%s -d <%s", compr, fn);
  5372. !     if ((out_file = popen(buf, "rb")) == NULL) {
  5373. !         printf("cannot open pipe to \"%s\"\n", buf);
  5374.           return(NULL);
  5375.       }
  5376. +     }
  5377.   
  5378.       return(out_file);
  5379.   }
  5380. diff -cb orig/unbatch.h new/unbatch.h
  5381. *** orig/unbatch.h    Thu Jun 11 22:48:17 1992
  5382. --- new/unbatch.h    Sun Aug 02 20:34:18 1992
  5383. ***************
  5384. *** 1,5 ****
  5385.   /*
  5386. !     SNEWS 1.0
  5387.   
  5388.       Unbatch private decls
  5389.   
  5390. --- 1,5 ----
  5391.   /*
  5392. !     SNEWS 2.0
  5393.   
  5394.       Unbatch private decls
  5395.   
  5396. ***************
  5397. *** 27,31 ****
  5398.   
  5399.   
  5400.   /*----------------------------- prototypes --------------------------------*/
  5401. ! FILE *decode_batches(char *fn, int no_toss);
  5402.   void toss(FILE *tmp_file);
  5403. --- 27,34 ----
  5404.   
  5405.   
  5406.   /*----------------------------- prototypes --------------------------------*/
  5407. ! FILE *decode_batch(char *fn, char *tn, int no_toss);
  5408.   void toss(FILE *tmp_file);
  5409. + #define COMPRESS     0x9D1F
  5410. + #define FREEZE       0x9F1F
  5411.