home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume28 / tin / part06 < prev    next >
Encoding:
Text File  |  1992-02-22  |  50.4 KB  |  2,410 lines

  1. Newsgroups: comp.sources.misc
  2. From: iain%estevax.uucp@unido.Informatik.Uni-Dortmund.DE (Iain Lea)
  3. Subject:  v28i050:  tin - threaded full screen newsreader v1.1, Part06/11
  4. Message-ID: <1992Feb18.043750.13156@sparky.imd.sterling.com>
  5. X-Md4-Signature: a6bccca19a5ebc1b81f7bd661d0be7f2
  6. Date: Tue, 18 Feb 1992 04:37:50 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 50
  11. Archive-name: tin/part06
  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.06 (part 6 of tin1.1)
  17. # do not concatenate these parts, unpack them in order with /bin/sh
  18. # file main.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" != 6; 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 main.c'
  34. else
  35. echo 'x - continuing file main.c'
  36. sed 's/^X//' << 'SHAR_EOF' >> 'main.c' &&
  37. X                update = TRUE;
  38. X                break;
  39. X
  40. X            case 'u':
  41. X                update = TRUE;
  42. X                break;
  43. X
  44. X            case 'U':
  45. X                update_fork = TRUE;
  46. X                update = TRUE;
  47. X                break;
  48. X
  49. X            case 'v':
  50. X                verbose = TRUE;
  51. X                break;
  52. X
  53. X            case 'z':
  54. X                start_any_unread = TRUE;
  55. X                update = TRUE;
  56. X                break;
  57. X
  58. X            case 'Z':
  59. X                check_any_unread = TRUE;
  60. X                update = TRUE;
  61. X                break;
  62. X
  63. X            case 'h':
  64. X            case '?':
  65. X            default:
  66. X                usage (progname);
  67. X                exit (1);
  68. X        }
  69. X    }
  70. X
  71. X    if (! update) {
  72. X        printf ("%s\n", cvers);
  73. X        fflush (stdout);
  74. X    }
  75. X
  76. X    hash_init ();
  77. X    for (i = 0; i < TABLE_SIZE; i++) {
  78. X        group_hash[i] = -1;
  79. X    }
  80. X
  81. X    nntp_startup ();                /* if -r connect to nntp server */
  82. X    created = read_active ();        /* load the active file into active[] */
  83. X
  84. X    if (optind < argc) {
  85. X        while (optind < argc) {
  86. X            if (add_group (argv[optind], TRUE) < 0) {
  87. X                error_message (txt_not_in_active_file, argv[optind]);
  88. X            }
  89. X            optind++;
  90. X        }
  91. X    } else {
  92. X        backup_newsrc ();
  93. X        read_newsrc (TRUE);
  94. X        mark_unthreaded_groups ();
  95. X    }
  96. X
  97. X    if (kill_articles) {        /* read in users kill file */
  98. X        read_kill_file ();
  99. X    }
  100. X    
  101. X    /*
  102. X     *  log name of user and start time to central logfile
  103. X     */
  104. X    log_user ();
  105. X
  106. X    /*
  107. X     *  check/start if any new/unread articles
  108. X     */
  109. X    start_groupnum = check_for_any_new_news (check_any_unread, start_any_unread);
  110. X
  111. X    /*
  112. X     *  mail any new articles to specified user
  113. X     *  or
  114. X     *  save any new articles to savedir structure for later reading
  115. X     */
  116. X    save_or_mail_new_news ();
  117. X    
  118. X    /*
  119. X     *  update index files
  120. X     */
  121. X    update_index_files ();
  122. X    
  123. X    if (! InitScreen ()) {
  124. X        error_message (txt_screen_init_failed, progname);
  125. X        exit (1);
  126. X    }
  127. X
  128. X    cmd_line = FALSE;
  129. X    ScreenSize (&LINES, &COLS);        /* screen size from termcap entry */
  130. X    Raw (TRUE);
  131. X
  132. X    set_win_size (&LINES, &COLS);    /* screen size doing ioctl() call */
  133. X
  134. X    if (notify_new_groups && ! created) {    /* check for new groups */
  135. X        notify_groups ();
  136. X    }
  137. X
  138. X    if (created_rcdir && update == FALSE) {
  139. X        show_intro_page (FALSE);        
  140. X    }
  141. X    
  142. #ifdef READ_CHAR_HACK
  143. X    setbuf (stdin, 0);
  144. #endif
  145. X
  146. X    selection_index (start_groupnum);
  147. X
  148. X    tin_done (0);
  149. }
  150. X
  151. /*
  152. X * usage
  153. X */
  154. X
  155. void usage (progname)
  156. X    char *progname;
  157. {
  158. X    error_message ("%s A threaded Netnews reader.\n", cvers);
  159. X    error_message ("Usage: %s [options] [newsgroups]", progname);
  160. X    error_message ("  -c       mark all news as read in subscribed newsgroups (batch mode)", (char *) 0);
  161. X    error_message ("  -d dir   directory to use when saving news [default=%s]", savedir);
  162. X    error_message ("  -f file  subscribed to newsgroups file [default=%s]", newsrc);
  163. X    error_message ("  -h       help", (char *) 0);
  164. X    error_message ("  -H       help information about %s", progname);
  165. X    error_message ("  -m dir   mailbox directory [default=%s]", maildir);
  166. X    error_message ("  -M user  mail new news to specified user (batch mode)", (char *) 0);
  167. X    error_message ("  -n       notify user if any new newsgroups were created since last session", (char *) 0);
  168. X    error_message ("  -p file  print program with options [default=%s]", DEFAULT_PRINTER);
  169. X    error_message ("  -r       read news remotely from default NNTP server", (char *) 0);
  170. X    error_message ("  -R       read news saved by -S option (not yet implemented)", (char *) 0);
  171. X    error_message ("  -s dir   spool directory [default=%s]", SPOOLDIR);
  172. X    error_message ("  -S       save new news for later reading (batch mode)", (char *) 0);
  173. X    error_message ("  -u       update index files (batch mode)", (char *) 0);
  174. X    error_message ("  -U       update index files in the background while reading news", (char *) 0);
  175. X    error_message ("  -v       verbose output for -c -M -S -u and -Z options (batch mode)", (char *) 0);
  176. X    error_message ("  -z       start if any unread news", (char *) 0);
  177. X    error_message ("  -Z       return status indicating if any unread news (batch mode)", (char *) 0);
  178. X    error_message ("\nMail bug reports/comments to %s", BUG_REPORT_ADDRESS);
  179. }
  180. X
  181. /*
  182. X *  check/start if any new/unread articles
  183. X */
  184. X
  185. int check_for_any_new_news (check_any_unread, start_any_unread)
  186. X    int check_any_unread;
  187. X    int start_any_unread;
  188. {
  189. X    int i;
  190. X    
  191. X    if (check_any_unread) {
  192. X        i = check_start_save_any_news (CHECK_ANY_NEWS);
  193. X        exit (i);
  194. X    } else if (start_any_unread) {
  195. X        i = check_start_save_any_news (START_ANY_NEWS);
  196. X        if (i == -1) {        /* no new/unread news so exit */
  197. X            exit (0);
  198. X        }
  199. X        update = FALSE;
  200. X        return i;
  201. X    }
  202. }
  203. X
  204. /*
  205. X *  mail any new articles to specified user
  206. X *  or
  207. X *  save any new articles to savedir structure for later reading
  208. X */
  209. X
  210. void save_or_mail_new_news ()
  211. {
  212. X    int i;
  213. X    
  214. X    if (mail_news || save_news) {
  215. X        i = catchup;            /* set catchup to FALSE */
  216. X        catchup = FALSE;
  217. X        do_update ();
  218. X        catchup = i;            /* set catchup to previous value */
  219. X        if (mail_news) {
  220. X            check_start_save_any_news (MAIL_ANY_NEWS);
  221. X        } else {
  222. X            check_start_save_any_news (SAVE_ANY_NEWS);
  223. X        }
  224. X        tin_done (0);
  225. X    }
  226. }
  227. X
  228. /*
  229. X *  update index files
  230. X */
  231. X
  232. void update_index_files ()
  233. {
  234. X    if (update || update_fork) {
  235. X        COLS = DEFAULT_COLS;            /* set because curses has not started */ 
  236. X        if (update_fork) {
  237. X            catchup = FALSE;            /* turn off msgs when running forked */ 
  238. X            verbose = FALSE;
  239. X            if (fork () == 0) {            /* fork child to update indexes in background */
  240. X                nntp_startup ();        /* connect server if we are using nntp */
  241. X                thread_arts = FALSE;    /* stop threading to run faster */
  242. X                do_update ();
  243. X                nntp_finish ();            /* connect server if we are using nntp */
  244. X                exit (0);
  245. X            }
  246. X            update = FALSE;
  247. X        } else {
  248. X            thread_arts = FALSE;    /* stop threading to run faster */
  249. X            do_update ();
  250. X            exit (0);
  251. X        }
  252. X    }
  253. }
  254. X
  255. /*
  256. X *  display page of general info. for first time user.
  257. X */
  258. X
  259. void show_intro_page ()
  260. {
  261. X    if (cmd_line) {
  262. X        printf ("%s", cvers);     
  263. X    } else {
  264. X        ClearScreen ();
  265. X        center_line (0, TRUE, cvers);     
  266. X    }
  267. X
  268. X    printf ("\n\nWelcome to tin, a full screen threaded Netnews reader. It can read news locally\n");
  269. X    printf ("(ie. <spool>/news) or remotely (-r option) from a NNTP  (Network News Transport\n");
  270. X    printf ("Protocol) server. tin -h lists the available command line options.\n\n");
  271. X
  272. X    printf ("It has four newsreading levels,  the newsgroup selection page,  the group index\n");
  273. X    printf ("page, the thread listing page and the article viewer. Help is available at each\n");
  274. X    printf ("level by pressing the 'h' command.\n\n");
  275. X
  276. X    printf ("Move up/down by using the terminal arrow keys or 'j' and 'k'.  Use PgUp/PgDn or\n");
  277. X    printf ("Ctrl-U and Ctrl-D to page up/down. Enter a newsgroup by pressing RETURN.\n\n");
  278. X
  279. X    printf ("Articles, threads, tagged articles or articles matching a pattern can be mailed\n");
  280. X    printf ("('m' command), printed ('o' command), saved ('s' command), piped ('|' command).\n");
  281. X    printf ("Use the 'w' command  to post  a news  article,  the 'f'/'F' commands to  post a\n");
  282. X    printf ("follow-up  to  an existing  news article and the 'r'/'R' commands to  reply via\n");
  283. X    printf ("mail to an existing news articles author.  The 'M' command allows the operation\n");
  284. X    printf ("of tin to be configured via a menu.\n\n");
  285. X
  286. X    printf ("For more in depth information please read  the supplied manual page and README.\n\n");
  287. X    printf ("Please send bug reports/comments to the programs author with the 'B' command.\n");
  288. X    fflush (stdout);
  289. X
  290. X    if (! cmd_line) {
  291. X        continue_prompt ();
  292. X    }
  293. }
  294. X
  295. SHAR_EOF
  296. echo 'File main.c is complete' &&
  297. chmod 0600 main.c ||
  298. echo 'restore of main.c failed'
  299. Wc_c="`wc -c < 'main.c'`"
  300. test 11249 -eq "$Wc_c" ||
  301.     echo 'main.c: original size 11249, current size' "$Wc_c"
  302. rm -f _shar_wnt_.tmp
  303. fi
  304. # ============= memory.c ==============
  305. if test -f 'memory.c' -a X"$1" != X"-c"; then
  306.     echo 'x - skipping memory.c (File already exists)'
  307.     rm -f _shar_wnt_.tmp
  308. else
  309. > _shar_wnt_.tmp
  310. echo 'x - extracting memory.c (Text)'
  311. sed 's/^X//' << 'SHAR_EOF' > 'memory.c' &&
  312. /*
  313. X *  Project   : tin - a threaded Netnews reader
  314. X *  Module    : memory.c
  315. X *  Author    : R.Skrenta / I.Lea
  316. X *  Created   : 01-04-91
  317. X *  Updated   : 04-11-91
  318. X *  Notes     :
  319. X *  Copyright : (c) Copyright 1991-92 by Rich Skrenta & Iain Lea
  320. X *                You may  freely  copy or  redistribute  this software,
  321. X *              so  long as there is no profit made from its use, sale
  322. X *              trade or  reproduction.  You may not change this copy-
  323. X *              right notice, and it must be included in any copy made
  324. X */
  325. X
  326. #include    "tin.h"
  327. X
  328. int active_num = 0;
  329. int article_num = 0;
  330. int *my_group;                    /* .newsrc --> active[] */
  331. int *unread;                    /* highest art read in group */
  332. long *base;
  333. struct group_t *active;            /* active file */
  334. struct article_t *arts;
  335. X
  336. /*
  337. X *  Dynamic table management
  338. X *  These settings are memory conservative:  small initial allocations
  339. X *  and a 50% expansion on table overflow.  A fast vm system with
  340. X *  much memory might want to start with higher initial allocations
  341. X *  and a 100% expansion on overflow, especially for the arts[] array.
  342. X */
  343. X
  344. void init_alloc ()
  345. {
  346. X    if (active_num) {    /* initial alloc */
  347. X        max_active = active_num;
  348. X    } else {
  349. X        max_active = DEFAULT_ACTIVE_NUM;
  350. X    }
  351. X
  352. X    active = (struct group_t *) my_malloc ((unsigned) sizeof(*active) * max_active);
  353. X    my_group = (int *) my_malloc ((unsigned) sizeof(int) * max_active);
  354. X    unread = (int *) my_malloc ((unsigned) sizeof(int) * max_active);
  355. X
  356. X    if(article_num) {    /* initial alloc */
  357. X        max_art = article_num;
  358. X    } else {
  359. X        max_art = DEFAULT_ARTICLE_NUM;
  360. X    }
  361. X
  362. X    arts = (struct article_t *) my_malloc ((unsigned) sizeof(*arts) * max_art);
  363. X    base = (long *) my_malloc ((unsigned) sizeof(long) * max_art);
  364. X
  365. X    max_kill = DEFAULT_KILL_NUM;
  366. X    
  367. X    killf = (struct kill_t *) my_malloc ((unsigned) sizeof(*killf) * max_kill);
  368. X
  369. X    max_save = DEFAULT_SAVE_NUM;
  370. X    
  371. X    save = (struct save_t *) my_malloc ((unsigned) sizeof(*save) * max_save);
  372. X
  373. X    screen = (struct screen_t *) 0;
  374. }
  375. X
  376. X
  377. void expand_art()
  378. {
  379. X    max_art += max_art / 2;        /* increase by 50% */
  380. X
  381. X    arts = (struct article_t *) my_realloc ((char *) arts, (unsigned) sizeof(*arts) * max_art);
  382. X    base = (long *) my_realloc ((char *) base, (unsigned) sizeof(long) * max_art);
  383. }
  384. X
  385. X
  386. void free_art_array ()
  387. {
  388. X    register int i;
  389. X
  390. X    for (i=0 ; i < top ; i++) {
  391. X        arts[i].artnum = 0L;
  392. X        arts[i].thread = ART_EXPIRED;
  393. X        arts[i].inthread = FALSE;
  394. X        arts[i].unread = ART_UNREAD;
  395. X        arts[i].tagged = FALSE;
  396. X        if (arts[i].part != (char *) 0) {
  397. X            free ((char *) arts[i].part);
  398. X            arts[i].part = (char *) 0;
  399. X        }
  400. X        if (arts[i].patch != (char *) 0) {
  401. X            free ((char *) arts[i].patch);
  402. X            arts[i].patch = (char *) 0;
  403. X        }
  404. X    }
  405. }
  406. X
  407. X
  408. void expand_active()
  409. {
  410. X    max_active += max_active / 2;        /* increase by 50% */
  411. X
  412. X    active = (struct group_t *) my_realloc((char *) active,
  413. X                        (unsigned) sizeof(*active) * max_active);
  414. X    my_group = (int *) my_realloc((char *) my_group, (unsigned) sizeof(int) * max_active);
  415. X    unread = (int *) my_realloc((char *) unread, (unsigned) sizeof(int) * max_active);
  416. }
  417. X
  418. X
  419. void expand_kill()
  420. {
  421. X    max_kill += max_kill / 2;        /* increase by 50% */
  422. X
  423. X    killf = (struct kill_t *) my_realloc((char *) killf, (unsigned) sizeof(struct kill_t) * max_kill);
  424. }
  425. X
  426. X
  427. void expand_save()
  428. {
  429. X    max_save += max_save / 2;        /* increase by 50% */
  430. X
  431. X    save = (struct save_t *) my_realloc((char *) save, (unsigned) sizeof(struct save_t) * max_save);
  432. }
  433. X
  434. X
  435. void init_screen_array (allocate)
  436. X    int allocate;
  437. {
  438. X    int i;
  439. X
  440. X    if (allocate) {
  441. X        screen = (struct screen_t *) my_malloc((unsigned) sizeof(*screen) * LINES);
  442. X
  443. X        for (i=0 ; i < LINES ; i++) {
  444. X            screen[i].col = (char *) my_malloc ((unsigned) COLS+1);
  445. X        }
  446. X    } else {
  447. X        if (screen != (struct screen_t *) 0) {
  448. X            for (i=0 ; i < LINES ; i++) {
  449. X                if (screen[i].col != (char *) 0) {
  450. X                    free ((char *) screen[i].col);
  451. X                    screen[i].col = (char *) 0;
  452. X                }
  453. X            }    
  454. X
  455. X            free ((char *) screen);
  456. X            screen = (struct screen_t *) 0;
  457. X        }
  458. X    }
  459. }
  460. X
  461. X
  462. void free_all_arrays ()
  463. {
  464. X    register int i;
  465. X
  466. X    hash_reclaim ();
  467. X    
  468. X    init_screen_array (FALSE);
  469. X
  470. X    free_art_array ();
  471. X
  472. X    if (my_group != (int *) 0) {
  473. X        free ((char *) my_group);
  474. X        my_group = (int *) 0;
  475. X    }
  476. X
  477. X    if (unread != (int *) 0) {
  478. X        free ((char *) unread);
  479. X        unread = (int *) 0;
  480. X    }
  481. X
  482. X    if (base != (long *) 0) {
  483. X        free ((char *) base);
  484. X        base = (long *) 0;
  485. X    }
  486. X
  487. X    if (killf != (struct kill_t *) 0) {
  488. X        free_kill_array ();
  489. X        if (killf != (struct kill_t *) 0) {
  490. X            free ((char *) killf);
  491. X            killf = (struct kill_t *) 0;
  492. X        }
  493. X    }
  494. X
  495. X    if (save != (struct save_t *) 0) {
  496. X        free_save_array ();
  497. X        if (save != (struct save_t *) 0) {
  498. X            free ((char *) save);
  499. X            save = (struct save_t *) 0;
  500. X        }
  501. X    }
  502. X
  503. X    if (active != (struct group_t *) 0) {
  504. X        for (i=0 ; i < max_active ; i++) {
  505. X            if (active[i].name != (char *) 0) {
  506. X                free ((char *) active[i].name);
  507. X                active[i].name = (char *) 0;
  508. X            }
  509. X        }
  510. X        if (active != (struct group_t *) 0) {
  511. X            free ((char *) active);
  512. X            active = (struct group_t *) 0;
  513. X        }
  514. X    }
  515. X
  516. X    if (arts != (struct article_t *) 0) {
  517. X        free ((char *) arts);
  518. X        arts = (struct article_t *) 0;
  519. X    }
  520. }
  521. X
  522. X
  523. void free_kill_array ()
  524. {
  525. X    int i;
  526. X    
  527. X    for (i=0 ; i < kill_num ; i++) {
  528. X        if (killf[i].kill_subj != (char *) 0) {
  529. X            free ((char *) killf[i].kill_subj);
  530. X            killf[i].kill_subj = (char *) 0;
  531. X        }
  532. X        if (killf[i].kill_from != (char *) 0) {
  533. X            free ((char *) killf[i].kill_from);
  534. X            killf[i].kill_from = (char *) 0;
  535. X        }
  536. X    }
  537. }
  538. X
  539. X
  540. /*
  541. X *  reset save list array to 0 and free's all its allocated memory
  542. X */
  543. void free_save_array ()
  544. {
  545. X    int i;
  546. X    
  547. X    for (i=0 ; i < save_num ; i++) {
  548. X        if (save[i].subject != (char *) 0) {
  549. X            free ((char *) save[i].subject);
  550. X            save[i].subject = (char *) 0;
  551. X        }
  552. X        if (save[i].archive != (char *) 0) {
  553. X            free ((char *) save[i].archive);
  554. X            save[i].archive = (char *) 0;
  555. X        }
  556. X        if (save[i].dir != (char *) 0) {
  557. X            free ((char *) save[i].dir);
  558. X            save[i].dir = (char *) 0;
  559. X        }
  560. X        if (save[i].file != (char *) 0) {
  561. X            free ((char *) save[i].file);
  562. X            save[i].file = (char *) 0;
  563. X        }
  564. X        if (save[i].part != (char *) 0) {
  565. X            free ((char *) save[i].part);
  566. X            save[i].part = (char *) 0;
  567. X        }
  568. X        if (save[i].patch != (char *) 0) {
  569. X            free ((char *) save[i].patch);
  570. X            save[i].patch = (char *) 0;
  571. X        }
  572. X        save[i].index   = -1;
  573. X        save[i].saved   = FALSE;
  574. X        save[i].is_mailbox = FALSE;
  575. X    }
  576. X    
  577. X    save_num = 0;
  578. }
  579. X
  580. X
  581. char *my_malloc (size)
  582. X    unsigned size;
  583. {
  584. X    char *p;
  585. X
  586. X    if ((p = (char *) calloc (1, (int) size)) == NULL) {
  587. X        error_message (txt_out_of_memory, progname);
  588. X        exit (1);
  589. X    }
  590. X    return p;
  591. }
  592. X
  593. X
  594. char *my_realloc (p, size)
  595. X    char *p;
  596. X    unsigned size;
  597. {
  598. X    if (! p) {
  599. X        p = (char *) calloc (1, (int) size);
  600. X    } else {
  601. X        p = (char *) realloc (p, (int) size);
  602. X    }
  603. X
  604. X    if (! p) {
  605. X        error_message (txt_out_of_memory, progname);
  606. X        exit (1);
  607. X    }
  608. X    return p;
  609. }
  610. SHAR_EOF
  611. chmod 0600 memory.c ||
  612. echo 'restore of memory.c failed'
  613. Wc_c="`wc -c < 'memory.c'`"
  614. test 6571 -eq "$Wc_c" ||
  615.     echo 'memory.c: original size 6571, current size' "$Wc_c"
  616. rm -f _shar_wnt_.tmp
  617. fi
  618. # ============= misc.c ==============
  619. if test -f 'misc.c' -a X"$1" != X"-c"; then
  620.     echo 'x - skipping misc.c (File already exists)'
  621.     rm -f _shar_wnt_.tmp
  622. else
  623. > _shar_wnt_.tmp
  624. echo 'x - extracting misc.c (Text)'
  625. sed 's/^X//' << 'SHAR_EOF' > 'misc.c' &&
  626. /*
  627. X *  Project   : tin - a threaded Netnews reader
  628. X *  Module    : misc.c
  629. X *  Author    : R.Skrenta / I.Lea
  630. X *  Created   : 01-04-91
  631. X *  Updated   : 15-12-91
  632. X *  Notes     :
  633. X *  Copyright : (c) Copyright 1991-92 by Rich Skrenta & Iain Lea
  634. X *                You may  freely  copy or  redistribute  this software,
  635. X *              so  long as there is no profit made from its use, sale
  636. X *              trade or  reproduction.  You may not change this copy-
  637. X *              right notice, and it must be included in any copy made
  638. X */
  639. X
  640. #include    "tin.h"
  641. X
  642. static char *mailbox_name = (char *) 0;
  643. static int  mailbox_size;
  644. X
  645. X
  646. void asfail(file, line, cond)
  647. X    char    *file;
  648. X    int    line;
  649. X    char    *cond;
  650. {
  651. X    fprintf(stderr, "%s: assertion failure: %s (%d): %s\n",progname,file,line,cond);
  652. X    fflush (stderr);
  653. X    exit(1);
  654. }
  655. X
  656. X
  657. void copy_fp (fp_ip, fp_op, prefix)
  658. X    FILE *fp_ip;
  659. X    FILE *fp_op;
  660. X    char *prefix;
  661. {
  662. X    extern int errno;
  663. X    char buf[8192];
  664. X
  665. X    if (prefix == (char *) 0) {
  666. X        while (fgets (buf, sizeof (buf), fp_ip) != NULL) {
  667. X            if (fprintf (fp_op, "%s", buf) == EOF) {
  668. X                sprintf (msg, "Error: fprintf() failed in copy_fp(). errno=%d", errno);
  669. X                error_message (msg, (char *) 0);
  670. X            }
  671. X        }
  672. X    } else {
  673. X        while (fgets (buf, sizeof (buf), fp_ip) != NULL) {
  674. X            if (fprintf (fp_op, "%s%s", prefix, buf) == EOF) {
  675. X                sprintf (msg, "Error: fprintf() failed in copy_fp(). errno=%d", errno);
  676. X                error_message (msg, (char *) 0);
  677. X            }
  678. X        }
  679. X    }
  680. }
  681. X
  682. X
  683. char *get_val (env, def)
  684. X    char *env;        /* Environment variable we're looking for    */
  685. X    char *def;        /* Default value if no environ value found    */
  686. {
  687. X    char *ptr;
  688. X
  689. X    if ((ptr = (char *) getenv(env)) != NULL)
  690. X        return (ptr);
  691. X    else
  692. X        return (def);
  693. }
  694. X
  695. X
  696. int invoke_editor (nam)
  697. X    char *nam;
  698. {
  699. X    char buf[LEN];
  700. X    char *my_editor;
  701. X    static char editor[LEN];
  702. X    static int first = TRUE;
  703. X
  704. X    if (first) {
  705. X        my_editor = (char *) getenv ("VISUAL");
  706. X
  707. X        strcpy (editor, my_editor != NULL ? my_editor : get_val ("EDITOR", DEFAULT_EDITOR));
  708. X        first = FALSE;
  709. X    }
  710. X
  711. #ifdef NO_START_LINE
  712. X    sprintf (buf, "%s %s", editor, nam);
  713. #else
  714. X    sprintf (buf, "%s +%d %s", editor, start_line_offset, nam);
  715. #endif
  716. X
  717. X    printf ("%s", buf);
  718. X    return invoke_cmd (buf);
  719. }
  720. X
  721. X
  722. void shell_escape ()
  723. {
  724. X    char shell[LEN];
  725. X    char *p;
  726. X
  727. #ifdef SIGTSTP
  728. X    SIGTYPE (*susp)();
  729. #endif
  730. X
  731. X    sprintf (msg, txt_shell_escape, default_shell_command);
  732. X    
  733. X    if (! prompt_string (msg, shell))
  734. X        strcpy (shell, get_val ("SHELL", DEFAULT_SHELL));
  735. X
  736. X    for (p = shell; *p && (*p == ' ' || *p == '\t'); p++)
  737. X        continue;
  738. X
  739. X    if (*p) {
  740. X        my_strncpy (default_shell_command, p, LEN);
  741. X    } else {
  742. X        if (default_shell_command[0]) {
  743. X            my_strncpy (shell, default_shell_command, LEN);
  744. X        } else {
  745. X            strcpy (shell, get_val ("SHELL", DEFAULT_SHELL));
  746. X        }
  747. X        p = shell;
  748. X    }
  749. X
  750. X    ClearScreen ();
  751. X    sprintf (msg, "Shell Command (%s)", p);
  752. X    center_line (0, TRUE, msg);
  753. X    MoveCursor (INDEX_TOP, 0);
  754. X    
  755. X    EndWin ();
  756. X    Raw (FALSE);
  757. X
  758. X    set_real_uid_gid ();
  759. X
  760. #ifdef SIGTSTP
  761. X    if (do_sigtstp)
  762. X        susp = signal (SIGTSTP, SIG_DFL);
  763. #endif
  764. X
  765. X    system (p);
  766. X
  767. #ifdef SIGTSTP
  768. X    if (do_sigtstp)
  769. X        signal (SIGTSTP, susp);
  770. #endif
  771. X
  772. X    set_tin_uid_gid ();
  773. X
  774. X    Raw (TRUE);
  775. X    InitWin ();
  776. X
  777. X    mail_setup ();
  778. X
  779. X    continue_prompt ();
  780. X
  781. X    if (draw_arrow_mark) {
  782. X        ClearScreen ();
  783. X    }
  784. }
  785. X
  786. X
  787. void tin_done (ret)
  788. X    int ret;
  789. {
  790. X    char group_path[LEN], *p;
  791. X    int ask = TRUE;
  792. X    register int i, j;
  793. X    
  794. X    /*
  795. X     * check if any groups were read & ask if they should marked read
  796. X     */
  797. X    if (catchup_read_groups) {
  798. X        for (i = 0 ; i < group_top ; i++) {
  799. X            if (active[my_group[i]].read) {
  800. X                if (ask) {
  801. X                    if (prompt_yn (LINES, "Catchup all groups entered during this session? (y/n): ", 'n')) {
  802. X                        ask = FALSE;
  803. X                        thread_arts = FALSE;    /* speeds up index loading */
  804. X                    } else {
  805. X                        break;
  806. X                    }
  807. X                }
  808. X                sprintf (msg, "Catchup %s...", active[my_group[i]].name);
  809. X                wait_message (msg);
  810. X                strcpy (group_path, active[my_group[i]].name);
  811. X                for (p = group_path; *p; p++) {
  812. X                    if (*p == '.') {
  813. X                        *p = '/';
  814. X                    }
  815. X                }
  816. X                index_group (active[my_group[i]].name, group_path);
  817. X                for (j = 0; j < top; j++) {
  818. X                    arts[j].unread = ART_READ;
  819. X                }
  820. X                update_newsrc (active[my_group[i]].name, my_group[i], FALSE);
  821. X            }
  822. X        }
  823. X    }
  824. X    nntp_finish ();            /* disconnect from NNTP server */
  825. X    free_all_arrays ();        /* deallocate all arrays */
  826. X    ClearScreen ();
  827. X    EndWin ();
  828. X    Raw (FALSE);
  829. X    exit (ret);
  830. }
  831. X
  832. /*
  833. X *  Load the active file into active[] and create copy of active ~/.tin/active
  834. X */
  835. X
  836. int read_active ()
  837. {
  838. X    FILE *fp;
  839. X    char *p, *q, *r;
  840. X    char buf[LEN];
  841. X    char moderated;
  842. X    int created, i;
  843. X    long h;
  844. X    
  845. X    num_active = 0;
  846. X
  847. X    if ((fp = open_active_fp ()) == NULL) {
  848. X        if (compiled_with_nntp) {
  849. X            printf ("Cannot open %s. Try %s -r to read news via NNTP.\n",
  850. X                active_file, progname);
  851. X        } else {
  852. X            printf (txt_cannot_open, active_file);
  853. X            putchar ('\n');
  854. X        }
  855. X        fflush (stdout);
  856. X        exit (1);
  857. X    }
  858. X
  859. X    if (read_news_via_nntp && update == FALSE) {
  860. X        wait_message (txt_reading_active_file);
  861. X    }
  862. X    
  863. X    while (fgets (buf, sizeof (buf), fp) != NULL) {
  864. X        for (p = buf; *p && *p != ' '; p++)
  865. X            continue;
  866. X        if (*p != ' ') {
  867. X            error_message (txt_bad_active_file, buf);
  868. X            continue;
  869. X        }
  870. X        *p++ = '\0';
  871. X
  872. X        if (num_active >= max_active)
  873. X            expand_active ();
  874. X
  875. X        h = hash_groupname (buf);
  876. X
  877. X        if (group_hash[h] == -1) {
  878. X            group_hash[h] = num_active;
  879. X        } else {                /* hash linked list chaining */
  880. X            for (i=group_hash[h]; active[i].next >= 0; i=active[i].next) {
  881. X                if (strcmp(active[i].name, buf) == 0) {
  882. X                    goto read_active_continue;        /* kill dups */
  883. X                }
  884. X            }
  885. X            if (strcmp(active[i].name, buf) == 0)
  886. X                goto read_active_continue;
  887. X            active[i].next = num_active;
  888. X        }
  889. X
  890. X        for (q = p; *q && *q != ' '; q++)
  891. X            continue;
  892. X        if (*q != ' ') {
  893. X            error_message (txt_bad_active_file, buf);
  894. X            continue;
  895. X        }
  896. X        *q++ = '\0';
  897. X
  898. X        for (r = q; *r && *r != '\n'; r++) {
  899. X            if (*r == 'y' || *r == 'm') {
  900. X                moderated = *r;
  901. X                break;
  902. X            }
  903. X        }
  904. X
  905. X        active[num_active].name = str_dup (buf);
  906. X        active[num_active].max = (long) atol (p);
  907. X        active[num_active].min = (long) atol (q);
  908. X        active[num_active].moderated = moderated;
  909. X        active[num_active].next = -1;            /* hash chaining */
  910. X        active[num_active].flag = UNSUBSCRIBED;    /* not in my_group[] yet */
  911. X        active[num_active].read = FALSE;        /* read/unread */
  912. X        active[num_active].thread = TRUE;        /* thread articles */
  913. X
  914. X        num_active++;
  915. X
  916. read_active_continue:;
  917. X
  918. X    }
  919. X    fclose (fp);
  920. X
  921. X    /*
  922. X     *  exit if active file is empty
  923. X     */
  924. X    if (! num_active) {
  925. X        error_message ("%s contains no newsgroups. Exiting.", active_file);
  926. X        exit (1);
  927. X    }
  928. X
  929. X    /*
  930. X     *  create backup of LIBDIR/active for use by -n option to notify new groups 
  931. X     */
  932. X    created = backup_active (TRUE);
  933. X
  934. X    debug_print_active ();
  935. X
  936. X    return (created);
  937. }
  938. X
  939. /*
  940. X *  Mark any groups in my_group[] that are in ~/.tin/unthread so they
  941. X *  will not be threaded
  942. X */
  943. void mark_unthreaded_groups ()
  944. {
  945. X    FILE *fp;
  946. X    char buf[LEN];
  947. X    int i;
  948. X    long h;
  949. X
  950. X    set_real_uid_gid ();
  951. X    
  952. X    if ((fp = fopen (unthreadfile, "r")) == NULL) {
  953. X        error_message (txt_cannot_open, unthreadfile);
  954. X        set_tin_uid_gid ();
  955. X        return;
  956. X    }
  957. X
  958. X    while (fgets (buf, sizeof (buf), fp) != NULL) {
  959. X        buf[strlen (buf)-1] = '\0'; 
  960. X        h = hash_groupname (buf);
  961. X
  962. X        if (debug) {
  963. X            printf ("Unthreading %s...\n", buf);
  964. X        }
  965. X
  966. X        if ((i = group_hash[h]) >= 0) {
  967. X            active[i].thread = FALSE;
  968. X        } else {
  969. X            for (i=group_hash[h]; active[i].next >= 0; i=active[i].next) {
  970. X                if (strcmp (active[i].name, buf) == 0) {
  971. X                    active[i].thread = FALSE;
  972. X                    break;
  973. X                }
  974. X            }
  975. X        }
  976. X    }
  977. X    fclose (fp);
  978. X    set_tin_uid_gid ();
  979. }
  980. X
  981. /*
  982. X *  create ~/.tin/active from LIBDIR/active if it does not exist 
  983. X */
  984. X
  985. int backup_active (create)
  986. X    int create;
  987. {
  988. X    char buf[LEN];
  989. X    FILE *fp;
  990. X    int created = FALSE;
  991. X    int i;
  992. X    struct stat sb;
  993. X    
  994. X    set_real_uid_gid ();
  995. X    
  996. X    sprintf (buf, "%s/active", rcdir);
  997. X    
  998. X    if (create) {
  999. X        if (stat (buf, &sb) != -1) {
  1000. X            goto backup_active_done;
  1001. X        }
  1002. X    }
  1003. X    
  1004. X    if ((fp = fopen (buf, "w")) != NULL) {
  1005. X        for (i = 0; i < num_active ; i++) {    /* for each group */
  1006. X            fprintf (fp, "%s\n", active[i].name);
  1007. X        }
  1008. X        fclose (fp);
  1009. X        chmod (buf, 0644);
  1010. X        created = TRUE;
  1011. X    }
  1012. X
  1013. backup_active_done:
  1014. X    set_tin_uid_gid ();
  1015. X    return (created);
  1016. }
  1017. X
  1018. X
  1019. #ifdef USE_MKDIR
  1020. mkdir (path, mode)
  1021. X    char *path;
  1022. X    int mode;
  1023. {
  1024. X    char buf[LEN];
  1025. X    struct stat sb;
  1026. X
  1027. X    sprintf(buf, "mkdir %s", path);
  1028. X    if (stat (path, &sb) == -1) {
  1029. X        system (buf);
  1030. X        chmod (path, mode);
  1031. X    }
  1032. }
  1033. #endif
  1034. X
  1035. X
  1036. long hash_groupname (buf)        /* hash group name for fast lookup later */
  1037. X    char *buf;
  1038. {
  1039. X    unsigned long h;
  1040. X    unsigned char *t = (unsigned char *) buf;
  1041. X
  1042. X    h = *t++;
  1043. X    while (*t)
  1044. X        h = ((h << 1) ^ *t++) % TABLE_SIZE;
  1045. X
  1046. X    return h;
  1047. }
  1048. X
  1049. X
  1050. void rename_file (old_filename, new_filename)
  1051. X    char *old_filename;
  1052. X    char *new_filename;
  1053. {    
  1054. X    char buf[LEN];
  1055. X    
  1056. X    unlink (new_filename);
  1057. X    if (link (old_filename, new_filename) == 1) {
  1058. X        sprintf (buf, txt_rename_error, old_filename, new_filename);
  1059. X        error_message (buf, "TWO");
  1060. X        return;
  1061. X    }
  1062. X    if (unlink (old_filename) == -1) {
  1063. X        sprintf (buf, txt_rename_error, old_filename, new_filename);
  1064. X        error_message (buf, "THREE");
  1065. X        return;
  1066. X    }
  1067. }
  1068. X
  1069. X
  1070. char *str_dup (str)
  1071. X    char *str;
  1072. {
  1073. X    char *dup = (char *) 0;
  1074. X
  1075. X    assert (str != (char *) 0);
  1076. X    
  1077. X    if (str) {
  1078. X        dup = my_malloc (strlen (str)+1);
  1079. X        strcpy (dup, str);
  1080. X    }
  1081. X    return dup;
  1082. }
  1083. X
  1084. X
  1085. int invoke_cmd (nam)
  1086. X    char *nam;
  1087. {
  1088. X    int ret;
  1089. X
  1090. #ifdef SIGTSTP
  1091. X    SIGTYPE (*susp)();
  1092. #endif
  1093. X
  1094. X    EndWin ();
  1095. X    Raw (FALSE);
  1096. X    set_real_uid_gid ();
  1097. X
  1098. #ifdef SIGTSTP
  1099. X    if (do_sigtstp)
  1100. X        susp = signal(SIGTSTP, SIG_DFL);
  1101. #endif
  1102. X
  1103. X    ret = system (nam);
  1104. X
  1105. #ifdef SIGTSTP
  1106. X    if (do_sigtstp)
  1107. X        signal (SIGTSTP, susp);
  1108. #endif
  1109. X
  1110. X    set_tin_uid_gid ();
  1111. X
  1112. X    Raw (TRUE);
  1113. X    InitWin ();
  1114. X
  1115. X    return ret == 0;
  1116. }
  1117. X
  1118. X
  1119. void draw_percent_mark (cur_num, max_num)
  1120. X    int cur_num;
  1121. X    int max_num;
  1122. {
  1123. X    char buf[32];
  1124. X    int percent = 0;
  1125. X
  1126. X    if (NOTESLINES <= 0) {
  1127. X        return;
  1128. X    }
  1129. X
  1130. X    if (cur_num <= 0 && max_num <= 0) {
  1131. X        return;
  1132. X    }
  1133. X        
  1134. X    percent = cur_num * 100 / max_num;
  1135. X    sprintf (buf, "%s(%d%%) [%d/%d]", txt_more, percent, cur_num, max_num);
  1136. X    MoveCursor (LINES, (COLS - (int) strlen (buf))-(1+BLANK_PAGE_COLS));
  1137. X    StartInverse ();    
  1138. X    printf ("%s", buf);
  1139. X    fflush (stdout);
  1140. X    EndInverse ();
  1141. }
  1142. X
  1143. X
  1144. void set_real_uid_gid ()
  1145. {
  1146. #if defined(BSD) && ! defined(SINIX)
  1147. X    if (setreuid (tin_uid, real_uid) == -1) {
  1148. X        error_message ("Error setreuid(real) failed", (char *) 0);
  1149. X    }
  1150. X    if (setregid (tin_gid, real_gid) == -1) {
  1151. X        error_message ("Error setregid(real) failed", (char *) 0);
  1152. X    }
  1153. #else
  1154. X    if (setuid (real_uid) == -1) {
  1155. X        error_message ("Error setuid(real) failed", (char *) 0);
  1156. X    }
  1157. X    if (setgid (real_gid) == -1) {
  1158. X        error_message ("Error setgid(real) failed", (char *) 0);
  1159. X    }
  1160. #endif
  1161. }
  1162. X
  1163. X
  1164. void set_tin_uid_gid ()
  1165. {
  1166. #if defined(BSD) && ! defined(SINIX)
  1167. X    if (setreuid (real_uid, tin_uid) == -1) {
  1168. X        error_message ("Error setreuid(tin) failed", (char *) 0);
  1169. X    }
  1170. X    if (setregid (real_gid, tin_gid) == -1) {
  1171. X        error_message ("Error setregid(tin) failed", (char *) 0);
  1172. X    }
  1173. #else
  1174. X    if (setuid (tin_uid) == -1) {
  1175. X        error_message ("Error setuid(tin) failed", (char *) 0);
  1176. X    }
  1177. X    if (setgid (tin_gid) == -1) {
  1178. X        error_message ("Error setgid(tin) failed", (char *) 0);
  1179. X    }
  1180. #endif
  1181. }
  1182. X
  1183. X
  1184. void notify_groups ()
  1185. {
  1186. X    char buf[LEN];
  1187. X    FILE *fp;
  1188. X    int group_not_found;
  1189. X    int i, j, index;
  1190. X    int num = 0;
  1191. X    int update_old_active = FALSE;
  1192. X    struct notify_t {
  1193. X        char name[LEN];
  1194. X        int len;
  1195. X    } *old_active;
  1196. X    
  1197. X    set_real_uid_gid ();
  1198. X    
  1199. X    sprintf (buf, "%s/active", rcdir);
  1200. X    
  1201. X    if ((fp = fopen (buf, "r")) == NULL) {
  1202. X        error_message (txt_cannot_open, buf);
  1203. X        goto notify_groups_done;
  1204. X    }
  1205. X
  1206. X    Raw (FALSE);
  1207. X    
  1208. X    printf ("Checking active list for new newsgroups...");
  1209. X    fflush (stdout);
  1210. X    
  1211. X    old_active = (struct notify_t *) my_malloc ((unsigned) sizeof (struct notify_t) * num_active);
  1212. X    if (old_active == (struct notify_t *) 0) {
  1213. X        error_message (txt_out_of_memory, progname);
  1214. X        goto notify_groups_done;
  1215. X    }
  1216. X    
  1217. X    while (fgets (old_active[num].name, sizeof (old_active[num].name), fp) != NULL) {
  1218. X        old_active[num].len = strlen (old_active[num].name)-1;
  1219. X        old_active[num].name[old_active[num].len] = '\0';
  1220. X        num++;
  1221. X        if (num == num_active) {
  1222. X            break;
  1223. X        }
  1224. X    }
  1225. X
  1226. X    for (i = 0 ; i < num_active ; i++) {    
  1227. X        group_not_found = TRUE;
  1228. X        for (j=0; j < num ; j++) {
  1229. X            if (strncmp (old_active[j].name, active[i].name, old_active[j].len) == 0) {
  1230. X                group_not_found = FALSE;        /* found it so read in next group */
  1231. X                break;
  1232. X            }
  1233. X        }
  1234. X
  1235. X        if (group_not_found) {
  1236. /*
  1237. && strlen (active[i].name) == old_active[j].len) {
  1238. */
  1239. X            update_old_active = TRUE;
  1240. X            printf ("\r\nSubscribe to %s (y/n): ", active[i].name);
  1241. X            fflush (stdout);
  1242. X            scanf ("%s", buf);
  1243. X            if (buf[0] == 'y') {
  1244. X                index = add_group (active[i].name, TRUE);
  1245. X                subscribe (active[my_group[index]].name, ':',
  1246. X                    my_group[index], FALSE);
  1247. X            }
  1248. X            printf ("Checking...");
  1249. X            fflush (stdout);
  1250. X        }
  1251. X    }
  1252. X    fclose (fp);
  1253. X
  1254. X    if (old_active != (struct notify_t *) 0) {
  1255. X        free ((char *) old_active);
  1256. X        old_active = (struct notify_t *) 0;
  1257. X    }
  1258. X
  1259. X    Raw (TRUE);
  1260. X
  1261. X    /*
  1262. X     *  write active[] to ~/.tin/active
  1263. X     */
  1264. X    if (update_old_active) {
  1265. X        backup_active (FALSE);
  1266. X    }
  1267. X
  1268. notify_groups_done:
  1269. X    set_tin_uid_gid ();
  1270. }
  1271. X
  1272. X
  1273. void basename (dirname, program)
  1274. X    char *dirname;        /* argv[0] */
  1275. X    char *program;        /* progname is returned */
  1276. {
  1277. X    int i;
  1278. X    
  1279. X    strcpy (program, dirname);
  1280. X    
  1281. X    for (i=(int) strlen (dirname)-1 ; i ; i--) {
  1282. X        if (dirname[i] == '/') {
  1283. X            strcpy (program, dirname+(i+1));
  1284. X            break;
  1285. X        }
  1286. X    }
  1287. }
  1288. X
  1289. X
  1290. /*
  1291. X *  Record size of mailbox so we can detect if new mail has arrived
  1292. X */
  1293. X
  1294. void mail_setup ()
  1295. {
  1296. X    struct stat buf;
  1297. X
  1298. X    mailbox_name = get_val ("MAIL", mailbox);
  1299. X
  1300. X    if (stat (mailbox_name, &buf) >= 0) {
  1301. X        mailbox_size = buf.st_size;
  1302. X    } else {
  1303. X        mailbox_size = 0;
  1304. X    }
  1305. }
  1306. X
  1307. /*
  1308. X *  Return TRUE if new mail has arrived
  1309. X */
  1310. X
  1311. int mail_check ()
  1312. {
  1313. X    struct stat buf;
  1314. X
  1315. X    if (mailbox_name != (char *) 0 &&
  1316. X        stat(mailbox_name, &buf) >= 0 &&
  1317. X        mailbox_size < buf.st_size) {
  1318. X        return TRUE;
  1319. X    }
  1320. X
  1321. X    return FALSE;
  1322. }
  1323. X
  1324. /*
  1325. X *  Parse various From: lines into the component mail addresses and
  1326. X *  real names
  1327. X */
  1328. X
  1329. void parse_from (str, addr, name)
  1330. X    char *str;
  1331. X    char *addr;
  1332. X    char *name;
  1333. {
  1334. X    register int c;
  1335. X    register char *cp, *ncp;
  1336. X    int gotlt, lastsp, level;
  1337. X
  1338. X    gotlt = 0;
  1339. X    lastsp = 0;
  1340. X    cp = addr;
  1341. X    ncp = name;
  1342. X    while (*str == ' ')
  1343. X        ++str;
  1344. X    while (c = *str++)
  1345. X        switch (c) {
  1346. X        case '(':
  1347. X            ncp = name;
  1348. X            level = 1;
  1349. X            while (*str != '\0' && level) {
  1350. X                switch (c = *str++) {
  1351. X                case '(':
  1352. X                    *ncp++ = c;
  1353. X                    level++;
  1354. X                    break;
  1355. X                case ')':
  1356. X                    level--;
  1357. X                    if (level > 0)
  1358. X                        *ncp++ = c;
  1359. X                    break;
  1360. X                default:
  1361. X                    *ncp++ = c;
  1362. X                    break;
  1363. X                }
  1364. X            }
  1365. X            if (*str)
  1366. X                str++;
  1367. X            lastsp = 0;
  1368. X            break;
  1369. X        case ' ':
  1370. X            if (str[0] == 'a' && str[1] == 't' && str[2] == ' ')
  1371. X                str += 3, *cp++ = '@';
  1372. X            else if (str[0] == '@' && str[1] == ' ')
  1373. X                str += 2, *cp++ = '@';
  1374. X            else
  1375. X                lastsp = 1;
  1376. X            if (ncp > name)
  1377. X                *ncp++ = ' ';
  1378. X            break;
  1379. X        case '<':
  1380. X            cp = addr;
  1381. X            gotlt++;
  1382. X            lastsp = 0;
  1383. X            break;
  1384. X        case '>':
  1385. X            if (gotlt)
  1386. X                goto done;
  1387. X            /* FALL THROUGH CASE */
  1388. X        default:
  1389. X            if (lastsp) {
  1390. X                lastsp = 0;
  1391. X                *cp++ = ' ';
  1392. X            }
  1393. X            *cp++ = c;
  1394. X            if (! gotlt)
  1395. X                *ncp++ = c;
  1396. X            break;
  1397. X        }
  1398. done:
  1399. X    *cp = 0;
  1400. X    while (ncp>name && ncp[-1]==' ')
  1401. X        --ncp;
  1402. X    *ncp = 0;
  1403. X    if (*addr == '@') {
  1404. X        char buf [512];
  1405. X
  1406. X        strcpy (buf, addr);
  1407. X        strcpy (addr, "root");
  1408. X        strcat (addr, buf);
  1409. X    }
  1410. }
  1411. X
  1412. /*
  1413. X *  Convert a string to a long, only look at first n characters
  1414. X */
  1415. X
  1416. long my_atol (s, n)
  1417. X    char *s;
  1418. X    int n;
  1419. {
  1420. X    long ret = 0;
  1421. X
  1422. X    while (*s && n--) {
  1423. X        if (*s >= '0' && *s <= '9')
  1424. X            ret = ret * 10 + (*s - '0');
  1425. X        else
  1426. X            return -1;
  1427. X        s++;
  1428. X    }
  1429. X
  1430. X    return ret;
  1431. }
  1432. X
  1433. /*
  1434. X *  Return a pointer into s eliminating any leading Re:'s.  Example:
  1435. X *
  1436. X *      Re: Reorganization of misc.jobs
  1437. X *      ^   ^
  1438. X */
  1439. X
  1440. char *eat_re (s)
  1441. X    char *s;
  1442. {
  1443. X
  1444. X    while (*s == 'r' || *s == 'R') {
  1445. X        if ((*(s+1) == 'e' || *(s+1) == 'E')) {
  1446. X            if (*(s+2) == ':')
  1447. X                s += 3;
  1448. X            else if (*(s+2) == '^' && isdigit(*(s+3)) && *(s+4) == ':')
  1449. X                s += 5;            /* hurray nn */
  1450. X            else
  1451. X                break;
  1452. X        } else
  1453. X            break;
  1454. X        while (*s == ' ')
  1455. X            s++;
  1456. X    }
  1457. X
  1458. X    return s;
  1459. }
  1460. X
  1461. /*
  1462. X *  Hash the subjects (after eating the Re's off) for a quicker
  1463. X *  thread search later.  We store the hashes for subjects in the
  1464. X *  index file for speed.
  1465. X */
  1466. X
  1467. long hash_s (s)
  1468. X    char *s;
  1469. {
  1470. X    long h = 0;
  1471. X    unsigned char *t = (unsigned char *) s;
  1472. X
  1473. X    while (*t)
  1474. X        h = h * 64 + *t++;
  1475. X
  1476. X    return h;
  1477. }
  1478. X
  1479. /*
  1480. X *  strncpy that stops at a newline and null terminates
  1481. X */
  1482. X
  1483. void my_strncpy(p, q, n)
  1484. X    char *p;
  1485. X    char *q;
  1486. X    int n;
  1487. {
  1488. X    while (n--) {
  1489. X        if (! *q || *q == '\n')
  1490. X            break;
  1491. X        *p++ = *q++;
  1492. X    }
  1493. X    *p = '\0';
  1494. }
  1495. X
  1496. X
  1497. int untag_all_articles ()
  1498. {
  1499. X    int untagged = FALSE;
  1500. X    register int i;
  1501. X
  1502. X    for (i=0 ; i < top ; i++) {
  1503. X        if (arts[i].tagged) {
  1504. X            arts[i].tagged = FALSE;
  1505. X            untagged = TRUE;
  1506. X        }
  1507. X    }
  1508. X    num_of_tagged_files = 0;
  1509. X
  1510. X    return (untagged);
  1511. }
  1512. X
  1513. X
  1514. /*
  1515. X * ANSI C strstr () - Uses Boyer-Moore algorithm. Downloaded from net.
  1516. X */
  1517. char *str_str (text, pattern, patlen)
  1518. X    char *text;
  1519. X    char *pattern;
  1520. X    int patlen;
  1521. {
  1522. X    register unsigned char *p, *t;
  1523. X    register int i, p1, j, *delta;
  1524. X    int deltaspace[256];
  1525. X    int textlen;
  1526. X
  1527. X    textlen = strlen (text);
  1528. X
  1529. X    /* algorithm fails if pattern is empty */
  1530. X    if ((p1 = patlen) == 0)
  1531. X        return (text);
  1532. X
  1533. X    /* code below fails (whenever i is unsigned) if pattern too long */
  1534. X    if (p1 > textlen)
  1535. X        return (NULL);
  1536. X
  1537. X    /* set up deltas */
  1538. X    delta = deltaspace;
  1539. X    for (i = 0; i <= 255; i++)
  1540. X        delta[i] = p1;
  1541. X    for (p = (unsigned char *) pattern, i = p1; --i > 0;)
  1542. X        delta[*p++] = i;
  1543. X
  1544. X    /*
  1545. X     * From now on, we want patlen - 1.
  1546. X     * In the loop below, p points to the end of the pattern,
  1547. X     * t points to the end of the text to be tested against the
  1548. X     * pattern, and i counts the amount of text remaining, not
  1549. X     * including the part to be tested.
  1550. X     */
  1551. X    p1--;
  1552. X    p = (unsigned char *) pattern + p1;
  1553. X    t = (unsigned char *) text + p1;
  1554. X    i = textlen - patlen;
  1555. X    for (;;) {
  1556. X        if (*p == *t && memcmp((p - p1), (t - p1), p1) == 0)
  1557. X            return ((char *)t - p1);
  1558. X        j = delta[*t];
  1559. X        if (i < j)
  1560. X            break;
  1561. X        i -= j;
  1562. X        t += j;
  1563. X    }
  1564. X    return (NULL);
  1565. }
  1566. X
  1567. X
  1568. void get_author (thread, respnum, str)
  1569. X    int thread;
  1570. X    int respnum;
  1571. X    char *str;
  1572. {    
  1573. X    extern int threaded_on_subject;
  1574. X    int author;
  1575. X    int len_from = max_from;
  1576. X    
  1577. X    if (thread) {
  1578. X        if (threaded_on_subject) {
  1579. X            len_from = max_subj+max_from;
  1580. X        } else {
  1581. X            len_from = max_from;
  1582. X        }
  1583. X        author = SHOW_FROM_BOTH;
  1584. X    } else {
  1585. X        author = show_author;
  1586. X    }
  1587. X
  1588. X    switch (author) {
  1589. X        case SHOW_FROM_ADDR:
  1590. X            my_strncpy (str, arts[respnum].from, len_from);
  1591. X            break;
  1592. X        case SHOW_FROM_NAME:
  1593. X            my_strncpy (str, arts[respnum].name, len_from);
  1594. X            break;
  1595. X        case SHOW_FROM_BOTH:
  1596. X            if (arts[respnum].name != arts[respnum].from) { 
  1597. X                sprintf (msg, "%s (%s)", arts[respnum].name, arts[respnum].from);
  1598. X                my_strncpy (str, msg, len_from);
  1599. X            } else { 
  1600. X                my_strncpy (str, arts[respnum].from, len_from);
  1601. X            }
  1602. X            break;
  1603. X    }
  1604. }
  1605. X
  1606. X
  1607. void toggle_inverse_video ()
  1608. {
  1609. X    inverse_okay = !inverse_okay;
  1610. X    if (inverse_okay) {
  1611. #ifndef USE_INVERSE_HACK    
  1612. X        draw_arrow_mark = FALSE;
  1613. #endif        
  1614. X        info_message (txt_inverse_on);
  1615. X    } else {
  1616. X        draw_arrow_mark = TRUE;
  1617. X        info_message (txt_inverse_off);
  1618. X    }
  1619. }
  1620. X
  1621. X
  1622. int get_arrow_key ()
  1623. {
  1624. X    int ch;
  1625. X    
  1626. X    ch = ReadCh ();
  1627. X    if (ch == '[' || ch == 'O')
  1628. X        ch = ReadCh();
  1629. X    switch (ch) {
  1630. X        case 'A':
  1631. X        case 'D':
  1632. X        case 'i':
  1633. X            return KEYMAP_UP;
  1634. X
  1635. X        case 'B':
  1636. X        case 'C':
  1637. X            return KEYMAP_DOWN;
  1638. X
  1639. X        case 'I':        /* ansi  PgUp */
  1640. X        case 'V':        /* at386 PgUp */
  1641. X        case 'S':        /* 97801 PgUp */
  1642. X        case 'v':        /* emacs style */
  1643. X            return KEYMAP_PAGE_UP;
  1644. X
  1645. X        case 'G':        /* ansi  PgDn */
  1646. X        case 'U':        /* at386 PgDn */
  1647. X        case 'T':        /* 97801 PgDn */
  1648. X            return KEYMAP_PAGE_DOWN;
  1649. X
  1650. X        case 'H':        /* at386  Home */
  1651. X            return KEYMAP_HOME;
  1652. X                    
  1653. X        case 'F':        /* ansi  End */
  1654. X        case 'Y':        /* at386  End */
  1655. X            return KEYMAP_END;
  1656. X
  1657. X        default:
  1658. X            return KEYMAP_UNKNOWN;
  1659. X    }
  1660. }
  1661. SHAR_EOF
  1662. chmod 0600 misc.c ||
  1663. echo 'restore of misc.c failed'
  1664. Wc_c="`wc -c < 'misc.c'`"
  1665. test 19128 -eq "$Wc_c" ||
  1666.     echo 'misc.c: original size 19128, current size' "$Wc_c"
  1667. rm -f _shar_wnt_.tmp
  1668. fi
  1669. # ============= newsrc.c ==============
  1670. if test -f 'newsrc.c' -a X"$1" != X"-c"; then
  1671.     echo 'x - skipping newsrc.c (File already exists)'
  1672.     rm -f _shar_wnt_.tmp
  1673. else
  1674. > _shar_wnt_.tmp
  1675. echo 'x - extracting newsrc.c (Text)'
  1676. sed 's/^X//' << 'SHAR_EOF' > 'newsrc.c' &&
  1677. /*
  1678. X *  Project   : tin - a threaded Netnews reader
  1679. X *  Module    : newsrc.c
  1680. X *  Author    : R.Skrenta / I.Lea
  1681. X *  Created   : 01-04-91
  1682. X *  Updated   : 15-12-91
  1683. X *  Notes     :
  1684. X *  Copyright : (c) Copyright 1991-92 by Rich Skrenta & Iain Lea
  1685. X *                You may  freely  copy or  redistribute  this software,
  1686. X *              so  long as there is no profit made from its use, sale
  1687. X *              trade or  reproduction.  You may not change this copy-
  1688. X *              right notice, and it must be included in any copy made
  1689. X */
  1690. X
  1691. #include    "tin.h"
  1692. X
  1693. X
  1694. /*
  1695. X * make a backup of users .newsrc in case of the bogie man
  1696. X */
  1697. X
  1698. void backup_newsrc ()
  1699. {
  1700. X    char buf[8192];
  1701. X    FILE *fp_newsrc, *fp_backup;
  1702. X    
  1703. X    set_real_uid_gid ();
  1704. X
  1705. X    if ((fp_newsrc = fopen (newsrc, "r")) != NULL) {
  1706. X        sprintf (buf, "%s/.oldnewsrc", homedir);
  1707. X        unlink (buf);    /* because rn makes a link of .newsrc -> .oldnewsrc */
  1708. X        if ((fp_backup = fopen (buf, "w")) != NULL) {
  1709. X            while (fgets (buf, sizeof (buf), fp_newsrc) != NULL) {
  1710. X                fputs (buf, fp_backup);
  1711. X            }
  1712. X            fclose (fp_backup);
  1713. X        }
  1714. X        fclose (fp_newsrc);
  1715. X    }
  1716. X
  1717. X    set_tin_uid_gid ();
  1718. }
  1719. X
  1720. /*
  1721. X *  Read $HOME/.newsrc into my_group[]. my_group[] ints point to
  1722. X *  active[] entries.  Sub_only determines  whether we just read
  1723. X *  subscribed groups or all of them.
  1724. X */
  1725. X
  1726. void read_newsrc (sub_only)
  1727. X    int sub_only;        /* TRUE=subscribed groups only, FALSE=all groups */
  1728. {
  1729. X    char c, *p, buf[8192];
  1730. X    char old_groups[LEN];
  1731. X    FILE *fp, *fp_old;
  1732. X    int i;
  1733. X    int remove_old_groups = FALSE;
  1734. X
  1735. X    group_top = 0;
  1736. X
  1737. X    set_real_uid_gid ();
  1738. X    
  1739. X    if ((fp = fopen (newsrc, "r")) == NULL) {  /* attempt to make a .newsrc */
  1740. X        for (i = 0; i < num_active; i++) {
  1741. X            if (group_top >= max_active) {
  1742. X                expand_active ();
  1743. X            }
  1744. X            my_group[group_top] = i;
  1745. X            active[i].flag = 0;
  1746. X            unread[group_top] = -1;
  1747. X            group_top++;
  1748. X        }
  1749. X        write_newsrc ();
  1750. X        return;
  1751. X    }
  1752. X
  1753. X    sprintf (old_groups, "%s/.newsrc.%d", homedir, getpid ());
  1754. X
  1755. X    while (fgets (buf, sizeof buf, fp) != NULL) {
  1756. X        p = buf;
  1757. X        while (*p && *p != '\n' && *p != ' ' && *p != ':' && *p != '!')
  1758. X            p++;
  1759. X        c = *p;
  1760. X        *p++ = '\0';
  1761. X
  1762. X        if (c == '!' && sub_only)
  1763. X            continue;        /* unsubscribed */
  1764. X
  1765. #ifdef XXX
  1766. X        if (strncmp ("options ", buf, 8) == 0)
  1767. X            continue;        /* options line */
  1768. #endif
  1769. X
  1770. X        if ((i = add_group (buf, FALSE)) < 0) {
  1771. X            if (! remove_old_groups) {
  1772. X                if ((fp_old = fopen (old_groups, "w")) == NULL) {
  1773. X                    error_message (txt_cannot_open, old_groups);
  1774. X                    continue;
  1775. X                }
  1776. X                remove_old_groups = TRUE;
  1777. X            }
  1778. X            fprintf (fp_old, "%s\n", buf);
  1779. X            continue;
  1780. X        }
  1781. X
  1782. X        if (c != '!')        /* if we're subscribed to it */
  1783. X            active[my_group[i]].flag |= SUBSCRIBED;
  1784. X
  1785. X        unread[i] = parse_unread (p, my_group[i]);
  1786. X    }
  1787. X    fclose (fp);
  1788. X
  1789. X    /*
  1790. X     *  rewrite newsrc to get rid of any non-existant groups 
  1791. X     */
  1792. X    if (remove_old_groups) {
  1793. X        fclose (fp_old);
  1794. X        rewrite_newsrc ();
  1795. X    }
  1796. X
  1797. X    set_tin_uid_gid ();
  1798. }
  1799. X
  1800. /*
  1801. X *  Write a new newsrc from my_group[] and active[] mygroup if
  1802. X *  rewriting to get rid of groups that don't exist any longer. Used
  1803. X *  to a create a new .newsrc if there isn't one already, or when
  1804. X *  the newsrc is reset.
  1805. X */
  1806. X
  1807. void write_newsrc ()
  1808. {
  1809. X    FILE *fp;
  1810. X    int i;
  1811. X
  1812. X    set_real_uid_gid ();
  1813. X
  1814. X    if ((fp = fopen (newsrc, "w")) == NULL) {
  1815. X        set_tin_uid_gid ();
  1816. X        return;
  1817. X    }
  1818. X
  1819. X    wait_message (txt_creating_newsrc);
  1820. X
  1821. X    for (i=0 ; i < num_active ; i++) {
  1822. X        fprintf (fp, "%s! \n", active[i].name);
  1823. X    }
  1824. X
  1825. X    fclose (fp);
  1826. X
  1827. X    set_tin_uid_gid ();
  1828. }
  1829. X
  1830. /*
  1831. X *  Rewrite newsrc to get rid of groups that don't exist any longer.
  1832. X */
  1833. X
  1834. void rewrite_newsrc ()
  1835. {
  1836. X    char buf[8192], old[LEN];
  1837. X    char old_groups[LEN];
  1838. X    FILE *fp, *fp_old, *fp_new;
  1839. X    int found_old_group, len;    
  1840. X
  1841. X    set_real_uid_gid ();
  1842. X
  1843. X    sprintf (old_groups, "%s/.newsrc.%d", homedir, getpid ());
  1844. X
  1845. X    if ((fp = fopen (newsrc, "r")) == NULL)
  1846. X        goto removed_old_groups_done;
  1847. X
  1848. X    if ((fp_old = fopen (old_groups, "r")) == NULL)
  1849. X        goto removed_old_groups_done;
  1850. X
  1851. X    if ((fp_new = fopen (newnewsrc, "w")) == NULL)
  1852. X        goto removed_old_groups_done;
  1853. X
  1854. X    while (fgets (buf, sizeof buf, fp) != NULL) {            /* read group from newsrc */
  1855. X        rewind (fp_old);
  1856. X        found_old_group = FALSE;    
  1857. X        while (fgets (old, sizeof old, fp_old) != NULL) {    /* read group from oldgroups */
  1858. X            len = strlen (old)-1;
  1859. X            if ((buf[len] == ':' || buf[len] == '!') &&
  1860. X                strncmp (buf, old, len) == 0) {
  1861. X                old[len] = '\0';
  1862. X                fprintf (stderr, txt_not_in_active_file, old);
  1863. X                fprintf (stderr, ". Deleting.\r\n");
  1864. X                fflush (stderr);
  1865. X                found_old_group = TRUE;    
  1866. X            }
  1867. X        }
  1868. X        if (! found_old_group) {
  1869. X            fprintf (fp_new, "%s", buf);
  1870. X        }
  1871. X    }
  1872. X    
  1873. X    fclose (fp);
  1874. X    fclose (fp_old);
  1875. X    fclose (fp_new);
  1876. X
  1877. X    rename_file (newnewsrc, newsrc);
  1878. X
  1879. removed_old_groups_done:
  1880. X    unlink (old_groups);
  1881. X    set_tin_uid_gid ();
  1882. }
  1883. X
  1884. /*
  1885. X *  Load the sequencer rang lists and mark arts[] according to the
  1886. X *  .newsrc info for a particular group.  i.e.  rec.arts.comics: 1-94,97
  1887. X */
  1888. X
  1889. void read_newsrc_line (group)
  1890. X    char *group;
  1891. {
  1892. X    FILE *fp;
  1893. X    char buf[8192];
  1894. X    char *p;
  1895. X
  1896. X    if ((fp = fopen (newsrc, "r")) == NULL)
  1897. X        return;
  1898. X
  1899. X    while (fgets (buf, sizeof buf, fp) != NULL) {
  1900. X        p = buf;
  1901. X        while (*p && *p != '\n' && *p != ' ' && *p != ':' && *p != '!')
  1902. X            p++;
  1903. X        *p++ = '\0';
  1904. X        if (strcmp (buf, group) != 0)
  1905. X            continue;
  1906. X        parse_seq (p);
  1907. X        break;
  1908. X    }
  1909. X
  1910. X    fclose (fp);
  1911. }
  1912. X
  1913. /*
  1914. X *  For our current group, update the sequencer information in .newsrc
  1915. X */
  1916. X
  1917. void update_newsrc (group, groupnum, mark_unread)
  1918. X    char *group;
  1919. X    int groupnum;            /* index into active[] for this group */
  1920. X    int mark_unread;
  1921. {
  1922. X    FILE *fp;
  1923. X    FILE *newfp;
  1924. X    char buf[8192];
  1925. X    char *p;
  1926. X    char c;
  1927. X
  1928. X    set_real_uid_gid ();
  1929. X
  1930. X    if ((newfp = fopen (newnewsrc, "w")) == NULL)
  1931. X        goto update_done;
  1932. X
  1933. X    if ((fp = fopen (newsrc, "r")) != NULL) {
  1934. X        while (fgets (buf, sizeof buf, fp) != NULL) {
  1935. X            for (p = buf; *p; p++)
  1936. X                if (*p == '\n') {
  1937. X                    *p = '\0';
  1938. X                    break;
  1939. X                }
  1940. X
  1941. X            p = buf;
  1942. X            while (*p && *p != ' ' && *p != ':' && *p != '!')
  1943. X                    p++;
  1944. X            c = *p;
  1945. X            if (c != '\0')
  1946. X                *p++ = '\0';
  1947. X
  1948. X            if (c != '!' && c != ' ')
  1949. X                c = ':';
  1950. X
  1951. X            if (strcmp (buf, group) == 0) {
  1952. X                if (mark_unread) {
  1953. X                    fprintf (newfp, "%s%c\n", buf, c);
  1954. X                } else {
  1955. X                    fprintf (newfp, "%s%c ", buf, c);
  1956. X                    print_seq (newfp, groupnum);
  1957. X                    fprintf (newfp, "\n");
  1958. X                }
  1959. X            } else
  1960. X                fprintf (newfp, "%s%c%s\n", buf, c, p);
  1961. X        }
  1962. X        fclose (fp);
  1963. X    }
  1964. X
  1965. X    fclose (newfp);
  1966. X    rename_file (newnewsrc, newsrc);
  1967. X
  1968. update_done:
  1969. X    set_tin_uid_gid ();
  1970. }
  1971. X
  1972. /*
  1973. X *  Subscribe/unsubscribe to a group in .newsrc.  ch should either be
  1974. X *  '!' to unsubscribe or ':' to subscribe.  num is the group's index
  1975. X *  in active[].
  1976. X */
  1977. X
  1978. void subscribe (group, ch, num, out_seq)
  1979. X    char *group;
  1980. X    char ch;
  1981. X    int num;
  1982. X    int out_seq;                /* output sequencer info? */
  1983. {
  1984. X    FILE *fp;
  1985. X    FILE *newfp;
  1986. X    char buf[8192];
  1987. X    char *p;
  1988. X    char c;
  1989. X    int gotit = FALSE;
  1990. X
  1991. X    if (ch == '!')
  1992. X        active[num].flag &= ~SUBSCRIBED;
  1993. X    else
  1994. X        active[num].flag |= SUBSCRIBED;
  1995. X
  1996. X    set_real_uid_gid ();
  1997. X
  1998. X    if ((newfp = fopen (newnewsrc, "w")) == NULL)
  1999. X        goto subscribe_done;
  2000. X
  2001. X    if ((fp = fopen (newsrc, "r")) != NULL) {
  2002. X        while (fgets (buf, sizeof buf, fp) != NULL) {
  2003. X            if (strncmp ("options ", buf, 8) == 0) {
  2004. X                fprintf (newfp, buf);
  2005. X            } else {
  2006. X                for (p = buf; *p; p++) {
  2007. X                    if (*p == '\n') {
  2008. X                        *p = '\0';
  2009. X                        break;
  2010. X                    }
  2011. X                }    
  2012. X
  2013. X                p = buf;
  2014. X                while (*p && *p != ' ' && *p != ':' && *p != '!')
  2015. X                        p++;
  2016. X                c = *p;
  2017. X                if (c != '\0')
  2018. X                    *p++ = '\0';
  2019. X
  2020. X                if (c != '!')
  2021. X                    c = ':';
  2022. X
  2023. X                if (strcmp (buf, group) == 0) {
  2024. X                    fprintf (newfp, "%s%c%s\n", buf, ch, p);
  2025. X                    gotit = TRUE;
  2026. X                } else {
  2027. X                    fprintf (newfp, "%s%c%s\n", buf, c, p);
  2028. X                }
  2029. X            }
  2030. X        }
  2031. X        fclose (fp);
  2032. X    }
  2033. X
  2034. X    if (! gotit) {
  2035. X        if (out_seq) {
  2036. X            fprintf (newfp, "%s%c ", group, ch);
  2037. X            print_seq (newfp, num);
  2038. X            fprintf (newfp, "\n");
  2039. X        } else
  2040. X            fprintf (newfp, "%s%c\n", group, ch);
  2041. X    }
  2042. X
  2043. X    fclose (newfp);
  2044. X    rename_file (newnewsrc, newsrc);
  2045. X
  2046. subscribe_done:
  2047. X    set_tin_uid_gid ();
  2048. }
  2049. X
  2050. X
  2051. void reset_newsrc ()
  2052. {
  2053. X    FILE *fp;
  2054. X    FILE *newfp;
  2055. X    char buf[8192];
  2056. X    char *p;
  2057. X    char c;
  2058. X    int i;
  2059. X
  2060. X    set_real_uid_gid ();
  2061. X
  2062. X    if ((newfp = fopen (newnewsrc, "w")) == NULL)
  2063. X        goto update_done;
  2064. X
  2065. X    if ((fp = fopen (newsrc, "r")) != NULL) {
  2066. X        while (fgets (buf, sizeof (buf), fp) != NULL) {
  2067. X            for (p = buf; *p && *p != '\n'; p++)
  2068. X                continue;
  2069. X            *p = '\0';
  2070. X
  2071. X            p = buf;
  2072. X            while (*p && *p != ' ' && *p != ':' && *p != '!')
  2073. X                    p++;
  2074. X            c = *p;
  2075. X            if (c != '\0')
  2076. X                *p++ = '\0';
  2077. X
  2078. X            if (c != '!')
  2079. X                c = ':';
  2080. X
  2081. X            fprintf (newfp, "%s%c\n", buf, c);
  2082. X        }
  2083. X        fclose (fp);
  2084. X    }
  2085. X
  2086. X    fclose (newfp);
  2087. X    rename_file (newnewsrc, newsrc);
  2088. X
  2089. update_done:
  2090. X    set_tin_uid_gid ();
  2091. X
  2092. X    for (i = 0; i < group_top; i++)
  2093. X        unread[i] = -1;
  2094. }
  2095. X
  2096. X
  2097. void delete_group (group)
  2098. X    char *group;
  2099. {
  2100. X    FILE *fp;
  2101. X    FILE *newfp;
  2102. X    char buf[8192];
  2103. X    char *p;
  2104. X    char c;
  2105. X    int gotit = FALSE;
  2106. X    FILE *del;
  2107. X
  2108. X    set_real_uid_gid ();
  2109. X
  2110. X    if ((newfp = fopen (newnewsrc, "w")) == NULL)
  2111. X        goto del_done;
  2112. X
  2113. X    if ((del = fopen (delgroups, "a+")) == NULL)
  2114. X        goto del_done;
  2115. X
  2116. X    if ((fp = fopen (newsrc, "r")) != NULL) {
  2117. X        while (fgets (buf, sizeof (buf), fp) != NULL) {
  2118. X            for (p = buf; *p && *p != '\n'; p++)
  2119. X                continue;
  2120. X            *p = '\0';
  2121. X
  2122. X            p = buf;
  2123. X            while (*p && *p != ' ' && *p != ':' && *p != '!')
  2124. X                    p++;
  2125. X            c = *p;
  2126. X            if (c != '\0')
  2127. X                *p++ = '\0';
  2128. X
  2129. X            if (c != '!')
  2130. X                c = ':';
  2131. X
  2132. X            if (strcmp (buf, group) == 0) {
  2133. X                fprintf (del, "%s%c%s\n", buf, c, p);
  2134. X                gotit = TRUE;
  2135. X            } else
  2136. X                fprintf (newfp, "%s%c%s\n", buf, c, p);
  2137. X        }
  2138. X        fclose (fp);
  2139. X    }
  2140. X
  2141. X    fclose (newfp);
  2142. X
  2143. X    if (! gotit)
  2144. X        fprintf (del, "%s! \n", group);
  2145. X
  2146. X    fclose (del);
  2147. X    rename_file (newnewsrc, newsrc);
  2148. X
  2149. del_done:
  2150. X    set_tin_uid_gid ();
  2151. }
  2152. X
  2153. X
  2154. int undel_group ()
  2155. {
  2156. X    FILE *del;
  2157. X    FILE *newfp;
  2158. X    FILE *fp;
  2159. X    char buf[2][8192];
  2160. X    char *p;
  2161. X    int which = 0;
  2162. X    long h;
  2163. X    extern int cur_groupnum;
  2164. X    int i, j;
  2165. X    char c;
  2166. X
  2167. X    set_real_uid_gid ();
  2168. X
  2169. X    if ((del = fopen(delgroups, "r")) == NULL) {
  2170. X        set_tin_uid_gid ();
  2171. X        return FALSE;
  2172. X    }
  2173. X
  2174. X    unlink(delgroups);
  2175. X    
  2176. X    if ((newfp = fopen(delgroups, "w")) == NULL) {
  2177. X        set_tin_uid_gid ();
  2178. X        return FALSE;
  2179. X    }
  2180. X
  2181. X    buf[0][0] = '\0';
  2182. X    buf[1][0] = '\0';
  2183. X
  2184. X    while (fgets(buf[which], sizeof (buf[which]), del) != NULL) {
  2185. X        which = !which;
  2186. X        if (*buf[which])
  2187. X            fputs(buf[which], newfp);
  2188. X    }
  2189. X
  2190. X    fclose(del);
  2191. X    fclose(newfp);
  2192. X    which = !which;
  2193. X
  2194. X    if (!*buf[which]) {
  2195. X        set_tin_uid_gid ();
  2196. X        return FALSE;
  2197. X    }
  2198. X
  2199. X    for (p = buf[which]; *p && *p != '\n'; p++)
  2200. X        continue;
  2201. X    *p = '\0';
  2202. X
  2203. X    p = buf[which];
  2204. X    while (*p && *p != ' ' && *p != ':' && *p != '!')
  2205. X        p++;
  2206. X    c = *p;
  2207. X    if (c != '\0')
  2208. X        *p++ = '\0';
  2209. X
  2210. X    if (c != '!')
  2211. X        c = ':';
  2212. X
  2213. X    h = hash_groupname (buf[which]);
  2214. X
  2215. X    for (i = group_hash[h]; i >= 0; i = active[i].next) {
  2216. X        if (strcmp(buf[which], active[i].name) == 0) {
  2217. X            for (j = 0; j < group_top; j++)
  2218. X                if (my_group[j] == i) {
  2219. X                    set_tin_uid_gid ();
  2220. X                    return j;
  2221. X                }
  2222. X
  2223. X            active[i].flag &= ~UNSUBSCRIBED;   /* mark that we got it */
  2224. X            if (c != '!')
  2225. X                active[i].flag |= SUBSCRIBED;
  2226. X
  2227. X            if (group_top >= max_active)
  2228. X                expand_active();
  2229. X            group_top++;
  2230. X            for (j = group_top; j > cur_groupnum; j--) {
  2231. X                my_group[j] = my_group[j-1];
  2232. X                unread[j] = unread[j-1];
  2233. X            }
  2234. X            my_group[cur_groupnum] = i;
  2235. X            unread[cur_groupnum] = parse_unread(p, i);
  2236. X
  2237. X            if ((fp = fopen(newsrc, "r")) == NULL) {
  2238. X                set_tin_uid_gid ();
  2239. X                return FALSE;
  2240. X            }
  2241. X            if ((newfp = fopen(newnewsrc, "w")) == NULL) {
  2242. X                fclose(fp);
  2243. X                set_tin_uid_gid ();
  2244. X                return FALSE;
  2245. X            }
  2246. X            i = 0;
  2247. X            while (fgets(buf[!which], sizeof (buf[!which]), fp) != NULL) {
  2248. X                for (p = buf[!which]; *p && *p != '\n'; p++)
  2249. X                    continue;
  2250. X                *p = '\0';
  2251. X
  2252. X                p = buf[!which];
  2253. X                while (*p && *p!=' ' && *p != ':' && *p != '!')
  2254. X                    p++;
  2255. X                c = *p;
  2256. X                if (c != '\0')
  2257. X                    *p++ = '\0';
  2258. X
  2259. X                if (c != '!')
  2260. X                    c = ':';
  2261. X
  2262. X                while (i < cur_groupnum) {
  2263. X                    if (strcmp(buf[!which],
  2264. X                      active[my_group[i]].name) == 0) {
  2265. X                        fprintf(newfp, "%s%c%s\n",
  2266. X                            buf[!which], c, p);
  2267. X                        goto foo_cont;
  2268. X                    }
  2269. X                    i++;
  2270. X                }
  2271. X                fprintf(newfp, "%s%c%s\n", buf[which], c, p);
  2272. X                fprintf(newfp, "%s%c%s\n", buf[!which], c, p);
  2273. X                break;
  2274. foo_cont:;
  2275. X            }
  2276. X
  2277. X            while (fgets (buf[!which], sizeof (buf[!which]), fp) != NULL)
  2278. X                fputs (buf[!which], newfp);
  2279. X
  2280. X            fclose (newfp);
  2281. X            fclose (fp);
  2282. X            rename_file (newnewsrc, newsrc);
  2283. X            set_tin_uid_gid ();
  2284. X            return TRUE;
  2285. X        }
  2286. X    }
  2287. X    set_tin_uid_gid ();
  2288. X
  2289. X    return FALSE;
  2290. }
  2291. X
  2292. X
  2293. void mark_group_read (group, groupnum)
  2294. X    char *group;
  2295. X    int groupnum;            /* index into active[] for this group */
  2296. {
  2297. X    FILE *fp;
  2298. X    FILE *newfp;
  2299. X    char buf[8192];
  2300. X    char *p;
  2301. X    char c;
  2302. X
  2303. X    if (active[groupnum].max < 2)
  2304. X        return;
  2305. X
  2306. X    set_real_uid_gid ();
  2307. X
  2308. X    if ((newfp = fopen (newnewsrc, "w")) == NULL)
  2309. X        goto mark_group_read_done;
  2310. X
  2311. X    if ((fp = fopen (newsrc, "r")) != NULL) {
  2312. X        while (fgets(buf, sizeof (buf), fp) != NULL) {
  2313. X            for (p = buf; *p; p++)
  2314. X                if (*p == '\n') {
  2315. X                    *p = '\0';
  2316. X                    break;
  2317. X                }
  2318. X
  2319. X            p = buf;
  2320. X            while (*p && *p != ' ' && *p != ':' && *p != '!')
  2321. X                    p++;
  2322. X            c = *p;
  2323. X            if (c != '\0')
  2324. X                *p++ = '\0';
  2325. X
  2326. X            if (c != '!')
  2327. X                c = ':';
  2328. X
  2329. X            if (strcmp (buf, group) == 0) {
  2330. X                fprintf (newfp, "%s%c 1-%ld\n", buf, c, active[groupnum].max);
  2331. X            } else
  2332. X                fprintf(newfp, "%s%c%s\n", buf, c, p);
  2333. X        }
  2334. X        fclose (fp);
  2335. X    }
  2336. X
  2337. X    fclose (newfp);
  2338. X    rename_file (newnewsrc, newsrc);
  2339. X
  2340. mark_group_read_done:
  2341. X    set_tin_uid_gid ();
  2342. }
  2343. X
  2344. X
  2345. void parse_seq(s)
  2346. X    char *s;
  2347. {
  2348. X    long low, high;
  2349. X    int i;
  2350. X
  2351. X    while (*s) {
  2352. X        while (*s && (*s < '0' || *s > '9'))
  2353. X            s++;
  2354. X
  2355. X        if (*s && *s >= '0' && *s <= '9') {
  2356. X            low = (long) atol (s);
  2357. X            while (*s && *s >= '0' && *s <= '9')
  2358. X                s++;
  2359. X            if (*s == '-') {
  2360. X                s++;
  2361. X                high = (long) atol (s);
  2362. X                while (*s && *s >= '0' && *s <= '9')
  2363. X                    s++;
  2364. X            }  else
  2365. X                high = low;
  2366. X
  2367. X            for (i = 0; i < top; i++)
  2368. X                if (arts[i].artnum >= low && arts[i].artnum <= high)
  2369. X                    arts[i].unread = ART_READ;
  2370. X        }
  2371. X    }
  2372. }
  2373. X
  2374. X
  2375. int parse_unread (s, groupnum)
  2376. X    char *s;
  2377. X    int groupnum;            /* index for group in active[] */
  2378. {
  2379. X    long low, high;
  2380. X    long last_high;
  2381. X    int sum = 0;
  2382. X    int gotone = FALSE;
  2383. X    int n;
  2384. X
  2385. /*
  2386. X *  Read the first range from the .newsrc sequencer information.  If the
  2387. X *  top of the first range is higher than what the active file claims is
  2388. SHAR_EOF
  2389. true || echo 'restore of newsrc.c failed'
  2390. fi
  2391. echo 'End of tin1.1 part 6'
  2392. echo 'File newsrc.c is continued in part 7'
  2393. echo 7 > _shar_seq_.tmp
  2394. exit 0
  2395.  
  2396. --
  2397. NAME   Iain Lea
  2398. EMAIL  iain%estevax.uucp@unido.Informatik.Uni-Dortmund.DE
  2399. SNAIL  Bruecken Strasse 12, 8500 Nuernberg 90, Germany
  2400. PHONE  +49-911-331963 (home)  +49-911-3089-407 (work)
  2401. -- 
  2402.  Dr. med. dipl.-math Dieter Becker           Tel.: (0 / +49) 6841 - 16 3046
  2403.  Medizinische Universitaets- und Poliklinik  Fax.: (0 / +49) 6841 - 16 3369
  2404.  Innere Medizin III                         
  2405.  D - 6650 Homburg / Saar                     Email: becker@med-in.uni-sb.de
  2406. exit 0 # Just in case...
  2407.