home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume29 / tin / part03 < prev    next >
Text File  |  1992-03-28  |  52KB  |  1,839 lines

  1. Newsgroups: comp.sources.misc
  2. From: iain%anl433.uucp@germany.eu.net (Iain J. Lea)
  3. Subject:  v29i021:  tin - threaded full screen newsreader v1.1P1, Part03/12
  4. Message-ID: <1992Mar27.033012.2189@sparky.imd.sterling.com>
  5. X-Md4-Signature: 7ac252288dcd0d07398f2b1d1636718c
  6. Date: Fri, 27 Mar 1992 03:30:12 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: iain%anl433.uucp@germany.eu.net (Iain J. Lea)
  10. Posting-number: Volume 29, Issue 21
  11. Archive-name: tin/part03
  12. Environment: BSD, SCO, ISC, SUNOS, SYSVR3, SYSVR4, ULTRIX, XENIX
  13. Supersedes: tin: Volume 28, Issue 45-55
  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
  38. X     KK         Mark thread as read and advance to next unread thread.
  39. X
  40. X     mm         Mail current article / thread / articles matching pattern
  41. X               / tagged articles to someone.
  42. X
  43. X     MM         User configurable options menu (for more information see
  44. X               section Options Menu).
  45. X
  46. X     nn         Go to the next article.
  47. X
  48. X     NN         Go to the next unread article.
  49. X
  50. X     oo         Output current article / thread / articles matching
  51. X               pattern / tagged articles to printer.
  52. X
  53. X     oo         Output article/thread/tagged articles to printer.
  54. X
  55. X     pp         Go to the previous article.
  56. X
  57. X     PP         Go to the previous unread article.
  58. X
  59. X     qq         Quit tin.
  60. X
  61. X     rr         Reply through mail to author.
  62. X
  63. X     RR         Reply through mail to author with a copy of the current
  64. X
  65. X
  66. X
  67. X
  68. 10                            Release 4.1R                       NEWS-OS
  69. X
  70. X
  71. X
  72. X
  73. X
  74. TIN(1)                           LOCAL                            TIN(1)
  75. X
  76. X
  77. X
  78. X               article included.
  79. X
  80. X     ss         Save current article / thread / articles matching pattern
  81. X               / tagged articles to file / files / mailbox. To save to a
  82. X               mailbox enter '=' or '=mailbox' when asked for filename
  83. X               to save to. To save in <newsgroup name>/<filename> format
  84. X               enter '+filename'. Environment variables are allowed
  85. X               within a filename (ie. $SOURCES/dir/filename).
  86. X
  87. X     tt         Return to group selection index.
  88. X
  89. X     vv         Print tin version number.
  90. X
  91. X     ww         Post an article to current group.
  92. X
  93. X     WW         List articles posted by user. The date posted, the
  94. X               newsgroup and the subject are listed.
  95. X
  96. X     zz         Mark article as unread.
  97. X
  98. X     //         Article forward search.
  99. X
  100. X     ??         Article backward search
  101. X
  102. X     ||         Pipe current article / thread / articles matching pattern
  103. X               / tagged articles into command.
  104. X
  105. X     <<         Goto the first article in the current thread.
  106. X
  107. X     >>         Goto the last article in the current thread.
  108. X
  109. OOPPTTIIOONNSS MMEENNUU
  110. X     This menu is accessed by pressing 'M' at all levels. It allows the
  111. X     user to customize the behaviour of tin. The options are saved to
  112. X     the file $_H_O_M_E/._t_i_n/_t_i_n_r_c. Use <SPACE> to toggle the required
  113. X     option and <CR> to set.
  114. X
  115. X     AAuuttoo ssaavvee
  116. X         Automatically save articles/threads by Archive-name: line in
  117. X         article header. This is useful to set ON in conjunction with
  118. X         'Save separate'.
  119. X
  120. X     SSaavvee sseeppaarraattee
  121. X         Save articles/threads to separate files. Set ON if saving
  122. X         source code.  Set OFF if saving a conversational thread.
  123. X
  124. X     MMaarrkk ssaavveedd rreeaadd
  125. X         This allows saved articles/threads to be automatically marked
  126. X         as having been read.
  127. X
  128. X     KKiillll aarrttiicclleess
  129. X         This allows the user to kill articles that match entries in the
  130. X
  131. X
  132. X
  133. X
  134. NEWS-OS                       Release 4.1R                            11
  135. X
  136. X
  137. X
  138. X
  139. X
  140. TIN(1)                           LOCAL                            TIN(1)
  141. X
  142. X
  143. X
  144. X         kill file $_H_O_M_E/._t_i_n/_k_i_l_l.
  145. X
  146. X     DDrraaww aarrrrooww
  147. X         Allows groups/articles to be selected by an arrow '->' if set
  148. X         ON or by an highlighted bar if set OFF.
  149. X
  150. X     PPrriinntt hheeaaddeerr
  151. X         This allows the complete mail header or only the Siubject: and
  152. X         From: fields to be output when printing articles.
  153. X
  154. X     GGoottoo 11sstt uunnrreeaadd
  155. X         This allows the cursor to be placed at the first / last unread
  156. X         article upon entering a newsgroup with unread news.
  157. X
  158. X     SSccrroollll ffuullll ppaaggee
  159. X         If set ON scrolling of groups/articles will be a full page at a
  160. X         time, otherwise half a page at a time.
  161. X
  162. X     CCaattcchhuupp oonn qquuiitt
  163. X         If set ON the user is asked when quitting if all groups read
  164. X         during the current session should be marked read.
  165. X
  166. X     TThhrreeaadd aarrttiicclleess
  167. X         If set ON articles will be threaded in all groups (default),
  168. X         otherwise articles will be shown unthreaded. If set ON but
  169. X         certain user specified groups are in $_H_O_M_E/._t_i_n/_u_n_t_h_r_e_a_d, the
  170. X         specified groups will be unthreaded and the rest will be
  171. X         threaded.
  172. X
  173. X     SShhooww oonnllyy uunnrreeaadd
  174. X         If set ON show only new/unread articles, otherwise show all
  175. X         articles.
  176. X
  177. X     SShhooww AAuutthhoorr
  178. X         If set 'None' only the Subject: line will be displayed. If set
  179. X         'Addr' Subject: line & the address part of the From: line are
  180. X         displayed. If set 'Name' Subject: line & the authors full name
  181. X         part of the From: line are displayed. If set 'Both' Subject:
  182. X         line & all of the From: line are displayed.
  183. X
  184. X     PPrroocceessss ttyyppee
  185. X         This specifies the default type of post processing to perform
  186. X         on saved articles. The following types of processing are
  187. X         allowed:
  188. X             -none.
  189. X             -unpacking of multi-part shell archives.
  190. X             -unpacking of multi-part uuencoded files.
  191. X             -unpacking of multi-part uuencoded files that produce a
  192. X              *.zoo archive whose contents is listed.
  193. X             -unpacking of multi-part uuencoded files that produce a
  194. X              *.zoo archive whose contents is extracted.
  195. X
  196. X
  197. X
  198. X
  199. X
  200. 12                            Release 4.1R                       NEWS-OS
  201. X
  202. X
  203. X
  204. X
  205. X
  206. TIN(1)                           LOCAL                            TIN(1)
  207. X
  208. X
  209. X
  210. X     SSoorrtt aarrttiicclleess bbyy
  211. X         This specifies how articles should be sorted. The following
  212. X         sort types are allowed:
  213. X             -don't sort articles (default).
  214. X             -sort articles by Subject: field (ascending & descending).
  215. X             -sort articles by From: field (ascending & descending).
  216. X             -sort articles by Date: field (ascending & descending).
  217. X
  218. X     SSaavvee ddiirreeccttoorryy
  219. X         The directory where articles/threads are to be saved. Default
  220. X         is $_H_O_M_E/_N_e_w_s.
  221. X
  222. X     MMaaiill ddiirreeccttoorryy
  223. X         The directory where articles/threads are to be saved in mailbox
  224. X         format.  This feature is mainly for use with the Elm mail
  225. X         program. It allows the user to save articles/threads/groups
  226. X         simply by giving '=' as the filename to save to.
  227. X
  228. X     PPrriinntteerr
  229. X         The printer program with options that is to be used to print
  230. X         articles. Default is lpr for BSD machines and lp for SysV
  231. X         machines.
  232. X
  233. KKIILLLL AARRTTIICCLLEE MMEENNUU
  234. X     This menu is accessed by pressing '^K' at the group and page
  235. X     levels. It allows the user to kill an article that matches the
  236. X     current Subject: line, From: line or a string entered by the user.
  237. X     The user entered string can be applied to the Subject: or From:
  238. X     lines of an article. The kill description can be limited to the
  239. X     current newsgroup or it can apply to all newsgroups.  Once entered
  240. X     the user can abort the command and not save the kill description,
  241. X     edit the kill file or save the kill description.
  242. X
  243. X     On starting tin the users killfile $_H_O_M_E/._t_i_n/_k_i_l_l is read and on
  244. X     entering a newsgroup any kill descriptions are applied. Articles
  245. X     that match a kill description are marked killed and are not
  246. X     displayed.
  247. X
  248. X     The 'Kill articles' option needs to be set ON in the Options Menu
  249. X     (selected by 'M' at any level) to activate this command.
  250. X
  251. PPOOSSTTIINNGG AARRTTIICCLLEESS
  252. X     Tin allows posting of articles, follow-up to already posted
  253. X     articles and replying direct through mail to the author of an
  254. X     article.
  255. X
  256. X     Use the 'w' command to post an article to a newsgroup. After
  257. X     entering the post subject the default editor (ie. vi) or the editor
  258. X     specified by the $VISUAL environment variable will be started and
  259. X     the article can be entered. To crosspost articles simply add a
  260. X     comma and the name of the newsgroup(s) to the end of the
  261. X     Newsgroups: line at the beginning of the article. After saving and
  262. X
  263. X
  264. X
  265. X
  266. NEWS-OS                       Release 4.1R                            13
  267. X
  268. X
  269. X
  270. X
  271. X
  272. TIN(1)                           LOCAL                            TIN(1)
  273. X
  274. X
  275. X
  276. X     exiting the editor you are asked if you wish to a)bort posting the
  277. X     article, e)dit the article again or p)ost the article to the
  278. X     specified newsgroup(s).
  279. X
  280. X     Use the 'W' command to display a history of the articles you have
  281. X     posted.  The date the article was posted, which newsgroups the
  282. X     article was posted to and the articles subject line are displayed.
  283. X
  284. X     Use the 'f' / 'F' command to post a follow-up article to an already
  285. X     posted article. The 'F' command will copy the text of the original
  286. X     article into the editor. The editing procedure is the same as when
  287. X     posting an article with the 'w' command.
  288. X
  289. X     Use the 'r' / 'R' command to reply direct through mail to the
  290. X     author of an already posted article. The 'R' command will copy the
  291. X     text of the original article into the editor. The editing procedure
  292. X     is the same as when posting an article with the 'w' command. After
  293. X     saving and exiting the editor you are asked if you wish to a)bort
  294. X     sending the article, e)dit the article again or s)end the article
  295. X     to the author.
  296. X
  297. MMAAIILLIINNGG PPIIPPIINNGG PPRRIINNTTIINNGG AANNDD SSAAVVIINNGG AARRTTIICCLLEESS
  298. X     The command interface to mail ('m'), pipe ('|'), print ('o') and
  299. X     save ('s') articles is the same for ease of use.
  300. X
  301. X     The initial command will ask you to select which a)rticle, t)hread,
  302. X     r)egex pattern, t)agged articles you wish to mail, pipe etc.
  303. X
  304. X     Tagged articles must have already been tagged with the 'T' command.
  305. X     All tagged articles can be untagged by the 'U' untag command.
  306. X
  307. X     If regex pattern matching is selected you are asked to enter a
  308. X     regular expression (ie. to match all articles subject lines
  309. X     containing 'net News' you must enter '*net News*'). Any articles
  310. X     that match the entered expression will be mailed, piped etc.
  311. X
  312. X     To save articles to a mailbox with the name of the current
  313. X     newsgroup (ie. Alt.sources) enter '=' or '=<mailbox name>' when
  314. X     asked for the save filename.
  315. X
  316. X     To save articles in <newsgroup name>/<filename> format enter
  317. X     '+<filename>'.
  318. X
  319. X     When saving articles you can specify whether the saved files should
  320. X     be post processed (ie. unshar shell archive, uudecode multiple
  321. X     parts etc).  A default process type can be set by the 'Process
  322. X     type:' in the 'M' options menu.
  323. X
  324. AAUUTTOOMMAATTIICC MMAAIILLIINNGG AANNDD SSAAVVIINNGG NNEEWW NNEEWWSS
  325. X     Tin allows new/unread news articles to be mailed (-M option)/saved
  326. X     (-S option) in batch mode for later reading. Useful when going on
  327. X     holiday and you don't want to return and find that expire has
  328. X
  329. X
  330. X
  331. X
  332. 14                            Release 4.1R                       NEWS-OS
  333. X
  334. X
  335. X
  336. X
  337. X
  338. TIN(1)                           LOCAL                            TIN(1)
  339. X
  340. X
  341. X
  342. X     removed a whole load of unread articles. Best to run from crontab
  343. X     everyday while away, after which you will be mailed a report of
  344. X     which articles were mailed/saved from which newsgroups and the
  345. X     total number of articles mailed/saved.  Articles are saved in a
  346. X     private news structure under your <savedir> directory (default is
  347. X     $_H_O_M_E/_N_e_w_s). Be careful of using this option if you read a lot of
  348. X     groups because you could overflow your filesystem. If you only want
  349. X     to save a few groups it would be best to backup your full
  350. X     $_H_O_M_E/._n_e_w_s_r_c and create a new one that only contains the
  351. X     newsgroups you want to mail/save.  Saved news can be read later by
  352. X     starting tin with the -R option.
  353. X
  354. X     tin -M iain -f newsrc.mail (mail any unread articles in newgroups
  355. X     specified in file newsrc.mail)
  356. X
  357. X     tin -S -f newsrc.save (save any unread articles in newgroups
  358. X     specified in file newsrc.save)
  359. X
  360. X     tin -R (read any unread articles saved by tin -S option)
  361. X
  362. SSIIGGNNAATTUURREESS
  363. X     Tin will recognize a signature in either $_H_O_M_E/._s_i_g_n_a_t_u_r_e or
  364. X     $_H_O_M_E/._S_i_g. If $_H_O_M_E/._s_i_g_n_a_t_u_r_e exists, then the signature will be
  365. X     pulled into the editor for Tin mail commands.  A signature in
  366. X     $_H_O_M_E/._s_i_g_n_a_t_u_r_e will not be pulled into the editor for posting
  367. X     commands since the inews program will append the signature itself.
  368. X
  369. X     A signature in $_H_O_M_E/._S_i_g will be pulled into the editor for both
  370. X     posting and mailing commands.
  371. X
  372. X     The following is an example of a $_H_O_M_E/._S_i_g file:
  373. X          NAME   Iain Lea
  374. X          EMAIL  iain%anl433.uucp@germany.eu.net
  375. X          SNAIL  Bruecken Strasse 12, 8500 Nuernberg 90, Germany
  376. X          PHONE  +49-911-331963 (home)  +49-911-3089-407 (work)
  377. X
  378. EENNVVIIRROOMMEENNTT VVAARRIIAABBLLEESS
  379. X     TTIINNDDIIRR
  380. X          Define this variable if you do not want tin's .tin directory
  381. X          in $HOME/.tin.  (ie. if you want all tin's private files in
  382. X          /tmp/.tin you would set TINDIR to contain /tmp.
  383. X
  384. X     NNNNTTPPSSEERRVVEERR
  385. X          The default NNTP server to remotely read news from. This
  386. X          variable only needs to be set if the -r command line option is
  387. X          specified and the file /_e_t_c/_n_n_t_p_s_e_r_v_e_r does not exist.
  388. X
  389. X     OORRGGAANNIIZZAATTIIOONN
  390. X          Set the mail header field Organization: to the contents of the
  391. X          variable instead of the system default. This variable has
  392. X          precedence over the file $_H_O_M_E/._t_i_n/_o_r_g_a_n_i_z_a_t_i_o_n that may also
  393. X          contain an organization string.
  394. X
  395. X
  396. X
  397. X
  398. NEWS-OS                       Release 4.1R                            15
  399. X
  400. X
  401. X
  402. X
  403. X
  404. TIN(1)                           LOCAL                            TIN(1)
  405. X
  406. X
  407. X
  408. X     RREEPPLLYYTTOO
  409. X          Set the mail header field Reply-To: to the return address
  410. X          specified by the variable.  This is useful if the machine is
  411. X          not registered in the UUCP mail maps or if you wish to recieve
  412. X          replies at a different machine.  This variable has precedence
  413. X          over the file $_H_O_M_E/._t_i_n/_r_e_p_l_y_t_o that may also contain a
  414. X          return address.
  415. X
  416. X     AADDDD_AADDDDRREESSSS
  417. X          This can contain an address to append to the return address
  418. X          when replying directly through mail to somebody whose mail
  419. X          address is not directly recognized by the local host. For
  420. X          example say the return address is _u_s_e_r@_b_i_g_v_a_x, but _b_i_g_v_a_x is
  421. X          not recognized by your host, so therfore the mail will not
  422. X          reach _u_s_e_r. But the host _l_i_t_t_e_v_a_x is known to recognize your
  423. X          host and _b_i_g_v_a_x, so if ADD_ADDRESS is set (ie. 'setenv
  424. X          ADD_ADDRESS @littevax' for csh or 'set ADD_ADDRESS @littevax'
  425. X          and 'export ADD_ADDRESS' for sh) the address
  426. 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 reach
  427. X          _u_s_e_r@_b_i_g_v_a_x.  This variable has precedence over the file
  428. X          $_H_O_M_E/._t_i_n/_a_d_d__a_d_d_r_e_s_s that may also contain an address.
  429. X
  430. X     BBUUGG_AADDDDRREESSSS
  431. X          If the 'B' command bug report mail address is not correct this
  432. X          variable should be set to the correct mail address. This
  433. X          variable has precedence over the file $_H_O_M_E/._t_i_n/_b_u_g__a_d_d_r_e_s_s
  434. X          that may also contain a mail address.
  435. X
  436. X     VVIISSUUAALL
  437. X          This variable has precedence over the default editor (ie. vi)
  438. X          that is used in all editing operations within tin (ie. posting
  439. X          'w', replying 'rR', follow-ups 'fF' and bug reports 'B').
  440. X
  441. TTIIPPSS AANNDD TTRRIICCKKSS
  442. X     The following newsgroups provide useful information concerning news
  443. X     software:
  444. X         -news.software.readers (info. about news user agents
  445. X          tin,rn,nn,vn etc.)
  446. X         -news.software.nntp (info. about NNTP)
  447. X         -news.software.b (info. about news transport agents Bnews &
  448. X          Cnews)
  449. X
  450. X     Many prompts (ie. 'Mark everything as read? (y/n): y') within tin
  451. X     offer a default choice that the cursor is positioned on. By
  452. X     pressing <CR> the default value is taken.
  453. X
  454. X     When tin is run in an xterm window it will resize itself each time
  455. X     the xterm is resized.
  456. X
  457. X     Tin will reread the active file at set intervals to show any new
  458. X     news.
  459. X
  460. X
  461. X
  462. X
  463. X
  464. 16                            Release 4.1R                       NEWS-OS
  465. X
  466. X
  467. X
  468. X
  469. X
  470. TIN(1)                           LOCAL                            TIN(1)
  471. X
  472. X
  473. X
  474. FFIILLEESS
  475. X     $_H_O_M_E/._n_e_w_s_r_c             subscribed to newgroups.
  476. X     $_H_O_M_E/._t_i_n/_t_i_n_r_c          options.
  477. X     $_H_O_M_E/._t_i_n/._i_n_d_e_x         newsgroup index files directory.
  478. 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.
  479. X     $_H_O_M_E/._t_i_n/_a_c_t_i_v_e         used by -n option for notifying user of new groups.
  480. X     $_H_O_M_E/._t_i_n/_b_u_g__a_d_d_r_e_s_s    address to send bug reports to.
  481. X     $_H_O_M_E/._t_i_n/_k_i_l_l           kill file.
  482. 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.
  483. X     $_H_O_M_E/._t_i_n/_p_o_s_t_e_d         history of articles posted by user.
  484. X     $_H_O_M_E/._t_i_n/_r_e_p_l_y_t_o        host address to use in Reply-To: mail header.
  485. X     $_H_O_M_E/._t_i_n/_u_n_t_h_r_e_a_d       contains groups that are not to be threaded.
  486. X     $_H_O_M_E/._s_i_g_n_a_t_u_r_e          signature.
  487. X     $_H_O_M_E/._S_i_g                signature.
  488. X
  489. BBUUGGSS
  490. X     There are bugs somewhere among the creeping featurism. Any bugs
  491. X     found should be reported by the 'B' (bug report) command.
  492. X
  493. X     There is a bug when article killing is switched ON/OFF at article
  494. X     page level and the 't' command is used to return to group selection
  495. X     index.
  496. X
  497. X     When articles have been unkilled, all articles will be marked
  498. X     unread even if they have already been read.
  499. X
  500. X     Killing articles when tin is setuid causes strange behaviour.
  501. X
  502. X     Will not uudecode some of the images in alt.binaries.pictures
  503. X     because more than one image is in the multi-part file to uudecode.
  504. X     Only the first image will be uudecoded.
  505. X
  506. X     Does not yet handle Xref: headers for cross-posted articles.
  507. X
  508. HHIISSTTOORRYY
  509. X     Based on the tass newsreader that was developed by Rich Skrenta and
  510. X     posted to alt.sources in March 1991. Tass was itself heavily
  511. X     infleuenced by NOTES which was developed at the University of
  512. X     Illinois in the early 1980's.
  513. X
  514. X     Tin v1.00 (full distribution) was posted in 8 parts to alt.sources
  515. X     on 23 Aug 1991.
  516. X     Tin v1.0 PL1 (full distribution) was posted in 8 parts to
  517. X     alt.sources on 03 Sep 1991.
  518. X     Tin v1.0 PL2 (full distribution) was posted in 9 parts to
  519. X     alt.sources on 24 Sep 1991.
  520. X     Tin v1.0 PL3 (patch) was posted in 4 parts to alt.sources on 30 Sep
  521. X     1991.
  522. X     Tin v1.0 PL4 (patch) was posted in 2 parts to alt.sources on 02 Oct
  523. X     1991.
  524. X     Tin v1.0 PL5 (patch) was posted in 4 parts to alt.sources on 17 Oct
  525. X     1991.
  526. X
  527. X
  528. X
  529. X
  530. NEWS-OS                       Release 4.1R                            17
  531. X
  532. X
  533. X
  534. X
  535. X
  536. TIN(1)                           LOCAL                            TIN(1)
  537. X
  538. X
  539. X
  540. X     Tin v1.0 PL6 (patch) was posted in 5 parts to alt.sources on 27 Nov
  541. X     1991.
  542. X     Tin v1.0 PL7 (patch) was posted in 2 parts to alt.sources on 27 Nov
  543. X     1991.
  544. X     Tin v1.1 PL0 (full distribution) was posted in 11 parts to
  545. X     alt.sources on 13 Feb 1992.
  546. X     Tin v1.1 PL1 (full distribution) was posted in 12 parts to
  547. X     alt.sources on 24 Mar 1992.
  548. X
  549. CCRREEDDIITTSS
  550. X     Rich Skrenta
  551. X          author of tass v3.2 which this newsreader used as its base.
  552. X
  553. X     Dave Taylor
  554. X          author of curses.c from the elm mailreader.
  555. X
  556. X     Rich Salz
  557. X          author of wildmat.c pattern matching routine.
  558. X
  559. X     Chris Thewalt
  560. X          author of getline.c emacs style editing routine.
  561. X
  562. X     Dieter Becker
  563. X          for generously posting certain versions and patches for me
  564. X          when my net connection was removed by a group of very short
  565. X          sighted people.
  566. X
  567. X     I wish to thank the following people for supplying patchs:
  568. X
  569. X     Anton Aylward, Dieter Becker, Dan Berry, Marc Boucher, Robert
  570. X     Claeson, Steven Cogswell, Ned Danieley, Brent Ermlick, Carl Hage,
  571. X     Ed Hanway, Torsten Homeyer, Nelson Kading, Fritz Kleeman, Karl-
  572. X     Koenig Koenigsson, Kris Kugel, Hakan Lennestal, Clifford Luke,
  573. X     Michael Faurot, David MacKenzie, Bill Poitras, Jim Robinson,
  574. X     Nickolay Saukh, Rich Salz, John Sauter, Bart Sears, Karl-Olav
  575. X     Serrander, Doug Sewell, Cliff Stanford, Adri Verhoef, Cary Whitney
  576. X
  577. X     I wish to thank the following people for bug reports/comments:
  578. X
  579. X     Klaus Arzig, Scott Babb, Reiner Balling, Volker Beyer, Roger Binns,
  580. X     Georg Biehler, Ian Brown, Andreas Brosig, Leila Burrell-Davis, Tom
  581. X     Czarnik, David Donovan, Peter Dressler, Gerhard Ermer, Hugh Fader,
  582. X     Joachim Feld, Paul Fox, Bernhard Gmelch, Viet Hoang, Andy Jackson,
  583. X     Joe Johnson, Cyrill Jung, Hans-Juergen Knopp, Per Lindqvist, Bob
  584. X     Lukas, Phillip Molloy, Toni Metz, Greg Miller, Klaus Neuberger,
  585. X     Otto Niesser, Reiner Oelhaf, Wolf Paul, John Palkovic, Andrew
  586. X     Phillips, Ted Richards, Fredy Schwatz, Bernd Schwerin, Klamer
  587. X     Schutte, Chris Smith, Daniel Smith, Steve Spearman, Hironobu
  588. X     Takahashi, Sven Werner
  589. X
  590. AAUUTTHHOORR
  591. X     Iain Lea
  592. X
  593. X
  594. X
  595. X
  596. 18                            Release 4.1R                       NEWS-OS
  597. X
  598. X
  599. X
  600. X
  601. X
  602. TIN(1)                           LOCAL                            TIN(1)
  603. X
  604. X
  605. X
  606. X          (iain%anl433.uucp@germany.eu.net)
  607. X
  608. X
  609. X
  610. X
  611. X
  612. X
  613. X
  614. X
  615. X
  616. X
  617. X
  618. X
  619. X
  620. X
  621. X
  622. X
  623. X
  624. X
  625. X
  626. X
  627. X
  628. X
  629. X
  630. X
  631. X
  632. X
  633. X
  634. X
  635. X
  636. X
  637. X
  638. X
  639. X
  640. X
  641. X
  642. X
  643. X
  644. X
  645. X
  646. X
  647. X
  648. X
  649. X
  650. X
  651. X
  652. X
  653. X
  654. X
  655. X
  656. X
  657. X
  658. X
  659. X
  660. X
  661. X
  662. NEWS-OS                       Release 4.1R                            19
  663. X
  664. X
  665. SHAR_EOF
  666. echo 'File tin.nrf is complete' &&
  667. chmod 0600 tin.nrf ||
  668. echo 'restore of tin.nrf failed'
  669. Wc_c="`wc -c < 'tin.nrf'`"
  670. test 44431 -eq "$Wc_c" ||
  671.     echo 'tin.nrf: original size 44431, current size' "$Wc_c"
  672. rm -f _shar_wnt_.tmp
  673. fi
  674. # ============= active.c ==============
  675. if test -f 'active.c' -a X"$1" != X"-c"; then
  676.     echo 'x - skipping active.c (File already exists)'
  677.     rm -f _shar_wnt_.tmp
  678. else
  679. > _shar_wnt_.tmp
  680. echo 'x - extracting active.c (Text)'
  681. sed 's/^X//' << 'SHAR_EOF' > 'active.c' &&
  682. /*
  683. X *  Project   : tin - a threaded Netnews reader
  684. X *  Module    : active.c
  685. X *  Author    : I.Lea
  686. X *  Created   : 16-02-92
  687. X *  Updated   : 01-03-92
  688. X *  Notes     :
  689. X *  Copyright : (c) Copyright 1991-92 by Iain Lea
  690. X *              You may  freely  copy or  redistribute  this software,
  691. X *              so  long as there is no profit made from its use, sale
  692. X *              trade or  reproduction.  You may not change this copy-
  693. X *              right notice, and it must be included in any copy made
  694. X */
  695. X
  696. #include    "tin.h"
  697. X
  698. int group_hash[TABLE_SIZE];            /* group name --> active[] */
  699. int reread_active_file = FALSE;
  700. X
  701. X
  702. int test_reread = 0;
  703. X
  704. X
  705. /*
  706. X *  Resync active file when SIGALRM signal reeived that
  707. X *  is triggered by alarm (RESYNC_ACTIVE_SECS) call.
  708. X */
  709. X
  710. void resync_active_file ()
  711. {
  712. #ifndef NO_RESYNC_ACTIVE_FILE     
  713. X    if (reread_active_file) {
  714. X        wait_message (txt_reading_active_file);
  715. X        free_active_arrays ();
  716. X        max_active = DEFAULT_ACTIVE_NUM;
  717. X        expand_active ();
  718. X        read_active_file ();
  719. X        read_newsrc (TRUE);
  720. X        reread_active_file = FALSE;
  721. X        alarm (RESYNC_ACTIVE_SECS);        /* reset alarm clock */
  722. X        group_selection_page ();
  723. X        test_reread++;        
  724. X    }
  725. #endif
  726. }
  727. X
  728. /*
  729. X *  Load the active file into active[] and create copy of active ~/.tin/active
  730. X */
  731. X
  732. int read_active_file ()
  733. {
  734. X    FILE *fp;
  735. X    char *p, *q, *r;
  736. X    char buf[LEN];
  737. X    char moderated;
  738. X    int created, i;
  739. X    long h;
  740. X    
  741. X    num_active = 0;
  742. X
  743. X    if ((fp = open_active_fp ()) == NULL) {
  744. X        if (compiled_with_nntp) {
  745. X            sprintf (msg, txt_cannot_open_active_file, active_file, progname);
  746. X            wait_message (msg);
  747. X        } else {
  748. X            printf (txt_cannot_open, active_file);
  749. X            putchar ('\n');
  750. X            fflush (stdout);
  751. X        }
  752. X        exit (1);
  753. X    }
  754. X
  755. X    if (reread_active_file == FALSE && (read_news_via_nntp && update == FALSE)) {
  756. X        wait_message (txt_reading_active_file);
  757. X    }
  758. X
  759. X    for (i = 0; i < TABLE_SIZE; i++) {
  760. X        group_hash[i] = -1;
  761. X    }
  762. X
  763. X    while (fgets (buf, sizeof (buf), fp) != NULL) {
  764. X        for (p = buf; *p && *p != ' '; p++)
  765. X            continue;
  766. X        if (*p != ' ') {
  767. X            error_message (txt_bad_active_file, buf);
  768. X            continue;
  769. X        }
  770. X        *p++ = '\0';
  771. X
  772. X        if (num_active >= max_active) {
  773. X            expand_active ();
  774. X        }
  775. X
  776. X        h = hash_groupname (buf);
  777. X
  778. X        if (group_hash[h] == -1) {
  779. X            group_hash[h] = num_active;
  780. X        } else {                /* hash linked list chaining */
  781. X            for (i=group_hash[h]; active[i].next >= 0; i=active[i].next) {
  782. X                if (strcmp(active[i].name, buf) == 0) {
  783. X                    goto read_active_continue;        /* kill dups */
  784. X                }
  785. X            }
  786. X            if (strcmp(active[i].name, buf) == 0)
  787. X                goto read_active_continue;
  788. X            active[i].next = num_active;
  789. X        }
  790. X
  791. X        for (q = p; *q && *q != ' '; q++)
  792. X            continue;
  793. X        if (*q != ' ') {
  794. X            error_message (txt_bad_active_file, buf);
  795. X            continue;
  796. X        }
  797. X        *q++ = '\0';
  798. X
  799. X        for (r = q; *r && *r != '\n'; r++) {
  800. X            if (*r == 'y' || *r == 'm') {
  801. X                moderated = *r;
  802. X                break;
  803. X            }
  804. X        }
  805. X
  806. X        active[num_active].name = str_dup (buf);
  807. X        active[num_active].max = (long) atol (p);
  808. X        active[num_active].min = (long) atol (q);
  809. X        active[num_active].moderated = moderated;
  810. X        active[num_active].next = -1;            /* hash chaining */
  811. X        active[num_active].flag = UNSUBSCRIBED;    /* not in my_group[] yet */
  812. X        active[num_active].read = FALSE;        /* read/unread */
  813. X        active[num_active].thread = TRUE;        /* thread articles */
  814. X
  815. X        num_active++;
  816. X
  817. read_active_continue:;
  818. X
  819. X    }
  820. X    fclose (fp);
  821. X
  822. X    /*
  823. X     *  exit if active file is empty
  824. X     */
  825. X    if (! num_active) {
  826. X        error_message (txt_active_file_is_empty, active_file);
  827. X        exit (1);
  828. X    }
  829. X
  830. X    /*
  831. X     *  create backup of LIBDIR/active for use by -n option to notify new groups 
  832. X     */
  833. X    created = backup_active (TRUE);
  834. X
  835. X    debug_print_active ();
  836. X
  837. X    if (cmd_line || (read_news_via_nntp && update == FALSE)) {
  838. X        wait_message ("\n");
  839. X    }
  840. X
  841. X    return (created);
  842. }
  843. X
  844. /*
  845. X *  create ~/.tin/active from LIBDIR/active if it does not exist 
  846. X */
  847. X
  848. int backup_active (create)
  849. X    int create;
  850. {
  851. X    char buf[LEN];
  852. X    FILE *fp;
  853. X    int created = FALSE;
  854. X    int i;
  855. X    struct stat sb;
  856. X    
  857. X    set_real_uid_gid ();
  858. X    
  859. X    sprintf (buf, "%s/active", rcdir);
  860. X    
  861. X    if (create) {
  862. X        if (stat (buf, &sb) != -1) {
  863. X            goto backup_active_done;
  864. X        }
  865. X    }
  866. X    
  867. X    if ((fp = fopen (buf, "w")) != NULL) {
  868. X        for (i = 0; i < num_active ; i++) {    /* for each group */
  869. X            fprintf (fp, "%s\n", active[i].name);
  870. X        }
  871. X        fclose (fp);
  872. X        chmod (buf, 0644);
  873. X        created = TRUE;
  874. X    }
  875. X
  876. backup_active_done:
  877. X    set_tin_uid_gid ();
  878. X    return (created);
  879. }
  880. X
  881. /*
  882. X *  Option -n to check for any newly created newsgroups.
  883. X */
  884. X
  885. #if 0    /* MY VERSION IAIN LEA */ 
  886. void notify_groups ()
  887. {
  888. X    char buf[LEN];
  889. X    FILE *fp;
  890. X    int group_not_found;
  891. X    int i, j, index;
  892. X    int num = 0;
  893. X    int update_old_active = FALSE;
  894. X    struct notify_t {
  895. X        char name[LEN];
  896. X        int len;
  897. X    } *old_active;
  898. X    
  899. X    set_real_uid_gid ();
  900. X    
  901. X    sprintf (buf, "%s/active", rcdir);
  902. X    
  903. X    if ((fp = fopen (buf, "r")) == NULL) {
  904. X        error_message (txt_cannot_open, buf);
  905. X        goto notify_groups_done;
  906. X    }
  907. X
  908. X    Raw (FALSE);
  909. X    
  910. X    wait_message (txt_checking_active_file);
  911. X    
  912. X    old_active = (struct notify_t *) my_malloc ((unsigned) sizeof (struct notify_t) * num_active);
  913. X    if (old_active == (struct notify_t *) 0) {
  914. X        error_message (txt_out_of_memory, progname);
  915. X        goto notify_groups_done;
  916. X    }
  917. X    
  918. X    while (fgets (old_active[num].name, sizeof (old_active[num].name), fp) != NULL) {
  919. X        old_active[num].len = strlen (old_active[num].name)-1;
  920. X        old_active[num].name[old_active[num].len] = '\0';
  921. X        num++;
  922. X        if (num == num_active) {
  923. X            break;
  924. X        }
  925. X    }
  926. X
  927. X    for (i = 0 ; i < num_active ; i++) {    
  928. X        group_not_found = TRUE;
  929. X        for (j=0; j < num ; j++) {
  930. X            if (strncmp (old_active[j].name, active[i].name, old_active[j].len) == 0) {
  931. X                group_not_found = FALSE;        /* found it so read in next group */
  932. X                break;
  933. X            }
  934. X        }
  935. X
  936. X        if (group_not_found) {
  937. X            update_old_active = TRUE;
  938. X            sprintf (msg, txt_subscribe_to_new_group, active[i].name);
  939. X            wait_message (msg);
  940. X            scanf ("%s", buf);
  941. X            if (buf[0] == 'y') {
  942. X                index = add_group (active[i].name, TRUE);
  943. X                subscribe (active[my_group[index]].name, ':',
  944. X                    my_group[index], FALSE);
  945. X            }
  946. X            wait_message (txt_checking);
  947. X        }
  948. X    }
  949. X    fclose (fp);
  950. X
  951. X    if (old_active != (struct notify_t *) 0) {
  952. X        free ((char *) old_active);
  953. X        old_active = (struct notify_t *) 0;
  954. X    }
  955. X
  956. X    Raw (TRUE);
  957. X
  958. X    /*
  959. X     *  write active[] to ~/.tin/active
  960. X     */
  961. X    if (update_old_active) {
  962. X        backup_active (FALSE);
  963. X    }
  964. X
  965. notify_groups_done:
  966. X    set_tin_uid_gid ();
  967. }
  968. X
  969. #endif
  970. X
  971. void notify_groups ()
  972. {
  973. X    char buf[LEN];
  974. X    FILE *fp;
  975. X    int group_not_found;
  976. X    int i, j, index;
  977. X    int num = 0;
  978. X    int update_old_active = FALSE;
  979. X    int max_old_active;
  980. X    struct notify_t {
  981. X        char name[LEN];
  982. X        int len;
  983. X        int visited;
  984. X    } *old_active;
  985. X    
  986. X    set_real_uid_gid ();
  987. X    
  988. X    sprintf (buf, "%s/active", rcdir);
  989. X    
  990. X    if ((fp = fopen (buf, "r")) == NULL) {
  991. X        error_message (txt_cannot_open, buf);
  992. X        goto notify_groups_done;
  993. X    }
  994. X
  995. X    Raw (FALSE);
  996. X    
  997. X    wait_message (txt_checking_active_file);
  998. X
  999. X    max_old_active = num_active;
  1000. X    
  1001. X    old_active = (struct notify_t *) my_malloc ((unsigned) sizeof (struct notify_t) * max_old_active);
  1002. X    if (old_active == (struct notify_t *) 0) {
  1003. X        error_message (txt_out_of_memory, progname);
  1004. X        goto notify_groups_done;
  1005. X    }
  1006. X    
  1007. X    while (fgets (old_active[num].name, sizeof (old_active[num].name), fp) != NULL) {
  1008. X        old_active[num].len = strlen (old_active[num].name)-1;
  1009. X        old_active[num].name[old_active[num].len] = '\0';
  1010. X        old_active[num].visited = FALSE;
  1011. X        num++;
  1012. X        if (num >= max_old_active) {
  1013. X            max_old_active= max_old_active + (max_old_active / 2);
  1014. X            old_active= (struct notify_t*) my_realloc(
  1015. X                (struct notify_t*) old_active, 
  1016. X                (unsigned) sizeof(struct notify_t) * max_old_active);
  1017. X            if (old_active == (struct notify_t *) 0) {
  1018. X                error_message (txt_out_of_memory, progname);
  1019. X                goto notify_groups_done;
  1020. X            }
  1021. X        }
  1022. X    }
  1023. X
  1024. X    for (i = 0 ; i < num_active ; i++) {    
  1025. X        group_not_found = TRUE;
  1026. X        for (j=0; j < num ; j++) {
  1027. X            if (strcmp (old_active[j].name, active[i].name) == 0) {
  1028. X                group_not_found = FALSE;    /* found it so read in next group */
  1029. X                old_active[j].visited = TRUE;
  1030. X                break;
  1031. X            }
  1032. X        }
  1033. X
  1034. X        if (group_not_found) {
  1035. X            update_old_active = TRUE;
  1036. X            printf ("\r\nSubscribe to %s (y/n): ", active[i].name);
  1037. X            fflush (stdout);
  1038. X            scanf ("%s", buf);
  1039. X            if (buf[0] == 'y') {
  1040. X                index = add_group (active[i].name, TRUE);
  1041. X                subscribe (active[my_group[index]].name, ':',
  1042. X                    my_group[index], FALSE);
  1043. X            }
  1044. X            printf ("Checking...");
  1045. X            fflush (stdout);
  1046. X        }
  1047. X    }
  1048. X    fclose (fp);
  1049. X
  1050. X    /*
  1051. X     * Look for bogus groups 
  1052. X     */
  1053. X    for (j = 0 ; j < num ; j++)  {
  1054. X        if (! old_active[j].visited) {
  1055. X            update_old_active= 1;
  1056. X            printf ("\nRemove bogus group %s (y/n): ", old_active[j].name);
  1057. X            fflush (stdout);
  1058. X            scanf ("%s", buf);
  1059. X            if (buf[0] == 'y') 
  1060. X                delete_group (old_active[j].name);
  1061. X        }
  1062. X    }
  1063. X    
  1064. X    if (old_active != (struct notify_t *) 0) {
  1065. X        free ((char *) old_active);
  1066. X        old_active = (struct notify_t *) 0;
  1067. X    }
  1068. X
  1069. X    Raw (TRUE);
  1070. X
  1071. X    /*
  1072. X     *  write active[] to ~/.tin/active
  1073. X     */
  1074. X    if (update_old_active) {
  1075. X        backup_active (FALSE);
  1076. X    }
  1077. X
  1078. notify_groups_done:
  1079. X    set_tin_uid_gid ();
  1080. }
  1081. SHAR_EOF
  1082. chmod 0600 active.c ||
  1083. echo 'restore of active.c failed'
  1084. Wc_c="`wc -c < 'active.c'`"
  1085. test 8707 -eq "$Wc_c" ||
  1086.     echo 'active.c: original size 8707, current size' "$Wc_c"
  1087. rm -f _shar_wnt_.tmp
  1088. fi
  1089. # ============= art.c ==============
  1090. if test -f 'art.c' -a X"$1" != X"-c"; then
  1091.     echo 'x - skipping art.c (File already exists)'
  1092.     rm -f _shar_wnt_.tmp
  1093. else
  1094. > _shar_wnt_.tmp
  1095. echo 'x - extracting art.c (Text)'
  1096. sed 's/^X//' << 'SHAR_EOF' > 'art.c' &&
  1097. /*
  1098. X *  Project   : tin - a threaded Netnews reader
  1099. X *  Module    : art.c
  1100. X *  Author    : I.Lea & R.Skrenta
  1101. X *  Created   : 01-04-91
  1102. X *  Updated   : 21-03-92
  1103. X *  Notes     :
  1104. X *  Copyright : (c) Copyright 1991-92 by Iain Lea & Rich Skrenta
  1105. X *              You may  freely  copy or  redistribute  this software,
  1106. X *              so  long as there is no profit made from its use, sale
  1107. X *              trade or  reproduction.  You may not change this copy-
  1108. X *              right notice, and it must be included in any copy made
  1109. X */
  1110. X
  1111. #include    "tin.h"
  1112. X
  1113. char index_file[LEN];
  1114. char *glob_art_group;
  1115. int index_file_killed = FALSE;
  1116. long last_read_article;
  1117. X
  1118. X
  1119. /*
  1120. X *  Construct the pointers to the basenotes of each thread
  1121. X *  arts[] contains every article in the group.  inthread is
  1122. X *  set on each article that is after the first article in the
  1123. X *  thread.  Articles which have been expired have their thread
  1124. X *  set to -2 (ART_EXPIRED).
  1125. X */
  1126. X
  1127. void find_base (only_unread)
  1128. X    int only_unread;
  1129. {
  1130. X    register int i;
  1131. X    register int j;
  1132. X
  1133. X    top_base = 0;
  1134. X
  1135. X    debug_print_arts ();
  1136. X
  1137. X    if (only_unread) {
  1138. X        for (i = 0; i < top; i++) {
  1139. X            if (arts[i].thread != ART_EXPIRED && arts[i].inthread == FALSE) {
  1140. X                if (top_base >= max_art) {
  1141. X                    expand_art ();
  1142. X                }
  1143. X                if (arts[i].unread == ART_UNREAD) {
  1144. X                    base[top_base++] = i;
  1145. X                } else {
  1146. X                    for (j = i ; j >= 0 ; j = arts[j].thread) {
  1147. X                        if (arts[j].unread) {
  1148. X                            base[top_base++] = i;
  1149. X                            break;
  1150. X                        }
  1151. X                    }
  1152. X                }
  1153. X            }
  1154. X        }
  1155. X    } else {
  1156. X        for (i = 0; i < top; i++) {
  1157. X            if (! arts[i].inthread && arts[i].thread != ART_EXPIRED) {
  1158. X                if (top_base >= max_art) {
  1159. X                    expand_art ();
  1160. X                }
  1161. X                base[top_base++] = i;
  1162. X            }
  1163. X        }
  1164. X    }
  1165. }
  1166. X
  1167. /* 
  1168. X *  Count the number of non-expired and non-killed articles in arts[]
  1169. X */
  1170. X
  1171. int num_of_arts ()
  1172. {
  1173. X    int sum = 0;
  1174. X    register int i;
  1175. X
  1176. X    for (i = 0; i < top; i++) {
  1177. X        if (arts[i].thread != ART_EXPIRED && arts[i].killed == FALSE) {
  1178. X            sum++;
  1179. X        }
  1180. X    }
  1181. X
  1182. X    return sum;
  1183. }
  1184. X
  1185. /*
  1186. X *  Do we have an entry for article art?
  1187. X */
  1188. X
  1189. int valid_artnum (art)
  1190. X    long art;
  1191. {
  1192. X    register int i;
  1193. X
  1194. X    for (i = 0; i < top; i++)
  1195. X        if (arts[i].artnum == art)
  1196. X            return i;
  1197. X
  1198. X    return -1;
  1199. }
  1200. X
  1201. /*
  1202. X *  Return TRUE if arts[] contains any expired articles
  1203. X *  (articles we have an entry for which don't have a corresponding
  1204. X *   article file in the spool directory)
  1205. X */
  1206. X
  1207. int purge_needed ()
  1208. {
  1209. X    register int i;
  1210. X
  1211. X    for (i = 0; i < top; i++)
  1212. X        if (arts[i].thread == ART_EXPIRED)
  1213. X            return TRUE;
  1214. X
  1215. X    return FALSE;
  1216. }
  1217. X
  1218. /*
  1219. X *  Main group indexing routine.  Group should be the name of the
  1220. X *  newsgroup, i.e. "comp.unix.amiga".  group_path should be the
  1221. X *  same but with the .'s turned into /'s: "comp/unix/amiga"
  1222. X *
  1223. X *  Will read any existing index, create or incrementally update
  1224. X *  the index by looking at the articles in the spool directory,
  1225. X *  and attempt to write a new index if necessary.
  1226. X */
  1227. X
  1228. void index_group (group, group_path)
  1229. X    char *group;
  1230. X    char *group_path;
  1231. {
  1232. X    int killed = FALSE;
  1233. X    int modified = FALSE;
  1234. X    glob_art_group = group;
  1235. X
  1236. X    set_signals_art ();
  1237. X    
  1238. X    if (! update) {
  1239. X        sprintf (msg, txt_group, group);
  1240. X        wait_message (msg);
  1241. X    }
  1242. X
  1243. X    hash_reclaim ();
  1244. X    free_art_array ();
  1245. X
  1246. X    /*
  1247. X     *  load articles from index file if it exists
  1248. X     */
  1249. X    load_index_file (group);
  1250. X
  1251. X    /*
  1252. X     *  load killed articles into arts[] because kill arts is OFF
  1253. X     */
  1254. X    if (! kill_articles && index_file_killed) {
  1255. X        index_file_killed = FALSE;
  1256. X        last_read_article = 0L;
  1257. X    }
  1258. X
  1259. X    /*
  1260. X     *  add any articles to arts[] that are new or were killed
  1261. X     */
  1262. X    modified = read_group (group, group_path);
  1263. X
  1264. X    /*
  1265. X     *  compare kill descriptions to arts[] and kill mark any that match
  1266. X     */
  1267. X    killed = kill_any_articles (group);
  1268. X    
  1269. X    if (modified || killed || purge_needed()) {
  1270. X        if (local_index) {        /* writing index in home directory */
  1271. X            set_real_uid_gid ();    /* so become them */
  1272. X        }
  1273. X
  1274. X        if (killed) {
  1275. X            reload_index_file (group, killed);
  1276. X        } else {
  1277. X            dump_index_file (group, FALSE);
  1278. X            read_newsrc_line (group);
  1279. X            make_threads (FALSE);
  1280. X            find_base (show_only_unread);
  1281. X        }
  1282. X
  1283. X        if (local_index) {
  1284. X            set_tin_uid_gid ();
  1285. X        }
  1286. X    } else {
  1287. X        read_newsrc_line (group);
  1288. X        make_threads (FALSE);
  1289. X        find_base (show_only_unread);
  1290. X    }
  1291. X    
  1292. X    if ((modified || killed) && ! update) {
  1293. X        clear_message ();
  1294. X    }
  1295. }
  1296. X
  1297. /*
  1298. X *  Index a group.  Assumes any existing index has already been
  1299. X *  loaded.
  1300. X */
  1301. X
  1302. int read_group (group, group_path)
  1303. X    char *group;
  1304. X    char *group_path;
  1305. {
  1306. X    int fd;
  1307. X    long art;
  1308. X    int count = 0;
  1309. X    int modified = FALSE;
  1310. X    int respnum;
  1311. X    register int i;
  1312. X    
  1313. X    setup_base (group, group_path);    /* load article numbers into base[] */
  1314. X
  1315. X    for (i = 0; i < top_base; i++) {    /* for each article # */
  1316. X        art = base[i];
  1317. X
  1318. /*
  1319. X *  Do we already have this article in our index?  Change thread from
  1320. X *  (ART_EXPIRED) to (ART_NORMAL) if so and skip the header eating.
  1321. X */
  1322. X
  1323. X        if ((respnum = valid_artnum (art)) >= 0 || art <= last_read_article) {
  1324. X            if (respnum >= 0) {
  1325. X                arts[respnum].thread = ART_NORMAL;
  1326. X                arts[respnum].unread = ART_UNREAD;
  1327. X            }    
  1328. X            continue;
  1329. X        }
  1330. X
  1331. X        if (! modified) {
  1332. X            modified = TRUE;   /* we've modified the index */
  1333. X                               /* it will need to be re-written */
  1334. X        }
  1335. X
  1336. X        if ((fd = open_header_fd (group_path, art)) < 0) {
  1337. X            continue;
  1338. X        }
  1339. X        
  1340. X        /*
  1341. X         *  Add article to arts[]
  1342. X         */
  1343. X        if (top >= max_art)
  1344. X            expand_art();
  1345. X
  1346. X        arts[top].artnum = art;
  1347. X        arts[top].thread = ART_NORMAL;
  1348. X
  1349. X        set_article (&arts[top]);
  1350. X
  1351. X        if (! parse_headers (fd, &arts[top])) {
  1352. X            continue;
  1353. X        }
  1354. X        close (fd);
  1355. X        last_read_article = arts[top].artnum;    /* used if arts are killed */
  1356. X        top++;
  1357. X
  1358. X        if (++count % MODULO_COUNT_NUM == 0 && ! update) {
  1359. #ifndef SLOW_SCREEN_UPDATE
  1360. X            sprintf (msg, txt_indexing_num, group, count);
  1361. #else
  1362. X            sprintf (msg, txt_indexing, group);
  1363. #endif
  1364. X            wait_message (msg);
  1365. X        }
  1366. X    }
  1367. X
  1368. X    return modified;
  1369. }
  1370. X
  1371. X
  1372. /*
  1373. X *  Go through the articles in arts[] and use .thread to snake threads
  1374. X *  through them.  Use the subject line to construct threads.  The
  1375. X *  first article in a thread should have .inthread set to FALSE, the
  1376. X *  rest TRUE.  Only do unexprired articles we haven't visited yet
  1377. X *  (arts[].thread == -1 ART_NORMAL).
  1378. X */
  1379. X
  1380. void make_threads (rethread)
  1381. X    int rethread;
  1382. {
  1383. X    extern int cur_groupnum;
  1384. X    register int i;
  1385. X    register int j;
  1386. X
  1387. X    /*
  1388. X     *  .thread & .inthread need to be reset if re-threading arts[]
  1389. X     */
  1390. X    if (rethread && active[my_group[cur_groupnum]].thread) {
  1391. X        for (i=0 ; i < top ; i++) {
  1392. X            arts[i].thread = ART_NORMAL;
  1393. X            arts[i].inthread = FALSE;
  1394. X        }
  1395. X    }
  1396. X
  1397. X    switch (sort_art_type) {
  1398. X        case SORT_BY_NOTHING:        /* don't sort at all */
  1399. X            qsort ((char *) arts, top, sizeof (struct article_t), artnum_comp);
  1400. X            break;
  1401. X        case SORT_BY_SUBJ_DESCEND:
  1402. X        case SORT_BY_SUBJ_ASCEND:
  1403. X            qsort ((char *) arts, top, sizeof (struct article_t), subj_comp);
  1404. X            break;
  1405. X        case SORT_BY_FROM_DESCEND:
  1406. X        case SORT_BY_FROM_ASCEND:
  1407. X            qsort ((char *) arts, top, sizeof (struct article_t), from_comp);
  1408. X            break;
  1409. X        case SORT_BY_DATE_DESCEND:
  1410. X        case SORT_BY_DATE_ASCEND:
  1411. X            qsort ((char *) arts, top, sizeof (struct article_t), date_comp);
  1412. X            break;
  1413. X        default:
  1414. X            break;
  1415. X    }
  1416. X
  1417. X    if (thread_arts && active[my_group[cur_groupnum]].thread) {
  1418. X        for (i = 0; i < top; i++) {
  1419. X            if (arts[i].thread == ART_NORMAL) {
  1420. X                for (j = i+1; j < top; j++) {
  1421. X                    if (arts[j].thread != ART_EXPIRED &&
  1422. X                        ((arts[i].subject == arts[j].subject) ||
  1423. X                        ((arts[i].part || arts[i].patch) &&
  1424. X                        arts[i].archive == arts[j].archive))) {
  1425. X                            arts[i].thread = j;
  1426. X                            arts[j].inthread = TRUE;
  1427. X                            break;
  1428. X                    }
  1429. X                }
  1430. X            }
  1431. X        }
  1432. X    }
  1433. }
  1434. X
  1435. X
  1436. int parse_headers (fd, h)
  1437. X    int fd;
  1438. X    struct article_t *h;
  1439. {
  1440. X    char buf[HEADER_LEN];
  1441. X    char buf2[HEADER_LEN];
  1442. X    char art_from_addr[LEN];
  1443. X    char art_full_name[LEN];
  1444. X    char *ptr, *ptrline, *s;
  1445. X    int n = 0, len = 0, lineno = 0;
  1446. X    int flag;
  1447. X    int got_subject = FALSE;
  1448. X    int got_from = FALSE;
  1449. X    int got_date = FALSE;
  1450. X    int got_archive = FALSE;
  1451. X    
  1452. X    if ((n = read (fd, buf, HEADER_LEN)) <= 0) {
  1453. X        return FALSE;
  1454. X    }
  1455. X
  1456. X    buf[n-1] = '\0';
  1457. X
  1458. X    ptr = buf;
  1459. X
  1460. X    while (1) {
  1461. X        for (ptrline = ptr; *ptr && *ptr != '\n'; ptr++) {
  1462. X            if (((*ptr) & 0xFF) < ' ') {
  1463. X                *ptr = ' ';
  1464. X            }
  1465. X        }
  1466. X        flag = *ptr;
  1467. X        *ptr++ = '\0';
  1468. X        lineno++;
  1469. X
  1470. X        if (! got_from && match_header (ptrline, "From", buf2, HEADER_LEN)) {
  1471. X            parse_from (buf2, art_from_addr, art_full_name); 
  1472. X            h->from = hash_str (art_from_addr);
  1473. X            h->name = hash_str (art_full_name);
  1474. X            got_from = TRUE;
  1475. X        } else if (! got_subject && match_header (ptrline, "Subject", buf2, HEADER_LEN)) {
  1476. X            s = eat_re (buf2);
  1477. X            h->subject = hash_str (eat_re (s));
  1478. X            got_subject = TRUE;
  1479. X        } else if (! got_date && match_header (ptrline, "Date", buf2, HEADER_LEN)) {
  1480. X            parse_date (buf2, h->date);
  1481. X            got_date = TRUE;
  1482. X        } else if (match_header (ptrline, "Archive-name", buf2, HEADER_LEN) ||
  1483. X                    match_header (ptrline, "Archive-Name", buf2, HEADER_LEN)) {
  1484. X            if ((s = (char *) strchr (buf2, '/')) != NULL) {
  1485. X                if (strncmp (s+1,"part",4) == 0 ||
  1486. X                    strncmp (s+1,"Part",4) == 0) {
  1487. X                    h->part = str_dup (s+5);
  1488. X                    len = (int) strlen (h->part);
  1489. X                    if (h->part[len-1] == '\n') {
  1490. X                        h->part[len-1] = '\0';
  1491. X                    }
  1492. X                } else {
  1493. X                    if (strncmp (s+1,"patch",5) == 0 ||
  1494. X                        strncmp (s+1,"Patch",5) == 0) {
  1495. X                        h->patch = str_dup (s+6);
  1496. X                        len = (int) strlen (h->patch);
  1497. X                        if (h->patch[len-1] == '\n') {
  1498. X                            h->patch[len-1] = '\0';
  1499. X                        }
  1500. X                    }
  1501. X                }
  1502. X                if (h->part || h->patch) {
  1503. X                    s = buf2;
  1504. X                    while (*s && *s != '/')
  1505. X                        s++;
  1506. X                    *s = '\0';    
  1507. X                    s = buf2;
  1508. X                    h->archive = hash_str (s);
  1509. X                    got_archive = TRUE;
  1510. X                }
  1511. X            }
  1512. X        }
  1513. X
  1514. X        if (! flag || lineno > 25 || got_archive) {
  1515. X            debug_print_header (h);
  1516. X            return TRUE;
  1517. X        }
  1518. X    }
  1519. X    /* NOTREACHED */
  1520. }
  1521. X
  1522. /* 
  1523. X *  Write out an index file.  Write the group name first so if
  1524. X *  local indexing is done we can disambiguate between group name
  1525. X *  hash collisions by looking at the index file.
  1526. X */
  1527. X
  1528. void dump_index_file (group, killed)
  1529. X    char *group;
  1530. X    int killed;
  1531. {
  1532. X    char nam[LEN];
  1533. X    FILE *fp;
  1534. X    int *iptr;
  1535. X    int realnum;
  1536. X    register int i;
  1537. X
  1538. X    sprintf (nam, "%s.%d", index_file, process_id);
  1539. X    if ((fp = fopen (nam, "w")) == NULL) {
  1540. X        error_message (txt_cannot_open, nam);
  1541. X        return;
  1542. X    }
  1543. X
  1544. X    /*
  1545. X     *  dump group header info.
  1546. X     */
  1547. X    if (sort_art_type != SORT_BY_NOTHING) {
  1548. X        qsort ((char *) arts, top, sizeof (struct article_t), artnum_comp);
  1549. X    }
  1550. X    fprintf (fp, "%s\n", group);
  1551. X    fprintf (fp, "%d\n", num_of_arts ());
  1552. X    if (top <= 0) {
  1553. X        fprintf (fp, "0\n");
  1554. X    } else {
  1555. X        if (last_read_article > arts[top-1].artnum) {
  1556. X            fprintf (fp, "%ld\n", last_read_article);
  1557. X        } else {
  1558. X            fprintf (fp, "%ld\n", arts[top-1].artnum);
  1559. X        }
  1560. X    }
  1561. X    if (index_file_killed && killed) {
  1562. X        fprintf (fp, "KILLED\n");
  1563. X    } else {
  1564. X        fprintf (fp, "COMPLETE\n");
  1565. X    }
  1566. X
  1567. X    /*
  1568. X     *  dump articles
  1569. X     */
  1570. X    realnum = 0; 
  1571. X    for (i = 0; i < top; i++) {
  1572. X        if (arts[i].thread != ART_EXPIRED && arts[i].killed == FALSE) { 
  1573. X            debug_print_header (&arts[i]);
  1574. X
  1575. X            fprintf(fp, "%ld\n", arts[i].artnum);
  1576. X
  1577. X            iptr = (int *) arts[i].subject;
  1578. X            iptr--;
  1579. X
  1580. X            if (! arts[i].subject) {
  1581. X                fprintf(fp, " \n");
  1582. X            } else if (*iptr < 0 || *iptr > top) {
  1583. X                fprintf(fp, " %s\n", arts[i].subject);
  1584. X                *iptr = realnum;
  1585. X            } else if (killed || *iptr == i) {
  1586. X                fprintf(fp, " %s\n", arts[i].subject);
  1587. X            } else {
  1588. X                fprintf(fp, "%%%d\n", *iptr);
  1589. X            }
  1590. X    
  1591. X            iptr = (int *) arts[i].from;
  1592. X            iptr--;
  1593. X
  1594. X            if (! arts[i].from) {
  1595. X                fprintf (fp, " \n");
  1596. X            } else if (*iptr < 0 || *iptr > top) {
  1597. X                fprintf (fp, " %s\n", arts[i].from);
  1598. X                *iptr = realnum;
  1599. X            } else if (killed || *iptr == i) {
  1600. X                fprintf(fp, " %s\n", arts[i].from);
  1601. X            } else {
  1602. X                fprintf(fp, "%%%d\n", *iptr);
  1603. X            }
  1604. X
  1605. X            iptr = (int *) arts[i].name;
  1606. X            iptr--;
  1607. X
  1608. X            if (! arts[i].name) {
  1609. X                fprintf (fp, " \n");
  1610. X            } else if (*iptr < 0 || *iptr > top) {
  1611. X                fprintf (fp, " %s\n", arts[i].name);
  1612. X                *iptr = realnum;
  1613. X            } else if (killed || *iptr == i) {
  1614. X                fprintf(fp, " %s\n", arts[i].name);
  1615. X            } else {
  1616. X                fprintf(fp, "%%%d\n", *iptr);
  1617. X            }
  1618. X
  1619. X            fprintf (fp, "%s\n", arts[i].date);
  1620. X            
  1621. X            iptr = (int *) arts[i].archive;
  1622. X            iptr--;
  1623. X
  1624. X            if (! arts[i].archive) {
  1625. X                fprintf (fp, "\n");
  1626. X            } else if (*iptr < 0 || *iptr > top) {
  1627. X                fprintf (fp, " %s\n", arts[i].archive);
  1628. X                *iptr = realnum;
  1629. X            } else if (arts[i].part || arts[i].patch) {
  1630. X                if (killed || *iptr == i) {
  1631. X                    fprintf(fp, " %s\n", arts[i].archive);
  1632. X                } else {
  1633. X                    fprintf (fp, "%%%d\n", *iptr);
  1634. X                }
  1635. X            } else {
  1636. X                fprintf (fp, "\n");
  1637. X            }
  1638. X            
  1639. X            if (! arts[i].part) {
  1640. X                fprintf (fp, " \n");
  1641. X            } else {
  1642. X                fprintf (fp, "%s\n", arts[i].part);
  1643. X            }
  1644. X
  1645. X            if (! arts[i].patch) {
  1646. X                fprintf (fp, " \n");
  1647. X            } else {
  1648. X                fprintf (fp, "%s\n", arts[i].patch);
  1649. X            }
  1650. X
  1651. X            realnum++;
  1652. X        }
  1653. X    }
  1654. X    fclose (fp);
  1655. X    chmod (index_file, 0644);
  1656. X    rename_file (nam, index_file);
  1657. X    if (debug == 2) {
  1658. X        sprintf (msg, "cp %s INDEX", index_file);
  1659. X        system (msg);
  1660. X    }
  1661. }
  1662. X
  1663. /*
  1664. X *  Read in an index file.
  1665. X *
  1666. X *  index file header 
  1667. X *    1.  newsgroup name (ie. alt.sources)
  1668. X *    2.  number of articles (ie. 26)
  1669. X *    3.  number of last read article (ie. 210)
  1670. X *    4.  Is this a complete/killed index file (ie. COMPLETE/KILLED)
  1671. X *
  1672. X *  index file record
  1673. X *    1.  article number    (ie. 183)               [mandatory]
  1674. X *    2.  Subject: line     (ie. Which newsreader?) [mandatory]
  1675. X *    3.  From: line (addr) (ie. iain@norisc)       [mandatory]
  1676. X *    4.  From: line (name) (ie. Iain Lea)          [mandatory]
  1677. X *    5.  Date: of posting  (ie. 911231125959)      [mandatory]
  1678. X *    6.  Archive: name     (ie. compiler)          [optional]
  1679. X *    7.  Part number of Archive: name  (ie. 01)    [optional]
  1680. X *    8.  Patch number of Archive: name (ie. 01)    [optional]
  1681. X */
  1682. X
  1683. int load_index_file (group_name)
  1684. X    char *group_name;
  1685. {
  1686. X    int error = 0;
  1687. X    int i, n;
  1688. X    char buf[LEN], *p;
  1689. X    FILE *fp;
  1690. X
  1691. X    top = 0;
  1692. X    last_read_article = 0L;
  1693. X
  1694. X    if ((fp = open_index_fp (group_name)) == NULL) {
  1695. X        return FALSE;
  1696. X    }
  1697. X
  1698. X    /*
  1699. X     *  load header - discard group name, num. of arts in index file after any arts were killed
  1700. X     */
  1701. X    if (fgets(buf, sizeof buf, fp) == NULL ||
  1702. X        fgets(buf, sizeof buf, fp) == NULL) {
  1703. X        error = 0;            
  1704. X        goto corrupt_index;    
  1705. X    }
  1706. X    i = atoi (buf);
  1707. X
  1708. X    /*
  1709. X     * num. of last_read_article including any that were killed
  1710. X     */
  1711. X    if (fgets(buf, sizeof buf, fp) == NULL) {
  1712. X        error = 1;                
  1713. X        goto corrupt_index;    
  1714. X    }                            
  1715. X    last_read_article = (long) atol (buf);
  1716. X    
  1717. X    /*
  1718. X     * is index file complete or were articles killed when it was dumped
  1719. X     */
  1720. X    if (fgets(buf, sizeof buf, fp) == NULL) {
  1721. X        error = 2;                
  1722. X        goto corrupt_index;    
  1723. X    }
  1724. X    index_file_killed = (buf[0] == 'K' ? TRUE : FALSE);
  1725. X    
  1726. X    /*
  1727. X     *  load articles
  1728. X     */
  1729. X    for (; top < i ; top++) {
  1730. X        if (top >= max_art) {
  1731. X            expand_art ();
  1732. X        }
  1733. X
  1734. X        arts[top].thread = ART_EXPIRED;
  1735. X        set_article (&arts[top]);
  1736. X
  1737. X        /*
  1738. X         * Article no.
  1739. X         */
  1740. X        if (fgets(buf, sizeof buf, fp) == NULL) {
  1741. X            error = 3;
  1742. X            goto corrupt_index;
  1743. X        }
  1744. X        arts[top].artnum = (long) atol (buf);
  1745. X
  1746. X        /*
  1747. X         * Subject:
  1748. X         */
  1749. X        if (fgets(buf, sizeof buf, fp) == NULL) {
  1750. X            error = 4;
  1751. X            goto corrupt_index;
  1752. X        }
  1753. X
  1754. X        if (buf[0] == '%') {
  1755. X            n = atoi (&buf[1]);
  1756. X            if (n >= top || n < 0) {
  1757. X                error = 5;
  1758. X                goto corrupt_index;
  1759. X            }
  1760. X            arts[top].subject = arts[n].subject;
  1761. X        } else if (buf[0] == ' ') {
  1762. X            for (p = &buf[1];  *p && *p != '\n'; p++)
  1763. X                continue;    
  1764. X            *p = '\0';
  1765. X            arts[top].subject = hash_str (&buf[1]);
  1766. X        } else {
  1767. X            error = 6;
  1768. X            goto corrupt_index;
  1769. X        }
  1770. X            
  1771. X        /*
  1772. X         * From: (addr part)
  1773. X         */
  1774. X        if (fgets(buf, sizeof buf, fp) == NULL) {
  1775. X            error = 7;
  1776. X            goto corrupt_index;
  1777. X        }
  1778. X
  1779. X        if (buf[0] == '%') {
  1780. X            n = atoi (&buf[1]);
  1781. X            if (n >= top || n < 0) {
  1782. X                error = 8;
  1783. X                goto corrupt_index;
  1784. X            }
  1785. X            arts[top].from = arts[n].from;
  1786. X        } else if (buf[0] == ' ') {
  1787. X            for (p = &buf[1];  *p && *p != '\n'; p++)
  1788. X                continue;
  1789. X            *p = '\0';
  1790. X            arts[top].from = hash_str (&buf[1]);
  1791. X        } else {
  1792. X            error = 9;
  1793. X            goto corrupt_index;
  1794. X        }
  1795. X
  1796. X        /*
  1797. X         * From: (full name)
  1798. X         */
  1799. X        if (fgets(buf, sizeof buf, fp) == NULL) {
  1800. X            error = 10;
  1801. X            goto corrupt_index;
  1802. X        }
  1803. X
  1804. X        if (buf[0] == '%') {
  1805. X            n = atoi (&buf[1]);
  1806. X            if (n > top || n < 0) {
  1807. X                error = 11;
  1808. X                goto corrupt_index;
  1809. X            }
  1810. X            if (n == top) {        /* no full name so .name = .from */
  1811. X                arts[top].name = arts[top].from;
  1812. X            } else {
  1813. X                arts[top].name = arts[n].name;
  1814. X            }
  1815. X        } else if (buf[0] == ' ') {
  1816. X            for (p = &buf[1];  *p && *p != '\n'; p++)
  1817. X                continue;
  1818. X            *p = '\0';
  1819. X            arts[top].name = hash_str (&buf[1]);
  1820. SHAR_EOF
  1821. true || echo 'restore of art.c failed'
  1822. fi
  1823. echo 'End of tin1.1 part 3'
  1824. echo 'File art.c is continued in part 4'
  1825. echo 4 > _shar_seq_.tmp
  1826. exit 0
  1827.  
  1828. --
  1829. NAME   Iain Lea 
  1830. EMAIL  iain%anl433.uucp@germany.eu.net
  1831. SNAIL  Siemens AG, ANL A433SZ, Gruendlacher Str. 248, 8510 Fuerth, Germany.
  1832. PHONE  +49-911-3089-407 (work) +49-911-331963 (home) +49-911-3089-290 (FAX)  
  1833. -- 
  1834.  Dr. med. dipl.-math Dieter Becker           Tel.: (0 / +49) 6841 - 16 3046
  1835.  Medizinische Universitaets- und Poliklinik  Fax.: (0 / +49) 6841 - 16 3369
  1836.  Innere Medizin III                         
  1837.  D - 6650 Homburg / Saar                     Email: becker@med-in.uni-sb.de
  1838. exit 0 # Just in case...
  1839.