home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume29 / tin / part04 < prev    next >
Text File  |  1992-03-28  |  52KB  |  2,275 lines

  1. Newsgroups: comp.sources.misc
  2. From: iain%anl433.uucp@germany.eu.net (Iain J. Lea)
  3. Subject:  v29i022:  tin - threaded full screen newsreader v1.1P1, Part04/12
  4. Message-ID: <1992Mar27.033058.2262@sparky.imd.sterling.com>
  5. Date: Fri, 27 Mar 1992 03:30:58 GMT
  6. Approved: kent@sparky.imd.sterling.com
  7. X-Md4-Signature: ea2bff95bf5b8e6337a9782b12c580df
  8.  
  9. Submitted-by: iain%anl433.uucp@germany.eu.net (Iain J. Lea)
  10. Posting-number: Volume 29, Issue 22
  11. Archive-name: tin/part04
  12. Environment: BSD, SCO, ISC, SUNOS, SYSVR3, SYSVR4, ULTRIX, XENIX
  13. Supersedes: tin: Volume 28, Issue 45-55
  14.  
  15. #!/bin/sh
  16. # this is tin.shar.04 (part 4 of tin1.1)
  17. # do not concatenate these parts, unpack them in order with /bin/sh
  18. # file art.c continued
  19. #
  20. if test ! -r _shar_seq_.tmp; then
  21.     echo 'Please unpack part 1 first!'
  22.     exit 1
  23. fi
  24. (read Scheck
  25.  if test "$Scheck" != 4; then
  26.     echo Please unpack part "$Scheck" next!
  27.     exit 1
  28.  else
  29.     exit 0
  30.  fi
  31. ) < _shar_seq_.tmp || exit 1
  32. if test ! -f _shar_wnt_.tmp; then
  33.     echo 'x - still skipping art.c'
  34. else
  35. echo 'x - continuing file art.c'
  36. sed 's/^X//' << 'SHAR_EOF' >> 'art.c' &&
  37. X        } else {
  38. X            error = 12;
  39. X            goto corrupt_index;
  40. X        }
  41. X
  42. X        /*
  43. X         * Date:
  44. X         */
  45. X        if (fgets(buf, sizeof buf, fp) == NULL) {
  46. X            error = 13;
  47. X            goto corrupt_index;
  48. X        }
  49. X
  50. X        buf[strlen (buf)-1] = '\0';
  51. X        my_strncpy (arts[top].date, buf, 12);
  52. X
  53. X        /*
  54. X         * Archive-name:
  55. X         */
  56. X        if (fgets(buf, sizeof buf, fp) == NULL) {
  57. X            error = 14;
  58. X            goto corrupt_index;
  59. X        }
  60. X
  61. X        if (buf[0] == '\n') {
  62. X            arts[top].archive = (char *) 0;
  63. X        } else if (buf[0] == '%') {
  64. X            n = atoi (&buf[1]);
  65. X            if (n > top || n < 0) {
  66. X                error = 15;
  67. X                goto corrupt_index;
  68. X            }
  69. X            arts[top].archive = arts[n].archive;
  70. X        } else if (buf[0] == ' ') {
  71. X            for (p = &buf[1]; *p && *p != '\n' ; p++)
  72. X                continue;
  73. X            *p = '\0';
  74. X            arts[top].archive = hash_str (&buf[1]);
  75. X        } else {
  76. X            error = 16;
  77. X            goto corrupt_index;
  78. X        }
  79. X
  80. X        /*
  81. X         * part no.
  82. X         */
  83. X        if (fgets(buf, sizeof buf, fp) == NULL) {
  84. X            error = 17;
  85. X            goto corrupt_index;
  86. X        }
  87. X
  88. X        if (buf[0] != ' ') { 
  89. X            buf[strlen (buf)-1] = '\0';
  90. X            arts[top].part = str_dup (buf);
  91. X        }
  92. X
  93. X        /*
  94. X         * patch no.
  95. X         */
  96. X        if (fgets(buf, sizeof buf, fp) == NULL) {
  97. X            error = 18;
  98. X            goto corrupt_index;
  99. X        }
  100. X
  101. X        if (buf[0] != ' ') { 
  102. X            buf[strlen (buf)-1] = '\0';
  103. X            arts[top].patch = str_dup (buf);
  104. X        }
  105. X
  106. X        debug_print_header (&arts[top]);
  107. X    }
  108. X
  109. X    fclose(fp);
  110. X    return TRUE;
  111. X
  112. corrupt_index:
  113. X    if (! update) {
  114. X        sprintf (msg, txt_corrupt_index, index_file, error, top); 
  115. X        error_message (msg, "");
  116. X    }
  117. X
  118. X    if (debug == 2) {
  119. X        sprintf (msg, "cp %s INDEX.BAD", index_file);
  120. X        system (msg);
  121. X    }
  122. X
  123. X    unlink (index_file);
  124. X    top = 0;
  125. X    return FALSE;
  126. }
  127. X
  128. X
  129. /*
  130. X *  Look in the local $HOME/RCDIR/INDEXDIR (or wherever) directory for the
  131. X *  index file for the given group.  Hashing the group name gets
  132. X *  a number.  See if that #.1 file exists; if so, read first line.
  133. X *  Group we want?  If no, try #.2.  Repeat until no such file or
  134. X *  we find an existing file that matches our group.
  135. X */
  136. X
  137. void find_index_file (group)
  138. X    char *group;
  139. {
  140. X    char *p;
  141. X    FILE *fp;
  142. X    int i = 1;
  143. X    static char buf[LEN];
  144. X    char dir[LEN];
  145. X    unsigned long h;
  146. X
  147. X    h = hash_groupname (group);
  148. X
  149. #ifdef NNTP_XINDEX     
  150. /*    sprintf (dir, "%s/%s", spooldir, INDEXDIR);
  151. */
  152. X    sprintf (index_file, "/tmp/idx%d", process_id);
  153. X    return;
  154. #else
  155. X    if (local_index) {
  156. X        strcpy (dir, indexdir);
  157. X    } else {
  158. X        sprintf (dir, "%s/%s", spooldir, INDEXDIR);
  159. X    }
  160. #endif    
  161. X    
  162. X    while (TRUE) {
  163. X        sprintf (index_file, "%s/%lu.%d", dir, h, i);
  164. X        
  165. X        if ((fp = fopen (index_file, "r")) == NULL) {
  166. X            return;
  167. X        }
  168. X
  169. X        if (fgets (buf, sizeof (buf), fp) == NULL) {
  170. X            fclose (fp);
  171. X            return;
  172. X        }
  173. X        fclose (fp);
  174. X
  175. X        for (p = buf; *p && *p != '\n'; p++) {
  176. X            continue;
  177. X        }    
  178. X        *p = '\0';
  179. X
  180. X        if (strcmp (buf, group) == 0) {
  181. X            return;
  182. X        }    
  183. X        i++;
  184. X    }    
  185. }
  186. X
  187. /*
  188. X *  Run the index file updater only for the groups we've loaded.
  189. X */
  190. X
  191. void do_update ()
  192. {
  193. X    int i, j;
  194. X    char group_path[LEN];
  195. X    char *p;
  196. X    long beg_epoch, end_epoch;
  197. X    
  198. X    if (verbose) {
  199. X        time (&beg_epoch);
  200. X    }
  201. X
  202. X    for (i = 0; i < group_top; i++) {
  203. X        strcpy(group_path, active[my_group[i]].name);
  204. X        for (p = group_path; *p; p++) {
  205. X            if (*p == '.') {
  206. X                *p = '/';
  207. X            }
  208. X        }
  209. X        if (verbose) {
  210. X            printf ("%s %s\n", (catchup ? "Catchup" : "Updating"),
  211. X                    active[my_group[i]].name);
  212. X            fflush (stdout);
  213. X        }
  214. X        index_group (active[my_group[i]].name, group_path);
  215. X        if (catchup) {
  216. X            for (j = 0; j < top; j++) {
  217. X                arts[j].unread = ART_READ;
  218. X            }
  219. X            update_newsrc (active[my_group[i]].name, my_group[i], FALSE);
  220. X        }
  221. X    }
  222. X
  223. X    if (verbose) {
  224. X        time (&end_epoch);
  225. X        sprintf (msg, "%s %d groups in %ld seconds\n", 
  226. X            (catchup ? "Caughtup" : "Updated"), group_top, end_epoch - beg_epoch);
  227. X        wait_message (msg);
  228. X    }
  229. }
  230. X
  231. /*
  232. X *  reload index after any articles have been killed
  233. X */
  234. void reload_index_file (group, killed)
  235. X    char *group;
  236. X    int killed;
  237. {
  238. X    char group_path[LEN];
  239. X    char *p;
  240. X
  241. X    if (local_index) {            /* writing index in home directory */
  242. X        set_real_uid_gid ();    /* so become them */
  243. X    }
  244. X
  245. X    strcpy (group_path, group);            /* turn comp.unix.amiga into */
  246. X    for (p = group_path; *p; p++)        /* comp/unix/amiga */
  247. X        if (*p == '.')
  248. X            *p = '/';
  249. X
  250. X    if (killed) {
  251. X        if (! update) {
  252. X            wait_message (txt_killing_arts);
  253. X        }
  254. X        index_file_killed = TRUE;
  255. X        setup_base (group, group_path);
  256. X        dump_index_file (group, killed);
  257. X        load_index_file (group);
  258. X        read_newsrc_line (group);
  259. X    } else {
  260. X        if (! update) {
  261. X            wait_message (txt_unkilling_arts);
  262. X        }
  263. X        find_index_file (group);
  264. X
  265. X        unlink (index_file);    /* delete index file */
  266. X
  267. X        index_file_killed = FALSE;
  268. X        last_read_article = 0L;
  269. X
  270. X        if (read_group (group, group_path)) {
  271. X            dump_index_file (group, killed);
  272. X        }
  273. X    }
  274. X
  275. X    make_threads (TRUE);
  276. X    find_base (show_only_unread);
  277. X
  278. X    if (local_index) {
  279. X        set_tin_uid_gid ();
  280. X    }
  281. X
  282. X    return; 
  283. }
  284. X
  285. /*
  286. X * convert date from ctime format to sortable format
  287. X * "24 Jul 91 12:59:59", "Mon, 24 Jul 91 12:59:59" and
  288. X * "Mon, 24 Jul 1991 12:59:59" are parsed and produce
  289. X * output of the form "910724125959"
  290. X */
  291. X
  292. char *parse_date (date, str)
  293. X    char *date;
  294. X    char *str;
  295. {
  296. X    char buf[4];
  297. X    int i = 0;
  298. X
  299. X    /* Check for extraneous day-of-week at start of date */
  300. X    while (isalpha(date[i]) || date[i] == ',' || date[i] == ' ') {
  301. X        i++;
  302. X    }
  303. X    
  304. X    if (date[i+1] == ' ') {    /* ie. "2 Aug..." instead of "12 Aug... */
  305. X        str[4] = '0';        /* day */
  306. X        str[5] = date[i++];
  307. X        i++;
  308. X    } else {
  309. X        str[4] = date[i++];        /* day */
  310. X        str[5] = date[i++];
  311. X        i++;
  312. X    }
  313. X    
  314. X    buf[0] = date[i++];        /* month in Jan,Feb,.. form */
  315. X    buf[1] = date[i++];
  316. X    buf[2] = date[i++];
  317. X    buf[3] = '\0';
  318. X
  319. X    i++;
  320. X    
  321. X    str[0] = date[i++];        /* year */
  322. X    str[1] = date[i++];
  323. X    if (isdigit(date[i])) {         /* 19xx format */
  324. X        str[0] = date[i++];
  325. X        str[1] = date[i++];
  326. X    }
  327. X    
  328. X    i++;
  329. X    
  330. X    if (strcmp (buf, "Jan") == 0) {        /* convert Jan to 01 etc */
  331. X        str[2] = '0';
  332. X        str[3] = '1';
  333. X    } else if (strcmp (buf, "Feb") == 0) {
  334. X        str[2] = '0';
  335. X        str[3] = '2';
  336. X    } else if (strcmp (buf, "Mar") == 0) {
  337. X        str[2] = '0';
  338. X        str[3] = '3';
  339. X    } else if (strcmp (buf, "Apr") == 0) {
  340. X        str[2] = '0';
  341. X        str[3] = '4';
  342. X    } else if (strcmp (buf, "May") == 0) {
  343. X        str[2] = '0';
  344. X        str[3] = '5';
  345. X    } else if (strcmp (buf, "Jun") == 0) {
  346. X        str[2] = '0';
  347. X        str[3] = '6';
  348. X    } else if (strcmp (buf, "Jul") == 0) {
  349. X        str[2] = '0';
  350. X        str[3] = '7';
  351. X    } else if (strcmp (buf, "Aug") == 0) {
  352. X        str[2] = '0';
  353. X        str[3] = '8';
  354. X    } else if (strcmp (buf, "Sep") == 0) {
  355. X        str[2] = '0';
  356. X        str[3] = '9';
  357. X    } else if (strcmp (buf, "Oct") == 0) {
  358. X        str[2] = '1';
  359. X        str[3] = '0';
  360. X    } else if (strcmp (buf, "Nov") == 0) {
  361. X        str[2] = '1';
  362. X        str[3] = '1';
  363. X    } else if (strcmp (buf, "Dec") == 0) {
  364. X        str[2] = '1';
  365. X        str[3] = '2';
  366. X    } else {
  367. X        str[2] = '0';
  368. X        str[3] = '0';
  369. X    }
  370. X    
  371. X    str[6] = date[i++];        /* hour */
  372. X    str[7] = date[i++];
  373. X
  374. X    i++;
  375. X    
  376. X    str[8] = date[i++];        /* minutes */
  377. X    str[9] = date[i++];
  378. X    
  379. X    i++;
  380. X    
  381. X    str[10] = date[i++];    /* seconds */
  382. X    str[11] = date[i++];
  383. X
  384. X    str[12] = '\0';        /* terminate string */
  385. X
  386. X    return (str);
  387. }
  388. X
  389. X
  390. int artnum_comp (p1, p2)
  391. X    char *p1;
  392. X    char *p2;
  393. {
  394. X    struct article_t *s1 = (struct article_t *) p1;
  395. X    struct article_t *s2 = (struct article_t *) p2;
  396. X
  397. X    /* s1->artnum less than s2->artnum */
  398. X    if (s1->artnum < s2->artnum) {
  399. X        return -1;
  400. X    }
  401. X    /* s1->artnum greater than s2->artnum */
  402. X    if (s1->artnum > s2->artnum) {
  403. X        return 1;
  404. X    }
  405. X    return 0;
  406. }
  407. X
  408. X
  409. int subj_comp (p1, p2)
  410. X    char *p1;
  411. X    char *p2;
  412. {
  413. X    struct article_t *s1 = (struct article_t *) p1;
  414. X    struct article_t *s2 = (struct article_t *) p2;
  415. X
  416. X    /* return result of strcmp (reversed for descending) */
  417. X    return (sort_art_type == SORT_BY_SUBJ_ASCEND 
  418. X            ? strcmp (s1->subject, s2->subject) 
  419. X            : strcmp (s2->subject, s1->subject));
  420. }
  421. X
  422. X
  423. int from_comp (p1, p2)
  424. X    char *p1;
  425. X    char *p2;
  426. {
  427. X    struct article_t *s1 = (struct article_t *) p1;
  428. X    struct article_t *s2 = (struct article_t *) p2;
  429. X
  430. X    /* return result of strcmp (reversed for descending) */
  431. X    return (sort_art_type == SORT_BY_FROM_ASCEND 
  432. X            ? strcmp (s1->from, s2->from) 
  433. X            : strcmp (s2->from, s1->from));
  434. }
  435. X
  436. X
  437. int date_comp (p1, p2)
  438. X    char *p1;
  439. X    char *p2;
  440. {
  441. X    struct article_t *s1 = (struct article_t *) p1;
  442. X    struct article_t *s2 = (struct article_t *) p2;
  443. X    /* return result of strcmp (reversed for descending) */
  444. X    return (sort_art_type == SORT_BY_DATE_ASCEND 
  445. X            ? strcmp (s1->date, s2->date) 
  446. X            : strcmp (s2->date, s1->date));
  447. }
  448. X
  449. X
  450. void set_article (art)
  451. X    struct article_t *art;
  452. {    
  453. X    art->subject = (char *) 0;
  454. X    art->from = (char *) 0;
  455. X    art->name = (char *) 0;
  456. X    art->date[0] = '\0';
  457. X    art->archive = (char *) 0;
  458. X    art->part = (char *) 0;
  459. X    art->patch = (char *) 0;
  460. X    art->unread = ART_UNREAD;
  461. X    art->inthread = FALSE;
  462. X    art->killed = FALSE;
  463. X    art->tagged = FALSE;
  464. }
  465. SHAR_EOF
  466. echo 'File art.c is complete' &&
  467. chmod 0600 art.c ||
  468. echo 'restore of art.c failed'
  469. Wc_c="`wc -c < 'art.c'`"
  470. test 24273 -eq "$Wc_c" ||
  471.     echo 'art.c: original size 24273, current size' "$Wc_c"
  472. rm -f _shar_wnt_.tmp
  473. fi
  474. # ============= curses.c ==============
  475. if test -f 'curses.c' -a X"$1" != X"-c"; then
  476.     echo 'x - skipping curses.c (File already exists)'
  477.     rm -f _shar_wnt_.tmp
  478. else
  479. > _shar_wnt_.tmp
  480. echo 'x - extracting curses.c (Text)'
  481. sed 's/^X//' << 'SHAR_EOF' > 'curses.c' &&
  482. /*
  483. X *  Project   : tin - a threaded Netnews reader
  484. X *  Module    : curses.c
  485. X *  Author    : D.Taylor & I.Lea
  486. X *  Created   : ??-??-86
  487. X *  Updated   : 22-03-92
  488. X *  Notes     : This is a screen management library borrowed with permission
  489. X *              from the Elm mail system (a great mailer--I highly recommend
  490. X *              it!).This library was hacked to provide what tin needs.
  491. X *  Copyright : Copyright (c) 1986-92 Dave Taylor & Iain Lea
  492. X *              The Elm Mail System  -  $Revision: 2.1 $   $State: Exp $
  493. X */
  494. X
  495. #include <stdio.h>
  496. #include <curses.h>
  497. X
  498. #define DEFAULT_LINES_ON_TERMINAL    24
  499. #define DEFAULT_COLUMNS_ON_TERMINAL    80
  500. X
  501. int LINES = 23;
  502. int COLS  = 80;
  503. int inverse_okay = TRUE;
  504. static int _inraw = FALSE;                  /* are we IN rawmode?    */
  505. X
  506. X
  507. #ifndef INDEX_DAEMON
  508. X
  509. #ifndef MINIX
  510. #    include <sys/ioctl.h>
  511. #endif
  512. X
  513. #define        BACKSPACE    '\b'
  514. #define        VERY_LONG_STRING    2500
  515. X
  516. #ifdef BSD 
  517. #    ifndef BSD4_1
  518. #        include <sgtty.h>
  519. #    else
  520. #        include <termio.h>
  521. #    endif
  522. #else
  523. #    ifndef SYSV
  524. #        ifndef MINIX
  525. #            ifdef sinix
  526. #                include <termios.h>
  527. #            else
  528. #                include <termio.h>
  529. #            endif
  530. #        else
  531. #            include <sgtty.h>
  532. #        endif
  533. #    endif
  534. #endif
  535. X
  536. #include <ctype.h>
  537. X
  538. #define TTYIN    0
  539. X
  540. #ifdef SHORTNAMES
  541. # define _clearinverse    _clrinv
  542. # define _cleartoeoln    _clrtoeoln
  543. # define _cleartoeos    _clr2eos
  544. #endif
  545. X
  546. #if defined(BSD) || defined(MINIX)
  547. #    define TCGETA    TIOCGETP
  548. #    define TCSETAW    TIOCSETP
  549. X
  550. struct sgttyb _raw_tty,
  551. X          _original_tty;
  552. #else
  553. #    ifdef sinix
  554. #        ifndef TCGETA
  555. #            define TCGETA    STCGETA
  556. #        endif
  557. #        ifndef TCSETA
  558. #            define TCSETAW    STCSETAW
  559. #        endif
  560. struct termios _raw_tty, 
  561. X              _original_tty;
  562. #    else
  563. struct termio _raw_tty, 
  564. X              _original_tty;
  565. #    endif
  566. #endif
  567. X
  568. static char *_clearscreen, *_moveto, *_cleartoeoln, *_cleartoeos,
  569. X            *_setinverse, *_clearinverse, *_setunderline, *_clearunderline,
  570. X            *_terminalinit, *_terminalend;
  571. X
  572. static int _lines,_columns;
  573. X
  574. static char _terminal[1024];              /* Storage for terminal entry */
  575. static char _capabilities[1024];           /* String for cursor motion */
  576. X
  577. static char *ptr = _capabilities;    /* for buffering         */
  578. X
  579. int    outchar ();            /* char output for tputs */
  580. extern char    *tgetstr ();        /* Get termcap capability */
  581. extern char    *tgoto ();        /* and the goto stuff    */
  582. X
  583. #endif /* INDEX_DAEMON */
  584. X
  585. #include "tin.h"
  586. X
  587. X
  588. int InitScreen ()
  589. {
  590. #ifndef INDEX_DAEMON
  591. X
  592. X    extern int tgetent();      /* get termcap entry */
  593. X    char termname[40], *p;
  594. X    
  595. X    if ((p = (char *) getenv ("TERM")) == NULL) {
  596. X        fprintf (stderr, "%s: TERM variable must be set to use screen capabilities\n", progname);
  597. X        return (FALSE);
  598. X    }
  599. X    if (strcpy (termname, p) == NULL) {
  600. X        fprintf (stderr,"%s: Can't get TERM variable\n", progname);
  601. X        return (FALSE);
  602. X    }
  603. X    if (tgetent (_terminal, termname) != 1) {
  604. X        fprintf (stderr,"%s: Can't get entry for TERM\n", progname);
  605. X        return (FALSE);
  606. X    }
  607. X
  608. X    /* load in all those pesky values */
  609. X    _clearscreen    = tgetstr ("cl", &ptr);
  610. X    _moveto         = tgetstr ("cm", &ptr);
  611. X    _cleartoeoln    = tgetstr ("ce", &ptr);
  612. X    _cleartoeos     = tgetstr ("cd", &ptr);
  613. X    _lines          = tgetnum ("li");
  614. X    _columns        = tgetnum ("co");
  615. X    _setinverse     = tgetstr ("so", &ptr);
  616. X    _clearinverse   = tgetstr ("se", &ptr);
  617. X    _setunderline   = tgetstr ("us", &ptr);
  618. X    _clearunderline = tgetstr ("ue", &ptr);
  619. X    _terminalinit   = tgetstr ("ti", &ptr);
  620. X    _terminalend    = tgetstr ("te", &ptr);
  621. X
  622. X    InitWin ();
  623. X
  624. X    if (!_clearscreen) {
  625. X        fprintf (stderr,
  626. X            "%s: Terminal must have clearscreen (cl) capability\n",progname);
  627. X        return (FALSE);
  628. X    }
  629. X    if (!_moveto) {
  630. X        fprintf (stderr,
  631. X            "%s: Terminal must have cursor motion (cm)\n", progname);
  632. X        return (FALSE);
  633. X    }
  634. X    if (!_cleartoeoln) {
  635. X        fprintf (stderr,
  636. X            "%s: Terminal must have clear to end-of-line (ce)\n", progname);
  637. X        return (FALSE);
  638. X    }
  639. X    if (!_cleartoeos) {
  640. X        fprintf (stderr,
  641. X            "%s: Terminal must have clear to end-of-screen (cd)\n", progname);
  642. X        return (FALSE);
  643. X    }
  644. X    if (_lines == -1)
  645. X        _lines = DEFAULT_LINES_ON_TERMINAL;
  646. X    if (_columns == -1)
  647. X        _columns = DEFAULT_COLUMNS_ON_TERMINAL;
  648. X    return (TRUE);
  649. X
  650. #else
  651. X
  652. X    return (FALSE);
  653. X
  654. #endif /* INDEX_DAEMON */
  655. }
  656. X
  657. /*
  658. X *  returns the number of lines and columns on the display.
  659. X */
  660. void ScreenSize (num_lines, num_columns)
  661. X    int *num_lines, *num_columns;
  662. {
  663. #ifndef INDEX_DAEMON
  664. X
  665. X    if (_lines == 0) _lines = DEFAULT_LINES_ON_TERMINAL;
  666. X    if (_columns == 0) _columns = DEFAULT_COLUMNS_ON_TERMINAL;
  667. X
  668. X    *num_lines = _lines - 1;        /* assume index from zero*/
  669. X    *num_columns = _columns;        /* assume index from one */
  670. X
  671. #endif /* INDEX_DAEMON */
  672. }
  673. X
  674. void InitWin ()
  675. {
  676. #ifndef INDEX_DAEMON
  677. X
  678. X    if (_terminalinit) {
  679. X        tputs (_terminalinit, 1, outchar);
  680. X        fflush (stdout);
  681. X    }
  682. X
  683. #endif /* INDEX_DAEMON */
  684. }
  685. X
  686. void EndWin ()
  687. {
  688. #ifndef INDEX_DAEMON
  689. X
  690. X    if (_terminalend) {
  691. X        tputs (_terminalend, 1, outchar);
  692. X        fflush (stdout);
  693. X    }
  694. X    
  695. #endif /* INDEX_DAEMON */
  696. }
  697. X
  698. /*
  699. X *  clear the screen: returns -1 if not capable
  700. X */
  701. X
  702. void ClearScreen ()
  703. {
  704. #ifndef INDEX_DAEMON
  705. X
  706. X    tputs (_clearscreen, 1, outchar);
  707. X    fflush (stdout);      /* clear the output buffer */
  708. X
  709. #endif /* INDEX_DAEMON */
  710. }
  711. X
  712. /*
  713. X *  move cursor to the specified row column on the screen.
  714. X *  0,0 is the top left!
  715. X */
  716. X
  717. void MoveCursor (row, col)
  718. X    int row, col;
  719. {
  720. #ifndef INDEX_DAEMON
  721. X
  722. X    char *stuff, *tgoto();
  723. X
  724. X    stuff = tgoto (_moveto, col, row);
  725. X    tputs (stuff, 1, outchar);
  726. X    fflush (stdout);
  727. X
  728. #endif /* INDEX_DAEMON */
  729. }
  730. X
  731. /*
  732. X *  clear to end of line
  733. X */
  734. X
  735. void CleartoEOLN ()
  736. {
  737. #ifndef INDEX_DAEMON
  738. X
  739. X    tputs (_cleartoeoln, 1, outchar);
  740. X    fflush (stdout);  /* clear the output buffer */
  741. X
  742. #endif /* INDEX_DAEMON */
  743. }
  744. X
  745. /*
  746. X *  clear to end of screen
  747. X */
  748. X
  749. void CleartoEOS ()
  750. {
  751. #ifndef INDEX_DAEMON
  752. X
  753. X    int i;
  754. X    
  755. X    if (_cleartoeos) {
  756. X        tputs (_cleartoeos, 1, outchar);
  757. X    } else {
  758. X        for (i=_lines ; i < _lines ; i++) {
  759. X            MoveCursor (i, 0);
  760. X            CleartoEOLN ();
  761. X        }
  762. X    }
  763. X    fflush (stdout);  /* clear the output buffer */
  764. X
  765. #endif /* INDEX_DAEMON */
  766. }
  767. X
  768. /*
  769. X *  set inverse video mode
  770. X */
  771. X
  772. void StartInverse ()
  773. {
  774. #ifndef INDEX_DAEMON
  775. X
  776. X    if (_setinverse && inverse_okay)
  777. X        tputs (_setinverse, 1, outchar);
  778. X    fflush (stdout);
  779. X
  780. #endif /* INDEX_DAEMON */
  781. }
  782. X
  783. /*
  784. X *  compliment of startinverse
  785. X */
  786. X
  787. void EndInverse ()
  788. {
  789. #ifndef INDEX_DAEMON
  790. X
  791. X    if (_clearinverse && inverse_okay)
  792. X        tputs (_clearinverse, 1, outchar);
  793. X    fflush (stdout);
  794. X
  795. #endif /* INDEX_DAEMON */
  796. }
  797. X
  798. /*
  799. X *  returns either 1 or 0, for ON or OFF
  800. X */
  801. X
  802. int RawState()
  803. {
  804. X    return (_inraw);
  805. }
  806. X
  807. /*
  808. X *  state is either TRUE or FALSE, as indicated by call
  809. X */
  810. X
  811. void Raw(state)
  812. X    int state;
  813. {
  814. #ifndef INDEX_DAEMON
  815. X
  816. X    if (state == FALSE && _inraw) {
  817. X      (void) ioctl(TTYIN, TCSETAW, &_original_tty);
  818. X      _inraw = 0;
  819. X    }
  820. X    else if (state == TRUE && ! _inraw) {
  821. X
  822. X      (void) ioctl(TTYIN, TCGETA, &_original_tty);    /** current setting **/
  823. X
  824. X      (void) ioctl(TTYIN, TCGETA, &_raw_tty);    /** again! **/
  825. #if defined(BSD) || defined(MINIX)
  826. X      _raw_tty.sg_flags &= ~(ECHO | CRMOD);    /* echo off */
  827. X      _raw_tty.sg_flags |= CBREAK;    /* raw on    */
  828. #else
  829. X      _raw_tty.c_lflag &= ~(ICANON | ECHO);    /* noecho raw mode        */
  830. X
  831. X      _raw_tty.c_cc[VMIN] = '\01';    /* minimum # of chars to queue    */
  832. X      _raw_tty.c_cc[VTIME] = '\0';    /* minimum time to wait for input */
  833. #endif
  834. X
  835. X      (void) ioctl(TTYIN, TCSETAW, &_raw_tty);
  836. X
  837. X      _inraw = 1;
  838. X    }
  839. X    
  840. #endif /* INDEX_DAEMON */
  841. }
  842. X
  843. /*
  844. X *  read a character with Raw mode set!
  845. X */
  846. X
  847. int ReadCh()
  848. {
  849. #ifndef INDEX_DAEMON
  850. X
  851. X    register int result;
  852. X    char ch;
  853. X    
  854. #ifdef READ_CHAR_HACK
  855. #undef getc
  856. X    ch = getc (stdin);
  857. X    return ((ch == EOF) ? EOF : ch & 0xFF);
  858. #else
  859. X    result = read(0, &ch, 1);
  860. X        return((result <= 0 ) ? EOF : ch & 0xFF);
  861. #endif        
  862. X
  863. #endif /* INDEX_DAEMON */
  864. }
  865. X
  866. /*
  867. X *  output a character. From tputs... (Note: this CANNOT be a macro!)
  868. X */
  869. X
  870. int outchar(c)
  871. X    char c;
  872. {
  873. X    putc(c, stdout);
  874. }
  875. SHAR_EOF
  876. chmod 0600 curses.c ||
  877. echo 'restore of curses.c failed'
  878. Wc_c="`wc -c < 'curses.c'`"
  879. test 7612 -eq "$Wc_c" ||
  880.     echo 'curses.c: original size 7612, current size' "$Wc_c"
  881. rm -f _shar_wnt_.tmp
  882. fi
  883. # ============= debug.c ==============
  884. if test -f 'debug.c' -a X"$1" != X"-c"; then
  885.     echo 'x - skipping debug.c (File already exists)'
  886.     rm -f _shar_wnt_.tmp
  887. else
  888. > _shar_wnt_.tmp
  889. echo 'x - extracting debug.c (Text)'
  890. sed 's/^X//' << 'SHAR_EOF' > 'debug.c' &&
  891. /*
  892. X *  Project   : tin - a threaded Netnews reader
  893. X *  Module    : debug.c
  894. X *  Author    : I.Lea
  895. X *  Created   : 01-04-91
  896. X *  Updated   : 07-03-92
  897. X *  Notes     : debug routines
  898. X *  Copyright : (c) Copyright 1991-92 by Iain Lea
  899. X *              You may  freely  copy or  redistribute  this software,
  900. X *              so  long as there is no profit made from its use, sale
  901. X *              trade or  reproduction.  You may not change this copy-
  902. X *              right notice, and it must be included in any copy made
  903. X */
  904. X
  905. #include "tin.h"
  906. #include "nntp.h"
  907. X
  908. int debug;
  909. X
  910. /*
  911. X *  nntp specific debug routines
  912. X */
  913. void debug_nntp (func, line)
  914. X    char *func;    
  915. X    char *line;    
  916. {
  917. #ifdef DEBUG
  918. X    FILE *fp;
  919. X
  920. X    if (debug != 1)
  921. X        return;
  922. X
  923. X    if ((fp = fopen ("/tmp/NNTP","a+")) != NULL) {
  924. X        fprintf (fp,"%s: %s\n", func, line);
  925. X        fclose (fp);
  926. X        chmod ("/tmp/NNTP", 0666);
  927. X    }
  928. #endif
  929. }
  930. X
  931. X
  932. void debug_nntp_respcode (respcode)
  933. X    int respcode;
  934. {
  935. #ifdef DEBUG
  936. X    debug_nntp ("get_respcode", nntp_respcode (respcode));
  937. #endif
  938. }    
  939. X
  940. /*
  941. X *  tin specific debug routines
  942. X */
  943. void debug_print_arts ()
  944. {
  945. #ifdef DEBUG
  946. X    int i;
  947. X
  948. X    if (debug != 2)
  949. X        return;
  950. X
  951. X    for (i = 0; i < top; i++) {    /* for each group */
  952. X        debug_print_header (&arts[i]);
  953. X    }
  954. #endif
  955. }
  956. X
  957. X
  958. void debug_print_header (s)
  959. X    struct article_t *s;
  960. {
  961. #ifdef DEBUG
  962. X    FILE *fp;
  963. X
  964. X    if (debug != 2)
  965. X        return;
  966. X
  967. X    if ((fp = fopen ("/tmp/ARTS","a+")) != NULL) {
  968. X        fprintf (fp,"art=[%5ld] killed=[%s]\n", s->artnum,
  969. X            (s->tagged ? "TRUE" : "FALSE"));
  970. X        fprintf (fp,"subj=[%-38s]\n", s->subject);
  971. X        fprintf (fp,"from=[%s]  name=[%s]\n", s->from, s->name);
  972. X         if (s->archive) {
  973. X             fprintf (fp, "arch=[%-38s]  ", s->archive);
  974. X         } else {
  975. X             fprintf (fp, "arch=[]  ");
  976. X         }
  977. X         if (s->part) {
  978. X             fprintf (fp, "part=[%s]  ", s->part);
  979. X         } else {
  980. X             fprintf (fp, "part=[]  ");
  981. X         }
  982. X         if (s->patch) {
  983. X             fprintf (fp, "patch=[%s]\n", s->patch);
  984. X        } else {
  985. X             fprintf (fp, "patch=[]\n");
  986. X         }
  987. X        fprintf (fp,"thread=[%d]  inthread=[%d]  unread=[%d]\n",
  988. X            s->thread, s->inthread, s->unread);
  989. /*        fprintf (fp,"thread=[%s]  inthread=[%s]  unread=[%s]\n",
  990. X            (s->thread == ART_NORMAL ? "ART_NORMAL" : "ART_EXPIRED"),
  991. X            (s->inthread ? "TRUE" : "FALSE"),
  992. X            (s->unread ? "TRUE" : "FALSE"));
  993. */
  994. X        fflush (fp);
  995. X        fclose (fp);
  996. X        chmod ("/tmp/DUMP", 0666);
  997. X    }
  998. #endif
  999. }
  1000. X
  1001. X
  1002. void debug_print_comment (comment)
  1003. X    char *comment;
  1004. {
  1005. #ifdef DEBUG
  1006. X    FILE *fp;
  1007. X
  1008. X    if (debug != 2)
  1009. X        return;
  1010. X
  1011. X    if ((fp = fopen ("/tmp/BASE","a+")) != NULL) {
  1012. X        fprintf (fp,"\n%s\n\n", comment);
  1013. X        fflush (fp);
  1014. X        fclose (fp);
  1015. X        chmod ("/tmp/BASE", 0666);
  1016. X    }
  1017. #endif
  1018. }
  1019. X
  1020. X
  1021. void debug_print_base ()
  1022. {
  1023. #ifdef DEBUG
  1024. X    FILE *fp;
  1025. X    int i;
  1026. X
  1027. X    if (debug != 2)
  1028. X        return;
  1029. X
  1030. X    if ((fp = fopen ("/tmp/BASE","a+")) != NULL) {
  1031. X        for (i = 0; i < top_base; i++) {
  1032. X            fprintf (fp, "base[%3d]=[%5ld]\n",i,base[i]);
  1033. X        }
  1034. X        fflush (fp);
  1035. X        fclose (fp);
  1036. X        chmod ("/tmp/BASE", 0666);
  1037. X    }
  1038. #endif
  1039. }
  1040. X
  1041. X
  1042. void debug_print_active ()
  1043. {
  1044. #ifdef DEBUG
  1045. X    FILE *fp;
  1046. X    int i;
  1047. X
  1048. X    if (debug > 0)
  1049. X        return;
  1050. X
  1051. X    if ((fp = fopen ("/tmp/ACTIVE","w")) != NULL) {
  1052. X        for (i = 0; i < num_active; i++) {    /* for each group */
  1053. X            fprintf (fp, "[%4d]=[%-28s] max=[%4ld] min=[%4ld] mod=[%c] nxt=[%4d] flag=[%d] read=[%d] thread=[%d]\n",
  1054. X                i, active[i].name, active[i].max, active[i].min,
  1055. X                active[i].moderated, active[i].next, active[i].flag,
  1056. X                active[i].read, active[i].thread);
  1057. X        }
  1058. X        fflush (fp);
  1059. X        fclose (fp);
  1060. X        chmod ("/tmp/ACTIVE", 0666);
  1061. X    }
  1062. #endif
  1063. }
  1064. SHAR_EOF
  1065. chmod 0600 debug.c ||
  1066. echo 'restore of debug.c failed'
  1067. Wc_c="`wc -c < 'debug.c'`"
  1068. test 3371 -eq "$Wc_c" ||
  1069.     echo 'debug.c: original size 3371, current size' "$Wc_c"
  1070. rm -f _shar_wnt_.tmp
  1071. fi
  1072. # ============= feed.c ==============
  1073. if test -f 'feed.c' -a X"$1" != X"-c"; then
  1074.     echo 'x - skipping feed.c (File already exists)'
  1075.     rm -f _shar_wnt_.tmp
  1076. else
  1077. > _shar_wnt_.tmp
  1078. echo 'x - extracting feed.c (Text)'
  1079. sed 's/^X//' << 'SHAR_EOF' > 'feed.c' &&
  1080. /*
  1081. X *  Project   : tin - a threaded Netnews reader
  1082. X *  Module    : feed.c
  1083. X *  Author    : I.Lea
  1084. X *  Created   : 31-08-91
  1085. X *  Updated   : 18-03-92
  1086. X *  Notes     : provides same interface to mail,pipe,print and save commands
  1087. X *  Copyright : (c) Copyright 1991-92 by Iain Lea
  1088. X *              You may  freely  copy or  redistribute  this software,
  1089. X *              so  long as there is no profit made from its use, sale
  1090. X *              trade or  reproduction.  You may not change this copy-
  1091. X *              right notice, and it must be included in any copy made
  1092. X */
  1093. X
  1094. #include    "tin.h"
  1095. X
  1096. extern char *glob_group;            /* Group name */
  1097. extern char note_h_date[LEN];        /* Date:    */
  1098. extern char note_h_newsgroups[LEN];    /* Newsgroups:    */
  1099. extern char note_h_subj[LEN];        /* Subject:    */
  1100. extern FILE *note_fp;                /* the body of the current article */
  1101. extern int note_end;                /* end of article ? */
  1102. extern int note_page;                /* what page we're on */
  1103. extern long note_mark[MAX_PAGES];    /* ftells on beginnings of pages */
  1104. X
  1105. char default_mail_address[LEN];
  1106. char default_pipe_command[LEN];
  1107. char default_save_file[LEN];
  1108. char default_regex_pattern[LEN];
  1109. char proc_ch_default;                /* set in change_rcfile () */
  1110. X
  1111. X
  1112. void feed_articles (function, level, prompt, respnum, group_path)
  1113. X    int function;
  1114. X    int level;
  1115. X    char *prompt;
  1116. X    int respnum;
  1117. X    char *group_path;
  1118. {
  1119. #ifndef INDEX_DAEMON
  1120. X
  1121. X    char address[LEN];
  1122. X    char command[LEN];
  1123. X    char file[LEN], *p;
  1124. X    char mailbox[LEN];
  1125. X    char pattern[LEN];
  1126. X    char ch = 'a', ch_default = 'a';
  1127. X    char proc_ch = proc_ch_default;
  1128. X    FILE *fp;
  1129. X    int b, i, j, count = 1;
  1130. X    int confirm;
  1131. X    int is_mailbox = FALSE;
  1132. X    int orig_note_end;
  1133. X    int orig_note_page;
  1134. X    int patlen;
  1135. X    int ret1 = FALSE;
  1136. X    int ret2 = FALSE;
  1137. X    int redraw_screen = FALSE;
  1138. X    
  1139. X    if (level == PAGE_LEVEL) {
  1140. X        orig_note_end = note_end;
  1141. X        orig_note_page = note_page;
  1142. X    }
  1143. X
  1144. X    b = which_thread (respnum);
  1145. X
  1146. X    if (num_of_tagged_files) {
  1147. X        ch_default = 'T';
  1148. X    }
  1149. X    if (! num_of_tagged_files && num_of_responses (b)) {
  1150. X        ch_default = 't';
  1151. X    }
  1152. X
  1153. X    if ((save_archive_name == FALSE || arts[respnum].archive == (char *) 0) ||
  1154. X        (save_archive_name == TRUE && function != FEED_SAVE) ||
  1155. X        ch_default == 'T') {
  1156. X        do {
  1157. X            sprintf (msg, "%s%s%c", prompt, txt_art_thread_regex_tag, ch_default);
  1158. X            wait_message (msg);
  1159. X            MoveCursor (LINES, (int) strlen (msg)-1);
  1160. X            if ((ch = (char) ReadCh ()) == CR)
  1161. X                ch = ch_default;
  1162. X        } while (ch != ESC && ch != 'a' && ch != 't' && ch != 'T' && ch != 'r' && ch != 'e');
  1163. X    } else {
  1164. X        file[0] = '\0';
  1165. X        ch = ch_default;
  1166. X        if (str_str (glob_group, "sources", 7)) {
  1167. X            proc_ch = 's';        /* *source* group */ 
  1168. X        } else if (str_str (glob_group, "binaries", 8)) {
  1169. X            proc_ch = 'u';        /* *binaries* group */
  1170. X        } else {
  1171. X            proc_ch = 's';
  1172. X        }
  1173. X    }
  1174. X
  1175. X    if (ch == 'e' || ch == ESC) {    /* exit */
  1176. X        clear_message ();
  1177. X        return;
  1178. X    }
  1179. X    
  1180. X    if (ch == 'r') {
  1181. X        sprintf (msg, txt_feed_pattern, default_regex_pattern);
  1182. X        if (! prompt_string (msg, pattern)) {
  1183. X            clear_message ();
  1184. X            return;
  1185. X        }    
  1186. X        if (strlen (pattern)) {
  1187. X            my_strncpy (default_regex_pattern, pattern, LEN);
  1188. X        } else {
  1189. X            if (default_regex_pattern[0]) {
  1190. X                my_strncpy (pattern, default_regex_pattern, LEN);
  1191. X            } else {
  1192. X                info_message (txt_no_match);
  1193. X                return;
  1194. X            }
  1195. X        }
  1196. X    }
  1197. X
  1198. X    switch (function) {
  1199. X        case FEED_MAIL:
  1200. X            sprintf (msg, txt_mail_art_to, default_mail_address);
  1201. X            if (! prompt_string (msg, address)) {
  1202. X                clear_message ();
  1203. X                return;
  1204. X            }    
  1205. X            if (strlen (address)) {
  1206. X                strcpy (default_mail_address, address);
  1207. X            } else {
  1208. X                if (default_mail_address[0]) {
  1209. X                    strcpy (address, default_mail_address);
  1210. X                } else {
  1211. X                    info_message (txt_no_mail_address);    
  1212. X                    return;
  1213. X                }
  1214. X            }
  1215. X            break;
  1216. X        case FEED_PIPE:
  1217. X            sprintf (msg, txt_pipe_to_command, default_pipe_command);
  1218. X            if (! prompt_string (msg, command)) {
  1219. X                clear_message ();
  1220. X                return;
  1221. X            }
  1222. X            if (strlen (command)) {
  1223. X                strcpy (default_pipe_command, command);
  1224. X            } else {
  1225. X                if (default_pipe_command[0]) {
  1226. X                    strcpy (command, default_pipe_command);
  1227. X                } else {
  1228. X                    info_message (txt_no_command);    
  1229. X                    return;
  1230. X                }
  1231. X            }
  1232. X
  1233. X            if ((fp = popen (command, "w")) == NULL) {
  1234. X                error_message (txt_command_failed_s, command);
  1235. X                return;
  1236. X            }
  1237. X            wait_message (txt_piping);
  1238. X            Raw (FALSE);
  1239. X            break;
  1240. X        case FEED_PRINT:    
  1241. X            if (default_printer) {
  1242. #ifdef sinix
  1243. X                    sprintf (command, "%s -dru=%s %s",
  1244. X                        printer, get_val ("PRINTER","ps"), redirect_output);
  1245. #else
  1246. X                    sprintf (command, "%s -P%s %s",
  1247. X                        printer, get_val ("PRINTER","ps"), redirect_output);
  1248. #endif
  1249. X            } else {
  1250. X                if (cmd_line_printer[0]) {
  1251. X                    sprintf (command, "%s %s",
  1252. X                        cmd_line_printer, redirect_output);
  1253. X                } else {
  1254. X                    sprintf (command, "%s %s",
  1255. X                        printer, redirect_output);
  1256. X                }
  1257. X            }
  1258. X            if ((fp = popen (command, "w")) == NULL) {
  1259. X                error_message (txt_command_failed_s, command);
  1260. X                return;
  1261. X            }
  1262. X            break;
  1263. X        case FEED_SAVE:        /* ask user for filename */
  1264. X            free_save_array ();
  1265. X            if ((save_archive_name == FALSE || arts[respnum].archive == (char *) 0)) {
  1266. X                sprintf (msg, txt_save_filename, default_save_file);
  1267. X                if (! prompt_string (msg, file)) {
  1268. X                    clear_message ();
  1269. X                    return;
  1270. X                }
  1271. X                if (strlen (file)) {
  1272. X                    strcpy (default_save_file, file);
  1273. X                } else {
  1274. X                    if (default_save_file[0]) {
  1275. X                        strcpy (file, default_save_file);
  1276. X                    } else {
  1277. X                        info_message (txt_no_filename);    
  1278. X                        return;
  1279. X                    }
  1280. X                }
  1281. X                for (p = file; *p && (*p == ' ' || *p == '\t'); p++) {
  1282. X                    continue;
  1283. X                }
  1284. X                if (! *p) {
  1285. X                    info_message (txt_no_filename);
  1286. X                    return;
  1287. X                }
  1288. X                if ((file[0] == '~' || file[0] == '+') && strlen (file) == 1) {
  1289. X                    info_message (txt_no_filename);
  1290. X                    return;
  1291. X                }
  1292. X                is_mailbox = create_path (file);
  1293. X                if (is_mailbox) {
  1294. X                    if ((int) strlen (file) > 1) {
  1295. X                        my_strncpy (mailbox, file+1, LEN);        
  1296. X                    } else {
  1297. X                        my_strncpy (mailbox, glob_group, LEN);
  1298. X                        /*
  1299. X                         *  convert 1st letter to uppercase
  1300. X                         */
  1301. X                        if (mailbox[0] >= 'a' && mailbox[0] <= 'z') {
  1302. X                            mailbox[0] = mailbox[0] - 32;
  1303. X                        }
  1304. X                    }
  1305. X                    my_strncpy (file, mailbox, LEN);
  1306. X                } else {        /* ask for post processing type */
  1307. X                    do {
  1308. X                        sprintf (msg, "%s%c", txt_post_process_type, proc_ch_default);
  1309. X                        wait_message (msg);
  1310. X                        MoveCursor (LINES, (int) strlen (msg)-1);
  1311. X                        if ((proc_ch = (char) ReadCh ()) == CR)
  1312. X                            proc_ch = proc_ch_default;
  1313. X                    } while (proc_ch != 'n' && proc_ch != 's' &&
  1314. X                            proc_ch != 'u' && proc_ch != 'U');
  1315. X                }
  1316. X            }
  1317. X            clear_message ();
  1318. X            break;
  1319. X    }
  1320. X    
  1321. X    switch (ch) {
  1322. X        case 'a':        /* article */
  1323. X            if (level == GROUP_LEVEL) {
  1324. X                note_page = art_open (arts[respnum].artnum, group_path);    
  1325. X            }
  1326. X            switch (function) {
  1327. X                case FEED_MAIL:
  1328. X                    redraw_screen = mail_to_someone (address, TRUE);
  1329. X                    break;
  1330. X                case FEED_PIPE:
  1331. X                    fseek (note_fp, 0L, 0);
  1332. X                    copy_fp (note_fp, fp, (char *) 0);
  1333. X                    break;
  1334. X                case FEED_PRINT:
  1335. X                    print_file (fp, respnum, 1);
  1336. X                    pclose (fp);        
  1337. X                    break;
  1338. X                case FEED_SAVE:
  1339. X                    wait_message (txt_saving);
  1340. X                    add_to_save_list (0, &arts[respnum], is_mailbox, file);
  1341. X                    (void) save_art_to_file (respnum, 0, FALSE, (char *) 0);
  1342. X                    break;
  1343. X            }
  1344. X            if (mark_saved_read) {
  1345. X                arts[respnum].unread = ART_READ;
  1346. X            }
  1347. X            if (level == GROUP_LEVEL) {
  1348. X                art_close ();
  1349. X            }
  1350. X            break;
  1351. X            
  1352. X        case 't':         /* thread */
  1353. X            confirm = TRUE;
  1354. X            for (i = (int) base[b]; i >= 0; i = arts[i].thread) {
  1355. X                if (function == FEED_PRINT) {
  1356. X                    if ((fp = popen (command, "w")) == NULL) {
  1357. X                        error_message (txt_command_failed_s, command);
  1358. X                        return;
  1359. X                    }
  1360. X                }
  1361. X                if (level == PAGE_LEVEL) {
  1362. X                    art_close ();
  1363. X                }
  1364. X                note_page = art_open (arts[i].artnum, group_path);    
  1365. X                switch (function) {
  1366. X                    case FEED_MAIL:
  1367. X                        mail_to_someone (address, confirm);
  1368. X                        confirm = FALSE;
  1369. X                        break;
  1370. X                    case FEED_PIPE:
  1371. X                        fseek (note_fp, 0L, 0);
  1372. X                        copy_fp (note_fp, fp, (char *) 0);
  1373. X                        break;
  1374. X                    case FEED_PRINT:
  1375. X                        print_file (fp, respnum, count);
  1376. X                        count++;                    
  1377. X                        pclose (fp);
  1378. X                        break;
  1379. X                    case FEED_SAVE:
  1380. X                        add_to_save_list (i, &arts[i], is_mailbox, file);
  1381. X                        break;
  1382. X                }
  1383. X                if (mark_saved_read) {
  1384. X                    arts[i].unread = ART_READ;
  1385. X                }
  1386. X                art_close ();
  1387. X            }
  1388. X            if (function == FEED_SAVE) {
  1389. X                sort_save_list ();
  1390. X                (void) save_thread_to_file (is_mailbox, group_path);
  1391. X            }
  1392. X            break;
  1393. X
  1394. X        case 'T':         /* tagged articles */
  1395. X            confirm = TRUE;
  1396. X            for (i=1 ; i <= num_of_tagged_files ; i++) {
  1397. X                for (j=0 ; j < top ; j++) {
  1398. X                    if (arts[j].tagged && arts[j].tagged == i) { 
  1399. X                        if (function == FEED_PRINT) {
  1400. X                            if ((fp = popen (command, "w")) == NULL) {
  1401. X                                error_message (txt_command_failed_s, command);
  1402. X                                return;
  1403. X                            }
  1404. X                        }
  1405. X                        if (level == PAGE_LEVEL) {
  1406. X                            art_close ();
  1407. X                        }
  1408. X                        note_page = art_open (arts[j].artnum, group_path);    
  1409. X                        switch (function) {
  1410. X                            case FEED_MAIL:
  1411. X                                mail_to_someone (address, confirm);
  1412. X                                confirm = FALSE;
  1413. X                                break;
  1414. X                            case FEED_PIPE:
  1415. X                                fseek (note_fp, 0L, 0);
  1416. X                                copy_fp (note_fp, fp, (char *) 0);
  1417. X                                break;
  1418. X                            case FEED_PRINT:
  1419. X                                print_file (fp, respnum, count);
  1420. X                                count++;                    
  1421. X                                pclose (fp);
  1422. X                                break;
  1423. X                            case FEED_SAVE:
  1424. X                                add_to_save_list (j, &arts[j], is_mailbox, file);
  1425. X                                break;
  1426. X                        }
  1427. X                        if (mark_saved_read) {
  1428. X                            arts[j].unread = ART_READ;
  1429. X                        }
  1430. X                        art_close ();
  1431. X                    }
  1432. X                }
  1433. X            }
  1434. X            if (function == FEED_SAVE) {                
  1435. X                (void) save_regex_arts (is_mailbox, group_path);
  1436. X            }
  1437. X            break;
  1438. X
  1439. X        case 'r':         /* regex pattern matched articles */
  1440. X            confirm = TRUE;
  1441. X            patlen = strlen (pattern);
  1442. X            for (i=0 ; i < top ; i++) {
  1443. #ifdef NO_REGEX
  1444. X                if (str_str (arts[i].subject, pattern, patlen) != 0) {
  1445. #else        
  1446. X                if (wildmat (arts[i].subject, pattern)) {
  1447. #endif        
  1448. X                    if (function == FEED_PRINT) {
  1449. X                        if ((fp = popen (command, "w")) == NULL) {
  1450. X                            error_message (txt_command_failed_s, command);
  1451. X                            return;
  1452. X                        }
  1453. X                    }
  1454. X                    if (level == PAGE_LEVEL) {
  1455. X                        art_close ();
  1456. X                    }
  1457. X                    note_page = art_open (arts[i].artnum, group_path);    
  1458. X                    switch (function) {
  1459. X                        case FEED_MAIL:
  1460. X                            mail_to_someone (address, confirm);
  1461. X                            confirm = FALSE;
  1462. X                            break;
  1463. X                        case FEED_PIPE:
  1464. X                            fseek (note_fp, 0L, 0);
  1465. X                            copy_fp (note_fp, fp, (char *) 0);
  1466. X                            break;
  1467. X                        case FEED_PRINT:
  1468. X                            print_file (fp, respnum, count);
  1469. X                            count++;                    
  1470. X                            pclose (fp);
  1471. X                            break;
  1472. X                        case FEED_SAVE:
  1473. X                            add_to_save_list (i, &arts[i], is_mailbox, file);
  1474. X                            break;
  1475. X                    }
  1476. X                    if (mark_saved_read) {
  1477. X                        arts[i].unread = ART_READ;
  1478. X                    }
  1479. X                     art_close ();
  1480. X                }
  1481. X            }
  1482. X            if (function == FEED_SAVE) {                
  1483. X                sort_save_list ();
  1484. X                (void) save_regex_arts (is_mailbox, group_path);
  1485. X            }
  1486. X            break;
  1487. X    }
  1488. X
  1489. X    redraw_screen = mail_check ();    /* in case of sending to oneself */
  1490. X
  1491. X    switch (function) {
  1492. X        case FEED_PIPE:
  1493. X            pclose (fp);        
  1494. X            Raw (TRUE);
  1495. X            continue_prompt ();
  1496. X            redraw_screen = TRUE;
  1497. X            break;
  1498. X        case FEED_SAVE:
  1499. X            if (proc_ch != 'n' && is_mailbox == FALSE) {
  1500. X                ret2 = post_process_files (proc_ch);
  1501. X            }
  1502. X            free_save_array ();
  1503. X            break;
  1504. X    }
  1505. X
  1506. X    untag_all_articles ();
  1507. X    
  1508. X    if (level == GROUP_LEVEL) {
  1509. X        ret1 = (mark_saved_read ? TRUE : FALSE);
  1510. X    }
  1511. X    if ((ret1 || ret2) && is_mailbox == FALSE) {
  1512. X        redraw_screen = TRUE;
  1513. X    }
  1514. X
  1515. X    if (level == PAGE_LEVEL) {
  1516. X        if (ch != 'a') {
  1517. X            note_page = art_open (arts[respnum].artnum, group_path);
  1518. X        }
  1519. X        note_end = orig_note_end;
  1520. X        note_page = orig_note_page;
  1521. X        fseek (note_fp, note_mark[note_page], 0);
  1522. X        if (redraw_screen) {
  1523. X            if (note_page == 0) {
  1524. X                show_note_page (respnum, glob_group);
  1525. X            } else {
  1526. X                redraw_page (respnum, glob_group);
  1527. X            }
  1528. X        } else {
  1529. X            if (function == FEED_PIPE) {
  1530. X                clear_message ();
  1531. X            }
  1532. X        }
  1533. X    } else {
  1534. X        if (redraw_screen) {
  1535. X            show_group_page (glob_group);
  1536. X        }
  1537. X    }
  1538. X    if (function == FEED_PRINT) {    
  1539. X        info_message (txt_printed);
  1540. X    }
  1541. X
  1542. #endif /* INDEX_DAEMON */
  1543. }
  1544. X
  1545. X
  1546. void print_file (fp, respnum, count)
  1547. X    FILE *fp;
  1548. X    int respnum;
  1549. X    int count;
  1550. {                            
  1551. X    sprintf (msg, "%s%d", txt_printing, count);
  1552. X    wait_message (msg);
  1553. X    
  1554. X    if (print_header) {
  1555. X        fseek(note_fp, 0L, 0);
  1556. X    } else {
  1557. X        fprintf (fp, "Newsgroups: %s\n", note_h_newsgroups);
  1558. X        fprintf (fp, "From: %s (%s)\n",
  1559. X            arts[respnum].from,arts[respnum].name);
  1560. X        fprintf (fp, "Subject: %s\n", note_h_subj);
  1561. X        fprintf (fp, "Date: %s\n\n", note_h_date);
  1562. X        fseek (note_fp, note_mark[0], 0);
  1563. X    }
  1564. X    copy_fp (note_fp, fp, (char *) 0);
  1565. }                        
  1566. SHAR_EOF
  1567. chmod 0600 feed.c ||
  1568. echo 'restore of feed.c failed'
  1569. Wc_c="`wc -c < 'feed.c'`"
  1570. test 12199 -eq "$Wc_c" ||
  1571.     echo 'feed.c: original size 12199, current size' "$Wc_c"
  1572. rm -f _shar_wnt_.tmp
  1573. fi
  1574. # ============= getline.c ==============
  1575. if test -f 'getline.c' -a X"$1" != X"-c"; then
  1576.     echo 'x - skipping getline.c (File already exists)'
  1577.     rm -f _shar_wnt_.tmp
  1578. else
  1579. > _shar_wnt_.tmp
  1580. echo 'x - extracting getline.c (Text)'
  1581. sed 's/^X//' << 'SHAR_EOF' > 'getline.c' &&
  1582. /*
  1583. X *  Project   : tin - a threaded Netnews reader
  1584. X *  Module    : getline.c
  1585. X *  Author    : Chris Thewalt / Iain Lea 
  1586. X *  Created   : 09-11-91
  1587. X *  Updated   : 13-03-92
  1588. X *  Notes     : emacs style line editing input package.  
  1589. X *  Copyright : (c) Copyright 1991-92 by Chris Thewalt & Iain Lea
  1590. X *              Permission to use, copy, modify, and distribute this
  1591. X *              software for any purpose and without fee is hereby
  1592. X *              granted, provided that the above copyright notices
  1593. X *              appear in all copies and that both the copyright
  1594. X *              notice and this permission notice appear in supporting
  1595. X *              documentation. This software is provided "as is" without
  1596. X *              express or implied warranty.
  1597. X */
  1598. X
  1599. #include "tin.h"
  1600. X
  1601. extern int      isatty ();    
  1602. X
  1603. #define BUF_SIZE    1024
  1604. #define SCROLL        30
  1605. #define TABSIZE        4
  1606. #ifndef HIST_SIZE
  1607. #define HIST_SIZE    100
  1608. #endif
  1609. X
  1610. #define CTRL_A    '\001'
  1611. #define CTRL_B    '\002'
  1612. #define CTRL_D    '\004'
  1613. #define CTRL_E    '\005'
  1614. #define CTRL_F    '\006'
  1615. #define CTRL_H    '\010'
  1616. #define CTRL_K    '\013'
  1617. #define CTRL_L    '\014'
  1618. #define CTRL_R    '\022'
  1619. #define CTRL_N    '\016'
  1620. #define CTRL_P    '\020'
  1621. #define TAB        '\t'
  1622. #define DEL        '\177'
  1623. X
  1624. char    *hist_buf[HIST_SIZE];
  1625. int        hist_pos, hist_last;
  1626. static char gl_buf[BUF_SIZE];       /* input buffer */
  1627. static char *gl_prompt;                /* to save the prompt string */
  1628. static int  gl_init_done = 0;        /* -1 is terminal, 1 is batch  */
  1629. static int  gl_width = 0;            /* net size available for input */
  1630. static int  gl_pos, gl_cnt = 0;     /* position and size of input */
  1631. X
  1632. #if __STDC__
  1633. X
  1634. static int      gl_tab (char *, int, int *);
  1635. static void        gl_redraw (void);
  1636. static void     gl_addchar (int);
  1637. static void     gl_newline (void);
  1638. static void     gl_fixup (int, int);
  1639. static void     gl_del (int);
  1640. static void     gl_kill (void);
  1641. static void     hist_add (void);
  1642. static void     hist_init (void);
  1643. static void     hist_next (void);
  1644. static void     hist_prev (void);
  1645. X
  1646. int     (*gl_in_hook)(char *) = 0;
  1647. int     (*gl_out_hook)(char *) = 0;
  1648. int     (*gl_tab_hook)(char *, int, int *) = gl_tab;
  1649. X
  1650. #else
  1651. X
  1652. static int      gl_tab ();
  1653. static void        gl_redraw ();
  1654. static void     gl_addchar ();
  1655. static void     gl_newline ();
  1656. static void     gl_fixup ();
  1657. static void     gl_del ();
  1658. static void     gl_kill ();
  1659. static void     hist_add ();
  1660. static void     hist_init ();
  1661. static void     hist_next ();
  1662. static void     hist_prev ();
  1663. X
  1664. int     (*gl_in_hook)() = 0;
  1665. int     (*gl_out_hook)() = 0;
  1666. int     (*gl_tab_hook)() = gl_tab;
  1667. X
  1668. #endif
  1669. X
  1670. X
  1671. #if __STDC__
  1672. char *getline (char *prompt, int number_only, char *str)
  1673. #else
  1674. char *getline (prompt, number_only, str)
  1675. X    char *prompt;
  1676. X    int number_only;
  1677. X    char *str;
  1678. #endif
  1679. {
  1680. X    int c, i, loc, tmp;
  1681. X
  1682. X    if (! gl_init_done) {
  1683. X        gl_init_done = 1;
  1684. X        hist_init ();
  1685. X    }
  1686. X
  1687. X    if (prompt == (char *) 0) {    
  1688. X        prompt = "";
  1689. X    }
  1690. X    gl_buf[0] = 0;        /* used as end of input indicator */
  1691. X    gl_fixup (-1, 0);    /* this resets gl_fixup */
  1692. X    gl_width = COLS - strlen (prompt);
  1693. X    gl_prompt = prompt;
  1694. X    gl_pos = gl_cnt = 0;
  1695. X
  1696. X    fputs (prompt, stdout);
  1697. X    fflush (stdout);
  1698. X    
  1699. X    if (gl_in_hook) {
  1700. X        loc = gl_in_hook (gl_buf);
  1701. X        if (loc >= 0)
  1702. X            gl_fixup (0, BUF_SIZE);
  1703. X    }
  1704. X    if (str != (char *) 0) {
  1705. X        for (i=0 ; str[i] ; i++) 
  1706. X            gl_addchar (str[i]);
  1707. X    }
  1708. X    while ((c = ReadCh ()) != EOF) {
  1709. X        if (isprint (c)) {
  1710. X            if (number_only) {
  1711. X                if (isdigit (c) && gl_cnt < 6) {    /* num < 100000 */
  1712. X                    gl_addchar (c);
  1713. X                } else {
  1714. X                    ring_bell ();
  1715. X                }
  1716. X            } else {
  1717. X                gl_addchar (c);
  1718. X            }
  1719. X        } else {
  1720. X            switch (c) {
  1721. X                case ESC:             /* abort */
  1722. X                    return (char *) 0;
  1723. X                    break;
  1724. X                case '\n':             /* newline */
  1725. X                case '\r':
  1726. X                    gl_newline ();
  1727. X                    return gl_buf;
  1728. X                    break;
  1729. X                case CTRL_A:
  1730. X                    gl_fixup (-1, 0);
  1731. X                    break;
  1732. X                case CTRL_B:
  1733. X                    gl_fixup (-1, gl_pos-1);
  1734. X                    break;
  1735. X                case CTRL_D:
  1736. X                    if (gl_cnt == 0) {
  1737. X                        gl_buf[0] = 0;
  1738. X                        fputc ('\n', stdout);
  1739. X                        return gl_buf;
  1740. X                    } else {
  1741. X                        gl_del (0);
  1742. X                    }
  1743. X                    break;
  1744. X                case CTRL_E:
  1745. X                    gl_fixup (-1, gl_cnt);
  1746. X                    break;
  1747. X                case CTRL_F:
  1748. X                    gl_fixup (-1, gl_pos+1);
  1749. X                    break;
  1750. X                case CTRL_H:
  1751. X                case DEL:
  1752. X                    gl_del (-1);
  1753. X                    break;
  1754. X                case TAB:
  1755. X                    if (gl_tab_hook) {
  1756. X                        tmp = gl_pos;
  1757. X                        loc = gl_tab_hook (gl_buf, strlen (gl_prompt), &tmp);
  1758. X                        if (loc >= 0 || tmp != gl_pos)
  1759. X                            gl_fixup (loc, tmp);
  1760. X                    }
  1761. X                    break;
  1762. X                case CTRL_K:
  1763. X                    gl_kill ();
  1764. X                    break;
  1765. X                case CTRL_L:
  1766. X                case CTRL_R:
  1767. X                    gl_redraw ();
  1768. X                    break;
  1769. X                case CTRL_N:
  1770. X                    hist_next ();
  1771. X                    break;
  1772. X                case CTRL_P:
  1773. X                    hist_prev ();
  1774. X                    break;
  1775. X                default:
  1776. X                    ring_bell ();
  1777. X                    break;
  1778. X            }
  1779. X        }
  1780. X    }
  1781. X    return gl_buf;
  1782. }
  1783. X
  1784. /*
  1785. X * adds the character c to the input buffer at current location if
  1786. X * the character is in the allowed template of characters
  1787. X */
  1788. X
  1789. #if __STDC__
  1790. static void gl_addchar (int c)
  1791. #else
  1792. static void gl_addchar (c)
  1793. X    int c;
  1794. #endif
  1795. {
  1796. X    int  i;
  1797. X
  1798. X    if (gl_cnt >= BUF_SIZE - 1) {
  1799. X        error_message ("getline: input buffer overflow", "");
  1800. X        exit (1);
  1801. X    }
  1802. X    
  1803. X    for (i=gl_cnt; i >= gl_pos; i--) {
  1804. X        gl_buf[i+1] = gl_buf[i];
  1805. X    }
  1806. X    gl_buf[gl_pos] = c;
  1807. X    gl_fixup (gl_pos, gl_pos+1);
  1808. }
  1809. X
  1810. /*
  1811. X * Cleans up entire line before returning to caller. A \n is appended.
  1812. X * If line longer than screen, we redraw starting at beginning
  1813. X */
  1814. X
  1815. static void gl_newline ()
  1816. {
  1817. X    int change = gl_cnt;
  1818. X    int len = gl_cnt;
  1819. X    int loc = gl_width - 5;    /* shifts line back to start position */
  1820. X
  1821. X    if (gl_cnt >= BUF_SIZE - 1) {
  1822. X        error_message ("getline: input buffer overflow", "");
  1823. X        exit (1);
  1824. X    }
  1825. X    hist_add ();            /* only adds if nonblank */
  1826. X    if (gl_out_hook) {
  1827. X        change = gl_out_hook (gl_buf);
  1828. X        len = strlen (gl_buf);
  1829. X    } 
  1830. X    if (loc > len)
  1831. X        loc = len;
  1832. X    gl_fixup (change, loc);    /* must do this before appending \n */
  1833. X    gl_buf[len] = '\0';
  1834. }
  1835. X
  1836. /*
  1837. X * Delete a character.  The loc variable can be:
  1838. X *    -1 : delete character to left of cursor
  1839. X *     0 : delete character under cursor
  1840. X */
  1841. X
  1842. #if __STDC__
  1843. static void gl_del (int loc)
  1844. #else
  1845. static void gl_del (loc)
  1846. X    int loc;
  1847. #endif
  1848. {
  1849. X    int i;
  1850. X
  1851. X    if (loc == -1 && gl_pos > 0 || loc == 0 && gl_pos < gl_cnt) {
  1852. X        for (i=gl_pos+loc; i < gl_cnt; i++)
  1853. X            gl_buf[i] = gl_buf[i+1];
  1854. X        gl_fixup (gl_pos+loc, gl_pos+loc);
  1855. X    } else {
  1856. X        ring_bell ();
  1857. X    }
  1858. }
  1859. X
  1860. /*
  1861. X * delete from current position to the end of line
  1862. X */
  1863. static void gl_kill ()
  1864. {
  1865. X    if (gl_pos < gl_cnt) {
  1866. X        gl_buf[gl_pos] = '\0';
  1867. X        gl_fixup (gl_pos, gl_pos);
  1868. X    } else {
  1869. X        ring_bell ();
  1870. X    }
  1871. }
  1872. X
  1873. /*
  1874. X * emit a newline, reset and redraw prompt and current input line
  1875. X */
  1876. X
  1877. static void gl_redraw ()
  1878. {
  1879. X    if (gl_init_done == -1) {
  1880. X        fputc ('\n', stdout);
  1881. X        fputs (gl_prompt, stdout);
  1882. X        gl_pos = 0;
  1883. X        gl_fixup (0, BUF_SIZE);
  1884. X    }
  1885. }
  1886. X
  1887. /*
  1888. X * This function is used both for redrawing when input changes or for
  1889. X * moving within the input line.  The parameters are:
  1890. X *   change : the index of the start of changes in the input buffer,
  1891. X *            with -1 indicating no changes.
  1892. X *   cursor : the desired location of the cursor after the call.
  1893. X *            A value of BUF_SIZE can be used to indicate the cursor
  1894. X *            should move just past the end of the input line.
  1895. X */
  1896. X
  1897. #if __STDC__
  1898. static void gl_fixup (int change, int cursor)
  1899. #else
  1900. static void gl_fixup (change, cursor)
  1901. X    int change;
  1902. X    int cursor;
  1903. #endif
  1904. {
  1905. X    static int   gl_shift;    /* index of first on screen character */
  1906. X    static int   off_right;    /* true if more text right of screen */
  1907. X    static int   off_left;    /* true if more text left of screen */
  1908. X    int          left = 0, right = -1;        /* bounds for redraw */
  1909. X    int          pad;        /* how much to erase at end of line */
  1910. X    int          backup;        /* how far to backup before fixing */
  1911. X    int          new_shift;     /* value of shift based on cursor */
  1912. X    int          extra;         /* adjusts when shift (scroll) happens */
  1913. X    int          i;
  1914. X
  1915. X    if (change == -1 && cursor == 0 && gl_buf[0] == 0) {   /* reset */
  1916. X        gl_shift = off_right = off_left = 0;
  1917. X        return;
  1918. X    }
  1919. X    pad = (off_right) ? gl_width - 1 : gl_cnt - gl_shift;   /* old length */
  1920. X    backup = gl_pos - gl_shift;
  1921. X    if (change >= 0) {
  1922. X        gl_cnt = strlen (gl_buf);
  1923. X        if (change > gl_cnt)
  1924. X            change = gl_cnt;
  1925. X    }
  1926. X    if (cursor > gl_cnt) {
  1927. X        if (cursor != BUF_SIZE)        /* BUF_SIZE means end of line */
  1928. X            ring_bell ();
  1929. X            cursor = gl_cnt;
  1930. X    }
  1931. X    if (cursor < 0) {
  1932. X        ring_bell ();
  1933. X        cursor = 0;
  1934. X    }
  1935. X    if (off_right || off_left && cursor < gl_shift + gl_width - SCROLL / 2)
  1936. X        extra = 2;            /* shift the scrolling boundary */
  1937. X    else 
  1938. X        extra = 0;
  1939. X    new_shift = cursor + extra + SCROLL - gl_width;
  1940. X    if (new_shift > 0) {
  1941. X        new_shift /= SCROLL;
  1942. X        new_shift *= SCROLL;
  1943. X    } else
  1944. X        new_shift = 0;
  1945. X    if (new_shift != gl_shift) {    /* scroll occurs */
  1946. X        gl_shift = new_shift;
  1947. X        off_left = (gl_shift) ? 1 : 0;
  1948. X        off_right = (gl_cnt > gl_shift + gl_width - 1)? 1 : 0;
  1949. X        left = gl_shift;
  1950. X        right = (off_right) ? gl_shift + gl_width - 2 : gl_cnt;
  1951. X    } else if (change >= 0) {        /* no scroll, but text changed */
  1952. X        if (change < gl_shift + off_left) {
  1953. X            left = gl_shift;
  1954. X        } else {
  1955. X            left = change;
  1956. X            backup = gl_pos - change;
  1957. X        }
  1958. X        off_right = (gl_cnt > gl_shift + gl_width - 1)? 1 : 0;
  1959. X        right = (off_right) ? gl_shift + gl_width - 2 : gl_cnt;
  1960. X    }
  1961. X    pad -= (off_right) ? gl_width - 1 : gl_cnt - gl_shift;
  1962. X    pad = (pad < 0)? 0 : pad;
  1963. X    if (left <= right) {        /* clean up screen */
  1964. X        for (i=0; i < backup; i++)
  1965. X            fputc ('\b', stdout);
  1966. X        if (left == gl_shift && off_left) {
  1967. X            fputc ('$', stdout);
  1968. X            left++;
  1969. X        }
  1970. X        for (i=left; i < right; i++)
  1971. X            fputc (gl_buf[i], stdout);
  1972. X        if (off_right) {
  1973. X            fputc ('$', stdout);
  1974. X            gl_pos = right + 1;
  1975. X        } else { 
  1976. X            for (i=0; i < pad; i++)    /* erase remains of prev line */
  1977. X                fputc (' ', stdout);
  1978. X            gl_pos = right + pad;
  1979. X        }
  1980. X    }
  1981. X    i = gl_pos - cursor;        /* move to final cursor location */
  1982. X    if (i > 0) {
  1983. X        while (i--)
  1984. X            fputc ('\b', stdout);
  1985. X    } else {
  1986. X        for (i=gl_pos; i < cursor; i++)
  1987. X            fputc (gl_buf[i], stdout);
  1988. X    }
  1989. X    fflush (stdout);
  1990. X    gl_pos = cursor;
  1991. }
  1992. X    
  1993. /*
  1994. X * default tab handler, acts like tabstops every TABSIZE cols
  1995. X */
  1996. X
  1997. #if __STDC__
  1998. static int gl_tab (char *buf, int offset, int *loc)
  1999. #else
  2000. static int gl_tab (buf, offset, loc)
  2001. X    char *buf;
  2002. X    int offset;
  2003. X    int *loc;
  2004. #endif
  2005. {
  2006. X    int i, count, len;
  2007. X    
  2008. X    len = strlen (buf);
  2009. X    count = TABSIZE - (offset + *loc) % TABSIZE;
  2010. X    for (i=len; i >= *loc; i--)
  2011. X        buf[i+count] = buf[i];
  2012. X    for (i=0; i < count; i++)
  2013. X        buf[*loc+i] = ' ';
  2014. X    i = *loc;
  2015. X    *loc = i + count;
  2016. X    return i;
  2017. }
  2018. X
  2019. /*
  2020. X * History functions
  2021. X */
  2022. X
  2023. static void hist_init ()
  2024. {
  2025. X    int i;
  2026. X    
  2027. X    for (i=0; i < HIST_SIZE; i++)
  2028. X        hist_buf[i] = (char *) 0;
  2029. }
  2030. X
  2031. X
  2032. static void hist_add ()
  2033. {
  2034. X    char *p = gl_buf;
  2035. X
  2036. X    while (*p == ' ' || *p == '\t')    /* only save nonblank line */
  2037. X        p++;
  2038. X    if (*p) {
  2039. X        hist_buf[hist_last] = str_dup (gl_buf);
  2040. X        hist_last = (hist_last + 1) % HIST_SIZE;
  2041. X        if (hist_buf[hist_last]) {    /* erase next location */
  2042. X            free(hist_buf[hist_last]);
  2043. X            hist_buf[hist_last] = (char *) 0;
  2044. X        }
  2045. X    }
  2046. X    hist_pos = hist_last;
  2047. }
  2048. X
  2049. /*
  2050. X * loads previous hist entry into input buffer, sticks on first
  2051. X */
  2052. static void hist_prev ()
  2053. {
  2054. X    int   next;
  2055. X
  2056. X    next = (hist_pos - 1 + HIST_SIZE) % HIST_SIZE;
  2057. X    if (next != hist_last) {
  2058. X        if (hist_buf[next]) {
  2059. X            hist_pos = next;
  2060. X            strcpy (gl_buf, hist_buf[hist_pos]);
  2061. X        } else {
  2062. X            ring_bell ();
  2063. X        }
  2064. X    } else {
  2065. X        ring_bell ();
  2066. X    }
  2067. X    if (gl_in_hook)
  2068. X        gl_in_hook (gl_buf);
  2069. X    gl_fixup (0, BUF_SIZE);
  2070. }
  2071. X
  2072. /*
  2073. X * loads next hist entry into input buffer, clears on last
  2074. X */
  2075. static void hist_next ()
  2076. {
  2077. X    if (hist_pos != hist_last) {
  2078. X        hist_pos = (hist_pos + 1) % HIST_SIZE;
  2079. X        if (hist_buf[hist_pos]) {
  2080. X            strcpy (gl_buf, hist_buf[hist_pos]);
  2081. X        } else {
  2082. X            gl_buf[0] = 0;
  2083. X        }
  2084. X    } else {
  2085. X        ring_bell ();
  2086. X    }
  2087. X    if (gl_in_hook) 
  2088. X        gl_in_hook (gl_buf);
  2089. X    gl_fixup (0, BUF_SIZE);
  2090. }
  2091. SHAR_EOF
  2092. chmod 0600 getline.c ||
  2093. echo 'restore of getline.c failed'
  2094. Wc_c="`wc -c < 'getline.c'`"
  2095. test 11438 -eq "$Wc_c" ||
  2096.     echo 'getline.c: original size 11438, current size' "$Wc_c"
  2097. rm -f _shar_wnt_.tmp
  2098. fi
  2099. # ============= group.c ==============
  2100. if test -f 'group.c' -a X"$1" != X"-c"; then
  2101.     echo 'x - skipping group.c (File already exists)'
  2102.     rm -f _shar_wnt_.tmp
  2103. else
  2104. > _shar_wnt_.tmp
  2105. echo 'x - extracting group.c (Text)'
  2106. sed 's/^X//' << 'SHAR_EOF' > 'group.c' &&
  2107. /*
  2108. X *  Project   : tin - a threaded Netnews reader
  2109. X *  Module    : group.c
  2110. X *  Author    : I.Lea & R.Skrenta
  2111. X *  Created   : 01-04-91
  2112. X *  Updated   : 22-03-92
  2113. X *  Notes     :
  2114. X *  Copyright : (c) Copyright 1991-92 by Iain Lea & Rich Skrenta
  2115. X *              You may  freely  copy or  redistribute  this software,
  2116. X *              so  long as there is no profit made from its use, sale
  2117. X *              trade or  reproduction.  You may not change this copy-
  2118. X *              right notice, and it must be included in any copy made
  2119. X */
  2120. X
  2121. #include    "tin.h"
  2122. X
  2123. extern char cvers[LEN];
  2124. extern int cur_groupnum;
  2125. extern int last_resp;        /* page.c */
  2126. extern int this_resp;        /* page.c */
  2127. X
  2128. char *glob_group;
  2129. int index_point;
  2130. int first_subj_on_screen;
  2131. int last_subj_on_screen;
  2132. X
  2133. X
  2134. void group_page (group)
  2135. X    char *group;
  2136. {
  2137. #ifndef INDEX_DAEMON
  2138. X
  2139. X    char group_path[LEN];
  2140. X    char buf[32];
  2141. X    char ch;
  2142. X    char *p;
  2143. X    int flag, i, n;
  2144. X    int kill_state;
  2145. X    int old_top;
  2146. X    int posted;
  2147. X    int sav_groupnum;
  2148. X    int scroll_lines;
  2149. X    long old_artnum;
  2150. X
  2151. X    active[my_group[cur_groupnum]].read = TRUE;
  2152. X
  2153. X    glob_group = group;
  2154. X    sav_groupnum = cur_groupnum;
  2155. X    
  2156. X    strcpy (group_path, group);            /* turn comp.unix.amiga into */
  2157. X    for (p = group_path; *p; p++)        /* comp/unix/amiga */
  2158. X        if (*p == '.')
  2159. X            *p = '/';
  2160. X
  2161. X    last_resp = -1;
  2162. X    this_resp = -1;
  2163. X    index_group (group, group_path);    /* update index file */
  2164. #if 0 /* JBR */
  2165. X    read_newsrc_line (group);            /* get sequencer information */
  2166. X
  2167. X    if (show_only_unread) {
  2168. X        make_threads (FALSE);
  2169. X        find_base (show_only_unread);
  2170. X    }
  2171. X
  2172. X    debug_print_base ();
  2173. #endif
  2174. X    
  2175. X    if (space_mode) {
  2176. X        for (i = 0; i < top_base; i++) {
  2177. X            if (new_responses (i)) {
  2178. X                break;
  2179. X            }
  2180. X        }
  2181. X        if (i < top_base) {
  2182. X            index_point = i;
  2183. X        } else {
  2184. X            index_point = top_base - 1;
  2185. X        }
  2186. X    } else {
  2187. X        index_point = top_base - 1;
  2188. X    }
  2189. X    if (index_point < 0) {
  2190. X        index_point = 0;
  2191. X    }
  2192. X    
  2193. X    clear_note_area ();
  2194. X
  2195. X    show_group_page (group);
  2196. X
  2197. X    while (TRUE) {
  2198. X        ch = (char) ReadCh ();
  2199. X
  2200. X        if (ch > '0' && ch <= '9') {    /* 0 goes to basenote */
  2201. X            prompt_subject_num (ch, group);
  2202. X            continue;
  2203. X        } 
  2204. X        switch (ch) {
  2205. X            case ESC:    /* common arrow keys */
  2206. X                switch (get_arrow_key ()) {
  2207. X                case KEYMAP_UP:
  2208. X                    goto group_up;
  2209. X
  2210. X                case KEYMAP_DOWN:
  2211. X                    goto group_down;
  2212. X
  2213. X                case KEYMAP_PAGE_UP:
  2214. X                    goto group_page_up;
  2215. X
  2216. X                case KEYMAP_PAGE_DOWN:
  2217. X                    goto group_page_down;
  2218. X
  2219. X                case KEYMAP_HOME:
  2220. X                    if (index_point != 0) {
  2221. X                        index_point = 0;
  2222. X                        show_group_page (group);
  2223. X                    }
  2224. X                    break;
  2225. X                    
  2226. X                case KEYMAP_END:
  2227. X                    goto end_of_list;
  2228. X                }
  2229. X                break;
  2230. X
  2231. #ifndef NO_SHELL_ESCAPE
  2232. X            case '!':
  2233. X                shell_escape ();
  2234. X                show_group_page (group);
  2235. X                break;
  2236. #endif
  2237. X
  2238. X            case '$':    /* show last page of articles */
  2239. end_of_list:            
  2240. X                if (index_point != top_base - 1) {
  2241. X                    index_point = top_base - 1;
  2242. X                    show_group_page (group);
  2243. X                }
  2244. X                break;
  2245. X                
  2246. X            case '-':    /* go to last viewed article */
  2247. X                if (this_resp < 0) {
  2248. X                    info_message (txt_no_last_message);
  2249. SHAR_EOF
  2250. true || echo 'restore of group.c failed'
  2251. fi
  2252. echo 'End of tin1.1 part 4'
  2253. echo 'File group.c is continued in part 5'
  2254. echo 5 > _shar_seq_.tmp
  2255. exit 0
  2256.  
  2257. --
  2258. NAME   Iain Lea 
  2259. EMAIL  iain%anl433.uucp@germany.eu.net
  2260. SNAIL  Siemens AG, ANL A433SZ, Gruendlacher Str. 248, 8510 Fuerth, Germany.
  2261. PHONE  +49-911-3089-407 (work) +49-911-331963 (home) +49-911-3089-290 (FAX)  
  2262. -- 
  2263.  Dr. med. dipl.-math Dieter Becker           Tel.: (0 / +49) 6841 - 16 3046
  2264.  Medizinische Universitaets- und Poliklinik  Fax.: (0 / +49) 6841 - 16 3369
  2265.  Innere Medizin III                         
  2266.  D - 6650 Homburg / Saar                     Email: becker@med-in.uni-sb.de
  2267. exit 0 # Just in case...
  2268.