home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #31 / NN_1992_31.iso / spool / de / comp / sources / os9 / 14 < prev    next >
Encoding:
Internet Message Format  |  1992-12-24  |  47.7 KB

  1. Xref: sparky de.comp.sources.os9:14 comp.os.os9:1559
  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 Part01/03
  6. Message-ID: <1hccj4INN76t@stasys.sta.sub.org>
  7. Date: 24 Dec 92 13:05:40 GMT
  8. Sender: news@stasys.sta.sub.org
  9. Followup-To: de.comp.sources.d
  10. Organization: Stasys News Server, Starnberg, Germany
  11. Lines: 2372
  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/part01
  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. :     'MANIFEST                                      660 bytes'
  22. :     'COPYRIGHT                                     356 bytes'
  23. :     'Makefile                                      679 bytes'
  24. :     'art.c                                       16520 bytes'
  25. :     'curses.c                                     8952 bytes'
  26. :     'group.c                                     16732 bytes'
  27. if test -f 'MANIFEST' ; then
  28.   echo 'File MANIFEST already exists, overwriting it'
  29.   del 'MANIFEST'
  30. fi
  31. echo Extracting \"'MANIFEST'\"
  32. sed "s/^X//" >'MANIFEST' <<'__END__OF__THIS__FILE__'
  33. XFilename                  Part   Description
  34. X----------------------------------------------------
  35. XMANIFEST                  1      This shipping list
  36. XCOPYRIGHT                 1      
  37. XMakefile                  1      
  38. Xart.c                     1      
  39. Xcurses.c                  1      
  40. Xgroup.c                   1      
  41. Xmail.c                    2      
  42. Xmain.c                    2      
  43. Xmisc.c                    2      
  44. Xpage.c                    2      
  45. Xprompt.c                  3      
  46. Xscreen.c                  3      
  47. Xselect.c                  3      
  48. Xsigs.c                    3      
  49. Xtass.h                    3      
  50. Xtime.c                    3      
  51. __END__OF__THIS__FILE__
  52. if test -f 'COPYRIGHT' ; then
  53.   echo 'File COPYRIGHT already exists, overwriting it'
  54.   del 'COPYRIGHT'
  55. fi
  56. echo Extracting \"'COPYRIGHT'\"
  57. sed "s/^X//" >'COPYRIGHT' <<'__END__OF__THIS__FILE__'
  58. X/*
  59. X *  Tass, a visual Usenet news reader
  60. X *  (c) Copyright 1990 by Rich Skrenta
  61. X *
  62. X *  Distribution agreement:
  63. X *
  64. X *    You may freely copy or redistribute this software, so long
  65. X *    as there is no profit made from its use, sale, trade or
  66. X *    reproduction.  You may not change this copyright notice,
  67. X *    and it must be included prominently in any copy made.
  68. X */
  69. __END__OF__THIS__FILE__
  70. if test -f 'Makefile' ; then
  71.   echo 'File Makefile already exists, overwriting it'
  72.   del 'Makefile'
  73. fi
  74. echo Extracting \"'Makefile'\"
  75. sed "s/^X//" >'Makefile' <<'__END__OF__THIS__FILE__'
  76. XG=    -g
  77. XCC=    cc
  78. XCFLAGS=    -qt=/dd/TMP $G -DREGEXP -DAPPEND_SIG -DMNEWS -DINCSTR \
  79. X    -DLOCK_INDEX -DRAND_SIG
  80. XLIBS=    -l=/dd/LIB/8bit.l -l=/dd/LIB/termlib.l -l=/dd/LIB/os9lib.l
  81. X
  82. X
  83. XOBJECTS    =    curses.r art.r group.r mail.r main.r misc.r page.r \
  84. X        prompt.r screen.r select.r time.r sigs.r
  85. X
  86. X/h0/ETC/CMDS/tass: $(OBJECTS)
  87. X    $(CC) $(CFLAGS) -m=20 -f=$@ $(OBJECTS) $(LIBS)
  88. X
  89. Xshar:
  90. X    -mv -f ../tass.shar ../tass.shar-
  91. X    shar -v [A-Z]* *.[ch] > ../tass.shar
  92. X
  93. X
  94. Xart.r:        art.c tass.h
  95. Xcurses.r:    curses.c
  96. Xgroup.r:    group.c tass.h
  97. Xmail.r:        mail.c
  98. Xmain.r:        main.c tass.h
  99. Xmisc.r:        misc.c tass.h
  100. Xpage.r:        page.c tass.h
  101. Xprompt.r:    prompt.c tass.h
  102. Xscreen.r:    screen.c tass.h
  103. Xselect.r:    select.c tass.h
  104. Xtime.r:        time.c
  105. __END__OF__THIS__FILE__
  106. if test -f 'art.c' ; then
  107.   echo 'File art.c already exists, overwriting it'
  108.   del 'art.c'
  109. fi
  110. echo Extracting \"'art.c'\"
  111. sed "s/^X//" >'art.c' <<'__END__OF__THIS__FILE__'
  112. X
  113. X
  114. X#include    <stdio.h>
  115. X#include    <time.h>
  116. X#include    <signal.h>
  117. X#include    <errno.h>
  118. X#include    "tass.h"
  119. X
  120. X
  121. X/* Hopefully one of these is right for you. */
  122. X
  123. X#ifdef BSD
  124. X#    include <sys/types.h>
  125. X#    include <sys/dir.h>
  126. X#    define        DIR_BUF        struct direct
  127. X#    define        D_LENGTH    d_namlen
  128. X#endif
  129. X#ifdef M_XENIX
  130. X#    include <sys/ndir.h>
  131. X#    define        DIR_BUF        struct direct
  132. X#    define        D_LENGTH    d_namlen
  133. X#endif
  134. X#ifdef    OSK
  135. X#    include <ctype.h>
  136. X#    include <modes.h>
  137. X#    include <dir.h>
  138. X#    define        DIR_BUF        struct direct
  139. X#    define        D_LENGTH    d_namlen
  140. X#    undef        SPOOLDIR
  141. X#    define        SPOOLDIR    spooldir
  142. X#endif    /* OSK */
  143. X#ifndef DIR_BUF
  144. X#    include    <sys/types.h>
  145. X#    include    <dirent.h>
  146. X#    define        DIR_BUF        struct dirent
  147. X#    define        D_LENGTH    d_reclen
  148. X#endif
  149. X
  150. Xextern char    *index ();
  151. Xextern char    *realloc ();
  152. X
  153. Xchar index_file[LEN+1];
  154. Xchar *glob_art_group;
  155. X
  156. Xstatic int    complete_count;
  157. Xstatic int    complete_expire;
  158. X
  159. X#ifdef SIGTSTP
  160. Xvoid
  161. Xart_susp(i)
  162. Xint i;
  163. X{
  164. X
  165. X    Raw(FALSE);
  166. X    putchar('\n');
  167. X    signal(SIGTSTP, SIG_DFL);
  168. X    kill(0, SIGTSTP);
  169. X
  170. X    signal(SIGTSTP, art_susp);
  171. X    Raw(TRUE);
  172. X
  173. X    mail_setup();
  174. X    ClearScreen();
  175. X    MoveCursor(LINES, 0);
  176. X    printf("Group %s...    ", glob_art_group);
  177. X    fflush(stdout);
  178. X}
  179. X#endif
  180. X
  181. X
  182. X/*
  183. X *  Convert a string to a long, only look at first n characters
  184. X */
  185. X
  186. Xmy_atol(s, n)
  187. Xchar *s;
  188. Xint n;
  189. X{
  190. X    long ret = 0;
  191. X
  192. X    while (*s && n--) {
  193. X        if (*s >= '0' && *s <= '9')
  194. X            ret = ret * 10 + (*s - '0');
  195. X        else
  196. X            return -1;
  197. X        s++;
  198. X    }
  199. X
  200. X    return ret;
  201. X}
  202. X
  203. X# ifdef        LOCK_INDEX
  204. X/*
  205. X *    Lock the index when modifieng it (only on global indicies)
  206. X */
  207. Xstatic char *
  208. Xlock_filename (fle)
  209. Xchar *fle;
  210. X{
  211. X#ifndef    OSK
  212. X    static int    siz = -1;
  213. X    static char    *fname = NULL;
  214. X    int        len;
  215. X
  216. X    if ((len = strlen (fle)) > siz) {
  217. X        siz = len;
  218. X        if (! (fname = realloc (fname, siz + 16)))
  219. X            return (NULL);
  220. X    }
  221. X    sprintf (fname, "%s_lock", fle);
  222. X    return (fname);
  223. X#else
  224. X    static char    fname[64];
  225. X    unsigned long    n;
  226. X    char        *ptr;
  227. X
  228. X    for (ptr = fle, n = 0; *ptr; n += *ptr++ & 0xff)
  229. X        ;
  230. X    sprintf (fname, "/dd/TMP/%u_lock", n);
  231. X    return (fname);
  232. X#endif
  233. X}
  234. X
  235. X# ifdef        OSK
  236. Xstatic void
  237. Xstop_signals ()
  238. X{
  239. X    sigmask (1);
  240. X}
  241. X
  242. Xstatic void
  243. Xstart_signals ()
  244. X{
  245. X    sigmask (-1);
  246. X}
  247. X# else        /* OSK */
  248. Xtypedef int    SIGTYPE;
  249. X
  250. Xstatic SIGTYPE    (*signals)()[NSIG];
  251. X
  252. Xstatic void
  253. Xstop_signals ()
  254. X{
  255. X    int    t;
  256. X
  257. X    for (t = 0; t < NSIG; ++t)
  258. X        signals[t] = signal (t, SIG_IGN);
  259. X}
  260. X
  261. Xstatic void
  262. Xstart_signals ()
  263. X{
  264. X    int    t;
  265. X
  266. X    for (t = 0; t < NSIG; ++t)
  267. X        signal (t, signals[t]);
  268. X}
  269. X# endif        /* OSK */
  270. X
  271. Xstatic int    lock_fd = -1;
  272. X
  273. Xstatic int
  274. Xlock_index (fle)
  275. Xchar *fle;
  276. X{
  277. X    int        tout;
  278. X    char        *fn;
  279. X
  280. X    if (lock_fd != -1)
  281. X        close (lock_fd);
  282. X    if (! (fn = lock_filename (fle)))
  283. X        return (-1);
  284. X    for (tout = 20; tout > 0; --tout) {
  285. X# ifndef    OSK
  286. X        if ((lock_fd = creat (fn, 0444)) == -1)
  287. X# else        /* OSK */
  288. X        unlink (fn);
  289. X        if (((lock_fd = create (fn, S_IWRITE, 033)) == -1) && (errno == E_CEF))
  290. X# endif        /* OSK */
  291. X            sleep (1);
  292. X        else
  293. X            break;
  294. X    }
  295. X    if (lock_fd != -1)
  296. X        stop_signals ();
  297. X    return (lock_fd == -1 ? -1 : 0);
  298. X}
  299. X
  300. Xstatic void
  301. Xunlock_index (fle)
  302. Xchar *fle;
  303. X{
  304. X    char    *fn;
  305. X
  306. X    if (lock_fd != -1) {
  307. X        close (lock_fd);
  308. X        lock_fd = -1;
  309. X        if (fn = lock_filename (fle)) {
  310. X# ifndef    OSK
  311. X            chmod (fn, 0666);
  312. X# endif        /* OSK */
  313. X            unlink (fn);
  314. X        }
  315. X        start_signals ();
  316. X    }
  317. X}
  318. X# endif        /* LOCK_INDEX */
  319. X
  320. X/*
  321. X *  Construct the pointers to the basenotes of each thread
  322. X *  arts[] contains every article in the group.  inthread is
  323. X *  set on each article that is after the first article in the
  324. X *  thread.  Articles which have been expired have their thread
  325. X *  set to -2.
  326. X */
  327. X
  328. Xfind_base() {
  329. X    int i;
  330. X
  331. X    top_base = 0;
  332. X
  333. X    for (i = 0; i < top; i++)
  334. X        if (!arts[i].inthread && arts[i].thread != -2) {
  335. X            if (top_base >= max_art)
  336. X                expand_art();
  337. X            base[top_base++] = i;
  338. X        }
  339. X}
  340. X
  341. X
  342. X/* 
  343. X *  Count the number of non-expired articles in arts[]
  344. X */
  345. X
  346. Xnum_arts() {
  347. X    int sum = 0;
  348. X    int i;
  349. X
  350. X    for (i = 0; i < top; i++)
  351. X        if (arts[i].thread != -2)
  352. X            sum++;
  353. X
  354. X    return sum;
  355. X}
  356. X
  357. X
  358. X/*
  359. X *  Do we have an entry for article art?
  360. X */
  361. X
  362. Xvalid_artnum(art)
  363. Xlong art;
  364. X{
  365. X    int i;
  366. X
  367. X    for (i = 0; i < top; i++)
  368. X        if (arts[i].artnum == art)
  369. X            return i;
  370. X
  371. X    return -1;
  372. X}
  373. X
  374. X
  375. X/*
  376. X *  Return TRUE if arts[] contains any expired articles
  377. X *  (articles we have an entry for which don't have a corresponding
  378. X *   article file in the spool directory)
  379. X */
  380. X
  381. Xpurge_needed() {
  382. X    int i;
  383. X
  384. X    for (i = 0; i < top; i++)
  385. X        if (arts[i].thread == -2)
  386. X            return TRUE;
  387. X
  388. X    return FALSE;
  389. X}
  390. X
  391. X
  392. X/*
  393. X *  Main group indexing routine.  Group should be the name of the
  394. X *  newsgroup, i.e. "comp.unix.amiga".  group_path should be the
  395. X *  same but with the .'s turned into /'s: "comp/unix/amiga"
  396. X *
  397. X *  Will read any existing index, create or incrementally update
  398. X *  the index by looking at the articles in the spool directory,
  399. X *  and attempt to write a new index if necessary.
  400. X */
  401. X
  402. Xindex_group(group, group_path)
  403. Xchar *group;
  404. Xchar *group_path;
  405. X{
  406. X    int modified;
  407. X
  408. X    glob_art_group = group;
  409. X
  410. X#ifdef SIGTSTP
  411. X    signal(SIGTSTP, art_susp);
  412. X#endif
  413. X
  414. X    if (!update) {
  415. X        clear_message();
  416. X        MoveCursor(LINES, 0);
  417. X        printf("Group %s...    ", group);
  418. X        fflush(stdout);
  419. X    }
  420. X
  421. X    if (local_index)
  422. X        find_local_index(group);
  423. X    else
  424. X        sprintf(index_file, "%s/%s/.tindex", SPOOLDIR, group_path);
  425. X
  426. X#ifdef    LOCK_INDEX
  427. X    if (! local_index)
  428. X        if (lock_index (index_file) < 0)
  429. X            return -1;
  430. X#endif    /* LOCK_INDEX */
  431. X
  432. X    load_index();
  433. X    modified = read_group(group_path);
  434. X    make_threads();
  435. X    if (modified || purge_needed()) {
  436. X#ifdef    USE_UID
  437. X        if (local_index) {    /* writing index in home directory */
  438. X            setuid(real_uid);    /* so become them */
  439. X            setgid(real_gid);
  440. X        }
  441. X#endif    /* USE_UID */
  442. X        dump_index(group);
  443. X#ifdef    USE_UID
  444. X        if (local_index) {
  445. X            setuid(tass_uid);
  446. X            setgid(tass_gid);
  447. X        }
  448. X#endif    /* USE_UID */
  449. X    }
  450. X
  451. X#ifdef    LOCK_INDEX
  452. X    if (! local_index)
  453. X        unlock_index (index_file);
  454. X#endif    /* LOCK_INDEX */
  455. X
  456. X    find_base();
  457. X
  458. X    if (modified && !update)
  459. X        clear_message();
  460. X}
  461. X
  462. X
  463. X/*
  464. X *  Longword comparison routine for the qsort()
  465. X */
  466. X
  467. Xbase_comp(a, b)
  468. Xlong *a;
  469. Xlong *b;
  470. X{
  471. X
  472. X    if (*a < *b)
  473. X        return -1;
  474. X    if (*a > *b)
  475. X        return 1;
  476. X    return 0;
  477. X}
  478. X
  479. X
  480. X/*
  481. X *  Read the article numbers existing in a group's spool directory
  482. X *  into base[] and sort them.  base_top is one past top.
  483. X */
  484. X
  485. Xscan_dir(group)
  486. Xchar *group;
  487. X{
  488. X    DIR *d;
  489. X    DIR_BUF *e;
  490. X    long art;
  491. X    char buf[200];
  492. X
  493. X    top_base = 0;
  494. X
  495. X    sprintf(buf, "%s/%s", SPOOLDIR, group);
  496. X
  497. X    d = opendir(buf);
  498. X    if (d != NULL) {
  499. X        while ((e = readdir(d)) != NULL) {
  500. X#ifdef        OSK
  501. X            e->D_LENGTH = strlen (e->d_name);
  502. X#endif        /* OSK */
  503. X            art = my_atol(e->d_name, e->D_LENGTH);
  504. X            if (art >= 0) {
  505. X                if (top_base >= max_art)
  506. X                    expand_art();
  507. X                base[top_base++] = art;
  508. X            }
  509. X        }
  510. X        closedir(d);
  511. X    }
  512. X
  513. X    qsort(base, top_base, sizeof(long), base_comp);
  514. X}
  515. X
  516. X
  517. X/*
  518. X *  Index a group.  Assumes any existing index has already been
  519. X *  loaded.
  520. X */
  521. X
  522. Xread_group(group)
  523. Xchar *group;
  524. X{
  525. X    char buf[200];
  526. X    int fd;
  527. X    long art;
  528. X    int count;
  529. X    int modified = FALSE;
  530. X    int respnum;
  531. X    int i;
  532. X
  533. X    scan_dir(group);    /* load article numbers into base[] */
  534. X
  535. X    count = 0;
  536. X
  537. X    for (i = 0; i < top_base; i++) {    /* for each article # */
  538. X        art = base[i];
  539. X
  540. X/*
  541. X *  Do we already have this article in our index?  Change thread from
  542. X *  -2 to -1 if so and skip the header eating.
  543. X */
  544. X
  545. X        if ((respnum = valid_artnum(art)) >= 0) {
  546. X            arts[respnum].thread = -1;
  547. X            arts[respnum].unread = 1;
  548. X            continue;
  549. X        }
  550. X
  551. X        if (!modified) {
  552. X            modified = TRUE;   /* we've modified the index */
  553. X                       /* it will need to be re-written */
  554. X#if 0
  555. X            if (!update) {
  556. X                MoveCursor(LINES, 0);
  557. X                fputs("Indexing...    ", stdout);
  558. X                fflush(stdout);
  559. X            }
  560. X#endif
  561. X        }
  562. X
  563. X/*
  564. X *  Add article to arts[]
  565. X */
  566. X        if (top >= max_art)
  567. X            expand_art();
  568. X
  569. X        arts[top].artnum = art;
  570. X        arts[top].thread = -1;
  571. X        arts[top].inthread = FALSE;
  572. X        arts[top].unread = 1;
  573. X
  574. X        sprintf(buf, "%s/%s/%ld", SPOOLDIR, group, art);
  575. X#ifndef    MNEWS
  576. X        fd = open(buf, 0);
  577. X#else    /* MNEWS */
  578. X#ifndef    OSK
  579. X        if ((fd = open (buf, O_RDONLY)) != -1) {
  580. X#else    /* OSK */
  581. X        if ((fd = open (buf, S_IREAD)) != -1) {
  582. X#endif    /* OSK */
  583. X            int    n;
  584. X            n = readln (fd, buf, 180);
  585. X            lseek (fd, 0, 0);
  586. X            if (n > 0) {
  587. X                buf[n - 1] = '\0';
  588. X                if (!strncmp (buf, "%(#)$ ", 6)) {
  589. X                    char    sav[200];
  590. X                    strcpy (sav, buf + 6);
  591. X                    sprintf (buf, "%s/%s", spooldir, sav);
  592. X                    close (fd);
  593. X#ifndef    OSK
  594. X                    fd = open (buf, O_RDONLY);
  595. X#else    /* OSK */
  596. X                    fd = open (buf, S_IREAD);
  597. X#endif    /* OSK */
  598. X                }
  599. X            }
  600. X        }
  601. X#endif    /* MNEWS */
  602. X
  603. X        if (fd < 0) {
  604. X            fprintf(stderr, "can't open article %s: ", buf);
  605. X            perror("");
  606. X            continue;
  607. X        }
  608. X
  609. X        if (!parse_headers(fd, &arts[top]))
  610. X            continue;
  611. X        top++;
  612. X        close(fd);
  613. X
  614. X        if (++count % 10 == 0 && !update) {
  615. X            printf("\b\b\b\b%4d", count);
  616. X            fflush(stdout);
  617. X        }
  618. X    }
  619. X
  620. X    complete_count += count;
  621. X
  622. X    return modified;
  623. X}
  624. X
  625. X
  626. X/*
  627. X *  Go through the articles in arts[] and use .thread to snake threads
  628. X *  through them.  Use the subject line to construct threads.  The
  629. X *  first article in a thread should have .inthread set to FALSE, the
  630. X *  rest TRUE.  Only do unexprired articles we haven't visited yet
  631. X *  (arts[].thread == -1).
  632. X */
  633. X
  634. Xmake_threads() {
  635. X    int i;
  636. X    int j;
  637. X
  638. X    for (i = 0; i < top; i++) {
  639. X        if (arts[i].thread == -1)
  640. X            for (j = i+1; j < top; j++)
  641. X            if (arts[i].hash == arts[j].hash
  642. X            &&  arts[j].thread != -2
  643. X            &&  strncmp(arts[i].nore, arts[j].nore, 10) == 0) {
  644. X                arts[i].thread = j;
  645. X                arts[j].inthread = TRUE;
  646. X                break;
  647. X            }
  648. X    }
  649. X}
  650. X
  651. X
  652. X/*
  653. X *  Return a pointer into s eliminating any leading Re:'s.  Example:
  654. X *
  655. X *      Re: Reorganization of misc.jobs
  656. X *      ^   ^
  657. X */
  658. X
  659. Xchar *
  660. Xeat_re(s)
  661. Xchar *s;
  662. X{
  663. X
  664. X#if 1
  665. X    while (*s == 'r' || *s == 'R') {
  666. X        if (*(s+1) == 'e' || *(s+1) == 'E') {
  667. X            if (*(s+2) == ':')
  668. X                s += 3;
  669. X            else if ((*(s+2) == '^') && isdigit (*(s+3))) {
  670. X                s += 4;
  671. X                if (*s == ':')
  672. X                    ++s;
  673. X            } else
  674. X                break;
  675. X        } else
  676. X            break;
  677. X        while (isspace (*s))
  678. X            ++s;
  679. X    }
  680. X#else
  681. X    while (*s == 'R') {
  682. X        if (strncmp(s, "Re: ", 4) == 0)
  683. X            s += 4;
  684. X        else if (strncmp(s, "Re:", 3) == 0)
  685. X            s += 3;
  686. X        else if (strncmp(s, "Re^2: ", 6) == 0)
  687. X            s += 6;
  688. X        else
  689. X            break;
  690. X    }
  691. X#endif
  692. X
  693. X    return s;
  694. X}
  695. X
  696. X
  697. X/*
  698. X *  Hash the subjects (after eating the Re's off) for a quicker
  699. X *  thread search later.  We store the hashes for subjects in the
  700. X *  index file for speed.
  701. X */
  702. X
  703. Xlong
  704. Xhash_s(s)
  705. Xchar *s;
  706. X{
  707. X    long h = 0;
  708. X
  709. X    while (*s)
  710. X        h = h + (*s++ & 0xff);
  711. X
  712. X    return h;
  713. X}
  714. X
  715. X
  716. Xparse_headers(fd, h)
  717. Xint fd;
  718. Xstruct header *h;
  719. X{
  720. X    char buf[1024];
  721. X    char *p, *q;
  722. X    char flag;
  723. X    char *ptr;
  724. X    int found_from, found_subj;
  725. X    int n;
  726. X
  727. X    if ((n = read(fd, buf, 1024)) <= 0)
  728. X        return FALSE;
  729. X
  730. X    buf[n > 1023 ? 1023 : n] = '\0';
  731. X
  732. X    p = buf;
  733. X    while (p = index (p, '\n'))
  734. X        if (*(p + 1) == '\n') {
  735. X            *p = '\0';
  736. X            break;
  737. X        } else
  738. X            ++p;
  739. X
  740. X    p = buf;
  741. X
  742. X    h->from[0] = '\0';
  743. X    h->subject[0] = '\0';
  744. X    h->nore = h->subject;
  745. X    h->hash = 0;
  746. X
  747. X    found_from = FALSE;
  748. X    found_subj = FALSE;
  749. X    while (1) {
  750. X        q = p;
  751. X        while (*p && *p != '\n') {
  752. X            if ((unsigned char) *p & 0x7F < 32)
  753. X                *p = ' ';
  754. X            p++;
  755. X        }
  756. X        flag = *p;
  757. X        *p++ = '\0';
  758. X
  759. X        if ((!found_from) && (strncmp(q, "From: ", 6) == 0)) {
  760. X            if (ptr = index (&q[6], '('))
  761. X                ++ptr;
  762. X            else
  763. X                ptr = &q[6];
  764. X            strncpy (h->from, ptr, MAX_FROM);
  765. X            h->from[MAX_FROM-1] = '\0';
  766. X            if (ptr = index (h->from, ')'))
  767. X                *ptr = '\0';
  768. X        } else if ((!found_subj) && (strncmp(q, "Subject: ", 9) == 0)) {
  769. X            h->hash = hash_s(eat_re(&q[9]));
  770. X            strncpy(h->subject, &q[9], MAX_SUBJ);
  771. X            h->subject[MAX_SUBJ-1] = '\0';
  772. X            h->nore = eat_re(h->subject);
  773. X        }
  774. X
  775. X        if ((!flag) || (found_from && found_subj))
  776. X            break;
  777. X    }
  778. X
  779. X    return TRUE;
  780. X}
  781. X
  782. X
  783. X/* 
  784. X *  Write out a .tindex file.  Write the group name first so if
  785. X *  local indexing is done we can disambiguate between group name
  786. X *  hash collisions by looking at the index file.
  787. X */
  788. Xvoid
  789. Xdump_index(group)
  790. Xchar *group;
  791. X{
  792. X    int i;
  793. X    char buf[200];
  794. X    FILE *fp;
  795. X    char *p, *q;
  796. X    long l;
  797. X#ifndef    USE_UID
  798. X    char lockfn[64];
  799. X    int lockfd;
  800. X
  801. X    if (! local_index) {
  802. X#ifndef    OSK
  803. X        sprintf (lockfn, "/tmp/%-.10s", group);
  804. X        lockfd = creat (lockfn, 0, 0444);
  805. X#else    /* OSK */
  806. X        sprintf (lockfn, "/dd/TMP/%-.20s", group);
  807. X        for (p = lockfn; *p; ++p)
  808. X            if (((unsigned char) *p >= 0x80) || ((!isalnum (*p)) && (*p != '/')))
  809. X                *p = '_';
  810. X        lockfd = create (lockfn, 0, 033);
  811. X#endif    /* OSK */
  812. X        if (lockfd < 0) {
  813. X            sleep (1);
  814. X            return;
  815. X        }
  816. X    }
  817. X#endif    /* USE_UID */
  818. X
  819. X    fp = fopen(index_file, "w");
  820. X    if (fp == NULL)
  821. X#ifndef    USE_UID
  822. X        goto dump_index_finish;
  823. X#else    /* USE_UID */
  824. X        return;
  825. X#endif    /* USE_UID */
  826. X
  827. X    fprintf(fp, "%s\n", group);
  828. X    fprintf(fp, "%d\n", num_arts());
  829. X    for (i = 0; i < top; i++)
  830. X        if (arts[i].thread != -2) {
  831. X        p = arts[i].nore;
  832. X        q = arts[i].subject;
  833. X        l = p - q;
  834. X        fprintf(fp, "%ld\n%s\n%s\n%ld\n%ld\n",
  835. X                arts[i].artnum,
  836. X                arts[i].subject,
  837. X                arts[i].from,
  838. X                arts[i].hash,
  839. X#if 0
  840. X                (long) arts[i].nore - (long) arts[i].subject);
  841. X#else
  842. X                l);
  843. X#endif
  844. X    } else
  845. X        ++complete_expire;
  846. X
  847. X    fclose(fp);
  848. X#ifdef    USE_UID
  849. X#ifndef    OSK
  850. X    chmod(index_file, 0644);
  851. X#else    /* OSK */
  852. X    chmod(index_file, 013);
  853. X#endif    /* OSK */
  854. X#else    /* USE_UID */
  855. Xdump_index_finish:
  856. X    if (local_index)
  857. X#ifndef    OSK
  858. X        chmod(index_file, 0644);
  859. X#else    /* OSK */
  860. X        chmod(index_file, 013);
  861. X#endif    /* OSK */
  862. X    else if (lockfd != -1) {
  863. X        close (lockfd);
  864. X#ifndef    OSK
  865. X        chmod (lockfn, 0666);
  866. X#endif    /* OSK */
  867. X        unlink (lockfn);
  868. X#ifndef    OSK
  869. X        chmod(index_file, 0666);
  870. X#else    /* OSK */
  871. X        chmod(index_file, 033);
  872. X#endif    /* OSK */
  873. X    }
  874. X#endif    /* USE_UID */
  875. X}
  876. X
  877. X
  878. X/*
  879. X *  strncpy that stops at a newline and null terminates
  880. X */
  881. X
  882. Xmy_strncpy(p, q, n)
  883. Xchar *p;
  884. Xchar *q;
  885. Xint n;
  886. X{
  887. X
  888. X    while (n--) {
  889. X        if (!*q || *q == '\n')
  890. X            break;
  891. X        *p++ = *q++;
  892. X    }
  893. X    *p = '\0';
  894. X}
  895. X
  896. X
  897. X/*
  898. X *  Read in a .tindex file.
  899. X */
  900. Xvoid
  901. Xload_index()
  902. X{
  903. X    int i;
  904. X    long j;
  905. X    char buf[200];
  906. X    FILE *fp;
  907. X    int first = TRUE;
  908. X
  909. X    top = 0;
  910. X
  911. X    fp = fopen(index_file, "r");
  912. X    if (fp == NULL)
  913. X        return;
  914. X
  915. X    if (fgets(buf, 200, fp) == NULL
  916. X    ||  fgets(buf, 200, fp) == NULL) {
  917. X        fprintf(stderr, "one\n");
  918. X        goto corrupt_index;
  919. X    }
  920. X
  921. X    i = atol(buf);
  922. X    while (top < i) {
  923. X        if (top >= max_art)
  924. X            expand_art();
  925. X
  926. X        arts[top].thread = -2;
  927. X        arts[top].inthread = FALSE;
  928. X
  929. X        if (fgets(buf, 200, fp) == NULL) {
  930. X            fprintf(stderr, "two\n");
  931. X            goto corrupt_index;
  932. X        }
  933. X        arts[top].artnum = atol(buf);
  934. X
  935. X        if (fgets(buf, 200, fp) == NULL) {
  936. X            fprintf(stderr, "three\n");
  937. X            goto corrupt_index;
  938. X        }
  939. X
  940. X        my_strncpy(arts[top].subject, buf, MAX_SUBJ-1);
  941. X            
  942. X        if (fgets(buf, 200, fp) == NULL) {
  943. X            fprintf(stderr, "four\n");
  944. X            goto corrupt_index;
  945. X        }
  946. X        my_strncpy(arts[top].from, buf, MAX_FROM-1);
  947. X
  948. X        if (fgets(buf, 200, fp) == NULL) {
  949. X            fprintf(stderr, "five\n");
  950. X            goto corrupt_index;
  951. X        }
  952. X        arts[top].hash = atol(buf);
  953. X
  954. X        if (fgets(buf, 200, fp) == NULL) {
  955. X            fprintf(stderr, "six\n");
  956. X            goto corrupt_index;
  957. X        }
  958. X
  959. X        j = atol(buf);
  960. X#if 0
  961. X        if (j < 0 || j > 100) {
  962. X#if 0
  963. X            goto corrupt_index;
  964. X#else
  965. X            arts[top].nore = eat_re(arts[top].subject);
  966. X#endif
  967. X        } else
  968. X            arts[top].nore = arts[top].subject + j;
  969. X#else
  970. X        arts[top].nore = eat_re(arts[top].subject);
  971. X#endif
  972. X
  973. X        top++;
  974. X    }
  975. X
  976. X    fclose(fp);
  977. X    return;
  978. X
  979. Xcorrupt_index:
  980. X    fprintf(stderr, "index file %s corrupt\n", index_file);
  981. X    fprintf(stderr, "top = %d\n", top);
  982. X    exit(1);
  983. X    unlink(index_file);
  984. X    top = 0;
  985. X}
  986. X
  987. X
  988. X/*
  989. X *  Look in the local $HOME/.tindex (or wherever) directory for the
  990. X *  index file for the given group.  Hashing the group name gets
  991. X *  a number.  See if that #.1 file exists; if so, read first line.
  992. X *  Group we want?  If no, try #.2.  Repeat until no such file or
  993. X *  we find an existing file that matches our group.
  994. X */
  995. Xvoid
  996. Xfind_local_index(group)
  997. Xchar *group;
  998. X{
  999. X    unsigned long h;
  1000. X    static char buf[200];
  1001. X    int i;
  1002. X    char *p;
  1003. X    FILE *fp;
  1004. X
  1005. X    {
  1006. X        char *t = group;
  1007. X
  1008. X        h = *t++;
  1009. X        while (*t)
  1010. X            h = (h << 1) + (*t++ & 0xff);
  1011. X    }
  1012. X
  1013. X    i = 1;
  1014. X    while (1) {
  1015. X        sprintf(index_file, "%s/%lu.%d", indexdir, h, i);
  1016. X        fp = fopen(index_file, "r");
  1017. X        if (fp == NULL)
  1018. X            return;
  1019. X
  1020. X        if (fgets(buf, 200, fp) == NULL) {
  1021. X            fclose(fp);
  1022. X            return;
  1023. X        }
  1024. X        fclose(fp);
  1025. X
  1026. X        for (p = buf; *p && *p != '\n'; p++) ;
  1027. X        *p = '\0';
  1028. X
  1029. X        if (strcmp(buf, group) == 0)
  1030. X            return;
  1031. X
  1032. X        i++;
  1033. X    }
  1034. X}
  1035. X
  1036. X
  1037. X/*
  1038. X *  Run the index file updater only for the groups we've loaded.
  1039. X */
  1040. X
  1041. Xdo_update() {
  1042. X    int i;
  1043. X    char group_path[200];
  1044. X    char *p;
  1045. X#ifdef    OSK
  1046. X    int len = 0;
  1047. X#endif    /* OSK */
  1048. X    time_t tim;
  1049. X    struct tm *tt;
  1050. X
  1051. X    complete_count = 0;
  1052. X    complete_expire = 0;
  1053. X
  1054. X    for (i = 0; i < local_top; i++) {
  1055. X        strcpy(group_path, active[my_group[i]].name);
  1056. X        for (p = group_path; *p; p++)
  1057. X#ifndef    OSK
  1058. X            if (*p == '.')
  1059. X                *p = '/';
  1060. X#else    /* OSK */
  1061. X        {
  1062. X            if (*p == '.') {
  1063. X                *p = '/';
  1064. X                len = 0;
  1065. X            } else if ((! isalnum (*p)) && (! index ("$_", *p)))
  1066. X                *p = '_';
  1067. X            if (++len > 26)
  1068. X                while (*(p + 1) && (*(p + 1) != '.'))
  1069. X                    ++p;
  1070. X        }
  1071. X#endif    /* OSK */
  1072. X
  1073. X        index_group(active[my_group[i]].name, group_path);
  1074. X    }
  1075. X
  1076. X    time (&tim);
  1077. X    tt = localtime (&tim);
  1078. X    printf ("[%02d.%02d.%04d %2d:%2d] Collected %d articles",
  1079. X        tt -> tm_mday,
  1080. X        tt -> tm_mon + 1,
  1081. X        tt -> tm_year + 1900,
  1082. X        tt -> tm_hour,
  1083. X        tt -> tm_min,
  1084. X        complete_count);
  1085. X
  1086. X    if (complete_expire)
  1087. X        printf (" (%d articles expired)", complete_expire);
  1088. X    putchar ('\n');
  1089. X}
  1090. __END__OF__THIS__FILE__
  1091. if test -f 'curses.c' ; then
  1092.   echo 'File curses.c already exists, overwriting it'
  1093.   del 'curses.c'
  1094. fi
  1095. echo Extracting \"'curses.c'\"
  1096. sed "s/^X//" >'curses.c' <<'__END__OF__THIS__FILE__'
  1097. X
  1098. X/*
  1099. X *  This is a screen management library borrowed with permission from the
  1100. X *  Elm mail system (a great mailer--I highly recommend it!).
  1101. X *
  1102. X *  I've hacked this library to only provide what Tass needs.
  1103. X *
  1104. X *  Original copyright follows:
  1105. X */
  1106. X
  1107. X/*******************************************************************************
  1108. X *  The Elm Mail System  -  $Revision: 2.1 $   $State: Exp $
  1109. X *
  1110. X *             Copyright (c) 1986 Dave Taylor
  1111. X ******************************************************************************/
  1112. X
  1113. X#include <stdio.h>
  1114. X#ifndef    OSK
  1115. X#include <curses.h>
  1116. X#include <sys/ioctl.h>
  1117. X#else    /* OSK */
  1118. X#include <termcap.h>
  1119. X#include <sgstat.h>
  1120. Xchar    PC_, *UP, *BC;
  1121. Xshort    ospeed;
  1122. X#endif    /* OSK */
  1123. X#include "tass.h"
  1124. X
  1125. X#define        BACKSPACE    '\b'
  1126. X#define        VERY_LONG_STRING    2500
  1127. X
  1128. Xint LINES=23;
  1129. Xint COLS=80;
  1130. X
  1131. Xint inverse_okay = TRUE;
  1132. X
  1133. X/*
  1134. X#ifdef BSD
  1135. X#  ifndef BSD4_1
  1136. X#    include <sgtty.h>
  1137. X#  else
  1138. X#    include <termio.h>
  1139. X#  endif
  1140. X# else
  1141. X#  include <termio.h>
  1142. X#endif
  1143. X*/
  1144. X
  1145. X#include <ctype.h>
  1146. X
  1147. X/*
  1148. X#ifdef BSD
  1149. X#undef tolower
  1150. X#endif
  1151. X*/
  1152. X
  1153. X#define TTYIN    0
  1154. X
  1155. X#ifdef SHORTNAMES
  1156. X# define _clearinverse    _clrinv
  1157. X# define _cleartoeoln    _clrtoeoln
  1158. X# define _cleartoeos    _clr2eos
  1159. X#endif
  1160. X
  1161. X#ifndef BSD
  1162. X#ifndef    OSK
  1163. Xstruct termio _raw_tty, 
  1164. X              _original_tty;
  1165. X#else    /* OSK */
  1166. Xstruct sgbuf    _raw_tty, 
  1167. X        _original_tty;
  1168. X#endif    /* OSK */
  1169. X#else
  1170. X#define TCGETA    TIOCGETP
  1171. X#define TCSETAW    TIOCSETP
  1172. X
  1173. Xstruct sgttyb _raw_tty,
  1174. X          _original_tty;
  1175. X#endif
  1176. X
  1177. Xstatic int _inraw = 0;                  /* are we IN rawmode?    */
  1178. X
  1179. X#define DEFAULT_LINES_ON_TERMINAL    24
  1180. X#define DEFAULT_COLUMNS_ON_TERMINAL    80
  1181. X
  1182. Xstatic int _memory_locked = 0;        /* are we IN memlock??   */
  1183. X
  1184. Xstatic int _intransmit;            /* are we transmitting keys? */
  1185. X
  1186. Xstatic
  1187. Xchar *_clearscreen, *_moveto, *_cleartoeoln, *_cleartoeos,
  1188. X    *_setinverse, *_clearinverse, *_setunderline, *_clearunderline;
  1189. X
  1190. X# define    K_UP        0
  1191. X# define    K_DOWN        1
  1192. X# define    K_LEFT        2
  1193. X# define    K_RIGHT        3
  1194. X# define    K_PUP        4
  1195. X# define    K_PDOWN        5
  1196. X
  1197. X# define    K_MAX        6
  1198. X
  1199. Xstatic
  1200. Xchar *_spckey[K_MAX];
  1201. Xstatic
  1202. Xchar *_spckeytc[K_MAX] = {
  1203. X    "ku", "kd", "kl", "kr", "kP", "kN"
  1204. X};
  1205. X
  1206. Xstatic
  1207. Xint _lines,_columns;
  1208. X
  1209. Xstatic char _terminal[1024];              /* Storage for terminal entry */
  1210. Xstatic char _capabilities[1024];           /* String for cursor motion */
  1211. X
  1212. Xstatic char *ptr = _capabilities;    /* for buffering         */
  1213. X
  1214. Xint    outchar();            /* char output for tputs */
  1215. Xchar  *tgetstr(),                    /* Get termcap capability */
  1216. X      *tgoto();                /* and the goto stuff    */
  1217. X
  1218. XInitScreen()
  1219. X{
  1220. Xint  tgetent(),      /* get termcap entry */
  1221. X     err;
  1222. Xchar termname[40];
  1223. Xchar *strcpy(), *getenv();
  1224. Xint i;
  1225. X    
  1226. X    if (getenv("TERM") == NULL) {
  1227. X        fprintf(stderr,
  1228. X          "TERM variable not set; Tass requires screen capabilities\n");
  1229. X        return(FALSE);
  1230. X    }
  1231. X    if (strcpy(termname, getenv("TERM")) == NULL) {
  1232. X        fprintf(stderr,"Can't get TERM variable\n");
  1233. X        return(FALSE);
  1234. X    }
  1235. X    if ((err = tgetent(_terminal, termname)) != 1) {
  1236. X        fprintf(stderr,"Can't get entry for TERM\n");
  1237. X        return(FALSE);
  1238. X    }
  1239. X
  1240. X    /* load in all those pesky values */
  1241. X    _clearscreen       = tgetstr("cl", &ptr);
  1242. X    _moveto            = tgetstr("cm", &ptr);
  1243. X    _cleartoeoln       = tgetstr("ce", &ptr);
  1244. X    _cleartoeos        = tgetstr("cd", &ptr);
  1245. X    _lines                 = tgetnum("li");
  1246. X    _columns       = tgetnum("co");
  1247. X    _setinverse        = tgetstr("so", &ptr);
  1248. X    _clearinverse      = tgetstr("se", &ptr);
  1249. X    _setunderline      = tgetstr("us", &ptr);
  1250. X    _clearunderline    = tgetstr("ue", &ptr);
  1251. X
  1252. X    if (!_clearscreen) {
  1253. X        fprintf(stderr,
  1254. X            "Terminal must have clearscreen (cl) capability\n");
  1255. X        return(FALSE);
  1256. X    }
  1257. X    if (!_moveto) {
  1258. X        fprintf(stderr,
  1259. X            "Terminal must have cursor motion (cm)\n");
  1260. X        return(FALSE);
  1261. X    }
  1262. X    if (!_cleartoeoln) {
  1263. X        fprintf(stderr,
  1264. X            "Terminal must have clear to end-of-line (ce)\n");
  1265. X        return(FALSE);
  1266. X    }
  1267. X    if (!_cleartoeos) {
  1268. X        fprintf(stderr,
  1269. X            "Terminal must have clear to end-of-screen (cd)\n");
  1270. X        return(FALSE);
  1271. X    }
  1272. X    if (_lines == -1)
  1273. X        _lines = DEFAULT_LINES_ON_TERMINAL;
  1274. X    if (_columns == -1)
  1275. X        _columns = DEFAULT_COLUMNS_ON_TERMINAL;
  1276. X
  1277. X    for (i = 0; i < K_MAX; ++i)
  1278. X        _spckey[i] = tgetstr (_spckeytc[i], &ptr);
  1279. X
  1280. X    return(TRUE);
  1281. X}
  1282. X
  1283. XScreenSize(lines, columns)
  1284. Xint *lines, *columns;
  1285. X{
  1286. X    /** returns the number of lines and columns on the display. **/
  1287. X
  1288. X    if (_lines == 0) _lines = DEFAULT_LINES_ON_TERMINAL;
  1289. X    if (_columns == 0) _columns = DEFAULT_COLUMNS_ON_TERMINAL;
  1290. X
  1291. X    *lines = _lines - 1;        /* assume index from zero*/
  1292. X    *columns = _columns;        /* assume index from one */
  1293. X}
  1294. X
  1295. XClearScreen()
  1296. X{
  1297. X    /* clear the screen: returns -1 if not capable */
  1298. X
  1299. X    tputs(_clearscreen, 1, outchar);
  1300. X    fflush(stdout);      /* clear the output buffer */
  1301. X}
  1302. X
  1303. XMoveCursor(row, col)
  1304. Xint row, col;
  1305. X{
  1306. X    /** move cursor to the specified row column on the screen.
  1307. X            0,0 is the top left! **/
  1308. X
  1309. X    char *stuff, *tgoto();
  1310. X
  1311. X    stuff = tgoto(_moveto, col, row);
  1312. X    tputs(stuff, 1, outchar);
  1313. X    fflush(stdout);
  1314. X}
  1315. X
  1316. XCleartoEOLN()
  1317. X{
  1318. X    /** clear to end of line **/
  1319. X
  1320. X    tputs(_cleartoeoln, 1, outchar);
  1321. X    fflush(stdout);  /* clear the output buffer */
  1322. X}
  1323. X
  1324. XCleartoEOS()
  1325. X{
  1326. X    /** clear to end of screen **/
  1327. X
  1328. X    tputs(_cleartoeos, 1, outchar);
  1329. X    fflush(stdout);  /* clear the output buffer */
  1330. X}
  1331. X
  1332. XStartInverse()
  1333. X{
  1334. X    /** set inverse video mode **/
  1335. X
  1336. X    if (_setinverse && inverse_okay)
  1337. X        tputs(_setinverse, 1, outchar);
  1338. X/*    fflush(stdout);    */
  1339. X}
  1340. X
  1341. X
  1342. XEndInverse()
  1343. X{
  1344. X    /** compliment of startinverse **/
  1345. X
  1346. X    if (_clearinverse && inverse_okay)
  1347. X        tputs(_clearinverse, 1, outchar);
  1348. X/*    fflush(stdout);    */
  1349. X}
  1350. X
  1351. X#if 0
  1352. XStartUnderline()
  1353. X{
  1354. X    /** start underline mode **/
  1355. X
  1356. X    if (!_setunderline)
  1357. X        return(-1);
  1358. X
  1359. X    tputs(_setunderline, 1, outchar);
  1360. X    fflush(stdout);
  1361. X    return(0);
  1362. X}
  1363. X
  1364. X
  1365. XEndUnderline()
  1366. X{
  1367. X    /** the compliment of start underline mode **/
  1368. X
  1369. X    if (!_clearunderline)
  1370. X        return(-1);
  1371. X
  1372. X    tputs(_clearunderline, 1, outchar);
  1373. X    fflush(stdout);
  1374. X    return(0);
  1375. X}
  1376. X#endif
  1377. X
  1378. XRawState()
  1379. X{
  1380. X    /** returns either 1 or 0, for ON or OFF **/
  1381. X
  1382. X    return( _inraw );
  1383. X}
  1384. X
  1385. XRaw(state)
  1386. Xint state;
  1387. X{
  1388. X    /** state is either TRUE or FALSE, as indicated by call **/
  1389. X
  1390. X    if (state == FALSE && _inraw) {
  1391. X#ifndef    OSK
  1392. X      (void) ioctl(TTYIN, TCSETAW, &_original_tty);
  1393. X#else    /* OSK */
  1394. X      (void) _ss_opt (TTYIN, &_original_tty);
  1395. X#endif    /* OSK */
  1396. X      _inraw = 0;
  1397. X    }
  1398. X    else if (state == TRUE && ! _inraw) {
  1399. X
  1400. X#ifndef    OSK
  1401. X      (void) ioctl(TTYIN, TCGETA, &_original_tty);    /** current setting **/
  1402. X
  1403. X      (void) ioctl(TTYIN, TCGETA, &_raw_tty);    /** again! **/
  1404. X#ifdef BSD
  1405. X      _raw_tty.sg_flags &= ~(ECHO | CRMOD);    /* echo off */
  1406. X      _raw_tty.sg_flags |= CBREAK;    /* raw on    */
  1407. X#else
  1408. X      _raw_tty.c_lflag &= ~(ICANON | ECHO);    /* noecho raw mode        */
  1409. X
  1410. X      _raw_tty.c_cc[VMIN] = '\01';    /* minimum # of chars to queue    */
  1411. X      _raw_tty.c_cc[VTIME] = '\0';    /* minimum time to wait for input */
  1412. X
  1413. X#endif
  1414. X      (void) ioctl(TTYIN, TCSETAW, &_raw_tty);
  1415. X#else    /* OSK */
  1416. X      (void) _gs_opt (TTYIN, &_original_tty);
  1417. X      _raw_tty = _original_tty;
  1418. X      _raw_tty.sg_echo = 0;
  1419. X      _raw_tty.sg_pause = 0;
  1420. X      _raw_tty.sg_alf = 0;
  1421. X      _raw_tty.sg_psch = 0;
  1422. X      _raw_tty.sg_eofch = 0;
  1423. X      
  1424. X      (void) _ss_opt (TTYIN, &_raw_tty);
  1425. X#endif    /* OSK */
  1426. X
  1427. X      _inraw = 1;
  1428. X    }
  1429. X}
  1430. X
  1431. Xint
  1432. XReadCh()
  1433. X{
  1434. X    /** read a character with Raw mode set! **/
  1435. X
  1436. X    register int result;
  1437. X    char ch;
  1438. X    register int i, j, n;
  1439. X    register char *spc;
  1440. X
  1441. X    spc = NULL;
  1442. X    do {
  1443. X        if (spc) {
  1444. X#ifdef    OSK
  1445. X            tsleep (4);
  1446. X            if (_gs_rdy (0) < 1)
  1447. X                tsleep (50 | (1 << 31));
  1448. X            if (_gs_rdy (0) < 1)
  1449. X#else    /* OSK */
  1450. X#ifdef    FIONREAD
  1451. X#define    CH_READ        FIONREAD
  1452. X#else    /* FIONREAD */
  1453. X#ifdef    TCRDCHK
  1454. X#define    CH_READ        TCRDCHK
  1455. X#else    /* TCRDCHK */
  1456. X    Panic!
  1457. X#endif    /* TCRDCHK */
  1458. X#endif    /* FIONREAD */
  1459. X            int tmp;
  1460. X
  1461. X            ioctl (0, CH_READ, &tmp);
  1462. X            if (tmp < 1)
  1463. X                nap (200);
  1464. X            ioctl (0, CH_READ, &tmp);
  1465. X            if (tmp < 1)
  1466. X#endif    /* OSK */
  1467. X                spc = NULL;
  1468. X        }
  1469. X        if ((result = read(0, &ch, 1)) != 1)
  1470. X            break;
  1471. X        if (!spc) {
  1472. X            for (i = 0; i < K_MAX; ++i)
  1473. X                if (_spckey[i] && (_spckey[i][0] == ch)) {
  1474. X                    spc = _spckey[i];
  1475. X                    n = 1;
  1476. X                    break;
  1477. X                }
  1478. X        } else if (ch != spc[n]) {
  1479. X            for (j = 0; j < K_MAX; ++j)
  1480. X                if (!_spckey[j])
  1481. X                    continue;
  1482. X                else if (spc[0]) {
  1483. X                    if ((!strncmp (spc, _spckey[j], n - 1)) && (_spckey[j][n] == ch))
  1484. X                        break;
  1485. X                } else if (spc[0] == _spckey[j][0]) {
  1486. X                    if (n > 1) {
  1487. X                        if ((!strncmp (spc + 1, _spckey[j] + 1, n - 2)) && (_spckey[j][n] == ch))
  1488. X                            break;
  1489. X                    } else if (_spckey[j][n] == ch)
  1490. X                        break;
  1491. X                }
  1492. X            if (j < K_MAX) {
  1493. X                spc = _spckey[j];
  1494. X                i = j;
  1495. X                ++n;
  1496. X            } else {
  1497. X                spc = NULL;
  1498. X                result = -1;
  1499. X            }
  1500. X        } else
  1501. X            ++n;
  1502. X        if (spc && (!spc[n])) {
  1503. X            spc = NULL;
  1504. X            switch (i) {
  1505. X                case K_UP:
  1506. X                    ch = ctrl('P');
  1507. X                    break;
  1508. X                case K_DOWN:
  1509. X                    ch = ctrl('N');
  1510. X                    break;
  1511. X                case K_LEFT:
  1512. X                    ch = ctrl('B');
  1513. X                    break;
  1514. X                case K_RIGHT:
  1515. X                    ch = ctrl('F');
  1516. X                    break;
  1517. X                case K_PUP:
  1518. X                    ch = ctrl('Z');
  1519. X                    break;
  1520. X                case K_PDOWN:
  1521. X                    ch = ctrl('V');
  1522. X                    break;
  1523. X            }
  1524. X        }
  1525. X    } while (spc || (result < 0));
  1526. X        return((result <= 0 ) ? EOF : ch & 0x7F);
  1527. X}
  1528. X
  1529. X
  1530. Xoutchar(c)
  1531. Xchar c;
  1532. X{
  1533. X    /** output the given character.  From tputs... **/
  1534. X    /** Note: this CANNOT be a macro!              **/
  1535. X
  1536. X    putc(c, stdout);
  1537. X}
  1538. X
  1539. X#ifdef    NO_NAP
  1540. Xnap (n)
  1541. Xint n;
  1542. X{
  1543. X    int    t;
  1544. X
  1545. X    for (t = 100 * n; t > 0; --t)
  1546. X        ;
  1547. X}
  1548. X#endif    /* NO_NAP */
  1549. __END__OF__THIS__FILE__
  1550. if test -f 'group.c' ; then
  1551.   echo 'File group.c already exists, overwriting it'
  1552.   del 'group.c'
  1553. fi
  1554. echo Extracting \"'group.c'\"
  1555. sed "s/^X//" >'group.c' <<'__END__OF__THIS__FILE__'
  1556. X
  1557. X
  1558. X#include    <stdio.h>
  1559. X#include    <signal.h>
  1560. X#ifdef        REGEXP
  1561. X#include    <regexp.h>
  1562. X#endif        /* REGEXP */
  1563. X#ifdef    OSK
  1564. X#include    <ctype.h>
  1565. X#endif    /* OSK */
  1566. X#include    "tass.h"
  1567. X
  1568. X#ifdef    GET_DIST
  1569. Xextern char    *index ();
  1570. X#endif    /* GET_DIST */
  1571. X
  1572. Xint index_point;
  1573. Xint first_subj_on_screen;
  1574. Xint last_subj_on_screen;
  1575. Xchar subject_search_string[LEN+1];    /* last search pattern */
  1576. Xextern int cur_groupnum;
  1577. Xextern int last_resp;        /* page.c */
  1578. Xextern int this_resp;        /* page.c */
  1579. Xextern int space_mode;        /* select.c */
  1580. Xextern char *cvers;
  1581. X
  1582. Xchar *glob_group;
  1583. X
  1584. X
  1585. X#ifdef SIGTSTP
  1586. Xvoid
  1587. Xgroup_susp(i)
  1588. Xint i;
  1589. X{
  1590. X
  1591. X    Raw(FALSE);
  1592. X    putchar('\n');
  1593. X    signal(SIGTSTP, SIG_DFL);
  1594. X    kill(0, SIGTSTP);
  1595. X
  1596. X    signal(SIGTSTP, group_susp);
  1597. X    Raw(TRUE);
  1598. X    mail_setup();
  1599. X    show_group_page(glob_group, TRUE);
  1600. X}
  1601. X#endif
  1602. X
  1603. X
  1604. Xgroup_page(group)
  1605. Xchar *group;
  1606. X{
  1607. X    char ch;
  1608. X    int i, n;
  1609. X    char group_path[200];
  1610. X    char *p;
  1611. X    char buf[200];
  1612. X
  1613. X    glob_group = group;
  1614. X
  1615. X    strcpy(group_path, group);        /* turn comp.unix.amiga into */
  1616. X    for (p = group_path; *p; p++)        /* comp/unix/amiga */
  1617. X        if (*p == '.')
  1618. X            *p = '/';
  1619. X#ifdef    OSK
  1620. X        else if ((!isalnum (*p)) || ((unsigned char) *p >= 0x80))
  1621. X            *p = '_';
  1622. X#endif    /* OSK */
  1623. X
  1624. X    last_resp = -1;
  1625. X    this_resp = -1;
  1626. X    index_group(group, group_path);        /* update index file */
  1627. X    read_newsrc_line(group);        /* get sequencer information */
  1628. X
  1629. X    if (space_mode) {
  1630. X        for (i = 0; i < top_base; i++)
  1631. X            if (new_responses(i))
  1632. X                break;
  1633. X        if (i < top_base)
  1634. X            index_point = i;
  1635. X        else
  1636. X            index_point = top_base - 1;
  1637. X    } else
  1638. X        index_point = top_base - 1;
  1639. X
  1640. X    show_group_page(group, TRUE);
  1641. X
  1642. X    while (1) {
  1643. X        if ((n = ReadCh()) == EOF)
  1644. X            longjmp (jmp_buffer, 1);
  1645. X        ch = (char) n;
  1646. X
  1647. X        if (ch > '0' && ch <= '9') {    /* 0 goes to basenote */
  1648. X            prompt_subject_num(ch, group);
  1649. X        } else switch (ch) {
  1650. X            case 'I':    /* toggle inverse video */
  1651. X                inverse_okay = !inverse_okay;
  1652. X                if (inverse_okay)
  1653. X                    info_message("Inverse video enabled");
  1654. X                else
  1655. X                    info_message("Inverse video disabled");
  1656. X                break;
  1657. X
  1658. X            case 's':    /* subscribe to this group */
  1659. X                subscribe(group, ':', my_group[cur_groupnum],
  1660. X                                    TRUE);
  1661. X                sprintf(buf, "subscribed to %s", group);
  1662. X                info_message(buf);
  1663. X                break;
  1664. X
  1665. X            case 'u':    /* unsubscribe to this group */
  1666. X                subscribe(group, '!', my_group[cur_groupnum],
  1667. X                                    TRUE);
  1668. X                sprintf(buf, "unsubscribed to %s", group);
  1669. X                info_message(buf);
  1670. X                break;
  1671. X
  1672. X            case 'g':    /* choose a new group by name */
  1673. X                n = choose_new_group();
  1674. X                if (n >= 0 && n != cur_groupnum) {
  1675. X                    fix_new_highest(cur_groupnum);
  1676. X                    cur_groupnum = n;
  1677. X                    index_point = -3;
  1678. X                    goto group_done;
  1679. X                }
  1680. X                break;
  1681. X
  1682. X            case 'c':    /* catchup--mark all articles as read */
  1683. X                if (prompt_yn("Mark everything as read? (y/n): ")) {
  1684. X                for (n = 0; n < top; n++)
  1685. X                    arts[n].unread = 0;
  1686. X                show_group_page(group, FALSE);
  1687. X                info_message("All articles marked as read");
  1688. X                }
  1689. X                break;
  1690. X
  1691. X#ifdef    USE_ARROW
  1692. X            case 27:    /* common arrow keys */
  1693. X                ch = ReadCh();
  1694. X                if (ch == '[' || ch == 'O')
  1695. X                    ch = ReadCh();
  1696. X                switch (ch) {
  1697. X                case 'A':
  1698. X                case 'D':
  1699. X                case 'i':
  1700. X                    goto group_up;
  1701. X
  1702. X                case 'B':
  1703. X                case 'I':
  1704. X                case 'C':
  1705. X                    goto group_down;
  1706. X                }
  1707. X                break;
  1708. X#endif    /* USE_ARROW */
  1709. X
  1710. X            case 'n':    /* next group */
  1711. X                clear_message();
  1712. X                if (cur_groupnum + 1 >= local_top)
  1713. X                    info_message("No more groups");
  1714. X                else {
  1715. X                    fix_new_highest(cur_groupnum);
  1716. X                    cur_groupnum++;
  1717. X                    index_point = -3;
  1718. X                    space_mode = FALSE;
  1719. X                    goto group_done;
  1720. X                }
  1721. X                break;
  1722. X
  1723. X            case 'p':    /* previous group */
  1724. X                clear_message();
  1725. X                if (cur_groupnum <= 0)
  1726. X                    info_message("No previous group");
  1727. X                else {
  1728. X                    fix_new_highest(cur_groupnum);
  1729. X                    cur_groupnum--;
  1730. X                    index_point = -3;
  1731. X                    space_mode = FALSE;
  1732. X                    goto group_done;
  1733. X                }
  1734. X                break;
  1735. X
  1736. X            case ' ':
  1737. X                if (top_base <= 0)
  1738. X                    info_message("*** No Articles ***");
  1739. X                else if (last_subj_on_screen == top_base)
  1740. X                    info_message("*** End of Articles ***");
  1741. X                else
  1742. X                    clear_message();
  1743. X                break;
  1744. X
  1745. X            case '\t':
  1746. X                fix_new_highest(cur_groupnum);
  1747. X                space_mode = TRUE;
  1748. X
  1749. X                if (index_point < 0
  1750. X                || (n=next_unread((int) base[index_point]))<0) {
  1751. X                    for (i = cur_groupnum+1;
  1752. X                            i < local_top; i++)
  1753. X                        if (unread[i] > 0)
  1754. X                            break;
  1755. X                    if (i >= local_top)
  1756. X                        goto group_done;
  1757. X
  1758. X                    cur_groupnum = i;
  1759. X                    index_point = -3;
  1760. X                    goto group_done;
  1761. X                }
  1762. X                index_point = show_page(n, group, group_path);
  1763. X                if (index_point < 0)
  1764. X                    goto group_done;
  1765. X                show_group_page(group, TRUE);
  1766. X                break;
  1767. X    
  1768. X
  1769. X            case 'N':    /* go to next unread article */
  1770. X                if (index_point < 0) {
  1771. X                    info_message("No next unread article");
  1772. X                    break;
  1773. X                }
  1774. X
  1775. X                n = next_unread( (int) base[index_point]);
  1776. X                if (n == -1)
  1777. X                    info_message("No next unread article");
  1778. X                else {
  1779. X                    index_point =
  1780. X                        show_page(n, group, group_path, TRUE);
  1781. X                    if (index_point < 0) {
  1782. X                        fix_new_highest(cur_groupnum);
  1783. X                        space_mode = FALSE;
  1784. X                        goto group_done;
  1785. X                    }
  1786. X                    show_group_page(group, TRUE);
  1787. X                }
  1788. X                break;
  1789. X
  1790. X            case 'P':    /* go to previous unread article */
  1791. X                if (index_point < 0) {
  1792. X                    info_message("No previous unread article");
  1793. X                    break;
  1794. X                }
  1795. X
  1796. X                n = prev_response( (int) base[index_point]);
  1797. X                n = prev_unread(n);
  1798. X                if (n == -1)
  1799. X                    info_message("No previous unread article");
  1800. X                else {
  1801. X                    index_point =
  1802. X                        show_page(n, group, group_path, TRUE);
  1803. X                    if (index_point < 0) {
  1804. X                        fix_new_highest(cur_groupnum);
  1805. X                        space_mode = FALSE;
  1806. X                        goto group_done;
  1807. X                    }
  1808. X                    show_group_page(group, TRUE);
  1809. X                }
  1810. X                break;
  1811. X
  1812. X            case 'w':    /* post a basenote */
  1813. X                post_base(group);
  1814. X                update_newsrc(group, my_group[cur_groupnum]);
  1815. X                index_group(group, group_path);
  1816. X                read_newsrc_line(group);
  1817. X                index_point = top_base - 1;
  1818. X                show_group_page(group, TRUE);
  1819. X                break;
  1820. X
  1821. X            case 't':    /* return to group selection page */
  1822. X            case ctrl('B'):    /* cursor key */
  1823. X                fix_new_highest(cur_groupnum);
  1824. X                goto group_done;
  1825. X
  1826. X#ifndef    OSK
  1827. X            case '\r':
  1828. X#else    /* OSK */
  1829. X            case '\l':
  1830. X#endif    /* OSK */
  1831. X            case '\n':    /* read current basenote */
  1832. X            case ctrl('F'):    /* cursor key */
  1833. X                if (index_point < 0) {
  1834. X                    info_message("*** No Articles ***");
  1835. X                    break;
  1836. X                }
  1837. X                index_point = show_page((int) base[index_point],
  1838. X                            group, group_path, TRUE);
  1839. X                if (index_point < 0) {
  1840. X                    fix_new_highest(cur_groupnum);
  1841. X                    space_mode = FALSE;
  1842. X                    goto group_done;
  1843. X                }
  1844. X                show_group_page(group, TRUE);
  1845. X                break;
  1846. X
  1847. X            case ctrl('D'):        /* page down */
  1848. X            case ctrl('V'):        /* full page down */
  1849. X                if (!top_base || index_point == top_base - 1)
  1850. X                    break;
  1851. X
  1852. X                erase_subject_arrow();
  1853. X                index_point += (ch == ctrl('V')) ? 
  1854. X                        NOTESLINES :
  1855. X                        NOTESLINES / 2;
  1856. X                if (index_point >= top_base)
  1857. X                    index_point = top_base - 1;
  1858. X
  1859. X                if (index_point < first_subj_on_screen
  1860. X                || index_point >= last_subj_on_screen)
  1861. X                    show_group_page(group, TRUE);
  1862. X                else
  1863. X                    draw_subject_arrow();
  1864. X                break;
  1865. X
  1866. X            case '-':    /* go to last viewed article */
  1867. X                if (this_resp < 0) {
  1868. X                    info_message("No last message");
  1869. X                    break;
  1870. X                }
  1871. X                index_point = show_page(this_resp,
  1872. X                            group, group_path, TRUE);
  1873. X                if (index_point < 0) {
  1874. X                    fix_new_highest(cur_groupnum);
  1875. X                    space_mode = FALSE;
  1876. X                    goto group_done;
  1877. X                }
  1878. X                show_group_page(group, TRUE);
  1879. X                break;
  1880. X
  1881. X            case ctrl('U'):        /* page up */
  1882. X            case ctrl('Z'):        /* full page up */
  1883. X                if (!top_base)
  1884. X                    break;
  1885. X
  1886. X                erase_subject_arrow();
  1887. X                index_point -= (ch == ctrl('Z')) ?
  1888. X                        NOTESLINES :
  1889. X                        NOTESLINES / 2;
  1890. X                if (index_point < 0)
  1891. X                    index_point = 0;
  1892. X                if (index_point < first_subj_on_screen
  1893. X                || index_point >= last_subj_on_screen)
  1894. X                    show_group_page(group, TRUE);
  1895. X                else
  1896. X                    draw_subject_arrow();
  1897. X                break;
  1898. X
  1899. X            case 'v':
  1900. X                info_message(cvers);
  1901. X                break;
  1902. X
  1903. X            case '!':
  1904. X                shell_escape();
  1905. X                show_group_page(group, TRUE);
  1906. X                break;
  1907. X
  1908. X            case ctrl('N'):
  1909. X            case 'j':        /* line down */
  1910. X#ifdef    USE_ARROW
  1911. Xgroup_down:
  1912. X#endif    /* USE_ARROW */
  1913. X                if (!top_base || index_point + 1 >= top_base)
  1914. X                    break;
  1915. X
  1916. X                erase_subject_arrow();
  1917. X                index_point++;
  1918. X                if (index_point >= last_subj_on_screen)
  1919. X                    show_group_page(group, FALSE);
  1920. X                else
  1921. X                    draw_subject_arrow();
  1922. X                break;
  1923. X
  1924. X            case ctrl('P'):
  1925. X            case 'k':        /* line up */
  1926. X#ifdef    USE_ARROW
  1927. Xgroup_up:
  1928. X#endif    /* USE_ARROW */
  1929. X                if (!top_base || !index_point)
  1930. X                    break;
  1931. X
  1932. X                erase_subject_arrow();
  1933. X                index_point--;
  1934. X                if (index_point + 1 <= first_subj_on_screen)
  1935. X                    show_group_page(group, FALSE);
  1936. X                else
  1937. X                    draw_subject_arrow();
  1938. X                break;
  1939. X
  1940. X            case ctrl('R'):
  1941. X            case ctrl('L'):
  1942. X            case ctrl('W'):
  1943. X            case 'i':        /* return to index */
  1944. X                    show_group_page(group, FALSE);
  1945. X                    break;
  1946. X
  1947. X            case '/':        /* forward search */
  1948. X                    search_subject(TRUE, group);
  1949. X                    break;
  1950. X
  1951. X            case '?':        /* backward search */
  1952. X                    search_subject(FALSE, group);
  1953. X                    break;
  1954. X
  1955. X#ifndef    OSK
  1956. X            case 'q':        /* quit */
  1957. X                    index_point = -2;
  1958. X                    fix_new_highest(cur_groupnum);
  1959. X                    space_mode = FALSE;
  1960. X                    goto group_done;
  1961. X#endif    /* OSK */
  1962. X
  1963. X            case 'h':
  1964. X                tass_group_help();
  1965. X                show_group_page(group, TRUE);
  1966. X                break;
  1967. X
  1968. X            default:
  1969. X                info_message("Bad command.  Type 'h' for help.");
  1970. X        }
  1971. X    }
  1972. X
  1973. Xgroup_done:
  1974. X    update_newsrc(group, my_group[cur_groupnum]);
  1975. X
  1976. X    if (index_point == -2)
  1977. X        tass_done(0);
  1978. X}
  1979. X
  1980. X
  1981. X/*
  1982. X *  Correct highest[] for the group selection page display since
  1983. X *  new articles may have been read or marked unread
  1984. X */
  1985. X
  1986. Xfix_new_highest(groupnum)
  1987. Xint groupnum;
  1988. X{
  1989. X    int i;
  1990. X    int sum = 0;
  1991. X
  1992. X    for (i = 0; i < top; i++)
  1993. X        if (arts[i].unread)
  1994. X            sum++;
  1995. X
  1996. X    unread[groupnum] = sum;
  1997. X}
  1998. X
  1999. X
  2000. Xshow_mail () {
  2001. X    if (mail_check()) {            /* you have mail message in */
  2002. X        MoveCursor(0, COLS - 14);        /* upper right */
  2003. X        printf("you have mail");
  2004. X        fflush (stdout);
  2005. X    }
  2006. X}
  2007. X
  2008. Xshow_group_page(group, clr)
  2009. Xchar *group;
  2010. Xint clr;
  2011. X{
  2012. X    int i;
  2013. X    int n;
  2014. X    char resps[10];
  2015. X    char new_resps;
  2016. X    int respnum;
  2017. X
  2018. X#ifdef SIGTSTP
  2019. X    signal(SIGTSTP, group_susp);
  2020. X#endif
  2021. X
  2022. X    if (clr) {
  2023. X        ClearScreen();
  2024. X        printf("%s\r\012", nice_time());    /* time in upper left */
  2025. X        center_line(1, group);
  2026. X    }
  2027. X
  2028. X    show_mail ();
  2029. X
  2030. X    MoveCursor(INDEX_TOP, 0);
  2031. X
  2032. X    first_subj_on_screen = (index_point / NOTESLINES) * NOTESLINES;
  2033. X    if (first_subj_on_screen < 0)
  2034. X        first_subj_on_screen = 0;
  2035. X
  2036. X    last_subj_on_screen = first_subj_on_screen + NOTESLINES;
  2037. X    if (last_subj_on_screen >= top_base) {
  2038. X        last_subj_on_screen = top_base;
  2039. X        first_subj_on_screen = top_base - NOTESLINES;
  2040. X
  2041. X        if (first_subj_on_screen < 0)
  2042. X            first_subj_on_screen = 0;
  2043. X    }
  2044. X
  2045. X    for (i = first_subj_on_screen; i < last_subj_on_screen; i++) {
  2046. X        if (new_responses(i))
  2047. X            new_resps = '+';
  2048. X        else
  2049. X            new_resps = ' ';
  2050. X
  2051. X        n = nresp(i);
  2052. X        if (n)
  2053. X            sprintf(resps, "%4d", n);
  2054. X        else
  2055. X            strcpy(resps, "    ");
  2056. X
  2057. X        respnum = base[i];
  2058. X
  2059. X        MoveCursor(INDEX_TOP + i - first_subj_on_screen, 3);
  2060. X        printf("%4d %c %s", i + 1, new_resps, arts[respnum].subject);
  2061. X        CleartoEOLN ();
  2062. X        MoveCursor(INDEX_TOP + i - first_subj_on_screen, COLS - 35);
  2063. X        printf ("%s %-.30s", resps, arts[respnum].from);
  2064. X        MoveCursor(INDEX_TOP + i - first_subj_on_screen, COLS - 1);
  2065. X        CleartoEOLN ();
  2066. X    }
  2067. X
  2068. X    if (top_base <= 0)
  2069. X        info_message("*** No Articles ***");
  2070. X    else if (last_subj_on_screen == top_base)
  2071. X        info_message("*** End of Articles ***");
  2072. X
  2073. X    if (top_base > 0)
  2074. X        draw_subject_arrow();
  2075. X}
  2076. X
  2077. Xdraw_subject_arrow() {
  2078. X
  2079. X    draw_arrow(INDEX_TOP + (index_point-first_subj_on_screen) );
  2080. X}
  2081. X
  2082. Xerase_subject_arrow() {
  2083. X
  2084. X    erase_arrow(INDEX_TOP + (index_point-first_subj_on_screen) );
  2085. X}
  2086. X
  2087. X
  2088. Xprompt_subject_num(ch, group)
  2089. Xchar ch;
  2090. Xchar *group;
  2091. X{
  2092. Xint num;
  2093. X
  2094. X
  2095. X    clear_message();
  2096. X
  2097. X    if ((num = parse_num(ch, "Read article> ")) == -1) {
  2098. X        clear_message();
  2099. X        return FALSE;
  2100. X    }
  2101. X    num--;        /* index from 0 (internal) vs. 1 (user) */
  2102. X
  2103. X    if (num >= top_base)
  2104. X        num = top_base - 1;
  2105. X
  2106. X    if (num >= first_subj_on_screen
  2107. X    &&  num < last_subj_on_screen) {
  2108. X        erase_subject_arrow();
  2109. X        index_point = num;
  2110. X        draw_subject_arrow();
  2111. X    } else {
  2112. X        index_point = num;
  2113. X        show_group_page(group, TRUE);
  2114. X    }
  2115. X}
  2116. X
  2117. Xvoid
  2118. Xsearch_subject(forward, group)
  2119. Xint forward;
  2120. Xchar *group;
  2121. X{
  2122. X    char buf[LEN+1];
  2123. X    int i;
  2124. X#ifndef    REGEXP
  2125. X    extern char *regcmp();
  2126. X    extern char *regex();
  2127. X    char *re;
  2128. X#else    /* REGEXP */
  2129. X    regexp *re;
  2130. X#endif    /* REGEXP */
  2131. X    char *prompt;
  2132. X
  2133. X    clear_message();
  2134. X
  2135. X    if (forward)
  2136. X        prompt = "/";
  2137. X    else
  2138. X        prompt = "?";
  2139. X
  2140. X    if (!parse_string(prompt, buf))
  2141. X        return;
  2142. X
  2143. X    if (strlen(buf))
  2144. X        strcpy(subject_search_string, buf);
  2145. X    else if (!strlen(subject_search_string)) {
  2146. X        info_message("No search pattern");
  2147. X        return;
  2148. X    }
  2149. X
  2150. X    i = index_point;
  2151. X
  2152. X    glob_name(subject_search_string, buf);
  2153. X
  2154. X#ifndef    REGEXP
  2155. X    if ((re = regcmp(buf, NULL)) == NULL) {
  2156. X#else    /* REGEXP */
  2157. X    if ((re = regcomp (buf)) == NULL) {
  2158. X#endif    /* REGEXP */
  2159. X        info_message("Bad search pattern");
  2160. X        return;
  2161. X    }
  2162. X
  2163. X    do {
  2164. X        if (forward)
  2165. X            i++;
  2166. X        else
  2167. X            i--;
  2168. X
  2169. X        if (i >= top_base)
  2170. X            i = 0;
  2171. X        if (i < 0)
  2172. X            i = top_base - 1;
  2173. X
  2174. X#ifndef    REGEXP
  2175. X        if (regex(re, arts[ base[i] ].subject) != NULL) {
  2176. X#else    /* REGEXP */
  2177. X        if (regexec (re, arts[ base[i] ].subject) != NULL) {
  2178. X#endif    /* REGEXP */
  2179. X            if (i >= first_subj_on_screen
  2180. X            &&  i < last_subj_on_screen) {
  2181. X                erase_subject_arrow();
  2182. X                index_point = i;
  2183. X                draw_subject_arrow();
  2184. X            } else {
  2185. X                index_point = i;
  2186. X                show_group_page(group, TRUE);
  2187. X            }
  2188. X            return;
  2189. X        }
  2190. X    } while (i != index_point);
  2191. X
  2192. X    info_message("No match");
  2193. X}
  2194. X
  2195. X
  2196. X/*
  2197. X *  Post an original article (not a followup)
  2198. X */
  2199. X
  2200. Xpost_base(group)
  2201. Xchar *group;
  2202. X{
  2203. X    FILE *fp;
  2204. X    char nam[100];
  2205. X    char ch;
  2206. X    char subj[LEN+1];
  2207. X    char buf[200];
  2208. X    int line;
  2209. X#ifdef    GET_DIST
  2210. X    char *ptr;
  2211. X#endif    /* GET_DIST */
  2212. X
  2213. X    if (!parse_string("Subject: ", subj))
  2214. X        return(FALSE);
  2215. X    if (subj[0] == '\0')
  2216. X        return(FALSE);
  2217. X
  2218. X#ifdef    USE_UID
  2219. X    setuid(real_uid);
  2220. X    setgid(real_gid);
  2221. X#endif    /* USE_UID */
  2222. X
  2223. X    sprintf(nam, "%s/.article", homedir);
  2224. X    umask (omask);
  2225. X    if ((fp = fopen(nam, "w")) == NULL) {
  2226. X        umask (0);
  2227. X        fprintf(stderr, "can't open %s: ", nam);
  2228. X        perror("");
  2229. X        return(FALSE);
  2230. X    }
  2231. X#ifndef    OSK
  2232. X    chmod(nam, 0600);
  2233. X#else    /* OSK */
  2234. X    chmod(nam, 013);
  2235. X#endif    /* OSK */
  2236. X
  2237. X    fprintf(fp, "Subject: %s\n", subj);
  2238. X    fprintf(fp, "Newsgroups: %s\n", group);
  2239. X#ifndef    GET_DIST
  2240. X/*    fprintf(fp, "Distribution: \n");    */
  2241. X    line = 2;
  2242. X#else    /* GET_DIST */
  2243. X    strcpy (buf, group);
  2244. X    if (ptr = index (buf, '.'))
  2245. X        *ptr = '\0';
  2246. X    fprintf(fp, "Distribution: %s\n", buf);
  2247. X    line = 3;
  2248. X#endif    /* GET_DIST */
  2249. X    if (*my_org) {
  2250. X        fprintf(fp, "Organization: %s\n", my_org);
  2251. X        ++line;
  2252. X    }
  2253. X    fprintf(fp, "\n");
  2254. X    ++line;
  2255. X
  2256. X#ifdef    APPEND_SIG
  2257. X    add_signature (fp);
  2258. X#endif    /* APPEND_SIG */
  2259. X
  2260. X    fclose(fp);
  2261. X    umask (0);
  2262. X
  2263. X    ch = 'e';
  2264. X    while (1) {
  2265. X        switch (ch) {
  2266. X        case 'e':
  2267. X            invoke_editor(nam, line);
  2268. X            break;
  2269. X
  2270. X        case 'a':
  2271. X            return FALSE;
  2272. X
  2273. X        case 'p':
  2274. X            printf("\rPosting...  ");
  2275. X            CleartoEOLN ();
  2276. X#ifndef    OSK
  2277. X            sprintf(buf, "%s/inews -h < %s", LIBDIR, nam);
  2278. X#else    /* OSK */
  2279. X            sprintf(buf, "inews -h <%s", nam);
  2280. X#endif    /* OSK */
  2281. X            if (invoke_cmd(buf)) {
  2282. X                printf("article posted ");
  2283. X                fflush(stdout);
  2284. X                goto post_base_done;
  2285. X            } else {
  2286. X                printf("article rejected ");
  2287. X                fflush(stdout);
  2288. X                break;
  2289. X            }
  2290. X        }
  2291. X
  2292. X        do {
  2293. X            MoveCursor(LINES, 0);
  2294. X            fputs("abort, edit, post: ", stdout);
  2295. X            fflush(stdout);
  2296. X            ch = ReadCh();
  2297. X        } while (ch != 'a' && ch != 'e' && ch != 'p');
  2298. X    }
  2299. X
  2300. Xpost_base_done:
  2301. X#ifdef    USE_UID
  2302. X    setuid(tass_uid);
  2303. X    setgid(tass_gid);
  2304. X#endif    /* USE_UID */
  2305. X
  2306. X    continue_prompt();
  2307. X
  2308. X    return(TRUE);
  2309. X}
  2310. X
  2311. X
  2312. X/*
  2313. X *  Return the number of unread articles there are within a thread
  2314. X */
  2315. X
  2316. Xnew_responses(thread)
  2317. Xint thread;
  2318. X{
  2319. X    int i;
  2320. X    int sum = 0;
  2321. X
  2322. X    for (i = base[thread]; i >= 0; i = arts[i].thread)
  2323. X        if (arts[i].unread)
  2324. X            sum++;
  2325. X
  2326. X    return sum;
  2327. X}
  2328. X
  2329. Xvoid
  2330. Xtass_group_help() {
  2331. X    char ch;
  2332. X
  2333. Xgroup_help_start:
  2334. X
  2335. X    ClearScreen();
  2336. X    center_line(0, TASS_HEADER);
  2337. X    center_line(1, "Index Page Commands (page 1 of 2)");
  2338. X
  2339. X    MoveCursor(3, 0);
  2340. X
  2341. X    printf("4        Select article 4\r\012");
  2342. X    printf("^D, ^V   half / full Page down\r\012");
  2343. X    printf("^U, ^Z   half / full  Page up\r\012");
  2344. X    printf("<CR>     Read current article\r\012");
  2345. X    printf("<TAB>    View next unread article or group\r\012");
  2346. X    printf("c        Mark all articles as read\r\012");
  2347. X    printf("g        Choose a new group by name\r\012");
  2348. X    printf("j        Down a line\r\012");
  2349. X    printf("k        Up a line\r\012");
  2350. X    printf("n        Go to next group\r\012");
  2351. X    printf("N        Go to next unread article\r\012");
  2352. X    printf("p        Go to previous group\r\012");
  2353. X    printf("P        Go to previous unread article\r\012");
  2354. X    printf("q        Quit\r\012");
  2355. X
  2356. X    center_line(LINES, "-- hit space for more commands --");
  2357. X    ch = ReadCh();
  2358. X    if (ch != ' ')
  2359. X        return;
  2360. X
  2361. X    ClearScreen();
  2362. X    center_line(0, TASS_HEADER);
  2363. X    center_line(1, "Index Page Commands (page 2 of 2)");
  2364. X
  2365. X    MoveCursor(3, 0);
  2366. X
  2367. X    printf("s        Subscribe to this group\r\012");
  2368. X    printf("t        Return to group selection index\r\012");
  2369. X    printf("u        Unsubscribe to this group\r\012");
  2370. X    printf("w        Post an article\r\012");
  2371. X    printf("/        Search forward for subject\r\012");
  2372. X    printf("?        Search backward for subject\r\012");
  2373. X    printf("-        Show last message\r\012");
  2374. X
  2375. X    center_line(LINES, "-- hit any key --");
  2376. X    ch = ReadCh();
  2377. X    if (ch == 'b')
  2378. X        goto group_help_start;
  2379. X}
  2380. __END__OF__THIS__FILE__
  2381. exit 0
  2382. : end of shell archive
  2383.  
  2384. -- 
  2385. Frank Kaefer # fkk@stasys.sta.sub.org # Starnberg, Germany
  2386.