home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume23 / tin / part05 < prev    next >
Text File  |  1991-09-25  |  51KB  |  2,469 lines

  1. Newsgroups: comp.sources.misc
  2. From: iain@estevax.uucp (Iain J. Lea)
  3. Subject:  v23i019:  tin - threaded full screen newsreader v1.0 PL2, Part05/09
  4. Message-ID: <1991Sep25.205221.2056@sparky.imd.sterling.com>
  5. X-Md4-Signature: 4a1bc3779892384aae5396602b0d9d7a
  6. Date: Wed, 25 Sep 1991 20:52:21 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: iain@estevax.uucp (Iain J. Lea)
  10. Posting-number: Volume 23, Issue 19
  11. Archive-name: tin/part05
  12. Environment: BSD, SCO, ISC, SUNOS, SYSVR3, SYSVR4, ULTRIX, XENIX
  13.  
  14. #!/bin/sh
  15. # this is tin.shar.05 (part 5 of tin1.02)
  16. # do not concatenate these parts, unpack them in order with /bin/sh
  17. # file misc.c continued
  18. #
  19. if touch 2>&1 | fgrep '[-amc]' > /dev/null
  20.  then TOUCH=touch
  21.  else TOUCH=true
  22. fi
  23. if test ! -r shar3_seq_.tmp; then
  24.     echo "Please unpack part 1 first!"
  25.     exit 1
  26. fi
  27. (read Scheck
  28.  if test "$Scheck" != 5; then
  29.     echo "Please unpack part $Scheck next!"
  30.     exit 1
  31.  else
  32.     exit 0
  33.  fi
  34. ) < shar3_seq_.tmp || exit 1
  35. echo "x - Continuing file misc.c"
  36. sed 's/^X//' << 'SHAR_EOF' >> misc.c &&
  37. X    int    line;
  38. X    char    *cond;
  39. X{
  40. X    fprintf(stderr, "%s: assertion failure: %s (%d): %s\n",progname,file,line,cond);
  41. X    fflush (stderr);
  42. X    exit(1);
  43. X}
  44. X
  45. X
  46. Xvoid copy_fp(a, b, prefix)
  47. X    FILE *a;
  48. X    FILE *b;
  49. X    char *prefix;
  50. X{
  51. X    char buf[8192];
  52. X
  53. X    while (fgets (buf, sizeof (buf), a) != NULL)
  54. X        fprintf (b, "%s%s", prefix, buf);
  55. X}
  56. X
  57. X
  58. Xchar *get_val(env, def)
  59. X    char *env;        /* Environment variable we're looking for    */
  60. X    char *def;        /* Default value if no environ value found    */
  61. X{
  62. X    char *ptr;
  63. X
  64. X    if ((ptr = (char *) getenv(env)) != NULL)
  65. X        return (ptr);
  66. X    else
  67. X        return (def);
  68. X}
  69. X
  70. X
  71. Xint invoke_editor (nam)
  72. X    char *nam;
  73. X{
  74. X    char buf[LEN+1];
  75. X    static char editor[LEN+1];
  76. X    static int first = TRUE;
  77. X
  78. X    if (first) {
  79. X        strcpy (editor, get_val ("EDITOR", DEFAULT_EDITOR));
  80. X        first = FALSE;
  81. X    }
  82. X
  83. X#ifdef DONT_USE_START_LINE
  84. X    sprintf (buf, "%s %s", editor, nam);
  85. X#else
  86. X    sprintf (buf, "%s +%d %s", editor, start_line_offset, nam);
  87. X#endif
  88. X
  89. X    printf ("%s", buf);
  90. X    return invoke_cmd (buf);
  91. X}
  92. X
  93. X
  94. Xvoid shell_escape ()
  95. X{
  96. X    char shell[LEN+1];
  97. X    char *p;
  98. X
  99. X#ifdef SIGTSTP
  100. X    void (*susp)();
  101. X#endif
  102. X
  103. X    if (! parse_string (txt_shell_escape, shell))
  104. X        strcpy (shell, get_val ("SHELL", DEFAULT_SHELL));
  105. X
  106. X    for (p = shell; *p && (*p == ' ' || *p == '\t'); p++)
  107. X        continue;
  108. X
  109. X    if (! *p)
  110. X        strcpy (shell, get_val ("SHELL", DEFAULT_SHELL));
  111. X    
  112. X    Raw (FALSE);
  113. X
  114. X    set_real_uid_gid ();
  115. X
  116. X    fputs ("\r\n", stdout);
  117. X
  118. X#ifdef SIGTSTP
  119. X    if (do_sigtstp)
  120. X        susp = signal (SIGTSTP, SIG_DFL);
  121. X#endif
  122. X
  123. X    system (p);
  124. X
  125. X#ifdef SIGTSTP
  126. X    if (do_sigtstp)
  127. X        signal (SIGTSTP, susp);
  128. X#endif
  129. X
  130. X    set_tin_uid_gid ();
  131. X
  132. X    Raw (TRUE);
  133. X
  134. X    mail_setup ();
  135. X
  136. X    continue_prompt ();
  137. X
  138. X    if (draw_arrow_mark) {
  139. X        ClearScreen ();
  140. X    }
  141. X}
  142. X
  143. X
  144. Xvoid tin_done (ret)
  145. X    int ret;
  146. X{
  147. X    nntp_finish ();            /* disconnect from NNTP server */
  148. X    free_all_arrays ();        /* deallocate all arrays */
  149. X    ClearScreen();
  150. X    Raw(FALSE);
  151. X    exit(ret);
  152. X}
  153. X
  154. X/*
  155. X *  Load the active file into active[] and create copy of active ~/.tin/active
  156. X */
  157. X
  158. Xint read_active ()
  159. X{
  160. X    FILE *fp;
  161. X    char *p, *q;
  162. X    char buf[LEN+1];
  163. X    int created, i;
  164. X    long h;
  165. X    
  166. X    num_active = 0;
  167. X
  168. X    if ((fp = open_active_fp ()) == NULL) {
  169. X        if (compiled_with_nntp) {
  170. X            printf ("Cannot open %s. Try %s -r to read news via NNTP.\n",
  171. X                active_file, progname);
  172. X        } else {
  173. X            printf (txt_cannot_open, active_file);
  174. X        }
  175. X        fflush (stdout);
  176. X        exit (1);
  177. X    }
  178. X
  179. X    while (fgets (buf, sizeof (buf), fp) != NULL) {
  180. X        for (p = buf; *p && *p != ' '; p++)
  181. X            continue;
  182. X        if (*p != ' ') {
  183. X            error_message (txt_bad_active_file, "");
  184. X            continue;
  185. X        }
  186. X        *p++ = '\0';
  187. X
  188. X        if (num_active >= max_active)
  189. X            expand_active ();
  190. X
  191. X        h = hash_groupname (buf);
  192. X
  193. X        if (group_hash[h] == -1) {
  194. X            group_hash[h] = num_active;
  195. X        } else {                /* hash linked list chaining */
  196. X            for (i=group_hash[h]; active[i].next >= 0; i=active[i].next) {
  197. X                if (strcmp(active[i].name, buf) == 0) {
  198. X                    goto read_active_continue;        /* kill dups */
  199. X                }
  200. X            }
  201. X            if (strcmp(active[i].name, buf) == 0)
  202. X                goto read_active_continue;
  203. X            active[i].next = num_active;
  204. X        }
  205. X
  206. X        for (q = p; *q && *q != ' '; q++)
  207. X            continue;
  208. X        if (*q != ' ') {
  209. X            error_message (txt_bad_active_file, "");
  210. X            continue;
  211. X        }
  212. X
  213. X        active[num_active].name = str_dup (buf);
  214. X        active[num_active].max = (long) atol (p);
  215. X        active[num_active].min = (long) atol (q);
  216. X        active[num_active].next = -1;        /* hash chaining */
  217. X        active[num_active].flag = NOTGOT;   /* not in my_group[] yet */
  218. X
  219. X        num_active++;
  220. X
  221. Xread_active_continue:;
  222. X
  223. X    }
  224. X    fclose (fp);
  225. X
  226. X    /*
  227. X     *  exit if active file is empty
  228. X     */
  229. X    if (! num_active) {
  230. X        error_message ("%s contains no newsgroups. Exiting.", active_file);
  231. X        exit (1);
  232. X    }
  233. X
  234. X    /*
  235. X     *  create backup of LIBDIR/active for use by -n option to notify new groups 
  236. X     */
  237. X    created = backup_active (TRUE);
  238. X
  239. X#ifdef SORT_ACTIVE_FILE        /* DOES NOT WORK - ERROR */
  240. X    if (num_active) {
  241. X        qsort (active, num_active, sizeof (struct group_ent), active_comp);
  242. X    }
  243. X#endif    
  244. X
  245. X    debug_print_active ();
  246. X
  247. X    return (created);
  248. X}
  249. X
  250. X
  251. X#ifdef SORT_ACTIVE_FILE        /* DOES NOT WORK - ERROR */
  252. Xint active_comp (p1, p2)
  253. X     char *p1;
  254. X     char *p2;
  255. X  {
  256. X     struct group_ent *s1 = (struct group_ent *) p1;
  257. X     struct group_ent *s2 = (struct group_ent *) p2;
  258. X    /* s1->name less than s2->name */
  259. X    if (strcmp (s1->name, s2->name) < 0) {
  260. X        return -1;
  261. X    }
  262. X    /* s1->name greater than s2->name */
  263. X    if (strcmp (s1->name, s2->name) > 0) {
  264. X        return 1;
  265. X    }
  266. X    return 0;
  267. X}
  268. X#endif
  269. X
  270. X
  271. X/*
  272. X *  create ~/.tin/active from LIBDIR/active if it does not exist 
  273. X */
  274. X
  275. Xint backup_active (create)
  276. X    int create;
  277. X{
  278. X    char buf[LEN];
  279. X    FILE *fp;
  280. X    int created = FALSE;
  281. X    int i;
  282. X    struct stat sb;
  283. X    
  284. X    set_real_uid_gid ();
  285. X    
  286. X    sprintf (buf, "%s/active", rcdir);
  287. X    
  288. X    if (create) {
  289. X        if (stat (buf, &sb) != -1) {
  290. X            goto backup_active_done;
  291. X        }
  292. X    }
  293. X    
  294. X    if ((fp = fopen (buf, "w")) != NULL) {
  295. X        for (i = 0; i < num_active ; i++) {    /* for each group */
  296. X            fprintf (fp, "%s\n", active[i].name);
  297. X        }
  298. X        fclose (fp);
  299. X        chmod (buf, 0644);
  300. X        created = TRUE;
  301. X    }
  302. X
  303. Xbackup_active_done:
  304. X    set_tin_uid_gid ();
  305. X    return (created);
  306. X}
  307. X
  308. X
  309. Xvoid add_signature (fp, flag)
  310. X    FILE *fp;
  311. X    int flag;
  312. X{
  313. X    FILE *sigf;
  314. X
  315. X    if ((sigf = fopen(signature, "r")) != NULL) {
  316. X        if (flag) {
  317. X            fprintf(fp, "\n--\n");
  318. X            copy_fp(sigf, fp, "");
  319. X        }
  320. X        fclose(sigf);
  321. X        return;
  322. X    }
  323. X
  324. X    if ((sigf = fopen(sig, "r")) != NULL) {
  325. X        fprintf(fp, "\n--\n");
  326. X        copy_fp(sigf, fp, "");
  327. X        fclose(sigf);
  328. X    }
  329. X}
  330. X
  331. X
  332. X#ifdef USE_MKDIR
  333. Xmkdir (path, mode)
  334. X    char *path;
  335. X    int mode;
  336. X{
  337. X    char buf[LEN+1];
  338. X    struct stat sb;
  339. X
  340. X    sprintf(buf, "mkdir %s", path);
  341. X    if (stat (path, &sb) == -1) {
  342. X        system (buf);
  343. X        chmod (path, mode);
  344. X    }
  345. X}
  346. X#endif
  347. X
  348. X
  349. Xlong hash_groupname (buf)        /* hash group name for fast lookup later */
  350. X    char *buf;
  351. X{
  352. X    unsigned long h;
  353. X    unsigned char *t = (unsigned char *) buf;
  354. X
  355. X    h = *t++;
  356. X    while (*t)
  357. X        h = ((h << 1) ^ *t++) % TABLE_SIZE;
  358. X
  359. X    return h;
  360. X}
  361. X
  362. X
  363. Xvoid rename_file (old_filename, new_filename)
  364. X    char *old_filename;
  365. X    char *new_filename;
  366. X{    
  367. X    char buf[LEN];
  368. X    
  369. X    unlink (new_filename);
  370. X    if (link (old_filename, new_filename) == 1) {
  371. X        sprintf (buf, txt_rename_error, old_filename, new_filename);
  372. X        error_message (buf, "TWO");
  373. X        return;
  374. X    }
  375. X    if (unlink (old_filename) == -1) {
  376. X        sprintf (buf, txt_rename_error, old_filename, new_filename);
  377. X        error_message (buf, "THREE");
  378. X        return;
  379. X    }
  380. X}
  381. X
  382. X
  383. Xchar *str_dup (str)
  384. X    char *str;
  385. X{
  386. X    char *dup = (char *) 0;
  387. X
  388. X    assert (str != (char *) 0);
  389. X    
  390. X    if (str) {
  391. X        dup = my_malloc (strlen (str)+1);
  392. X        strcpy (dup, str);
  393. X    }
  394. X    return dup;
  395. X}
  396. X
  397. X
  398. Xint invoke_cmd (nam)
  399. X    char *nam;
  400. X{
  401. X    int ret;
  402. X
  403. X#ifdef SIGTSTP
  404. X    void (*susp)();
  405. X#endif
  406. X
  407. X    Raw (FALSE);
  408. X    set_real_uid_gid ();
  409. X
  410. X#ifdef SIGTSTP
  411. X    if (do_sigtstp)
  412. X        susp = signal(SIGTSTP, SIG_DFL);
  413. X#endif
  414. X
  415. X    ret = system (nam);
  416. X
  417. X#ifdef SIGTSTP
  418. X    if (do_sigtstp)
  419. X        signal (SIGTSTP, susp);
  420. X#endif
  421. X
  422. X    set_tin_uid_gid ();
  423. X    Raw (TRUE);
  424. X
  425. X    return ret == 0;
  426. X}
  427. X
  428. X
  429. Xvoid draw_percent_mark (cur_num, max_num)
  430. X    int cur_num;
  431. X    int max_num;
  432. X{
  433. X    char buf[32];
  434. X    int percent = 0;
  435. X
  436. X    if (NOTESLINES <= 0) {
  437. X        return;
  438. X    }
  439. X
  440. X    if (cur_num <= 0 && max_num <= 0) {
  441. X        return;
  442. X    }
  443. X        
  444. X    percent = cur_num * 100 / max_num;
  445. X    sprintf (buf, "%s(%d%%) [%d/%d]", txt_more, percent, cur_num, max_num);
  446. X    MoveCursor (LINES, (COLS - (int) strlen (buf))-(1+BLANK_PAGE_COLS));
  447. X    StartInverse ();    
  448. X    printf ("%s", buf);
  449. X    fflush (stdout);
  450. X    EndInverse ();
  451. X}
  452. X
  453. X
  454. Xvoid set_real_uid_gid ()
  455. X{
  456. X    setuid (real_uid);
  457. X    setgid (real_gid);
  458. X}
  459. X
  460. X
  461. Xvoid set_tin_uid_gid ()
  462. X{
  463. X    setuid (tin_uid);
  464. X    setgid (tin_gid);
  465. X}
  466. X
  467. X
  468. Xvoid notify_groups ()
  469. X{
  470. X    char buf[LEN];
  471. X    FILE *fp;
  472. X    int group_not_found;
  473. X    int i, j, index;
  474. X    int num = 0;
  475. X    int update_old_active = FALSE;
  476. X    struct notify_t {
  477. X        char name[LEN];
  478. X        int len;
  479. X    } *old_active;
  480. X    
  481. X    set_real_uid_gid ();
  482. X    
  483. X    sprintf (buf, "%s/active", rcdir);
  484. X    
  485. X    if ((fp = fopen (buf, "r")) == NULL) {
  486. X        error_message (txt_cannot_open, buf);
  487. X        goto notify_groups_done;
  488. X    }
  489. X
  490. X    Raw (FALSE);
  491. X    
  492. X    printf ("Checking for new newsgroups...");
  493. X    fflush (stdout);
  494. X    
  495. X    old_active = (struct notify_t *) my_malloc (sizeof (struct notify_t) * num_active);
  496. X    if (old_active == (struct notify_t *) 0) {
  497. X        error_message (txt_out_of_memory, progname);
  498. X        goto notify_groups_done;
  499. X    }
  500. X    
  501. X    while (fgets (old_active[num].name, sizeof (old_active[num].name), fp) != NULL) {
  502. X        old_active[num].len = strlen (old_active[num].name)-1;
  503. X        old_active[num].name[old_active[num].len] = '\0';
  504. X        num++;
  505. X        if (num == num_active) {
  506. X            break;
  507. X        }
  508. X    }
  509. X
  510. X    for (i = 0 ; i < num_active ; i++) {    
  511. X        group_not_found = TRUE;
  512. X        for (j=0; j < num ; j++) {
  513. X            if (strncmp (old_active[j].name, active[i].name, old_active[j].len) == 0) {
  514. X                group_not_found = FALSE;        /* found it so read in next group */
  515. X                break;
  516. X            }
  517. X        }
  518. X
  519. X        if (group_not_found) {
  520. X/*
  521. X&& strlen (active[i].name) == old_active[j].len) {
  522. X*/
  523. X            update_old_active = TRUE;
  524. X            printf ("\r\nSubscribe to %s (y/n): ", active[i].name);
  525. X            fflush (stdout);
  526. X            scanf ("%s", buf);
  527. X            if (buf[0] == 'y') {
  528. X                index = add_group (active[i].name, TRUE);
  529. X                subscribe (active[my_group[index]].name, ':',
  530. X                    my_group[index], FALSE);
  531. X            }
  532. X            printf ("Checking...");
  533. X            fflush (stdout);
  534. X        }
  535. X    }
  536. X    fclose (fp);
  537. X
  538. X    if (old_active != (struct notify_t *) 0) {
  539. X        free (old_active);
  540. X        old_active = (struct notify_t *) 0;
  541. X    }
  542. X
  543. X    Raw (TRUE);
  544. X
  545. X    /*
  546. X     *  write active[] to ~/.tin/active
  547. X     */
  548. X    if (update_old_active) {
  549. X        backup_active (FALSE);
  550. X    }
  551. X
  552. Xnotify_groups_done:
  553. X    set_tin_uid_gid ();
  554. X}
  555. X
  556. X
  557. Xvoid basename (dirname, basename)
  558. X    char *dirname;        /* argv[0] */
  559. X    char *basename;        /* progname is returned */
  560. X{
  561. X    int i;
  562. X    
  563. X    strcpy (basename, dirname);
  564. X    
  565. X    for (i=(int) strlen(dirname)-1 ; i ; i--) {
  566. X        if (dirname[i] == '/') {
  567. X            strcpy (basename, dirname+(i+1));
  568. X            break;
  569. X        }
  570. X    }
  571. X}
  572. X
  573. X
  574. X/*
  575. X *  Record size of mailbox so we can detect if new mail has arrived
  576. X */
  577. X
  578. Xvoid mail_setup ()
  579. X{
  580. X    struct stat buf;
  581. X
  582. X    mailbox_name = get_val ("MAIL", mailbox);
  583. X
  584. X    if (stat (mailbox_name, &buf) >= 0) {
  585. X        mailbox_size = buf.st_size;
  586. X    } else {
  587. X        mailbox_size = 0;
  588. X    }
  589. X}
  590. X
  591. X/*
  592. X *  Return TRUE if new mail has arrived
  593. X */
  594. X
  595. Xint mail_check ()
  596. X{
  597. X    struct stat buf;
  598. X
  599. X    if (mailbox_name != NULL
  600. X    &&  stat(mailbox_name, &buf) >= 0
  601. X    &&  mailbox_size < buf.st_size)
  602. X        return TRUE;
  603. X
  604. X    return FALSE;
  605. X}
  606. SHAR_EOF
  607. echo "File misc.c is complete" &&
  608. $TOUCH -am 0923200291 misc.c &&
  609. chmod 0600 misc.c ||
  610. echo "restore of misc.c failed"
  611. set `wc -c misc.c`;Wc_c=$1
  612. if test "$Wc_c" != "19195"; then
  613.     echo original size 19195, current size $Wc_c
  614. fi
  615. # ============= newsrc.c ==============
  616. echo "x - extracting newsrc.c (Text)"
  617. sed 's/^X//' << 'SHAR_EOF' > newsrc.c &&
  618. X/*
  619. X *  Project   : tin - a visual threaded usenet newsreader
  620. X *  Module    : newsrc.c
  621. X *  Author    : R.Skrenta / I.Lea
  622. X *  Created   : 01-04-91
  623. X *  Updated   : 23-09-91
  624. X *  Release   : 1.0
  625. X *  Notes     :
  626. X *  Copyright : (c) Copyright 1991 by Rich Skrenta & Iain Lea
  627. X *                You may  freely  copy or  redistribute  this software,
  628. X *              so  long as there is no profit made from its use, sale
  629. X *              trade or  reproduction.  You may not change this copy-
  630. X *              right notice, and it must be included in any copy made
  631. X */
  632. X
  633. X#include    "tin.h"
  634. X
  635. X
  636. X/*
  637. X * make a backup of users .newsrc in case of the bogie man
  638. X */
  639. X
  640. Xvoid backup_newsrc ()
  641. X{
  642. X    char buf[8192];
  643. X    FILE *fp_newsrc, *fp_backup;
  644. X    
  645. X    set_real_uid_gid ();
  646. X    
  647. X    if ((fp_newsrc = fopen (newsrc, "r")) != NULL) {
  648. X        sprintf (buf, "%s/.oldnewsrc", homedir);
  649. X        if ((fp_backup = fopen (buf, "w")) != NULL) {
  650. X            while (fgets (buf, sizeof (buf), fp_newsrc) != NULL) {
  651. X                fputs (buf, fp_backup);
  652. X            }
  653. X            fclose (fp_backup);
  654. X        }
  655. X        fclose (fp_newsrc);
  656. X    }
  657. X
  658. X    set_tin_uid_gid ();
  659. X}
  660. X
  661. X/*
  662. X *  Read $HOME/.newsrc into my_group[]. my_group[] ints point to
  663. X *  active[] entries.  Sub_only determines  whether we just read
  664. X *  subscribed groups or all of them.
  665. X */
  666. X
  667. Xvoid read_newsrc (sub_only)
  668. X    int sub_only;        /* TRUE=subscribed groups only, FALSE=all groups */
  669. X{
  670. X    char c, *p, buf[8192];
  671. X    char old_groups[LEN];
  672. X    FILE *fp, *fp_old;
  673. X    int i;
  674. X    int remove_old_groups = FALSE;
  675. X
  676. X    local_top = 0;
  677. X
  678. X    set_real_uid_gid ();
  679. X    
  680. X    if ((fp = fopen (newsrc, "r")) == NULL) {  /* attempt to make a .newsrc */
  681. X        for (i = 0; i < num_active; i++) {
  682. X            if (local_top >= max_active) {
  683. X                expand_active ();
  684. X            }
  685. X            my_group[local_top] = i;
  686. X            active[i].flag = 0;
  687. X            unread[local_top] = -1;
  688. X            local_top++;
  689. X        }
  690. X        write_newsrc ();
  691. X        return;
  692. X    }
  693. X
  694. X    sprintf (old_groups, "%s/.newsrc.%d", homedir, getpid ());
  695. X
  696. X    while (fgets (buf, sizeof buf, fp) != NULL) {
  697. X        p = buf;
  698. X        while (*p && *p != '\n' && *p != ' ' && *p != ':' && *p != '!')
  699. X            p++;
  700. X        c = *p;
  701. X        *p++ = '\0';
  702. X
  703. X        if (c == '!' && sub_only)
  704. X            continue;        /* unsubscribed */
  705. X
  706. X#ifdef XXX
  707. X        if (strncmp ("options ", buf, 8) == 0)
  708. X            continue;        /* options line */
  709. X#endif
  710. X
  711. X        if ((i = add_group (buf, FALSE)) < 0) {
  712. X            if (! remove_old_groups) {
  713. X                if ((fp_old = fopen (old_groups, "w")) == NULL) {
  714. X                    error_message (txt_cannot_open, old_groups);
  715. X                    continue;
  716. X                }
  717. X                remove_old_groups = TRUE;
  718. X            }
  719. X            fprintf (fp_old, "%s\n", buf);
  720. X            continue;
  721. X        }
  722. X
  723. X        if (c != '!')        /* if we're subscribed to it */
  724. X            active[my_group[i]].flag |= SUBS;
  725. X
  726. X        unread[i] = parse_unread (p, my_group[i]);
  727. X    }
  728. X    fclose (fp);
  729. X
  730. X    /*
  731. X     *  rewrite newsrc to get rid of any non-existant groups 
  732. X     */
  733. X    if (remove_old_groups) {
  734. X        fclose (fp_old);
  735. X        rewrite_newsrc ();
  736. X    }
  737. X
  738. X    set_tin_uid_gid ();
  739. X}
  740. X
  741. X/*
  742. X *  Write a new newsrc from my_group[] and active[] mygroup if
  743. X *  rewriting to get rid of groups that don't exist any longer. Used
  744. X *  to a create a new .newsrc if there isn't one already, or when
  745. X *  the newsrc is reset.
  746. X */
  747. X
  748. Xvoid write_newsrc ()
  749. X{
  750. X    FILE *fp;
  751. X    int i;
  752. X
  753. X    set_real_uid_gid ();
  754. X
  755. X    if ((fp = fopen (newsrc, "w")) == NULL)
  756. X        goto write_newsrc_done;
  757. X
  758. X    for (i=0 ; i < num_active ; i++) {
  759. X        fprintf (fp, "%s: \n", active[i].name);
  760. X    }
  761. X
  762. X    fclose (fp);
  763. X
  764. Xwrite_newsrc_done:
  765. X    set_tin_uid_gid ();
  766. X}
  767. X
  768. X/*
  769. X *  Rewrite newsrc to get rid of groups that don't exist any longer.
  770. X */
  771. X
  772. Xvoid rewrite_newsrc ()
  773. X{
  774. X    char buf[8192], old[LEN+1];
  775. X    char old_groups[LEN];
  776. X    FILE *fp, *fp_old, *fp_new;
  777. X    int found_old_group, len;    
  778. X
  779. X    set_real_uid_gid ();
  780. X
  781. X    sprintf (old_groups, "%s/.newsrc.%d", homedir, getpid ());
  782. X
  783. X    if ((fp = fopen (newsrc, "r")) == NULL)
  784. X        goto removed_old_groups_done;
  785. X
  786. X    if ((fp_old = fopen (old_groups, "r")) == NULL)
  787. X        goto removed_old_groups_done;
  788. X
  789. X    if ((fp_new = fopen (newnewsrc, "w")) == NULL)
  790. X        goto removed_old_groups_done;
  791. X
  792. X    while (fgets (buf, sizeof buf, fp) != NULL) {            /* read group from newsrc */
  793. X        rewind (fp_old);
  794. X        found_old_group = FALSE;    
  795. X        while (fgets (old, sizeof old, fp_old) != NULL) {    /* read group from oldgroups */
  796. X            len = strlen (old)-1;
  797. X            if ((buf[len] == ':' || buf[len] == '!') &&
  798. X                strncmp (buf, old, len) == 0) {
  799. X                old[len] = '\0';
  800. X                fprintf (stderr, txt_not_in_active_file, old);
  801. X                fprintf (stderr, ". Deleting.\n");
  802. X                fflush (stderr);
  803. X                found_old_group = TRUE;    
  804. X            }
  805. X        }
  806. X        if (! found_old_group) {
  807. X            fprintf (fp_new, "%s", buf);
  808. X        }
  809. X    }
  810. X    
  811. X    fclose (fp);
  812. X    fclose (fp_old);
  813. X    fclose (fp_new);
  814. X
  815. X    rename_file (newnewsrc, newsrc);
  816. X
  817. Xremoved_old_groups_done:
  818. X    unlink (old_groups);
  819. X    set_tin_uid_gid ();
  820. X}
  821. X
  822. X/*
  823. X *  Load the sequencer rang lists and mark arts[] according to the
  824. X *  .newsrc info for a particular group.  i.e.  rec.arts.comics: 1-94,97
  825. X */
  826. X
  827. Xvoid read_newsrc_line (group)
  828. X    char *group;
  829. X{
  830. X    FILE *fp;
  831. X    char buf[8192];
  832. X    char *p;
  833. X
  834. X    if ((fp = fopen (newsrc, "r")) == NULL)
  835. X        return;
  836. X
  837. X    while (fgets (buf, sizeof buf, fp) != NULL) {
  838. X        p = buf;
  839. X        while (*p && *p != '\n' && *p != ' ' && *p != ':' && *p != '!')
  840. X            p++;
  841. X        *p++ = '\0';
  842. X        if (strcmp (buf, group) != 0)
  843. X            continue;
  844. X        parse_seq (p);
  845. X        break;
  846. X    }
  847. X
  848. X    fclose (fp);
  849. X}
  850. X
  851. X/*
  852. X *  For our current group, update the sequencer information in .newsrc
  853. X */
  854. X
  855. Xvoid update_newsrc (group, groupnum, mark_unread)
  856. X    char *group;
  857. X    int groupnum;            /* index into active[] for this group */
  858. X    int mark_unread;
  859. X{
  860. X    FILE *fp;
  861. X    FILE *newfp;
  862. X    char buf[8192];
  863. X    char *p;
  864. X    char c;
  865. X
  866. X    set_real_uid_gid ();
  867. X
  868. X    if ((newfp = fopen (newnewsrc, "w")) == NULL)
  869. X        goto update_done;
  870. X
  871. X    if ((fp = fopen (newsrc, "r")) != NULL) {
  872. X        while (fgets (buf, sizeof buf, fp) != NULL) {
  873. X            for (p = buf; *p; p++)
  874. X                if (*p == '\n') {
  875. X                    *p = '\0';
  876. X                    break;
  877. X                }
  878. X
  879. X            p = buf;
  880. X            while (*p && *p != ' ' && *p != ':' && *p != '!')
  881. X                    p++;
  882. X            c = *p;
  883. X            if (c != '\0')
  884. X                *p++ = '\0';
  885. X
  886. X            if (c != '!')
  887. X                c = ':';
  888. X
  889. X            if (strcmp (buf, group) == 0) {
  890. X                if (mark_unread) {
  891. X                    fprintf (newfp, "%s%c\n", buf, c);
  892. X                } else {
  893. X                    fprintf (newfp, "%s%c ", buf, c);
  894. X                    print_seq (newfp, groupnum);
  895. X                    fprintf (newfp, "\n");
  896. X                }
  897. X            } else
  898. X                fprintf (newfp, "%s%c%s\n", buf, c, p);
  899. X        }
  900. X        fclose (fp);
  901. X    }
  902. X
  903. X    fclose (newfp);
  904. X    rename_file (newnewsrc, newsrc);
  905. X
  906. Xupdate_done:
  907. X    set_tin_uid_gid ();
  908. X}
  909. X
  910. X/*
  911. X *  Subscribe/unsubscribe to a group in .newsrc.  ch should either be
  912. X *  '!' to unsubscribe or ':' to subscribe.  num is the group's index
  913. X *  in active[].
  914. X */
  915. X
  916. Xvoid subscribe (group, ch, num, out_seq)
  917. X    char *group;
  918. X    char ch;
  919. X    int num;
  920. X    int out_seq;                /* output sequencer info? */
  921. X{
  922. X    FILE *fp;
  923. X    FILE *newfp;
  924. X    char buf[8192];
  925. X    char *p;
  926. X    char c;
  927. X    int gotit = FALSE;
  928. X
  929. X    if (ch == '!')
  930. X        active[num].flag &= ~SUBS;
  931. X    else
  932. X        active[num].flag |= SUBS;
  933. X
  934. X    set_real_uid_gid ();
  935. X
  936. X    if ((newfp = fopen (newnewsrc, "w")) == NULL)
  937. X        goto subscribe_done;
  938. X
  939. X    if ((fp = fopen (newsrc, "r")) != NULL) {
  940. X        while (fgets (buf, sizeof buf, fp) != NULL) {
  941. X            if (strncmp ("options ", buf, 8) == 0) {
  942. X                fprintf (newfp, buf);
  943. X            } else {
  944. X                for (p = buf; *p; p++) {
  945. X                    if (*p == '\n') {
  946. X                        *p = '\0';
  947. X                        break;
  948. X                    }
  949. X                }    
  950. X
  951. X                p = buf;
  952. X                while (*p && *p != ' ' && *p != ':' && *p != '!')
  953. X                        p++;
  954. X                c = *p;
  955. X                if (c != '\0')
  956. X                    *p++ = '\0';
  957. X
  958. X                if (c != '!')
  959. X                    c = ':';
  960. X
  961. X                if (strcmp (buf, group) == 0) {
  962. X                    fprintf (newfp, "%s%c%s\n", buf, ch, p);
  963. X                    gotit = TRUE;
  964. X                } else {
  965. X                    fprintf (newfp, "%s%c%s\n", buf, c, p);
  966. X                }
  967. X            }
  968. X        }
  969. X        fclose (fp);
  970. X    }
  971. X
  972. X    if (! gotit) {
  973. X        if (out_seq) {
  974. X            fprintf (newfp, "%s%c ", group, ch);
  975. X            print_seq (newfp, num);
  976. X            fprintf (newfp, "\n");
  977. X        } else
  978. X            fprintf (newfp, "%s%c\n", group, ch);
  979. X    }
  980. X
  981. X    fclose (newfp);
  982. X    rename_file (newnewsrc, newsrc);
  983. X
  984. Xsubscribe_done:
  985. X    set_tin_uid_gid ();
  986. X}
  987. X
  988. X
  989. Xvoid reset_newsrc ()
  990. X{
  991. X    FILE *fp;
  992. X    FILE *newfp;
  993. X    char buf[8192];
  994. X    char *p;
  995. X    char c;
  996. X    int i;
  997. X
  998. X    set_real_uid_gid ();
  999. X
  1000. X    if ((newfp = fopen (newnewsrc, "w")) == NULL)
  1001. X        goto update_done;
  1002. X
  1003. X    if ((fp = fopen (newsrc, "r")) != NULL) {
  1004. X        while (fgets (buf, sizeof (buf), fp) != NULL) {
  1005. X            for (p = buf; *p && *p != '\n'; p++)
  1006. X                continue;
  1007. X            *p = '\0';
  1008. X
  1009. X            p = buf;
  1010. X            while (*p && *p != ' ' && *p != ':' && *p != '!')
  1011. X                    p++;
  1012. X            c = *p;
  1013. X            if (c != '\0')
  1014. X                *p++ = '\0';
  1015. X
  1016. X            if (c != '!')
  1017. X                c = ':';
  1018. X
  1019. X            fprintf (newfp, "%s%c\n", buf, c);
  1020. X        }
  1021. X        fclose (fp);
  1022. X    }
  1023. X
  1024. X    fclose (newfp);
  1025. X    rename_file (newnewsrc, newsrc);
  1026. X
  1027. Xupdate_done:
  1028. X    set_tin_uid_gid ();
  1029. X
  1030. X    for (i = 0; i < local_top; i++)
  1031. X        unread[i] = -1;
  1032. X}
  1033. X
  1034. X
  1035. Xvoid delete_group (group)
  1036. X    char *group;
  1037. X{
  1038. X    FILE *fp;
  1039. X    FILE *newfp;
  1040. X    char buf[8192];
  1041. X    char *p;
  1042. X    char c;
  1043. X    int gotit = FALSE;
  1044. X    FILE *del;
  1045. X
  1046. X    set_real_uid_gid ();
  1047. X
  1048. X    if ((newfp = fopen (newnewsrc, "w")) == NULL)
  1049. X        goto del_done;
  1050. X
  1051. X    if ((del = fopen (delgroups, "a+")) == NULL)
  1052. X        goto del_done;
  1053. X
  1054. X    if ((fp = fopen (newsrc, "r")) != NULL) {
  1055. X        while (fgets (buf, sizeof (buf), fp) != NULL) {
  1056. X            for (p = buf; *p && *p != '\n'; p++)
  1057. X                continue;
  1058. X            *p = '\0';
  1059. X
  1060. X            p = buf;
  1061. X            while (*p && *p != ' ' && *p != ':' && *p != '!')
  1062. X                    p++;
  1063. X            c = *p;
  1064. X            if (c != '\0')
  1065. X                *p++ = '\0';
  1066. X
  1067. X            if (c != '!')
  1068. X                c = ':';
  1069. X
  1070. X            if (strcmp (buf, group) == 0) {
  1071. X                fprintf (del, "%s%c%s\n", buf, c, p);
  1072. X                gotit = TRUE;
  1073. X            } else
  1074. X                fprintf (newfp, "%s%c%s\n", buf, c, p);
  1075. X        }
  1076. X        fclose (fp);
  1077. X    }
  1078. X
  1079. X    fclose (newfp);
  1080. X
  1081. X    if (! gotit)
  1082. X        fprintf (del, "%s! \n", group);
  1083. X
  1084. X    fclose (del);
  1085. X    rename_file (newnewsrc, newsrc);
  1086. X
  1087. Xdel_done:
  1088. X    set_tin_uid_gid ();
  1089. X}
  1090. X
  1091. X
  1092. Xint undel_group ()
  1093. X{
  1094. X    FILE *del;
  1095. X    FILE *newfp;
  1096. X    FILE *fp;
  1097. X    char buf[2][8192];
  1098. X    char *p;
  1099. X    int which = 0;
  1100. X    long h;
  1101. X    extern int cur_groupnum;
  1102. X    int i, j;
  1103. X    char c;
  1104. X
  1105. X    set_real_uid_gid ();
  1106. X
  1107. X    if ((del = fopen(delgroups, "r")) == NULL) {
  1108. X        set_tin_uid_gid ();
  1109. X        return FALSE;
  1110. X    }
  1111. X
  1112. X    unlink(delgroups);
  1113. X    
  1114. X    if ((newfp = fopen(delgroups, "w")) == NULL) {
  1115. X        set_tin_uid_gid ();
  1116. X        return FALSE;
  1117. X    }
  1118. X
  1119. X    buf[0][0] = '\0';
  1120. X    buf[1][0] = '\0';
  1121. X
  1122. X    while (fgets(buf[which], sizeof (buf[which]), del) != NULL) {
  1123. X        which = !which;
  1124. X        if (*buf[which])
  1125. X            fputs(buf[which], newfp);
  1126. X    }
  1127. X
  1128. X    fclose(del);
  1129. X    fclose(newfp);
  1130. X    which = !which;
  1131. X
  1132. X    if (!*buf[which]) {
  1133. X        set_tin_uid_gid ();
  1134. X        return FALSE;
  1135. X    }
  1136. X
  1137. X    for (p = buf[which]; *p && *p != '\n'; p++)
  1138. X        continue;
  1139. X    *p = '\0';
  1140. X
  1141. X    p = buf[which];
  1142. X    while (*p && *p != ' ' && *p != ':' && *p != '!')
  1143. X        p++;
  1144. X    c = *p;
  1145. X    if (c != '\0')
  1146. X        *p++ = '\0';
  1147. X
  1148. X    if (c != '!')
  1149. X        c = ':';
  1150. X
  1151. X    h = hash_groupname (buf[which]);
  1152. X
  1153. X    for (i = group_hash[h]; i >= 0; i = active[i].next) {
  1154. X        if (strcmp(buf[which], active[i].name) == 0) {
  1155. X            for (j = 0; j < local_top; j++)
  1156. X                if (my_group[j] == i) {
  1157. X                    set_tin_uid_gid ();
  1158. X                    return j;
  1159. X                }
  1160. X
  1161. X            active[i].flag &= ~NOTGOT;   /* mark that we got it */
  1162. X            if (c != '!')
  1163. X                active[i].flag |= SUBS;
  1164. X
  1165. X            if (local_top >= max_active)
  1166. X                expand_active();
  1167. X            local_top++;
  1168. X            for (j = local_top; j > cur_groupnum; j--) {
  1169. X                my_group[j] = my_group[j-1];
  1170. X                unread[j] = unread[j-1];
  1171. X            }
  1172. X            my_group[cur_groupnum] = i;
  1173. X            unread[cur_groupnum] = parse_unread(p, i);
  1174. X
  1175. X            if ((fp = fopen(newsrc, "r")) == NULL) {
  1176. X                set_tin_uid_gid ();
  1177. X                return FALSE;
  1178. X            }
  1179. X            if ((newfp = fopen(newnewsrc, "w")) == NULL) {
  1180. X                fclose(fp);
  1181. X                set_tin_uid_gid ();
  1182. X                return FALSE;
  1183. X            }
  1184. X            i = 0;
  1185. X            while (fgets(buf[!which], sizeof (buf[!which]), fp) != NULL) {
  1186. X                for (p = buf[!which]; *p && *p != '\n'; p++)
  1187. X                    continue;
  1188. X                *p = '\0';
  1189. X
  1190. X                p = buf[!which];
  1191. X                while (*p && *p!=' ' && *p != ':' && *p != '!')
  1192. X                    p++;
  1193. X                c = *p;
  1194. X                if (c != '\0')
  1195. X                    *p++ = '\0';
  1196. X
  1197. X                if (c != '!')
  1198. X                    c = ':';
  1199. X
  1200. X                while (i < cur_groupnum) {
  1201. X                    if (strcmp(buf[!which],
  1202. X                      active[my_group[i]].name) == 0) {
  1203. X                        fprintf(newfp, "%s%c%s\n",
  1204. X                            buf[!which], c, p);
  1205. X                        goto foo_cont;
  1206. X                    }
  1207. X                    i++;
  1208. X                }
  1209. X                fprintf(newfp, "%s%c%s\n", buf[which], c, p);
  1210. X                fprintf(newfp, "%s%c%s\n", buf[!which], c, p);
  1211. X                break;
  1212. Xfoo_cont:;
  1213. X            }
  1214. X
  1215. X            while (fgets (buf[!which], sizeof (buf[!which]), fp) != NULL)
  1216. X                fputs (buf[!which], newfp);
  1217. X
  1218. X            fclose (newfp);
  1219. X            fclose (fp);
  1220. X            rename_file (newnewsrc, newsrc);
  1221. X            set_tin_uid_gid ();
  1222. X            return TRUE;
  1223. X        }
  1224. X    }
  1225. X    set_tin_uid_gid ();
  1226. X
  1227. X    return FALSE;
  1228. X}
  1229. X
  1230. X
  1231. Xvoid mark_group_read (group, groupnum)
  1232. X    char *group;
  1233. X    int groupnum;            /* index into active[] for this group */
  1234. X{
  1235. X    FILE *fp;
  1236. X    FILE *newfp;
  1237. X    char buf[8192];
  1238. X    char *p;
  1239. X    char c;
  1240. X
  1241. X    if (active[groupnum].max < 2)
  1242. X        return;
  1243. X
  1244. X    set_real_uid_gid ();
  1245. X
  1246. X    if ((newfp = fopen (newnewsrc, "w")) == NULL)
  1247. X        goto mark_group_read_done;
  1248. X
  1249. X    if ((fp = fopen (newsrc, "r")) != NULL) {
  1250. X        while (fgets(buf, sizeof (buf), fp) != NULL) {
  1251. X            for (p = buf; *p; p++)
  1252. X                if (*p == '\n') {
  1253. X                    *p = '\0';
  1254. X                    break;
  1255. X                }
  1256. X
  1257. X            p = buf;
  1258. X            while (*p && *p != ' ' && *p != ':' && *p != '!')
  1259. X                    p++;
  1260. X            c = *p;
  1261. X            if (c != '\0')
  1262. X                *p++ = '\0';
  1263. X
  1264. X            if (c != '!')
  1265. X                c = ':';
  1266. X
  1267. X            if (strcmp (buf, group) == 0) {
  1268. X                fprintf (newfp, "%s%c 1-%ld\n", buf, c, active[groupnum].max);
  1269. X            } else
  1270. X                fprintf(newfp, "%s%c%s\n", buf, c, p);
  1271. X        }
  1272. X        fclose (fp);
  1273. X    }
  1274. X
  1275. X    fclose (newfp);
  1276. X    rename_file (newnewsrc, newsrc);
  1277. X
  1278. Xmark_group_read_done:
  1279. X    set_tin_uid_gid ();
  1280. X}
  1281. X
  1282. X
  1283. Xvoid parse_seq(s)
  1284. X    char *s;
  1285. X{
  1286. X    long low, high;
  1287. X    int i;
  1288. X
  1289. X    while (*s) {
  1290. X        while (*s && (*s < '0' || *s > '9'))
  1291. X            s++;
  1292. X
  1293. X        if (*s && *s >= '0' && *s <= '9') {
  1294. X            low = (long) atol (s);
  1295. X            while (*s && *s >= '0' && *s <= '9')
  1296. X                s++;
  1297. X            if (*s == '-') {
  1298. X                s++;
  1299. X                high = (long) atol (s);
  1300. X                while (*s && *s >= '0' && *s <= '9')
  1301. X                    s++;
  1302. X            }  else
  1303. X                high = low;
  1304. X
  1305. X            for (i = 0; i < top; i++)
  1306. X                if (arts[i].artnum >= low && arts[i].artnum <= high)
  1307. X                    arts[i].unread = ART_READ;
  1308. X        }
  1309. X    }
  1310. X}
  1311. X
  1312. X
  1313. Xint parse_unread (s, groupnum)
  1314. X    char *s;
  1315. X    int groupnum;            /* index for group in active[] */
  1316. X{
  1317. X    long low, high;
  1318. X    long last_high;
  1319. X    int sum = 0;
  1320. X    int gotone = FALSE;
  1321. X    int n;
  1322. X
  1323. X/*
  1324. X *  Read the first range from the .newsrc sequencer information.  If the
  1325. X *  top of the first range is higher than what the active file claims is
  1326. X *  the bottom, use it as the new bottom instead
  1327. X */
  1328. X
  1329. X    high = 0;
  1330. X    if (*s) {
  1331. X        while (*s && (*s < '0' || *s > '9'))
  1332. X            s++;
  1333. X
  1334. X        if (*s && *s >= '0' && *s <= '9') {
  1335. X            low = (long) atol (s);
  1336. X            while (*s && *s >= '0' && *s <= '9')
  1337. X                s++;
  1338. X            if (*s == '-') {
  1339. X                s++;
  1340. X                high = (long) atol (s);
  1341. X                while (*s && *s >= '0' && *s <= '9')
  1342. X                    s++;
  1343. X            }  else
  1344. X                high = low;
  1345. X            gotone = TRUE;
  1346. X        }
  1347. X    }
  1348. X
  1349. X    if (high < active[groupnum].min)
  1350. X        high = active[groupnum].min;
  1351. X
  1352. X    while (*s) {
  1353. X        last_high = high;
  1354. X
  1355. X        while (*s && (*s < '0' || *s > '9'))
  1356. X            s++;
  1357. X
  1358. X        if (*s && *s >= '0' && *s <= '9') {
  1359. X            low = (long) atol (s);
  1360. X            while (*s && *s >= '0' && *s <= '9')
  1361. X                s++;
  1362. X            if (*s == '-') {
  1363. X                s++;
  1364. X                high = (long) atol (s);
  1365. X                while (*s && *s >= '0' && *s <= '9')
  1366. X                    s++;
  1367. X            }  else
  1368. X                high = low;
  1369. X
  1370. X            if (low > last_high)    /* otherwise seq out of order */
  1371. X                sum += (low - last_high) - 1;
  1372. X        }
  1373. X    }
  1374. X
  1375. X    if (gotone) {
  1376. X        if (active[groupnum].max > high)
  1377. X            sum += active[groupnum].max - high;
  1378. X        return sum;
  1379. X    }
  1380. X
  1381. X    n = (int) (active[groupnum].max - active[groupnum].min);
  1382. X    if (n < 2)
  1383. X        return 0;
  1384. X
  1385. X    return -1;
  1386. X}
  1387. X
  1388. X
  1389. Xint get_line_unread(group, groupnum)
  1390. X    char *group;
  1391. X    int groupnum;                /* index for group in active[] */
  1392. X{
  1393. X    FILE *fp;
  1394. X    char buf[8192];
  1395. X    char *p;
  1396. X    int ret = -1;
  1397. X
  1398. X    if ((fp = fopen(newsrc, "r")) == NULL)
  1399. X        return -1;
  1400. X
  1401. X    while (fgets(buf, sizeof (buf), fp) != NULL) {
  1402. X        p = buf;
  1403. X        while (*p && *p != '\n' && *p != ' ' && *p != ':' && *p != '!')
  1404. X            p++;
  1405. X        *p++ = '\0';
  1406. X        
  1407. X        if (strcmp (buf, group) != 0)
  1408. X            continue;
  1409. X            
  1410. X        ret = parse_unread (p, groupnum);
  1411. X        break;
  1412. X    }
  1413. X
  1414. X    fclose (fp);
  1415. X    return ret;
  1416. X}
  1417. X
  1418. X
  1419. Xvoid print_seq (fp, groupnum)
  1420. X    FILE *fp;
  1421. X    int groupnum;            /* index into active[] for this group */
  1422. X{
  1423. X    int i;
  1424. X    int flag = FALSE;
  1425. X
  1426. X    if (top <= 0) {
  1427. X        if (active[groupnum].min > 1) {
  1428. X            fprintf (fp, "1-%ld", active[groupnum].min);
  1429. X            fflush (fp);
  1430. X        }
  1431. X        return;
  1432. X    }
  1433. X
  1434. X    /*
  1435. X     *  sort into the same order as in the spool area for writing
  1436. X     *  read article numbers to ~/.newsrc
  1437. X     */
  1438. X    qsort (arts, top, sizeof (struct header), artnum_comp);
  1439. X
  1440. X    i = 0;
  1441. X    if (arts[0].artnum > 1) {
  1442. X        for (; i < top && !arts[i].unread; i++)
  1443. X            continue;
  1444. X        if (i > 0)
  1445. X            fprintf (fp, "1-%ld", arts[i-1].artnum);
  1446. X        else
  1447. X            fprintf (fp, "1-%ld", arts[0].artnum - 1);
  1448. X        flag = TRUE;
  1449. X    }
  1450. X
  1451. X    for (; i < top; i++) {
  1452. X        if (! arts[i].unread) {
  1453. X            if (flag)
  1454. X                fprintf(fp, ",");
  1455. X            else
  1456. X                flag = TRUE;
  1457. X            fprintf (fp, "%ld", arts[i].artnum);
  1458. X            if (i+1 < top && !arts[i+1].unread) {
  1459. X                while (i+1 < top && ! arts[i+1].unread)
  1460. X                    i++;
  1461. X                fprintf (fp, "-%ld", arts[i].artnum);
  1462. X            }
  1463. X        }
  1464. X    }
  1465. X
  1466. X    if (! flag && active[groupnum].min > 1)
  1467. X        fprintf (fp, "1-%ld", active[groupnum].min);
  1468. X    fflush (fp);
  1469. X
  1470. X    /*
  1471. X     *  resort into required sort order
  1472. X     */
  1473. X    switch (sort_art_type) {
  1474. X        case SORT_BY_NOTHING:        /* already sorted above */
  1475. X            break;
  1476. X        case SORT_BY_SUBJ_DESCEND:
  1477. X        case SORT_BY_SUBJ_ASCEND:
  1478. X            qsort (arts, top, sizeof (struct header), subj_comp);
  1479. X            break;
  1480. X        case SORT_BY_FROM_DESCEND:
  1481. X        case SORT_BY_FROM_ASCEND:
  1482. X            qsort (arts, top, sizeof (struct header), from_comp);
  1483. X            break;
  1484. X        case SORT_BY_DATE_DESCEND:
  1485. X        case SORT_BY_DATE_ASCEND:
  1486. X            qsort (arts, top, sizeof (struct header), date_comp);
  1487. X            break;
  1488. X    }
  1489. X}
  1490. X
  1491. X/*
  1492. X *  rewrite .newsrc and position group at specifed position
  1493. X */
  1494. X
  1495. Xint pos_group_in_newsrc (group, pos)
  1496. X    char *group;
  1497. X    int pos;
  1498. X{
  1499. X    char sub[1024];
  1500. X    char unsub[1024];
  1501. X    char buf[1024];
  1502. X    char newsgroup[1024];
  1503. X    extern int cur_groupnum;
  1504. X    FILE *fp_in, *fp_out;
  1505. X    FILE *fp_sub, *fp_unsub;
  1506. X    int repositioned = FALSE;
  1507. X    int subscribed_pos = 1;
  1508. X    int group_len;
  1509. X    int option_line = FALSE;
  1510. X    int ret_code = FALSE;
  1511. X
  1512. X    set_real_uid_gid ();
  1513. X    
  1514. X    if ((fp_in = fopen (newsrc, "r")) == NULL) {
  1515. X        goto rewrite_group_done;
  1516. X    }
  1517. X    if ((fp_out = fopen (newnewsrc, "w")) == NULL) {
  1518. X        goto rewrite_group_done;
  1519. X    }
  1520. X
  1521. X    sprintf (sub, "/tmp/.subrc.%d", getpid ());
  1522. X    sprintf (unsub, "/tmp/.unsubrc.%d", getpid ());
  1523. X
  1524. X    if ((fp_sub = fopen (sub, "w")) == NULL) {
  1525. X        goto rewrite_group_done;
  1526. X    }
  1527. X    if ((fp_unsub = fopen (unsub, "w")) == NULL) {
  1528. X        goto rewrite_group_done;
  1529. X    }
  1530. X
  1531. X    /*
  1532. X     *  split newsrc into subscribed and unsubscribed to files
  1533. X     */
  1534. X    group_len = strlen (group);
  1535. X
  1536. X    while (fgets (buf, sizeof (buf), fp_in) != NULL) {
  1537. X        if (strncmp (group, buf, group_len) == 0 && buf[group_len] == ':') {
  1538. X            my_strncpy (newsgroup, buf, LEN);
  1539. X        } else if (strchr (buf, ':') != NULL) {
  1540. X            fprintf (fp_sub, "%s", buf);
  1541. X        } else if (strchr (buf, '!') != NULL) {
  1542. X            fprintf (fp_unsub, "%s", buf);
  1543. X        } else {    /* options line at beginning of .newsrc */
  1544. X            fprintf (fp_sub, "%s", buf);
  1545. X            option_line = TRUE;
  1546. X        }
  1547. X    }
  1548. X
  1549. X    fclose (fp_in);
  1550. X    fclose (fp_sub);
  1551. X    fclose (fp_unsub);
  1552. X
  1553. X    /*
  1554. X     *  write subscribed groups & position group to newnewsrc
  1555. X     */
  1556. X    if ((fp_sub = fopen (sub, "r")) == NULL) {
  1557. X        unlink (sub);
  1558. X        goto rewrite_group_done;
  1559. X    }
  1560. X    while (fgets (buf, LEN, fp_sub) != NULL) {
  1561. X        if (option_line) {
  1562. X            if (strchr (buf, ':') == NULL && strchr (buf, '!') == NULL) {
  1563. X                fprintf (fp_out, "%s", buf);
  1564. X                continue;
  1565. X            } else {
  1566. X                option_line = FALSE;
  1567. X            }
  1568. X        }
  1569. X
  1570. X        if (pos == subscribed_pos) {
  1571. X            fprintf (fp_out, "%s\n", newsgroup);
  1572. X            repositioned = TRUE;
  1573. X        }
  1574. X        
  1575. X        fprintf (fp_out, "%s", buf);
  1576. X
  1577. X        subscribed_pos++;
  1578. X    }
  1579. X    if (! repositioned) {
  1580. X        fprintf (fp_out, "%s\n", newsgroup);
  1581. X        repositioned = TRUE;
  1582. X    }
  1583. X    
  1584. X    fclose (fp_sub);
  1585. X     unlink (sub);
  1586. X
  1587. X    /*
  1588. X     *  write unsubscribed groups to newnewsrc
  1589. X     */
  1590. X    if ((fp_unsub = fopen (unsub, "r")) == NULL) {
  1591. X        unlink (unsub);
  1592. X        goto rewrite_group_done;
  1593. X    }
  1594. X    while (fgets (buf, LEN, fp_unsub) != NULL) {
  1595. X        fprintf (fp_out, "%s", buf);
  1596. X    }
  1597. X
  1598. X    fclose (fp_unsub);
  1599. X    unlink (unsub);
  1600. X    fclose (fp_out);
  1601. X
  1602. X    if (repositioned) {
  1603. X        cur_groupnum = pos;
  1604. X        rename_file (newnewsrc, newsrc);
  1605. X        ret_code = TRUE;
  1606. X    }
  1607. X
  1608. Xrewrite_group_done:
  1609. X    set_tin_uid_gid ();
  1610. X    return ret_code;
  1611. X}
  1612. X
  1613. X/*
  1614. X *  mark all orther Xref: articles as read when one article read
  1615. X *  Xref: sitename newsgroup:artnum newsgroup:artnum [newsgroup:artnum ...]
  1616. X */
  1617. Xvoid mark_all_xref_read (xref_line)
  1618. X    char *xref_line; 
  1619. X{
  1620. X    char group[LEN];
  1621. X    long artnum;
  1622. X    
  1623. X    if (xref_line == (char *) 0) {
  1624. X        return;
  1625. X    }
  1626. X
  1627. X    /*
  1628. X     *  check sitename macthes nodename of current machine
  1629. X     */
  1630. X
  1631. X    /*
  1632. X     *  tokenize each pair and update that newsgroup if it
  1633. X     *  is in users my_group[].
  1634. X     */
  1635. X     
  1636. X}
  1637. SHAR_EOF
  1638. $TOUCH -am 0923175591 newsrc.c &&
  1639. chmod 0600 newsrc.c ||
  1640. echo "restore of newsrc.c failed"
  1641. set `wc -c newsrc.c`;Wc_c=$1
  1642. if test "$Wc_c" != "19674"; then
  1643.     echo original size 19674, current size $Wc_c
  1644. fi
  1645. # ============= open.c ==============
  1646. echo "x - extracting open.c (Text)"
  1647. sed 's/^X//' << 'SHAR_EOF' > open.c &&
  1648. X/*
  1649. X *  Project   : tin - a visual threaded usenet newsreader
  1650. X *  Module    : open.c
  1651. X *  Author    : R.Skrenta / I.Lea
  1652. X *  Created   : 01-04-91
  1653. X *  Updated   : 28-08-91
  1654. X *  Release   : 1.0
  1655. X *  Notes     : reads news locally (/usr/spool/news) or via NNTP
  1656. X *  Copyright : (c) Copyright 1991 by Rich Skrenta & Iain Lea
  1657. X *                You may  freely  copy or  redistribute  this software,
  1658. X *              so  long as there is no profit made from its use, sale
  1659. X *              trade or  reproduction.  You may not change this copy-
  1660. X *              right notice, and it must be included in any copy made
  1661. X */
  1662. X
  1663. X#include    "tin.h"
  1664. X#ifdef USE_NNTP
  1665. X#include    "nntp.h"
  1666. X#endif
  1667. X
  1668. X/* Hopefully one of these is right for you. */
  1669. X
  1670. X#ifdef BSD
  1671. X#    include <sys/dir.h>
  1672. X#    define        DIR_BUF        struct direct
  1673. X#    define        D_LENGTH    d_namlen
  1674. X#endif
  1675. X#ifdef M_XENIX
  1676. X#    include <sys/ndir.h>
  1677. X#    define        DIR_BUF        struct direct
  1678. X#    define        D_LENGTH    d_namlen
  1679. X#endif
  1680. X#ifndef DIR_BUF
  1681. X#ifdef sorix960
  1682. X#    include    <sys/dirent.h>
  1683. X#else
  1684. X#    include    <dirent.h>
  1685. X#endif
  1686. X#    define        DIR_BUF        struct dirent
  1687. X#    define        D_LENGTH    d_reclen
  1688. X#endif
  1689. X
  1690. X#ifdef USE_NNTP
  1691. Xint compiled_with_nntp = TRUE;        /* used in mail_bug_report() info */
  1692. X#else
  1693. Xint compiled_with_nntp = FALSE;
  1694. X#endif
  1695. X
  1696. Xchar server_name[LEN+1];
  1697. X
  1698. X
  1699. Xchar *is_remote ()
  1700. X{
  1701. X    server_name[0] = '\0';
  1702. X    
  1703. X#ifdef USE_NNTP
  1704. X    if (read_news_via_nntp) {
  1705. X        if (nntp_server[0]) {
  1706. X            sprintf (server_name, " (%s)", nntp_server);
  1707. X        } else {
  1708. X            if (getserverbyfile (NNTP_SERVER_FILE)) {
  1709. X                sprintf (server_name, " (%s)", getserverbyfile (NNTP_SERVER_FILE));
  1710. X            } else {
  1711. X                strcpy (server_name, " (NO SERVER)");
  1712. X            }
  1713. X        }
  1714. X    }
  1715. X#endif
  1716. X
  1717. X    return (server_name);
  1718. X}
  1719. X
  1720. X
  1721. Xvoid nntp_startup ()
  1722. X{
  1723. X#ifdef USE_NNTP    
  1724. X    char *server_name;
  1725. X    int ret;
  1726. X    extern char *getenv();
  1727. X
  1728. X    if (read_news_via_nntp) {
  1729. X        if (nntp_server[0]) {
  1730. X            server_name = nntp_server;
  1731. X        } else {
  1732. X            server_name = getserverbyfile (NNTP_SERVER_FILE);
  1733. X        }
  1734. X        if (server_name == NULL) {
  1735. X            fprintf(stderr, txt_cannot_get_nntp_server_name);
  1736. X            fprintf(stderr, txt_server_name_in_file_env_var, NNTP_SERVER_FILE);
  1737. X            exit(1);
  1738. X        }
  1739. X
  1740. X        ret = server_init (server_name);
  1741. X/*
  1742. X        handle_server_response (ret, server_name);
  1743. X*/        
  1744. X        switch (ret) {
  1745. X        case OK_CANPOST:
  1746. X        case OK_NOPOST:
  1747. X            break;    
  1748. X
  1749. X        case -1:
  1750. X            fprintf (stderr, txt_failed_to_connect_to_server, server_name);
  1751. X            exit (1);
  1752. X
  1753. X        default:
  1754. X            fprintf (stderr, txt_rejected_by_nntpserver, ret);
  1755. X            exit (1);
  1756. X        }
  1757. X    }
  1758. X#endif    
  1759. X}
  1760. X
  1761. X
  1762. Xvoid nntp_finish()
  1763. X{
  1764. X#ifdef USE_NNTP
  1765. X    if (read_news_via_nntp) {
  1766. X        close_server();
  1767. X    }
  1768. X#endif    
  1769. X}
  1770. X
  1771. X
  1772. XFILE *open_active_fp()
  1773. X{
  1774. X    if (read_news_via_nntp) {
  1775. X#ifdef USE_NNTP
  1776. X        put_server ("list");
  1777. X        if (get_respcode () != OK_GROUPS) {
  1778. X            return NULL;
  1779. X        }
  1780. X        return nntp_to_fp ();
  1781. X#else
  1782. X        return NULL;
  1783. X#endif        
  1784. X    } else {
  1785. X        return fopen (active_file, "r");
  1786. X    }
  1787. X}
  1788. X
  1789. X
  1790. XFILE *open_art_fp (group_path, art)
  1791. X    char *group_path;
  1792. X    long art;
  1793. X{
  1794. X    char buf[LEN+1];
  1795. X    struct stat sb;
  1796. X    extern long note_size;
  1797. X
  1798. X    if (read_news_via_nntp) {
  1799. X#ifdef USE_NNTP
  1800. X        sprintf (buf, "article %ld", art);
  1801. X
  1802. X        put_server (buf);
  1803. X        if (get_respcode () != OK_ARTICLE) {
  1804. X            return NULL;
  1805. X        }
  1806. X
  1807. X        return nntp_to_fp ();
  1808. X#else
  1809. X        return NULL;
  1810. X#endif
  1811. X    } else {
  1812. X        sprintf (buf, "%s/%s/%ld", SPOOLDIR, group_path, art);
  1813. X
  1814. X        if (stat (buf, &sb) < 0) {
  1815. X            note_size = 0;
  1816. X        } else {
  1817. X            note_size = sb.st_size;
  1818. X        }
  1819. X        return fopen (buf, "r");
  1820. X    }
  1821. X}
  1822. X
  1823. X
  1824. Xint open_header_fd (group_path, art)
  1825. X    char *group_path;
  1826. X    long art;
  1827. X{
  1828. X    char buf[LEN+1];
  1829. X
  1830. X    if (read_news_via_nntp) {
  1831. X#ifdef USE_NNTP    
  1832. X        sprintf(buf, "head %ld", art);
  1833. X        
  1834. X        put_server (buf);
  1835. X        if (get_respcode () != OK_HEAD) {
  1836. X            return -1;
  1837. X        }
  1838. X
  1839. X        return nntp_to_fd ();
  1840. X#else
  1841. X        return -1;
  1842. X#endif        
  1843. X    } else {
  1844. X        sprintf (buf, "%s/%s/%ld", SPOOLDIR, group_path, art);
  1845. X        return open (buf, 0);
  1846. X    }
  1847. X}
  1848. X
  1849. X/*
  1850. X *  Longword comparison routine for the qsort()
  1851. X */
  1852. X
  1853. Xint base_comp (p1, p2)
  1854. X    char *p1;
  1855. X    char *p2;
  1856. X{
  1857. X    long *a = (long *) p1;
  1858. X    long *b = (long *) p2;
  1859. X
  1860. X    if (*a < *b)
  1861. X        return -1;
  1862. X    if (*a > *b)
  1863. X        return 1;
  1864. X    return 0;
  1865. X}
  1866. X
  1867. X
  1868. X/*
  1869. X *  Read the article numbers existing in a group's spool directory
  1870. X *  into base[] and sort them.  base_top is one past top.
  1871. X */
  1872. X
  1873. Xvoid setup_base (group, group_path)
  1874. X    char *group;
  1875. X    char *group_path;
  1876. X{
  1877. X    char buf[LEN+1];
  1878. X#ifdef USE_NNTP
  1879. X    char line[NNTP_STRLEN];
  1880. X#endif
  1881. X    DIR *d;
  1882. X    DIR_BUF *e;
  1883. X    long art, start, last, dummy, count;
  1884. X
  1885. X    top_base = 0;
  1886. X
  1887. X    if (read_news_via_nntp) {
  1888. X#ifdef USE_NNTP
  1889. X        sprintf (buf, "group %s", group);
  1890. X        put_server (buf);
  1891. X
  1892. X        if (get_server(line, NNTP_STRLEN) == -1) {
  1893. X            fprintf(stderr, txt_connection_to_server_broken);
  1894. X            tin_done(1);
  1895. X        }
  1896. X
  1897. X        if (atoi(line) != OK_GROUP) {
  1898. X            return;
  1899. X        }
  1900. X
  1901. X        sscanf (line,"%ld %ld %ld %ld", &dummy, &count, &start, &last);
  1902. X        if (last - count > start) {
  1903. X            start = last - count;
  1904. X        }
  1905. X
  1906. X        while (start <= last) {
  1907. X            if (top_base >= max_art) {
  1908. X                expand_art();
  1909. X            }
  1910. X            base[top_base++] = start++;
  1911. X        }
  1912. X#else
  1913. X        return; 
  1914. X#endif
  1915. X    } else {
  1916. X        sprintf (buf, "%s/%s", SPOOLDIR, group_path);
  1917. X
  1918. X        if (access (buf, 4) != 0) {
  1919. X            return;
  1920. X        }
  1921. X
  1922. X        d = opendir (buf);
  1923. X        if (d != NULL) {
  1924. X            while ((e = readdir (d)) != NULL) {
  1925. X                art = my_atol (e->d_name, (int) e->D_LENGTH);
  1926. X                if (art >= 0) {
  1927. X                    if (top_base >= max_art)
  1928. X                        expand_art ();
  1929. X                    base[top_base++] = art;
  1930. X                }
  1931. X            }
  1932. X            closedir (d);
  1933. X            qsort ((char *) base, top_base, sizeof(long), base_comp);
  1934. X        }
  1935. X    }
  1936. X}
  1937. X
  1938. X/*
  1939. X *  get_respcode
  1940. X *  get a response code from the server and return it to the caller
  1941. X */
  1942. X
  1943. Xint get_respcode()
  1944. X{
  1945. X#ifdef USE_NNTP
  1946. X    char line[NNTP_STRLEN];
  1947. X
  1948. X    if (get_server (line, NNTP_STRLEN) == -1) {
  1949. X        fprintf (stderr, txt_connection_to_server_broken);
  1950. X        tin_done (1);
  1951. X    }
  1952. X
  1953. X    return atoi (line);
  1954. X#endif
  1955. X}
  1956. X
  1957. X
  1958. Xint stuff_nntp (fnam)
  1959. X    char *fnam;
  1960. X{
  1961. X#ifdef USE_NNTP
  1962. X    FILE *fp;
  1963. X    char line[NNTP_STRLEN];
  1964. X    extern char *mktemp();
  1965. X    struct stat sb;
  1966. X    extern long note_size;
  1967. X
  1968. X    strcpy(fnam, "/tmp/tin_nntpXXXXXX");
  1969. X    mktemp(fnam);
  1970. X
  1971. X    if ((fp = fopen(fnam, "w")) == NULL) {
  1972. X        error_message (txt_stuff_nntp_cannot_open, fnam);
  1973. X        return FALSE;
  1974. X    }
  1975. X
  1976. X    while (1) {
  1977. X        if (get_server(line, NNTP_STRLEN) == -1) {
  1978. X            fprintf(stderr, txt_connection_to_server_broken);
  1979. X            tin_done (1);
  1980. X        }
  1981. X        if (strcmp(line, ".") == 0)
  1982. X            break;            /* end of text */
  1983. X        strcat(line, "\n");
  1984. X        if (line[0] == '.')        /* reduce leading .'s */
  1985. X            fputs(&line[1], fp);
  1986. X        else
  1987. X            fputs(line, fp);
  1988. X    }
  1989. X    fclose(fp);
  1990. X
  1991. X    if (stat(fnam, &sb) < 0)
  1992. X        note_size = 0;
  1993. X    else
  1994. X        note_size = sb.st_size;
  1995. X
  1996. X    return TRUE;
  1997. X#endif
  1998. X}
  1999. X
  2000. X
  2001. XFILE *nntp_to_fp ()
  2002. X{
  2003. X    char fnam[LEN+1];
  2004. X    FILE *fp;
  2005. X
  2006. X    if (! stuff_nntp (fnam))
  2007. X        return NULL;
  2008. X
  2009. X    if ((fp = fopen (fnam, "r")) == NULL) {
  2010. X        error_message (txt_nntp_to_fp_cannot_reopen, fnam);
  2011. X        return NULL;
  2012. X    }
  2013. X    unlink (fnam);
  2014. X    return fp;
  2015. X}
  2016. X
  2017. X
  2018. Xint nntp_to_fd ()
  2019. X{
  2020. X#ifdef USE_NNTP
  2021. X    char fnam[LEN+1];
  2022. X    int fd;
  2023. X
  2024. X    if (! stuff_nntp (fnam))
  2025. X        return -1;
  2026. X
  2027. X    if ((fd = open (fnam, 0)) == -1) {
  2028. X        error_message (txt_nntp_to_fd_cannot_reopen, fnam);
  2029. X        return -1;
  2030. X    }
  2031. X    unlink (fnam);
  2032. X    return fd;
  2033. X#endif
  2034. X}
  2035. SHAR_EOF
  2036. $TOUCH -am 0923175591 open.c &&
  2037. chmod 0600 open.c ||
  2038. echo "restore of open.c failed"
  2039. set `wc -c open.c`;Wc_c=$1
  2040. if test "$Wc_c" != "6736"; then
  2041.     echo original size 6736, current size $Wc_c
  2042. fi
  2043. # ============= page.c ==============
  2044. echo "x - extracting page.c (Text)"
  2045. sed 's/^X//' << 'SHAR_EOF' > page.c &&
  2046. X/*
  2047. X *  Project   : tin - a visual threaded usenet newsreader
  2048. X *  Module    : page.c
  2049. X *  Author    : R.Skrenta / I.Lea
  2050. X *  Created   : 01-04-91
  2051. X *  Updated   : 16-09-91
  2052. X *  Release   : 1.0
  2053. X *  Notes     :
  2054. X *  Copyright : (c) Copyright 1991 by Rich Skrenta & Iain Lea
  2055. X *                You may  freely  copy or  redistribute  this software,
  2056. X *              so  long as there is no profit made from its use, sale
  2057. X *              trade or  reproduction.  You may not change this copy-
  2058. X *              right notice, and it must be included in any copy made
  2059. X */
  2060. X
  2061. X#include    "tin.h"
  2062. X
  2063. X#define        NOTE_UNAVAIL    -1
  2064. X
  2065. Xextern int cur_groupnum;
  2066. X
  2067. Xchar note_h_path[LEN+1];            /* Path:    */
  2068. Xchar note_h_date[LEN+1];            /* Date:    */
  2069. Xchar note_h_subj[LEN+1];            /* Subject:    */
  2070. Xchar note_h_from[LEN+1];            /* From:    */
  2071. Xchar note_h_org[LEN+1];                /* Organization: */
  2072. Xchar note_h_newsgroups[LEN+1];        /* Newsgroups:    */
  2073. Xchar note_h_messageid[LEN+1];        /* Message-ID:    */
  2074. Xchar note_h_distrib[LEN+1];            /* Distribution: */
  2075. Xchar note_h_followup[LEN+1];        /* Followup-To: */
  2076. X
  2077. Xchar note_full_name[100];
  2078. Xchar note_from_addr[100];
  2079. Xchar *glob_page_group;
  2080. X
  2081. XFILE *note_fp;                /* the body of the current article */
  2082. X
  2083. Xint    note_line;
  2084. Xint    note_page;                    /* what page we're on */
  2085. Xint    note_end;                    /* we're done showing this article */
  2086. Xint    rotate;                        /* 0=normal, 13=rot13 decode */
  2087. Xint last_resp;        /* current & previous article for - command */
  2088. Xint this_resp;
  2089. Xint glob_respnum;
  2090. X
  2091. Xlong    note_mark[MAX_PAGES];    /* ftells on beginnings of pages */
  2092. Xlong note_size;                    /* stat size in bytes of article */
  2093. X
  2094. X
  2095. Xint show_page (respnum, group, group_path)
  2096. X    int respnum;
  2097. X    char *group;
  2098. X    char *group_path;
  2099. X{
  2100. X    char ch;
  2101. X    int i, n;
  2102. X    int kill_state = NO_KILLING;
  2103. X    int old_artnum;
  2104. X    int old_sort_art_type = sort_art_type;
  2105. X    int old_top;
  2106. X    long art;
  2107. X
  2108. Xrestart:
  2109. X
  2110. X    glob_respnum = respnum;
  2111. X    glob_page_group = group;
  2112. X
  2113. X#ifdef SIGTSTP
  2114. X    if (do_sigtstp) {
  2115. X#ifdef POSIX_JOB_CONTROL
  2116. X        sigemptyset (&page_act.sa_mask);
  2117. X        page_act.sa_flags = SA_RESTART | SA_RESETHAND;
  2118. X        page_act.sa_handler = page_suspend;
  2119. X        sigaction (SIGTSTP, &page_act, 0L);
  2120. X#else
  2121. X        signal (SIGTSTP, page_suspend);
  2122. X#endif
  2123. X    }
  2124. X#endif
  2125. X
  2126. X#ifdef SIGWINCH
  2127. X    signal (SIGWINCH, page_resize);
  2128. X#endif
  2129. X
  2130. X    if (respnum != this_resp) {       /* remember current & previous */
  2131. X        last_resp = this_resp;       /* articles for - command */
  2132. X        this_resp = respnum;
  2133. X    }
  2134. X
  2135. X    rotate = 0;            /* normal mode, not rot13 */
  2136. X    art = arts[respnum].artnum;
  2137. X    arts[respnum].unread = ART_READ;    /* mark article as read */
  2138. X    open_note (art, group_path);
  2139. X
  2140. X    if (note_page == NOTE_UNAVAIL) {
  2141. X        ClearScreen ();
  2142. X        printf (txt_art_unavailable, art);
  2143. X        fflush (stdout);
  2144. X    } else {
  2145. X        show_note_page (respnum, group);
  2146. X    }
  2147. X
  2148. X    while (1) {
  2149. X        ch = ReadCh();
  2150. X
  2151. X        if (ch >= '0' && ch <= '9') {
  2152. X
  2153. X            n = prompt_response (ch, respnum);
  2154. X            if (n != -1) {
  2155. X                respnum = n;
  2156. X                goto restart;
  2157. X            }
  2158. X
  2159. X        } else switch (ch) {
  2160. X            case 27:
  2161. X                ch = ReadCh ();
  2162. X                if (ch == '[' || ch == 'O')
  2163. X                    ch = ReadCh ();
  2164. X                switch (ch) {
  2165. X                case 'G':        /* ansi  PgDn */
  2166. X                case 'U':        /* at386 PgDn */
  2167. X                    goto page_down;
  2168. X
  2169. X                case 'I':        /* ansi  PgUp */
  2170. X                case 'V':        /* at386 PgUp */
  2171. X                    goto page_up;
  2172. X
  2173. X                case 'H':        /* at386 Home */
  2174. X                    goto begin_of_article;
  2175. X
  2176. X                case 'F':        /* ansi End */
  2177. X                case 'Y':        /* at386 End */
  2178. X                    goto end_of_article;
  2179. X                }
  2180. X                break;
  2181. X
  2182. X            case '!':
  2183. X                shell_escape ();
  2184. X                redraw_page (respnum, group);
  2185. X                break;
  2186. X
  2187. X            case '$':    /* goto end of article */
  2188. X            case 'G':    /* 'less' compatible */
  2189. Xend_of_article:            
  2190. X                if (show_last_page ()) {
  2191. X                    show_note_page(respnum, group);
  2192. X                }
  2193. X                break;
  2194. X
  2195. X            case '-':    /* show last viewed article */
  2196. X                if (last_resp < 0) {
  2197. X                    info_message(txt_no_last_message);
  2198. X                    break;
  2199. X                }
  2200. X                note_cleanup();
  2201. X                respnum = last_resp;
  2202. X                goto restart;
  2203. X
  2204. X            case '|':    /* pipe article/thread/tagged arts to command */
  2205. X                feed_articles (FEED_PIPE, PAGE_LEVEL, "Pipe", respnum, group_path);
  2206. X                break;
  2207. X
  2208. X            case '/':    /* search forwards in article */
  2209. X                if (search_article (TRUE)) {
  2210. X                    show_note_page (respnum, group);
  2211. X                }
  2212. X                break;
  2213. X
  2214. X            case '<':    /* goto first article in current thread */
  2215. X                n = which_base (respnum);
  2216. X                if (n != respnum && n >= 0) {
  2217. X                    respnum = n;
  2218. X                    note_cleanup ();
  2219. X                    goto restart;
  2220. X                }
  2221. X                break;
  2222. X
  2223. X            case '>':    /* goto last article in current thread */
  2224. X                for (i = respnum; i >= 0; i = arts[i].thread) {
  2225. X                    n = i;
  2226. X                }
  2227. X                if (n != respnum) {
  2228. X                    respnum = n;
  2229. X                    note_cleanup ();
  2230. X                    goto restart;
  2231. X                }
  2232. X                break;
  2233. X
  2234. X            case ctrl('D'):
  2235. X            case ' ':     /* next page or response */
  2236. Xpage_down:
  2237. X                if (note_page == NOTE_UNAVAIL) {
  2238. X                    n = next_response (respnum);
  2239. X                    if (n == -1) {
  2240. X                        return (which_base (respnum));
  2241. X                    }
  2242. X                    respnum = n;
  2243. X                    goto restart;
  2244. X                } else if (note_end) {
  2245. X                    note_cleanup ();
  2246. X                    n = next_response (respnum);
  2247. X                    if (n == -1) {
  2248. X                        return (which_base (respnum));
  2249. X                    }
  2250. X                    respnum = n;
  2251. X                    goto restart;
  2252. X                } else
  2253. X                    show_note_page (respnum, group);
  2254. X                break;
  2255. X
  2256. X            case '\r':
  2257. X            case '\n':    /* go to start of next thread */
  2258. X                note_cleanup ();
  2259. X                n = next_basenote (respnum);
  2260. X                if (n == -1)
  2261. X                    return (which_base (respnum));
  2262. X
  2263. X                respnum = n;
  2264. X                goto restart;
  2265. X
  2266. X            case '\t':     /* next page or unread response */
  2267. X                if (note_page == NOTE_UNAVAIL) {
  2268. X                    n = next_unread (next_response (respnum));
  2269. X                    if (n == -1)
  2270. X                        return (which_base (respnum));
  2271. X
  2272. X                    respnum = n;
  2273. X                    goto restart;
  2274. X
  2275. X                } else if (note_end) {
  2276. X                    note_cleanup();
  2277. X                    n = next_unread(next_response(respnum));
  2278. X                    if (n == -1)
  2279. X                        return (which_base (respnum));
  2280. X
  2281. X                    respnum = n;
  2282. X                    goto restart;
  2283. X                } else
  2284. X                    show_note_page(respnum, group);
  2285. X                break;
  2286. X
  2287. X            case ctrl('H'):    /* show article headers */
  2288. X                if (note_page == NOTE_UNAVAIL) {
  2289. X                    n = next_response (respnum);
  2290. X                    if (n == -1)
  2291. X                        return (which_base (respnum));
  2292. X
  2293. X                    respnum = n;
  2294. X                    goto restart;
  2295. X                } else {
  2296. X                    note_page = 0;
  2297. X                    note_end = FALSE;
  2298. X                    fseek(note_fp, 0L, 0);
  2299. X                    show_note_page(respnum, group);
  2300. X                }
  2301. X                break;
  2302. X
  2303. X            case ctrl('K'):        /* kill article */
  2304. X                if (kill_articles) {
  2305. X                    if (kill_art_menu (group, respnum)) {
  2306. X                        if (kill_any_articles (group)) {
  2307. X                            reload_index_file (group, TRUE);
  2308. X                        }
  2309. X                    }
  2310. X                    redraw_page(respnum, group);
  2311. X                } else {
  2312. X                    info_message (txt_switch_on_kill_art_menu);
  2313. X                }
  2314. X                break;
  2315. X
  2316. X            case ctrl('L'):        /* redraw current page of article */
  2317. X                redraw_page (respnum, group);
  2318. X                break;
  2319. X
  2320. X            case ctrl('R'):        /* redraw beginning of article */
  2321. X            case 'g':            /* 'less' compatible */
  2322. Xbegin_of_article:            
  2323. X                if (note_page == NOTE_UNAVAIL) {
  2324. X                    ClearScreen();
  2325. X                    printf(txt_art_unavailable,arts[respnum].artnum);
  2326. X                    fflush(stdout);
  2327. X                } else {
  2328. X                    note_page = 0;
  2329. X                    note_end = FALSE;
  2330. X                    fseek(note_fp, note_mark[0], 0);
  2331. X                    show_note_page(respnum, group);
  2332. X                }
  2333. X                break;
  2334. X
  2335. X            case ctrl('X'):
  2336. X            case '%':
  2337. X            case 'd':    /* toggle rot-13 mode */
  2338. X                if (rotate)
  2339. X                    rotate = 0;
  2340. X                else
  2341. X                    rotate = 13;
  2342. X                redraw_page (respnum, group);
  2343. X                info_message (txt_toggled_rot13);
  2344. X                break;
  2345. X
  2346. X            case 'a':    /* author search forward */
  2347. X            case 'A':    /* author search backward */
  2348. X                i = (ch == 'a');
  2349. X                n = search_author (respnum, i);
  2350. X                if (n < 0)
  2351. X                    break;
  2352. X                respnum = n;
  2353. X                goto restart;
  2354. X                /* NOTREACHED */
  2355. X
  2356. X            case ctrl('U'):
  2357. X            case 'b':        /* back a page */
  2358. Xpage_up:
  2359. X                if (note_page == NOTE_UNAVAIL) {
  2360. X                    note_cleanup();
  2361. X                    n = prev_response (respnum);
  2362. X                    if (n == -1)
  2363. X                        return (which_resp (respnum));
  2364. X
  2365. X                    respnum = n;
  2366. X                    goto restart;
  2367. X
  2368. X                } else {
  2369. X                    if (note_page <= 1) {
  2370. X                        info_message (txt_begin_of_art);
  2371. X                    } else {
  2372. X                        note_page -= 2;
  2373. X                        note_end = FALSE;
  2374. X                        fseek (note_fp, note_mark[note_page], 0);
  2375. X                        show_note_page (respnum, group);
  2376. X                    }
  2377. X                }
  2378. X                break;
  2379. X
  2380. X            case 'B':    /* bug/gripe/comment mailed to author */
  2381. X                mail_bug_report ();
  2382. X                redraw_page (respnum, group);
  2383. X                break;
  2384. X                
  2385. X            case 'c':    /* catchup--mark all articles as read */
  2386. X                if (prompt_yn (LINES, txt_mark_all_read, 'y')) {
  2387. X                    for (n = 0; n < top; n++) {
  2388. X                        arts[n].unread = ART_READ;
  2389. X                    }
  2390. X                    fix_new_highest(cur_groupnum);
  2391. X                    if (cur_groupnum + 1 < local_top) {
  2392. X                        cur_groupnum++;
  2393. X                    }
  2394. X                    note_cleanup();
  2395. X                    return -1;
  2396. X                }
  2397. X                break;
  2398. X
  2399. X            case 'C':    /* cancel an article */
  2400. X                if (cancel_article ()) {
  2401. X                    redraw_page (respnum, group);
  2402. X                }
  2403. X                break;
  2404. X    
  2405. X            case 'f':    /* post a followup to this article */
  2406. X                if (post_response (group, FALSE)) {
  2407. X                    update_newsrc (group, my_group[cur_groupnum], FALSE);
  2408. X                    n = which_base (respnum);
  2409. X                    note_cleanup ();
  2410. X                    index_group (group, group_path);
  2411. X                    read_newsrc_line (group);
  2412. X                    respnum = choose_resp (n, nresp(n));
  2413. X                    goto restart;
  2414. X                } else
  2415. X                    redraw_page (respnum, group);
  2416. X                break;
  2417. X
  2418. X            case 'F':    /* post a followup to this article */
  2419. X                if (post_response (group, TRUE)) {
  2420. X                    update_newsrc (group, my_group[cur_groupnum], FALSE);
  2421. X                    n = which_base (respnum);
  2422. X                    note_cleanup ();
  2423. X                    index_group (group, group_path);
  2424. X                    read_newsrc_line (group);
  2425. X                    respnum = choose_resp (n, nresp(n));
  2426. X                    goto restart;
  2427. X                } else
  2428. X                    redraw_page (respnum, group);
  2429. X                break;
  2430. X
  2431. X            case 'h':    /* help overview */
  2432. X                show_info_page (HELP_INFO, help_page, txt_art_pager_com);
  2433. X                redraw_page (respnum, group);
  2434. X                break;
  2435. X
  2436. X            case 'H':    /* help in-depth */
  2437. X                help_page_info ();
  2438. X                redraw_page(respnum, group);
  2439. X                break;
  2440. X
  2441. X            case 'i':    /* return to index page */
  2442. Xreturn_to_index:
  2443. X                note_cleanup ();
  2444. X                if (kill_state == NO_KILLING &&
  2445. X                    sort_art_type != old_sort_art_type) {
  2446. X                    make_threads (TRUE);
  2447. X                    find_base ();
  2448. X                }
  2449. X                if (kill_state == KILLING) {
  2450. X                    old_top = top;
  2451. X                    old_artnum = arts[respnum].artnum;
  2452. X                    if (kill_articles) {
  2453. X                        kill_any_articles (group);
  2454. X                        reload_index_file (group, TRUE);    /* kill arts */
  2455. SHAR_EOF
  2456. echo "End of tin1.02 part 5"
  2457. echo "File page.c is continued in part 6"
  2458. echo "6" > shar3_seq_.tmp
  2459. exit 0
  2460.  
  2461. exit 0 # Just in case...
  2462. -- 
  2463. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  2464. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  2465. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  2466. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  2467.