home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume31 / tin / part08 < prev    next >
Encoding:
Text File  |  1992-07-07  |  54.0 KB  |  2,338 lines

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