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

  1. Newsgroups: comp.sources.misc
  2. From: iain%estevax.uucp@unido.Informatik.Uni-Dortmund.DE (Iain Lea)
  3. Subject:  v28i047:  tin - threaded full screen newsreader v1.1, Part03/11
  4. Message-ID: <1992Feb18.043612.12785@sparky.imd.sterling.com>
  5. X-Md4-Signature: f37955312af61c11d30fcf35556b4a19
  6. Date: Tue, 18 Feb 1992 04:36:12 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 47
  11. Archive-name: tin/part03
  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.03 (part 3 of tin1.1)
  17. # do not concatenate these parts, unpack them in order with /bin/sh
  18. # file tin.nrf 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" != 3; 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 tin.nrf'
  34. else
  35. echo 'x - continuing file tin.nrf'
  36. sed 's/^X//' << 'SHAR_EOF' >> 'tin.nrf' &&
  37. X          tevax' for csh or 'set ADD_ADDRESS @littevax' and
  38. X          'export ADD_ADDRESS' for sh) the address
  39. X          _u_s_e_r@_b_i_g_v_a_x@_l_i_t_t_l_e_v_a_x will be used and the mail will
  40. X          reach _u_s_e_r@_b_i_g_v_a_x.  This variable has precedence over
  41. X          the file $_H_O_M_E/._t_i_n/_a_d_d__a_d_d_r_e_s_s that may also contain
  42. X
  43. X
  44. X
  45. X
  46. NEWS-OS                   Release 4.1R                         15
  47. X
  48. X
  49. X
  50. X
  51. X
  52. TIN(1)             NEWS-OS Programmer's Manual             TIN(1)
  53. X
  54. X
  55. X
  56. X          an address.
  57. X
  58. X     BBUUGG_AADDDDRREESSSS
  59. X          If the 'B' command bug report mail address is not
  60. X          correct this variable should be set to the correct mail
  61. X          address. This variable has precedence over the file
  62. X          $_H_O_M_E/._t_i_n/_b_u_g__a_d_d_r_e_s_s that may also contain a mail
  63. X          address.
  64. X
  65. X     EEDDIITTOORR
  66. X          This variable has precedence over the default editor
  67. X          (ie. vi) that is used in all editing operations within
  68. X          tin (ie. posting 'w', replying 'rR', follow-ups 'fF'
  69. X          and bug reports 'B').
  70. X
  71. TTIIPPSS AANNDD TTRRIICCKKSS
  72. X     The following newsgroups provide useful information concern-
  73. X     ing news software:
  74. X         -news.software.readers (info. about news user agents
  75. X          tin,rn,nn,vn etc.)
  76. X         -news.software.nntp (info. about NNTP)
  77. X         -news.software.b (info. about news transport agents
  78. X          Bnews & Cnews)
  79. X
  80. X     Many prompts (ie. 'Mark everything as read? (y/n): y')
  81. X     within tin offer a default choice that the cursor is posi-
  82. X     tioned on. By pressing <CR> the default value is taken.
  83. X
  84. X     When tin is run in an xterm window it will resize itself
  85. X     each time the xterm is resized.
  86. X
  87. FFIILLEESS
  88. X     $_H_O_M_E/._n_e_w_s_r_c             subscribed to newgroups.
  89. X     $_H_O_M_E/._t_i_n/_t_i_n_r_c          options.
  90. X     $_H_O_M_E/._t_i_n/._i_n_d_e_x         newsgroup index files directory.
  91. X     $_H_O_M_E/._t_i_n/_a_d_d__a_d_d_r_e_s_s    address to add to when replying through mail.
  92. X     $_H_O_M_E/._t_i_n/_a_c_t_i_v_e         used by -n option for notifying user of new groups.
  93. X     $_H_O_M_E/._t_i_n/_b_u_g__a_d_d_r_e_s_s    address to send bug reports to.
  94. X     $_H_O_M_E/._t_i_n/_k_i_l_l           kill file.
  95. X     $_H_O_M_E/._t_i_n/_o_r_g_a_n_i_z_a_t_i_o_n   string to replace default organization.
  96. X     $_H_O_M_E/._t_i_n/_p_o_s_t_e_d         history of articles posted by user.
  97. X     $_H_O_M_E/._t_i_n/_r_e_p_l_y_t_o        host address to use in Reply-To: mail header.
  98. X     $_H_O_M_E/._t_i_n/_u_n_t_h_r_e_a_d       contains groups that are not to be threaded.
  99. X     $_H_O_M_E/._s_i_g_n_a_t_u_r_e          signature.
  100. X     $_H_O_M_E/._S_i_g                signature.
  101. X
  102. BBUUGGSS
  103. X     There are bugs somewhere among the creeping featurism. Any
  104. X     bugs found should be reported by the 'B' (bug report) com-
  105. X     mand.
  106. X
  107. X
  108. X
  109. X
  110. X
  111. X
  112. 16                        Release 4.1R                    NEWS-OS
  113. X
  114. X
  115. X
  116. X
  117. X
  118. TIN(1)             NEWS-OS Programmer's Manual             TIN(1)
  119. X
  120. X
  121. X
  122. X     There is a bug when article killing is switched ON/OFF at
  123. X     article page level and the 't' command is used to return to
  124. X     group selection index.
  125. X
  126. X     When articles have been unkilled, all articles will be
  127. X     marked unread even if they have already been read.
  128. X
  129. X     Killing articles when tin is setuid causes strange
  130. X     behaviour.
  131. X
  132. X     Will not uudecode some of the images in
  133. X     alt.binaries.pictures because more than one image is in the
  134. X     multi-part file to uudecode. Only the first image will be
  135. X     uudecoded.
  136. X
  137. X     Does not handle Xref: headers for cross-posted articles.
  138. X
  139. X     More than one page of responses within a thread cause offset
  140. X     problems at thread level.
  141. X
  142. HHIISSTTOORRYY
  143. X     Based on the tass newsreader that was developed by Rich
  144. X     Skrenta and posted to alt.sources in March 1991. Tass was
  145. X     itself heavily infleuenced by NOTES which was developed at
  146. X     the University of Illinois in the early 1980's.
  147. X
  148. X     Tin v1.00 (full distribution) was posted in 8 parts to
  149. X     alt.sources on 23 Aug 1991.
  150. X     Tin v1.0 PL1 (full distribution) was posted in 8 parts to
  151. X     alt.sources on 03 Sep 1991.
  152. X     Tin v1.0 PL2 (full distribution) was posted in 9 parts to
  153. X     alt.sources on 24 Sep 1991.
  154. X     Tin v1.0 PL3 (patch) was posted in 4 parts to alt.sources on
  155. X     30 Sep 1991.
  156. X     Tin v1.0 PL4 (patch) was posted in 2 parts to alt.sources on
  157. X     02 Oct 1991.
  158. X     Tin v1.0 PL5 (patch) was posted in 4 parts to alt.sources on
  159. X     17 Oct 1991.
  160. X     Tin v1.0 PL6 (patch) was posted in 5 parts to alt.sources on
  161. X     27 Nov 1991.
  162. X     Tin v1.0 PL7 (patch) was posted in 2 parts to alt.sources on
  163. X     27 Nov 1991.
  164. X     Tin v1.1 PL0 (full distribution) was posted in ?? parts to
  165. X     alt.sources on ?? Feb 1992.
  166. X
  167. CCRREEDDIITTSS
  168. X     Rich Skrenta
  169. X          author of tass v3.2 which this newsreader used as its
  170. X          base.
  171. X
  172. X     Dave Taylor
  173. X          author of curses.c from the elm mailreader.
  174. X
  175. X
  176. X
  177. X
  178. NEWS-OS                   Release 4.1R                         17
  179. X
  180. X
  181. X
  182. X
  183. X
  184. TIN(1)             NEWS-OS Programmer's Manual             TIN(1)
  185. X
  186. X
  187. X
  188. X     Rich Salz
  189. X          author of wildmat.c pattern matching routine.
  190. X
  191. X     Chris Thewalt
  192. X          author of getline.c emacs style editing routine.
  193. X
  194. X     I wish to thank the following people for supplying patchs:
  195. X
  196. X     Anton Aylward, Dieter Becker, Marc Boucher, Robert Claeson,
  197. X     Ned Danieley, Brent Ermlick, Carl Hage, Ed Hanway, Torsten
  198. X     Homeyer, Karl-Koenig Koenigsson, Kris Kugel, Hakan Lenne-
  199. X     stal, Clifford Luke, Bill Poitras, Jim Robinson, Nickolay
  200. X     Saukh, Rich Salz, John Sauter, Bart Sears, Karl-Olav Ser-
  201. X     rander, Doug Sewell, Cliff Stanford, Adri Verhoef, Cary
  202. X     Whitney
  203. X
  204. X     I wish to thank the following people for bug
  205. X     reports/comments:
  206. X
  207. X     Klaus Arzig, Scott Babb, Reiner Balling, Dan Berry, Volker
  208. X     Beyer, Roger Binns, Georg Biehler, Ian Brown, Andreas Bro-
  209. X     sig, Steven Cogswell, Tom Czarnik, David Donovan, Peter
  210. X     Dressler, Gerhard Ermer, Hugh Fader, Joachim Feld, Paul Fox,
  211. X     Bernhard Gmelch, Viet Hoang, Andy Jackson, Joe Johnson,
  212. X     Cyrill Jung, Hans-Juergen Knopp, Per Lindqvist, Bob Lukas,
  213. X     Phillip Molloy, Toni Metz, Greg Miller, Klaus Neuberger,
  214. X     Otto Niesser, Reiner Oelhaf, Wolf Paul, Andrew Phillips, Ted
  215. X     Richards, Fredy Schwatz, Bernd Schwerin, Klamer Schutte,
  216. X     Chris Smith, Steve Spearman, Hironobu Takahashi, Sven Werner
  217. X
  218. AAUUTTHHOORR
  219. X     Iain Lea
  220. X          (iain%estevax.uucp@unido.Informatik.Uni-Dortmund.DE)
  221. X
  222. X
  223. X
  224. X
  225. X
  226. X
  227. X
  228. X
  229. X
  230. X
  231. X
  232. X
  233. X
  234. X
  235. X
  236. X
  237. X
  238. X
  239. X
  240. X
  241. X
  242. X
  243. X
  244. 18                        Release 4.1R                    NEWS-OS
  245. X
  246. X
  247. SHAR_EOF
  248. echo 'File tin.nrf is complete' &&
  249. chmod 0600 tin.nrf ||
  250. echo 'restore of tin.nrf failed'
  251. Wc_c="`wc -c < 'tin.nrf'`"
  252. test 41067 -eq "$Wc_c" ||
  253.     echo 'tin.nrf: original size 41067, current size' "$Wc_c"
  254. rm -f _shar_wnt_.tmp
  255. fi
  256. # ============= art.c ==============
  257. if test -f 'art.c' -a X"$1" != X"-c"; then
  258.     echo 'x - skipping art.c (File already exists)'
  259.     rm -f _shar_wnt_.tmp
  260. else
  261. > _shar_wnt_.tmp
  262. echo 'x - extracting art.c (Text)'
  263. sed 's/^X//' << 'SHAR_EOF' > 'art.c' &&
  264. /*
  265. X *  Project   : tin - a threaded Netnews reader
  266. X *  Module    : art.c
  267. X *  Author    : R.Skrenta / I.Lea
  268. X *  Created   : 01-04-91
  269. X *  Updated   : 04-02-92
  270. X *  Notes     :
  271. X *  Copyright : (c) Copyright 1991-92 by Rich Skrenta & Iain Lea
  272. X *              You may  freely  copy or  redistribute  this software,
  273. X *              so  long as there is no profit made from its use, sale
  274. X *              trade or  reproduction.  You may not change this copy-
  275. X *              right notice, and it must be included in any copy made
  276. X */
  277. X
  278. #include    "tin.h"
  279. X
  280. char index_file[LEN];
  281. char *glob_art_group;
  282. int index_file_killed = FALSE;
  283. long last_read_article;
  284. X
  285. X
  286. /*
  287. X *  Construct the pointers to the basenotes of each thread
  288. X *  arts[] contains every article in the group.  inthread is
  289. X *  set on each article that is after the first article in the
  290. X *  thread.  Articles which have been expired have their thread
  291. X *  set to -2 (ART_EXPIRED).
  292. X */
  293. X
  294. void find_base (only_unread)
  295. X    int only_unread;
  296. {
  297. X    register int i;
  298. X    register int j;
  299. X
  300. X    top_base = 0;
  301. X
  302. debug_print_arts ();
  303. X
  304. X    if (only_unread) {
  305. X        for (i = 0; i < top; i++) {
  306. X            if (arts[i].thread != ART_EXPIRED && arts[i].inthread == FALSE) {
  307. X                if (top_base >= max_art) {
  308. X                    expand_art ();
  309. X                }
  310. X                if (arts[i].unread == ART_UNREAD) {
  311. X                    base[top_base++] = i;
  312. X                } else {
  313. X                    for (j = i ; j >= 0 ; j = arts[j].thread) {
  314. X                        if (arts[j].unread) {
  315. X                            base[top_base++] = i;
  316. X                            break;
  317. X                        }
  318. X                    }
  319. X                }
  320. X            }
  321. X        }
  322. X    } else {
  323. X        for (i = 0; i < top; i++) {
  324. X            if (! arts[i].inthread && arts[i].thread != ART_EXPIRED) {
  325. X                if (top_base >= max_art) {
  326. X                    expand_art ();
  327. X                }
  328. X                base[top_base++] = i;
  329. X            }
  330. X        }
  331. X    }
  332. }
  333. X
  334. /* 
  335. X *  Count the number of non-expired and non-killed articles in arts[]
  336. X */
  337. X
  338. int num_of_arts ()
  339. {
  340. X    int sum = 0;
  341. X    register int i;
  342. X
  343. X    for (i = 0; i < top; i++) {
  344. X        if (arts[i].thread != ART_EXPIRED && arts[i].killed == FALSE) {
  345. X            sum++;
  346. X        }
  347. X    }
  348. X
  349. X    return sum;
  350. }
  351. X
  352. /*
  353. X *  Do we have an entry for article art?
  354. X */
  355. X
  356. int valid_artnum (art)
  357. X    long art;
  358. {
  359. X    register int i;
  360. X
  361. X    for (i = 0; i < top; i++)
  362. X        if (arts[i].artnum == art)
  363. X            return i;
  364. X
  365. X    return -1;
  366. }
  367. X
  368. /*
  369. X *  Return TRUE if arts[] contains any expired articles
  370. X *  (articles we have an entry for which don't have a corresponding
  371. X *   article file in the spool directory)
  372. X */
  373. X
  374. int purge_needed ()
  375. {
  376. X    register int i;
  377. X
  378. X    for (i = 0; i < top; i++)
  379. X        if (arts[i].thread == ART_EXPIRED)
  380. X            return TRUE;
  381. X
  382. X    return FALSE;
  383. }
  384. X
  385. /*
  386. X *  Main group indexing routine.  Group should be the name of the
  387. X *  newsgroup, i.e. "comp.unix.amiga".  group_path should be the
  388. X *  same but with the .'s turned into /'s: "comp/unix/amiga"
  389. X *
  390. X *  Will read any existing index, create or incrementally update
  391. X *  the index by looking at the articles in the spool directory,
  392. X *  and attempt to write a new index if necessary.
  393. X */
  394. X
  395. void index_group (group, group_path)
  396. X    char *group;
  397. X    char *group_path;
  398. {
  399. X    int killed = FALSE;
  400. X    int modified = FALSE;
  401. X    glob_art_group = group;
  402. X
  403. X    set_signals_art ();
  404. X    
  405. X    if (! update) {
  406. X        sprintf (msg, txt_group, group);
  407. X        wait_message (msg);
  408. X    }
  409. X
  410. X    hash_reclaim ();
  411. X    free_art_array ();
  412. X
  413. X    if (local_index)
  414. X        find_local_index (group);
  415. X    else
  416. X        sprintf (index_file, "%s/%s/%s", spooldir, group_path, INDEXDIR);
  417. X
  418. X    /*
  419. X     *  load articles from index file if it exists
  420. X     */
  421. X    load_index ();
  422. X
  423. X    /*
  424. X     *  load killed articles into arts[] because kill arts is OFF
  425. X     */
  426. X    if (! kill_articles && index_file_killed) {
  427. X        index_file_killed = FALSE;
  428. X        last_read_article = 0L;
  429. X    }
  430. X
  431. X    /*
  432. X     *  add any articles to arts[] that are new or were killed
  433. X     */
  434. X    modified = read_group (group, group_path);
  435. X
  436. X    /*
  437. X     *  compare kill descriptions to arts[] and kill mark any that match
  438. X     */
  439. X    killed = kill_any_articles (group);
  440. X    
  441. X    if (modified || killed || purge_needed()) {
  442. X        if (local_index) {        /* writing index in home directory */
  443. X            set_real_uid_gid ();    /* so become them */
  444. X        }
  445. X
  446. X        if (killed) {
  447. X            reload_index_file (group, killed);
  448. X        } else {
  449. X            dump_index (group, FALSE);
  450. X            make_threads (FALSE);
  451. X            find_base (show_only_unread);
  452. X        }
  453. X
  454. X        if (local_index) {
  455. X            set_tin_uid_gid ();
  456. X        }
  457. X    } else {
  458. X        make_threads (FALSE);
  459. X        find_base (show_only_unread);
  460. X    }
  461. X    
  462. X    if ((modified || killed) && ! update) {
  463. X        clear_message ();
  464. X    }
  465. }
  466. X
  467. /*
  468. X *  Index a group.  Assumes any existing index has already been
  469. X *  loaded.
  470. X */
  471. X
  472. int read_group (group, group_path)
  473. X    char *group;
  474. X    char *group_path;
  475. {
  476. X    int fd;
  477. X    long art;
  478. X    int count = 0;
  479. X    int display_groupname = TRUE; 
  480. X    int modified = FALSE;
  481. X    int respnum;
  482. X    register int i;
  483. X    
  484. X    setup_base (group, group_path);    /* load article numbers into base[] */
  485. X
  486. X    for (i = 0; i < top_base; i++) {    /* for each article # */
  487. X        art = base[i];
  488. X
  489. /*
  490. X *  Do we already have this article in our index?  Change thread from
  491. X *  (ART_EXPIRED) to (ART_NORMAL) if so and skip the header eating.
  492. X */
  493. X
  494. X        if ((respnum = valid_artnum (art)) >= 0 || art <= last_read_article) {
  495. X            arts[respnum].thread = ART_NORMAL;
  496. X            arts[respnum].unread = ART_UNREAD;
  497. X            continue;
  498. X        }
  499. X
  500. X        if (! modified) {
  501. X            modified = TRUE;   /* we've modified the index */
  502. X                               /* it will need to be re-written */
  503. X        }
  504. X
  505. X        if ((fd = open_header_fd (group_path, art)) < 0) {
  506. X            continue;
  507. X        }
  508. X        
  509. X        /*
  510. X         *  Add article to arts[]
  511. X         */
  512. X        if (top >= max_art)
  513. X            expand_art();
  514. X
  515. X        arts[top].artnum = art;
  516. X        arts[top].thread = ART_NORMAL;
  517. X
  518. X        set_article (&arts[top]);
  519. X
  520. X        if (! parse_headers (fd, &arts[top])) {
  521. X            continue;
  522. X        }
  523. X        close (fd);
  524. X        last_read_article = arts[top].artnum;    /* used if arts are killed */
  525. X        top++;
  526. X
  527. X        if (++count % MODULO_COUNT_NUM == 0 && ! update) {
  528. #ifndef SLOW_SCREEN_UPDATE
  529. X            sprintf (msg, txt_indexing_num, group, count);
  530. #else
  531. X            sprintf (msg, txt_indexing, group);
  532. #endif
  533. X            wait_message (msg);
  534. X        }
  535. X    }
  536. X
  537. X    return modified;
  538. }
  539. X
  540. X
  541. /*
  542. X *  Go through the articles in arts[] and use .thread to snake threads
  543. X *  through them.  Use the subject line to construct threads.  The
  544. X *  first article in a thread should have .inthread set to FALSE, the
  545. X *  rest TRUE.  Only do unexprired articles we haven't visited yet
  546. X *  (arts[].thread == -1 ART_NORMAL).
  547. X */
  548. X
  549. void make_threads (rethread)
  550. X    int rethread;
  551. {
  552. X    extern int cur_groupnum;
  553. X    register int i;
  554. X    register int j;
  555. X
  556. X    /*
  557. X     *  .thread & .inthread need to be reset if re-threading arts[]
  558. X     */
  559. X    if (rethread && active[my_group[cur_groupnum]].thread) {
  560. X        for (i=0 ; i < top ; i++) {
  561. X            arts[i].thread = ART_NORMAL;
  562. X            arts[i].inthread = FALSE;
  563. X        }
  564. X    }
  565. X
  566. X    switch (sort_art_type) {
  567. X        case SORT_BY_NOTHING:        /* don't sort at all */
  568. X            qsort ((char *) arts, top, sizeof (struct article_t), artnum_comp);
  569. X            break;
  570. X        case SORT_BY_SUBJ_DESCEND:
  571. X        case SORT_BY_SUBJ_ASCEND:
  572. X            qsort ((char *) arts, top, sizeof (struct article_t), subj_comp);
  573. X            break;
  574. X        case SORT_BY_FROM_DESCEND:
  575. X        case SORT_BY_FROM_ASCEND:
  576. X            qsort ((char *) arts, top, sizeof (struct article_t), from_comp);
  577. X            break;
  578. X        case SORT_BY_DATE_DESCEND:
  579. X        case SORT_BY_DATE_ASCEND:
  580. X            qsort ((char *) arts, top, sizeof (struct article_t), date_comp);
  581. X            break;
  582. X        default:
  583. X            break;
  584. X    }
  585. X
  586. X    if (thread_arts && active[my_group[cur_groupnum]].thread) {
  587. X        for (i = 0; i < top; i++) {
  588. X            if (arts[i].thread == ART_NORMAL) {
  589. X                for (j = i+1; j < top; j++) {
  590. X                    if (arts[j].thread != ART_EXPIRED &&
  591. X                        ((arts[i].subject == arts[j].subject) ||
  592. X                        ((arts[i].part || arts[i].patch) &&
  593. X                        arts[i].archive == arts[j].archive))) {
  594. X                            arts[i].thread = j;
  595. X                            arts[j].inthread = TRUE;
  596. X                            break;
  597. X                    }
  598. X                }
  599. X            }
  600. X        }
  601. X    }
  602. }
  603. X
  604. X
  605. int parse_headers (fd, h)
  606. X    int fd;
  607. X    struct article_t *h;
  608. {
  609. X    char buf[HEADER_LEN];
  610. X    char buf2[HEADER_LEN];
  611. X    char art_from_addr[LEN];
  612. X    char art_full_name[LEN];
  613. X    char *ptr, *ptrline, *s;
  614. X    int n = 0, len = 0, lineno = 0;
  615. X    int flag;
  616. X    int got_subject = FALSE;
  617. X    int got_from = FALSE;
  618. X    int got_date = FALSE;
  619. X    int got_archive = FALSE;
  620. X    
  621. X    if ((n = read (fd, buf, HEADER_LEN)) <= 0) {
  622. X        return FALSE;
  623. X    }
  624. X
  625. X    buf[n-1] = '\0';
  626. X
  627. X    ptr = buf;
  628. X
  629. X    while (1) {
  630. X        for (ptrline = ptr; *ptr && *ptr != '\n'; ptr++) {
  631. X            if (((*ptr) & 0xFF) < ' ') {
  632. X                *ptr = ' ';
  633. X            }
  634. X        }
  635. X        flag = *ptr;
  636. X        *ptr++ = '\0';
  637. X        lineno++;
  638. X
  639. X        if (! got_from && match_header (ptrline, "From", buf2, HEADER_LEN)) {
  640. X            parse_from (buf2, art_from_addr, art_full_name); 
  641. X            h->from = hash_str (art_from_addr);
  642. X            h->name = hash_str (art_full_name);
  643. X            got_from = TRUE;
  644. X        } else if (! got_subject && match_header (ptrline, "Subject", buf2, HEADER_LEN)) {
  645. X            s = eat_re (buf2);
  646. X            h->subject = hash_str (eat_re (s));
  647. X            got_subject = TRUE;
  648. X        } else if (! got_date && match_header (ptrline, "Date", buf2, HEADER_LEN)) {
  649. X            parse_date (buf2, h->date);
  650. X            got_date = TRUE;
  651. X        } else if (match_header (ptrline, "Archive-name", buf2, HEADER_LEN) ||
  652. X                    match_header (ptrline, "Archive-Name", buf2, HEADER_LEN)) {
  653. X            if ((s = (char *) strchr (buf2, '/')) != NULL) {
  654. X                if (strncmp (s+1,"part",4) == 0 ||
  655. X                    strncmp (s+1,"Part",4) == 0) {
  656. X                    h->part = str_dup (s+5);
  657. X                    len = (int) strlen (h->part);
  658. X                    if (h->part[len-1] == '\n') {
  659. X                        h->part[len-1] = '\0';
  660. X                    }
  661. X                } else {
  662. X                    if (strncmp (s+1,"patch",5) == 0 ||
  663. X                        strncmp (s+1,"Patch",5) == 0) {
  664. X                        h->patch = str_dup (s+6);
  665. X                        len = (int) strlen (h->patch);
  666. X                        if (h->patch[len-1] == '\n') {
  667. X                            h->patch[len-1] = '\0';
  668. X                        }
  669. X                    }
  670. X                }
  671. X                if (h->part || h->patch) {
  672. X                    s = buf2;
  673. X                    while (*s && *s != '/')
  674. X                        s++;
  675. X                    *s = '\0';    
  676. X                    s = buf2;
  677. X                    h->archive = hash_str (s);
  678. X                    got_archive = TRUE;
  679. X                }
  680. X            }
  681. X        }
  682. X
  683. X        if (! flag || lineno > 25 || got_archive) {
  684. X            debug_print_header (h);
  685. X            return TRUE;
  686. X        }
  687. X    }
  688. X    /* NOTREACHED */
  689. }
  690. X
  691. /* 
  692. X *  Write out an index file.  Write the group name first so if
  693. X *  local indexing is done we can disambiguate between group name
  694. X *  hash collisions by looking at the index file.
  695. X */
  696. X
  697. void dump_index (group, killed)
  698. X    char *group;
  699. X    int killed;
  700. {
  701. X    char nam[LEN];
  702. X    FILE *fp;
  703. X    int *iptr;
  704. X    int realnum;
  705. X    register int i;
  706. X
  707. X    sprintf (nam, "%s.%d", index_file, getpid());
  708. X    if ((fp = fopen (nam, "w")) == NULL) {
  709. X        error_message (txt_cannot_open, nam);
  710. X        return;
  711. X    }
  712. X
  713. X    /*
  714. X     *  dump group header info.
  715. X     */
  716. X    if (sort_art_type != SORT_BY_NOTHING) {
  717. X        qsort ((char *) arts, top, sizeof (struct article_t), artnum_comp);
  718. X    }
  719. X    fprintf (fp, "%s\n", group);
  720. X    fprintf (fp, "%d\n", num_of_arts ());
  721. X    if (top <= 0) {
  722. X        fprintf (fp, "0\n");
  723. X    } else {
  724. X        if (last_read_article > arts[top-1].artnum) {
  725. X            fprintf (fp, "%ld\n", last_read_article);
  726. X        } else {
  727. X            fprintf (fp, "%ld\n", arts[top-1].artnum);
  728. X        }
  729. X    }
  730. X    if (index_file_killed && killed) {
  731. X        fprintf (fp, "KILLED\n");
  732. X    } else {
  733. X        fprintf (fp, "COMPLETE\n");
  734. X    }
  735. X
  736. X    /*
  737. X     *  dump articles
  738. X     */
  739. X    realnum = 0; 
  740. X    for (i = 0; i < top; i++) {
  741. X        if (arts[i].thread != ART_EXPIRED && arts[i].killed == FALSE) { 
  742. X            debug_print_header (&arts[i]);
  743. X
  744. X            fprintf(fp, "%ld\n", arts[i].artnum);
  745. X
  746. X            iptr = (int *) arts[i].subject;
  747. X            iptr--;
  748. X
  749. X            if (! arts[i].subject) {
  750. X                fprintf(fp, " \n");
  751. X            } else if (*iptr < 0 || *iptr > top) {
  752. X                fprintf(fp, " %s\n", arts[i].subject);
  753. X                *iptr = realnum;
  754. X            } else if (killed || *iptr == i) {
  755. X                fprintf(fp, " %s\n", arts[i].subject);
  756. X            } else {
  757. X                fprintf(fp, "%%%d\n", *iptr);
  758. X            }
  759. X    
  760. X            iptr = (int *) arts[i].from;
  761. X            iptr--;
  762. X
  763. X            if (! arts[i].from) {
  764. X                fprintf (fp, " \n");
  765. X            } else if (*iptr < 0 || *iptr > top) {
  766. X                fprintf (fp, " %s\n", arts[i].from);
  767. X                *iptr = realnum;
  768. X            } else if (killed || *iptr == i) {
  769. X                fprintf(fp, " %s\n", arts[i].from);
  770. X            } else {
  771. X                fprintf(fp, "%%%d\n", *iptr);
  772. X            }
  773. X
  774. X            iptr = (int *) arts[i].name;
  775. X            iptr--;
  776. X
  777. X            if (! arts[i].name) {
  778. X                fprintf (fp, " \n");
  779. X            } else if (*iptr < 0 || *iptr > top) {
  780. X                fprintf (fp, " %s\n", arts[i].name);
  781. X                *iptr = realnum;
  782. X            } else if (killed || *iptr == i) {
  783. X                fprintf(fp, " %s\n", arts[i].name);
  784. X            } else {
  785. X                fprintf(fp, "%%%d\n", *iptr);
  786. X            }
  787. X
  788. X            fprintf (fp, "%s\n", arts[i].date);
  789. X            
  790. X            iptr = (int *) arts[i].archive;
  791. X            iptr--;
  792. X
  793. X            if (! arts[i].archive) {
  794. X                fprintf (fp, "\n");
  795. X            } else if (*iptr < 0 || *iptr > top) {
  796. X                fprintf (fp, " %s\n", arts[i].archive);
  797. X                *iptr = realnum;
  798. X            } else if (arts[i].part || arts[i].patch) {
  799. X                if (killed || *iptr == i) {
  800. X                    fprintf(fp, " %s\n", arts[i].archive);
  801. X                } else {
  802. X                    fprintf (fp, "%%%d\n", *iptr);
  803. X                }
  804. X            } else {
  805. X                fprintf (fp, "\n");
  806. X            }
  807. X            
  808. X            if (! arts[i].part) {
  809. X                fprintf (fp, " \n");
  810. X            } else {
  811. X                fprintf (fp, "%s\n", arts[i].part);
  812. X            }
  813. X
  814. X            if (! arts[i].patch) {
  815. X                fprintf (fp, " \n");
  816. X            } else {
  817. X                fprintf (fp, "%s\n", arts[i].patch);
  818. X            }
  819. X
  820. X            realnum++;
  821. X        }
  822. X    }
  823. X    fclose (fp);
  824. X    chmod (index_file, 0644);
  825. X    rename_file (nam, index_file);
  826. X    if (debug) {
  827. X        sprintf (msg, "cp %s INDEX", index_file);
  828. X        system (msg);
  829. X    }
  830. }
  831. X
  832. /*
  833. X *  Read in an index file.
  834. X *
  835. X *  index file header 
  836. X *    1.  newsgroup name (ie. alt.sources)
  837. X *    2.  number of articles (ie. 26)
  838. X *    3.  number of last read article (ie. 210)
  839. X *    4.  Is this a complete/killed index file (ie. COMPLETE/KILLED)
  840. X *  index file record
  841. X *    1.  article number    (ie. 183)               [mandatory]
  842. X *    2.  Subject: line     (ie. Which newsreader?) [mandatory]
  843. X *    3.  From: line (addr) (ie. iain@norisc)       [mandatory]
  844. X *    4.  From: line (name) (ie. Iain Lea)          [mandatory]
  845. X *    5.  Date: of posting  (ie. 911231125959)      [mandatory]
  846. X *    6.  Archive: name     (ie. compiler)          [optional]
  847. X *    7.  Part number of Archive: name  (ie. 01)    [optional]
  848. X *    8.  Patch number of Archive: name (ie. 01)    [optional]
  849. X */
  850. X
  851. int load_index ()
  852. {
  853. X    int error = 0;
  854. X    int i, n;
  855. X    char buf[LEN], *p;
  856. X    FILE *fp;
  857. X
  858. X    top = 0;
  859. X    last_read_article = 0L;
  860. X
  861. X    if ((fp = fopen (index_file, "r")) == NULL) {
  862. X        return FALSE;
  863. X    }
  864. X
  865. X    /*
  866. X     *  load header - discard group name, num. of arts in index file after any arts were killed
  867. X     */
  868. X    if (fgets(buf, sizeof buf, fp) == NULL ||
  869. X        fgets(buf, sizeof buf, fp) == NULL) {
  870. X        error = 0;            
  871. X        goto corrupt_index;    
  872. X    }
  873. X    i = atoi (buf);
  874. X
  875. X    /*
  876. X     * num. of last_read_article including any that were killed
  877. X     */
  878. X    if (fgets(buf, sizeof buf, fp) == NULL) {
  879. X        error = 1;                
  880. X        goto corrupt_index;    
  881. X    }                            
  882. X    last_read_article = (long) atol (buf);
  883. X    
  884. X    /*
  885. X     * is index file complete or were articles killed when it was dumped
  886. X     */
  887. X    if (fgets(buf, sizeof buf, fp) == NULL) {
  888. X        error = 2;                
  889. X        goto corrupt_index;    
  890. X    }
  891. X    index_file_killed = (buf[0] == 'K' ? TRUE : FALSE);
  892. X    
  893. X    /*
  894. X     *  load articles
  895. X     */
  896. X    for (; top < i ; top++) {
  897. X        if (top >= max_art) {
  898. X            expand_art ();
  899. X        }
  900. X
  901. X        arts[top].thread = ART_EXPIRED;
  902. X        set_article (&arts[top]);
  903. X
  904. X        /*
  905. X         * Article no.
  906. X         */
  907. X        if (fgets(buf, sizeof buf, fp) == NULL) {
  908. X            error = 3;
  909. X            goto corrupt_index;
  910. X        }
  911. X        arts[top].artnum = (long) atol (buf);
  912. X
  913. X        /*
  914. X         * Subject:
  915. X         */
  916. X        if (fgets(buf, sizeof buf, fp) == NULL) {
  917. X            error = 4;
  918. X            goto corrupt_index;
  919. X        }
  920. X
  921. X        if (buf[0] == '%') {
  922. X            n = atoi (&buf[1]);
  923. X            if (n >= top || n < 0) {
  924. X                error = 5;
  925. X                goto corrupt_index;
  926. X            }
  927. X            arts[top].subject = arts[n].subject;
  928. X        } else if (buf[0] == ' ') {
  929. X            for (p = &buf[1];  *p && *p != '\n'; p++)
  930. X                continue;    
  931. X            *p = '\0';
  932. X            arts[top].subject = hash_str (&buf[1]);
  933. X        } else {
  934. X            error = 6;
  935. X            goto corrupt_index;
  936. X        }
  937. X            
  938. X        /*
  939. X         * From: (addr part)
  940. X         */
  941. X        if (fgets(buf, sizeof buf, fp) == NULL) {
  942. X            error = 7;
  943. X            goto corrupt_index;
  944. X        }
  945. X
  946. X        if (buf[0] == '%') {
  947. X            n = atoi (&buf[1]);
  948. X            if (n >= top || n < 0) {
  949. X                error = 8;
  950. X                goto corrupt_index;
  951. X            }
  952. X            arts[top].from = arts[n].from;
  953. X        } else if (buf[0] == ' ') {
  954. X            for (p = &buf[1];  *p && *p != '\n'; p++)
  955. X                continue;
  956. X            *p = '\0';
  957. X            arts[top].from = hash_str (&buf[1]);
  958. X        } else {
  959. X            error = 9;
  960. X            goto corrupt_index;
  961. X        }
  962. X
  963. X        /*
  964. X         * From: (full name)
  965. X         */
  966. X        if (fgets(buf, sizeof buf, fp) == NULL) {
  967. X            error = 10;
  968. X            goto corrupt_index;
  969. X        }
  970. X
  971. X        if (buf[0] == '%') {
  972. X            n = atoi (&buf[1]);
  973. X            if (n > top || n < 0) {
  974. X                error = 11;
  975. X                goto corrupt_index;
  976. X            }
  977. X            if (n == top) {        /* no full name so .name = .from */
  978. X                arts[top].name = arts[top].from;
  979. X            } else {
  980. X                arts[top].name = arts[n].name;
  981. X            }
  982. X        } else if (buf[0] == ' ') {
  983. X            for (p = &buf[1];  *p && *p != '\n'; p++)
  984. X                continue;
  985. X            *p = '\0';
  986. X            arts[top].name = hash_str (&buf[1]);
  987. X        } else {
  988. X            error = 12;
  989. X            goto corrupt_index;
  990. X        }
  991. X
  992. X        /*
  993. X         * Date:
  994. X         */
  995. X        if (fgets(buf, sizeof buf, fp) == NULL) {
  996. X            error = 13;
  997. X            goto corrupt_index;
  998. X        }
  999. X
  1000. X        buf[strlen (buf)-1] = '\0';
  1001. X        my_strncpy (arts[top].date, buf, 12);
  1002. X
  1003. X        /*
  1004. X         * Archive-name:
  1005. X         */
  1006. X        if (fgets(buf, sizeof buf, fp) == NULL) {
  1007. X            error = 14;
  1008. X            goto corrupt_index;
  1009. X        }
  1010. X
  1011. X        if (buf[0] == '\n') {
  1012. X            arts[top].archive = (char *) 0;
  1013. X        } else if (buf[0] == '%') {
  1014. X            n = atoi (&buf[1]);
  1015. X            if (n > top || n < 0) {
  1016. X                error = 15;
  1017. X                goto corrupt_index;
  1018. X            }
  1019. X            arts[top].archive = arts[n].archive;
  1020. X        } else if (buf[0] == ' ') {
  1021. X            for (p = &buf[1]; *p && *p != '\n' ; p++)
  1022. X                continue;
  1023. X            *p = '\0';
  1024. X            arts[top].archive = hash_str (&buf[1]);
  1025. X        } else {
  1026. X            error = 16;
  1027. X            goto corrupt_index;
  1028. X        }
  1029. X
  1030. X        /*
  1031. X         * part no.
  1032. X         */
  1033. X        if (fgets(buf, sizeof buf, fp) == NULL) {
  1034. X            error = 17;
  1035. X            goto corrupt_index;
  1036. X        }
  1037. X
  1038. X        if (buf[0] != ' ') { 
  1039. X            buf[strlen (buf)-1] = '\0';
  1040. X            arts[top].part = str_dup (buf);
  1041. X        }
  1042. X
  1043. X        /*
  1044. X         * patch no.
  1045. X         */
  1046. X        if (fgets(buf, sizeof buf, fp) == NULL) {
  1047. X            error = 18;
  1048. X            goto corrupt_index;
  1049. X        }
  1050. X
  1051. X        if (buf[0] != ' ') { 
  1052. X            buf[strlen (buf)-1] = '\0';
  1053. X            arts[top].patch = str_dup (buf);
  1054. X        }
  1055. X
  1056. X        debug_print_header (&arts[top]);
  1057. X    }
  1058. X
  1059. X    fclose(fp);
  1060. X    return TRUE;
  1061. X
  1062. corrupt_index:
  1063. X    if (! update) {
  1064. X        sprintf (msg, txt_corrupt_index, index_file, error, top); 
  1065. X        error_message (msg, "");
  1066. X    }
  1067. X
  1068. X    if (debug) {
  1069. X        sprintf (msg, "cp %s INDEX.BAD", index_file);
  1070. X        system (msg);
  1071. X    }
  1072. X
  1073. X    unlink (index_file);
  1074. X    top = 0;
  1075. X    return FALSE;
  1076. }
  1077. X
  1078. X
  1079. /*
  1080. X *  Look in the local $HOME/RCDIR/INDEXDIR (or wherever) directory for the
  1081. X *  index file for the given group.  Hashing the group name gets
  1082. X *  a number.  See if that #.1 file exists; if so, read first line.
  1083. X *  Group we want?  If no, try #.2.  Repeat until no such file or
  1084. X *  we find an existing file that matches our group.
  1085. X */
  1086. X
  1087. void find_local_index (group)
  1088. X    char *group;
  1089. {
  1090. X    unsigned long h;
  1091. X    static char buf[LEN];
  1092. X    int i;
  1093. X    char *p;
  1094. X    FILE *fp;
  1095. X
  1096. X    h = hash_groupname (group);
  1097. X
  1098. X    i = 1;
  1099. X    while (1) {
  1100. X        sprintf(index_file, "%s/%lu.%d", indexdir, h, i);
  1101. X
  1102. X        if ((fp = fopen(index_file, "r")) == NULL) {
  1103. X            return;
  1104. X        }
  1105. X
  1106. X        if (fgets(buf, sizeof buf, fp) == NULL) {
  1107. X            fclose(fp);
  1108. X            return;
  1109. X        }
  1110. X        fclose(fp);
  1111. X
  1112. X        for (p = buf; *p && *p != '\n'; p++)
  1113. X            continue;
  1114. X        *p = '\0';
  1115. X
  1116. X        if (strcmp(buf, group) == 0)
  1117. X            return;
  1118. X
  1119. X        i++;
  1120. X    }
  1121. }
  1122. X
  1123. /*
  1124. X *  Run the index file updater only for the groups we've loaded.
  1125. X */
  1126. X
  1127. void do_update ()
  1128. {
  1129. X    int i, j;
  1130. X    char group_path[LEN];
  1131. X    char *p;
  1132. X    long epoch;
  1133. X    
  1134. X    if (verbose) {
  1135. X        time (&epoch);
  1136. X        printf ("%s", ctime (&epoch));
  1137. X        fflush (stdout);
  1138. X    }
  1139. X
  1140. X    for (i = 0; i < group_top; i++) {
  1141. X        strcpy(group_path, active[my_group[i]].name);
  1142. X        for (p = group_path; *p; p++) {
  1143. X            if (*p == '.') {
  1144. X                *p = '/';
  1145. X            }
  1146. X        }
  1147. X        if (verbose) {
  1148. X            printf ("%s %s\n", (catchup ? "Catchup" : "Updating"),
  1149. X                    active[my_group[i]].name);
  1150. X            fflush (stdout);
  1151. X        }
  1152. X        index_group (active[my_group[i]].name, group_path);
  1153. X        if (catchup) {
  1154. X            for (j = 0; j < top; j++) {
  1155. X                arts[j].unread = ART_READ;
  1156. X            }
  1157. X            update_newsrc (active[my_group[i]].name, my_group[i], FALSE);
  1158. X        }
  1159. X    }
  1160. X
  1161. X    if (verbose) {
  1162. X        time (&epoch);
  1163. X        printf ("%s", ctime (&epoch));
  1164. X        fflush (stdout);
  1165. X    }
  1166. }
  1167. X
  1168. /*
  1169. X *  reload index after any articles have been killed
  1170. X */
  1171. void reload_index_file (group, killed)
  1172. X    char *group;
  1173. X    int killed;
  1174. {
  1175. X    char group_path[LEN];
  1176. X    char *p;
  1177. X
  1178. X    if (local_index) {            /* writing index in home directory */
  1179. X        set_real_uid_gid ();    /* so become them */
  1180. X    }
  1181. X
  1182. X    strcpy (group_path, group);            /* turn comp.unix.amiga into */
  1183. X    for (p = group_path; *p; p++)        /* comp/unix/amiga */
  1184. X        if (*p == '.')
  1185. X            *p = '/';
  1186. X
  1187. X    if (killed) {
  1188. X        if (! update) {
  1189. X            wait_message (txt_killing_arts);
  1190. X        }
  1191. X        index_file_killed = TRUE;
  1192. X        setup_base (group, group_path);
  1193. X        dump_index (group, killed);
  1194. X        load_index ();
  1195. X    } else {
  1196. X        if (! update) {
  1197. X            wait_message (txt_unkilling_arts);
  1198. X        }
  1199. X        if (local_index) {
  1200. X            find_local_index (group);
  1201. X        } else {
  1202. X            sprintf (index_file, "%s/%s/%s", spooldir, group_path, INDEXDIR);
  1203. X        }
  1204. X
  1205. X        unlink (index_file);    /* delete index file */
  1206. X
  1207. X        index_file_killed = FALSE;
  1208. X        last_read_article = 0L;
  1209. X
  1210. X        if (read_group (group, group_path)) {
  1211. X            dump_index (group, killed);
  1212. X        }
  1213. X    }
  1214. X
  1215. X    make_threads (TRUE);
  1216. X    find_base (show_only_unread);
  1217. X
  1218. X    if (local_index) {
  1219. X        set_tin_uid_gid ();
  1220. X    }
  1221. X
  1222. X    return; 
  1223. }
  1224. X
  1225. /*
  1226. X * convert date from ctime format to sortable format
  1227. X * "24 Jul 91 12:59:59", "Mon, 24 Jul 91 12:59:59" and
  1228. X * "Mon, 24 Jul 1991 12:59:59" are parsed and produce
  1229. X * output of the form "910724125959"
  1230. X */
  1231. X
  1232. char *parse_date (date, str)
  1233. X    char *date;
  1234. X    char *str;
  1235. {
  1236. X    char buf[4];
  1237. X    int i = 0;
  1238. X
  1239. X    /* Check for extraneous day-of-week at start of date */
  1240. X    while (isalpha(date[i]) || date[i] == ',' || date[i] == ' ') {
  1241. X        i++;
  1242. X    }
  1243. X    
  1244. X    if (date[i+1] == ' ') {    /* ie. "2 Aug..." instead of "12 Aug... */
  1245. X        str[4] = '0';        /* day */
  1246. X        str[5] = date[i++];
  1247. X        i++;
  1248. X    } else {
  1249. X        str[4] = date[i++];        /* day */
  1250. X        str[5] = date[i++];
  1251. X        i++;
  1252. X    }
  1253. X    
  1254. X    buf[0] = date[i++];        /* month in Jan,Feb,.. form */
  1255. X    buf[1] = date[i++];
  1256. X    buf[2] = date[i++];
  1257. X    buf[3] = '\0';
  1258. X
  1259. X    i++;
  1260. X    
  1261. X    str[0] = date[i++];        /* year */
  1262. X    str[1] = date[i++];
  1263. X    if (isdigit(date[i])) {         /* 19xx format */
  1264. X        str[0] = date[i++];
  1265. X        str[1] = date[i++];
  1266. X    }
  1267. X    
  1268. X    i++;
  1269. X    
  1270. X    if (strcmp (buf, "Jan") == 0) {        /* convert Jan to 01 etc */
  1271. X        str[2] = '0';
  1272. X        str[3] = '1';
  1273. X    } else if (strcmp (buf, "Feb") == 0) {
  1274. X        str[2] = '0';
  1275. X        str[3] = '2';
  1276. X    } else if (strcmp (buf, "Mar") == 0) {
  1277. X        str[2] = '0';
  1278. X        str[3] = '3';
  1279. X    } else if (strcmp (buf, "Apr") == 0) {
  1280. X        str[2] = '0';
  1281. X        str[3] = '4';
  1282. X    } else if (strcmp (buf, "May") == 0) {
  1283. X        str[2] = '0';
  1284. X        str[3] = '5';
  1285. X    } else if (strcmp (buf, "Jun") == 0) {
  1286. X        str[2] = '0';
  1287. X        str[3] = '6';
  1288. X    } else if (strcmp (buf, "Jul") == 0) {
  1289. X        str[2] = '0';
  1290. X        str[3] = '7';
  1291. X    } else if (strcmp (buf, "Aug") == 0) {
  1292. X        str[2] = '0';
  1293. X        str[3] = '8';
  1294. X    } else if (strcmp (buf, "Sep") == 0) {
  1295. X        str[2] = '0';
  1296. X        str[3] = '9';
  1297. X    } else if (strcmp (buf, "Oct") == 0) {
  1298. X        str[2] = '1';
  1299. X        str[3] = '0';
  1300. X    } else if (strcmp (buf, "Nov") == 0) {
  1301. X        str[2] = '1';
  1302. X        str[3] = '1';
  1303. X    } else if (strcmp (buf, "Dec") == 0) {
  1304. X        str[2] = '1';
  1305. X        str[3] = '2';
  1306. X    } else {
  1307. X        str[2] = '0';
  1308. X        str[3] = '0';
  1309. X    }
  1310. X    
  1311. X    str[6] = date[i++];        /* hour */
  1312. X    str[7] = date[i++];
  1313. X
  1314. X    i++;
  1315. X    
  1316. X    str[8] = date[i++];        /* minutes */
  1317. X    str[9] = date[i++];
  1318. X    
  1319. X    i++;
  1320. X    
  1321. X    str[10] = date[i++];    /* seconds */
  1322. X    str[11] = date[i++];
  1323. X
  1324. X    str[12] = '\0';        /* terminate string */
  1325. X
  1326. X    return (str);
  1327. }
  1328. X
  1329. X
  1330. int artnum_comp (p1, p2)
  1331. X    char *p1;
  1332. X    char *p2;
  1333. {
  1334. X    struct article_t *s1 = (struct article_t *) p1;
  1335. X    struct article_t *s2 = (struct article_t *) p2;
  1336. X
  1337. X    /* s1->artnum less than s2->artnum */
  1338. X    if (s1->artnum < s2->artnum) {
  1339. X        return -1;
  1340. X    }
  1341. X    /* s1->artnum greater than s2->artnum */
  1342. X    if (s1->artnum > s2->artnum) {
  1343. X        return 1;
  1344. X    }
  1345. X    return 0;
  1346. }
  1347. X
  1348. X
  1349. int subj_comp (p1, p2)
  1350. X    char *p1;
  1351. X    char *p2;
  1352. {
  1353. X    struct article_t *s1 = (struct article_t *) p1;
  1354. X    struct article_t *s2 = (struct article_t *) p2;
  1355. X
  1356. X    /* return result of strcmp (reversed for descending) */
  1357. X    return (sort_art_type == SORT_BY_SUBJ_ASCEND 
  1358. X            ? strcmp (s1->subject, s2->subject) 
  1359. X            : strcmp (s2->subject, s1->subject));
  1360. }
  1361. X
  1362. X
  1363. int from_comp (p1, p2)
  1364. X    char *p1;
  1365. X    char *p2;
  1366. {
  1367. X    struct article_t *s1 = (struct article_t *) p1;
  1368. X    struct article_t *s2 = (struct article_t *) p2;
  1369. X
  1370. X    /* return result of strcmp (reversed for descending) */
  1371. X    return (sort_art_type == SORT_BY_FROM_ASCEND 
  1372. X            ? strcmp (s1->from, s2->from) 
  1373. X            : strcmp (s2->from, s1->from));
  1374. }
  1375. X
  1376. X
  1377. int date_comp (p1, p2)
  1378. X    char *p1;
  1379. X    char *p2;
  1380. {
  1381. X    struct article_t *s1 = (struct article_t *) p1;
  1382. X    struct article_t *s2 = (struct article_t *) p2;
  1383. X    /* return result of strcmp (reversed for descending) */
  1384. X    return (sort_art_type == SORT_BY_DATE_ASCEND 
  1385. X            ? strcmp (s1->date, s2->date) 
  1386. X            : strcmp (s2->date, s1->date));
  1387. }
  1388. X
  1389. X
  1390. void set_article (art)
  1391. X    struct article_t *art;
  1392. {    
  1393. X    art->subject = (char *) 0;
  1394. X    art->from = (char *) 0;
  1395. X    art->name = (char *) 0;
  1396. X    art->date[0] = '\0';
  1397. X    art->archive = (char *) 0;
  1398. X    art->part = (char *) 0;
  1399. X    art->patch = (char *) 0;
  1400. X    art->unread = ART_UNREAD;
  1401. X    art->inthread = FALSE;
  1402. X    art->killed = FALSE;
  1403. X    art->tagged = FALSE;
  1404. }
  1405. SHAR_EOF
  1406. chmod 0600 art.c ||
  1407. echo 'restore of art.c failed'
  1408. Wc_c="`wc -c < 'art.c'`"
  1409. test 23976 -eq "$Wc_c" ||
  1410.     echo 'art.c: original size 23976, current size' "$Wc_c"
  1411. rm -f _shar_wnt_.tmp
  1412. fi
  1413. # ============= curses.c ==============
  1414. if test -f 'curses.c' -a X"$1" != X"-c"; then
  1415.     echo 'x - skipping curses.c (File already exists)'
  1416.     rm -f _shar_wnt_.tmp
  1417. else
  1418. > _shar_wnt_.tmp
  1419. echo 'x - extracting curses.c (Text)'
  1420. sed 's/^X//' << 'SHAR_EOF' > 'curses.c' &&
  1421. /*
  1422. X *  Project   : tin - a threaded Netnews reader
  1423. X *  Module    : curses.c
  1424. X *  Author    : Dave Taylor
  1425. X *  Created   : ??-??-86
  1426. X *  Updated   : 13-12-91
  1427. X *  Notes     : This is a screen management library borrowed with permission
  1428. X *              from the Elm mail system (a great mailer--I highly recommend
  1429. X *              it!).This library was hacked to provide what tin needs.
  1430. X *  Copyright : Copyright (c) 1986 Dave Taylor
  1431. X *              The Elm Mail System  -  $Revision: 2.1 $   $State: Exp $
  1432. X */
  1433. X
  1434. #include <stdio.h>
  1435. #include <curses.h>
  1436. #ifndef MINIX
  1437. #    include <sys/ioctl.h>
  1438. #endif
  1439. X
  1440. #ifdef TRUE
  1441. #    undef TRUE
  1442. #    define        TRUE        1
  1443. #else    
  1444. #    define        TRUE        1
  1445. #endif
  1446. X
  1447. #ifdef FALSE
  1448. #    undef FALSE
  1449. #    define        FALSE        0
  1450. #else    
  1451. #    define        FALSE        0
  1452. #endif
  1453. X
  1454. #define        BACKSPACE    '\b'
  1455. #define        VERY_LONG_STRING    2500
  1456. X
  1457. int LINES=23;
  1458. int COLS=80;
  1459. X
  1460. int inverse_okay = TRUE;
  1461. X
  1462. #ifdef BSD 
  1463. #    ifndef BSD4_1
  1464. #        include <sgtty.h>
  1465. #    else
  1466. #        include <termio.h>
  1467. #    endif
  1468. #else
  1469. #    ifndef SYSV
  1470. #        ifndef MINIX
  1471. #            ifdef SINIX
  1472. #                include <termios.h>
  1473. #            else
  1474. #                include <termio.h>
  1475. #            endif
  1476. #        else
  1477. #            include <sgtty.h>
  1478. #        endif
  1479. #    endif
  1480. #endif
  1481. X
  1482. #include <ctype.h>
  1483. X
  1484. #include "tin.h"
  1485. X
  1486. #define TTYIN    0
  1487. X
  1488. #ifdef SHORTNAMES
  1489. # define _clearinverse    _clrinv
  1490. # define _cleartoeoln    _clrtoeoln
  1491. # define _cleartoeos    _clr2eos
  1492. #endif
  1493. X
  1494. #if defined(BSD) || defined(MINIX)
  1495. #    define TCGETA    TIOCGETP
  1496. #    define TCSETAW    TIOCSETP
  1497. X
  1498. struct sgttyb _raw_tty,
  1499. X          _original_tty;
  1500. #else
  1501. #    ifdef SINIX
  1502. #        define TCGETA    STCGETA
  1503. #        define TCSETAW    STCSETAW
  1504. struct termios _raw_tty, 
  1505. X              _original_tty;
  1506. #    else
  1507. struct termio _raw_tty, 
  1508. X              _original_tty;
  1509. #    endif
  1510. #endif
  1511. X
  1512. static int _inraw = FALSE;                  /* are we IN rawmode?    */
  1513. X
  1514. #define DEFAULT_LINES_ON_TERMINAL    24
  1515. #define DEFAULT_COLUMNS_ON_TERMINAL    80
  1516. X
  1517. static char *_clearscreen, *_moveto, *_cleartoeoln, *_cleartoeos,
  1518. X            *_setinverse, *_clearinverse, *_setunderline, *_clearunderline,
  1519. X            *_terminalinit, *_terminalend;
  1520. X
  1521. static int _lines,_columns;
  1522. X
  1523. static char _terminal[1024];              /* Storage for terminal entry */
  1524. static char _capabilities[1024];           /* String for cursor motion */
  1525. X
  1526. static char *ptr = _capabilities;    /* for buffering         */
  1527. X
  1528. int    outchar ();            /* char output for tputs */
  1529. char  *tgetstr (),            /* Get termcap capability */
  1530. X      *tgoto ();            /* and the goto stuff    */
  1531. X
  1532. int InitScreen ()
  1533. {
  1534. X    int  tgetent();      /* get termcap entry */
  1535. X    char termname[40], *p;
  1536. X    
  1537. X    if ((p = (char *) getenv ("TERM")) == NULL) {
  1538. X        fprintf (stderr, "%s: TERM variable must be set to use screen capabilities\n", progname);
  1539. X        return (FALSE);
  1540. X    }
  1541. X    if (strcpy (termname, p) == NULL) {
  1542. X        fprintf (stderr,"%s: Can't get TERM variable\n", progname);
  1543. X        return (FALSE);
  1544. X    }
  1545. X    if (tgetent (_terminal, termname) != 1) {
  1546. X        fprintf (stderr,"%s: Can't get entry for TERM\n", progname);
  1547. X        return (FALSE);
  1548. X    }
  1549. X
  1550. X    /* load in all those pesky values */
  1551. X    _clearscreen    = tgetstr ("cl", &ptr);
  1552. X    _moveto         = tgetstr ("cm", &ptr);
  1553. X    _cleartoeoln    = tgetstr ("ce", &ptr);
  1554. X    _cleartoeos     = tgetstr ("cd", &ptr);
  1555. X    _lines          = tgetnum ("li");
  1556. X    _columns        = tgetnum ("co");
  1557. X    _setinverse     = tgetstr ("so", &ptr);
  1558. X    _clearinverse   = tgetstr ("se", &ptr);
  1559. X    _setunderline   = tgetstr ("us", &ptr);
  1560. X    _clearunderline = tgetstr ("ue", &ptr);
  1561. X    _terminalinit   = tgetstr ("ti", &ptr);
  1562. X    _terminalend    = tgetstr ("te", &ptr);
  1563. X
  1564. X    InitWin ();
  1565. X
  1566. X    if (!_clearscreen) {
  1567. X        fprintf (stderr,
  1568. X            "%s: Terminal must have clearscreen (cl) capability\n",progname);
  1569. X        return (FALSE);
  1570. X    }
  1571. X    if (!_moveto) {
  1572. X        fprintf (stderr,
  1573. X            "%s: Terminal must have cursor motion (cm)\n", progname);
  1574. X        return (FALSE);
  1575. X    }
  1576. X    if (!_cleartoeoln) {
  1577. X        fprintf (stderr,
  1578. X            "%s: Terminal must have clear to end-of-line (ce)\n", progname);
  1579. X        return (FALSE);
  1580. X    }
  1581. X    if (!_cleartoeos) {
  1582. /*
  1583. X        fprintf (stderr,
  1584. X            "%s: terminal does not have clear to end-of-screen (ce). Simulating\n", progname);
  1585. */        
  1586. X        fprintf (stderr,
  1587. X            "%s: Terminal must have clear to end-of-screen (cd)\n", progname);
  1588. X        return (FALSE);
  1589. X    }
  1590. X    if (_lines == -1)
  1591. X        _lines = DEFAULT_LINES_ON_TERMINAL;
  1592. X    if (_columns == -1)
  1593. X        _columns = DEFAULT_COLUMNS_ON_TERMINAL;
  1594. X    return (TRUE);
  1595. }
  1596. X
  1597. /*
  1598. X *  returns the number of lines and columns on the display.
  1599. X */
  1600. void ScreenSize(num_lines, num_columns)
  1601. X    int *num_lines, *num_columns;
  1602. {
  1603. X    if (_lines == 0) _lines = DEFAULT_LINES_ON_TERMINAL;
  1604. X    if (_columns == 0) _columns = DEFAULT_COLUMNS_ON_TERMINAL;
  1605. X
  1606. X    *num_lines = _lines - 1;        /* assume index from zero*/
  1607. X    *num_columns = _columns;        /* assume index from one */
  1608. }
  1609. X
  1610. void InitWin ()
  1611. {
  1612. X    if (_terminalinit) {
  1613. X        tputs (_terminalinit, 1, outchar);
  1614. X        fflush (stdout);
  1615. X    }
  1616. }
  1617. X
  1618. void EndWin ()
  1619. {
  1620. X    if (_terminalend) {
  1621. X        tputs (_terminalend, 1, outchar);
  1622. X        fflush (stdout);
  1623. X    }
  1624. }
  1625. X
  1626. /*
  1627. X *  clear the screen: returns -1 if not capable
  1628. X */
  1629. X
  1630. void ClearScreen()
  1631. {
  1632. X    tputs(_clearscreen, 1, outchar);
  1633. X    fflush(stdout);      /* clear the output buffer */
  1634. }
  1635. X
  1636. /*
  1637. X *  move cursor to the specified row column on the screen.
  1638. X *  0,0 is the top left!
  1639. X */
  1640. X
  1641. void MoveCursor(row, col)
  1642. X    int row, col;
  1643. {
  1644. X    char *stuff, *tgoto();
  1645. X
  1646. X    stuff = tgoto (_moveto, col, row);
  1647. X    tputs (stuff, 1, outchar);
  1648. X    fflush (stdout);
  1649. }
  1650. X
  1651. /*
  1652. X *  clear to end of line
  1653. X */
  1654. X
  1655. void CleartoEOLN()
  1656. {
  1657. X    tputs(_cleartoeoln, 1, outchar);
  1658. X    fflush(stdout);  /* clear the output buffer */
  1659. }
  1660. X
  1661. /*
  1662. X *  clear to end of screen
  1663. X */
  1664. X
  1665. void CleartoEOS()
  1666. {
  1667. X    int i;
  1668. X    
  1669. X    if (_cleartoeos) {
  1670. X        tputs(_cleartoeos, 1, outchar);
  1671. X    } else {
  1672. X        for (i=_lines ; i < _lines ; i++) {
  1673. X            MoveCursor (i, 0);
  1674. X            CleartoEOLN ();
  1675. X        }
  1676. X    }
  1677. X    fflush(stdout);  /* clear the output buffer */
  1678. }
  1679. X
  1680. /*
  1681. X *  set inverse video mode
  1682. X */
  1683. X
  1684. void StartInverse()
  1685. {
  1686. X    if (_setinverse && inverse_okay)
  1687. X        tputs(_setinverse, 1, outchar);
  1688. X    fflush(stdout);
  1689. }
  1690. X
  1691. /*
  1692. X *  compliment of startinverse
  1693. X */
  1694. X
  1695. void EndInverse()
  1696. {
  1697. X    if (_clearinverse && inverse_okay)
  1698. X        tputs(_clearinverse, 1, outchar);
  1699. X    fflush(stdout);
  1700. }
  1701. X
  1702. /*
  1703. X *  returns either 1 or 0, for ON or OFF
  1704. X */
  1705. X
  1706. int RawState()
  1707. {
  1708. X    return (_inraw);
  1709. }
  1710. X
  1711. /*
  1712. X *  state is either TRUE or FALSE, as indicated by call
  1713. X */
  1714. X
  1715. void Raw(state)
  1716. X    int state;
  1717. {
  1718. X    if (state == FALSE && _inraw) {
  1719. X      (void) ioctl(TTYIN, TCSETAW, &_original_tty);
  1720. X      _inraw = 0;
  1721. X    }
  1722. X    else if (state == TRUE && ! _inraw) {
  1723. X
  1724. X      (void) ioctl(TTYIN, TCGETA, &_original_tty);    /** current setting **/
  1725. X
  1726. X      (void) ioctl(TTYIN, TCGETA, &_raw_tty);    /** again! **/
  1727. #if defined(BSD) || defined(MINIX)
  1728. X      _raw_tty.sg_flags &= ~(ECHO | CRMOD);    /* echo off */
  1729. X      _raw_tty.sg_flags |= CBREAK;    /* raw on    */
  1730. #else
  1731. X      _raw_tty.c_lflag &= ~(ICANON | ECHO);    /* noecho raw mode        */
  1732. X
  1733. X      _raw_tty.c_cc[VMIN] = '\01';    /* minimum # of chars to queue    */
  1734. X      _raw_tty.c_cc[VTIME] = '\0';    /* minimum time to wait for input */
  1735. #endif
  1736. X
  1737. X      (void) ioctl(TTYIN, TCSETAW, &_raw_tty);
  1738. X
  1739. X      _inraw = 1;
  1740. X    }
  1741. }
  1742. X
  1743. /*
  1744. X *  read a character with Raw mode set!
  1745. X */
  1746. X
  1747. int ReadCh()
  1748. {
  1749. X    register int result;
  1750. X    char ch;
  1751. X    
  1752. #ifdef READ_CHAR_HACK
  1753. #undef getc
  1754. X    ch = getc (stdin);
  1755. X    return ((ch == EOF) ? EOF : ch & 0xFF);
  1756. #else
  1757. X    result = read(0, &ch, 1);
  1758. X        return((result <= 0 ) ? EOF : ch & 0xFF);
  1759. #endif        
  1760. }
  1761. X
  1762. /*
  1763. X *  output a character. From tputs... (Note: this CANNOT be a macro!)
  1764. X */
  1765. X
  1766. int outchar(c)
  1767. X    char c;
  1768. {
  1769. X    putc(c, stdout);
  1770. }
  1771. SHAR_EOF
  1772. chmod 0600 curses.c ||
  1773. echo 'restore of curses.c failed'
  1774. Wc_c="`wc -c < 'curses.c'`"
  1775. test 7108 -eq "$Wc_c" ||
  1776.     echo 'curses.c: original size 7108, current size' "$Wc_c"
  1777. rm -f _shar_wnt_.tmp
  1778. fi
  1779. # ============= debug.c ==============
  1780. if test -f 'debug.c' -a X"$1" != X"-c"; then
  1781.     echo 'x - skipping debug.c (File already exists)'
  1782.     rm -f _shar_wnt_.tmp
  1783. else
  1784. > _shar_wnt_.tmp
  1785. echo 'x - extracting debug.c (Text)'
  1786. sed 's/^X//' << 'SHAR_EOF' > 'debug.c' &&
  1787. /*
  1788. X *  Project   : tin - a threaded Netnews reader
  1789. X *  Module    : debug.c
  1790. X *  Author    : I.Lea
  1791. X *  Created   : 01-04-91
  1792. X *  Updated   : 21-01-92
  1793. X *  Notes     : debug routines
  1794. X *  Copyright : (c) Copyright 1991-92 by Iain Lea
  1795. X *                You may  freely  copy or  redistribute  this software,
  1796. X *              so  long as there is no profit made from its use, sale
  1797. X *              trade or  reproduction.  You may not change this copy-
  1798. X *              right notice, and it must be included in any copy made
  1799. X */
  1800. X
  1801. #include "tin.h"
  1802. X
  1803. int debug;
  1804. X
  1805. X
  1806. void debug_print_arts ()
  1807. {
  1808. #ifdef DEBUG
  1809. X    int i;
  1810. X
  1811. X    if (! debug)
  1812. X        return;
  1813. X
  1814. X    for (i = 0; i < top; i++) {    /* for each group */
  1815. X        debug_print_header (&arts[i]);
  1816. X    }
  1817. #endif
  1818. }
  1819. X
  1820. X
  1821. void debug_print_header (s)
  1822. X    struct article_t *s;
  1823. {
  1824. #ifdef DEBUG
  1825. X    FILE *fp;
  1826. X
  1827. X    if (! debug)
  1828. X        return;
  1829. X
  1830. X    if ((fp = fopen ("/tmp/DUMP","a+")) != NULL) {
  1831. X        fprintf (fp,"art=[%5ld] killed=[%s]\n", s->artnum,
  1832. X            (s->tagged ? "TRUE" : "FALSE"));
  1833. X        fprintf (fp,"subj=[%-38s]\n", s->subject);
  1834. X        fprintf (fp,"from=[%s]  name=[%s]\n", s->from, s->name);
  1835. X         if (s->archive) {
  1836. X             fprintf (fp, "arch=[%-38s]  ", s->archive);
  1837. X         } else {
  1838. X             fprintf (fp, "arch=[]  ");
  1839. X         }
  1840. X         if (s->part) {
  1841. X             fprintf (fp, "part=[%s]  ", s->part);
  1842. X         } else {
  1843. X             fprintf (fp, "part=[]  ");
  1844. X         }
  1845. X         if (s->patch) {
  1846. X             fprintf (fp, "patch=[%s]\n", s->patch);
  1847. X        } else {
  1848. X             fprintf (fp, "patch=[]\n");
  1849. X         }
  1850. X        fprintf (fp,"thread=[%d]  inthread=[%d]  unread=[%d]\n",
  1851. X            s->thread, s->inthread, s->unread);
  1852. /*        fprintf (fp,"thread=[%s]  inthread=[%s]  unread=[%s]\n",
  1853. X            (s->thread == ART_NORMAL ? "ART_NORMAL" : "ART_EXPIRED"),
  1854. X            (s->inthread ? "TRUE" : "FALSE"),
  1855. X            (s->unread ? "TRUE" : "FALSE"));
  1856. */
  1857. X        fflush (fp);
  1858. X        fclose (fp);
  1859. X        chmod ("/tmp/DUMP", 0666);
  1860. X    }
  1861. #endif
  1862. }
  1863. X
  1864. X
  1865. void debug_print_comment (comment)
  1866. X    char *comment;
  1867. {
  1868. #ifdef DEBUG
  1869. X    FILE *fp;
  1870. X
  1871. X    if (! debug)
  1872. X        return;
  1873. X
  1874. X    if ((fp = fopen ("/tmp/BASE","a+")) != NULL) {
  1875. X        fprintf (fp,"\n%s\n\n", comment);
  1876. X        fflush (fp);
  1877. X        fclose (fp);
  1878. X        chmod ("/tmp/BASE", 0666);
  1879. X    }
  1880. #endif
  1881. }
  1882. X
  1883. X
  1884. void debug_print_base ()
  1885. {
  1886. #ifdef DEBUG
  1887. X    FILE *fp;
  1888. X    int i;
  1889. X
  1890. X    if (! debug)
  1891. X        return;
  1892. X
  1893. X    if ((fp = fopen ("/tmp/BASE","a+")) != NULL) {
  1894. X        for (i = 0; i < top_base; i++) {
  1895. X            fprintf (fp, "base[%3d]=[%5ld]\n",i,base[i]);
  1896. X        }
  1897. X        fflush (fp);
  1898. X        fclose (fp);
  1899. X        chmod ("/tmp/BASE", 0666);
  1900. X    }
  1901. #endif
  1902. }
  1903. X
  1904. X
  1905. void debug_print_active ()
  1906. {
  1907. #ifdef DEBUG
  1908. X    FILE *fp;
  1909. X    int i;
  1910. X
  1911. X    if (! debug)
  1912. X        return;
  1913. X
  1914. X    if ((fp = fopen ("/tmp/ACTIVE","w")) != NULL) {
  1915. X        for (i = 0; i < num_active; i++) {    /* for each group */
  1916. X            fprintf (fp, "[%4d]=[%-28s] max=[%4ld] min=[%4ld] mod=[%c] nxt=[%4d] flag=[%d] read=[%d] thread=[%d]\n",
  1917. X                i, active[i].name, active[i].max, active[i].min,
  1918. X                active[i].moderated, active[i].next, active[i].flag,
  1919. X                active[i].read, active[i].thread);
  1920. X        }
  1921. X        fflush (fp);
  1922. X        fclose (fp);
  1923. X        chmod ("/tmp/ACTIVE", 0666);
  1924. X    }
  1925. #endif
  1926. }
  1927. X
  1928. X
  1929. void log_user ()
  1930. {
  1931. #ifdef LOG_USER
  1932. X    char buf[33];
  1933. X    FILE *fp;
  1934. X    long epoch;
  1935. X    extern struct passwd *myentry;
  1936. X
  1937. X    if ((fp = fopen (LOG_USER_FILE, "a+")) != NULL) {
  1938. X        time (&epoch);
  1939. X        my_strncpy (buf, myentry->pw_gecos, 32);
  1940. X        fprintf (fp, "%s%d: %-32s (%-8s) %s", VERSION, PATCHLEVEL,
  1941. X                buf, myentry->pw_name, ctime (&epoch));
  1942. X        fclose (fp);
  1943. X        chmod (LOG_USER_FILE, 0666);
  1944. X    }
  1945. #endif
  1946. }
  1947. SHAR_EOF
  1948. chmod 0600 debug.c ||
  1949. echo 'restore of debug.c failed'
  1950. Wc_c="`wc -c < 'debug.c'`"
  1951. test 3249 -eq "$Wc_c" ||
  1952.     echo 'debug.c: original size 3249, current size' "$Wc_c"
  1953. rm -f _shar_wnt_.tmp
  1954. fi
  1955. # ============= feed.c ==============
  1956. if test -f 'feed.c' -a X"$1" != X"-c"; then
  1957.     echo 'x - skipping feed.c (File already exists)'
  1958.     rm -f _shar_wnt_.tmp
  1959. else
  1960. > _shar_wnt_.tmp
  1961. echo 'x - extracting feed.c (Text)'
  1962. sed 's/^X//' << 'SHAR_EOF' > 'feed.c' &&
  1963. /*
  1964. X *  Project   : tin - a threaded Netnews reader
  1965. X *  Module    : feed.c
  1966. X *  Author    : I.Lea
  1967. X *  Created   : 31-08-91
  1968. X *  Updated   : 31-01-92
  1969. X *  Notes     : provides same interface to mail,pipe,print and save commands
  1970. X *  Copyright : (c) Copyright 1991-92 by Iain Lea
  1971. X *              You may  freely  copy or  redistribute  this software,
  1972. X *              so  long as there is no profit made from its use, sale
  1973. X *              trade or  reproduction.  You may not change this copy-
  1974. X *              right notice, and it must be included in any copy made
  1975. X */
  1976. X
  1977. #include    "tin.h"
  1978. X
  1979. extern char *glob_group;            /* Group name */
  1980. extern char note_h_date[LEN];        /* Date:    */
  1981. extern char note_h_subj[LEN];        /* Subject:    */
  1982. extern FILE *note_fp;                /* the body of the current article */
  1983. extern int note_end;                /* end of article ? */
  1984. extern int note_page;                /* what page we're on */
  1985. extern long note_mark[MAX_PAGES];    /* ftells on beginnings of pages */
  1986. X
  1987. char default_mail_address[LEN];
  1988. char default_pipe_command[LEN];
  1989. char default_save_file[LEN];
  1990. char default_regex_pattern[LEN];
  1991. char proc_ch_default;                /* set in change_rcfile () */
  1992. X
  1993. X
  1994. void feed_articles (function, level, prompt, respnum, group_path)
  1995. X    int function;
  1996. X    int level;
  1997. X    char *prompt;
  1998. X    int respnum;
  1999. X    char *group_path;
  2000. {
  2001. X    char address[LEN];
  2002. X    char command[LEN];
  2003. X    char file[LEN], *p;
  2004. X    char mailbox[LEN];
  2005. X    char pattern[LEN];
  2006. X    char ch = 'a', ch_default = 'a';
  2007. X    char proc_ch = proc_ch_default;
  2008. X    FILE *fp;
  2009. X    int b, i, j, count = 1;
  2010. X    int is_mailbox = FALSE;
  2011. X    int orig_note_end;
  2012. X    int orig_note_page;
  2013. X    int patlen;
  2014. X    int ret1 = FALSE;
  2015. X    int ret2 = FALSE;
  2016. X    int redraw_screen = FALSE;
  2017. X    
  2018. X    if (level == PAGE_LEVEL) {
  2019. X        orig_note_end = note_end;
  2020. X        orig_note_page = note_page;
  2021. X    }
  2022. X
  2023. X    b = which_thread (respnum);
  2024. X
  2025. X    if (num_of_tagged_files) {
  2026. X        ch_default = 'T';
  2027. X    }
  2028. X    if (! num_of_tagged_files && num_of_responses (b)) {
  2029. X        ch_default = 't';
  2030. X    }
  2031. X
  2032. X    if ((save_archive_name == FALSE || arts[respnum].archive == (char *) 0) ||
  2033. X        (save_archive_name == TRUE && function != FEED_SAVE) ||
  2034. X        ch_default == 'T') {
  2035. X        do {
  2036. X            sprintf (msg, "%s%s%c", prompt, txt_art_thread_regex_tag, ch_default);
  2037. X            wait_message (msg);
  2038. X            MoveCursor (LINES, (int) strlen (msg)-1);
  2039. X            if ((ch = (char) ReadCh ()) == CR)
  2040. X                ch = ch_default;
  2041. X        } while (ch != ESC && ch != 'a' && ch != 't' && ch != 'T' && ch != 'r' && ch != 'e');
  2042. X    } else {
  2043. X        file[0] = '\0';
  2044. X        ch = ch_default;
  2045. X        if (str_str (glob_group, "sources", 7)) {
  2046. X            proc_ch = 's';        /* *source* group */ 
  2047. X        } else if (str_str (glob_group, "binaries", 8)) {
  2048. X            proc_ch = 'u';        /* *binaries* group */
  2049. X        } else {
  2050. X            proc_ch = 's';
  2051. X        }
  2052. X    }
  2053. X
  2054. X    if (ch == 'e' || ch == ESC) {    /* exit */
  2055. X        clear_message ();
  2056. X        return;
  2057. X    }
  2058. X    
  2059. X    if (ch == 'r') {
  2060. X        sprintf (msg, txt_feed_pattern, default_regex_pattern);
  2061. X        if (! prompt_string (msg, pattern)) {
  2062. X            clear_message ();
  2063. X            return;
  2064. X        }    
  2065. X        if (strlen (pattern)) {
  2066. X            my_strncpy (default_regex_pattern, pattern, LEN);
  2067. X        } else {
  2068. X            if (default_regex_pattern[0]) {
  2069. X                my_strncpy (pattern, default_regex_pattern, LEN);
  2070. X            } else {
  2071. X                info_message (txt_no_match);
  2072. X                return;
  2073. X            }
  2074. X        }
  2075. X    }
  2076. X
  2077. X    switch (function) {
  2078. X        case FEED_MAIL:
  2079. X            sprintf (msg, txt_mail_art_to, default_mail_address);
  2080. X            if (! prompt_string (msg, address)) {
  2081. X                clear_message ();
  2082. X                return;
  2083. X            }    
  2084. X            if (strlen (address)) {
  2085. X                strcpy (default_mail_address, address);
  2086. X            } else {
  2087. X                if (default_mail_address[0]) {
  2088. X                    strcpy (address, default_mail_address);
  2089. X                } else {
  2090. X                    info_message (txt_no_mail_address);    
  2091. X                    return;
  2092. X                }
  2093. X            }
  2094. X            break;
  2095. X        case FEED_PIPE:
  2096. X            sprintf (msg, txt_pipe_to_command, default_pipe_command);
  2097. X            if (! prompt_string (msg, command)) {
  2098. X                clear_message ();
  2099. X                return;
  2100. X            }
  2101. X            if (strlen (command)) {
  2102. X                strcpy (default_pipe_command, command);
  2103. X            } else {
  2104. X                if (default_pipe_command[0]) {
  2105. X                    strcpy (command, default_pipe_command);
  2106. X                } else {
  2107. X                    info_message (txt_no_command);    
  2108. X                    return;
  2109. X                }
  2110. X            }
  2111. X
  2112. X            if ((fp = popen (command, "w")) == NULL) {
  2113. X                error_message (txt_command_failed_s, command);
  2114. X                return;
  2115. X            }
  2116. X            wait_message (txt_piping);
  2117. X            Raw (FALSE);
  2118. X            break;
  2119. X        case FEED_PRINT:    
  2120. X            if (default_printer) {
  2121. #ifdef SINIX
  2122. X                    sprintf (command, "%s -dru=%s %s",
  2123. X                        printer, get_val ("PRINTER","ps0"), redirect_output);
  2124. #else
  2125. X                    sprintf (command, "%s -P%s %s",
  2126. X                        printer, get_val ("PRINTER","ps0"), redirect_output);
  2127. #endif
  2128. X            } else {
  2129. X                if (cmd_line_printer[0]) {
  2130. X                    sprintf (command, "%s %s",
  2131. X                        cmd_line_printer, redirect_output);
  2132. X                } else {
  2133. X                    sprintf (command, "%s %s",
  2134. X                        printer, redirect_output);
  2135. X                }
  2136. X            }
  2137. X            if ((fp = popen (command, "w")) == NULL) {
  2138. X                error_message (txt_command_failed_s, command);
  2139. X                return;
  2140. X            }
  2141. X            break;
  2142. X        case FEED_SAVE:        /* ask user for filename */
  2143. X            free_save_array ();
  2144. X            if ((save_archive_name == FALSE || arts[respnum].archive == (char *) 0)) {
  2145. X                sprintf (msg, txt_save_filename, default_save_file);
  2146. X                if (! prompt_string (msg, file)) {
  2147. X                    clear_message ();
  2148. X                    return;
  2149. X                }
  2150. X                if (strlen (file)) {
  2151. X                    strcpy (default_save_file, file);
  2152. SHAR_EOF
  2153. true || echo 'restore of feed.c failed'
  2154. fi
  2155. echo 'End of tin1.1 part 3'
  2156. echo 'File feed.c is continued in part 4'
  2157. echo 4 > _shar_seq_.tmp
  2158. exit 0
  2159.  
  2160. --
  2161. NAME   Iain Lea
  2162. EMAIL  iain%estevax.uucp@unido.Informatik.Uni-Dortmund.DE
  2163. SNAIL  Bruecken Strasse 12, 8500 Nuernberg 90, Germany
  2164. PHONE  +49-911-331963 (home)  +49-911-3089-407 (work)
  2165. -- 
  2166.  Dr. med. dipl.-math Dieter Becker           Tel.: (0 / +49) 6841 - 16 3046
  2167.  Medizinische Universitaets- und Poliklinik  Fax.: (0 / +49) 6841 - 16 3369
  2168.  Innere Medizin III                         
  2169.  D - 6650 Homburg / Saar                     Email: becker@med-in.uni-sb.de
  2170. exit 0 # Just in case...
  2171.