home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume28 / tin / part04 < prev    next >
Text File  |  1992-02-23  |  52KB  |  2,200 lines

  1. Newsgroups: comp.sources.misc
  2. From: iain%estevax.uucp@unido.Informatik.Uni-Dortmund.DE (Iain Lea)
  3. Subject:  v28i048:  tin - threaded full screen newsreader v1.1, Part04/11
  4. Message-ID: <1992Feb18.043700.13011@sparky.imd.sterling.com>
  5. X-Md4-Signature: e4e1bb749ad26711a058e20a6a7b26a6
  6. Date: Tue, 18 Feb 1992 04:37:00 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: iain%estevax.uucp@unido.Informatik.Uni-Dortmund.DE (Iain Lea)
  10. Posting-number: Volume 28, Issue 48
  11. Archive-name: tin/part04
  12. Environment: BSD, SCO, ISC, SUNOS, SYSVR3, SYSVR4, ULTRIX, XENIX
  13. Supersedes: tin: Volume 23, Issue 15-23
  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 feed.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 feed.c'
  34. else
  35. echo 'x - continuing file feed.c'
  36. sed 's/^X//' << 'SHAR_EOF' >> 'feed.c' &&
  37. X                } else {
  38. X                    if (default_save_file[0]) {
  39. X                        strcpy (file, default_save_file);
  40. X                    } else {
  41. X                        info_message (txt_no_filename);    
  42. X                        return;
  43. X                    }
  44. X                }
  45. X                for (p = file; *p && (*p == ' ' || *p == '\t'); p++) {
  46. X                    continue;
  47. X                }
  48. X                if (! *p) {
  49. X                    info_message (txt_no_filename);
  50. X                    return;
  51. X                }
  52. X                if ((file[0] == '~' || file[0] == '+') && strlen (file) == 1) {
  53. X                    info_message (txt_no_filename);
  54. X                    return;
  55. X                }
  56. X                is_mailbox = create_path (file);
  57. X                if (is_mailbox) {
  58. X                    if ((int) strlen (file) > 1) {
  59. X                        my_strncpy (mailbox, file+1, LEN);        
  60. X                    } else {
  61. X                        my_strncpy (mailbox, glob_group, LEN);
  62. X                        /*
  63. X                         *  convert 1st letter to uppercase
  64. X                         */
  65. X                        if (mailbox[0] >= 'a' && mailbox[0] <= 'z') {
  66. X                            mailbox[0] = mailbox[0] - 32;
  67. X                        }
  68. X                    }
  69. X                    my_strncpy (file, mailbox, LEN);
  70. X                } else {        /* ask for post processing type */
  71. X                    do {
  72. X                        sprintf (msg, "%s%c", txt_post_process_type, proc_ch_default);
  73. X                        wait_message (msg);
  74. X                        MoveCursor (LINES, (int) strlen (msg)-1);
  75. X                        if ((proc_ch = (char) ReadCh ()) == CR)
  76. X                            proc_ch = proc_ch_default;
  77. X                    } while (proc_ch != 'n' && proc_ch != 's' &&
  78. X                            proc_ch != 'u' && proc_ch != 'U');
  79. X                }
  80. X            }
  81. X            clear_message ();
  82. X            break;
  83. X    }
  84. X    
  85. X    switch (ch) {
  86. X        case 'a':        /* article */
  87. X            if (level == GROUP_LEVEL) {
  88. X                art_open (arts[respnum].artnum, group_path);    
  89. X            }
  90. X            switch (function) {
  91. X                case FEED_MAIL:
  92. X                    redraw_screen = mail_to_someone (address);
  93. X                    break;
  94. X                case FEED_PIPE:
  95. X                    fseek (note_fp, 0L, 0);
  96. X                    copy_fp (note_fp, fp, (char *) 0);
  97. X                    break;
  98. X                case FEED_PRINT:
  99. X                    wait_message (txt_printing);
  100. X                    if (print_header) {
  101. X                        fseek (note_fp, 0L, 0);
  102. X                    } else {
  103. X                        fprintf (fp, "From: %s (%s)\n",
  104. X                            arts[respnum].from,arts[respnum].name);
  105. X                        fprintf (fp, "Subject: %s\n", note_h_subj);
  106. X                        fprintf (fp, "Date: %s\n\n", note_h_date);
  107. X                        fseek (note_fp, note_mark[0], 0);
  108. X                    }
  109. X                    copy_fp (note_fp, fp, (char *) 0);
  110. X                    pclose (fp);        
  111. X                    break;
  112. X                case FEED_SAVE:
  113. X                    wait_message (txt_saving);
  114. X                    add_to_save_list (0, &arts[respnum], is_mailbox, file);
  115. X                    (void) save_art_to_file (respnum, 0, FALSE, (char *) 0);
  116. X                    break;
  117. X            }
  118. X            if (mark_saved_read) {
  119. X                arts[respnum].unread = ART_READ;
  120. X            }
  121. X            if (level == GROUP_LEVEL) {
  122. X                art_close ();
  123. X            }
  124. X            break;
  125. X            
  126. X        case 't':         /* thread */
  127. X            for (i = (int) base[b]; i >= 0; i = arts[i].thread) {
  128. X                if (function == FEED_PRINT) {
  129. X                    if ((fp = popen (command, "w")) == NULL) {
  130. X                        error_message (txt_command_failed_s, command);
  131. X                        return;
  132. X                    }
  133. X                }
  134. X                if (level == PAGE_LEVEL) {
  135. X                    art_close ();
  136. X                }
  137. X                art_open (arts[i].artnum, group_path);    
  138. X                switch (function) {
  139. X                    case FEED_MAIL:
  140. X                        mail_to_someone (address);
  141. X                        break;
  142. X                    case FEED_PIPE:
  143. X                        fseek (note_fp, 0L, 0);
  144. X                        copy_fp (note_fp, fp, (char *) 0);
  145. X                        break;
  146. X                    case FEED_PRINT:
  147. X                        sprintf (msg, "%s%d", txt_printing, count++);
  148. X                        wait_message (msg);
  149. X                        if (print_header) {
  150. X                            fseek(note_fp, 0L, 0);
  151. X                        } else {
  152. X                            fprintf (fp, "From: %s (%s)\n",
  153. X                                arts[respnum].from,arts[respnum].name);
  154. X                            fprintf (fp, "Subject: %s\n", note_h_subj);
  155. X                            fprintf (fp, "Date: %s\n\n", note_h_date);
  156. X                            fseek (note_fp, note_mark[0], 0);
  157. X                        }
  158. X                        copy_fp (note_fp, fp, (char *) 0);
  159. X                        pclose (fp);
  160. X                        break;
  161. X                    case FEED_SAVE:
  162. X                        add_to_save_list (i, &arts[i], is_mailbox, file);
  163. X                        break;
  164. X                }
  165. X                if (mark_saved_read) {
  166. X                    arts[i].unread = ART_READ;
  167. X                }
  168. X                art_close ();
  169. X            }
  170. X            if (function == FEED_SAVE) {
  171. X                sort_save_list ();
  172. X                (void) save_thread_to_file (is_mailbox, group_path);
  173. X            }
  174. X            break;
  175. X
  176. X        case 'T':         /* tagged articles */
  177. X            for (i=1 ; i <= num_of_tagged_files ; i++) {
  178. X                for (j=0 ; j < top ; j++) {
  179. X                    if (arts[j].tagged && arts[j].tagged == i) { 
  180. X                        if (function == FEED_PRINT) {
  181. X                            if ((fp = popen (command, "w")) == NULL) {
  182. X                                error_message (txt_command_failed_s, command);
  183. X                                return;
  184. X                            }
  185. X                        }
  186. X                        if (level == PAGE_LEVEL) {
  187. X                            art_close ();
  188. X                        }
  189. X                        art_open (arts[j].artnum, group_path);    
  190. X                        switch (function) {
  191. X                            case FEED_MAIL:
  192. X                                mail_to_someone (address);
  193. X                                break;
  194. X                            case FEED_PIPE:
  195. X                                fseek (note_fp, 0L, 0);
  196. X                                copy_fp (note_fp, fp, (char *) 0);
  197. X                                break;
  198. X                            case FEED_PRINT:
  199. X                                sprintf (msg, "%s%d", txt_printing, count++);
  200. X                                wait_message (msg);
  201. X                                if (print_header) {
  202. X                                    fseek(note_fp, 0L, 0);
  203. X                                } else {
  204. X                                    fprintf (fp, "From: %s (%s)\n",
  205. X                                        arts[respnum].from,arts[respnum].name);
  206. X                                    fprintf (fp, "Subject: %s\n", note_h_subj);
  207. X                                    fprintf (fp, "Date: %s\n\n", note_h_date);
  208. X                                    fseek (note_fp, note_mark[0], 0);
  209. X                                }
  210. X                                copy_fp (note_fp, fp, (char *) 0);
  211. X                                pclose (fp);
  212. X                                break;
  213. X                            case FEED_SAVE:
  214. X                                add_to_save_list (j, &arts[j], is_mailbox, file);
  215. X                                break;
  216. X                        }
  217. X                        if (mark_saved_read) {
  218. X                            arts[j].unread = ART_READ;
  219. X                        }
  220. X                        art_close ();
  221. X                    }
  222. X                }
  223. X            }
  224. X            if (function == FEED_SAVE) {                
  225. X                (void) save_regex_arts (is_mailbox, group_path);
  226. X            }
  227. X            break;
  228. X
  229. X        case 'r':         /* regex pattern matched articles */
  230. X            patlen = strlen (pattern);
  231. X            for (i=0 ; i < top ; i++) {
  232. #ifdef NO_REGEX
  233. X                if (str_str (arts[i].subject, pattern, patlen) != 0) {
  234. #else        
  235. X                if (wildmat (arts[i].subject, pattern)) {
  236. #endif        
  237. X                    if (function == FEED_PRINT) {
  238. X                        if ((fp = popen (command, "w")) == NULL) {
  239. X                            error_message (txt_command_failed_s, command);
  240. X                            return;
  241. X                        }
  242. X                    }
  243. X                    if (level == PAGE_LEVEL) {
  244. X                        art_close ();
  245. X                    }
  246. X                    art_open (arts[i].artnum, group_path);    
  247. X                    switch (function) {
  248. X                        case FEED_MAIL:
  249. X                            mail_to_someone (address);
  250. X                            break;
  251. X                        case FEED_PIPE:
  252. X                            fseek (note_fp, 0L, 0);
  253. X                            copy_fp (note_fp, fp, (char *) 0);
  254. X                            break;
  255. X                        case FEED_PRINT:
  256. X                            sprintf (msg, "%s%d", txt_printing, count++);
  257. X                            wait_message (msg);    
  258. X                            if (print_header) {
  259. X                                fseek(note_fp, 0L, 0);
  260. X                            } else {
  261. X                                fprintf (fp, "From: %s (%s)\n",
  262. X                                    arts[respnum].from,arts[respnum].name);
  263. X                                fprintf (fp, "Subject: %s\n", note_h_subj);
  264. X                                fprintf (fp, "Date: %s\n\n", note_h_date);
  265. X                                fseek (note_fp, note_mark[0], 0);
  266. X                            }
  267. X                            copy_fp (note_fp, fp, (char *) 0);
  268. X                            pclose (fp);
  269. X                            break;
  270. X                        case FEED_SAVE:
  271. X                            add_to_save_list (i, &arts[i], is_mailbox, file);
  272. X                            break;
  273. X                    }
  274. X                    if (mark_saved_read) {
  275. X                        arts[i].unread = ART_READ;
  276. X                    }
  277. X                     art_close ();
  278. X                }
  279. X            }
  280. X            if (function == FEED_SAVE) {                
  281. X                sort_save_list ();
  282. X                (void) save_regex_arts (is_mailbox, group_path);
  283. X            }
  284. X            break;
  285. X    }
  286. X
  287. X    redraw_screen = mail_check ();    /* in case of sending to oneself */
  288. X
  289. X    switch (function) {
  290. X        case FEED_PIPE:
  291. X            pclose (fp);        
  292. X            Raw (TRUE);
  293. X            continue_prompt ();
  294. X            redraw_screen = TRUE;
  295. X            break;
  296. X        case FEED_SAVE:
  297. X            if (proc_ch != 'n' && is_mailbox == FALSE) {
  298. X                ret2 = post_process_files (proc_ch);
  299. X            }
  300. X            free_save_array ();
  301. X            break;
  302. X    }
  303. X
  304. X    untag_all_articles ();
  305. X    
  306. X    if (level == GROUP_LEVEL) {
  307. X        ret1 = (mark_saved_read ? TRUE : FALSE);
  308. X    }
  309. X    if ((ret1 || ret2) && is_mailbox == FALSE) {
  310. X        redraw_screen = TRUE;
  311. X    }
  312. X
  313. X    if (level == PAGE_LEVEL) {
  314. X        if (ch != 'a') {
  315. X            art_open (arts[respnum].artnum, group_path);
  316. X        }
  317. X        note_end = orig_note_end;
  318. X        note_page = orig_note_page;
  319. X        fseek (note_fp, note_mark[note_page], 0);
  320. X        if (redraw_screen) {
  321. X            if (note_page == 0) {
  322. X                show_note_page (respnum, glob_group);
  323. X            } else {
  324. X                redraw_page (respnum, glob_group);
  325. X            }
  326. X        } else {
  327. X            if (function == FEED_PIPE) {
  328. X                clear_message ();
  329. X            }
  330. X        }
  331. X    } else {
  332. X        if (redraw_screen) {
  333. X            show_group_page (glob_group);
  334. X        }
  335. X    }
  336. X    if (function == FEED_PRINT) {    
  337. X        info_message (txt_printed);
  338. X    }
  339. }
  340. SHAR_EOF
  341. echo 'File feed.c is complete' &&
  342. chmod 0600 feed.c ||
  343. echo 'restore of feed.c failed'
  344. Wc_c="`wc -c < 'feed.c'`"
  345. test 12822 -eq "$Wc_c" ||
  346.     echo 'feed.c: original size 12822, current size' "$Wc_c"
  347. rm -f _shar_wnt_.tmp
  348. fi
  349. # ============= getline.c ==============
  350. if test -f 'getline.c' -a X"$1" != X"-c"; then
  351.     echo 'x - skipping getline.c (File already exists)'
  352.     rm -f _shar_wnt_.tmp
  353. else
  354. > _shar_wnt_.tmp
  355. echo 'x - extracting getline.c (Text)'
  356. sed 's/^X//' << 'SHAR_EOF' > 'getline.c' &&
  357. /*
  358. X *  Project   : tin - a threaded Netnews reader
  359. X *  Module    : getline.c
  360. X *  Author    : Chris Thewalt / Iain Lea 
  361. X *  Created   : 09-11-91
  362. X *  Updated   : 29-11-91
  363. X *  Notes     : emacs style line editing input package.  
  364. X *  Copyright : (c) Copyright 1991-92 by Chris Thewalt & Iain Lea
  365. X *              Permission to use, copy, modify, and distribute this
  366. X *              software for any purpose and without fee is hereby
  367. X *              granted, provided that the above copyright notices
  368. X *              appear in all copies and that both the copyright
  369. X *              notice and this permission notice appear in supporting
  370. X *              documentation. This software is provided "as is" without\
  371. X *              express or implied warranty.
  372. X */
  373. X
  374. #include "tin.h"
  375. X
  376. extern int      isatty ();    
  377. X
  378. #define BUF_SIZE    1024
  379. #define SCROLL        30
  380. #define TABSIZE        4
  381. #ifndef HIST_SIZE
  382. #define HIST_SIZE    100
  383. #endif
  384. X
  385. #define CTRL_A    '\001'
  386. #define CTRL_B    '\002'
  387. #define CTRL_D    '\004'
  388. #define CTRL_E    '\005'
  389. #define CTRL_F    '\006'
  390. #define CTRL_H    '\010'
  391. #define CTRL_K    '\013'
  392. #define CTRL_L    '\014'
  393. #define CTRL_R    '\022'
  394. #define CTRL_N    '\016'
  395. #define CTRL_P    '\020'
  396. #define TAB        '\t'
  397. #define DEL        '\177'
  398. X
  399. char    *hist_buf[HIST_SIZE];
  400. int        hist_pos, hist_last;
  401. static char gl_buf[BUF_SIZE];       /* input buffer */
  402. static char *gl_prompt;                /* to save the prompt string */
  403. static int  gl_init_done = 0;        /* -1 is terminal, 1 is batch  */
  404. static int  gl_width = 0;            /* net size available for input */
  405. static int  gl_pos, gl_cnt = 0;     /* position and size of input */
  406. X
  407. #if __STDC__
  408. X
  409. static int      gl_tab (char *, int, int *);
  410. static void        gl_redraw (void);
  411. static void     gl_addchar (int);
  412. static void     gl_newline (void);
  413. static void     gl_fixup (int, int);
  414. static void     gl_del (int);
  415. static void     gl_kill (void);
  416. static void     hist_add (void);
  417. static void     hist_init (void);
  418. static void     hist_next (void);
  419. static void     hist_prev (void);
  420. X
  421. int     (*gl_in_hook)(char *) = 0;
  422. int     (*gl_out_hook)(char *) = 0;
  423. int     (*gl_tab_hook)(char *, int, int *) = gl_tab;
  424. X
  425. #else
  426. X
  427. static int      gl_tab ();
  428. static void        gl_redraw ();
  429. static void     gl_addchar ();
  430. static void     gl_newline ();
  431. static void     gl_fixup ();
  432. static void     gl_del ();
  433. static void     gl_kill ();
  434. static void     hist_add ();
  435. static void     hist_init ();
  436. static void     hist_next ();
  437. static void     hist_prev ();
  438. X
  439. int     (*gl_in_hook)() = 0;
  440. int     (*gl_out_hook)() = 0;
  441. int     (*gl_tab_hook)() = gl_tab;
  442. X
  443. #endif
  444. X
  445. X
  446. #if __STDC__
  447. char *getline (char *prompt, int number_only, char *str)
  448. #else
  449. char *getline (prompt, number_only, str)
  450. X    char *prompt;
  451. X    int number_only;
  452. X    char *str;
  453. #endif
  454. {
  455. X    int c, i, loc, tmp;
  456. X
  457. X    if (! gl_init_done) {
  458. X        gl_init_done = 1;
  459. X        hist_init ();
  460. X    }
  461. X
  462. X    gl_buf[0] = 0;        /* used as end of input indicator */
  463. X    gl_fixup (-1, 0);    /* this resets gl_fixup */
  464. X    gl_width = COLS - strlen (prompt);
  465. X    if (prompt == (char *) 0) {    
  466. X        prompt = "";
  467. X    }
  468. X    gl_prompt = prompt;
  469. X    gl_pos = gl_cnt = 0;
  470. X
  471. X    fputs (prompt, stdout);
  472. X    fflush (stdout);
  473. X    
  474. X    if (gl_in_hook) {
  475. X        loc = gl_in_hook (gl_buf);
  476. X        if (loc >= 0)
  477. X            gl_fixup (0, BUF_SIZE);
  478. X    }
  479. X    if (str != (char *) 0) {
  480. X        for (i=0 ; str[i] ; i++) 
  481. X            gl_addchar (str[i]);
  482. X    }
  483. X    while ((c = ReadCh ()) != EOF) {
  484. X        if (isprint (c)) {
  485. X            if (number_only) {
  486. X                if (isdigit (c) && gl_cnt < 6) {    /* num < 100000 */
  487. X                    gl_addchar (c);
  488. X                } else {
  489. X                    ring_bell ();
  490. X                }
  491. X            } else {
  492. X                gl_addchar (c);
  493. X            }
  494. X        } else {
  495. X            switch (c) {
  496. X                case ESC:             /* abort */
  497. X                    return (char *) 0;
  498. X                    break;
  499. X                case '\n':             /* newline */
  500. X                case '\r':
  501. X                    gl_newline ();
  502. X                    return gl_buf;
  503. X                    break;
  504. X                case CTRL_A:
  505. X                    gl_fixup (-1, 0);
  506. X                    break;
  507. X                case CTRL_B:
  508. X                    gl_fixup (-1, gl_pos-1);
  509. X                    break;
  510. X                case CTRL_D:
  511. X                    if (gl_cnt == 0) {
  512. X                        gl_buf[0] = 0;
  513. X                        fputc ('\n', stdout);
  514. X                        return gl_buf;
  515. X                    } else {
  516. X                        gl_del (0);
  517. X                    }
  518. X                    break;
  519. X                case CTRL_E:
  520. X                    gl_fixup (-1, gl_cnt);
  521. X                    break;
  522. X                case CTRL_F:
  523. X                    gl_fixup (-1, gl_pos+1);
  524. X                    break;
  525. X                case CTRL_H:
  526. X                case DEL:
  527. X                    gl_del (-1);
  528. X                    break;
  529. X                case TAB:
  530. X                    if (gl_tab_hook) {
  531. X                        tmp = gl_pos;
  532. X                        loc = gl_tab_hook (gl_buf, strlen (gl_prompt), &tmp);
  533. X                        if (loc >= 0 || tmp != gl_pos)
  534. X                            gl_fixup (loc, tmp);
  535. X                    }
  536. X                    break;
  537. X                case CTRL_K:
  538. X                    gl_kill ();
  539. X                    break;
  540. X                case CTRL_L:
  541. X                case CTRL_R:
  542. X                    gl_redraw ();
  543. X                    break;
  544. X                case CTRL_N:
  545. X                    hist_next ();
  546. X                    break;
  547. X                case CTRL_P:
  548. X                    hist_prev ();
  549. X                    break;
  550. X                default:
  551. X                    ring_bell ();
  552. X                    break;
  553. X            }
  554. X        }
  555. X    }
  556. X    return gl_buf;
  557. }
  558. X
  559. /*
  560. X * adds the character c to the input buffer at current location if
  561. X * the character is in the allowed template of characters
  562. X */
  563. X
  564. #if __STDC__
  565. static void gl_addchar (int c, char *template, int len)
  566. #else
  567. static void gl_addchar (c, template, len)
  568. X    int c;
  569. X    char *template;
  570. X    int len;
  571. #endif
  572. {
  573. X    int  i;
  574. X
  575. X    if (gl_cnt >= BUF_SIZE - 1) {
  576. X        error_message ("getline: input buffer overflow");
  577. X        exit (1);
  578. X    }
  579. X    
  580. X    for (i=gl_cnt; i >= gl_pos; i--) {
  581. X        gl_buf[i+1] = gl_buf[i];
  582. X    }
  583. X    gl_buf[gl_pos] = c;
  584. X    gl_fixup (gl_pos, gl_pos+1);
  585. }
  586. X
  587. /*
  588. X * Cleans up entire line before returning to caller. A \n is appended.
  589. X * If line longer than screen, we redraw starting at beginning
  590. X */
  591. X
  592. static void gl_newline ()
  593. {
  594. X    int change = gl_cnt;
  595. X    int len = gl_cnt;
  596. X    int loc = gl_width - 5;    /* shifts line back to start position */
  597. X
  598. X    if (gl_cnt >= BUF_SIZE - 1) {
  599. X        error_message ("getline: input buffer overflow");
  600. X        exit (1);
  601. X    }
  602. X    hist_add ();            /* only adds if nonblank */
  603. X    if (gl_out_hook) {
  604. X        change = gl_out_hook (gl_buf);
  605. X        len = strlen (gl_buf);
  606. X    } 
  607. X    if (loc > len)
  608. X        loc = len;
  609. X    gl_fixup (change, loc);    /* must do this before appending \n */
  610. X    gl_buf[len] = '\0';
  611. }
  612. X
  613. /*
  614. X * Delete a character.  The loc variable can be:
  615. X *    -1 : delete character to left of cursor
  616. X *     0 : delete character under cursor
  617. X */
  618. X
  619. #if __STDC__
  620. static void gl_del (int loc)
  621. #else
  622. static void gl_del (loc)
  623. X    int loc;
  624. #endif
  625. {
  626. X    int i;
  627. X
  628. X    if (loc == -1 && gl_pos > 0 || loc == 0 && gl_pos < gl_cnt) {
  629. X        for (i=gl_pos+loc; i < gl_cnt; i++)
  630. X            gl_buf[i] = gl_buf[i+1];
  631. X        gl_fixup (gl_pos+loc, gl_pos+loc);
  632. X    } else {
  633. X        ring_bell ();
  634. X    }
  635. }
  636. X
  637. /*
  638. X * delete from current position to the end of line
  639. X */
  640. static void gl_kill ()
  641. {
  642. X    if (gl_pos < gl_cnt) {
  643. X        gl_buf[gl_pos] = '\0';
  644. X        gl_fixup (gl_pos, gl_pos);
  645. X    } else {
  646. X        ring_bell ();
  647. X    }
  648. }
  649. X
  650. /*
  651. X * emit a newline, reset and redraw prompt and current input line
  652. X */
  653. X
  654. static void gl_redraw ()
  655. {
  656. X    if (gl_init_done == -1) {
  657. X        fputc ('\n', stdout);
  658. X        fputs (gl_prompt, stdout);
  659. X        gl_pos = 0;
  660. X        gl_fixup (0, BUF_SIZE);
  661. X    }
  662. }
  663. X
  664. /*
  665. X * This function is used both for redrawing when input changes or for
  666. X * moving within the input line.  The parameters are:
  667. X *   change : the index of the start of changes in the input buffer,
  668. X *            with -1 indicating no changes.
  669. X *   cursor : the desired location of the cursor after the call.
  670. X *            A value of BUF_SIZE can be used to indicate the cursor
  671. X *            should move just past the end of the input line.
  672. X */
  673. X
  674. #if __STDC__
  675. static void gl_fixup (int change, int cursor)
  676. #else
  677. static void gl_fixup (change, cursor)
  678. X    int change;
  679. X    int cursor;
  680. #endif
  681. {
  682. X    static int   gl_shift;    /* index of first on screen character */
  683. X    static int   off_right;    /* true if more text right of screen */
  684. X    static int   off_left;    /* true if more text left of screen */
  685. X    int          left = 0, right = -1;        /* bounds for redraw */
  686. X    int          pad;        /* how much to erase at end of line */
  687. X    int          backup;        /* how far to backup before fixing */
  688. X    int          new_shift;     /* value of shift based on cursor */
  689. X    int          extra;         /* adjusts when shift (scroll) happens */
  690. X    int          i;
  691. X
  692. X    if (change == -1 && cursor == 0 && gl_buf[0] == 0) {   /* reset */
  693. X        gl_shift = off_right = off_left = 0;
  694. X        return;
  695. X    }
  696. X    pad = (off_right) ? gl_width - 1 : gl_cnt - gl_shift;   /* old length */
  697. X    backup = gl_pos - gl_shift;
  698. X    if (change >= 0) {
  699. X        gl_cnt = strlen (gl_buf);
  700. X        if (change > gl_cnt)
  701. X            change = gl_cnt;
  702. X    }
  703. X    if (cursor > gl_cnt) {
  704. X        if (cursor != BUF_SIZE)        /* BUF_SIZE means end of line */
  705. X            ring_bell ();
  706. X            cursor = gl_cnt;
  707. X    }
  708. X    if (cursor < 0) {
  709. X        ring_bell ();
  710. X        cursor = 0;
  711. X    }
  712. X    if (off_right || off_left && cursor < gl_shift + gl_width - SCROLL / 2)
  713. X        extra = 2;            /* shift the scrolling boundary */
  714. X    else 
  715. X        extra = 0;
  716. X    new_shift = cursor + extra + SCROLL - gl_width;
  717. X    if (new_shift > 0) {
  718. X        new_shift /= SCROLL;
  719. X        new_shift *= SCROLL;
  720. X    } else
  721. X        new_shift = 0;
  722. X    if (new_shift != gl_shift) {    /* scroll occurs */
  723. X        gl_shift = new_shift;
  724. X        off_left = (gl_shift) ? 1 : 0;
  725. X        off_right = (gl_cnt > gl_shift + gl_width - 1)? 1 : 0;
  726. X        left = gl_shift;
  727. X        right = (off_right) ? gl_shift + gl_width - 2 : gl_cnt;
  728. X    } else if (change >= 0) {        /* no scroll, but text changed */
  729. X        if (change < gl_shift + off_left) {
  730. X            left = gl_shift;
  731. X        } else {
  732. X            left = change;
  733. X            backup = gl_pos - change;
  734. X        }
  735. X        off_right = (gl_cnt > gl_shift + gl_width - 1)? 1 : 0;
  736. X        right = (off_right) ? gl_shift + gl_width - 2 : gl_cnt;
  737. X    }
  738. X    pad -= (off_right) ? gl_width - 1 : gl_cnt - gl_shift;
  739. X    pad = (pad < 0)? 0 : pad;
  740. X    if (left <= right) {        /* clean up screen */
  741. X        for (i=0; i < backup; i++)
  742. X            fputc ('\b', stdout);
  743. X        if (left == gl_shift && off_left) {
  744. X            fputc ('$', stdout);
  745. X            left++;
  746. X        }
  747. X        for (i=left; i < right; i++)
  748. X            fputc (gl_buf[i], stdout);
  749. X        if (off_right) {
  750. X            fputc ('$', stdout);
  751. X            gl_pos = right + 1;
  752. X        } else { 
  753. X            for (i=0; i < pad; i++)    /* erase remains of prev line */
  754. X                fputc (' ', stdout);
  755. X            gl_pos = right + pad;
  756. X        }
  757. X    }
  758. X    i = gl_pos - cursor;        /* move to final cursor location */
  759. X    if (i > 0) {
  760. X        while (i--)
  761. X            fputc ('\b', stdout);
  762. X    } else {
  763. X        for (i=gl_pos; i < cursor; i++)
  764. X            fputc (gl_buf[i], stdout);
  765. X    }
  766. X    fflush (stdout);
  767. X    gl_pos = cursor;
  768. }
  769. X    
  770. /*
  771. X * default tab handler, acts like tabstops every TABSIZE cols
  772. X */
  773. X
  774. #if __STDC__
  775. static int gl_tab (char *buf, int offset, int *loc)
  776. #else
  777. static int gl_tab (buf, offset, loc)
  778. X    char *buf;
  779. X    int offset;
  780. X    int *loc;
  781. #endif
  782. {
  783. X    int i, count, len;
  784. X    
  785. X    len = strlen (buf);
  786. X    count = TABSIZE - (offset + *loc) % TABSIZE;
  787. X    for (i=len; i >= *loc; i--)
  788. X        buf[i+count] = buf[i];
  789. X    for (i=0; i < count; i++)
  790. X        buf[*loc+i] = ' ';
  791. X    i = *loc;
  792. X    *loc = i + count;
  793. X    return i;
  794. }
  795. X
  796. /*
  797. X * History functions
  798. X */
  799. X
  800. static void hist_init ()
  801. {
  802. X    int i;
  803. X    
  804. X    for (i=0; i < HIST_SIZE; i++)
  805. X        hist_buf[i] = (char *) 0;
  806. }
  807. X
  808. X
  809. static void hist_add ()
  810. {
  811. X    char *p = gl_buf;
  812. X
  813. X    while (*p == ' ' || *p == '\t')    /* only save nonblank line */
  814. X        p++;
  815. X    if (*p) {
  816. X        hist_buf[hist_last] = str_dup (gl_buf);
  817. X        hist_last = (hist_last + 1) % HIST_SIZE;
  818. X        if (hist_buf[hist_last]) {    /* erase next location */
  819. X            free(hist_buf[hist_last]);
  820. X            hist_buf[hist_last] = (char *) 0;
  821. X        }
  822. X    }
  823. X    hist_pos = hist_last;
  824. }
  825. X
  826. /*
  827. X * loads previous hist entry into input buffer, sticks on first
  828. X */
  829. static void hist_prev ()
  830. {
  831. X    int   next;
  832. X
  833. X    next = (hist_pos - 1 + HIST_SIZE) % HIST_SIZE;
  834. X    if (next != hist_last) {
  835. X        if (hist_buf[next]) {
  836. X            hist_pos = next;
  837. X            strcpy (gl_buf, hist_buf[hist_pos]);
  838. X        } else {
  839. X            ring_bell ();
  840. X        }
  841. X    } else {
  842. X        ring_bell ();
  843. X    }
  844. X    if (gl_in_hook)
  845. X        gl_in_hook (gl_buf);
  846. X    gl_fixup (0, BUF_SIZE);
  847. }
  848. X
  849. /*
  850. X * loads next hist entry into input buffer, clears on last
  851. X */
  852. static void hist_next ()
  853. {
  854. X    if (hist_pos != hist_last) {
  855. X        hist_pos = (hist_pos + 1) % HIST_SIZE;
  856. X        if (hist_buf[hist_pos]) {
  857. X            strcpy (gl_buf, hist_buf[hist_pos]);
  858. X        } else {
  859. X            gl_buf[0] = 0;
  860. X        }
  861. X    } else {
  862. X        ring_bell ();
  863. X    }
  864. X    if (gl_in_hook) 
  865. X        gl_in_hook (gl_buf);
  866. X    gl_fixup (0, BUF_SIZE);
  867. }
  868. SHAR_EOF
  869. chmod 0600 getline.c ||
  870. echo 'restore of getline.c failed'
  871. Wc_c="`wc -c < 'getline.c'`"
  872. test 11498 -eq "$Wc_c" ||
  873.     echo 'getline.c: original size 11498, current size' "$Wc_c"
  874. rm -f _shar_wnt_.tmp
  875. fi
  876. # ============= group.c ==============
  877. if test -f 'group.c' -a X"$1" != X"-c"; then
  878.     echo 'x - skipping group.c (File already exists)'
  879.     rm -f _shar_wnt_.tmp
  880. else
  881. > _shar_wnt_.tmp
  882. echo 'x - extracting group.c (Text)'
  883. sed 's/^X//' << 'SHAR_EOF' > 'group.c' &&
  884. /*
  885. X *  Project   : tin - a threaded Netnews reader
  886. X *  Module    : group.c
  887. X *  Author    : R.Skrenta / I.Lea
  888. X *  Created   : 01-04-91
  889. X *  Updated   : 23-01-92
  890. X *  Notes     :
  891. X *  Copyright : (c) Copyright 1991-92 by Rich Skrenta & Iain Lea
  892. X *                You may  freely  copy or  redistribute  this software,
  893. X *              so  long as there is no profit made from its use, sale
  894. X *              trade or  reproduction.  You may not change this copy-
  895. X *              right notice, and it must be included in any copy made
  896. X */
  897. X
  898. #include    "tin.h"
  899. X
  900. extern char cvers[LEN];
  901. extern int cur_groupnum;
  902. extern int last_resp;        /* page.c */
  903. extern int this_resp;        /* page.c */
  904. X
  905. char *glob_group;
  906. int index_point;
  907. int first_subj_on_screen;
  908. int last_subj_on_screen;
  909. X
  910. X
  911. void group_page (group)
  912. X    char *group;
  913. {
  914. X    char group_path[LEN];
  915. X    char ch;
  916. X    char *p;
  917. X    int flag, i, n;
  918. X    int kill_state;
  919. X    int old_top;
  920. X    int posted;
  921. X    int sav_groupnum;
  922. X    int scroll_lines;
  923. X    int thread_marked_unread = FALSE;
  924. X    long old_artnum;
  925. X
  926. X    active[my_group[cur_groupnum]].read = TRUE;
  927. X
  928. X    glob_group = group;
  929. X    sav_groupnum = cur_groupnum;
  930. X    
  931. X    strcpy (group_path, group);            /* turn comp.unix.amiga into */
  932. X    for (p = group_path; *p; p++)        /* comp/unix/amiga */
  933. X        if (*p == '.')
  934. X            *p = '/';
  935. X
  936. X    last_resp = -1;
  937. X    this_resp = -1;
  938. X    index_group (group, group_path);    /* update index file */
  939. X    read_newsrc_line (group);            /* get sequencer information */
  940. X
  941. X    if (show_only_unread) {
  942. X        make_threads (FALSE);
  943. X        find_base (show_only_unread);
  944. X    }
  945. X
  946. X    debug_print_base ();
  947. X    
  948. X    if (space_mode) {
  949. X        for (i = 0; i < top_base; i++) {
  950. X            if (new_responses (i)) {
  951. X                break;
  952. X            }
  953. X        }
  954. X        if (i < top_base) {
  955. X            index_point = i;
  956. X        } else {
  957. X            index_point = top_base - 1;
  958. X        }
  959. X    } else {
  960. X        index_point = top_base - 1;
  961. X    }
  962. X    if (index_point < 0) {
  963. X        index_point = 0;
  964. X    }
  965. X    
  966. X    clear_note_area ();
  967. X
  968. X    show_group_page (group);
  969. X
  970. X    while (TRUE) {
  971. X        ch = (char) ReadCh ();
  972. X
  973. X        if (ch > '0' && ch <= '9') {    /* 0 goes to basenote */
  974. X            prompt_subject_num (ch, group);
  975. X        } else switch (ch) {
  976. X            case ESC:    /* common arrow keys */
  977. X                switch (get_arrow_key ()) {
  978. X                case KEYMAP_UP:
  979. X                    goto group_up;
  980. X
  981. X                case KEYMAP_DOWN:
  982. X                    goto group_down;
  983. X
  984. X                case KEYMAP_PAGE_UP:
  985. X                    goto group_page_up;
  986. X
  987. X                case KEYMAP_PAGE_DOWN:
  988. X                    goto group_page_down;
  989. X
  990. X                case KEYMAP_HOME:
  991. X                    if (index_point != 0) {
  992. X                        index_point = 0;
  993. X                        show_group_page (group);
  994. X                    }
  995. X                    break;
  996. X                    
  997. X                case KEYMAP_END:
  998. X                    goto end_of_list;
  999. X                }
  1000. X                break;
  1001. X
  1002. #ifndef NO_SHELL_ESCAPE
  1003. X            case '!':
  1004. X                shell_escape ();
  1005. X                show_group_page (group);
  1006. X                break;
  1007. #endif
  1008. X
  1009. X            case '$':    /* show last page of articles */
  1010. end_of_list:            
  1011. X                if (index_point != top_base - 1) {
  1012. X                    index_point = top_base - 1;
  1013. X                    show_group_page (group);
  1014. X                }
  1015. X                break;
  1016. X                
  1017. X            case '-':    /* go to last viewed article */
  1018. X                if (this_resp < 0) {
  1019. X                    info_message (txt_no_last_message);
  1020. X                    break;
  1021. X                }
  1022. X                index_point = show_page (this_resp, group, group_path);
  1023. X                if (index_point < 0) {
  1024. X                    space_mode = FALSE;
  1025. X                    goto group_done;
  1026. X                }
  1027. X                clear_note_area ();
  1028. X                show_group_page (group);
  1029. X                break;
  1030. X
  1031. X            case '|':    /* pipe article/thread/tagged arts to command */
  1032. X                if (index_point >= 0) {
  1033. X                    set_real_uid_gid ();
  1034. X                    feed_articles (FEED_PIPE, GROUP_LEVEL, "Pipe",
  1035. X                        (int) base[index_point], group_path);
  1036. X                    set_tin_uid_gid ();
  1037. X                }
  1038. X                break;
  1039. X
  1040. X            case '/':    /* forward/backward search */
  1041. X            case '?':
  1042. X                i = (ch == '/');
  1043. X                search_subject (i, group);
  1044. X                break;
  1045. X
  1046. X            case '\r':
  1047. X            case '\n':    /* read current basenote */
  1048. X                if (index_point < 0) {
  1049. X                    info_message(txt_no_arts);
  1050. X                    break;
  1051. X                }
  1052. X                i = (int) base[index_point];
  1053. X                index_point = show_page (i, group, group_path);
  1054. X                if (index_point < 0) {
  1055. X                    space_mode = FALSE;
  1056. X                    goto group_done;
  1057. X                }
  1058. X                clear_note_area ();
  1059. X                show_group_page (group);
  1060. X                break;
  1061. X
  1062. X            case '\t':
  1063. X                 space_mode = TRUE;
  1064. X
  1065. X                if (index_point < 0
  1066. X                || (n=next_unread((int) base[index_point]))<0) {
  1067. X                    for (i = cur_groupnum+1 ; i < group_top ; i++)
  1068. X                        if (unread[i] > 0)
  1069. X                            break;
  1070. X                    if (i >= group_top)
  1071. X                        goto group_done;
  1072. X
  1073. X                    cur_groupnum = i;
  1074. X                    index_point = -3;
  1075. X                    goto group_done;
  1076. X                }
  1077. X                index_point = show_page(n, group, group_path);
  1078. X                if (index_point < 0)
  1079. X                    goto group_done;
  1080. X                clear_note_area ();
  1081. X                show_group_page(group);
  1082. X                break;
  1083. X    
  1084. X            case ' ':            /* page down */
  1085. X            case ctrl('D'):        /* vi style */
  1086. X            case ctrl('V'):        /* emacs style */
  1087. group_page_down:
  1088. X                if (! top_base || index_point == top_base - 1)
  1089. X                    break;
  1090. X
  1091. X                erase_subject_arrow ();
  1092. X                scroll_lines = (full_page_scroll ? NOTESLINES : NOTESLINES / 2);
  1093. X                index_point = ((index_point + scroll_lines) / scroll_lines) * scroll_lines;
  1094. X                if (index_point >= top_base) {
  1095. X                    index_point = (top_base / scroll_lines) * scroll_lines;
  1096. X                    if (index_point < top_base - 1) {
  1097. X                        index_point = top_base - 1;
  1098. X                    }
  1099. X                }
  1100. X                if (index_point < first_subj_on_screen
  1101. X                || index_point >= last_subj_on_screen)
  1102. X                    show_group_page (group);
  1103. X                else
  1104. X                    draw_subject_arrow ();
  1105. X                break;
  1106. X
  1107. X            case ctrl('K'):        /* kill article */
  1108. X                 if (index_point < 0) {
  1109. X                     info_message (txt_no_arts);
  1110. X                    break;
  1111. X                }
  1112. X                if (kill_articles) {
  1113. X                    old_top = top;
  1114. X                    n = (int) base[index_point];
  1115. X                    old_artnum = arts[n].artnum;
  1116. X                    if (kill_art_menu (group, (int) base[index_point])) {
  1117. X                        kill_any_articles (group);
  1118. X                        reload_index_file (group, TRUE);
  1119. X                        index_point = find_new_pos (old_top, old_artnum, index_point);
  1120. X                    }
  1121. X                    show_group_page (group);
  1122. X                } else {
  1123. X                    info_message (txt_switch_on_kill_art_menu);
  1124. X                }
  1125. X                break;
  1126. X
  1127. X            case ctrl('L'):        /* redraw screen */
  1128. X            case ctrl('R'):
  1129. X            case ctrl('W'):
  1130. #ifndef USE_CLEARSCREEN
  1131. X                ClearScreen ();
  1132. #endif
  1133. X                show_group_page (group);
  1134. X                break;
  1135. X
  1136. X            case ctrl('N'):
  1137. X            case 'j':        /* line down */
  1138. group_down:
  1139. X                if (! top_base || index_point + 1 >= top_base)
  1140. X                    break;
  1141. X
  1142. X                if (index_point + 1 >= last_subj_on_screen) {
  1143. #ifndef USE_CLEARSCREEN
  1144. X                    erase_subject_arrow();
  1145. #endif                    
  1146. X                    index_point++;
  1147. X                    show_group_page(group);
  1148. X                } else {
  1149. X                    erase_subject_arrow();
  1150. X                    index_point++;
  1151. X                    draw_subject_arrow();
  1152. X                }
  1153. X                break;
  1154. X
  1155. X            case ctrl('P'):
  1156. X            case 'k':        /* line up */
  1157. group_up:
  1158. X                if (!top_base || !index_point)
  1159. X                    break;
  1160. X
  1161. X                if (index_point <= first_subj_on_screen) {
  1162. X                    index_point--;
  1163. X                    show_group_page(group);
  1164. X                } else {
  1165. X                    erase_subject_arrow();
  1166. X                    index_point--;
  1167. X                    draw_subject_arrow();
  1168. X                }
  1169. X                break;
  1170. X
  1171. X            case ctrl('U'):        /* page up */
  1172. X            case 'b':
  1173. group_page_up:
  1174. X                if (! top_base)
  1175. X                    break;
  1176. X
  1177. #ifndef USE_CLEARSCREEN
  1178. X                clear_message ();
  1179. #endif
  1180. X                erase_subject_arrow ();
  1181. X                scroll_lines = (full_page_scroll ? NOTESLINES : NOTESLINES / 2);
  1182. X                if ((n = index_point % scroll_lines) > 0) {
  1183. X                    index_point = index_point - n;
  1184. X                } else {
  1185. X                    index_point = ((index_point - scroll_lines) / scroll_lines) * scroll_lines;
  1186. X                }
  1187. X                if (index_point < 0) {
  1188. X                    index_point = 0;
  1189. X                }
  1190. X                if (index_point < first_subj_on_screen
  1191. X                || index_point >= last_subj_on_screen)
  1192. X                    show_group_page (group);
  1193. X                else
  1194. X                    draw_subject_arrow ();
  1195. X                break;
  1196. X
  1197. X            case 'a':    /* author search forward */
  1198. X            case 'A':    /* author search backward */
  1199. X                if (index_point < 0) {
  1200. X                    info_message (txt_no_arts);
  1201. X                    break;
  1202. X                }
  1203. X
  1204. X                i = (ch == 'a');
  1205. X
  1206. X                n = search_author(top, (int) base[index_point], i);
  1207. X                if (n < 0)
  1208. X                    break;
  1209. X
  1210. X                index_point = show_page(n, group, group_path);
  1211. X                if (index_point < 0) {
  1212. X                    space_mode = FALSE;
  1213. X                    goto group_done;
  1214. X                }
  1215. X                clear_note_area ();
  1216. X                show_group_page (group);
  1217. X                break;
  1218. X
  1219. X            case 'B':    /* bug/gripe/comment mailed to author */
  1220. X                mail_bug_report ();
  1221. #ifndef USE_CLEARSCREEN
  1222. X                ClearScreen ();
  1223. #endif
  1224. X                show_group_page (group);
  1225. X                break;
  1226. X                
  1227. X            case 'c':    /* catchup--mark all articles as read */
  1228. X                if (prompt_yn (LINES, txt_mark_all_read, 'y')) {
  1229. X                    for (n = 0; n < top; n++) {
  1230. X                        arts[n].unread = ART_READ;
  1231. X                    }
  1232. X                    if (cur_groupnum + 1 < group_top) {
  1233. X                        cur_groupnum++;
  1234. X                    }
  1235. X                    goto group_done;
  1236. X                }
  1237. X                break;
  1238. X
  1239. X            case 'd':    /* toggle display of subject & subj/author */
  1240. X                if (show_author + 1 > SHOW_FROM_BOTH) {
  1241. X                    show_author = SHOW_FROM_NONE;
  1242. X                } else {
  1243. X                    show_author++;
  1244. X                }
  1245. X                if (show_author == SHOW_FROM_BOTH) {
  1246. X                    max_subj = (COLS / 2) - 2;
  1247. X                } else {
  1248. X                    max_subj = (COLS / 2) + 5;
  1249. X                }
  1250. X                max_from = (COLS - max_subj) - 17;
  1251. X                show_group_page (group);
  1252. X                break;
  1253. X
  1254. X            case 'g':    /* choose a new group by name */
  1255. X                n = choose_new_group ();
  1256. X                if (n >= 0 && n != cur_groupnum) {
  1257. X                    cur_groupnum = n;
  1258. X                    index_point = -3;
  1259. X                    goto group_done;
  1260. X                }
  1261. X                break;
  1262. X
  1263. X            case 'h':    /* help */
  1264. X                show_info_page (HELP_INFO, help_group, txt_index_page_com);
  1265. X                show_group_page (group);
  1266. X                break;
  1267. X
  1268. X            case 'I':    /* toggle inverse video */
  1269. X                toggle_inverse_video ();
  1270. X                show_group_page (group);
  1271. X                break;
  1272. X
  1273. X            case 'K':    /* mark rest of thread as read */
  1274. X                if (index_point < 0) {
  1275. X                    info_message (txt_no_next_unread_art);
  1276. X                    break;
  1277. X                }
  1278. X                if (new_responses (index_point)) {
  1279. X                    for (i = (int) base[index_point]; i >= 0; i = arts[i].thread) {
  1280. X                        arts[i].unread = ART_READ;
  1281. X                        if (arts[i].tagged) {
  1282. X                            sprintf (msg, "%3d", arts[i].tagged);
  1283. X                        } else {
  1284. X                            sprintf (msg, "%3s", (arts[i].unread ? "  +" : "   "));
  1285. X                        }
  1286. X                        mark_screen (SCREEN_READ_UNREAD, msg);    
  1287. X                    }
  1288. X                    flag = FALSE;
  1289. X                } else
  1290. X                    flag = TRUE;
  1291. X
  1292. X                n = next_unread (next_response ((int) base[index_point]));
  1293. X                if (n < 0) {
  1294. X                    if (flag)
  1295. X                        info_message (txt_no_next_unread_art);
  1296. X                    else
  1297. X                        MoveCursor (LINES, 0);
  1298. X                    break;
  1299. X                }
  1300. X
  1301. X                if ((n = which_thread (n)) < 0) {
  1302. X                    info_message("Internal error: K which_thread < 0");
  1303. X                    break;
  1304. X                }
  1305. X
  1306. X                if (n >= last_subj_on_screen) {
  1307. X                    index_point = n;
  1308. X                    show_group_page (group);
  1309. X                } else {
  1310. X                    erase_subject_arrow ();
  1311. X                    index_point = n;
  1312. X                    draw_subject_arrow ();
  1313. X                }
  1314. X                break;
  1315. X
  1316. X            case 'l':    /* list articles within current thread */
  1317. X                 space_mode = TRUE;
  1318. X                if (show_thread ((int) base[index_point], group, group_path)) {
  1319. X                    show_group_page (group);
  1320. X                }
  1321. X                break;    
  1322. X
  1323. X            case 'm':    /* mail article to somebody */
  1324. X                if (index_point >= 0) {
  1325. X                    set_real_uid_gid ();
  1326. X                    feed_articles (FEED_MAIL, GROUP_LEVEL, "Mail",
  1327. X                        (int) base[index_point], group_path);
  1328. X                    set_tin_uid_gid ();
  1329. X                }
  1330. X                break;
  1331. X
  1332. X            case 'M':    /* options menu */
  1333. X                if (top_base > 0) {
  1334. X                    old_top = top;
  1335. X                    n = (int) base[index_point];
  1336. X                    old_artnum = arts[n].artnum;
  1337. X                }
  1338. X                n = sort_art_type;
  1339. X                kill_state = change_rcfile (group, TRUE);
  1340. X                if (kill_state == NO_KILLING && n != sort_art_type) {
  1341. X                    make_threads (TRUE);
  1342. X                    find_base (show_only_unread);
  1343. X                }
  1344. X                index_point = find_new_pos (old_top, old_artnum, index_point);
  1345. X                show_group_page (group);
  1346. X                break;
  1347. X
  1348. X            case 'n':    /* next group */
  1349. X                clear_message();
  1350. X                if (cur_groupnum + 1 >= group_top)
  1351. X                    info_message(txt_no_more_groups);
  1352. X                else {
  1353. X                    cur_groupnum++;
  1354. X                    index_point = -3;
  1355. X                    space_mode = pos_first_unread;
  1356. X                    goto group_done;
  1357. X                }
  1358. X                break;
  1359. X
  1360. X            case 'N':    /* go to next unread article */
  1361. X                if (index_point < 0) {
  1362. X                    info_message(txt_no_next_unread_art);
  1363. X                    break;
  1364. X                }
  1365. X
  1366. X                n = next_unread ((int) base[index_point]);
  1367. X                if (n == -1)
  1368. X                    info_message (txt_no_next_unread_art);
  1369. X                else {
  1370. X                    index_point = show_page (n, group, group_path);
  1371. X                    if (index_point < 0) {
  1372. X                        space_mode = pos_first_unread;
  1373. X                        goto group_done;
  1374. X                    }
  1375. X                    clear_note_area ();
  1376. X                    show_group_page (group);
  1377. X                }
  1378. X                break;
  1379. X
  1380. X            case 'o':    /* output art/thread/tagged arts to printer */
  1381. X                if (index_point >= 0) {
  1382. X                    set_real_uid_gid ();
  1383. X                    feed_articles (FEED_PRINT, GROUP_LEVEL, "Print",
  1384. X                        (int) base[index_point], group_path);
  1385. X                    set_tin_uid_gid ();
  1386. X                }
  1387. X                break;
  1388. X
  1389. X            case 'p':    /* previous group */
  1390. X                clear_message();
  1391. X                if (cur_groupnum <= 0)
  1392. X                    info_message(txt_no_prev_group);
  1393. X                else {
  1394. X                    cur_groupnum--;
  1395. X                    index_point = -3;
  1396. X                    space_mode = pos_first_unread;
  1397. X                    goto group_done;
  1398. X                }
  1399. X                break;
  1400. X
  1401. X            case 'P':    /* go to previous unread article */
  1402. X                if (index_point < 0) {
  1403. X                    info_message(txt_no_prev_unread_art);
  1404. X                    break;
  1405. X                }
  1406. X                n = prev_response( (int) base[index_point]);
  1407. X                n = prev_unread(n);
  1408. X                if (n == -1)
  1409. X                    info_message(txt_no_prev_unread_art);
  1410. X                else {
  1411. X                    index_point = show_page (n, group, group_path);
  1412. X                    if (index_point < 0) {
  1413. X                        space_mode = pos_first_unread;
  1414. X                        goto group_done;
  1415. X                    }
  1416. X                    clear_note_area ();
  1417. X                    show_group_page (group);
  1418. X                }
  1419. X                break;
  1420. X
  1421. X            case 'q':        /* quit */
  1422. X                index_point = -2;
  1423. X                space_mode = FALSE;
  1424. X                goto group_done;
  1425. X
  1426. X            case 's':    /* save regex pattern to file/s */
  1427. X                if (index_point >= 0) {
  1428. X                    set_real_uid_gid ();
  1429. X                    feed_articles (FEED_SAVE, GROUP_LEVEL, "Save",
  1430. X                        (int) base[index_point], group_path);
  1431. X                    set_tin_uid_gid ();
  1432. X                }
  1433. X                break;
  1434. X            
  1435. X            case 't':
  1436. X            case 'i':    /* return to group selection page */
  1437. X                goto group_done;
  1438. X
  1439. X            case 'T':    /* tag/untag art for mailing/piping/printing/saving */
  1440. X                 if (index_point >= 0) {
  1441. X                    n = (int) base[index_point];
  1442. X                    if (arts[n].tagged) {
  1443. X                        arts[n].tagged = 0;
  1444. X                        sprintf (msg, "%3s", (arts[n].unread ? "  +" : "   "));
  1445. X                        info_message (txt_untagged_art);
  1446. X                    } else {
  1447. X                        arts[n].tagged = ++num_of_tagged_files;
  1448. X                        sprintf (msg, "%3d", arts[n].tagged);
  1449. X                        info_message (txt_tagged_art);
  1450. X                    }
  1451. X                    mark_screen (SCREEN_READ_UNREAD, msg);
  1452. X                    goto group_down;    /* advance an article */
  1453. X                }
  1454. X                break;
  1455. X
  1456. X            case 'u':    /* unthread/thread articles */
  1457. X                 if (index_point >= 0) {
  1458. X                    thread_arts = !thread_arts;
  1459. X                    make_threads (TRUE);
  1460. X                    find_base (show_only_unread);
  1461. X                    show_group_page (group);
  1462. X                }
  1463. X                break;
  1464. X
  1465. X            case 'U':    /* untag all articles */
  1466. X                 if (index_point >= 0) {
  1467. X                    untag_all_articles ();
  1468. X                    show_group_page (group);
  1469. X                }
  1470. X                break;
  1471. X
  1472. X            case 'v':
  1473. X                info_message (cvers);
  1474. X                break;
  1475. X
  1476. X            case 'w':    /* post a basenote */
  1477. X                if (! can_post) {
  1478. X                    info_message (txt_cannot_post);
  1479. X                    break;
  1480. X                }
  1481. X                if (post_base (group, &posted)) {
  1482. X                    if (posted) {
  1483. X                        update_newsrc (group, my_group[cur_groupnum], FALSE);
  1484. X                        index_group (group, group_path);
  1485. X                        read_newsrc_line (group);
  1486. X                        index_point = top_base - 1;
  1487. X                    }
  1488. X                    show_group_page (group);
  1489. X                }
  1490. X                break;
  1491. X
  1492. X            case 'W':    /* display messages posted by user */
  1493. X                if (user_posted_messages ()) {
  1494. X                    show_group_page(group);
  1495. X                }
  1496. X                break;
  1497. X
  1498. X            case 'z':    /* mark article as unread */
  1499. X                 if (index_point < 0) {
  1500. X                     info_message (txt_no_arts);
  1501. X                    break;
  1502. X                }
  1503. X                i = (int) base[index_point];
  1504. X                arts[i].unread = ART_UNREAD;
  1505. X                mark_screen (SCREEN_READ_UNREAD, "  +");    
  1506. X                info_message (txt_art_marked_as_unread);
  1507. X                break;
  1508. X
  1509. X            case 'Z':    /* mark thread as unread */
  1510. X                 if (index_point < 0) {
  1511. X                     info_message (txt_no_arts);
  1512. X                    break;
  1513. X                }
  1514. X                for (i = (int) base[index_point] ; i != -1 ; i = arts[i].thread) {
  1515. X                    arts[i].unread = ART_UNREAD;
  1516. X                    thread_marked_unread = TRUE;
  1517. X                }
  1518. X                if (thread_marked_unread) {
  1519. X                    mark_screen (SCREEN_READ_UNREAD, "  +");    
  1520. X                    info_message (txt_thread_marked_as_unread);
  1521. X                    thread_marked_unread = FALSE;
  1522. X                }
  1523. X                break;
  1524. X
  1525. X            default:
  1526. X                info_message (txt_bad_command);
  1527. X        }
  1528. X    }
  1529. X
  1530. group_done:
  1531. X    fix_new_highest (sav_groupnum);
  1532. X    update_newsrc (group, my_group[sav_groupnum], FALSE);
  1533. X
  1534. X    if (index_point == -2) {
  1535. X        tin_done (0);
  1536. X    }    
  1537. X    clear_note_area ();
  1538. }
  1539. X
  1540. X
  1541. /*
  1542. X *  Correct highest[] for the group selection page display since
  1543. X *  new articles may have been read or marked unread
  1544. X */
  1545. X
  1546. void fix_new_highest (groupnum)
  1547. X    int groupnum;
  1548. {
  1549. X    register int i;
  1550. X    int sum = 0;
  1551. X
  1552. X    for (i = 0; i < top; i++) {
  1553. X        if (arts[i].unread) {
  1554. X            sum++;
  1555. X        }
  1556. X    }
  1557. X    
  1558. X    unread[groupnum] = sum;
  1559. }
  1560. X
  1561. X
  1562. void show_group_page (group)
  1563. X    char *group;
  1564. {
  1565. X    char buf[LEN];
  1566. X    char new_resps[8];
  1567. X    char resps[8];
  1568. X    char from[LEN];
  1569. X    char subject[LEN];
  1570. X    int col, i, j, n;
  1571. X    int len_from;
  1572. X    int len_subj;
  1573. X    int respnum;
  1574. X    int unread_top = 0;
  1575. X
  1576. X    set_signals_group ();
  1577. X    
  1578. #ifdef USE_CLEARSCREEN
  1579. X    ClearScreen ();
  1580. #else
  1581. X    MoveCursor (0, 0);
  1582. X    CleartoEOLN ();
  1583. #endif
  1584. X
  1585. X    if (show_only_unread) {
  1586. X        for (i = 0 ; i < top_base ; i++) {
  1587. X            unread_top += 1 + num_of_responses (i);
  1588. X        }    
  1589. X    } else {
  1590. X        unread_top = top;
  1591. X    }
  1592. X
  1593. X    if (active[my_group[cur_groupnum]].thread && thread_arts) {
  1594. X        sprintf (buf, "%s (%d %d)", group, top_base, unread_top);
  1595. X    } else {
  1596. X        sprintf (buf, "%s (U %d)", group, unread_top);
  1597. X    }
  1598. X    show_title (buf);
  1599. X
  1600. #ifndef USE_CLEARSCREEN
  1601. X    MoveCursor (1, 0);
  1602. X    CleartoEOLN ();
  1603. #endif
  1604. X
  1605. X    MoveCursor (INDEX_TOP, 0);
  1606. X
  1607. X    if (index_point >= top_base) {
  1608. X        index_point = top_base - 1;
  1609. X    }
  1610. X
  1611. X    if (NOTESLINES <= 0) {
  1612. X        first_subj_on_screen = 0;
  1613. X    } else {
  1614. X        first_subj_on_screen = (index_point / NOTESLINES) * NOTESLINES;
  1615. X        if (first_subj_on_screen < 0) {
  1616. X            first_subj_on_screen = 0;
  1617. X        }
  1618. X    }
  1619. X
  1620. X    last_subj_on_screen = first_subj_on_screen + NOTESLINES;
  1621. X
  1622. X    if (last_subj_on_screen >= top_base) {
  1623. X        last_subj_on_screen = top_base;
  1624. X        first_subj_on_screen = (top_base / NOTESLINES) * NOTESLINES;
  1625. X
  1626. X        if (first_subj_on_screen == last_subj_on_screen ||
  1627. X            first_subj_on_screen < 0) {
  1628. X            if (first_subj_on_screen < 0) {
  1629. X                first_subj_on_screen = 0;
  1630. X            } else {
  1631. X                first_subj_on_screen = last_subj_on_screen - NOTESLINES;
  1632. X            }
  1633. X        }
  1634. X    }
  1635. X
  1636. X    if (top_base == 0) {
  1637. X        first_subj_on_screen = 0;
  1638. X        last_subj_on_screen = 0;
  1639. X    }
  1640. X
  1641. X    if (show_author != SHOW_FROM_NONE) {
  1642. X       len_from = max_from-BLANK_GROUP_COLS;
  1643. X    } else {
  1644. X        len_subj = (max_subj+max_from+3)-BLANK_GROUP_COLS;
  1645. X    }
  1646. X
  1647. X    if (draw_arrow_mark) {
  1648. X        CleartoEOS ();
  1649. X    }
  1650. X
  1651. X    for (j=0, i = first_subj_on_screen; i < last_subj_on_screen; i++, j++) {
  1652. X        respnum = (int) base[i];
  1653. X
  1654. X        if (arts[respnum].tagged) {
  1655. X            sprintf (new_resps, "%3d", arts[respnum].tagged);
  1656. X        } else if (new_responses(i)) {
  1657. X            sprintf (new_resps, "  %c", UNREAD_ART_MARK);
  1658. X        } else {
  1659. X            strcpy (new_resps, "   ");
  1660. X        }
  1661. X
  1662. X        n = num_of_responses (i);
  1663. X        if (n) {
  1664. X            sprintf (resps, "%-3d", n); 
  1665. X        } else {
  1666. X            strcpy (resps, "   ");
  1667. X        }
  1668. X
  1669. X        get_author (FALSE, respnum, from);
  1670. X
  1671. X        if (draw_arrow_mark) {
  1672. X            if (show_author != SHOW_FROM_NONE) {
  1673. X                my_strncpy (subject, arts[respnum].subject, max_subj);
  1674. X                printf ("  %4d%3s %s%-*s   %-s\r\n",
  1675. X                       i+1, new_resps, resps, max_subj, subject, from);
  1676. X            } else {
  1677. X                my_strncpy (subject, arts[respnum].subject, max_subj+max_from+3);
  1678. X                printf ("  %4d%3s %s%-s\r\n",
  1679. X                       i+1, new_resps, resps, subject);
  1680. X            }
  1681. X        } else {
  1682. X            if (show_author != SHOW_FROM_NONE) {
  1683. X                my_strncpy (subject, arts[respnum].subject, max_subj);
  1684. X                sprintf (screen[j].col, "  %4d%3s %s%-*s   %-*s\r\n",
  1685. X                       i+1, new_resps, resps, max_subj, subject, len_from, from);
  1686. X            } else {
  1687. X                my_strncpy (subject, arts[respnum].subject, max_subj+max_from+3);
  1688. X                sprintf (screen[j].col, "  %4d%3s %s%-*s\r\n",
  1689. X                       i+1, new_resps, resps, len_subj, subject);
  1690. X            }
  1691. X            printf ("%s", screen[j].col);
  1692. X        }
  1693. X    }
  1694. X
  1695. #ifndef USE_CLEARSCREEN
  1696. X    CleartoEOS ();
  1697. #endif
  1698. X
  1699. X    if (top_base <= 0) {
  1700. X        info_message(txt_no_arts);
  1701. X        return;
  1702. X    } else if (last_subj_on_screen == top_base) {
  1703. X        info_message(txt_end_of_arts);
  1704. X    }
  1705. X
  1706. X    draw_subject_arrow();
  1707. }
  1708. X
  1709. void draw_subject_arrow()
  1710. {
  1711. X    draw_arrow (INDEX_TOP + (index_point-first_subj_on_screen));
  1712. }
  1713. X
  1714. void erase_subject_arrow()
  1715. {
  1716. X    erase_arrow (INDEX_TOP + (index_point-first_subj_on_screen));
  1717. }
  1718. X
  1719. X
  1720. int prompt_subject_num (ch, group)
  1721. X    char ch;
  1722. X    char *group;
  1723. {
  1724. X    int num;
  1725. X
  1726. X    clear_message ();
  1727. X
  1728. X    if ((num = prompt_num (ch, txt_read_art)) == -1) {
  1729. X        clear_message ();
  1730. X        return FALSE;
  1731. X    }
  1732. X    num--;        /* index from 0 (internal) vs. 1 (user) */
  1733. X
  1734. X    if (num < 0) {
  1735. X        num = 0;
  1736. X    }
  1737. X    if (num >= top_base) {
  1738. X        num = top_base - 1;
  1739. X    }
  1740. X
  1741. X    if (num >= first_subj_on_screen
  1742. X    &&  num < last_subj_on_screen) {
  1743. X        erase_subject_arrow();
  1744. X        index_point = num;
  1745. X        draw_subject_arrow();
  1746. X    } else {
  1747. #ifndef USE_CLEARSCREEN
  1748. X        erase_subject_arrow();
  1749. #endif        
  1750. X        index_point = num;
  1751. X        show_group_page(group);
  1752. X    }
  1753. X    return TRUE;
  1754. }
  1755. X
  1756. X
  1757. void clear_note_area ()
  1758. {
  1759. #ifndef USE_CLEARSCREEN
  1760. X    MoveCursor (INDEX_TOP, 0);
  1761. X    CleartoEOS ();
  1762. #endif
  1763. }
  1764. X
  1765. X
  1766. int find_new_pos (old_top, old_artnum, cur_pos)
  1767. X    int old_top;
  1768. X    long old_artnum;
  1769. X    int cur_pos;
  1770. {
  1771. X    int pos;
  1772. X    
  1773. X    if (top != old_top) {
  1774. X        if ((pos = valid_artnum (old_artnum)) >= 0) {
  1775. X            if ((pos = which_thread (pos)) >= 0) {
  1776. X                return pos;
  1777. X            } else {
  1778. X                return top_base - 1;
  1779. X            }
  1780. X        } else {
  1781. X            return top_base - 1;
  1782. X        }
  1783. X    }
  1784. X
  1785. X    return cur_pos;
  1786. }
  1787. X
  1788. X
  1789. void mark_screen (col, value)
  1790. X    int col;
  1791. X    char *value;
  1792. {
  1793. X    int i, len;
  1794. X
  1795. X    len = strlen (value);
  1796. X    
  1797. X    if (draw_arrow_mark) {
  1798. X        MoveCursor(INDEX_TOP + (index_point - first_subj_on_screen), col);
  1799. X        printf ("%s", value);
  1800. X        MoveCursor (LINES, 0);
  1801. X        fflush(stdout);
  1802. X    } else {
  1803. X        for (i=0 ; i < len ; i++) {
  1804. X            screen[index_point-first_subj_on_screen].col[col+i] = value[i];
  1805. X        }
  1806. X        draw_subject_arrow();
  1807. X    }
  1808. }
  1809. SHAR_EOF
  1810. chmod 0600 group.c ||
  1811. echo 'restore of group.c failed'
  1812. Wc_c="`wc -c < 'group.c'`"
  1813. test 20637 -eq "$Wc_c" ||
  1814.     echo 'group.c: original size 20637, current size' "$Wc_c"
  1815. rm -f _shar_wnt_.tmp
  1816. fi
  1817. # ============= hashstr.c ==============
  1818. if test -f 'hashstr.c' -a X"$1" != X"-c"; then
  1819.     echo 'x - skipping hashstr.c (File already exists)'
  1820.     rm -f _shar_wnt_.tmp
  1821. else
  1822. > _shar_wnt_.tmp
  1823. echo 'x - extracting hashstr.c (Text)'
  1824. sed 's/^X//' << 'SHAR_EOF' > 'hashstr.c' &&
  1825. /*
  1826. X *  Project   : tin - a threaded Netnews reader
  1827. X *  Module    : hashstr.c
  1828. X *  Author    : R.Skrenta
  1829. X *  Created   : 01-04-91
  1830. X *  Updated   : 21-01-92
  1831. X *  Notes     :
  1832. X *  Copyright : (c) Copyright 1991-92 by Rich Skrenta
  1833. X *                You may  freely  copy or  redistribute  this software,
  1834. X *              so  long as there is no profit made from its use, sale
  1835. X *              trade or  reproduction.  You may not change this copy-
  1836. X *              right notice, and it must be included in any copy made
  1837. X */
  1838. X
  1839. #include    "tin.h"
  1840. X
  1841. /*
  1842. X *  Maintain a table of all strings we have seen.
  1843. X *  If a new string comes in, add it to the table and return a pointer
  1844. X *  to it.  If we've seen it before, just return the pointer to it.
  1845. X *
  1846. X *  Usage:  hash_str("some string") returns char *
  1847. X *
  1848. X *  Spillovers are chained on the end
  1849. X */
  1850. X
  1851. /*
  1852. X *  Arbitrary table size, but make sure it's prime!
  1853. X */
  1854. X
  1855. #define        HASHNODE_TABLE_SIZE    2411
  1856. X
  1857. struct hashnode *table[HASHNODE_TABLE_SIZE];
  1858. X
  1859. X
  1860. char *hash_str (s)
  1861. X    char *s;
  1862. {
  1863. X    long h;                /* result of hash:  index into hash table */
  1864. X    struct hashnode *p;    /* used to descend the spillover structs */
  1865. X
  1866. X    if (s == (char *) 0) {
  1867. X        return ((char *) 0);
  1868. X    }
  1869. X
  1870. X    {
  1871. X        unsigned char *t = (unsigned char *) s;
  1872. X
  1873. X        h = *t++;
  1874. X        while (*t)
  1875. X            h = ((h << 1) ^ *t++) % (long) HASHNODE_TABLE_SIZE;
  1876. X    }
  1877. X
  1878. X    p = table[h];
  1879. X
  1880. X    if (p == (struct hashnode *) 0) {
  1881. X        table[h] = add_string (s);
  1882. X        return table[h]->s;
  1883. X    }
  1884. X
  1885. X    while (1) {
  1886. X        if (strcmp (s, p->s) == 0) {
  1887. X            return (p->s);
  1888. X        }
  1889. X
  1890. X        if (p->next == (struct hashnode *) 0) {
  1891. X            p->next = add_string (s);
  1892. X            return p->next->s;
  1893. X        } else {
  1894. X            p = p->next;
  1895. X        }
  1896. X    }
  1897. X    /* NOTREACHED */
  1898. }
  1899. X
  1900. X
  1901. struct hashnode *add_string (s)
  1902. X    char *s;
  1903. {
  1904. X    int *iptr;
  1905. X    struct hashnode *p;
  1906. X
  1907. X    p = (struct hashnode *) my_malloc ((unsigned) sizeof (*p));
  1908. X
  1909. X    p->next = (struct hashnode *) 0;
  1910. X    iptr = (int *) my_malloc ((unsigned) strlen (s) + sizeof (int) + 1);
  1911. X    *iptr++ = -1;
  1912. X    p->s = (char *) iptr;
  1913. X    strcpy (p->s, s);
  1914. X    return (p);
  1915. }
  1916. X
  1917. X
  1918. void hash_init ()
  1919. {
  1920. X    int i;
  1921. X
  1922. X    for (i = 0; i < HASHNODE_TABLE_SIZE; i++) {
  1923. X        table[i] = (struct hashnode *) 0;
  1924. X    }
  1925. }
  1926. X
  1927. X
  1928. void hash_reclaim ()
  1929. {
  1930. X    int i;
  1931. X    int *iptr;
  1932. X    struct hashnode *p, *next;
  1933. X
  1934. X    for (i = 0; i < HASHNODE_TABLE_SIZE; i++)
  1935. X        if (table[i] != (struct hashnode *) 0) {
  1936. X            p = table[i];
  1937. X            while (p != (struct hashnode *) 0) {
  1938. X                next = p->next;
  1939. X                if (p->s != (char *) 0) {
  1940. X                    iptr = (int *) p->s;
  1941. X                    free ((char *) --iptr);
  1942. X                }
  1943. X                free ((char *) p);
  1944. X                p = next;
  1945. X            }
  1946. X            table[i] = (struct hashnode *) 0;
  1947. X        }
  1948. }
  1949. SHAR_EOF
  1950. chmod 0600 hashstr.c ||
  1951. echo 'restore of hashstr.c failed'
  1952. Wc_c="`wc -c < 'hashstr.c'`"
  1953. test 2466 -eq "$Wc_c" ||
  1954.     echo 'hashstr.c: original size 2466, current size' "$Wc_c"
  1955. rm -f _shar_wnt_.tmp
  1956. fi
  1957. # ============= help.c ==============
  1958. if test -f 'help.c' -a X"$1" != X"-c"; then
  1959.     echo 'x - skipping help.c (File already exists)'
  1960.     rm -f _shar_wnt_.tmp
  1961. else
  1962. > _shar_wnt_.tmp
  1963. echo 'x - extracting help.c (Text)'
  1964. sed 's/^X//' << 'SHAR_EOF' > 'help.c' &&
  1965. /*
  1966. X *  Project   : tin - a threaded Netnews reader
  1967. X *  Module    : help.c
  1968. X *  Author    : I.Lea
  1969. X *  Created   : 01-04-91
  1970. X *  Updated   : 05-02-92
  1971. X *  Notes     :
  1972. X *  Copyright : (c) Copyright 1991-92 by Iain Lea
  1973. X *              You may  freely  copy or  redistribute  this software,
  1974. X *              so  long as there is no profit made from its use, sale
  1975. X *              trade or  reproduction.  You may not change this copy-
  1976. X *              right notice, and it must be included in any copy made
  1977. X */
  1978. X
  1979. #include    "tin.h"
  1980. #include    "nntp.h"
  1981. X
  1982. char *help_select[] = {
  1983. X    txt_help_g_4,
  1984. X    txt_help_ctrl_d,
  1985. X    txt_help_ctrl_l,
  1986. X    txt_help_g_ctrl_k,
  1987. X    txt_help_g_ctrl_r,
  1988. X    txt_help_g_cr,
  1989. X    txt_help_g_tab,
  1990. X    txt_help_b,
  1991. X    txt_help_bug_report,
  1992. X    txt_help_sel_c,
  1993. X    txt_help_g,
  1994. X    txt_help_j,
  1995. X    txt_help_h,
  1996. X    txt_help_I,
  1997. X    txt_help_m,
  1998. X    txt_help_M,
  1999. X    txt_help_n,
  2000. X    txt_help_q,
  2001. X    txt_help_s,
  2002. X    txt_help_S,
  2003. X    txt_help_v,
  2004. X    txt_help_w,
  2005. X    txt_help_W,
  2006. X    txt_help_g_y,
  2007. X    txt_help_g_dollar,
  2008. X    txt_help_g_z,
  2009. X    txt_help_g_search,
  2010. #ifndef NO_SHELL_ESCAPE
  2011. X    txt_help_shell,
  2012. #endif
  2013. X    (char *) 0
  2014. };
  2015. X
  2016. char *help_group[] = {
  2017. X    txt_help_i_4,
  2018. X    txt_help_ctrl_d,
  2019. X    txt_help_ctrl_k,
  2020. X    txt_help_ctrl_l,
  2021. X    txt_help_i_cr,
  2022. X    txt_help_i_tab,
  2023. X    txt_help_a,
  2024. X    txt_help_b,
  2025. X    txt_help_bug_report,
  2026. X    txt_help_c,
  2027. X    txt_help_d,
  2028. X    txt_help_g,
  2029. X    txt_help_h,
  2030. X    txt_help_I,
  2031. X    txt_help_j,
  2032. X    txt_help_K,
  2033. X    txt_help_l,
  2034. X    txt_help_p_m,
  2035. X    txt_help_M,
  2036. X    txt_help_o,
  2037. X    txt_help_i_n,
  2038. X    txt_help_i_p,
  2039. X    txt_help_q,
  2040. X    txt_help_p_s,
  2041. X    txt_help_t,
  2042. X    txt_help_T,
  2043. X
  2044. X    txt_help_U,
  2045. X    txt_help_v,
  2046. X    txt_help_w,
  2047. X    txt_help_W,
  2048. X    txt_help_p_z,
  2049. X    txt_help_i_search,
  2050. #ifndef NO_SHELL_ESCAPE
  2051. X    txt_help_shell,
  2052. #endif
  2053. X    txt_help_dash,
  2054. X    txt_help_pipe,
  2055. X    (char *) 0
  2056. };
  2057. X
  2058. char *help_thread[] = {
  2059. X    txt_help_t_0,
  2060. X    txt_help_t_4,
  2061. X    txt_help_ctrl_d,
  2062. X    txt_help_ctrl_l,
  2063. X    txt_help_t_cr,
  2064. X    txt_help_p_tab,
  2065. X    txt_help_b,
  2066. X    txt_help_h,
  2067. X    txt_help_I,
  2068. X    txt_help_j,
  2069. X    txt_help_p_k,
  2070. X    txt_help_q,
  2071. X    txt_help_v,
  2072. X    txt_help_p_z,
  2073. X    (char *) 0
  2074. };
  2075. X
  2076. char *help_page[] = {
  2077. X    txt_help_p_0,
  2078. X    txt_help_p_4,
  2079. X    txt_help_ctrl_h,
  2080. X    txt_help_ctrl_k,
  2081. X    txt_help_ctrl_l,
  2082. X    txt_help_p_ctrl_r,
  2083. X    txt_help_p_cr,
  2084. X    txt_help_p_tab,
  2085. X    txt_help_b,
  2086. X    txt_help_a,
  2087. X    txt_help_bug_report,
  2088. X    txt_help_c,
  2089. X    txt_help_C,
  2090. X    txt_help_p_d,
  2091. X    txt_help_p_f,
  2092. X    txt_help_p_g,
  2093. X    txt_help_h,
  2094. X    txt_help_p_i,
  2095. X    txt_help_I,
  2096. X    txt_help_p_k,
  2097. X    txt_help_p_m,
  2098. X    txt_help_M,
  2099. X    txt_help_p_n,
  2100. X    txt_help_o,
  2101. X    txt_help_p_p,
  2102. X    txt_help_q,
  2103. X    txt_help_p_r,
  2104. X    txt_help_p_s,
  2105. X    txt_help_t,
  2106. X    txt_help_T,
  2107. X    txt_help_v,
  2108. X    txt_help_w,
  2109. X    txt_help_W,
  2110. X    txt_help_p_z,
  2111. X    txt_help_p_search,
  2112. #ifndef NO_SHELL_ESCAPE
  2113. X    txt_help_shell,
  2114. #endif
  2115. X    txt_help_dash,
  2116. X    txt_help_pipe,
  2117. X    txt_help_thread,
  2118. X    (char *) 0
  2119. };
  2120. X
  2121. X
  2122. void show_info_page (type, help, title)
  2123. X    int type; 
  2124. X    char *help[];
  2125. X    char *title;
  2126. {
  2127. X    char buf[LEN];
  2128. X    char ch;
  2129. X    int i, len;
  2130. X    int group_len = 0;
  2131. X    int old_page = 0;
  2132. X    int cur_page = 1;
  2133. X    int max_page = 1;
  2134. X    int pos_help = 0;
  2135. X
  2136. X    if (NOTESLINES <= 0) {
  2137. X        return;
  2138. X    }
  2139. X
  2140. X    /*
  2141. X     *  find how many elements in array
  2142. X     */
  2143. X    if (type == HELP_INFO) {
  2144. X        for (i=0 ; help[i] ; i++) {
  2145. X            continue;
  2146. X        }
  2147. X    } else {
  2148. X        for (i=0 ; posted[i].date[0] ; i++) {
  2149. X            len = strlen (posted[i].group);
  2150. X            if (len > group_len) {
  2151. X                 group_len = len;
  2152. X            }
  2153. X         }
  2154. X    }
  2155. X    
  2156. X    max_page = i / NOTESLINES;
  2157. X    if (i % NOTESLINES) {
  2158. X        max_page++;
  2159. X    }
  2160. X
  2161. X    while (1) {
  2162. X        if (cur_page != old_page) {
  2163. X            ClearScreen ();
  2164. X            sprintf (buf, title, cur_page, max_page);
  2165. X            center_line (0, TRUE, buf);
  2166. X            MoveCursor (INDEX_TOP, 0);
  2167. X
  2168. X            if (type == HELP_INFO) { 
  2169. X                for (i=pos_help ; i < (pos_help + NOTESLINES) && help[i] ; i++) {
  2170. X                    printf ("%s", help[i]);
  2171. X                }
  2172. X            } else {
  2173. X                for (i=pos_help ; i < (pos_help + NOTESLINES) && posted[i].date[0] ; i++) {
  2174. X                    sprintf (msg, "%8s  %-*s  %s", posted[i].date,
  2175. X                        group_len, posted[i].group, posted[i].subj);
  2176. X                        msg[COLS-2] = '\0';
  2177. X                    printf ("%s\r\n", msg);
  2178. SHAR_EOF
  2179. true || echo 'restore of help.c failed'
  2180. fi
  2181. echo 'End of tin1.1 part 4'
  2182. echo 'File help.c is continued in part 5'
  2183. echo 5 > _shar_seq_.tmp
  2184. exit 0
  2185.  
  2186. --
  2187. NAME   Iain Lea
  2188. EMAIL  iain%estevax.uucp@unido.Informatik.Uni-Dortmund.DE
  2189. SNAIL  Bruecken Strasse 12, 8500 Nuernberg 90, Germany
  2190. PHONE  +49-911-331963 (home)  +49-911-3089-407 (work)
  2191. -- 
  2192.  Dr. med. dipl.-math Dieter Becker           Tel.: (0 / +49) 6841 - 16 3046
  2193.  Medizinische Universitaets- und Poliklinik  Fax.: (0 / +49) 6841 - 16 3369
  2194.  Innere Medizin III                         
  2195.  D - 6650 Homburg / Saar                     Email: becker@med-in.uni-sb.de
  2196. exit 0 # Just in case...
  2197.