home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 3 / 3899 < prev    next >
Internet Message Format  |  1991-08-23  |  50KB

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