home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #31 / NN_1992_31.iso / spool / de / comp / sources / os9 / 15 < prev    next >
Encoding:
Text File  |  1992-12-24  |  67.8 KB  |  3,504 lines

  1. Xref: sparky de.comp.sources.os9:15 comp.os.os9:1560
  2. Path: sparky!uunet!elroy.jpl.nasa.gov!ames!sun-barr!news2me.EBay.Sun.COM!seven-up.East.Sun.COM!sungy!stasys!stasys!not-for-mail
  3. From: frank.kaefer@stasys.sta.sub.org (Frank Kaefer)
  4. Newsgroups: de.comp.sources.os9,comp.os.os9
  5. Subject: Tass for OS-9 Part02/03
  6. Message-ID: <1hccjaINN773@stasys.sta.sub.org>
  7. Date: 24 Dec 92 13:05:46 GMT
  8. Sender: news@stasys.sta.sub.org
  9. Followup-To: de.comp.sources.d
  10. Organization: Stasys News Server, Starnberg, Germany
  11. Lines: 3489
  12. Approved: frank.kaefer@stasys.sta.sub.org (Frank Kaefer)
  13. NNTP-Posting-Host: stasys.sta.sub.org
  14.  
  15. Submitted-by: Ulrich Dessauer <ud@Nightmare.ddt.sub.org>
  16. Archive-name: tass/part02
  17.  
  18. : ----- Cut here ----- Cut here ----- Cut here ----- Cut here -----
  19. : Use  sh filename  to extract shell archive
  20. : This shell archive contains following files:
  21. :     'mail.c                                        836 bytes'
  22. :     'main.c                                      23086 bytes'
  23. :     'misc.c                                       8468 bytes'
  24. :     'page.c                                      31558 bytes'
  25. if test -f 'mail.c' ; then
  26.   echo 'File mail.c already exists, overwriting it'
  27.   del 'mail.c'
  28. fi
  29. echo Extracting \"'mail.c'\"
  30. sed "s/^X//" >'mail.c' <<'__END__OF__THIS__FILE__'
  31. X
  32. X#include    <stdio.h>
  33. X#ifndef        OSK
  34. X#include    <sys/types.h>
  35. X#include    <sys/stat.h>
  36. X#else        /* OSK */
  37. X#include    <types.h>
  38. X#include    <stat.h>
  39. Xtypedef long    off_t;
  40. X#endif        /* OSK */
  41. X#include    "tass.h"
  42. X
  43. Xchar *mailbox_name = NULL;
  44. Xoff_t mailbox_size;
  45. X
  46. X
  47. X/*
  48. X *  Record size of mailbox so we can detect if new mail has arrived
  49. X */
  50. X
  51. Xmail_setup() {
  52. X    struct stat buf;
  53. X    extern char *getenv();
  54. X
  55. X    if (do_mail_check) {
  56. X        if (mailbox_name == NULL)
  57. X            mailbox_name = getenv("MAIL");
  58. X
  59. X        if (mailbox_name == NULL)
  60. X            mailbox_size = 0;
  61. X        else {
  62. X            if (stat(mailbox_name, &buf) >= 0)
  63. X                mailbox_size = buf.st_size;
  64. X            else
  65. X                mailbox_size = 0;
  66. X        }
  67. X    }
  68. X}
  69. X
  70. X
  71. X/*
  72. X *  Return TRUE if new mail has arrived
  73. X */
  74. X
  75. Xmail_check() {
  76. X    struct stat buf;
  77. X
  78. X    if (mailbox_name != NULL
  79. X    &&  stat(mailbox_name, &buf) >= 0
  80. X    &&  mailbox_size < buf.st_size)
  81. X        return TRUE;
  82. X
  83. X    return FALSE;
  84. X}
  85. X
  86. __END__OF__THIS__FILE__
  87. if test -f 'main.c' ; then
  88.   echo 'File main.c already exists, overwriting it'
  89.   del 'main.c'
  90. fi
  91. echo Extracting \"'main.c'\"
  92. sed "s/^X//" >'main.c' <<'__END__OF__THIS__FILE__'
  93. X
  94. X/*
  95. X *  Tass, a visual Usenet news reader
  96. X *  (c) Copyright 1990 by Rich Skrenta
  97. X *
  98. X *  Distribution agreement:
  99. X *
  100. X *    You may freely copy or redistribute this software, so long
  101. X *    as there is no profit made from its use, sale, trade or
  102. X *    reproduction.  You may not change this copyright notice,
  103. X *    and it must be included prominently in any copy made.
  104. X */
  105. X
  106. X#include    <stdio.h>
  107. X#include    <signal.h>
  108. X#ifdef    OSK
  109. X#include    <modes.h>
  110. X#include    <pwd.h>
  111. X#else    /* OSK */
  112. X#include    <sys/types.h>
  113. X#include    <sys/stat.h>
  114. X#endif    /* OSK */
  115. X#include    "tass.h"
  116. X
  117. X#ifdef    OSK
  118. Xextern char    *index ();
  119. X
  120. Xextern
  121. X#endif    /* OSK */
  122. Xint LINES, COLS;
  123. X
  124. Xint max_active;
  125. Xstruct group_ent *active;        /* active file */
  126. Xint group_hash[TABLE_SIZE];        /* group name --> active[] */
  127. Xint *my_group;                /* .newsrc --> active[] */
  128. Xint *unread;                /* highest art read in group */
  129. Xint num_active;                /* one past top of active */
  130. Xint local_top;                /* one past top of my_group */
  131. Xint update = FALSE;            /* update index files only mode */
  132. X
  133. Xstruct header *arts;
  134. Xlong *base;
  135. Xint max_art;
  136. Xint top = 0;
  137. Xint top_base;
  138. X
  139. X#ifdef    USE_UID
  140. Xint tass_uid;
  141. Xint tass_gid;
  142. Xint real_uid;
  143. Xint real_gid;
  144. X#ifdef    OSK
  145. X#define    DEF_TASSUID    (39 | (1 << 16))
  146. X#endif    /* OSK */
  147. X#endif    /* USE_UID */
  148. X
  149. Xint local_index;            /* do private indexing? */
  150. X
  151. Xint do_mail_check;            /* if we want to check for mail */
  152. X
  153. Xint omask;
  154. X
  155. Xjmp_buf jmp_buffer;
  156. X
  157. Xchar *cvers = "Tass 3.0  (c) Copyright 1991 by Rich Skrenta.  All rights reserved";
  158. X
  159. X
  160. X#ifdef SIGTSTP
  161. Xvoid
  162. Xmain_susp(i)
  163. Xint i;
  164. X{
  165. X
  166. X    Raw(FALSE);
  167. X    putchar('\n');
  168. X    signal(SIGTSTP, SIG_DFL);
  169. X    kill(0, SIGTSTP);
  170. X
  171. X    signal(SIGTSTP, main_susp);
  172. X    mail_setup();
  173. X    Raw(TRUE);
  174. X}
  175. X#endif
  176. X
  177. X
  178. Xmain(argc, argv)
  179. Xint argc;
  180. Xchar **argv;
  181. X{
  182. X    extern int optind, opterr;
  183. X    extern char *optarg;
  184. X    int errflag = 0;
  185. X    int i;
  186. X    int c;
  187. X#ifdef    OSK
  188. X    struct passwd    *pw;
  189. X#endif    /* OSK */
  190. X
  191. X    for (i = 0; i < TABLE_SIZE; i++)
  192. X        group_hash[i] = -1;
  193. X
  194. X#ifdef    SIGPIPE
  195. X    signal(SIGPIPE, SIG_IGN);
  196. X#endif    /* SIGPIPE */
  197. X#ifdef SIGTSTP
  198. X    signal(SIGTSTP, main_susp);
  199. X#endif
  200. X#ifdef    SIGQUIT
  201. X    signal(SIGQUIT, SIG_IGN);
  202. X#endif    /* SIGQUIT */
  203. X#ifdef    SIGINT
  204. X    signal(SIGINT, SIG_IGN);
  205. X#endif    /* SIGINT */
  206. X
  207. X#ifdef    USE_UID
  208. X#ifndef    OSK
  209. X    tass_uid = geteuid();
  210. X    tass_gid = getegid();
  211. X    real_uid = getuid();
  212. X    real_gid = getgid();
  213. X#else    /* OSK */
  214. X    real_uid = getuid ();
  215. X    setpwent ();
  216. X    if (pw = getpwnam ("news"))
  217. X        tass_uid = pw->pw_uid | (pw->pw_gid << 16);
  218. X    else
  219. X        tass_uid = DEF_TASSUID;
  220. X    endpwent ();
  221. X    setup_convtable (TRUE, TRUE);
  222. X    setuid (tass_uid);
  223. X#endif    /* OSK */
  224. X#endif    /* USE_UID */
  225. X
  226. X    omask = umask (0);
  227. X    init_selfinfo();    /* set up char *'s: homedir, newsrc, etc. */
  228. X    init_alloc();        /* allocate initial array sizes */
  229. X
  230. X#ifdef    USE_UID
  231. X    if (tass_uid == real_uid) {    /* run out of someone's account */
  232. X#endif    /* USE_UID */
  233. X        local_index = FALSE;    /* index in their home directory */
  234. X        if (access (indexdir, S_IFDIR) == -1)
  235. X#ifndef    OSK
  236. X            mkdir(indexdir, 0755);
  237. X#else    /* OSK */
  238. X            makdir (indexdir, S_IREAD | S_IWRITE, 033);
  239. X#endif    /* OSK */
  240. X#ifdef    USE_UID
  241. X    } else            /* we're setuid, index in /usr/spool/news */
  242. X        local_index = FALSE;
  243. X#endif    /* USE_UID */
  244. X
  245. X    do_mail_check = FALSE;
  246. X
  247. X    read_active();        /* load the active file into active[] */
  248. X
  249. X    while ((c = getopt(argc, argv, "f:ugm")) != -1) {
  250. X        switch(c) {
  251. X        case 'f':
  252. X            strcpy(newsrc, optarg);
  253. X            break;
  254. X
  255. X        case 'u':
  256. X            update = TRUE;
  257. X            break;
  258. X
  259. X        case 'g':
  260. X            local_index = TRUE;
  261. X            break;
  262. X
  263. X        case 'm':
  264. X            do_mail_check = TRUE;
  265. X            break;
  266. X
  267. X        case '?':
  268. X        default:
  269. X            errflag++;
  270. X        }
  271. X    }
  272. X
  273. X    if (errflag) {
  274. X        fprintf(stderr, "usage: tass [options] [newsgroups]\n");
  275. X        fprintf(stderr, "   -f file   use file instead of $HOME/.newsrc\n");
  276. X        fprintf(stderr, "   -u        update index files only\n");
  277. X        fprintf(stderr, "   -g        don't use global instead of local index files\n");
  278. X        fprintf(stderr, "   -m        check for new mail while reading news\n");
  279. X        exit(1);
  280. X    }
  281. X
  282. X    if (!update)
  283. X        printf("Tass 3.0\n");
  284. X
  285. X    if (optind < argc) {
  286. X        while (optind < argc) {
  287. X            if (add_group(argv[optind], TRUE) < 0)
  288. X                fprintf(stderr,
  289. X                    "group %s not found in active file\n",
  290. X                                argv[optind]);
  291. X            optind++;
  292. X        }
  293. X    } else
  294. X        read_newsrc(TRUE);
  295. X
  296. X    if (update) {            /* index file updater only */
  297. X        do_update();
  298. X        exit(0);
  299. X    }
  300. X
  301. X    if (InitScreen() == FALSE) {
  302. X        fprintf(stderr,"Screen initialization failed\n");
  303. X        exit(1);
  304. X    }
  305. X
  306. X    if (!setjmp (jmp_buffer)) {
  307. X        ScreenSize(&LINES, &COLS);
  308. X        Raw(TRUE);
  309. X
  310. X        mail_setup();        /* record mailbox size for "you have mail" */
  311. X        selection_index();
  312. X    }
  313. X
  314. X    tass_done(0);
  315. X}
  316. X
  317. X
  318. X
  319. Xtass_done(ret)
  320. Xint ret;
  321. X{
  322. X
  323. X    MoveCursor(LINES, 0);
  324. X    printf("\r\012");
  325. X    Raw(FALSE);
  326. X    umask (omask);
  327. X    exit(ret);
  328. X}
  329. X
  330. X
  331. X/*
  332. X *  Dynamic table management
  333. X *  These settings are memory conservative:  small initial allocations
  334. X *  and a 50% expansion on table overflow.  A fast vm system with
  335. X *  much memory might want to start with higher initial allocations
  336. X *  and a 100% expansion on overflow, especially for the arts[] array.
  337. X */
  338. X
  339. Xinit_alloc() {
  340. X
  341. X    max_active = 100;    /* initial alloc */
  342. X
  343. X    active = (struct group_ent *) my_malloc(sizeof(*active) * max_active);
  344. X    my_group = (int *) my_malloc(sizeof(int) * max_active);
  345. X    unread = (int *) my_malloc(sizeof(int) * max_active);
  346. X
  347. X    max_art = 300;        /* initial alloc */
  348. X
  349. X    arts = (struct header *) my_malloc(sizeof(*arts) * max_art);
  350. X    base = (long *) my_malloc(sizeof(long) * max_art);
  351. X}
  352. X
  353. X
  354. Xexpand_art() {
  355. X
  356. X    max_art += max_art / 2;        /* increase by 50% */
  357. X
  358. X    arts = (struct header *) my_realloc(arts, sizeof(*arts) * max_art);
  359. X    base = (long *) my_realloc(base, sizeof(long) * max_art);
  360. X}
  361. X
  362. X
  363. Xexpand_active() {
  364. X
  365. X    max_active += max_active / 2;        /* increase by 50% */
  366. X
  367. X    active = (struct group_ent *) my_realloc(active,
  368. X                        sizeof(*active) * max_active);
  369. X    my_group = (int *) my_realloc(my_group, sizeof(int) * max_active);
  370. X    unread = (int *) my_realloc(unread, sizeof(int) * max_active);
  371. X}
  372. X
  373. X
  374. X/*
  375. X *  Load the active file into active[]
  376. X */
  377. X
  378. Xread_active()
  379. X{
  380. X    FILE *fp;
  381. X    char *p, *q;
  382. X    char buf[200];
  383. X    long h;
  384. X    int i;
  385. X
  386. X    num_active = 0;
  387. X
  388. X    if ((fp = fopen(active_file, "r")) == NULL) {
  389. X        fprintf(stderr, "can't open %s: ", active_file);
  390. X        perror("");
  391. X        exit(1);
  392. X    }
  393. X
  394. X    while (fgets(buf, 200, fp) != NULL) {
  395. X        for (p = buf; *p && *p != ' '; p++) ;
  396. X        if (*p != ' ') {
  397. X#ifndef    OSK
  398. X            fprintf(stderr, "active file corrupt\n");
  399. X#else    /* OSK */
  400. X            fprintf(stderr, "active file corrupt in line '%s'\n", buf);
  401. X#endif    /* OSK */
  402. X            continue;
  403. X        }
  404. X
  405. X        *p++ = '\0';
  406. X
  407. X        if (num_active >= max_active)
  408. X            expand_active();
  409. X
  410. X        {        /* hash group name for fast lookup later */
  411. X            char *t = buf;
  412. X
  413. X            h = *t++;
  414. X            while (*t)
  415. X                h = (h * 64 + *t++) % TABLE_SIZE;
  416. X        }
  417. X
  418. X        if (group_hash[h] == -1)
  419. X            group_hash[h] = num_active;
  420. X        else {                /* hash linked list chaining */
  421. X            for (i = group_hash[h]; active[i].next >= 0;
  422. X                        i = active[i].next) {
  423. X                if (strcmp(active[i].name, buf) == 0)
  424. X                    goto read_active_continue;
  425. X                            /* kill dups */
  426. X            }
  427. X            if (strcmp(active[i].name, buf) == 0)
  428. X                goto read_active_continue;
  429. X            active[i].next = num_active;
  430. X        }
  431. X
  432. X        for (q = p; *q && *q != ' '; q++) ;
  433. X        if (*q != ' ') {
  434. X            fprintf(stderr, "active file corrupt\n");
  435. X            continue;
  436. X        }
  437. X
  438. X        active[num_active].name = str_save(buf);
  439. X
  440. X        active[num_active].max = atol(p);
  441. X        active[num_active].min = atol(q);
  442. X
  443. X        active[num_active].next = -1;        /* hash chaining */
  444. X        active[num_active].flag = NOTGOT;   /* not in my_group[] yet */
  445. X
  446. X        num_active++;
  447. X
  448. Xread_active_continue:;
  449. X
  450. X    }
  451. X
  452. X    fclose(fp);
  453. X}
  454. X
  455. X
  456. X
  457. X/*
  458. X *  Read $HOME/.newsrc into my_group[].  my_group[] ints point to
  459. X *  active[] entries.  Sub_only determines whether we just read
  460. X *  subscribed groups or all of them.
  461. X */
  462. Xvoid
  463. Xread_newsrc(sub_only)
  464. Xint sub_only;        /* TRUE=subscribed groups only, FALSE=all groups */
  465. X{
  466. X    FILE *fp;
  467. X    char *p;
  468. X    char buf[8192];
  469. X    char c;
  470. X    int i;
  471. X
  472. X    local_top = 0;
  473. X
  474. X#ifdef    USE_UID
  475. X    setuid(real_uid);    /* become the user to write in his */
  476. X    setgid(real_gid);    /* home directory */
  477. X#endif    /* USE_UID */
  478. X
  479. X    fp = fopen(newsrc, "r");
  480. X    if (fp == NULL) {        /* attempt to make a .newsrc */
  481. X#ifdef    USE_UID
  482. X        setuid(tass_uid);
  483. X        setgid(tass_gid);
  484. X#endif    /* USE_UID */
  485. X        for (i = 0; i < num_active; i++) {
  486. X            if (local_top >= max_active)
  487. X                expand_active();
  488. X            my_group[local_top] = i;
  489. X            active[i].flag = 0;
  490. X#if 0
  491. X            unread[local_top] = active[i].max - active[i].min;
  492. X#else
  493. X            unread[local_top] = -1;
  494. X#endif
  495. X            local_top++;
  496. X        }
  497. X        write_newsrc();
  498. X        return;
  499. X    }
  500. X
  501. X    while (fgets(buf, 8192, fp) != NULL) {
  502. X        p = buf;
  503. X        while (*p && *p != '\n' && *p != ' ' && *p != ':' && *p != '!')
  504. X            p++;
  505. X        c = *p;
  506. X        *p++ = '\0';
  507. X        if (c == '!' && sub_only)
  508. X            continue;        /* unsubscribed */
  509. X
  510. X        if ((i = add_group(buf, FALSE)) < 0) {
  511. X            fprintf(stderr, "group %s not found in active file\n", buf);
  512. X            continue;
  513. X        }
  514. X
  515. X        if (c != '!')        /* if we're subscribed to it */
  516. X            active[my_group[i]].flag |= SUBS;
  517. X
  518. X        unread[i] = parse_unread(p, my_group[i]);
  519. X    }
  520. X    fclose(fp);
  521. X#ifdef    USE_UID
  522. X    setuid(tass_uid);
  523. X    setgid(tass_gid);
  524. X#endif    /* USE_UID */
  525. X}
  526. X
  527. X
  528. X/*
  529. X *  Write a new newsrc from my_group[] and active[]
  530. X *  Used to a create a new .newsrc if there isn't one already, or when
  531. X *  the newsrc is reset.
  532. X */
  533. X
  534. Xwrite_newsrc() {
  535. X    FILE *fp;
  536. X    int i;
  537. X
  538. X#ifdef    USE_UID
  539. X    setuid(real_uid);    /* become the user to write in his */
  540. X    setgid(real_gid);    /* home directory */
  541. X#endif    /* USE_UID */
  542. X
  543. X    umask (omask);
  544. X    fp = fopen(newsrc, "w");
  545. X    if (fp == NULL)
  546. X        goto write_newsrc_done;
  547. X
  548. X    for (i = 0; i < num_active; i++)
  549. X        fprintf(fp, "%s: \n", active[i].name);
  550. X
  551. X    fclose(fp);
  552. X
  553. Xwrite_newsrc_done:
  554. X    umask (0);
  555. X#ifdef    USE_UID
  556. X    setuid(tass_uid);
  557. X    setgid(tass_gid);
  558. X#endif    /* USE_UID */
  559. X}
  560. X
  561. X
  562. X/*
  563. X *  Load the sequencer rang lists and mark arts[] according to the
  564. X *  .newsrc info for a particular group.  i.e.  rec.arts.comics: 1-94,97
  565. X */
  566. X
  567. Xread_newsrc_line(group)
  568. Xchar *group;
  569. X{
  570. X    FILE *fp;
  571. X    char buf[8192];
  572. X    char *p;
  573. X
  574. X#ifdef    USE_UID
  575. X    setuid(real_uid);
  576. X    setgid(real_gid);
  577. X#endif    /* USE_UID */
  578. X
  579. X    fp = fopen(newsrc, "r");
  580. X    if (fp == NULL)
  581. X        goto read_newsrc_line_done;
  582. X
  583. X    while (fgets(buf, 8192, fp) != NULL) {
  584. X        p = buf;
  585. X        while (*p && *p != '\n' && *p != ' ' && *p != ':' && *p != '!')
  586. X            p++;
  587. X        *p++ = '\0';
  588. X        if (strcmp(buf, group) != 0)
  589. X            continue;
  590. X        parse_seq(p);
  591. X        break;
  592. X    }
  593. X
  594. X    fclose(fp);
  595. Xread_newsrc_line_done:
  596. X#ifdef    USE_UID
  597. X    setuid(tass_uid);
  598. X    setgid(tass_gid);
  599. X#else    /* USE UID */
  600. X    ;
  601. X#endif    /* USE_UID */
  602. X}
  603. X
  604. X
  605. X/*
  606. X *  For our current group, update the sequencer information in .newsrc
  607. X */
  608. X
  609. Xupdate_newsrc(group, groupnum)
  610. Xchar *group;
  611. Xint groupnum;            /* index into active[] for this group */
  612. X{
  613. X    FILE *fp;
  614. X    FILE *newfp;
  615. X    char buf[8192];
  616. X    char *p;
  617. X    char c;
  618. X    int gotit = FALSE;
  619. X
  620. X#ifdef    USE_UID
  621. X    setuid(real_uid);
  622. X    setgid(real_gid);
  623. X#endif    /* USE_UID */
  624. X
  625. X    umask (omask);
  626. X    fp = fopen(newsrc, "r");
  627. X    newfp = fopen(newnewsrc, "w");
  628. X    if (newfp == NULL)
  629. X        goto update_done;
  630. X
  631. X    if (fp != NULL) {
  632. X        while (fgets(buf, 8192, fp) != NULL) {
  633. X            for (p = buf; *p; p++)
  634. X                if (*p == '\n') {
  635. X                    *p = '\0';
  636. X                    break;
  637. X                }
  638. X
  639. X            p = buf;
  640. X            while (*p && *p != ' ' && *p != ':' && *p != '!')
  641. X                    p++;
  642. X            c = *p;
  643. X            if (c != '\0')
  644. X                *p++ = '\0';
  645. X
  646. X            if (c != '!')
  647. X                c = ':';
  648. X
  649. X            if (strcmp(buf, group) == 0) {
  650. X                fprintf(newfp, "%s%c ", buf, c);
  651. X                gotit = TRUE;
  652. X                print_seq(newfp, groupnum);
  653. X                fprintf(newfp, "\n");
  654. X            } else
  655. X                fprintf(newfp, "%s%c%s\n", buf, c, p);
  656. X        }
  657. X        fclose(fp);
  658. X    }
  659. X
  660. X    fclose(newfp);
  661. X    unlink(newsrc);
  662. X#ifndef    OSK
  663. X    link(newnewsrc, newsrc);
  664. X    unlink(newnewsrc);
  665. X#else    /* OSK */
  666. X    rename(newnewsrc, newsrc);
  667. X#endif    /* OSK */
  668. X
  669. Xupdate_done:
  670. X    umask (0);
  671. X#ifdef    USE_UID
  672. X    setuid(tass_uid);
  673. X    setgid(tass_gid);
  674. X#endif    /* USE_UID */
  675. X}
  676. X
  677. X
  678. X/*
  679. X *  Subscribe/unsubscribe to a group in .newsrc.  ch should either be
  680. X *  '!' to unsubscribe or ':' to subscribe.  num is the group's index
  681. X *  in active[].
  682. X */
  683. X
  684. Xsubscribe(group, ch, num, out_seq)
  685. Xchar *group;
  686. Xchar ch;
  687. Xint num;
  688. Xint out_seq;                /* output sequencer info? */
  689. X{
  690. X    FILE *fp;
  691. X    FILE *newfp;
  692. X    char buf[8192];
  693. X    char *p;
  694. X    char c;
  695. X    int gotit = FALSE;
  696. X
  697. X    if (ch == '!')
  698. X        active[num].flag &= ~SUBS;
  699. X    else
  700. X        active[num].flag |= SUBS;
  701. X
  702. X#ifdef    USE_UID
  703. X    setuid(real_uid);
  704. X    setgid(real_gid);
  705. X#endif    /* USE_UID */
  706. X
  707. X    umask (omask);
  708. X    fp = fopen(newsrc, "r");
  709. X    newfp = fopen(newnewsrc, "w");
  710. X    if (newfp == NULL)
  711. X        goto update_done;
  712. X
  713. X    if (fp != NULL) {
  714. X        while (fgets(buf, 8192, fp) != NULL) {
  715. X            for (p = buf; *p; p++)
  716. X                if (*p == '\n') {
  717. X                    *p = '\0';
  718. X                    break;
  719. X                }
  720. X
  721. X            p = buf;
  722. X            while (*p && *p != ' ' && *p != ':' && *p != '!')
  723. X                    p++;
  724. X            c = *p;
  725. X            if (c != '\0')
  726. X                *p++ = '\0';
  727. X
  728. X            if (c != '!')
  729. X                c = ':';
  730. X
  731. X            if (strcmp(buf, group) == 0) {
  732. X                fprintf(newfp, "%s%c%s\n", buf, ch, p);
  733. X                gotit = TRUE;
  734. X            } else
  735. X                fprintf(newfp, "%s%c%s\n", buf, c, p);
  736. X        }
  737. X        fclose(fp);
  738. X    }
  739. X
  740. X    if (!gotit) {
  741. X        if (out_seq) {
  742. X            fprintf(newfp, "%s%c ", group, ch);
  743. X            print_seq(newfp, num);
  744. X            fprintf(newfp, "\n");
  745. X        } else
  746. X            fprintf(newfp, "%s%c\n", group, ch);
  747. X    }
  748. X
  749. X    fclose(newfp);
  750. X    unlink(newsrc);
  751. X#ifndef    OSK
  752. X    link(newnewsrc, newsrc);
  753. X    unlink(newnewsrc);
  754. X#else    /* OSK */
  755. X    rename(newnewsrc, newsrc);
  756. X#endif    /* OSK */
  757. X
  758. Xupdate_done:
  759. X    umask (0);
  760. X#ifdef    USE_UID
  761. X    setuid(tass_uid);
  762. X    setgid(tass_gid);
  763. X#endif    /* USE_UID */
  764. X}
  765. X
  766. Xvoid
  767. Xprint_seq(fp, groupnum)
  768. XFILE *fp;
  769. Xint groupnum;            /* index into active[] for this group */
  770. X{
  771. X    int i;
  772. X    int flag = FALSE;
  773. X
  774. X    if (top <= 0) {
  775. X        if (active[groupnum].min > 1) {
  776. X            fprintf(fp, "1-%ld", active[groupnum].min);
  777. X            fflush(fp);
  778. X        }
  779. X        return;
  780. X    }
  781. X
  782. X    i = 0;
  783. X    if (arts[0].artnum > 1) {
  784. X        for (; i < top && !arts[i].unread; i++) ;
  785. X        if (i > 0)
  786. X            fprintf(fp, "1-%ld", arts[i-1].artnum);
  787. X        else
  788. X            fprintf(fp, "1-%ld", arts[0].artnum - 1);
  789. X        flag = TRUE;
  790. X    }
  791. X
  792. X    for (; i < top; i++) {
  793. X        if (!arts[i].unread) {
  794. X            if (flag)
  795. X                fprintf(fp, ",");
  796. X            else
  797. X                flag = TRUE;
  798. X            fprintf(fp, "%ld", arts[i].artnum);
  799. X            if (i+1 < top && !arts[i+1].unread) {
  800. X                while (i+1 < top && !arts[i+1].unread)
  801. X                    i++;
  802. X                fprintf(fp, "-%ld", arts[i].artnum);
  803. X            }
  804. X        }
  805. X    }
  806. X
  807. X    if (!flag && active[groupnum].min > 1)
  808. X        fprintf(fp, "1-%ld", active[groupnum].min);
  809. X    fflush(fp);
  810. X}
  811. X
  812. X
  813. Xparse_seq(s)
  814. Xchar *s;
  815. X{
  816. X    long low, high;
  817. X    int i;
  818. X
  819. X    while (*s) {
  820. X        while (*s && (*s < '0' || *s > '9'))
  821. X            s++;
  822. X
  823. X        if (*s && *s >= '0' && *s <= '9') {
  824. X            low = atol(s);
  825. X            while (*s && *s >= '0' && *s <= '9')
  826. X                s++;
  827. X            if (*s == '-') {
  828. X                s++;
  829. X                high = atol(s);
  830. X                while (*s && *s >= '0' && *s <= '9')
  831. X                    s++;
  832. X            }  else
  833. X                high = low;
  834. X
  835. X            for (i = 0; i < top; i++)
  836. X                if (arts[i].artnum >= low &&
  837. X                    arts[i].artnum <= high)
  838. X                    arts[i].unread = 0;
  839. X        }
  840. X    }
  841. X}
  842. X
  843. X
  844. Xparse_unread(s, groupnum)
  845. Xchar *s;
  846. Xint groupnum;            /* index for group in active[] */
  847. X{
  848. X    long low, high;
  849. X    long last_high;
  850. X    int i;
  851. X    int sum = 0;
  852. X    int gotone = FALSE;
  853. X    int n;
  854. X
  855. X/*
  856. X *  Read the first range from the .newsrc sequencer information.  If the
  857. X *  top of the first range is higher than what the active file claims is
  858. X *  the bottom, use it as the new bottom instead
  859. X */
  860. X
  861. X    high = 0;
  862. X    if (*s) {
  863. X        while (*s && (*s < '0' || *s > '9'))
  864. X            s++;
  865. X
  866. X        if (*s && *s >= '0' && *s <= '9') {
  867. X            low = atol(s);
  868. X            while (*s && *s >= '0' && *s <= '9')
  869. X                s++;
  870. X            if (*s == '-') {
  871. X                s++;
  872. X                high = atol(s);
  873. X                while (*s && *s >= '0' && *s <= '9')
  874. X                    s++;
  875. X            }  else
  876. X                high = low;
  877. X            gotone = TRUE;
  878. X        }
  879. X    }
  880. X
  881. X    if (high < active[groupnum].min)
  882. X        high = active[groupnum].min;
  883. X
  884. X#ifdef    OSK
  885. X    if (! gotone) {
  886. X        high = active [groupnum].min;
  887. X        low = high;
  888. X        gotone = low != active[groupnum].max;
  889. X    }
  890. X#endif    /* OSK */
  891. X
  892. X    while (*s) {
  893. X        last_high = high;
  894. X
  895. X        while (*s && (*s < '0' || *s > '9'))
  896. X            s++;
  897. X
  898. X        if (*s && *s >= '0' && *s <= '9') {
  899. X            low = atol(s);
  900. X            while (*s && *s >= '0' && *s <= '9')
  901. X                s++;
  902. X            if (*s == '-') {
  903. X                s++;
  904. X                high = atol(s);
  905. X                while (*s && *s >= '0' && *s <= '9')
  906. X                    s++;
  907. X            }  else
  908. X                high = low;
  909. X
  910. X            if (low > last_high)    /* otherwise seq out of order */
  911. X                sum += (low - last_high) - 1;
  912. X        }
  913. X    }
  914. X
  915. X    if (gotone) {
  916. X        if (active[groupnum].max > high)
  917. X            sum += active[groupnum].max - high;
  918. X        return sum;
  919. X    }
  920. X
  921. X    n = (int) (active[groupnum].max - active[groupnum].min);
  922. X    if (n < 2)
  923. X        return 0;
  924. X
  925. X    return -1;
  926. X}
  927. X
  928. X
  929. Xget_line_unread(group, groupnum)
  930. Xchar *group;
  931. Xint groupnum;                /* index for group in active[] */
  932. X{
  933. X    FILE *fp;
  934. X    char buf[8192];
  935. X    char *p;
  936. X    int ret = -1;
  937. X
  938. X#ifdef    USE_UID
  939. X    setuid(real_uid);
  940. X    setgid(real_gid);
  941. X#endif    /* USE_UID */
  942. X
  943. X    fp = fopen(newsrc, "r");
  944. X    if (fp == NULL) {
  945. X#ifdef    USE_UID
  946. X        setuid(tass_uid);
  947. X        setgid(tass_gid);
  948. X#endif    /* USE_UID */
  949. X
  950. X        return -1;
  951. X    }
  952. X
  953. X    while (fgets(buf, 8192, fp) != NULL) {
  954. X        p = buf;
  955. X        while (*p && *p != '\n' && *p != ' ' && *p != ':' && *p != '!')
  956. X            p++;
  957. X        *p++ = '\0';
  958. X        if (strcmp(buf, group) != 0)
  959. X            continue;
  960. X        ret = parse_unread(p, groupnum);
  961. X        break;
  962. X    }
  963. X
  964. X    fclose(fp);
  965. X
  966. X#ifdef    USE_UID
  967. X    setuid(tass_uid);
  968. X    setgid(tass_gid);
  969. X#endif    /* USE_UID */
  970. X
  971. X    return ret;
  972. X}
  973. X
  974. X
  975. Xreset_newsrc()
  976. X{
  977. X    FILE *fp;
  978. X    FILE *newfp;
  979. X    char buf[8192];
  980. X    char *p;
  981. X    char c;
  982. X    int gotit = FALSE;
  983. X    int i;
  984. X
  985. X#ifdef    USE_UID
  986. X    setuid(real_uid);
  987. X    setgid(real_gid);
  988. X#endif    /* USE_UID */
  989. X
  990. X    umask (omask);
  991. X    fp = fopen(newsrc, "r");
  992. X    newfp = fopen(newnewsrc, "w");
  993. X    if (newfp == NULL)
  994. X        goto update_done;
  995. X
  996. X    if (fp != NULL) {
  997. X        while (fgets(buf, 8192, fp) != NULL) {
  998. X            for (p = buf; *p && *p != '\n'; p++) ;
  999. X            *p = '\0';
  1000. X
  1001. X            p = buf;
  1002. X            while (*p && *p != ' ' && *p != ':' && *p != '!')
  1003. X                    p++;
  1004. X            c = *p;
  1005. X            if (c != '\0')
  1006. X                *p++ = '\0';
  1007. X
  1008. X            if (c != '!')
  1009. X                c = ':';
  1010. X
  1011. X            fprintf(newfp, "%s%c\n", buf, c);
  1012. X        }
  1013. X        fclose(fp);
  1014. X    }
  1015. X
  1016. X    fclose(newfp);
  1017. X    unlink(newsrc);
  1018. X#ifndef    OSK
  1019. X    link(newnewsrc, newsrc);
  1020. X    unlink(newnewsrc);
  1021. X#else    /* OSK */
  1022. X    rename(newnewsrc, newsrc);
  1023. X#endif    /* OSK */
  1024. X
  1025. Xupdate_done:
  1026. X    umask (0);
  1027. X#ifdef    USE_UID
  1028. X    setuid(tass_uid);
  1029. X    setgid(tass_gid);
  1030. X#endif    /* USE_UID */
  1031. X
  1032. X    for (i = 0; i < local_top; i++)
  1033. X        unread[i] = -1;
  1034. X}
  1035. X
  1036. X
  1037. Xdelete_group(group)
  1038. Xchar *group;
  1039. X{
  1040. X    FILE *fp;
  1041. X    FILE *newfp;
  1042. X    char buf[8192];
  1043. X    char *p;
  1044. X    char c;
  1045. X    int gotit = FALSE;
  1046. X    FILE *del;
  1047. X
  1048. X#ifdef    USE_UID
  1049. X    setuid(real_uid);
  1050. X    setgid(real_gid);
  1051. X#endif    /* USE_UID */
  1052. X
  1053. X    umask (omask);
  1054. X    fp = fopen(newsrc, "r");
  1055. X    newfp = fopen(newnewsrc, "w");
  1056. X    if (newfp == NULL)
  1057. X        goto del_done;
  1058. X    del = fopen(delgroups, "a+");
  1059. X    if (del == NULL)
  1060. X        goto del_done;
  1061. X
  1062. X    if (fp != NULL) {
  1063. X        while (fgets(buf, 8192, fp) != NULL) {
  1064. X            for (p = buf; *p && *p != '\n'; p++) ;
  1065. X            *p = '\0';
  1066. X
  1067. X            p = buf;
  1068. X            while (*p && *p != ' ' && *p != ':' && *p != '!')
  1069. X                    p++;
  1070. X            c = *p;
  1071. X            if (c != '\0')
  1072. X                *p++ = '\0';
  1073. X
  1074. X            if (c != '!')
  1075. X                c = ':';
  1076. X
  1077. X            if (strcmp(buf, group) == 0) {
  1078. X                fprintf(del, "%s%c%s\n", buf, c, p);
  1079. X                gotit = TRUE;
  1080. X            } else
  1081. X                fprintf(newfp, "%s%c%s\n", buf, c, p);
  1082. X        }
  1083. X        fclose(fp);
  1084. X    }
  1085. X
  1086. X    fclose(newfp);
  1087. X
  1088. X    if (!gotit)
  1089. X        fprintf(del, "%s! \n", group);
  1090. X
  1091. X    fclose(del);
  1092. X    unlink(newsrc);
  1093. X#ifndef    OSK
  1094. X    link(newnewsrc, newsrc);
  1095. X    unlink(newnewsrc);
  1096. X#else    /* OSK */
  1097. X    rename(newnewsrc, newsrc);
  1098. X#endif    /* OSK */
  1099. X
  1100. Xdel_done:
  1101. X    umask (0);
  1102. X#ifdef    USE_UID
  1103. X    setuid(tass_uid);
  1104. X    setgid(tass_gid);
  1105. X#endif    /* USE_UID */
  1106. X}
  1107. X
  1108. X
  1109. Xundel_group() {
  1110. X    FILE *del;
  1111. X    FILE *newfp;
  1112. X    FILE *fp;
  1113. X    char buf[2][8192];
  1114. X    char *p;
  1115. X    int which = 0;
  1116. X    long h;
  1117. X    extern int cur_groupnum;
  1118. X    int i, j;
  1119. X    char c;
  1120. X
  1121. X#ifdef    USE_UID
  1122. X    setuid(real_uid);
  1123. X    setgid(real_gid);
  1124. X#endif    /* USE_UID */
  1125. X
  1126. X    del = fopen(delgroups, "r");
  1127. X    if (del == NULL) {
  1128. X#ifdef    USE_UID
  1129. X        setuid(tass_uid);
  1130. X        setgid(tass_gid);
  1131. X#endif    /* USE_UID */
  1132. X        return FALSE;
  1133. X    }
  1134. X    unlink(delgroups);
  1135. X    umask (omask);
  1136. X    newfp = fopen(delgroups, "w");
  1137. X    if (newfp == NULL) {
  1138. X        umask (0);
  1139. X#ifdef    USE_UID
  1140. X        setuid(tass_uid);
  1141. X        setgid(tass_gid);
  1142. X#endif    /* USE_UID */
  1143. X        return FALSE;
  1144. X    }
  1145. X
  1146. X    buf[0][0] = '\0';
  1147. X    buf[1][0] = '\0';
  1148. X
  1149. X    while (fgets(buf[which], 8192, del) != NULL) {
  1150. X        which = !which;
  1151. X        if (*buf[which])
  1152. X            fputs(buf[which], newfp);
  1153. X    }
  1154. X
  1155. X    fclose(del);
  1156. X    fclose(newfp);
  1157. X    which = !which;
  1158. X
  1159. X    if (!*buf[which]) {
  1160. X        umask (0);
  1161. X#ifdef    USE_UID
  1162. X        setuid(tass_uid);
  1163. X        setgid(tass_gid);
  1164. X#endif    /* USE_UID */
  1165. X        return FALSE;
  1166. X    }
  1167. X
  1168. X    for (p = buf[which]; *p && *p != '\n'; p++) ;
  1169. X    *p = '\0';
  1170. X
  1171. X    p = buf[which];
  1172. X    while (*p && *p != ' ' && *p != ':' && *p != '!')
  1173. X        p++;
  1174. X    c = *p;
  1175. X    if (c != '\0')
  1176. X        *p++ = '\0';
  1177. X
  1178. X    if (c != '!')
  1179. X        c = ':';
  1180. X
  1181. X    {            /* find the hash of the group name */
  1182. X        char *t = buf[which];
  1183. X
  1184. X        h = *t++;
  1185. X        while (*t)
  1186. X            h = (h * 64 + *t++) % TABLE_SIZE;
  1187. X    }
  1188. X
  1189. X    for (i = group_hash[h]; i >= 0; i = active[i].next) {
  1190. X        if (strcmp(buf[which], active[i].name) == 0) {
  1191. X            for (j = 0; j < local_top; j++)
  1192. X                if (my_group[j] == i) {
  1193. X                    umask (0);
  1194. X#ifdef    USE_UID
  1195. X                    setuid(tass_uid);
  1196. X                    setgid(tass_gid);
  1197. X#endif    /* USE_UID */
  1198. X                    return j;
  1199. X                }
  1200. X
  1201. X            active[i].flag &= ~NOTGOT;   /* mark that we got it */
  1202. X            if (c != '!')
  1203. X                active[i].flag |= SUBS;
  1204. X
  1205. X            if (local_top >= max_active)
  1206. X                expand_active();
  1207. X            local_top++;
  1208. X            for (j = local_top; j > cur_groupnum; j--) {
  1209. X                my_group[j] = my_group[j-1];
  1210. X                unread[j] = unread[j-1];
  1211. X            }
  1212. X            my_group[cur_groupnum] = i;
  1213. X            unread[cur_groupnum] = parse_unread(p, i);
  1214. X
  1215. X            fp = fopen(newsrc, "r");
  1216. X            if (fp == NULL) {
  1217. X                umask (0);
  1218. X#ifdef    USE_UID
  1219. X                setuid(tass_uid);
  1220. X                setgid(tass_gid);
  1221. X#endif    /* USE_UID */
  1222. X                return FALSE;
  1223. X            }
  1224. X            newfp = fopen(newnewsrc, "w");
  1225. X            if (newfp == NULL) {
  1226. X                fclose(fp);
  1227. X                umask (0);
  1228. X#ifdef    USE_UID
  1229. X                setuid(tass_uid);
  1230. X                setgid(tass_gid);
  1231. X#endif    /* USE_UID */
  1232. X                return FALSE;
  1233. X            }
  1234. X            i = 0;
  1235. X            while (fgets(buf[!which], 8192, fp) != NULL) {
  1236. X                for (p = buf[!which]; *p && *p != '\n'; p++) ;
  1237. X                *p = '\0';
  1238. X
  1239. X                p = buf[!which];
  1240. X                while (*p && *p!=' ' && *p != ':' && *p != '!')
  1241. X                    p++;
  1242. X                c = *p;
  1243. X                if (c != '\0')
  1244. X                    *p++ = '\0';
  1245. X
  1246. X                if (c != '!')
  1247. X                    c = ':';
  1248. X
  1249. X                while (i < cur_groupnum) {
  1250. X                    if (strcmp(buf[!which],
  1251. X                      active[my_group[i]].name) == 0) {
  1252. X                        fprintf(newfp, "%s%c%s\n",
  1253. X                            buf[!which], c, p);
  1254. X                        goto foo_cont;
  1255. X                    }
  1256. X                    i++;
  1257. X                }
  1258. X                fprintf(newfp, "%s%c%s\n", buf[which], c, p);
  1259. X                fprintf(newfp, "%s%c%s\n", buf[!which], c, p);
  1260. X                break;
  1261. Xfoo_cont:;
  1262. X            }
  1263. X
  1264. X            while (fgets(buf[!which], 8192, fp) != NULL)
  1265. X                fputs(buf[!which], newfp);
  1266. X
  1267. X            fclose(newfp);
  1268. X            fclose(fp);
  1269. X            unlink(newsrc);
  1270. X#ifndef    OSK
  1271. X            link(newnewsrc, newsrc);
  1272. X            unlink(newnewsrc);
  1273. X#else    /* OSK */
  1274. X            rename(newnewsrc, newsrc);
  1275. X#endif    /* OSK */
  1276. X            umask (0);
  1277. X#ifdef    USE_UID
  1278. X            setuid(tass_uid);
  1279. X            setgid(tass_gid);
  1280. X#endif    /* USE_UID */
  1281. X            return TRUE;
  1282. X        }
  1283. X    }
  1284. X
  1285. X    umask (0);
  1286. X#ifdef    USE_UID
  1287. X    setuid(tass_uid);
  1288. X    setgid(tass_gid);
  1289. X#endif    /* USE_UID */
  1290. X
  1291. X    return FALSE;
  1292. X}
  1293. X
  1294. Xvoid
  1295. Xmark_group_read(group, groupnum)
  1296. Xchar *group;
  1297. Xint groupnum;            /* index into active[] for this group */
  1298. X{
  1299. X    FILE *fp;
  1300. X    FILE *newfp;
  1301. X    char buf[8192];
  1302. X    char *p;
  1303. X    char c;
  1304. X    int gotit = FALSE;
  1305. X
  1306. X    if (active[groupnum].max < 2)
  1307. X        return;
  1308. X
  1309. X#ifdef    USE_UID
  1310. X    setuid(real_uid);
  1311. X    setgid(real_gid);
  1312. X#endif    /* USE_UID */
  1313. X
  1314. X    umask (omask);
  1315. X    fp = fopen(newsrc, "r");
  1316. X    newfp = fopen(newnewsrc, "w");
  1317. X    if (newfp == NULL)
  1318. X        goto mark_group_read_done;
  1319. X
  1320. X    if (fp != NULL) {
  1321. X        while (fgets(buf, 8192, fp) != NULL) {
  1322. X            for (p = buf; *p; p++)
  1323. X                if (*p == '\n') {
  1324. X                    *p = '\0';
  1325. X                    break;
  1326. X                }
  1327. X
  1328. X            p = buf;
  1329. X            while (*p && *p != ' ' && *p != ':' && *p != '!')
  1330. X                    p++;
  1331. X            c = *p;
  1332. X            if (c != '\0')
  1333. X                *p++ = '\0';
  1334. X
  1335. X            if (c != '!')
  1336. X                c = ':';
  1337. X
  1338. X            if (strcmp(buf, group) == 0) {
  1339. X                fprintf(newfp, "%s%c 1-%ld\n", buf, c,
  1340. X                        active[groupnum].max);
  1341. X                gotit = TRUE;
  1342. X            } else
  1343. X                fprintf(newfp, "%s%c%s\n", buf, c, p);
  1344. X        }
  1345. X        fclose(fp);
  1346. X    }
  1347. X
  1348. X    fclose(newfp);
  1349. X    unlink(newsrc);
  1350. X#ifndef    OSK
  1351. X    link(newnewsrc, newsrc);
  1352. X    unlink(newnewsrc);
  1353. X#else    /* OSK */
  1354. X    rename(newnewsrc, newsrc);
  1355. X#endif    /* OSK */
  1356. X
  1357. Xmark_group_read_done:
  1358. X    umask (0);
  1359. X#ifdef    USE_UID
  1360. X    setuid(tass_uid);
  1361. X    setgid(tass_gid);
  1362. X#endif    /* USE_UID */
  1363. X}
  1364. __END__OF__THIS__FILE__
  1365. if test -f 'misc.c' ; then
  1366.   echo 'File misc.c already exists, overwriting it'
  1367.   del 'misc.c'
  1368. fi
  1369. echo Extracting \"'misc.c'\"
  1370. sed "s/^X//" >'misc.c' <<'__END__OF__THIS__FILE__'
  1371. X
  1372. X#include    <stdio.h>
  1373. X#include    <signal.h>
  1374. X#include    <pwd.h>
  1375. X#ifndef        OSK
  1376. X#include    <sys/types.h>
  1377. X#include    <sys/stat.h>
  1378. X#else        /* OSK */
  1379. X#include    <types.h>
  1380. X#include    <stat.h>
  1381. X#endif        /* OSK */
  1382. X#include    "tass.h"
  1383. X
  1384. Xextern char *rindex ();
  1385. X
  1386. Xchar active_file[LEN];
  1387. X#ifdef    OSK
  1388. Xchar spooldir[LEN];
  1389. X#endif    /* OSK */
  1390. Xchar homedir[LEN];
  1391. Xchar userid[LEN];
  1392. Xchar delgroups[LEN];
  1393. Xchar newsrc[LEN];
  1394. Xchar newnewsrc[LEN];
  1395. Xchar indexdir[LEN];
  1396. Xchar my_org[LEN];        /* organization */
  1397. X#ifdef    INCSTR
  1398. Xchar *incstr;
  1399. X#endif    /* INCSTR */
  1400. X
  1401. X/*
  1402. X *  Which base note (an index into base[]) does a respnum
  1403. X *  (an index into arts[]) corresponsd to?
  1404. X *
  1405. X *  In other words, base[] points to an entry in arts[] which is
  1406. X *  the head of a thread, linked with arts[].thread.  For any q: arts[q],
  1407. X *  find i such that base[i]->arts[n]->arts[o]->...->arts[q]
  1408. X */
  1409. X
  1410. Xwhich_base(n)
  1411. Xint n;
  1412. X{
  1413. X    int i, j;
  1414. X
  1415. X    for (i = 0; i < top_base; i++)
  1416. X        for (j = base[i]; j >= 0; j = arts[j].thread)
  1417. X            if (j == n)
  1418. X                return i;
  1419. X
  1420. X    fprintf(stderr, "can't find base article\n");
  1421. X    return 0;
  1422. X}
  1423. X
  1424. X
  1425. X/*
  1426. X *  Find how deep in a thread a response is.  Start counting at zero
  1427. X */
  1428. X
  1429. Xwhich_resp(n)
  1430. Xint n;
  1431. X{
  1432. X    int i, j;
  1433. X    int num = 0;
  1434. X
  1435. X    i = which_base(n);
  1436. X
  1437. X    for (j = base[i]; j != -1; j = arts[j].thread)
  1438. X        if (j == n)
  1439. X            break;
  1440. X        else
  1441. X            num++;
  1442. X
  1443. X    return num;
  1444. X}
  1445. X
  1446. X
  1447. X/*
  1448. X *  Given an index into base[], find the number of responses for
  1449. X *  that basenote
  1450. X */
  1451. X
  1452. Xnresp(n)
  1453. Xint n;
  1454. X{
  1455. X    int i;
  1456. X    int oldi = -3;
  1457. X    int sum = 0;
  1458. X
  1459. X    assert(n < top_base);
  1460. X
  1461. X    for (i = base[n]; i != -1; i = arts[i].thread) {
  1462. X        assert(i != -2);
  1463. X        assert(i != oldi);
  1464. X        oldi = i;
  1465. X        sum++;
  1466. X    }
  1467. X
  1468. X    return sum - 1;
  1469. X}
  1470. X
  1471. X
  1472. Xasfail(file, line, cond)
  1473. Xchar    *file;
  1474. Xint    line;
  1475. Xchar    *cond;
  1476. X{
  1477. X    fprintf(stderr, "tass: assertion failure: %s (%d): %s\n",
  1478. X                            file, line, cond);
  1479. X    exit(1);
  1480. X}
  1481. X
  1482. X
  1483. X/*
  1484. X *  Make regular expressions pleasant for the masses:  glob them
  1485. X */
  1486. X
  1487. Xglob_name(group, grp)
  1488. Xchar *group;
  1489. Xchar *grp;
  1490. X{
  1491. Xchar *p, *q;
  1492. X
  1493. X/*
  1494. X *  Prefix the .'s in the group name so they won't be interpreted
  1495. X *  as regular expression commands.  Change 'all' into '*'
  1496. X */
  1497. X
  1498. X    p = group;
  1499. X    q = grp;
  1500. X
  1501. X    if (strncmp(p, "all", 3) == 0 && (p[3] == '.' || p[3] == '\0')) {
  1502. X        *q++ = '.';
  1503. X        *q++ = '*';
  1504. X        p = &p[3];
  1505. X    }
  1506. X    while (*p != '\0') {
  1507. X        if (*p == '.') {
  1508. X            *q++ = '\\';
  1509. X            *q++ = '.';
  1510. X            p++;
  1511. X
  1512. X            if (strncmp(p, "all", 3) == 0 &&
  1513. X                (p[3] == '.' || p[3] == '\0')) {
  1514. X                    *q++ = '.';
  1515. X                    *q++ = '*';
  1516. X                    p = &p[3];
  1517. X                }
  1518. X        } else if (*p == '*') {
  1519. X            *q++ = '.';
  1520. X            *q++ = '*';
  1521. X            p++;
  1522. X        } else
  1523. X            *q++ = *p++;
  1524. X    }
  1525. X    *q = '\0';
  1526. X}
  1527. X
  1528. X
  1529. X/*
  1530. X * init_selfinfo
  1531. X *   Deterimines users home directory, userid, and a path
  1532. X *   for an rc file in the home directory
  1533. X */
  1534. X
  1535. Xinit_selfinfo()
  1536. X{
  1537. X    struct passwd *myentry;
  1538. X    extern struct passwd *getpwuid();
  1539. X    struct stat sb;
  1540. X    char nam[LEN];
  1541. X    char *p;
  1542. X    extern char *getenv();
  1543. X    FILE *fp;
  1544. X
  1545. X#ifndef    OSK
  1546. X    myentry = getpwuid(getuid());
  1547. X#else    /* OSK */
  1548. X    setpwent ();
  1549. X#ifdef    USE_UID
  1550. X    myentry = getpwuid(real_uid () & 0xffff);
  1551. X#else    /* USE_UID */
  1552. X    myentry = getpwuid(getuid () & 0xffff);
  1553. X#endif    /* USE_UID */
  1554. X    endpwent ();
  1555. X#endif    /* OSK */
  1556. X    strcpy(userid, myentry->pw_name);
  1557. X    strcpy(homedir, myentry->pw_dir);
  1558. X
  1559. X    sprintf(newsrc, "%s/.newsrc", homedir);
  1560. X    sprintf(newnewsrc, "%s/.newnewsrc", homedir);
  1561. X    sprintf(delgroups, "%s/.delgroups", homedir);
  1562. X    sprintf(indexdir, "%s/.tindex", homedir);
  1563. X#ifndef    OSK
  1564. X    sprintf(active_file, "%s/active", LIBDIR);
  1565. X#else    /* OSK */
  1566. X    if (!info_str ("MNEWS.LIB", active_file, LEN - 20))
  1567. X        strcpy (active_file, LIBDIR);
  1568. X    strcat (active_file, "/Active");
  1569. X    if (!info_str ("MNEWS.DIR", spooldir, LEN))
  1570. X        strcpy (spooldir, SPOOLDIR);
  1571. X#endif    /* OSK */
  1572. X#ifdef    INCSTR
  1573. X    if (!(incstr = getenv ("INCSTR")))
  1574. X        incstr = "> ";
  1575. X#endif    /* INCSTR */
  1576. X
  1577. X    if (stat(active_file, &sb) >= 0)
  1578. X        goto got_active;
  1579. X
  1580. X#ifndef    OSK
  1581. X/*
  1582. X *  I hate forgetting to define LIBDIR correctly.  Guess a
  1583. X *  couple of likely places if it's not where LIBDIR says it is.
  1584. X */
  1585. X
  1586. X    strcpy(active_file, "/usr/lib/news/active");
  1587. X    if (stat(active_file, &sb) >= 0)
  1588. X        goto got_active;
  1589. X
  1590. X    strcpy(active_file, "/usr/local/lib/news/active");
  1591. X    if (stat(active_file, &sb) >= 0)
  1592. X        goto got_active;
  1593. X
  1594. X    strcpy(active_file, "/usr/public/lib/news/active");
  1595. X    if (stat(active_file, &sb) >= 0)
  1596. X        goto got_active;
  1597. X
  1598. X/*
  1599. X *  Oh well.  Revert to what LIBDIR says it is to produce a
  1600. X *  useful error message when read_active() fails later.
  1601. X */
  1602. X
  1603. X    sprintf(active_file, "%s/active", LIBDIR);
  1604. X#endif    /* OSK */
  1605. X
  1606. Xgot_active:
  1607. X
  1608. X    *my_org = '\0';
  1609. X    p = getenv("ORGANIZATION");
  1610. X    if (p != NULL) {
  1611. X        strcpy(my_org, p);
  1612. X        goto got_org;
  1613. X    }
  1614. X
  1615. X#ifndef    OSK
  1616. X    sprintf(nam, "%s/organization", LIBDIR);
  1617. X    fp = fopen(nam, "r");
  1618. X
  1619. X    if (fp == NULL) {
  1620. X        sprintf(nam, "/usr/lib/news/organization");
  1621. X        fp = fopen(nam, "r");
  1622. X    }
  1623. X
  1624. X    if (fp == NULL) {
  1625. X        sprintf(nam, "/usr/local/lib/news/organization");
  1626. X        fp = fopen(nam, "r");
  1627. X    }
  1628. X
  1629. X    if (fp == NULL) {
  1630. X        sprintf(nam, "/usr/public/lib/news/organization");
  1631. X        fp = fopen(nam, "r");
  1632. X    }
  1633. X
  1634. X    if (fp == NULL) {
  1635. X        sprintf(nam, "/etc/organization");
  1636. X        fp = fopen(nam, "r");
  1637. X    }
  1638. X
  1639. X    if (fp != NULL) {
  1640. X        if (fgets(my_org, LEN, fp) != NULL) {
  1641. X            for (p = my_org; *p && *p != '\n'; p++) ;
  1642. X            *p = '\0';
  1643. X        }
  1644. X        fclose(fp);
  1645. X    }
  1646. X#endif    /* OSK */
  1647. X
  1648. Xgot_org:;
  1649. X
  1650. X}
  1651. X
  1652. X
  1653. Xchar *
  1654. Xmy_malloc(size)
  1655. Xunsigned size;
  1656. X{
  1657. X    char *p;
  1658. X    extern char *malloc();
  1659. X
  1660. X    p = malloc(size);
  1661. X    if (p == NULL) {
  1662. X        fprintf(stderr, "tass: out of memory\n");
  1663. X        exit(1);
  1664. X    }
  1665. X    return p;
  1666. X}
  1667. X
  1668. X
  1669. Xchar *
  1670. Xmy_realloc(p, size)
  1671. Xchar *p;
  1672. Xunsigned size;
  1673. X{
  1674. X    extern char *malloc();
  1675. X    extern char *realloc();
  1676. X
  1677. X    if (p == NULL)
  1678. X        p = malloc(size);
  1679. X    else
  1680. X        p = realloc(p, size);
  1681. X
  1682. X    if (p == NULL) {
  1683. X        fprintf(stderr, "tass: out of memory\n");
  1684. X        exit(1);
  1685. X    }
  1686. X    return p;
  1687. X}
  1688. X
  1689. X
  1690. Xchar *
  1691. Xstr_save(s)
  1692. Xchar *s;
  1693. X{
  1694. Xchar *p;
  1695. X
  1696. X    assert(s != NULL);
  1697. X    
  1698. X    p = my_malloc(strlen(s) + 1);
  1699. X    strcpy(p, s);
  1700. X
  1701. X    return(p);
  1702. X}
  1703. X
  1704. X
  1705. Xcopy_fp(a, b, prefix)
  1706. XFILE *a;
  1707. XFILE *b;
  1708. Xchar *prefix;
  1709. X{
  1710. X    char buf[8192];
  1711. X
  1712. X    while (fgets(buf, 8192, a) != NULL) {
  1713. X#ifdef    MNEWS
  1714. X        conv_charset (buf, strlen (buf));
  1715. X#endif    /* MNEWS */
  1716. X        fprintf(b, "%s%s", prefix, buf);
  1717. X    }
  1718. X}
  1719. X
  1720. X
  1721. Xchar *
  1722. Xget_val(env, def)
  1723. Xchar *env;        /* Environment variable we're looking for    */
  1724. Xchar *def;        /* Default value if no environ value found    */
  1725. X{
  1726. X    extern char *getenv();
  1727. X    char *ptr;
  1728. X
  1729. X    if ((ptr = getenv(env)) != NULL)
  1730. X        return(ptr);
  1731. X    else
  1732. X        return(def);
  1733. X}
  1734. X
  1735. X
  1736. Xinvoke_editor(nam, line)
  1737. Xchar *nam;
  1738. Xint line;
  1739. X{
  1740. X    char buf[200];
  1741. X    static int first = TRUE;
  1742. X    static char editor[200];
  1743. X    static int type = -1;
  1744. X    char *ptr;
  1745. X
  1746. X    if (first) {
  1747. X#ifndef    OSK
  1748. X        strcpy(editor, get_val("EDITOR", "/usr/bin/vi"));
  1749. X#else    /* OSK */
  1750. X        strcpy(editor, get_val("EDITOR", "me"));
  1751. X#endif    /* OSK */
  1752. X        if (ptr = rindex (editor, '/'))
  1753. X            ++ptr;
  1754. X        else
  1755. X            ptr = editor;
  1756. X        if (!strncmp (ptr, "vi", 2))
  1757. X            type = 0;
  1758. X        else if ((!strncmp (ptr, "me", 2)) || (!strncmp (ptr, "emacs")))
  1759. X            type = 1;
  1760. X        first = FALSE;
  1761. X    }
  1762. X
  1763. X    ++line;
  1764. X    switch (type) {
  1765. X        case -1:
  1766. X        default:
  1767. X            sprintf(buf, "%s %s", editor, nam);
  1768. X            break;
  1769. X        case 0:
  1770. X            sprintf (buf, "%s +%d %s", editor, line, nam);
  1771. X            break;
  1772. X        case 1:
  1773. X            sprintf (buf, "%s -g=%d %s", editor, line, nam);
  1774. X            break;
  1775. X    }
  1776. X    printf("\r%s", buf);
  1777. X    CleartoEOLN ();
  1778. X    return invoke_cmd(buf);
  1779. X}
  1780. X
  1781. X
  1782. Xinvoke_cmd(nam)
  1783. Xchar *nam;
  1784. X{
  1785. X    int ret;
  1786. X#ifdef SIGTSTP
  1787. X    void (*susp)();
  1788. X#endif
  1789. X
  1790. X    Raw(FALSE);
  1791. X#ifdef    USE_UID
  1792. X    setuid(real_uid);
  1793. X    setgid(real_gid);
  1794. X#endif    /* USE_UID */
  1795. X
  1796. X#ifndef    OSK
  1797. X#ifdef SIGTSTP
  1798. X    susp = signal(SIGTSTP, SIG_DFL);
  1799. X#endif
  1800. X
  1801. X    ret = system(nam);
  1802. X
  1803. X#ifdef SIGTSTP
  1804. X    signal(SIGTSTP, susp);
  1805. X#endif
  1806. X#else    /* OSK */
  1807. X    ret = system (nam);
  1808. X#endif    /* OSK */
  1809. X
  1810. X#ifdef    USE_UID
  1811. X    setuid(tass_uid);
  1812. X    setgid(tass_gid);
  1813. X#endif    /* USE_UID */
  1814. X    Raw(TRUE);
  1815. X
  1816. X    return ret == 0;
  1817. X}
  1818. X
  1819. X
  1820. Xshell_escape() {
  1821. X    char shell[LEN];
  1822. X    char *p;
  1823. X#ifdef SIGTSTP
  1824. X    void (*susp)();
  1825. X#endif
  1826. X
  1827. X    if (!parse_string("!", shell))
  1828. X        strcpy(shell, get_val("SHELL", "/bin/sh"));
  1829. X
  1830. X    for (p = shell; *p && (*p == ' ' || *p == '\t'); p++) ;
  1831. X
  1832. X    if (!*p)
  1833. X        strcpy(shell, get_val("SHELL", "/bin/sh"));
  1834. X    
  1835. X    Raw(FALSE);
  1836. X
  1837. X#ifdef    USE_UID
  1838. X    setuid(real_uid);
  1839. X    setgid(real_gid);
  1840. X#endif    /* USE_UID */
  1841. X
  1842. X    fputs("\r\012", stdout);
  1843. X
  1844. X#ifndef    OSK
  1845. X#ifdef SIGTSTP
  1846. X    susp = signal(SIGTSTP, SIG_DFL);
  1847. X#endif
  1848. X
  1849. X    system(p);
  1850. X
  1851. X#ifdef SIGTSTP
  1852. X    signal(SIGTSTP, susp);
  1853. X#endif
  1854. X#else    /* OSK */
  1855. X    system (p);
  1856. X#endif    /* OSK */
  1857. X
  1858. X#ifdef    USE_UID
  1859. X    setuid(tass_uid);
  1860. X    setgid(tass_gid);
  1861. X#endif    /* USE_UID */
  1862. X
  1863. X    Raw(TRUE);
  1864. X
  1865. X    continue_prompt();
  1866. X    mail_setup();
  1867. X}
  1868. X
  1869. X
  1870. X/*
  1871. X *  Find the next unread response in this group 
  1872. X */
  1873. X
  1874. Xnext_unread(n)
  1875. Xint n;
  1876. X{
  1877. X
  1878. X    while (n >= 0) {
  1879. X        if (arts[n].unread == 1)
  1880. X            return n;
  1881. X        n = next_response(n);
  1882. X    }
  1883. X
  1884. X    return -1;
  1885. X}
  1886. X
  1887. X
  1888. X/*
  1889. X *  Find the previous unread response in this thread
  1890. X */
  1891. X
  1892. Xprev_unread(n)
  1893. Xint n;
  1894. X{
  1895. X
  1896. X    while (n >= 0) {
  1897. X        if (arts[n].unread == 1)
  1898. X            return n;
  1899. X        n = prev_response(n);
  1900. X    }
  1901. X
  1902. X    return -1;
  1903. X}
  1904. X
  1905. __END__OF__THIS__FILE__
  1906. if test -f 'page.c' ; then
  1907.   echo 'File page.c already exists, overwriting it'
  1908.   del 'page.c'
  1909. fi
  1910. echo Extracting \"'page.c'\"
  1911. sed "s/^X//" >'page.c' <<'__END__OF__THIS__FILE__'
  1912. X
  1913. X#include    <stdio.h>
  1914. X#include    <signal.h>
  1915. X#ifndef    OSK
  1916. X#include    <sys/types.h>
  1917. X#include    <sys/stat.h>
  1918. X#else    /* OSK */
  1919. X#include    <types.h>
  1920. X#include    <stat.h>
  1921. X
  1922. Xextern FILE    *popen ();
  1923. X#endif    /* OSK */
  1924. X#include    "tass.h"
  1925. X
  1926. X#define        MAX_PAGES    1000
  1927. X#define        NOTE_UNAVAIL    -1
  1928. X
  1929. Xchar note_h_path[LEN];            /* Path:    */
  1930. Xchar note_h_date[LEN];            /* Date:    */
  1931. Xchar note_h_subj[LEN];            /* Subject:    */
  1932. Xchar note_h_from[LEN];            /* From:    */
  1933. Xchar note_h_reply[LEN];            /* Reply-To:    */
  1934. Xchar note_h_org[LEN];            /* Organization: */
  1935. Xchar note_h_newsgroups[LEN];        /* Newsgroups:    */
  1936. Xchar note_h_messageid[LEN];        /* Message-ID:    */
  1937. Xchar note_h_distrib[LEN];        /* Distribution: */
  1938. Xchar note_h_followup[LEN];        /* Followup-To: */
  1939. X
  1940. Xint    note_line;
  1941. Xint    note_page;        /* what page we're on */
  1942. Xlong    note_mark[MAX_PAGES];    /* ftells on beginnings of pages */
  1943. XFILE    *note_fp;        /* the body of the current article */
  1944. Xint    note_end;        /* we're done showing this article */
  1945. Xint    rotate;            /* 0=normal, 13=rot13 decode */
  1946. X
  1947. Xstruct stat note_stat;        /* so we can tell how big it is */
  1948. X
  1949. Xchar    note_full_name[100];
  1950. Xchar    note_from_addr[100];
  1951. X
  1952. X
  1953. Xint last_resp;        /* current & previous article for - command */
  1954. Xint this_resp;
  1955. X
  1956. Xint glob_respnum;
  1957. Xchar *glob_page_group;
  1958. Xextern int cur_groupnum;
  1959. X
  1960. X
  1961. X#ifdef SIGTSTP
  1962. Xvoid
  1963. Xpage_susp(i)
  1964. Xint i;
  1965. X{
  1966. X
  1967. X    Raw(FALSE);
  1968. X    putchar('\n');
  1969. X    signal(SIGTSTP, SIG_DFL);
  1970. X    kill(0, SIGTSTP);
  1971. X
  1972. X    signal(SIGTSTP, page_susp);
  1973. X    mail_setup();
  1974. X    Raw(TRUE);
  1975. X    redraw_page(glob_respnum, glob_page_group);
  1976. X}
  1977. X#endif
  1978. X
  1979. X
  1980. Xshow_page(respnum, group, group_path)
  1981. Xint respnum;
  1982. Xchar *group;
  1983. Xchar *group_path;
  1984. X{
  1985. X    char ch;
  1986. X    int n;
  1987. X    long art;
  1988. X    int sav_unread;
  1989. X
  1990. Xrestart:
  1991. X
  1992. X    glob_respnum = respnum;
  1993. X    glob_page_group = group;
  1994. X
  1995. X#ifdef SIGTSTP
  1996. X    signal(SIGTSTP, page_susp);
  1997. X#endif
  1998. X
  1999. X    if (respnum != this_resp) {       /* remember current & previous */
  2000. X        last_resp = this_resp;       /* articles for - command */
  2001. X        this_resp = respnum;
  2002. X    }
  2003. X
  2004. X    rotate = 0;            /* normal mode, not rot13 */
  2005. X    art = arts[respnum].artnum;
  2006. X    sav_unread = arts[respnum].unread;
  2007. X    arts[respnum].unread = 0;    /* mark article as read */
  2008. X    open_note(art, group_path);
  2009. X
  2010. X    if (note_page == NOTE_UNAVAIL) {
  2011. X        ClearScreen();
  2012. X        printf("[Article %ld unvailable]\r\012", art);
  2013. X        fflush(stdout);
  2014. X    } else
  2015. X        show_note_page(respnum, group);
  2016. X
  2017. X    while (1) {
  2018. X        if ((n = ReadCh()) == EOF)
  2019. X            longjmp (jmp_buffer, 1);
  2020. X        ch = (char) n;
  2021. X
  2022. X        if ((ch >= '0' && ch <= '9') || (ch == '=')) {
  2023. X
  2024. X            if (ch != '=')
  2025. X                n = prompt_response(ch, respnum);
  2026. X            else {
  2027. X                n = choose_resp (which_base (respnum), 0);
  2028. X                info_message ("Base note selected");
  2029. X            }
  2030. X
  2031. X            if (n != -1) {
  2032. X                arts[respnum].unread = sav_unread;
  2033. X                respnum = n;
  2034. X                goto restart;
  2035. X            }
  2036. X
  2037. X        } else switch (ch) {
  2038. X            case '|':    /* pipe article into command */
  2039. X                pipe_article();
  2040. X                redraw_page(respnum, group);
  2041. X                break;
  2042. X
  2043. X            case 'I':    /* toggle inverse video */
  2044. X                inverse_okay = !inverse_okay;
  2045. X                if (inverse_okay)
  2046. X                    info_message("Inverse video enabled");
  2047. X                else
  2048. X                    info_message("Inverse video disabled");
  2049. X                goto pager_ctrlr;
  2050. X                break;
  2051. X
  2052. X            case 's':
  2053. X                save_art_to_file();
  2054. X                break;
  2055. X
  2056. X            case 'S':
  2057. X                save_thread_to_file(respnum, group_path);
  2058. X                break;
  2059. X
  2060. X            case ctrl('X'):
  2061. X            case '%':    /* toggle rot-13 mode */
  2062. X                if (rotate)
  2063. X                    rotate = 0;
  2064. X                else
  2065. X                    rotate = 13;
  2066. X                goto pager_ctrlr;
  2067. X                break;
  2068. X
  2069. X            case 'P':    /* previous unread article */
  2070. X                n = prev_unread(prev_response(respnum));
  2071. X                if (n == -1)
  2072. X                    info_message("No previous unread article");
  2073. X                else {
  2074. X                    note_cleanup();
  2075. X                    respnum = n;
  2076. X                    goto restart;
  2077. X                }
  2078. X                break;
  2079. X
  2080. X            case 'F':    /* post a followup to this article */
  2081. X            case 'W':    /* ... compatible to notes */
  2082. X                if (post_response(group, TRUE)) {
  2083. X                    update_newsrc(group,
  2084. X                        my_group[cur_groupnum]);
  2085. X                    n = which_base(respnum);
  2086. X                    note_cleanup();
  2087. X                    index_group(group, group_path);
  2088. X                    read_newsrc_line(group);
  2089. X                    respnum = choose_resp(n, nresp(n));
  2090. X                    goto restart;
  2091. X                } else
  2092. X                    redraw_page(respnum, group);
  2093. X                break;
  2094. X
  2095. X            case 'f':    /* post a followup to this article */
  2096. X            case 'w':    /* ... compatible to notes */
  2097. X                if (post_response(group, FALSE)) {
  2098. X                    update_newsrc(group,
  2099. X                        my_group[cur_groupnum]);
  2100. X                    n = which_base(respnum);
  2101. X                    note_cleanup();
  2102. X                    index_group(group, group_path);
  2103. X                    read_newsrc_line(group);
  2104. X                    respnum = choose_resp(n, nresp(n));
  2105. X                    goto restart;
  2106. X                } else
  2107. X                    redraw_page(respnum, group);
  2108. X                break;
  2109. X
  2110. X            case 'z':    /* mark article as unread (to return) */
  2111. X                arts[respnum].unread = 2;
  2112. X                info_message("Article marked as unread");
  2113. X                break;
  2114. X
  2115. X            case 'K':    /* mark rest of thread as read */
  2116. X            case 'J':    /* ... compatible to notes */
  2117. X                for (n = respnum; n >= 0; n = arts[n].thread)
  2118. X                    arts[n].unread = 0;
  2119. X                n = next_unread(next_response(respnum));
  2120. X                if (n == -1)
  2121. X                    goto return_to_index;
  2122. X                else {
  2123. X                    note_cleanup();
  2124. X                    respnum = n;
  2125. X                    goto restart;
  2126. X                }
  2127. X                break;
  2128. X
  2129. X            case 'i':    /* return to index page */
  2130. X            case ctrl('B'):    /* possibly cursor doen */
  2131. Xreturn_to_index:
  2132. X                note_cleanup();
  2133. X                return( which_base(respnum) );
  2134. X
  2135. X            case 't':    /* return to group selection page */
  2136. X                note_cleanup();
  2137. X                return -1;
  2138. X
  2139. X            case ctrl('R'):      /* redraw beginning of article */
  2140. Xpager_ctrlr:
  2141. X                if (note_page == NOTE_UNAVAIL) {
  2142. X                    ClearScreen();
  2143. X                    printf("[Article %ld unvailable]\r\012",
  2144. X                            arts[respnum].artnum);
  2145. X                    fflush(stdout);
  2146. X                } else {
  2147. X                    note_page = 0;
  2148. X                    note_end = FALSE;
  2149. X                    fseek(note_fp, note_mark[0], 0);
  2150. X                    show_note_page(respnum, group);
  2151. X                }
  2152. X                break;
  2153. X
  2154. X            case '!':
  2155. X                shell_escape();
  2156. X                redraw_page(respnum, group);
  2157. X                break;
  2158. X
  2159. X            case '\b':
  2160. X            case 'b':    /* back a page */
  2161. X            case ctrl('P'):    /* possibly cursor doen */
  2162. X                if (note_page == NOTE_UNAVAIL
  2163. X                ||  note_page <= 1) {
  2164. X                    note_cleanup();
  2165. X                    n = prev_response(respnum);
  2166. X                    if (n == -1)
  2167. X                        return( which_resp(respnum) );
  2168. X
  2169. X                    respnum = n;
  2170. X                    goto restart;
  2171. X
  2172. X                } else {
  2173. X                    note_page -= 2;
  2174. X                    note_end = FALSE;
  2175. X                    fseek(note_fp, note_mark[note_page], 0);
  2176. X                    show_note_page(respnum, group);
  2177. X                }
  2178. X                break;
  2179. X
  2180. X            case 'm':    /* mail article to somebody */
  2181. X                mail_to_someone();
  2182. X                redraw_page(respnum, group);
  2183. X                break;
  2184. X
  2185. X            case 'r':    /* reply to author through mail */
  2186. X                mail_to_author(FALSE);
  2187. X                redraw_page(respnum, group);
  2188. X                break;
  2189. X
  2190. X            case 'R':    /* reply to author, copy text */
  2191. X                mail_to_author(TRUE);
  2192. X                redraw_page(respnum, group);
  2193. X                break;
  2194. X
  2195. X            case '-':    /* show last viewed article */
  2196. X                if (last_resp < 0) {
  2197. X                    info_message("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
  2205. X            case 'p':    /* previous article */
  2206. X                note_cleanup();
  2207. X                n = prev_response(respnum);
  2208. X                if (n == -1)
  2209. X                    return( which_resp(respnum) );
  2210. X
  2211. X                respnum = n;
  2212. X                goto restart;
  2213. X
  2214. X            case 'n':    /* skip to next article */
  2215. X                note_cleanup();
  2216. X                n = next_response(respnum);
  2217. X                if (n == -1)
  2218. X                    return( which_base(respnum) );
  2219. X
  2220. X                respnum = n;
  2221. X                goto restart;
  2222. X
  2223. X            case 'k':
  2224. X            case 'j':    /* ... compatible to notes */
  2225. X                if (note_page == NOTE_UNAVAIL) {
  2226. X                    n = next_unread(next_response(respnum));
  2227. X                    if (n == -1)
  2228. X                        return( which_base(respnum) );
  2229. X
  2230. X                    respnum = n;
  2231. X                    goto restart;
  2232. X
  2233. X                } else {
  2234. X                    note_cleanup();
  2235. X                    n = next_unread(next_response(respnum));
  2236. X                    if (n == -1)
  2237. X                        return( which_base(respnum) );
  2238. X
  2239. X                    respnum = n;
  2240. X                    goto restart;
  2241. X                }
  2242. X                break;
  2243. X
  2244. X            case ' ':     /* next page or response */
  2245. X            case ctrl('N'):    /* possibly cursor doen */
  2246. X                if (note_page == NOTE_UNAVAIL) {
  2247. X                    n = next_response(respnum);
  2248. X                    if (n == -1)
  2249. X                        return( which_base(respnum) );
  2250. X
  2251. X                    respnum = n;
  2252. X                    goto restart;
  2253. X
  2254. X                } else if (note_end) {
  2255. X                    note_cleanup();
  2256. X                    n = next_response(respnum);
  2257. X                    if (n == -1)
  2258. X                        return( which_base(respnum) );
  2259. X
  2260. X                    respnum = n;
  2261. X                    goto restart;
  2262. X                } else
  2263. X                    show_note_page(respnum, group);
  2264. X                break;
  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 'N':    /* next unread article */
  2288. X                n = next_unread(next_response(respnum));
  2289. X                if (n == -1)
  2290. X                    info_message("No next unread article");
  2291. X                else {
  2292. X                    note_cleanup();
  2293. X                    respnum = n;
  2294. X                    goto restart;
  2295. X                }
  2296. X                break;
  2297. X
  2298. X            case 'C':    /* Cancel */
  2299. X            case 'd':    /* delete */
  2300. X            case 'Z':    /* zap (director option in notes) */
  2301. X                note_cleanup();
  2302. X                cancel_article ();
  2303. X                note_page = NOTE_UNAVAIL;
  2304. X                /* Fall through ... */
  2305. X
  2306. X#ifndef    OSK
  2307. X            case '\r':
  2308. X#else    /* OSK */
  2309. X            case '\l':
  2310. X#endif    /* OSK */
  2311. X            case '\n':    /* go to start of next thread */
  2312. X            case ctrl('F'):    /* possibly cursor down */
  2313. X                note_cleanup();
  2314. X                n = next_basenote(respnum);
  2315. X                if (n == -1)
  2316. X                    return( which_base(respnum) );
  2317. X
  2318. X                respnum = n;
  2319. X                goto restart;
  2320. X
  2321. X#ifndef    OSK
  2322. X            case 'q':    /* quit */
  2323. X                return -2;
  2324. X#endif    /* OSK */
  2325. X
  2326. X            case 'H':    /* show article headers */
  2327. X                if (note_page == NOTE_UNAVAIL) {
  2328. X                    n = next_response(respnum);
  2329. X                    if (n == -1)
  2330. X                        return( which_base(respnum) );
  2331. X
  2332. X                    respnum = n;
  2333. X                    goto restart;
  2334. X                } else {
  2335. X                    note_page = 0;
  2336. X                    note_end = FALSE;
  2337. X                    fseek(note_fp, 0L, 0);
  2338. X                    show_note_page(respnum, group);
  2339. X                }
  2340. X                break;
  2341. X
  2342. X
  2343. X            case 'h':
  2344. X                tass_page_help();
  2345. X                redraw_page(respnum, group);
  2346. X                break;
  2347. X
  2348. X            default:
  2349. X                info_message("Bad command.  Type 'h' for help.");
  2350. X        }
  2351. X    }
  2352. X}
  2353. X
  2354. X
  2355. Xnote_cleanup() {
  2356. X
  2357. X    if (note_page != NOTE_UNAVAIL)
  2358. X        fclose(note_fp);
  2359. X}
  2360. X
  2361. X
  2362. Xredraw_page(respnum, group)
  2363. Xint respnum;
  2364. Xchar *group;
  2365. X{
  2366. X
  2367. X    if (note_page == NOTE_UNAVAIL) {
  2368. X        ClearScreen();
  2369. X        printf("[Article %ld unvailable]\r\012", arts[respnum].artnum);
  2370. X        fflush(stdout);
  2371. X    } else if (note_page > 0) {
  2372. X        note_page--;
  2373. X        fseek(note_fp, note_mark[note_page], 0);
  2374. X        show_note_page(respnum, group);
  2375. X    }
  2376. X}
  2377. X
  2378. X
  2379. Xshow_note_page(respnum, group)
  2380. Xint respnum;
  2381. Xchar *group;
  2382. X{
  2383. X    char buf[LEN];
  2384. X    char buf2[LEN+50];
  2385. X    int percent;
  2386. X    char *p, *q;
  2387. X    int i, j;
  2388. X    int ctrl_L;        /* form feed character detected */
  2389. X
  2390. X    ClearScreen();
  2391. X
  2392. X    note_line = 1;
  2393. X
  2394. X    if (note_page == 0)
  2395. X        show_first_header(respnum, group);
  2396. X    else
  2397. X        show_cont_header(respnum);
  2398. X
  2399. X    ctrl_L = FALSE;
  2400. X    while (note_line < LINES) {
  2401. X        if (fgets(buf, LEN, note_fp) == NULL) {
  2402. X            note_end = TRUE;
  2403. X            break;
  2404. X        }
  2405. X
  2406. X        buf[LEN-1] = '\0';
  2407. X#ifdef    MNEWS
  2408. X        conv_charset (buf, strlen (buf));
  2409. X#endif    /* MNEWS */
  2410. X        if (rotate)
  2411. X            for (p = buf, q = buf2;
  2412. X                    *p && *p != '\n' && q<&buf2[LEN]; p++) {
  2413. X                if (*p == '\b' && q > buf2) {
  2414. X                    q--;
  2415. X                } else if (*p == 12) {        /* ^L */
  2416. X                    *q++ = '^';
  2417. X                    *q++ = 'L';
  2418. X                    ctrl_L = TRUE;
  2419. X                } else if (*p == '\t') {
  2420. X                    i = q - buf2;
  2421. X                    j = (i|7) + 1;
  2422. X
  2423. X                    while (i++ < j)
  2424. X                        *q++ = ' ';
  2425. X                } else if (*p & 0x7F < 32) {
  2426. X                    *q++ = '^';
  2427. X                    *q++ = (*p & 0x7F) + '@';
  2428. X                } else if (*p >= 'A' && *p <= 'Z')
  2429. X                    *q++ = 'A' + (*p - 'A' + rotate) % 26;
  2430. X                else if (*p >= 'a' && *p <= 'z')
  2431. X                    *q++ = 'a' + (*p - 'a' + rotate) % 26;
  2432. X                else
  2433. X                    *q++ = *p;
  2434. X            }
  2435. X        else
  2436. X            for (p = buf, q = buf2;
  2437. X                    *p && *p != '\n' && q<&buf2[LEN]; p++) {
  2438. X                if (*p == '\b' && q > buf2) {
  2439. X                    q--;
  2440. X                } else if (*p == 12) {        /* ^L */
  2441. X                    *q++ = '^';
  2442. X                    *q++ = 'L';
  2443. X                    ctrl_L = TRUE;
  2444. X                } else if (*p == '\t') {
  2445. X                    i = q - buf2;
  2446. X                    j = (i|7) + 1;
  2447. X
  2448. X                    while (i++ < j)
  2449. X                        *q++ = ' ';
  2450. X                } else if ((*p & 0x7F) < 32) {
  2451. X                    *q++ = '^';
  2452. X                    *q++ = (*p & 0x7F) + '@';
  2453. X                } else
  2454. X                    *q++ = *p;
  2455. X            }
  2456. X
  2457. X        *q = '\0';
  2458. X
  2459. X        printf("%s\r\012", buf2);
  2460. X
  2461. X#if 1
  2462. X        note_line += (strlen(buf2) / COLS) + 1;
  2463. X#else
  2464. X        if (*buf2)
  2465. X            note_line += (strlen(buf2) + COLS) / (COLS+1);
  2466. X        else
  2467. X            note_line++;
  2468. X#endif
  2469. X        if (ctrl_L)
  2470. X            break;
  2471. X    }
  2472. X
  2473. X    note_mark[++note_page] = ftell(note_fp);
  2474. X
  2475. X    MoveCursor(LINES, MORE_POS);
  2476. X/*    StartInverse();    */
  2477. X    if (note_end) {
  2478. X        if (arts[respnum].thread != -1)
  2479. X            printf("-- next response --");
  2480. X        else
  2481. X            printf("-- last response --");
  2482. X    } else {
  2483. X        if (note_stat.st_size > 0) {
  2484. X            percent = note_mark[note_page] * 100 / note_stat.st_size;
  2485. X            printf("--More--(%d%%)", percent);
  2486. X        } else
  2487. X            printf("--More--");
  2488. X    }
  2489. X/*    EndInverse();    */
  2490. X
  2491. X    fflush(stdout);
  2492. X}
  2493. X
  2494. X
  2495. Xshow_first_header(respnum, group)
  2496. Xint respnum;
  2497. Xchar *group;
  2498. X{
  2499. X    int whichresp;
  2500. X    int x_resp;
  2501. X    char buf[200];
  2502. X    char tmp[200];
  2503. X    int pos, i;
  2504. X    int n;
  2505. X
  2506. X    whichresp = which_resp( respnum );
  2507. X    x_resp = nresp( which_base(respnum) );
  2508. X
  2509. X    ClearScreen();
  2510. X
  2511. X    strcpy(buf, note_h_date);
  2512. X    pos = (COLS - strlen(group)) / 2;
  2513. X    for (i = strlen(buf); i < pos; i++)
  2514. X        buf[i] = ' ';
  2515. X    buf[i] = '\0';
  2516. X
  2517. X    strcat(buf, group);
  2518. X
  2519. X    for (i = strlen(buf); i < RIGHT_POS; i++)
  2520. X        buf[i] = ' ';
  2521. X    buf[i] = '\0';
  2522. X
  2523. X    printf("%sNote %3d of %3d\r\012", buf, which_base(respnum) + 1, top_base);
  2524. X
  2525. X    sprintf(buf, "Article %ld  ", arts[respnum].artnum);
  2526. X    n = strlen(buf);
  2527. X    fputs(buf, stdout);
  2528. X
  2529. X    pos = (COLS - strlen( note_h_subj )) / 2 - 2;
  2530. X
  2531. X    if (pos > n)
  2532. X        MoveCursor(1, pos);
  2533. X    else
  2534. X        MoveCursor(1, n);
  2535. X
  2536. X    StartInverse();
  2537. X    strcpy(buf, note_h_subj);
  2538. X    buf[RIGHT_POS - 2 - n] = '\0';
  2539. X    fputs(buf, stdout);
  2540. X    EndInverse();
  2541. X
  2542. X    MoveCursor(1, RIGHT_POS);
  2543. X    if (whichresp)
  2544. X        printf("Resp %3d of %3d\r\012", whichresp, x_resp);
  2545. X    else {
  2546. X        if (x_resp == 0)
  2547. X            printf("No responses\r\012");
  2548. X        else if (x_resp == 1)
  2549. X            printf("1 Response\r\012");
  2550. X        else
  2551. X            printf("%d Responses\r\012", x_resp);
  2552. X    }
  2553. X
  2554. X    if (*note_h_org)
  2555. X        sprintf(tmp, "%s at %s", note_full_name, note_h_org);
  2556. X    else
  2557. X        strcpy(tmp, note_full_name);
  2558. X
  2559. X    tmp[79] = '\0';
  2560. X
  2561. X    sprintf(buf, "%s  ", note_from_addr);
  2562. X
  2563. X    pos = COLS - 1 - strlen(tmp);
  2564. X    if (strlen(buf) + strlen(tmp) >= COLS - 1) {
  2565. X        strncat(buf, tmp, COLS - 1 - strlen(buf));
  2566. X        buf[COLS - 1] = '\0';
  2567. X    } else {
  2568. X        for (i = strlen(buf); i < pos; i++)
  2569. X            buf[i] = ' ';
  2570. X        buf[i] = '\0';
  2571. X        strcat(buf, tmp);
  2572. X    }
  2573. X    printf("%s\r\012\r\012", buf);
  2574. X
  2575. X    note_line += 4;
  2576. X}
  2577. X
  2578. X
  2579. Xshow_cont_header(respnum)
  2580. Xint respnum;
  2581. X{
  2582. Xint whichresp;
  2583. Xint whichbase;
  2584. Xchar buf[LEN+60];
  2585. X
  2586. X    whichresp = which_resp(respnum);
  2587. X    whichbase = which_base(respnum);
  2588. X
  2589. X    assert (whichbase < top_base);
  2590. X
  2591. X    if (whichresp)
  2592. X        sprintf(buf, "Note %d of %d, Resp %d (page %d):  %s",
  2593. X            whichbase + 1,
  2594. X            top_base,
  2595. X            whichresp,
  2596. X            note_page + 1,
  2597. X            note_h_subj);
  2598. X    else
  2599. X        sprintf(buf, "Note %d of %d (page %d):  %s",
  2600. X            whichbase + 1,
  2601. X            top_base,
  2602. X            note_page + 1,
  2603. X            note_h_subj);
  2604. X
  2605. X    buf[COLS] = '\0';
  2606. X    printf("%s\r\012\r\012", buf);
  2607. X
  2608. X    note_line += 2;
  2609. X}
  2610. X
  2611. Xvoid
  2612. Xopen_note(art, group_path)
  2613. Xlong art;
  2614. Xchar *group_path;
  2615. X{
  2616. X    char buf[1025];
  2617. X
  2618. X    note_page = 0;
  2619. X
  2620. X#ifndef    OSK
  2621. X    sprintf(buf, "/usr/spool/news/%s/%ld", group_path, art);
  2622. X#else    /* OSK */
  2623. X    sprintf(buf, "%s/%s/%ld", spooldir, group_path, art);
  2624. X#endif    /* OSK */
  2625. X
  2626. X    if (stat(buf, ¬e_stat) < 0)
  2627. X        note_stat.st_size = 0;
  2628. X
  2629. X    note_fp = fopen(buf, "r");
  2630. X
  2631. X#ifdef    MNEWS
  2632. X    if (note_fp)
  2633. X        if (fgets (buf, 256, note_fp)) {
  2634. X            rewind (note_fp);
  2635. X            if (!strncmp (buf, "%(#)$ ", 6)) {
  2636. X                char    sav[200];
  2637. X
  2638. X                buf[strlen (buf) - 1] = '\0';
  2639. X                strcpy (sav, buf + 6);
  2640. X                sprintf (buf, "%s/%s", spooldir, sav);
  2641. X                fclose (note_fp);
  2642. X                if (stat (buf, ¬e_stat) < 0)
  2643. X                    note_stat.st_size = 0;
  2644. X                note_fp = fopen (buf, "r");
  2645. X            }
  2646. X        }
  2647. X#endif    /* MNEWS */
  2648. X
  2649. X    if (note_fp == NULL) {
  2650. X        fprintf(stderr, "can't open %s: ", buf);
  2651. X        perror("");
  2652. X        note_page = NOTE_UNAVAIL;
  2653. X        return;
  2654. X    }
  2655. X
  2656. X    note_h_from[0] = '\0';
  2657. X    note_h_reply[0] = '\0';
  2658. X    note_h_path[0] = '\0';
  2659. X    note_h_subj[0] = '\0';
  2660. X    note_h_org[0] = '\0';
  2661. X    note_h_date[0] = '\0';
  2662. X    note_h_newsgroups[0] = '\0';
  2663. X    note_h_messageid[0] = '\0';
  2664. X    note_h_distrib[0] = '\0';
  2665. X    note_h_followup[0] = '\0';
  2666. X
  2667. X    while (fgets(buf, 1024, note_fp) != NULL) {
  2668. X        buf[1024] = '\0';
  2669. X        buf[strlen(buf)-1] = '\0';
  2670. X#ifdef    MNEWS
  2671. X        conv_charset (buf, strlen (buf));
  2672. X#endif    /* MNEWS */
  2673. X
  2674. X        if (*buf == '\0')
  2675. X            break;
  2676. X
  2677. X        if (strncmp(buf, "From: ", 6) == 0) {
  2678. X            strncpy(note_h_from, &buf[6], LEN);
  2679. X            note_h_from[LEN-1] = '\0';
  2680. X        } else if (strncmp(buf, "Reply-To: ", 10) == 0) {
  2681. X            strncpy(note_h_reply, &buf[10], LEN);
  2682. X            note_h_reply[LEN-1] = '\0';
  2683. X        } else if (strncmp(buf, "Path: ", 6) == 0) {
  2684. X            strncpy(note_h_path, &buf[6], LEN);
  2685. X            note_h_path[LEN-1] = '\0';
  2686. X        } else if (strncmp(buf, "Subject: ", 9) == 0) {
  2687. X            strncpy(note_h_subj, &buf[9], LEN);
  2688. X            note_h_subj[LEN-1] = '\0';
  2689. X        } else if (strncmp(buf, "Organization: ", 14) == 0) {
  2690. X            strncpy(note_h_org, &buf[14], LEN);
  2691. X            note_h_org[LEN-1] = '\0';
  2692. X        } else if (strncmp(buf, "Date: ", 6) == 0) {
  2693. X            strncpy(note_h_date, &buf[6], LEN);
  2694. X            note_h_date[LEN-1] = '\0';
  2695. X        } else if (strncmp(buf, "Newsgroups: ", 12) == 0) {
  2696. X            strncpy(note_h_newsgroups, &buf[12], LEN);
  2697. X            note_h_newsgroups[LEN-1] = '\0';
  2698. X        } else if (strncmp(buf, "Message-ID: ", 12) == 0) {
  2699. X            strncpy(note_h_messageid, &buf[12], LEN);
  2700. X            note_h_messageid[LEN-1] = '\0';
  2701. X        } else if (strncmp(buf, "Distribution: ", 14) == 0) {
  2702. X            strncpy(note_h_distrib, &buf[14], LEN);
  2703. X            note_h_distrib[LEN-1] = '\0';
  2704. X        } else if (strncmp(buf, "Followup-To: ", 13) == 0) {
  2705. X            strncpy(note_h_followup, &buf[13], LEN);
  2706. X            note_h_followup[LEN-1] = '\0';
  2707. X        }
  2708. X    }
  2709. X
  2710. X    note_page = 0;
  2711. X    note_mark[0] = ftell(note_fp);
  2712. X
  2713. X    parse_from(note_h_from, note_from_addr, note_full_name);
  2714. X    note_end = FALSE;
  2715. X
  2716. X    return;
  2717. X}
  2718. X
  2719. X
  2720. Xprompt_response(ch, respnum)
  2721. Xint respnum;
  2722. X{
  2723. X    int num;
  2724. X
  2725. X    clear_message();
  2726. X
  2727. X    if ((num = parse_num(ch, "Read response> ")) == -1) {
  2728. X        clear_message();
  2729. X        return(-1);
  2730. X    }
  2731. X
  2732. X    return choose_resp( which_base(respnum), num );
  2733. X}
  2734. X
  2735. X
  2736. X/*
  2737. X *  return response number n from thread i
  2738. X */
  2739. X
  2740. Xchoose_resp(i, n)
  2741. Xint i;
  2742. Xint n;
  2743. X{
  2744. X    int j;
  2745. X
  2746. X    j = base[i];
  2747. X
  2748. X    while (n-- && arts[j].thread >= 0)
  2749. X        j = arts[j].thread;
  2750. X
  2751. X    return j;
  2752. X}
  2753. X
  2754. X
  2755. X/*
  2756. X *  Parse various From: lines into the component mail addresses and
  2757. X *  real names
  2758. X */
  2759. X
  2760. Xparse_from(str, addr, name)
  2761. Xchar *str;
  2762. Xchar *addr;
  2763. Xchar *name;
  2764. X{
  2765. X    while (*str && *str != ' ')
  2766. X        *addr++ = *str++;
  2767. X    *addr = '\0';
  2768. X    if (*str++ == ' ') {
  2769. X        if (*str++ == '(') {
  2770. X            if (*str == '"')
  2771. X                str++;  /* Kill "quotes around names"         */
  2772. X                    /* But don't touch quotes inside the  */
  2773. X                    /* Name (that's what that nonsense    */
  2774. X                    /* below is for                  */
  2775. X            while (*str && *str != ')' && !(*str=='"'&&str[1]==')'))
  2776. X                *name++ = *str++;
  2777. X        }
  2778. X    }
  2779. X    *name = '\0';
  2780. X}
  2781. X
  2782. X
  2783. X/*
  2784. X *  Find the previous response.  Go to the last response in the previous
  2785. X *  thread if we go past the beginning of this thread.
  2786. X */
  2787. X
  2788. Xprev_response(n)
  2789. Xint n;
  2790. X{
  2791. X    int resp;
  2792. X    int i;
  2793. X
  2794. X    resp = which_resp(n);
  2795. X
  2796. X    if (resp > 0)
  2797. X        return choose_resp( which_base(n), resp-1 );
  2798. X
  2799. X    i = which_base(n) - 1;
  2800. X
  2801. X    if (i < 0)
  2802. X        return -1;
  2803. X
  2804. X    return choose_resp( i, nresp(i) );
  2805. X}
  2806. X
  2807. X
  2808. X/*
  2809. X *  Find the next response.  Go to the next basenote if there
  2810. X *  are no more responses in this thread
  2811. X */
  2812. X
  2813. Xnext_response(n)
  2814. Xint n;
  2815. X{
  2816. X    int i;
  2817. X
  2818. X    if (arts[n].thread >= 0)
  2819. X        return arts[n].thread;
  2820. X
  2821. X    i = which_base(n) + 1;
  2822. X
  2823. X    if (i >= top_base)
  2824. X        return -1;
  2825. X
  2826. X    return base[i];
  2827. X}
  2828. X
  2829. X
  2830. X/*
  2831. X *  Given a respnum (index into arts[]), find the respnum of the
  2832. X *  next basenote
  2833. X */
  2834. X
  2835. Xnext_basenote(n)
  2836. Xint n;
  2837. X{
  2838. X    int i;
  2839. X
  2840. X    i = which_base(n) + 1;
  2841. X    if (i >= top_base)
  2842. X        return -1;
  2843. X
  2844. X    return base[i];
  2845. X}
  2846. X
  2847. Xvoid
  2848. Xtass_page_help() {
  2849. X    char ch;
  2850. X
  2851. Xpage_help_start:
  2852. X
  2853. X    ClearScreen();
  2854. X    center_line(0, TASS_HEADER);
  2855. X    center_line(1, "Article Pager Commands (page 1 of 2)");
  2856. X
  2857. X    MoveCursor(3, 0);
  2858. X
  2859. X    printf("0, =     Read the base article in this thread\r\012");
  2860. X    printf("4        Read response 4 in this thread\r\012");
  2861. X    printf("<CR>     Skip to next base article\r\012");
  2862. X    printf("<TAB>    Advance to next page or unread article\r\012");
  2863. X    printf("b        Back a page\r\012");
  2864. X    printf("f, w     Post a followup\r\012");
  2865. X    printf("F, W     Post a followup, copy text)\r\012");
  2866. X    printf("H        Show article headers\r\012");
  2867. X    printf("i        Return to index page\r\012");
  2868. X    printf("k, j      Mark article as read & advance to next unread\r\012");
  2869. X    printf("K, J      Mark rest of thread as read && advance to next unread\r\012");
  2870. X    printf("m        Mail this article to someone\r\012");
  2871. X    printf("n        Skip to the next article)\r\012");
  2872. X    printf("N        Skip to the next unread article\r\012");
  2873. X    printf("p        Go to the previous article\r\012");
  2874. X    printf("P        Go to the previous unread article\r\012");
  2875. X
  2876. X    center_line(LINES, "-- hit space for more commands --");
  2877. X    ch = ReadCh();
  2878. X    if (ch != ' ')
  2879. X        return;
  2880. X
  2881. X    ClearScreen();
  2882. X    center_line(0, TASS_HEADER);
  2883. X    center_line(1, "Article Pager Commands (page 2 of 2)");
  2884. X
  2885. X    MoveCursor(3, 0);
  2886. X
  2887. X    printf("q        Quit\r\012");
  2888. X    printf("r        Reply through mail to author\r\012");
  2889. X    printf("R        Reply through mail to author, copy text\r\012");
  2890. X    printf("s        Save article to file\r\012");
  2891. X    printf("S        Save thread to file\r\012");
  2892. X    printf("t        Return to group selection index\r\012");
  2893. X    printf("z        Mark article as unread\r\012");
  2894. X    printf("d, C, Z  delete article (if it's yours)\r\012");
  2895. X    printf("^R       Redisplay first page of article\r\012");
  2896. X    printf("%%, ^X    Toggle rot-13 decoding for this article\r\012");
  2897. X    printf("-        Show last message\r\012");
  2898. X    printf("|        Pipe article into command\r\012");
  2899. X
  2900. X    center_line(LINES, "-- hit any key --");
  2901. X    ch = ReadCh();
  2902. X
  2903. X    if (ch == 'b')
  2904. X        goto page_help_start;
  2905. X}
  2906. X
  2907. X
  2908. X
  2909. X/*
  2910. X *  Read a file grabbing the address given for To: and
  2911. X *  sticking it in mail_to
  2912. X */
  2913. Xvoid
  2914. Xfind_new_to(nam, mail_to)
  2915. Xchar *nam;
  2916. Xchar *mail_to;
  2917. X{
  2918. X    FILE *fp;
  2919. X    char buf[LEN];
  2920. X    char buf2[LEN];
  2921. X    char dummy[LEN];
  2922. X    char *ptr;
  2923. X
  2924. X    fp = fopen(nam, "r");
  2925. X    if (fp != NULL) {
  2926. X
  2927. X        while (fgets(buf, 1024, fp) != NULL) {
  2928. X            if (*buf == '\n')
  2929. X                break;
  2930. X            if (strncmp(buf, "To: ", 4) == 0) {
  2931. X                buf[strlen(buf)-1] = '\0';
  2932. X                strncpy(buf2, &buf[4], LEN);
  2933. X                buf2[LEN-1] = '\0';
  2934. X                parse_from(buf2, mail_to, dummy);
  2935. X                break;
  2936. X            }
  2937. X        }
  2938. X
  2939. X        fclose(fp);
  2940. X    }
  2941. X    for (ptr = mail_to; *ptr; ++ptr)
  2942. X        if (*ptr == ',')
  2943. X            *ptr++ = ' ';
  2944. X        else if (*ptr == '(') {
  2945. X            int    nest = 0;
  2946. X            while (*ptr) {
  2947. X                if (*ptr == '(')
  2948. X                    ++nest;
  2949. X                else if (*ptr == ')')
  2950. X                    --nest;
  2951. X                *ptr++ = ' ';
  2952. X                if (nest <= 0)
  2953. X                    break;
  2954. X            }
  2955. X        } else
  2956. X            ++ptr;
  2957. X}
  2958. X
  2959. Xvoid
  2960. Xcancel_article () {
  2961. X    char    buf[LEN+40];
  2962. X    FILE    *pp;
  2963. X    int    err;
  2964. X
  2965. X    if (!note_h_messageid[0]) {
  2966. X        printf ("\rLost message-id!");
  2967. X        CleartoEOLN ();
  2968. X        return;
  2969. X    }
  2970. X    printf("\rCancel %s...  ", note_h_messageid);
  2971. X    CleartoEOLN ();
  2972. X#ifndef    MNEWS
  2973. X    Insert your cancel-cmd here!
  2974. X#else    /* MNEWS */
  2975. X    sprintf(buf, "inews '-c=cancel:%s'", note_h_messageid);
  2976. X#endif    /* MNEWS */
  2977. X    if (pp = popen (buf, "w")) {
  2978. X        fprintf (pp, "\nArticle canceled from tass\n");
  2979. X        err = pclose (pp);
  2980. X    } else
  2981. X        err = 1;
  2982. X    if (! err)
  2983. X        printf("article canceled ");
  2984. X    else
  2985. X        printf("article not canceled ");
  2986. X    continue_prompt();
  2987. X}
  2988. X
  2989. Xmail_to_someone() {
  2990. X    char nam[100];
  2991. X    FILE *fp;
  2992. X    char ch;
  2993. X    char buf[200];
  2994. X    char mail_to[LEN+1];
  2995. X    char subj[LEN+1];
  2996. X    int line;
  2997. X
  2998. X#ifdef    USE_UID
  2999. X    setuid(real_uid);
  3000. X    setgid(real_gid);
  3001. X#endif    /* USE_UID */
  3002. X
  3003. X    if (!parse_string("Mail article to: ", mail_to))
  3004. X        return(FALSE);
  3005. X    if (mail_to[0] == '\0')
  3006. X        return(FALSE);
  3007. X
  3008. X    sprintf(nam, "%s/.letter", homedir);
  3009. X    umask (omask);
  3010. X    if ((fp = fopen(nam, "w")) == NULL) {
  3011. X        umask (0);
  3012. X        fprintf(stderr, "can't open %s: ", nam);
  3013. X        perror("");
  3014. X        return(FALSE);
  3015. X    }
  3016. X#ifndef    OSK
  3017. X    chmod(nam, 0600);
  3018. X#else    /* OSK */
  3019. X    chmod(nam, 013);
  3020. X#endif    /* OSK */
  3021. X
  3022. X    fprintf(fp, "To: %s\n", mail_to);
  3023. X    fprintf(fp, "Subject: %s\n", note_h_subj);
  3024. X    if (*note_h_followup)
  3025. X        fprintf(fp, "Newsgroups: %s\n\n", note_h_followup);
  3026. X    else
  3027. X        fprintf(fp, "Newsgroups: %s\n", note_h_newsgroups);
  3028. X    line = 3;
  3029. X    if (*my_org) {
  3030. X        fprintf(fp, "Organization: %s\n", my_org);
  3031. X        ++line;
  3032. X    }
  3033. X    fputs("\n", fp);
  3034. X    ++line;
  3035. X
  3036. X    fseek(note_fp, 0L, 0);
  3037. X    copy_fp(note_fp, fp, "");
  3038. X
  3039. X    fclose(fp);
  3040. X    umask (0);
  3041. X
  3042. X    while (1) {
  3043. X        do {
  3044. X            MoveCursor(LINES, 0);
  3045. X            fputs("abort, edit, send: ", stdout);
  3046. X            fflush(stdout);
  3047. X            ch = ReadCh();
  3048. X        } while (ch != 'a' && ch != 'e' && ch != 's');
  3049. X
  3050. X        switch (ch) {
  3051. X        case 'e':
  3052. X            invoke_editor(nam, line);
  3053. X            break;
  3054. X
  3055. X        case 'a':
  3056. X            return FALSE;
  3057. X
  3058. X        case 's':
  3059. X/*
  3060. X *  Open letter an get the To: line in case they changed it with
  3061. X *  the editor
  3062. X */
  3063. X
  3064. X            find_new_to(nam, mail_to);
  3065. X            printf("\rMailing to %s...", mail_to);
  3066. X            CleartoEOLN ();
  3067. X#ifndef    OSK
  3068. X            sprintf(buf, "%s \"%s\" < %s", MAILER,
  3069. X#else    /* OSK */
  3070. X            sprintf(buf, "%s \"%s\" <%s", MAILER,
  3071. X#endif    /* OSK */
  3072. X                            mail_to, nam);
  3073. X            if (invoke_cmd(buf)) {
  3074. X                printf("Message sent ");
  3075. X                fflush(stdout);
  3076. X                goto mail_to_someone_done;
  3077. X            } else {
  3078. X                printf("Command failed: %s ", buf);
  3079. X                fflush(stdout);
  3080. X                break;
  3081. X            }
  3082. X        }
  3083. X    }
  3084. X
  3085. Xmail_to_someone_done:
  3086. X#ifdef    USE_UID
  3087. X    setuid(tass_uid);
  3088. X    setgid(tass_gid);
  3089. X#endif    /* USE_UID */
  3090. X
  3091. X    continue_prompt();
  3092. X
  3093. X    return TRUE;
  3094. X}
  3095. X
  3096. Xmail_to_author(copy_text)
  3097. Xint copy_text;
  3098. X{
  3099. X    char nam[100];
  3100. X    FILE *fp;
  3101. X    char ch;
  3102. X    char buf[200];
  3103. X    char mail_to[LEN+1];
  3104. X    int line;
  3105. X
  3106. X#ifdef    USE_UID
  3107. X    setuid(real_uid);
  3108. X    setgid(real_gid);
  3109. X#endif    /* USE_UID */
  3110. X
  3111. X    printf("\r\012Mailing to %s...\r\012\r\012", note_h_from);
  3112. X
  3113. X    sprintf(nam, "%s/.letter", homedir);
  3114. X    umask (omask);
  3115. X    if ((fp = fopen(nam, "w")) == NULL) {
  3116. X        umask (0);
  3117. X        fprintf(stderr, "can't open %s: ", nam);
  3118. X        perror("");
  3119. X        return(FALSE);
  3120. X    }
  3121. X#ifndef    OSK
  3122. X    chmod(nam, 0600);
  3123. X#else    /* OSK */
  3124. X    chmod(nam, 013);
  3125. X#endif    /* OSK */
  3126. X
  3127. X    fprintf(fp, "To: %s\n", note_h_from);
  3128. X    fprintf(fp, "Subject: Re: %s\n", eat_re(note_h_subj) );
  3129. X    fprintf(fp, "Newsgroups: %s\n", note_h_newsgroups);
  3130. X    line = 3;
  3131. X    if (*my_org) {
  3132. X        fprintf(fp, "Organization: %s\n", my_org);
  3133. X        ++line;
  3134. X    }
  3135. X    fputs("\n", fp);
  3136. X    ++line;
  3137. X
  3138. X    if (copy_text) {        /* if "copy_text" */
  3139. X        fprintf(fp, "In article %s you write:\n", note_h_messageid);
  3140. X
  3141. X        fseek(note_fp, note_mark[0], 0);
  3142. X#ifndef    INCSTR
  3143. X        copy_fp(note_fp, fp, "> ");
  3144. X#else    /* INCSTR */
  3145. X        copy_fp(note_fp, fp, incstr);
  3146. X#endif    /* INCSTR */
  3147. X    }
  3148. X
  3149. X#ifdef    APPEND_SIG
  3150. X    add_signature (fp);
  3151. X#endif    /* APPEND_SIG */
  3152. X
  3153. X    fclose(fp);
  3154. X    umask (0);
  3155. X
  3156. X    ch = 'e';
  3157. X    while (1) {
  3158. X        switch (ch) {
  3159. X        case 'e':
  3160. X            invoke_editor(nam, line);
  3161. X            break;
  3162. X
  3163. X        case 'a':
  3164. X            return FALSE;
  3165. X
  3166. X        case 's':
  3167. X            strcpy(mail_to, note_h_reply[0] ? note_h_reply : note_from_addr);
  3168. X            find_new_to(nam, mail_to);
  3169. X            printf("\rMailing to %s...  ", mail_to);
  3170. X            CleartoEOLN ();
  3171. X#ifndef    OSK
  3172. X            sprintf(buf, "/usr/bin/rmail \"%s\" < %s",
  3173. X#else    /* OSK */
  3174. X            sprintf(buf, "%s \"%s\" <%s", MAILER,
  3175. X#endif    /* OSK */
  3176. X                                mail_to, nam);
  3177. X            if (invoke_cmd(buf)) {
  3178. X                printf("Message sent ");
  3179. X                fflush(stdout);
  3180. X                goto mail_to_author_done;
  3181. X            } else {
  3182. X                printf("Command failed: %s ", buf);
  3183. X                fflush(stdout);
  3184. X                break;
  3185. X            }
  3186. X        }
  3187. X
  3188. X        do {
  3189. X            MoveCursor(LINES, 0);
  3190. X            fputs("abort, edit, send: ", stdout);
  3191. X            fflush(stdout);
  3192. X            ch = ReadCh();
  3193. X        } while (ch != 'a' && ch != 'e' && ch != 's');
  3194. X    }
  3195. X
  3196. Xmail_to_author_done:
  3197. X#ifdef    USE_UID
  3198. X    setuid(tass_uid);
  3199. X    setgid(tass_gid);
  3200. X#endif    /* USE_UID */
  3201. X
  3202. X    continue_prompt();
  3203. X
  3204. X    return TRUE;
  3205. X}
  3206. X
  3207. X
  3208. Xpost_response(group, respnum)
  3209. Xint respnum;
  3210. X{
  3211. X    FILE *fp;
  3212. X    char nam[100];
  3213. X    char ch;
  3214. X    char buf[200];
  3215. X    int post_anyway = FALSE;
  3216. X    int line;
  3217. X
  3218. X    if (*note_h_followup && strcmp(note_h_followup, "poster") == 0) {
  3219. X        clear_message();
  3220. X        MoveCursor(LINES,0);
  3221. X        printf("Note: Responses have been directed to the poster");
  3222. X        if (!prompt_yn("Post anyway? (y/n): "))
  3223. X            return FALSE;
  3224. X        *note_h_followup = '\0';
  3225. X    } else if (*note_h_followup && strcmp(note_h_followup, group) != 0) {
  3226. X        clear_message();
  3227. X        MoveCursor(LINES,0);
  3228. X        printf("Note:  Responses have been directed to %s\r\012\r\012",
  3229. X                            note_h_followup);
  3230. X        if (!prompt_yn("Continue? (y/n): "))
  3231. X        return FALSE;
  3232. X    }
  3233. X
  3234. X#ifdef    USE_UID
  3235. X    setuid(real_uid);
  3236. X    setgid(real_gid);
  3237. X#endif    /* USE_UID */
  3238. X
  3239. X    sprintf(nam, "%s/.article", homedir);
  3240. X    umask (omask);
  3241. X    if ((fp = fopen(nam, "w")) == NULL) {
  3242. X        umask (0);
  3243. X        fprintf(stderr, "can't open %s: ", nam);
  3244. X        perror("");
  3245. X        return FALSE;
  3246. X    }
  3247. X#ifndef    OSK
  3248. X    chmod(nam, 0600);
  3249. X#else    /* OSK */
  3250. X    chmod(nam, 013);
  3251. X#endif    /* OSK */
  3252. X
  3253. X    fprintf(fp, "Subject: Re: %s\n", eat_re(note_h_subj));
  3254. X
  3255. X    if (*note_h_followup && strcmp(note_h_followup, "poster") != 0)
  3256. X        fprintf(fp, "Newsgroups: %s\n", note_h_followup);
  3257. X    else
  3258. X        fprintf(fp, "Newsgroups: %s\n", note_h_newsgroups);
  3259. X    line = 2;
  3260. X
  3261. X    if (*my_org) {
  3262. X        fprintf(fp, "Organization: %s\n", my_org);
  3263. X        ++line;
  3264. X    }
  3265. X
  3266. X    if (note_h_distrib != '\0') {
  3267. X        fprintf(fp, "Distribution: %s\n", note_h_distrib);
  3268. X        ++line;
  3269. X    }
  3270. X
  3271. X    fprintf(fp, "References: %s\n", note_h_messageid);
  3272. X    fprintf(fp, "\n");
  3273. X    line += 2;
  3274. X
  3275. X    if (respnum) {        /* if "copy_text" */
  3276. X        fprintf(fp, "%s writes:\n", note_h_from);
  3277. X        ++line;
  3278. X
  3279. X        fseek(note_fp, note_mark[0], 0);
  3280. X#ifndef    INCSTR
  3281. X        copy_fp(note_fp, fp, "> ");
  3282. X#else    /* INCSTR */
  3283. X        copy_fp(note_fp, fp, incstr);
  3284. X#endif    /* INCSTR */
  3285. X    }
  3286. X
  3287. X#ifdef    APPEND_SIG
  3288. X    add_signature (fp);
  3289. X#endif    /* APPEND_SIG */
  3290. X
  3291. X    fclose(fp);
  3292. X    umask (0);
  3293. X
  3294. X    ch = 'e';
  3295. X    while (1) {
  3296. X        switch (ch) {
  3297. X        case 'e':
  3298. X            invoke_editor(nam, line);
  3299. X            break;
  3300. X
  3301. X        case 'a':
  3302. X            return FALSE;
  3303. X
  3304. X        case 'p':
  3305. X            printf("\rPosting...  ");
  3306. X            CleartoEOLN ();
  3307. X#ifndef    OSK
  3308. X            sprintf(buf, "%s/inews -h < %s", LIBDIR, nam);
  3309. X#else    /* OSK */
  3310. X            sprintf(buf, "inews -h <%s", nam);
  3311. X#endif    /* OSK */
  3312. X            if (invoke_cmd(buf)) {
  3313. X                printf("article posted ");
  3314. X                fflush(stdout);
  3315. X                goto post_response_done;
  3316. X            } else {
  3317. X                printf("article rejected ");
  3318. X                fflush(stdout);
  3319. X                break;
  3320. X            }
  3321. X        }
  3322. X
  3323. X        do {
  3324. X            MoveCursor(LINES, 0);
  3325. X            fputs("abort, edit, post: ", stdout);
  3326. X            fflush(stdout);
  3327. X            ch = ReadCh();
  3328. X        } while (ch != 'a' && ch != 'e' && ch != 'p');
  3329. X    }
  3330. X
  3331. Xpost_response_done:
  3332. X#ifdef    USE_UID
  3333. X    setuid(tass_uid);
  3334. X    setgid(tass_gid);
  3335. X#endif    /* USE_UID */
  3336. X
  3337. X    continue_prompt();
  3338. X
  3339. X    return TRUE;
  3340. X}
  3341. X
  3342. Xvoid
  3343. Xsave_art_to_file()
  3344. X{
  3345. X    char nam[LEN];
  3346. X    FILE *fp;
  3347. X    char *p;
  3348. X
  3349. X    if (!parse_string("Save article to file: ", nam))
  3350. X        return;
  3351. X    if (nam[0] == '\0')
  3352. X        return;
  3353. X
  3354. X    for (p = nam; *p && (*p == ' ' || *p == '\t'); p++) ;
  3355. X    if (!*p)
  3356. X        return;
  3357. X
  3358. X#ifdef    USE_UID
  3359. X    setuid(real_uid);
  3360. X    setgid(real_gid);
  3361. X#endif    /* USE_UID */
  3362. X
  3363. X    umask (omask);
  3364. X    if ((fp = fopen(p, "a+")) == NULL) {
  3365. X        umask (0);
  3366. X        fprintf(stderr, "can't open %s: ", nam);
  3367. X        perror("");
  3368. X        info_message("-- article not saved --");
  3369. X#ifdef    USE_UID
  3370. X        setuid(real_uid);
  3371. X        setgid(real_gid);
  3372. X#endif    /* USE_UID */
  3373. X        return;
  3374. X    }
  3375. X
  3376. X    MoveCursor(LINES, 0);
  3377. X    fputs("Saving...", stdout);
  3378. X    fflush(stdout);
  3379. X
  3380. X    fprintf(fp, "From %s %s\n", note_h_path, note_h_date);
  3381. X
  3382. X    fseek(note_fp, 0L, 0);
  3383. X    copy_fp(note_fp, fp, "");
  3384. X    fputs("\n", fp);
  3385. X
  3386. X    fclose(fp);
  3387. X    umask (0);
  3388. X
  3389. X#ifdef    USE_UID
  3390. X    setuid(real_uid);
  3391. X    setgid(real_gid);
  3392. X#endif    /* USE_UID */
  3393. X
  3394. X    info_message("-- article saved --");
  3395. X}
  3396. X
  3397. Xvoid
  3398. Xsave_thread_to_file(respnum, group_path)
  3399. Xlong respnum;
  3400. Xchar *group_path;
  3401. X{
  3402. X    char nam[LEN];
  3403. X    FILE *fp;
  3404. X    FILE *art;
  3405. X    int i;
  3406. X    char buf[8192];
  3407. X    int b;
  3408. X    int count = 0;
  3409. X    char *p;
  3410. X
  3411. X    b = which_base(respnum);
  3412. X
  3413. X    if (!parse_string("Save thread to file: ", nam))
  3414. X        return;
  3415. X    if (nam[0] == '\0')
  3416. X        return;
  3417. X
  3418. X    for (p = nam; *p && (*p == ' ' || *p == '\t'); p++) ;
  3419. X    if (!*p)
  3420. X        return;
  3421. X
  3422. X#ifdef    USE_UID
  3423. X    setuid(real_uid);
  3424. X    setgid(real_gid);
  3425. X#endif    /* USE_UID */
  3426. X
  3427. X    umask (omask);
  3428. X    if ((fp = fopen(nam, "a+")) == NULL) {
  3429. X        umask (0);
  3430. X        fprintf(stderr, "can't open %s: ", nam);
  3431. X        perror("");
  3432. X        info_message("-- thread not saved --");
  3433. X#ifdef    USE_UID
  3434. X        setuid(real_uid);
  3435. X        setgid(real_gid);
  3436. X#endif    /* USE_UID */
  3437. X        return;
  3438. X    }
  3439. X
  3440. X    MoveCursor(LINES, 0);
  3441. X    fputs("Saving...    ", stdout);
  3442. X    fflush(stdout);
  3443. X
  3444. X    note_cleanup();
  3445. X
  3446. X    for (i = base[b]; i >= 0; i = arts[i].thread) {
  3447. X        open_note(arts[i].artnum, group_path);
  3448. X
  3449. X        fprintf(fp, "From %s %s\n", note_h_path, note_h_date);
  3450. X        fseek(note_fp, 0L, 0);
  3451. X        copy_fp(note_fp, fp, "");
  3452. X        fputs("\n", fp);
  3453. X
  3454. X        note_cleanup();
  3455. X        printf("\b\b\b\b%4d", ++count);
  3456. X        fflush(stdout);
  3457. X    }
  3458. X
  3459. X    fclose(fp);
  3460. X    umask (0);
  3461. X
  3462. X#ifdef    USE_UID
  3463. X    setuid(real_uid);
  3464. X    setgid(real_gid);
  3465. X#endif    /* USE_UID */
  3466. X
  3467. X    info_message("-- thread saved --");
  3468. X    open_note(arts[respnum].artnum, group_path);
  3469. X}
  3470. X
  3471. Xvoid
  3472. Xpipe_article() {
  3473. X    char command[LEN];
  3474. X    FILE *fp;
  3475. X
  3476. X    if (!parse_string("Pipe to command: ", command))
  3477. X        return;
  3478. X    if (command[0] == '\0')
  3479. X        return;
  3480. X
  3481. X    fp = popen(command, "w");
  3482. X    if (fp == NULL) {
  3483. X        fprintf(stderr, "command failed: ");
  3484. X        perror("");
  3485. X        goto pipe_article_done;
  3486. X    }
  3487. X
  3488. X    fseek(note_fp, 0L, 0);
  3489. X    copy_fp(note_fp, fp, "");
  3490. X    pclose(fp);
  3491. X
  3492. Xpipe_article_done:
  3493. X
  3494. X    continue_prompt();
  3495. X}
  3496. X
  3497. __END__OF__THIS__FILE__
  3498. exit 0
  3499. : end of shell archive
  3500.  
  3501. -- 
  3502. Frank Kaefer # fkk@stasys.sta.sub.org # Starnberg, Germany
  3503.