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

  1. Newsgroups: comp.sources.misc
  2. From: iain%estevax.uucp@unido.Informatik.Uni-Dortmund.DE (Iain Lea)
  3. Subject:  v28i053:  tin - threaded full screen newsreader v1.1, Part09/11
  4. Message-ID: <1992Feb18.043906.13394@sparky.imd.sterling.com>
  5. X-Md4-Signature: 4412c003d8f1c31d4771ca237c327ac6
  6. Date: Tue, 18 Feb 1992 04:39:06 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 53
  11. Archive-name: tin/part09
  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.09 (part 9 of tin1.1)
  17. # do not concatenate these parts, unpack them in order with /bin/sh
  18. # file save.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" != 9; 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 save.c'
  34. else
  35. echo 'x - continuing file save.c'
  36. sed 's/^X//' << 'SHAR_EOF' >> 'save.c' &&
  37. X     */
  38. X    if (path[0] == '=') {
  39. X        return TRUE;
  40. X    }
  41. X
  42. X    /*
  43. X     * if ~/file expand (ie. /usr/homedir/file)
  44. X     */
  45. X    switch (path[0]) {
  46. X        case '~':
  47. X            my_strncpy (buf, path+1, LEN);
  48. X            sprintf (path, "%s%s", homedir, buf);
  49. X            break;
  50. X        case '+':
  51. X            my_strncpy (buf, path+1, LEN);
  52. #ifdef USE_LONG_FILENAMES 
  53. X            strcpy (group, glob_group);
  54. #else
  55. X            my_strncpy (group, glob_group, 14);
  56. #endif
  57. X            /*
  58. X             *  convert 1st letter to uppercase
  59. X             */
  60. X            if (group[0] >= 'a' && group[0] <= 'z') {
  61. X                group[0] = group[0] - 32;
  62. X            }
  63. X            sprintf (path, "%s/%s/%s", savedir, group, buf);
  64. X            break;
  65. X        case '$':
  66. X            for (i = 0 ; isalnum (path[i+1]) ; i++) {
  67. X                buf[i] = path[i+1];
  68. X            }
  69. X            buf[i] = '\0';
  70. X            if (buf[0] == '\0' || (env = getenv (buf)) == NULL ||
  71. X                (len = strlen (env)) == 0) {
  72. X            }
  73. X            sprintf (buf, "%s%s%s", env, (path[i+1] != '/' &&
  74. X                    env[len-1] != '/') ? "/" : "", &path[i+1]);
  75. X            strcpy (path, buf);
  76. X            break;
  77. X        case '/':
  78. X            break;
  79. X        case '.':
  80. X            error_message ("Cannot create %s", buf);
  81. X            return FALSE;
  82. X            /* NOTREACHED */
  83. X        default:
  84. X            sprintf (buf, "%s/%s", savedir, path);
  85. X            my_strncpy (path, buf, LEN);
  86. X            break;
  87. X    }
  88. X
  89. X    /*
  90. X     *  create any directories, otherwise check
  91. X     *  errno and give appropiate error message
  92. X     */
  93. X    len = (int) strlen (path);
  94. X    
  95. X    for (i=0, j=0 ; i < len ; i++, j++) {
  96. X        buf[j] = path[i];
  97. X        if (i+1 < len && path[i+1] == '/') {
  98. X            buf[j+1] = '\0';
  99. X            if (stat (buf, &st) == -1) {
  100. X                if (mkdir (buf, 0755) == -1) {
  101. X                    error_message ("Cannot create %s", buf);
  102. X                    return FALSE;
  103. X                }
  104. X            }
  105. X        }
  106. X    }
  107. X    return FALSE;
  108. }
  109. X
  110. X
  111. int create_sub_dir (i)
  112. X    int i;
  113. {
  114. X    char dir[LEN];
  115. X    struct stat st;
  116. X
  117. X    if (! save[i].is_mailbox && save[i].archive) {
  118. X        sprintf (dir, "%s/%s", save[i].dir, save[i].archive);
  119. X        if (stat (dir, &st) == -1) {
  120. X            mkdir (dir, 0755);
  121. X            return TRUE;
  122. X        }
  123. X        if ((st.st_mode & S_IFMT) == S_IFDIR) {
  124. X            return TRUE;
  125. X        } else {
  126. X            return FALSE;
  127. X        }
  128. X    }
  129. X    return FALSE;
  130. }
  131. X
  132. /*
  133. X *  add files to be saved to save array
  134. X */
  135. X
  136. void add_to_save_list (index, article, is_mailbox, path)
  137. X    int index;
  138. X    struct article_t *article;
  139. X    int is_mailbox;
  140. X    char *path;
  141. {
  142. X    char dir[LEN];
  143. X    char file[LEN];
  144. X    int i;
  145. X    
  146. X    dir[0] = '\0';
  147. X    file[0] = '\0';
  148. X
  149. X    if (save_num == max_save-1) {
  150. X        expand_save ();
  151. X    }
  152. X
  153. X    save[save_num].index   = index;
  154. X    save[save_num].saved   = FALSE;
  155. X    save[save_num].is_mailbox = is_mailbox;
  156. X    save[save_num].dir     = (char *) 0;
  157. X    save[save_num].file    = (char *) 0;
  158. X    save[save_num].archive = (char *) 0;
  159. X    save[save_num].part    = (char *) 0;
  160. X    save[save_num].patch   = (char *) 0;
  161. X
  162. X    save[save_num].subject = str_dup (article->subject);
  163. X    if (article->archive) {
  164. X        save[save_num].archive = str_dup (article->archive);
  165. X    }
  166. X    if (article->part) {
  167. X        save[save_num].part = str_dup (article->part);
  168. X    }
  169. X    if (article->patch) {
  170. X        save[save_num].patch = str_dup (article->patch);
  171. X    }
  172. X
  173. X    if (is_mailbox) {
  174. X        if ((int) strlen (path) > 1) {
  175. X            if (path[0] == '=') {
  176. X                strcpy (file, path+1);
  177. X            } else {
  178. X                strcpy (file, path);
  179. X            }
  180. X        } else {
  181. X            strcpy (file, glob_group);
  182. X        }
  183. X        save[save_num].dir = str_dup (maildir);
  184. X        save[save_num].file = str_dup (file);
  185. X    } else {
  186. X        if (path[0]) {
  187. X            for (i=strlen (path) ; i ; i--) {
  188. X                if (path[i] == '/') {
  189. X                    strncpy (dir, path, i);
  190. X                    dir[i] = '\0';
  191. X                    strcpy (file, path+i+1);
  192. X                    break;
  193. X                }
  194. X            }
  195. X        }
  196. X        
  197. X        if (dir[0]) {
  198. X            save[save_num].dir = str_dup (dir);
  199. X        } else {
  200. X            save[save_num].dir = str_dup (savedir);
  201. X        }
  202. X
  203. X        if (file[0]) {
  204. X            save[save_num].file = str_dup (file);
  205. X        } else {
  206. X            if (path[0]) {
  207. X                save[save_num].file = str_dup (path);
  208. X            } else {
  209. X                save[save_num].file = str_dup (save[save_num].archive);
  210. X            }
  211. X        }
  212. X    }
  213. X    save_num++;
  214. }
  215. X
  216. /*
  217. X *  print save array of files to be saved
  218. X */
  219. X
  220. void sort_save_list ()
  221. {
  222. X    qsort ((char *) save, save_num, sizeof (struct save_t), save_comp);
  223. }
  224. X
  225. /*
  226. X *  string comparison routine for the qsort()
  227. X *  ie. qsort(array, 5, 32, save_comp);
  228. X */
  229. X
  230. int save_comp (p1, p2)
  231. X    char *p1;
  232. X    char *p2;
  233. {
  234. X    struct save_t *s1 = (struct save_t *)p1;
  235. X    struct save_t *s2 = (struct save_t *)p2;
  236. X
  237. X    /* s1->subject less than s2->subject */
  238. X    if (strcmp (s1->subject, s2->subject) < 0) {
  239. X        return -1;
  240. X    }
  241. X    /* s1->subject greater than s2->subject */
  242. X    if (strcmp (s1->subject, s2->subject) > 0) {
  243. X        return 1;
  244. X    }
  245. X    return 0;
  246. }
  247. X
  248. X
  249. char *save_filename (i)
  250. X    int i;
  251. {
  252. X    char *filename;
  253. X
  254. X    filename = (char *) my_malloc (LEN);
  255. X
  256. X    if (save[i].is_mailbox) {
  257. X        sprintf (filename, "%s/%s", save[i].dir, save[i].file);
  258. X        return (filename);
  259. X    }
  260. X    
  261. X    if (! save_separate || ! save_archive_name || (! save[i].part && ! save[i].patch)) {
  262. X        if (! save_separate || save_num == 1) {
  263. X            sprintf (filename, "%s/%s", save[i].dir, save[i].file);
  264. X        } else {
  265. X            sprintf (filename, "%s/%s.%02d", save[i].dir, save[i].file, i+1);
  266. X        }
  267. X    } else {
  268. X        if (save[i].part) {
  269. X            if (create_sub_dir (i)) {
  270. X                sprintf (filename, "%s/%s/%s.%s%s", save[i].dir, save[i].archive, save[i].archive, LONG_PATH_PART, save[i].part);
  271. X            } else {
  272. X                sprintf (filename, "%s/%s.%s%s", save[i].dir, save[i].archive, LONG_PATH_PART, save[i].part);
  273. X            }
  274. X        } else {
  275. X            if (save[i].patch) {
  276. X                if (create_sub_dir (i)) {
  277. X                    sprintf (filename, "%s/%s/%s.%s%s", save[i].dir, save[i].archive, save[i].archive, LONG_PATH_PATCH, save[i].patch);
  278. X                } else {
  279. X                    sprintf (filename, "%s/%s.%s%s", save[i].dir, save[i].archive, LONG_PATH_PATCH, save[i].patch);
  280. X                }
  281. X            } else {
  282. X                  sprintf (filename, "%s/%s", save[i].dir, save[i].file);
  283. X            }
  284. X        }
  285. X    }
  286. X
  287. X    return (filename);
  288. }
  289. X
  290. X
  291. char *get_first_savefile ()
  292. {
  293. X    char *file;
  294. X    int i;
  295. X
  296. X    for (i=0 ; i < save_num ; i++) {
  297. X        if (save[i].saved) {
  298. X            file = (char *) my_malloc (LEN);
  299. X            if (save[i].is_mailbox) {
  300. X                sprintf (file, "%s/%s", save[i].dir, save[i].file);
  301. X                return (file);
  302. X            } else {
  303. X                if (save[i].archive && save_archive_name) {
  304. X                    if (save[i].part) {
  305. X                        if (create_subdir) {
  306. X                            sprintf (file, "%s/%s.%s%s", save[i].archive, save[i].archive, LONG_PATH_PART, save[i].part);
  307. X                        } else {
  308. X                            sprintf (file, "%s.%s%s", save[i].archive, LONG_PATH_PART, save[i].part);
  309. X                        }
  310. X                    } else {
  311. X                        if (create_subdir) {
  312. X                            sprintf (file, "%s/%s.%s%s", save[i].archive, save[i].archive, LONG_PATH_PATCH, save[i].patch);
  313. X                        } else {
  314. X                            sprintf (file, "%s.%s%s", save[i].archive, LONG_PATH_PATCH, save[i].patch);
  315. X                        }
  316. X                    }
  317. X                } else {
  318. X                    if (! save_separate || save_num == 1) {
  319. X                        sprintf (file, "%s", save[i].file);
  320. X                    } else {
  321. X                        sprintf (file, "%s.%02d", save[i].file, i+1);
  322. X                    }
  323. X                }
  324. X                return (file);
  325. X            }
  326. X        }
  327. X    }
  328. X    return ((char *) 0);
  329. }
  330. X
  331. X
  332. char *get_last_savefile ()
  333. {
  334. X    char *file;
  335. X    int i;
  336. X    
  337. X    for (i=save_num-1 ; i >= 0 ; i--) {
  338. X        if (save[i].saved) {
  339. X            file = (char *) my_malloc (LEN);
  340. X            if (save[i].is_mailbox) {
  341. X                sprintf (file, "%s/%s", save[i].dir, save[i].file);
  342. X                return (file);
  343. X            } else {
  344. X                if (save[i].archive && save_archive_name) {
  345. X                    if (save[i].part) {
  346. X                        if (create_subdir) {
  347. X                            sprintf (file, "%s/%s.%s%s", save[i].archive, save[i].archive, LONG_PATH_PART, save[i].part);
  348. X                        } else {
  349. X                            sprintf (file, "%s.%s%s", save[i].archive, LONG_PATH_PART, save[i].part);
  350. X                        }
  351. X                    } else {
  352. X                        if (create_subdir) {
  353. X                            sprintf (file, "%s/%s.%s%s", save[i].archive, save[i].archive, LONG_PATH_PATCH, save[i].patch);
  354. X                        } else {
  355. X                            sprintf (file, "%s.%s%s", save[i].archive, LONG_PATH_PATCH, save[i].patch);
  356. X                        }
  357. X                    }
  358. X                } else {
  359. X                    if (! save_separate || save_num == 1) {
  360. X                        sprintf (file, "%s", save[i].file);
  361. X                    } else {
  362. X                        sprintf (file, "%s.%02d", save[i].file, i+1);
  363. X                    }
  364. X                }
  365. X                return (file);
  366. X            }
  367. X        }
  368. X    }
  369. X    return ((char *) 0);
  370. }
  371. X
  372. X
  373. int post_process_files (proc_type_ch)
  374. X    char proc_type_ch;
  375. {
  376. X    if (save_num) {
  377. X        wait_message (txt_post_processing);
  378. X
  379. X        set_real_uid_gid();
  380. X
  381. X        switch (proc_type_ch) {
  382. X            case 's':
  383. X                post_process_sh ();
  384. X                break;
  385. X                
  386. X            case 'u':
  387. X                post_process_uud (POST_PROC_UUDECODE);
  388. X                break;
  389. X
  390. X            case 'U':
  391. X                if (post_proc_type == POST_PROC_UUD_EXT_ZOO) {
  392. X                    post_process_uud (POST_PROC_UUD_EXT_ZOO);
  393. X                } else {
  394. X                    post_process_uud (POST_PROC_UUD_LST_ZOO);
  395. X                }
  396. X                break;
  397. X        }
  398. X
  399. X        info_message (txt_post_processing_finished);
  400. X        sleep (1);
  401. X        return TRUE;
  402. X    }
  403. X    return FALSE;
  404. }
  405. X
  406. X
  407. void post_process_uud (pp)
  408. X    int pp;
  409. {
  410. X    char s[LEN], t[LEN], u[LEN];
  411. X    char buf[LEN], *file;
  412. X    char file_out[LEN];
  413. X    char file_out_dir[LEN];
  414. X    FILE *fp_in, *fp_out;
  415. X    int i, state = INITIAL;
  416. X    int file_size = 0;
  417. X    struct stat st;
  418. X    
  419. X    t[0] = '\0';
  420. X    u[0] = '\0';
  421. X
  422. X    my_strncpy (file_out_dir, save_filename (0), LEN);
  423. X    for (i=strlen(file_out_dir) ; i > 0 ; i--) {
  424. X        if (file_out_dir[i] == '/') {
  425. X            file_out_dir[i] = '\0';
  426. X            break;
  427. X        }
  428. X    }
  429. X
  430. X    sprintf (file_out, "%s/tin.%05d", file_out_dir, getpid ());
  431. X    
  432. X    if ((fp_out = fopen (file_out, "a+")) == NULL) {
  433. X        error_message (txt_cannot_open, file_out);
  434. X    }
  435. X
  436. X
  437. X    for (i=0 ; i < save_num ; i++) {
  438. X        my_strncpy (buf, save_filename (i), LEN);
  439. X
  440. X        if ((fp_in = fopen (buf, "r")) != NULL) {
  441. X            if (fgets (s, sizeof s, fp_in) == NULL) {
  442. X                fclose (fp_in);
  443. X                continue;
  444. X            }
  445. X            while (state != END) { 
  446. X                switch (state) {
  447. X                    case INITIAL:
  448. X                        if (! strncmp ("begin", s, 5)) {
  449. X                            state = MIDDLE;
  450. X                            fprintf (fp_out, "%s", s);
  451. X                        }
  452. X                        break;
  453. X
  454. X                    case MIDDLE:
  455. X                        if (s[0] == 'M') {
  456. X                            fprintf (fp_out, "%s", s);
  457. X                        } else if (strncmp("end", s, 3)) {
  458. X                            state = OFF;
  459. X                        } else { /* end */
  460. X                            state = END;
  461. X                            if (u[0] != 'M') {
  462. X                                fprintf (fp_out, "%s", u);
  463. X                            }
  464. X                            if (t[0] != 'M') {
  465. X                                fprintf (fp_out, "%s", t);
  466. X                            }
  467. X                            fprintf (fp_out, "%s\n", s);
  468. X                        }
  469. X                        break;
  470. X
  471. X                    case OFF:
  472. X                        if ((s[0] == 'M') && (t[0] == 'M') && (u[0] == 'M')) {
  473. X                            fprintf (fp_out, "%s", u);
  474. X                            fprintf (fp_out, "%s", t);
  475. X                            fprintf (fp_out, "%s", s);
  476. X                            state = MIDDLE;
  477. X                        } else if (! strncmp ("end", s, 3)) {
  478. X                            state = END;
  479. X                            if (u[0] != 'M') {
  480. X                                fprintf (fp_out, "%s", u);
  481. X                            }
  482. X                            if (t[0] != 'M') {
  483. X                                fprintf (fp_out, "%s", t);
  484. X                            }
  485. X                            fprintf (fp_out, "%s\n", s);
  486. X                        }
  487. X                        break;
  488. X
  489. X                    case END:
  490. X                        break;
  491. X
  492. X                    default:
  493. X                        fprintf (stderr, "\r\nerror: ASSERT - default state\n");
  494. X                        fclose (fp_in);
  495. X                        fclose (fp_out);
  496. X                        unlink (file_out);
  497. X                        return;
  498. X                }
  499. X                strcpy (u,t);
  500. X                strcpy (t,s);
  501. X                /*
  502. X                 *  read next line & if error goto next file in save array
  503. X                 */
  504. X                if (fgets (s, sizeof s, fp_in) == NULL) {
  505. X                    break;
  506. X                }
  507. X            }
  508. X            fclose (fp_in);
  509. X        }
  510. X    }
  511. X    fclose (fp_out);
  512. X
  513. X    /*
  514. X     *  uudecode file
  515. X     */
  516. X    wait_message (txt_uudecoding);
  517. X    
  518. X    sprintf (buf, "cd %s; uudecode %s", file_out_dir, file_out); 
  519. X    if (invoke_cmd (buf)) {
  520. X        set_real_uid_gid ();
  521. X        /*
  522. X         *  sum file
  523. X         */
  524. X        if ((file = get_archive_file (file_out_dir, "*")) != NULL) { 
  525. X            sprintf (buf, "%s %s", DEFAULT_SUM, file); 
  526. X            printf ("\r\n\r\nChecksum of %s...\r\n\r\n", file); 
  527. X            fflush (stdout);
  528. X            if ((fp_in = popen (buf, "r")) == NULL) {
  529. X                printf ("Cannot execute %s\r\n", buf); 
  530. X                fflush (stdout);
  531. X            } else {
  532. X                if (stat (file, &st) != -1) {
  533. X                    file_size = (int) st.st_size;
  534. X                }
  535. X                if (fgets (buf, sizeof buf, fp_in) != NULL) {
  536. X                    buf[strlen (buf)-1] = '\0';
  537. X                }
  538. X                fclose (fp_in);
  539. X                printf ("%s  %8d bytes\r\n", buf, file_size); 
  540. X                fflush (stdout);
  541. X            }
  542. X            if (file != (char *) 0) {
  543. X                free (file);
  544. X                file = (char *) 0;
  545. X            }
  546. X        }
  547. X    }
  548. X
  549. X    set_real_uid_gid ();
  550. X
  551. X    if (pp > POST_PROC_UUDECODE) {
  552. X        sprintf (buf, "*.%s", archiver[pp].ext); 
  553. X        if ((file = get_archive_file (file_out_dir, buf)) != NULL) {
  554. X            if (pp == POST_PROC_UUD_EXT_ZOO) {
  555. X                sprintf (buf, "cd %s; %s %s %s", file_out_dir,
  556. X                    archiver[pp].name, archiver[pp].extract, file);
  557. X                printf ("\r\n\r\nListing %s archive...\r\n", file); 
  558. X            } else {
  559. X                sprintf (buf, "cd %s; %s %s %s", file_out_dir,
  560. X                    archiver[pp].name, archiver[pp].list, file);
  561. X                printf ("\r\n\r\nExtracting %s archive...\r\n", file);
  562. X            }
  563. X            fflush (stdout);
  564. X            if (file != (char *) 0) {
  565. X                free (file);
  566. X                file = (char *) 0;
  567. X            }
  568. X            if (! invoke_cmd (buf)) {
  569. X                set_real_uid_gid ();
  570. X                error_message ("Post processing failed", "");
  571. X            }
  572. X            set_real_uid_gid ();
  573. X        }
  574. X    }
  575. X    delete_processed_files ();
  576. X
  577. X    unlink (file_out);
  578. }
  579. X
  580. /*
  581. X *  Unpack /bin/sh archives
  582. X */
  583. void post_process_sh ()
  584. {
  585. X    char buf[LEN];
  586. X    char file_in[LEN];
  587. X    char file_out[LEN];
  588. X    char file_out_dir[LEN];
  589. X    char *ptr1, *ptr2;
  590. X    char sh_pattern_1[16];
  591. X    char sh_pattern_2[16];
  592. X    FILE *fp_in, *fp_out;
  593. X    int found_header;
  594. X    int i, j;
  595. X    int patlen1, patlen2;
  596. X
  597. X    strcpy (sh_pattern_1, "#! /bin/sh");
  598. X    strcpy (sh_pattern_2, "#!/bin/sh");
  599. X
  600. X    my_strncpy (file_out_dir, save_filename (0), LEN);
  601. X    for (i=strlen(file_out_dir) ; i > 0 ; i--) {
  602. X        if (file_out_dir[i] == '/') {
  603. X            file_out_dir[i] = '\0';
  604. X            break;
  605. X        }
  606. X    }
  607. X
  608. X    sprintf (file_out, "%s/tin.%05d", file_out_dir, getpid ());
  609. X
  610. X    for (j=0 ; j < save_num ; j++) {
  611. X        my_strncpy (file_in, save_filename (j), LEN);
  612. X
  613. X        printf ("\r\nExtracting %s...\r\n", file_in);
  614. X        fflush (stdout);
  615. X
  616. X        found_header = FALSE;
  617. X        
  618. X        if ((fp_out = fopen (file_out, "w")) != NULL) {
  619. X            if ((fp_in = fopen (file_in, "r")) != NULL) {
  620. X                ptr1 = sh_pattern_1;
  621. X                ptr2 = sh_pattern_2;
  622. X                patlen1 = strlen (sh_pattern_1);
  623. X                patlen2 = strlen (sh_pattern_2);
  624. X                while (! feof (fp_in)) {
  625. X                    if (fgets (buf, sizeof buf, fp_in)) {
  626. X                        /*
  627. X                         *  find #!/bin/sh or #! /bin/sh pattern
  628. X                         */
  629. X                        if (!found_header) {
  630. X                            if (str_str (buf, ptr1, patlen1) != 0 ||
  631. X                                str_str (buf, ptr2, patlen2) != 0) {
  632. X                                found_header = TRUE;
  633. X                            }
  634. X                        }
  635. X                    
  636. X                        /*
  637. X                         *  Write to temp file
  638. X                         */
  639. X                        if (found_header) {
  640. X                            fputs (buf, fp_out);
  641. X                        }
  642. X                    }
  643. X                }
  644. X                fclose (fp_in);
  645. X            }
  646. X            fclose (fp_out);
  647. X
  648. X            sprintf (buf, "cd %s; sh %s", file_out_dir, file_out); 
  649. X            printf ("\r\n");
  650. X            fflush (stdout);
  651. X            Raw (FALSE);
  652. X            invoke_cmd (buf);
  653. X            set_real_uid_gid ();
  654. X            Raw (TRUE);
  655. X            unlink (file_out);
  656. X        }
  657. X    }
  658. X    delete_processed_files ();
  659. }
  660. X
  661. X
  662. char *get_archive_file (dir, ext)
  663. X    char *dir;
  664. X    char *ext;
  665. {
  666. X    char buf[LEN];
  667. X    char *file = NULL;
  668. X    FILE *fp;
  669. X    
  670. X    sprintf (buf, "ls -t %s/%s", dir, ext);
  671. X
  672. X    if ((fp = popen (buf, "r")) == NULL) {
  673. X        return (char *) 0;
  674. X    }
  675. X
  676. X    if (fgets (buf, sizeof buf, fp) != NULL) {
  677. X        file = str_dup (buf);
  678. X        file[strlen (file)-1] = '\0';
  679. X    }
  680. X    
  681. X    fclose (fp);
  682. X
  683. X    return (file);
  684. }
  685. X
  686. X
  687. void delete_processed_files ()
  688. {
  689. X    int i;
  690. X
  691. X    printf ("\r\n");
  692. X    fflush (stdout);
  693. X    
  694. X    if (prompt_yn (LINES, "Delete saved files that have been post processed? (y/n): ", 'y')) {
  695. X        wait_message (txt_deleting);
  696. X
  697. X        for (i=0 ; i < save_num ; i++) {
  698. X            unlink (save_filename (i));
  699. X        }
  700. X    }
  701. }
  702. SHAR_EOF
  703. echo 'File save.c is complete' &&
  704. chmod 0600 save.c ||
  705. echo 'restore of save.c failed'
  706. Wc_c="`wc -c < 'save.c'`"
  707. test 24939 -eq "$Wc_c" ||
  708.     echo 'save.c: original size 24939, current size' "$Wc_c"
  709. rm -f _shar_wnt_.tmp
  710. fi
  711. # ============= screen.c ==============
  712. if test -f 'screen.c' -a X"$1" != X"-c"; then
  713.     echo 'x - skipping screen.c (File already exists)'
  714.     rm -f _shar_wnt_.tmp
  715. else
  716. > _shar_wnt_.tmp
  717. echo 'x - extracting screen.c (Text)'
  718. sed 's/^X//' << 'SHAR_EOF' > 'screen.c' &&
  719. /*
  720. X *  Project   : tin - a threaded Netnews reader
  721. X *  Module    : screen.c
  722. X *  Author    : R.Skrenta / I.Lea
  723. X *  Created   : 01-04-91
  724. X *  Updated   : 15-12-91
  725. X *  Notes     :
  726. X *  Copyright : (c) Copyright 1991-92 by Rich Skrenta & Iain Lea
  727. X *                You may  freely  copy or  redistribute  this software,
  728. X *              so  long as there is no profit made from its use, sale
  729. X *              trade or  reproduction.  You may not change this copy-
  730. X *              right notice, and it must be included in any copy made
  731. X */
  732. X
  733. #include    "tin.h"
  734. X
  735. extern int errno;
  736. X
  737. char msg[LEN];
  738. struct screen_t *screen;
  739. X
  740. X
  741. void info_message (str)
  742. X    char *str;
  743. {
  744. X    clear_message ();                /* Clear any old messages hanging around */
  745. X    center_line (LINES, FALSE, str);    /* center the message at screen bottom */
  746. X    if (! cmd_line) {
  747. X        MoveCursor (LINES, 0);
  748. X    }
  749. }
  750. X
  751. X
  752. void wait_message (str)
  753. X    char *str;
  754. {
  755. X    clear_message ();      /* Clear any old messages hanging around */
  756. X    printf ("%s", str);
  757. X    fflush (stdout);
  758. }
  759. X
  760. X
  761. void error_message (template, str)
  762. X    char *template;
  763. X    char *str;
  764. {
  765. X    errno = 0;
  766. X
  767. X    clear_message ();      /* Clear any old messages hanging around */
  768. X    
  769. X    fprintf (stderr, template, str);
  770. X    fflush (stderr);
  771. X
  772. X    if (cmd_line) {
  773. X        fprintf (stderr, "\n");
  774. X        fflush (stderr);
  775. X    } else {
  776. X        MoveCursor (LINES, 0);
  777. X        sleep (2);
  778. X    }
  779. }
  780. X
  781. X
  782. void clear_message ()
  783. {
  784. X    if (! cmd_line) {
  785. X        MoveCursor (LINES, 0);
  786. X        CleartoEOLN ();
  787. X    }
  788. }
  789. X
  790. X
  791. void center_line (line, inverse, str)
  792. X    int line;
  793. X    int inverse;
  794. X    char *str;
  795. {
  796. X    int pos;
  797. X
  798. X    if (! cmd_line) {
  799. X        pos = (COLS - (int) strlen (str)) / 2;
  800. X        MoveCursor (line, pos);
  801. X        if (inverse) {
  802. X            StartInverse ();
  803. X        }
  804. X    }
  805. X
  806. X    printf ("%s", str);
  807. X    fflush (stdout);
  808. X
  809. X    if (! cmd_line) {
  810. X        if (inverse) {
  811. X            EndInverse ();
  812. X        }
  813. X    }
  814. }
  815. X
  816. X
  817. void draw_arrow (line)
  818. X    int line;
  819. {
  820. X    MoveCursor (line, 0);
  821. X
  822. X    if (draw_arrow_mark) {
  823. X        printf ("->");
  824. X        fflush (stdout);
  825. X    } else {
  826. X        StartInverse ();
  827. X        printf ("%s", screen[line-INDEX_TOP].col);
  828. X        fflush (stdout);
  829. X        EndInverse ();
  830. X    }
  831. X    MoveCursor (LINES, 0);
  832. }
  833. X
  834. X
  835. void erase_arrow (line)
  836. X    int line;
  837. {
  838. X    MoveCursor (line, 0);
  839. X
  840. X    if (draw_arrow_mark) {
  841. X        printf ("  ");
  842. X    } else {
  843. X        EndInverse ();
  844. X        printf ("%s", screen[line-INDEX_TOP].col);
  845. X    }
  846. X    fflush (stdout);
  847. }
  848. X
  849. X
  850. void show_title (title)
  851. X    char *title;
  852. {    
  853. X    int col;
  854. X    
  855. X    col = (COLS - (int) strlen (txt_type_h_for_help))+1;
  856. X    if (col) {
  857. X        MoveCursor (0, 0);
  858. X        if (kill_articles) {        /* display KILL on screen */
  859. X            printf ("KILL ON");
  860. X        }
  861. X        
  862. X        MoveCursor (0, col);
  863. X        if (mail_check ()) {        /* you have mail message in */
  864. X            printf (txt_you_have_mail);
  865. X        } else {
  866. X            printf (txt_type_h_for_help);
  867. X        }
  868. X    }
  869. X    center_line (0, TRUE, title);
  870. }
  871. X
  872. X
  873. void ring_bell ()
  874. {
  875. X    fputc ('\007', stdout);
  876. X    fflush (stdout);
  877. }
  878. SHAR_EOF
  879. chmod 0600 screen.c ||
  880. echo 'restore of screen.c failed'
  881. Wc_c="`wc -c < 'screen.c'`"
  882. test 2661 -eq "$Wc_c" ||
  883.     echo 'screen.c: original size 2661, current size' "$Wc_c"
  884. rm -f _shar_wnt_.tmp
  885. fi
  886. # ============= search.c ==============
  887. if test -f 'search.c' -a X"$1" != X"-c"; then
  888.     echo 'x - skipping search.c (File already exists)'
  889.     rm -f _shar_wnt_.tmp
  890. else
  891. > _shar_wnt_.tmp
  892. echo 'x - extracting search.c (Text)'
  893. sed 's/^X//' << 'SHAR_EOF' > 'search.c' &&
  894. /*
  895. X *  Project   : tin - a threaded Netnews reader
  896. X *  Module    : search.c
  897. X *  Author    : R.Skrenta / I.Lea
  898. X *  Created   : 01-04-91
  899. X *  Updated   : 31-01-92
  900. X *  Notes     :
  901. X *  Copyright : (c) Copyright 1991-92 by Rich Skrenta & Iain Lea
  902. X *              You may  freely  copy or  redistribute  this software,
  903. X *              so  long as there is no profit made from its use, sale
  904. X *              trade or  reproduction.  You may not change this copy-
  905. X *              right notice, and it must be included in any copy made
  906. X */
  907. X
  908. #include    "tin.h"
  909. X
  910. extern FILE *note_fp;
  911. extern int cur_groupnum;
  912. extern int first_group_on_screen;
  913. extern int last_group_on_screen;
  914. extern int first_subj_on_screen;
  915. extern int last_subj_on_screen;
  916. extern int index_point;
  917. extern int note_line;
  918. extern int note_page;
  919. extern int note_end;
  920. extern long note_mark[MAX_PAGES];
  921. X
  922. /*
  923. X * last search patterns
  924. X */
  925. X
  926. char author_search_string[LEN];
  927. char group_search_string[LEN];
  928. char subject_search_string[LEN];
  929. char art_search_string[LEN];
  930. X
  931. X
  932. /*
  933. X *  group.c & page.c
  934. X */
  935. int search_author (max_art, current_art, forward)
  936. X    int max_art;
  937. X    int current_art;
  938. X    int forward;
  939. {
  940. X    char buf[LEN];
  941. X    char buf2[LEN];
  942. X    int i, patlen;
  943. X
  944. X    clear_message ();
  945. X
  946. X    if (forward) {
  947. X        sprintf (buf2, txt_author_search_forwards, author_search_string);
  948. X    } else {
  949. X        sprintf (buf2, txt_author_search_backwards, author_search_string);
  950. X    }
  951. X    
  952. X    if (! prompt_string (buf2, buf)) {
  953. X        return -1;
  954. X    }
  955. X    
  956. X    if (strlen (buf)) {
  957. X        strcpy (author_search_string, buf);
  958. X    } else {
  959. X        if (author_search_string[0]) {
  960. X            strcpy (buf, author_search_string);
  961. X        } else {
  962. X            info_message (txt_no_search_string);    
  963. X            return -1;
  964. X        }
  965. X    }
  966. X
  967. X    wait_message (txt_searching);
  968. X
  969. X    make_lower (author_search_string, buf);
  970. X
  971. X    patlen = strlen (author_search_string);
  972. X
  973. X    i = current_art;
  974. X
  975. X    do {
  976. X        if (forward) {
  977. X            i = next_response (i);
  978. X            if (i < 0)
  979. X                i = 0;
  980. X        } else {
  981. X            i = prev_response (i);
  982. X            if (i < 0)
  983. X                i = max_art - 1;
  984. X        }
  985. X
  986. X        if (arts[i].name == (char *) 0) {
  987. X            make_lower (arts[i].from, buf2);
  988. X        } else {
  989. X            sprintf (msg, "%s (%s)", arts[i].from, arts[i].name);
  990. X            make_lower (msg, buf2);
  991. X        }
  992. X
  993. X        if (str_str (buf2, buf, patlen) != 0) {
  994. X            clear_message ();
  995. X            return i;
  996. X        }
  997. X    } while (i != current_art);
  998. X
  999. X    info_message (txt_no_match);
  1000. X    return -1;
  1001. }
  1002. X
  1003. /*
  1004. X * select.c
  1005. X */
  1006. void search_group (forward)
  1007. X    int forward;
  1008. {
  1009. X    char buf[LEN];
  1010. X    char buf2[LEN];
  1011. X    int i, patlen;
  1012. X
  1013. X    clear_message ();
  1014. X
  1015. X    if (forward) {
  1016. X        sprintf (buf2, txt_search_forwards, group_search_string);
  1017. X    } else {
  1018. X        sprintf (buf2, txt_search_backwards, group_search_string);
  1019. X    }
  1020. X
  1021. X    if (! prompt_string (buf2, buf)) {
  1022. X        return;
  1023. X    }
  1024. X
  1025. X    if (strlen (buf)) {
  1026. X        strcpy (group_search_string, buf);
  1027. X    } else {
  1028. X        if (group_search_string[0]) {
  1029. X            strcpy (buf, group_search_string);
  1030. X        } else {
  1031. X            info_message (txt_no_search_string);    
  1032. X            return;
  1033. X        }
  1034. X    }
  1035. X
  1036. X    wait_message (txt_searching);
  1037. X
  1038. X    make_lower (group_search_string, buf);
  1039. X
  1040. X    patlen = strlen (group_search_string);
  1041. X
  1042. X    i = cur_groupnum;
  1043. X
  1044. X    do {
  1045. X        if (forward)
  1046. X            i++;
  1047. X        else
  1048. X            i--;
  1049. X
  1050. X        if (i >= group_top)
  1051. X            i = 0;
  1052. X        if (i < 0)
  1053. X            i = group_top - 1;
  1054. X
  1055. X        make_lower (active[my_group[i]].name, buf2);
  1056. X
  1057. X        if (str_str (buf2, buf, patlen) != 0) {
  1058. X            if (i >= first_group_on_screen
  1059. X            &&  i < last_group_on_screen) {
  1060. X                clear_message ();
  1061. X                erase_group_arrow ();
  1062. X                cur_groupnum = i;
  1063. X                draw_group_arrow ();
  1064. X            } else {
  1065. X                cur_groupnum = i;
  1066. X                group_selection_page ();
  1067. X            }
  1068. X            return;
  1069. X        }
  1070. X    } while (i != cur_groupnum);
  1071. X
  1072. X    info_message (txt_no_match);
  1073. }
  1074. X
  1075. /*
  1076. X * group.c
  1077. X */
  1078. X
  1079. void search_subject (forward, group)
  1080. X    int forward;
  1081. X    char *group;
  1082. {
  1083. X    char buf[LEN];
  1084. X    char buf2[LEN];
  1085. X    int i, j, patlen;
  1086. X
  1087. X    if (index_point < 0) {
  1088. X        info_message (txt_no_arts);
  1089. X        return;
  1090. X    }
  1091. X    
  1092. X    clear_message ();
  1093. X
  1094. X    if (forward) {
  1095. X        sprintf (buf2, txt_search_forwards, subject_search_string);
  1096. X    } else {
  1097. X        sprintf (buf2, txt_search_backwards, subject_search_string);
  1098. X    }
  1099. X
  1100. X    if (! prompt_string (buf2, buf)) {
  1101. X        return;
  1102. X    }
  1103. X
  1104. X    if (strlen (buf)) {
  1105. X        strcpy (subject_search_string, buf);
  1106. X    } else {
  1107. X        if (subject_search_string[0]) {
  1108. X            strcpy (buf, subject_search_string);
  1109. X        } else {
  1110. X            info_message (txt_no_search_string);    
  1111. X            return;
  1112. X        }
  1113. X    }
  1114. X
  1115. X    wait_message (txt_searching);
  1116. X
  1117. X    make_lower (subject_search_string, buf);
  1118. X
  1119. X    patlen = strlen (subject_search_string);
  1120. X
  1121. X    i = index_point;
  1122. X
  1123. X    do {
  1124. X        if (forward)
  1125. X            i++;
  1126. X        else
  1127. X            i--;
  1128. X
  1129. X        if (i >= top_base)
  1130. X            i = 0;
  1131. X        if (i < 0)
  1132. X            i = top_base - 1;
  1133. X
  1134. X        j = (int) base[i];
  1135. X
  1136. X        make_lower (arts[j].subject, buf2);
  1137. X
  1138. X        if (str_str (buf2, buf, patlen) != 0) {
  1139. X            if (i >= first_subj_on_screen
  1140. X                &&  i < last_subj_on_screen) {
  1141. X                clear_message ();
  1142. X                erase_subject_arrow ();
  1143. X                index_point = i;
  1144. X                draw_subject_arrow ();
  1145. X            } else {
  1146. X                index_point = i;
  1147. X                show_group_page (group);
  1148. X            }
  1149. X            return;
  1150. X        }
  1151. X    } while (i != index_point);
  1152. X
  1153. X    info_message (txt_no_match);
  1154. }
  1155. X
  1156. /*
  1157. X *  page.c (search article body)
  1158. X */
  1159. X
  1160. int search_article (forward)
  1161. X    int forward;
  1162. {
  1163. X    char buf[LEN];
  1164. X    char buf2[LEN];
  1165. X    char string[LEN];
  1166. X    char pattern[LEN];
  1167. X    char *p, *q;
  1168. X    int ctrl_L;
  1169. X    int i, j, patlen;
  1170. X    int orig_note_end;
  1171. X    int orig_note_page;
  1172. X
  1173. X    clear_message ();
  1174. X
  1175. X    if (forward) {
  1176. X        sprintf (buf2, txt_search_forwards, art_search_string);
  1177. X    } else {
  1178. X        sprintf (buf2, txt_search_backwards, art_search_string);
  1179. X    }
  1180. X
  1181. X    if (! prompt_string (buf2, buf)) {
  1182. X        return FALSE;
  1183. X    }
  1184. X
  1185. X    if (strlen (buf)) {
  1186. X        strcpy (art_search_string, buf);
  1187. X    } else {
  1188. X        if (art_search_string[0]) {
  1189. X            strcpy (buf, art_search_string);
  1190. X        } else {
  1191. X            info_message (txt_no_search_string);    
  1192. X            return FALSE;
  1193. X        }
  1194. X    }
  1195. X
  1196. X    wait_message (txt_searching);
  1197. X    
  1198. X    make_lower (art_search_string, pattern);
  1199. X
  1200. X    patlen = strlen (art_search_string);
  1201. X
  1202. X    /*
  1203. X     *  save current position in article
  1204. X     */
  1205. X    orig_note_end = note_end;
  1206. X    orig_note_page = note_page;
  1207. X    
  1208. X    while (! note_end) {
  1209. X        note_line = 1;
  1210. X        ctrl_L = FALSE;
  1211. X
  1212. X        if (note_page == 0) {
  1213. X            note_line += 4;
  1214. X        } else {
  1215. X            note_line += 2;
  1216. X        }
  1217. X        while (note_line < LINES) {
  1218. X            if (fgets (buf, sizeof buf, note_fp) == NULL) {
  1219. X                note_end = TRUE;
  1220. X                break;
  1221. X            }
  1222. X            buf[LEN-1] = '\0';
  1223. X            for (p = buf, q = buf2;    *p && *p != '\n' && q<&buf2[LEN]; p++) {
  1224. X                if (*p == '\b' && q > buf2) {
  1225. X                    q--;
  1226. X                } else if (*p == '\f') {        /* ^L */
  1227. X                    *q++ = '^';
  1228. X                    *q++ = 'L';
  1229. X                    ctrl_L = TRUE;
  1230. X                } else if (*p == '\t') {
  1231. X                    i = q - buf2;
  1232. X                    j = (i|7) + 1;
  1233. X
  1234. X                    while (i++ < j) {
  1235. X                        *q++ = ' ';
  1236. X                    }
  1237. X                } else if (((*p) & 0xFF) < ' ') {
  1238. X                    *q++ = '^';
  1239. X                    *q++ = ((*p) & 0xFF) + '@';
  1240. X                } else {
  1241. X                    *q++ = *p;
  1242. X                }
  1243. X            }
  1244. X            *q = '\0';
  1245. X
  1246. X            make_lower (buf2, string);
  1247. X
  1248. X            if (str_str (string, pattern, patlen) != 0) {
  1249. X                fseek (note_fp, note_mark[note_page], 0);
  1250. X                return TRUE;
  1251. X            }
  1252. X
  1253. X            note_line += ((int) strlen(buf2) / COLS) + 1;
  1254. X
  1255. X            if (ctrl_L) {
  1256. X                break;
  1257. X            }
  1258. X        }
  1259. X        if (! note_end) {
  1260. X            note_mark[++note_page] = ftell (note_fp);
  1261. X        }
  1262. X    }
  1263. X
  1264. X    note_end = orig_note_end;
  1265. X    note_page = orig_note_page;
  1266. X    fseek (note_fp, note_mark[note_page], 0);
  1267. X    info_message (txt_no_match);
  1268. X    return FALSE;
  1269. }
  1270. X
  1271. X
  1272. void make_lower (s, t)
  1273. X    char *s;
  1274. X    char *t;
  1275. {
  1276. X
  1277. X    while (*s) {
  1278. X        if (isupper(*s))
  1279. X            *t = tolower(*s);
  1280. X        else
  1281. X            *t = *s;
  1282. X        s++;
  1283. X        t++;
  1284. X    }
  1285. X    *t = 0;
  1286. }
  1287. SHAR_EOF
  1288. chmod 0600 search.c ||
  1289. echo 'restore of search.c failed'
  1290. Wc_c="`wc -c < 'search.c'`"
  1291. test 7006 -eq "$Wc_c" ||
  1292.     echo 'search.c: original size 7006, current size' "$Wc_c"
  1293. rm -f _shar_wnt_.tmp
  1294. fi
  1295. # ============= select.c ==============
  1296. if test -f 'select.c' -a X"$1" != X"-c"; then
  1297.     echo 'x - skipping select.c (File already exists)'
  1298.     rm -f _shar_wnt_.tmp
  1299. else
  1300. > _shar_wnt_.tmp
  1301. echo 'x - extracting select.c (Text)'
  1302. sed 's/^X//' << 'SHAR_EOF' > 'select.c' &&
  1303. /*
  1304. X *  Project   : tin - a threaded Netnews reader
  1305. X *  Module    : select.c
  1306. X *  Author    : R.Skrenta / I.Lea
  1307. X *  Created   : 01-04-91
  1308. X *  Updated   : 31-01-92
  1309. X *  Notes     :
  1310. X *  Copyright : (c) Copyright 1991-92 by Rich Skrenta & Iain Lea
  1311. X *                You may  freely  copy or  redistribute  this software,
  1312. X *              so  long as there is no profit made from its use, sale
  1313. X *              trade or  reproduction.  You may not change this copy-
  1314. X *              right notice, and it must be included in any copy made
  1315. X */
  1316. X
  1317. #include    "tin.h"
  1318. X
  1319. X
  1320. extern char cvers[LEN];
  1321. extern int index_point;
  1322. X
  1323. int cur_groupnum = 0;
  1324. int first_group_on_screen;
  1325. int last_group_on_screen;
  1326. int reread_active_file = TRUE;
  1327. int space_mode;
  1328. X
  1329. X
  1330. void selection_index (start_groupnum)
  1331. X    int start_groupnum;
  1332. {
  1333. X    char buf[LEN];
  1334. X    char post_group[LEN];
  1335. X    char ch;
  1336. X    int i, n;
  1337. X    int patlen;
  1338. X    int posted;
  1339. X    int scroll_lines;
  1340. X    int subscribe_num;
  1341. X
  1342. X    cur_groupnum = start_groupnum;
  1343. X    
  1344. X    mail_setup ();        /* record mailbox size for "you have mail" */
  1345. X
  1346. #ifndef USE_CLEARSCREEN
  1347. X    ClearScreen();
  1348. #endif
  1349. X
  1350. X    group_selection_page ();        /* display group selection page */
  1351. X
  1352. X    while (TRUE) {
  1353. X        num_of_killed_files = 0;
  1354. X        num_of_tagged_files = 0;
  1355. X        ch = (char) ReadCh();
  1356. X
  1357. X        if (ch > '0' && ch <= '9') {
  1358. X            prompt_group_num (ch);
  1359. X        } else switch (ch) {
  1360. X            case ESC:    /* (ESC) common arrow keys */
  1361. X                switch (get_arrow_key ()) {
  1362. X                    case KEYMAP_UP:
  1363. X                        goto select_up;
  1364. X
  1365. X                    case KEYMAP_DOWN:
  1366. X                        goto select_down;
  1367. X
  1368. X                    case KEYMAP_PAGE_UP:
  1369. X                        goto select_page_up;
  1370. X
  1371. X                    case KEYMAP_PAGE_DOWN:
  1372. X                        goto select_page_down;
  1373. X
  1374. X                    case KEYMAP_HOME:
  1375. X                        if (cur_groupnum != 0) {
  1376. X                            cur_groupnum = 0;
  1377. X                            group_selection_page ();
  1378. X                        }
  1379. X                        break;
  1380. X                    
  1381. X                    case KEYMAP_END:
  1382. X                        goto end_of_list;
  1383. X                }
  1384. X                break;
  1385. X
  1386. #ifndef NO_SHELL_ESCAPE
  1387. X            case '!':
  1388. X                shell_escape ();
  1389. X                group_selection_page ();
  1390. X                break;
  1391. #endif
  1392. X
  1393. X            case '$':    /* show last page of groups */
  1394. end_of_list:
  1395. X                if (cur_groupnum != group_top - 1) {
  1396. X                    cur_groupnum = group_top - 1;
  1397. X                    group_selection_page ();
  1398. X                }
  1399. X                break;
  1400. X
  1401. X            case '/':    /* search forward */
  1402. X            case '?':    /* search backward */
  1403. X                i = (ch == '/');
  1404. X                search_group (i);
  1405. X                break;
  1406. X
  1407. X            case '\r':    /* go into group */
  1408. X            case '\n':
  1409. X                if (group_top == 0) {
  1410. X                    info_message (txt_no_groups);
  1411. X                    break;
  1412. X                }
  1413. X                
  1414. X                n = my_group[cur_groupnum];
  1415. X                if (active[n].min <= active[n].max) {
  1416. X                    space_mode = pos_first_unread;
  1417. X                    clear_message();
  1418. X                    index_point = -1;
  1419. X                    do {
  1420. X                        n = my_group[cur_groupnum];
  1421. X                        group_page (active[n].name);
  1422. X                    } while (index_point == -3);
  1423. X                    group_selection_page ();
  1424. X                } else {
  1425. X                    info_message (txt_no_arts);
  1426. X                }
  1427. X                break;
  1428. X
  1429. X            case '\t':    /* enter next group containing unread articles */
  1430. X            case 'n':
  1431. X                next_unread_group (TRUE);
  1432. X                break;
  1433. X
  1434. X            case ' ':            /* page down */
  1435. X            case ctrl('D'):        /* vi style */
  1436. X            case ctrl('V'):        /* emacs style */
  1437. select_page_down:
  1438. X                if (group_top == 0) {
  1439. X                    break;
  1440. X                }
  1441. X                if (cur_groupnum == group_top - 1) {
  1442. X                    break;
  1443. X                }
  1444. X                erase_group_arrow ();
  1445. X                scroll_lines = (full_page_scroll ? NOTESLINES : NOTESLINES / 2);
  1446. X                cur_groupnum = ((cur_groupnum + scroll_lines) / scroll_lines) * scroll_lines;
  1447. X                if (cur_groupnum >= group_top) {
  1448. X                    cur_groupnum = (group_top / scroll_lines) * scroll_lines;
  1449. X                    if (cur_groupnum < group_top - 1) {
  1450. X                        cur_groupnum = group_top - 1;
  1451. X                    }
  1452. X                }
  1453. X
  1454. X                if (cur_groupnum <= first_group_on_screen
  1455. X                ||  cur_groupnum >= last_group_on_screen)
  1456. X                    group_selection_page ();
  1457. X                else
  1458. X                    draw_group_arrow ();
  1459. X                break;
  1460. X
  1461. X            case ctrl('K'):
  1462. X                if (group_top <= 0) {
  1463. X                    info_message (txt_no_groups_to_delete);
  1464. X                    break;
  1465. X                }
  1466. X
  1467. X                sprintf (buf, active[my_group[cur_groupnum]].name);
  1468. X                sprintf (msg, txt_del_group_in_newsrc, buf);
  1469. X                if (prompt_yn (LINES, msg, 'y')) {
  1470. X                    delete_group (active[my_group[cur_groupnum]].name);
  1471. X                    active[my_group[cur_groupnum]].flag = UNSUBSCRIBED;    
  1472. X
  1473. X                    group_top--;
  1474. X                    for (i = cur_groupnum; i < group_top; i++) {
  1475. X                        my_group[i] = my_group[i+1];
  1476. X                        unread[i] = unread[i+1];
  1477. X                    }
  1478. X                    if (cur_groupnum >= group_top)
  1479. X                        cur_groupnum = group_top - 1;    
  1480. X
  1481. X                    group_selection_page ();
  1482. X                    sprintf (msg, txt_group_deleted, buf);
  1483. X                    info_message (msg);
  1484. X                }
  1485. X                break;
  1486. X
  1487. X            case ctrl('L'):        /* redraw */
  1488. #ifndef USE_CLEARSCREEN
  1489. X                ClearScreen ();
  1490. #endif
  1491. X                group_selection_page();
  1492. X                break;
  1493. X
  1494. X            case ctrl('N'):        /* line down */
  1495. X            case 'j':
  1496. select_down:
  1497. X                if (cur_groupnum + 1 >= group_top) {
  1498. X                    break;
  1499. X                }
  1500. X                if (cur_groupnum + 1 >= last_group_on_screen) {
  1501. #ifndef USE_CLEARSCREEN
  1502. X                    erase_group_arrow();
  1503. #endif                    
  1504. X                    cur_groupnum++;
  1505. X                    group_selection_page();
  1506. X                } else {
  1507. X                    erase_group_arrow();
  1508. X                    cur_groupnum++;
  1509. X                    draw_group_arrow();
  1510. X                }
  1511. X                break;
  1512. X
  1513. X            case ctrl('P'):        /* line up */
  1514. X            case 'k':
  1515. select_up:
  1516. X                if (cur_groupnum == 0) {
  1517. X                    break;
  1518. X                }
  1519. X                if (cur_groupnum <= first_group_on_screen) {
  1520. X                    cur_groupnum--;
  1521. X                    group_selection_page();
  1522. X                } else {
  1523. X                    erase_group_arrow();
  1524. X                    cur_groupnum--;
  1525. X                    draw_group_arrow();
  1526. X                }
  1527. X                break;
  1528. X
  1529. X            case ctrl('R'):    /* reset .newsrc */
  1530. X                if (prompt_yn (LINES, txt_reset_newsrc, 'n')) {
  1531. X                    reset_newsrc ();
  1532. X                    cur_groupnum = 0;
  1533. X                    group_selection_page ();
  1534. X                }
  1535. X                break;
  1536. X
  1537. X            case ctrl('U'):        /* page up */
  1538. X            case 'b':
  1539. select_page_up:
  1540. X                if (group_top == 0) {
  1541. X                    break;
  1542. X                }
  1543. X                if (cur_groupnum == 0) {
  1544. X                    break;
  1545. X                }
  1546. X                erase_group_arrow ();
  1547. X                scroll_lines = (full_page_scroll ? NOTESLINES : NOTESLINES / 2);
  1548. X                if ((n = cur_groupnum % scroll_lines) > 0) {
  1549. X                    cur_groupnum = cur_groupnum - n;
  1550. X                } else {
  1551. X                    cur_groupnum = ((cur_groupnum - scroll_lines) / scroll_lines) * scroll_lines;
  1552. X                }
  1553. X                if (cur_groupnum < 0) {
  1554. X                    cur_groupnum = 0;
  1555. X                }
  1556. X                if (cur_groupnum < first_group_on_screen
  1557. X                ||  cur_groupnum >= last_group_on_screen)
  1558. X                    group_selection_page ();
  1559. X                else
  1560. X                    draw_group_arrow ();
  1561. X                break;
  1562. X
  1563. X            case 'B':    /* bug/gripe/comment mailed to author */
  1564. X                mail_bug_report ();
  1565. #ifndef USE_CLEARSCREEN
  1566. X                ClearScreen ();
  1567. #endif
  1568. X                group_selection_page();
  1569. X                break;
  1570. X                
  1571. X            case 'c':    /* catchup--mark all articles as read */
  1572. X            case 'C':    /* catchup & goto next unread group */
  1573. X                if (group_top == 0) {
  1574. X                    break;
  1575. X                }
  1576. X                catchup_group ((ch == 'C'));
  1577. X                break;
  1578. X
  1579. X            case 'g':    /* prompt for a new group name */
  1580. X                if ((n = choose_new_group ()) >= 0) {
  1581. X                    if (active[my_group[n]].flag != SUBSCRIBED) {
  1582. X                        subscribe (active[my_group[n]].name, ':',
  1583. X                            my_group[n], FALSE);
  1584. X                    }
  1585. X                    erase_group_arrow();
  1586. X                    cur_groupnum = reposition_group (active[my_group[n]].name,
  1587. X                                                    (n ? n : cur_groupnum));
  1588. X                    if (cur_groupnum < first_group_on_screen ||
  1589. X                        cur_groupnum >= last_group_on_screen ||
  1590. X                        cur_groupnum != n) {
  1591. X                        group_selection_page();
  1592. X                    } else {
  1593. X                        clear_message ();
  1594. X                        draw_group_arrow();
  1595. X                    }
  1596. X                }
  1597. X                break;
  1598. X
  1599. X            case 'h':    /* help */
  1600. X                show_info_page (HELP_INFO, help_select, txt_group_select_com);
  1601. X                group_selection_page ();
  1602. X                break;
  1603. X
  1604. X            case 'I':    /* toggle inverse video */
  1605. X                erase_group_arrow ();
  1606. X                toggle_inverse_video ();
  1607. X                group_selection_page ();
  1608. X                break;
  1609. X
  1610. X            case 'm':    /* reposition group within group list */
  1611. X                if (active[my_group[cur_groupnum]].flag == SUBSCRIBED) {
  1612. X                    n = cur_groupnum;
  1613. X                    erase_group_arrow ();
  1614. X                    cur_groupnum = reposition_group (active[my_group[n]].name, n);
  1615. X                    if (cur_groupnum < first_group_on_screen ||
  1616. X                        cur_groupnum >= last_group_on_screen ||
  1617. X                        cur_groupnum != n) {
  1618. X                        group_selection_page ();
  1619. X                    } else {
  1620. X                        clear_message ();
  1621. X                        draw_group_arrow ();
  1622. X                    }
  1623. X                }
  1624. X                break;
  1625. X
  1626. X            case 'M':    /* options menu */
  1627. X                change_rcfile ("", TRUE);
  1628. X                group_selection_page ();
  1629. X                break;
  1630. X
  1631. X            case 'N':    /* goto next unread group */
  1632. X                next_unread_group (FALSE);
  1633. X                break;
  1634. X
  1635. X            case 'q':    /* quit */
  1636. X                tin_done (0);
  1637. X                break;
  1638. X
  1639. X            case 's':    /* subscribe to current group */
  1640. X                if (group_top == 0) {
  1641. X                    break;
  1642. X                }
  1643. X                if (active[my_group[cur_groupnum]].flag != SUBSCRIBED) {
  1644. X                    MoveCursor (INDEX_TOP + (cur_groupnum-first_group_on_screen), 3);
  1645. X                    if (draw_arrow_mark) {
  1646. X                        putchar (' ');
  1647. X                    } else {
  1648. X                        screen[cur_groupnum-first_group_on_screen].col[3] = ' ';
  1649. X                        draw_group_arrow ();
  1650. X                    }
  1651. X                    fflush (stdout);
  1652. X                    MoveCursor (LINES, 0);    
  1653. X
  1654. X                    subscribe (active[my_group[cur_groupnum]].name,
  1655. X                        ':', my_group[cur_groupnum], FALSE);
  1656. X                    sprintf (buf, txt_subscribed_to, active[my_group[cur_groupnum]].name);
  1657. X                    info_message (buf);
  1658. X                }
  1659. X                break;
  1660. X
  1661. X            case 'S':    /* subscribe to groups matching pattern */
  1662. X                if (prompt_string (txt_subscribe_pattern, buf) && buf[0]) {
  1663. X                    wait_message (txt_subscribing);
  1664. X                    patlen = strlen (buf);
  1665. X                    for (subscribe_num=0, i=0 ; i < group_top ; i++) {
  1666. #ifdef NO_REGEX 
  1667. X                        if (str_str (active[my_group[i]].name, buf, patlen)) {
  1668. #else        
  1669. X                        if (wildmat (active[my_group[i]].name, buf)) {
  1670. #endif        
  1671. X                                if (active[my_group[i]].flag != SUBSCRIBED) {
  1672. #ifndef SLOW_SCREEN_UPDATE
  1673. X                                sprintf (msg, txt_subscribing_to, active[my_group[i]].name);
  1674. X                                wait_message (msg);
  1675. #endif                                
  1676. X                                subscribe (active[my_group[i]].name,
  1677. X                                    ':', my_group[i], FALSE);
  1678. X                            }
  1679. X                            subscribe_num++;
  1680. X                        }
  1681. X                    }
  1682. X                    if (subscribe_num) {
  1683. X                        group_selection_page ();    
  1684. X                        sprintf (buf, txt_subscribed_num_groups, subscribe_num);
  1685. X                        info_message (buf);
  1686. X                    } else {
  1687. X                        info_message (txt_no_match);
  1688. X                    }
  1689. X                } else {
  1690. X                    clear_message ();
  1691. X                }
  1692. X                break;
  1693. X
  1694. X            case 'u':    /* unsubscribe to current group */
  1695. X                if (group_top == 0) {
  1696. X                    break;
  1697. X                }
  1698. X                if (active[my_group[cur_groupnum]].flag == SUBSCRIBED) {
  1699. X                    MoveCursor(INDEX_TOP + (cur_groupnum-first_group_on_screen), 3);
  1700. X                    if (draw_arrow_mark) {
  1701. X                        putchar('u');
  1702. X                    } else {
  1703. X                        screen[cur_groupnum-first_group_on_screen].col[3] = 'u';
  1704. X                        draw_group_arrow ();
  1705. X                    }
  1706. X                    fflush(stdout);
  1707. X                    MoveCursor(LINES, 0);
  1708. X
  1709. X                    subscribe(active[my_group[cur_groupnum]].name,
  1710. X                        '!', my_group[cur_groupnum], FALSE);
  1711. X                    sprintf(buf, txt_unsubscribed_to,active[my_group[cur_groupnum]].name);
  1712. X                    info_message(buf);
  1713. X                }
  1714. X                break;
  1715. X
  1716. X            case 'U':    /* unsubscribe to groups matching pattern */
  1717. X                if (prompt_string (txt_unsubscribe_pattern, buf) && buf[0]) {    
  1718. X                    wait_message (txt_unsubscribing);
  1719. X                    patlen = strlen (buf);    
  1720. X                    for (subscribe_num=0, i=0 ; i < group_top ; i++) {        
  1721. #ifdef NO_REGEX
  1722. X                        if (str_str (active[my_group[i]].name, buf, patlen)) {
  1723. #else        
  1724. X                        if (wildmat (active[my_group[i]].name, buf)) {
  1725. #endif        
  1726. X                                if (active[my_group[i]].flag == SUBSCRIBED) {
  1727. #ifndef SLOW_SCREEN_UPDATE
  1728. X                                sprintf (msg, txt_unsubscribing_from, active[my_group[i]].name);
  1729. X                                wait_message (msg);
  1730. #endif                                
  1731. X                                subscribe (active[my_group[i]].name,
  1732. X                                    '!', my_group[i], FALSE);
  1733. X                            }
  1734. X                            subscribe_num++;
  1735. X                        }
  1736. X                    }
  1737. X                    if (subscribe_num) {
  1738. X                        group_selection_page ();    
  1739. X                        sprintf (buf, txt_unsubscribed_num_groups, subscribe_num);
  1740. X                        info_message (buf);
  1741. X                    } else {
  1742. X                        info_message (txt_no_match);
  1743. X                    }
  1744. X                } else {
  1745. X                    clear_message ();
  1746. X                }
  1747. X                break;
  1748. X
  1749. X            case 'v':    /* show tin version */
  1750. X                info_message (cvers);
  1751. X                break;
  1752. X
  1753. X            case 'w':    /* post a basenote */
  1754. X                if (! can_post) {
  1755. X                    info_message (txt_cannot_post);
  1756. X                    break;
  1757. X                }
  1758. X                if (group_top == 0) {
  1759. X                    if (! prompt_string (txt_post_newsgroup, buf)) 
  1760. X                        break;
  1761. X                    if (buf[0] == '\0')
  1762. X                        break;
  1763. X                    strcpy (post_group, buf);
  1764. X                } else {
  1765. X                    strcpy (post_group, active[my_group[cur_groupnum]].name);
  1766. X                }
  1767. X                if (post_base (post_group, &posted)) {
  1768. X                    group_selection_page ();
  1769. X                }
  1770. X                break;
  1771. X
  1772. X            case 'W':    /* display messages posted by user */
  1773. X                if (user_posted_messages ()) {
  1774. X                    group_selection_page ();
  1775. X                }
  1776. X                break;
  1777. X
  1778. X            case 'y':    /* pull in rest of groups from active */
  1779. X                if (reread_active_file) {
  1780. X                    wait_message (txt_yanking_all_groups);
  1781. X                    n = group_top;
  1782. X                    for (i = 0; i < num_active; i++) {
  1783. X                        active[i].flag = UNSUBSCRIBED;
  1784. X                    }
  1785. X                    read_newsrc (FALSE);
  1786. X                    for (i = 0; i < num_active; i++) {
  1787. X                        if (active[i].flag & UNSUBSCRIBED) {
  1788. X                            active[i].flag &= ~UNSUBSCRIBED;
  1789. X                            my_group[group_top] = i;
  1790. X                            unread[group_top] = -1;
  1791. X                            group_top++;
  1792. X                        }
  1793. X                    }
  1794. X                    if (n < group_top) {
  1795. X                        sprintf(buf, txt_added_groups, group_top - n,
  1796. X                            group_top - n == 1 ? "" : txt_plural);
  1797. X                        group_selection_page();
  1798. X                        info_message(buf);
  1799. X                    } else {
  1800. X                        info_message(txt_no_groups_to_yank_in);
  1801. X                    }
  1802. X                    reread_active_file = FALSE;
  1803. X                } else {
  1804. X                    wait_message (txt_yanking_sub_groups);
  1805. X                    read_newsrc (TRUE);
  1806. X                    cur_groupnum = group_top - 1;
  1807. X                    group_selection_page();
  1808. X                    reread_active_file = TRUE;
  1809. X                }
  1810. X                break;
  1811. X
  1812. X            case 'Y':    /* reread .newsrc, no unsub groups */
  1813. X                wait_message (txt_yanking_sub_groups);
  1814. X                cur_groupnum = 0;
  1815. X                group_top = 0;
  1816. X                for (i = 0; i < num_active; i++) {
  1817. X                    active[i].flag = UNSUBSCRIBED;
  1818. X                }
  1819. X                read_newsrc (TRUE);
  1820. X                group_selection_page ();
  1821. X                break;
  1822. X
  1823. X            case 'z':    /* mark group unread */
  1824. X                if (group_top == 0) {
  1825. X                    break;
  1826. X                }
  1827. X                n = cur_groupnum;
  1828. X                update_newsrc (active[my_group[n]].name, my_group[n], TRUE);
  1829. X                cur_groupnum = 0;
  1830. X                group_top = 0;
  1831. X                read_newsrc (TRUE);            
  1832. X                cur_groupnum = n;
  1833. X                group_selection_page ();
  1834. X                break;
  1835. X
  1836. X            case 'Z':    /* undelete groups deleted by ctrl-K */
  1837. X                if (undel_group ()) {
  1838. X                    group_selection_page ();
  1839. X                    info_message (txt_group_undeleted);
  1840. X                }
  1841. X                break;
  1842. X
  1843. X            default:
  1844. X                info_message(txt_bad_command);
  1845. X        }
  1846. X    }
  1847. }
  1848. X
  1849. X
  1850. void group_selection_page ()
  1851. {
  1852. X    char buf[LEN];
  1853. X    char new[10];
  1854. X    char subs;
  1855. X    int col, i, j, n;
  1856. X
  1857. X    set_signals_select ();
  1858. X
  1859. #ifdef USE_CLEARSCREEN
  1860. X    ClearScreen ();
  1861. #else
  1862. X    MoveCursor (0, 0);        /* top left corner */
  1863. X    CleartoEOLN ();
  1864. #endif
  1865. X
  1866. X    sprintf (buf, "%s (%d)", txt_group_selection, group_top);
  1867. X    show_title (buf);
  1868. X
  1869. #ifndef USE_CLEARSCREEN
  1870. X    MoveCursor (1, 0);
  1871. X    CleartoEOLN ();
  1872. #endif
  1873. X
  1874. X    MoveCursor (INDEX_TOP, 0);
  1875. X
  1876. X    if (cur_groupnum >= group_top) {
  1877. X        cur_groupnum = group_top - 1;
  1878. X    }
  1879. X    if (cur_groupnum < 0) {
  1880. X        cur_groupnum = 0;
  1881. X    }
  1882. X    if (NOTESLINES <= 0) {
  1883. X        first_group_on_screen = 0;
  1884. X    } else {
  1885. X        first_group_on_screen = (cur_groupnum / NOTESLINES) * NOTESLINES;
  1886. X        if (first_group_on_screen < 0) {
  1887. X            first_group_on_screen = 0;
  1888. X        }
  1889. X    }
  1890. X
  1891. X    last_group_on_screen = first_group_on_screen + NOTESLINES;
  1892. X
  1893. X    if (last_group_on_screen >= group_top) {
  1894. X        last_group_on_screen = group_top;
  1895. X        first_group_on_screen = (cur_groupnum / NOTESLINES) * NOTESLINES;
  1896. X
  1897. X        if (first_group_on_screen == last_group_on_screen ||
  1898. X            first_group_on_screen < 0) {
  1899. X            if (first_group_on_screen < 0) {
  1900. X                first_group_on_screen = 0;
  1901. X            } else {
  1902. X                first_group_on_screen = last_group_on_screen - NOTESLINES;    
  1903. X            }
  1904. X        }    
  1905. X    }
  1906. X
  1907. X    if (group_top == 0) {
  1908. X        first_group_on_screen = 0;
  1909. X        last_group_on_screen = 0;
  1910. X    }
  1911. X
  1912. X    for (j=0, i = first_group_on_screen; i < last_group_on_screen; i++,j++) {
  1913. X        switch (unread[i]) {
  1914. X            case -2:
  1915. X                sprintf (new, "?    ");
  1916. X                break;
  1917. X
  1918. X            case -1:
  1919. X                sprintf (new, "-    ");
  1920. X                break;
  1921. X
  1922. X            case 0:
  1923. X                sprintf (new, "     ");
  1924. X                break;
  1925. X
  1926. X            default:
  1927. X                sprintf (new, "%-5d", unread[i]);
  1928. X        }
  1929. X        
  1930. X        n = my_group[i];
  1931. X        if (active[n].flag & SUBSCRIBED)    /* subscribed? */
  1932. X            subs = ' ';
  1933. X        else
  1934. X            subs = 'u';    /* u next to unsubscribed groups */
  1935. X
  1936. X        if (draw_arrow_mark) {
  1937. X            printf ("   %c %4d  %-40s %s\r\n",
  1938. X                   subs, i+1, active[n].name, new);
  1939. X        } else {
  1940. X            sprintf (screen[j].col, "   %c %4d  %-40s %s%*s\r\n",
  1941. X                subs, i+1, active[n].name, new, COLS-BLANK_SELECT_COLS, " ");
  1942. X            printf ("%s", screen[j].col);
  1943. X        }
  1944. X    }
  1945. #ifndef USE_CLEARSCREEN
  1946. X    CleartoEOS ();
  1947. #endif
  1948. X
  1949. X    if (group_top <= 0) {
  1950. X        info_message (txt_no_groups);
  1951. X        return;
  1952. X    } else if (last_group_on_screen == group_top) {
  1953. X        info_message (txt_end_of_groups);
  1954. X    }
  1955. X    
  1956. X    draw_group_arrow ();
  1957. }
  1958. X
  1959. X
  1960. int prompt_group_num (ch)
  1961. X    char ch;
  1962. {
  1963. X    int num;
  1964. X
  1965. X    clear_message ();
  1966. X
  1967. X    if ((num = prompt_num (ch, txt_select_group)) == -1) {
  1968. X        clear_message ();
  1969. X        return FALSE;
  1970. X    }
  1971. X    num--;        /* index from 0 (internal) vs. 1 (user) */
  1972. X
  1973. X    if (num < 0) {
  1974. X        num = 0;
  1975. X    }
  1976. X    if (num >= group_top) {
  1977. X        num = group_top - 1;
  1978. X    }
  1979. X
  1980. X    if (num >= first_group_on_screen
  1981. X    &&  num < last_group_on_screen) {
  1982. X        erase_group_arrow ();
  1983. X        cur_groupnum = num;
  1984. X        draw_group_arrow ();
  1985. X    } else {
  1986. #ifndef USE_CLEARSCREEN
  1987. X        erase_group_arrow ();
  1988. #endif        
  1989. X        cur_groupnum = num;
  1990. X        group_selection_page ();
  1991. X    }
  1992. X
  1993. X    return TRUE;
  1994. }
  1995. X
  1996. X
  1997. void erase_group_arrow ()
  1998. {
  1999. X    erase_arrow (INDEX_TOP + (cur_groupnum-first_group_on_screen));
  2000. }
  2001. X
  2002. X
  2003. void draw_group_arrow()
  2004. {
  2005. X    draw_arrow (INDEX_TOP + (cur_groupnum-first_group_on_screen));
  2006. }
  2007. X
  2008. X
  2009. int choose_new_group ()
  2010. {
  2011. X    char buf[LEN];
  2012. X    char *p;
  2013. X    int ret;
  2014. X
  2015. X    if (! prompt_string (txt_newsgroup, buf))
  2016. X        return -1;
  2017. X
  2018. X    for (p = buf; *p && (*p == ' ' || *p == '\t'); p++)
  2019. X        continue;
  2020. X    if (*p == '\0')
  2021. X        return -1;
  2022. X
  2023. X    clear_message ();
  2024. X
  2025. X    if ((ret = add_group (p, TRUE)) < 0) {
  2026. X        sprintf (msg, txt_not_in_active_file, p);
  2027. X        info_message (msg);
  2028. X    }
  2029. X
  2030. X    return ret;
  2031. }
  2032. X
  2033. /*
  2034. X *  Add a group to the selection list (my_group[])
  2035. X *  Return the index of my_group[] if group is added or was already
  2036. X *  there.  Return -1 if named group is not in active[].
  2037. X */
  2038. X
  2039. int add_group (s, get_unread)
  2040. X    char *s;
  2041. X    int get_unread;            /* look in .newsrc for sequencer unread info? */
  2042. {
  2043. X    long h;
  2044. X    int i, j;
  2045. X
  2046. X    h = hash_groupname (s);
  2047. X
  2048. X    for (i = group_hash[h]; i >= 0; i = active[i].next) {
  2049. X        if (strcmp (s, active[i].name) == 0) {
  2050. X            for (j = 0; j < group_top; j++) {
  2051. X                if (my_group[j] == i) {
  2052. X                    return j;
  2053. X                }
  2054. X            }
  2055. X
  2056. X            active[i].flag &= ~UNSUBSCRIBED;   /* mark that we got it */
  2057. X            my_group[group_top] = i;
  2058. X
  2059. X            if (get_unread)
  2060. X                unread[group_top] = get_line_unread (s, i);
  2061. X            else
  2062. X                unread[group_top] = -2;
  2063. X
  2064. X            group_top++;
  2065. X            return group_top - 1;
  2066. X        }
  2067. X    }
  2068. X
  2069. X    return -1;
  2070. }
  2071. X
  2072. X
  2073. int reposition_group (group, default_num)
  2074. X    char *group;
  2075. X    int default_num;
  2076. {
  2077. X    char buf[LEN];
  2078. X    char pos[LEN];
  2079. X    int pos_num = 0;
  2080. X
  2081. X    sprintf (buf, txt_newsgroup_position, group);
  2082. X    
  2083. X    if (! prompt_string (buf, pos)) 
  2084. X        return default_num;
  2085. X
  2086. X    if (pos[0] == '\0')
  2087. X        return default_num;
  2088. X        
  2089. X    if (pos[0] == '$') {
  2090. X        pos_num = group_top;
  2091. X    } else {
  2092. X        pos_num = atoi (pos);
  2093. X        if (pos_num > group_top) {
  2094. X            pos_num = group_top;
  2095. X        } else if (pos_num <= 0) {
  2096. X            pos_num = 1;
  2097. X        }
  2098. X    }
  2099. X
  2100. X    wait_message (txt_moving);
  2101. X    
  2102. X    if (pos_group_in_newsrc (group, pos_num)) {
  2103. X        read_newsrc (TRUE);
  2104. X        return (pos_num-1);
  2105. X    } else {
  2106. X        return (default_num);
  2107. X    }
  2108. }
  2109. X
  2110. X
  2111. void catchup_group (goto_next_unread_group)
  2112. X    int goto_next_unread_group;
  2113. {    
  2114. X    int i;
  2115. X    
  2116. X    if (prompt_yn (LINES, txt_mark_group_read, 'y')) {
  2117. X        unread[cur_groupnum] = 0;
  2118. X        mark_group_read (active[my_group[cur_groupnum]].name,
  2119. X                        my_group[cur_groupnum]);
  2120. X        if (draw_arrow_mark) {    
  2121. X            MoveCursor (INDEX_TOP+(cur_groupnum - first_group_on_screen), 51);
  2122. X            printf ("     ");
  2123. X            MoveCursor (LINES, 0);
  2124. X            fflush (stdout);
  2125. X        } else {
  2126. X            i = cur_groupnum - first_group_on_screen;
  2127. X            screen[i].col[51] = ' ';
  2128. X            screen[i].col[52] = ' ';
  2129. X            screen[i].col[53] = ' ';
  2130. X            screen[i].col[54] = ' ';
  2131. X            screen[i].col[55] = ' ';
  2132. X        }
  2133. X        erase_group_arrow ();
  2134. X        if (cur_groupnum+1 < last_group_on_screen) {
  2135. X            cur_groupnum++;
  2136. X        }
  2137. X        draw_group_arrow ();
  2138. X
  2139. X        if (goto_next_unread_group) {
  2140. X            next_unread_group (FALSE);    
  2141. X        }
  2142. X    }
  2143. }
  2144. X
  2145. X
  2146. void next_unread_group (enter_group)
  2147. X    int enter_group;
  2148. {
  2149. X    int i;
  2150. X    
  2151. X    for (i = cur_groupnum; i < group_top; i++) {
  2152. X        if (unread[i] != 0) {
  2153. X            break;
  2154. X        }
  2155. X    }
  2156. X    if (i >= group_top) {
  2157. X        info_message (txt_no_groups_to_read);
  2158. X        return;
  2159. X    }
  2160. X
  2161. X    erase_group_arrow ();
  2162. X    cur_groupnum = i;
  2163. X    if (cur_groupnum >= last_group_on_screen) {
  2164. X        group_selection_page ();
  2165. X    } else {
  2166. X        draw_group_arrow ();
  2167. X    }
  2168. X    space_mode = pos_first_unread;
  2169. X
  2170. X    if (enter_group) {
  2171. X        clear_message ();
  2172. X        index_point = -1;
  2173. X        do {
  2174. X            group_page (active[my_group[cur_groupnum]].name);
  2175. X        } while (index_point == -3);
  2176. X        group_selection_page ();
  2177. X    }
  2178. }
  2179. SHAR_EOF
  2180. chmod 0600 select.c ||
  2181. echo 'restore of select.c failed'
  2182. Wc_c="`wc -c < 'select.c'`"
  2183. test 19773 -eq "$Wc_c" ||
  2184.     echo 'select.c: original size 19773, current size' "$Wc_c"
  2185. rm -f _shar_wnt_.tmp
  2186. fi
  2187. # ============= signal.c ==============
  2188. if test -f 'signal.c' -a X"$1" != X"-c"; then
  2189.     echo 'x - skipping signal.c (File already exists)'
  2190.     rm -f _shar_wnt_.tmp
  2191. else
  2192. > _shar_wnt_.tmp
  2193. echo 'x - extracting signal.c (Text)'
  2194. sed 's/^X//' << 'SHAR_EOF' > 'signal.c' &&
  2195. /*
  2196. X *  Project   : tin - a threaded Netnews reader
  2197. X *  Module    : signal.c
  2198. X *  Author    : I.Lea
  2199. X *  Created   : 01-04-91
  2200. X *  Updated   : 22-01-92
  2201. X *  Notes     : signal handlers for different modes and window resizing
  2202. X *  Copyright : (c) Copyright 1991-92 by Iain Lea
  2203. X *                You may  freely  copy or  redistribute  this software,
  2204. X *              so  long as there is no profit made from its use, sale
  2205. X *              trade or  reproduction.  You may not change this copy-
  2206. X *              right notice, and it must be included in any copy made
  2207. X */
  2208. X
  2209. #include    "tin.h"
  2210. X
  2211. extern char *glob_art_group;
  2212. extern char *glob_group;
  2213. extern int glob_respnum;
  2214. extern char *glob_page_group;
  2215. X
  2216. #ifdef SIGTSTP
  2217. int do_sigtstp = 0;
  2218. #endif
  2219. X
  2220. #ifdef POSIX_JOB_CONTROL
  2221. struct sigaction art_act;
  2222. struct sigaction group_act;
  2223. struct sigaction kill_act;
  2224. struct sigaction main_act;
  2225. struct sigaction old_act;
  2226. struct sigaction page_act;
  2227. struct sigaction rcfile_act;
  2228. struct sigaction select_act;
  2229. struct sigaction thread_act;
  2230. #endif
  2231. X
  2232. X
  2233. void set_signal_handlers ()
  2234. {
  2235. X    signal (SIGINT, signal_handler);    /* ctrl-C */
  2236. X    signal (SIGQUIT, signal_handler);    /* ctrl-\ */
  2237. X    signal (SIGILL, signal_handler);
  2238. X    signal (SIGBUS, signal_handler);
  2239. X    signal (SIGSEGV, signal_handler);
  2240. X     
  2241. X    signal (SIGPIPE, SIG_IGN);
  2242. X
  2243. #if defined(SIGTSTP) && ! defined(MINIX)
  2244. X    {
  2245. X        SIGTYPE (*ptr)();
  2246. X        ptr = signal (SIGTSTP, SIG_DFL);
  2247. X        signal (SIGTSTP, ptr);
  2248. X        if (ptr != SIG_IGN) {
  2249. X            /*
  2250. X             *  SIGTSTP is ignored when starting from shells
  2251. X             *  without job-control
  2252. X             */
  2253. X            do_sigtstp = 1; 
  2254. X            signal (SIGTSTP, main_suspend);
  2255. X        }
  2256. X    }
  2257. #endif
  2258. X
  2259. #ifdef SIGWINCH
  2260. X    signal (SIGWINCH, main_resize);
  2261. #endif
  2262. }
  2263. X
  2264. X
  2265. void signal_handler (sig)
  2266. X    int sig;
  2267. {
  2268. X    char *sigtext;
  2269. X
  2270. X    switch (sig) {
  2271. X        case SIGINT:
  2272. X            if (update) {
  2273. X                sigtext = "SIGINT ";
  2274. X            } else {
  2275. X                signal (SIGINT, signal_handler);
  2276. X                return;
  2277. X            }
  2278. X            break;
  2279. X        case SIGQUIT:
  2280. X            sigtext = "SIGQUIT ";
  2281. X            break;
  2282. X        case SIGBUS:
  2283. X            sigtext = "SIGBUS ";
  2284. X            break;
  2285. X        case SIGSEGV:
  2286. X            sigtext = "SIGSEGV ";
  2287. X            break;
  2288. X        default:
  2289. X            sigtext = "";
  2290. X            break;
  2291. X    }
  2292. X    Raw (FALSE);
  2293. X    EndWin ();
  2294. X    fprintf (stderr, "\n%s: signal handler caught signal %s(%d).\n",
  2295. X        progname, sigtext, sig);
  2296. X    if (sig != SIGINT && sig != SIGQUIT) {
  2297. SHAR_EOF
  2298. true || echo 'restore of signal.c failed'
  2299. fi
  2300. echo 'End of tin1.1 part 9'
  2301. echo 'File signal.c is continued in part 10'
  2302. echo 10 > _shar_seq_.tmp
  2303. exit 0
  2304.  
  2305. --
  2306. NAME   Iain Lea
  2307. EMAIL  iain%estevax.uucp@unido.Informatik.Uni-Dortmund.DE
  2308. SNAIL  Bruecken Strasse 12, 8500 Nuernberg 90, Germany
  2309. PHONE  +49-911-331963 (home)  +49-911-3089-407 (work)
  2310. -- 
  2311.  Dr. med. dipl.-math Dieter Becker           Tel.: (0 / +49) 6841 - 16 3046
  2312.  Medizinische Universitaets- und Poliklinik  Fax.: (0 / +49) 6841 - 16 3369
  2313.  Innere Medizin III                         
  2314.  D - 6650 Homburg / Saar                     Email: becker@med-in.uni-sb.de
  2315. exit 0 # Just in case...
  2316.