home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 3 / 3895 < prev    next >
Internet Message Format  |  1991-08-23  |  50KB

  1. Path: wupost!uunet!mcsun!unido!estevax!norisc!iain
  2. From: iain@norisc.UUCP (Iain Lea)
  3. Newsgroups: alt.sources
  4. Subject: tin v1.00 - YAN (Yet Another Newsreader) Part 01/08
  5. Message-ID: <582@norisc.UUCP>
  6. Date: 23 Aug 91 13:50:34 GMT
  7. Sender: iain@norisc.UUCP (Iain Lea)
  8. Organization: What organization?
  9. Lines: 1985
  10.  
  11. Submitted-by: iain@estevax.uucp
  12. Archive-name: tin/part01
  13.  
  14. #!/bin/sh
  15. # This is tin, a shell archive (shar 3.24)
  16. # made 08/23/1991 13:37 UTC by iain@estevax.uucp
  17. # Source directory /piez/iain/.src/tin
  18. #
  19. # existing files WILL be overwritten
  20. #
  21. # This is part 1 of a multipart archive                                    
  22. # do not concatenate these parts, unpack them in order with /bin/sh        
  23. #
  24. # This shar contains:
  25. # length  mode       name
  26. # ------ ---------- ------------------------------------------
  27. #    570 -rw------- MANIFEST
  28. #   8147 -rw------- Makefile
  29. #   4930 -rw------- README
  30. #   1305 -rw------- TODO
  31. #    512 -rwx------ UPDATE_INDEX
  32. #   5457 -rw------- alloca.c
  33. #  23276 -rw------- art.c
  34. #   6075 -rw------- curses.c
  35. #   2276 -rw------- debug.c
  36. #  20085 -rw------- group.c
  37. #   2673 -rw------- hashstr.c
  38. #   4794 -rw------- help.c
  39. #   9014 -rw------- kill.c
  40. #  16340 -rw------- lang.c
  41. #   8856 -rw------- lang.h
  42. #   1260 -rw------- mail.c
  43. #   6852 -rw------- main.c
  44. #   5489 -rw------- memory.c
  45. #  12707 -rw------- misc.c
  46. #  16290 -rw------- newsrc.c
  47. #   3688 -rw------- nntp.h
  48. #   6594 -rw------- open.c
  49. #  34638 -rw------- page.c
  50. #   2328 -rw------- posted.c
  51. #   3061 -rw------- prompt.c
  52. #  16291 -rw------- proto.h
  53. #  15340 -rw------- rcfile.c
  54. #  22644 -rw------- save.c
  55. #   1936 -rw------- screen.c
  56. #   7656 -rw------- search.c
  57. #  17154 -rw------- select.c
  58. #   1611 -rw------- time.c
  59. #   7369 -rw------- tin.h
  60. #   3866 -rw------- wildmat.c
  61. #  18929 -rw------- tin.1
  62. #
  63. if touch 2>&1 | fgrep '[-amc]' > /dev/null
  64.  then TOUCH=touch
  65.  else TOUCH=true
  66. fi
  67. if test -r shar3_seq_.tmp; then
  68.     echo "Must unpack archives in sequence!"
  69.     next=`cat shar3_seq_.tmp`; echo "Please unpack part $next next"
  70.     exit 1
  71. fi
  72. # ============= MANIFEST ==============
  73. echo "x - extracting MANIFEST (Text)"
  74. sed 's/^X//' << 'SHAR_EOF' > MANIFEST &&
  75. XMANIFEST for tin v1.00
  76. X----------------------
  77. X  567  MANIFEST
  78. X 8187  Makefile
  79. X 4930  README
  80. X  889  TODO
  81. X  512  UPDATE_INDEX
  82. X 5457  alloca.c
  83. X23418  art.c
  84. X 6075  curses.c
  85. X 2272  debug.c
  86. X20085  group.c
  87. X 2673  hashstr.c
  88. X 4734  help.c
  89. X 9014  kill.c
  90. X16120  lang.c
  91. X 8704  lang.h
  92. X 1260  mail.c
  93. X 6852  main.c
  94. X 5452  memory.c
  95. X12197  misc.c
  96. X16281  newsrc.c
  97. X 3688  nntp.h
  98. X 6594  open.c
  99. X34637  page.c
  100. X 2328  posted.c
  101. X 3061  prompt.c
  102. X15901  proto.h
  103. X15340  rcfile.c
  104. X22473  save.c
  105. X 1936  screen.c
  106. X 7648  search.c
  107. X16958  select.c
  108. X 1611  time.c
  109. X18933  tin.1
  110. X 7363  tin.h
  111. X 3866  wildmat.c
  112. SHAR_EOF
  113. $TOUCH -am 0821104491 MANIFEST &&
  114. chmod 0600 MANIFEST ||
  115. echo "restore of MANIFEST failed"
  116. set `wc -c MANIFEST`;Wc_c=$1
  117. if test "$Wc_c" != "570"; then
  118.     echo original size 570, current size $Wc_c
  119. fi
  120. # ============= Makefile ==============
  121. echo "x - extracting Makefile (Text)"
  122. sed 's/^X//' << 'SHAR_EOF' > Makefile &&
  123. X# Makefile
  124. X
  125. X# name of executable file
  126. X#
  127. XEXE=tin
  128. X
  129. X# command line compile flags
  130. X#
  131. X# -D DONT_USE_START_LINE
  132. X#   stop editor being started with line offset into file
  133. X#
  134. X# -D DONT_USE_REGEX
  135. X#   don't match strings using regular expressions
  136. X#
  137. X# -D USE_LONG_FILENAMES
  138. X#   include -DUSE_LONG_FILENAMES if filesystem supports filenames
  139. X#   longer than 14 chars. (default for BSD type systems)
  140. X#
  141. X# -D USE_CLEARSCREEN
  142. X#   define if the you wish screen to use ClearScreen() and not MoveCursor()
  143. X#   and CleartoEOLN(). This is perhaps faster on slow terminals but I have
  144. X#   not really run any speed tests.
  145. X#
  146. X# -D LIBDIR=\"\"
  147. X#   defaults to /usr/lib/news if not defined
  148. X#
  149. X# -D SPOOLDIR=\"\"
  150. X#   defaults to /usr/spool/news if not defined
  151. X#
  152. X# -D USE_NNTP
  153. X#   include -DUSE_NNTP if you want to allow reading of news locally and
  154. X#   also remotely via the -r option over an NNTP server.
  155. X#
  156. X#  You only need to worry about the following two defines if you have
  157. X#  defined NNTP to build a version to access news locally & remotely
  158. X#
  159. X#  NNTPLIB=
  160. X#    point NNTPLIB at the nntp clientlib.o support library
  161. X#
  162. X#  NETLIBS=
  163. X#    NETLIBS should be the networking libraries you need to link with
  164. X#    the nntp clientlib.o
  165. X
  166. XBINDIR = /piez/iain/bin
  167. XTROFF=drf
  168. XPRINT=-Pps0
  169. X
  170. XHFILES    =    tin.h proto.h lang.h nntp.h
  171. X
  172. XCFILES    =    art.c curses.c debug.c group.c hashstr.c help.c kill.c lang.c mail.c \
  173. X        main.c memory.c misc.c newsrc.c open.c page.c prompt.c posted.c \
  174. X        rcfile.c save.c screen.c search.c select.c time.c wildmat.c
  175. X
  176. XOBJECTS    =    art.o curses.o debug.o group.o hashstr.o help.o kill.o lang.o mail.o \
  177. X        main.o memory.o misc.o newsrc.o open.o page.o prompt.o posted.o \
  178. X        rcfile.o save.o screen.o search.o select.o time.o wildmat.o
  179. X
  180. XLINTFLAGS=-a -c -h -n -x 
  181. X
  182. X.c.o :
  183. X    $(CC) $(CFLAGS) $*.c
  184. X
  185. Xall : 
  186. X    @echo "There is no default. Specify one of the following targets."
  187. X    @echo "    make bsd       (BSD/Ultrix)"
  188. X    @echo "    make sysv      (SysV)"
  189. X    @echo "    make sysvr4    (SysV R4)"
  190. X    @echo "    make sco       (SCO Unix)"
  191. X    @echo "    make xenix     (Xenix 386)"
  192. X    @echo "    make norisc    (Site specific)"
  193. X    @echo "    make estevax   (Site specific)"
  194. X
  195. X# For Berkeley systems:
  196. Xbsd:
  197. X    @echo "Compiling for BSD/Ultrix..."
  198. X    @$(MAKE) CFLAGS='-c -O -DBSD -DLIBDIR=\"/usr/lib/news\" -DSPOOLDIR=\"/usr/spool/news\"' \
  199. X             LIBS="-lcurses -ltermcap" \
  200. X             STRIP=strip EXE=tin linkit
  201. X
  202. X# For System V:
  203. Xsysv:
  204. X    @echo "Compiling for System V..."
  205. X    @$(MAKE) CFLAGS='-c -O -DUSE_NNTP -DLIBDIR="\\"/usr/lib/news\\"" -DSPOOLDIR="\\"/usr/spool/news\\""' \
  206. X             NNTPLIB="clientlib.o" \
  207. X             NETLIBS="-lnet -lnsl_s" \
  208. X             LIBS="-lcurses -ltermcap" \
  209. X             STRIP=strip EXE=tin linkit
  210. X
  211. X# For System V Release 4:
  212. Xsysvr4:
  213. X    @echo "Compiling for System V Release 4..."
  214. X    @$(MAKE) CFLAGS='-c -O -DUSE_NNTP -DLIBDIR=\"/usr/lib/news\" -DSPOOLDIR=\"/usr/spool/news\"' \
  215. X             NNTPLIB="./nntp/clientlib.o" \
  216. X             NETLIBS="-lnsl -lsocket" \
  217. X             LIBS="-lcurses -ltermcap" \
  218. X             STRIP=strip EXE=tin linkit
  219. X
  220. X# For Sco Unix:
  221. Xsco:
  222. X    @echo "Compiling for Sco Unix..."
  223. X    @$(MAKE) CFLAGS='-c -O -UM_XENIX -DLIBDIR=\"/usr/lib/news\" -DSPOOLDIR=\"/usr/spool/news\"' \
  224. X             LIBS="-lcurses -lgen -lc_s" \
  225. X             STRIP=strip EXE=tin linkit
  226. X
  227. X# For Xenix 386:
  228. Xxenix:
  229. X    @echo "Compiling for Xenix 386..."
  230. X    @$(MAKE) CFLAGS='-c -Zi -DLIBDIR="\\"/usr/lib/news\\"" -DSPOOLDIR="\\"/usr/spool/news\\""' \
  231. X             LIBS="-lcurses -ltinfo -lx" \
  232. X             STRIP=echo EXE=tin linkit
  233. X
  234. X# SITE SPECIFIC - IGNORE
  235. Xnorisc:
  236. X    @echo "Compiling for NORISC with NNTP..."
  237. X    @$(MAKE) CFLAGS='-c -O -DBSD -DUSE_NNTP -DLIBDIR=\"/news/lib\" -DSPOOLDIR=\"/news/spool\"' \
  238. X             NNTPLIB=/news/nntp/clientlib.o \
  239. X             LIBS="-lcurses -ltermcap" \
  240. X             STRIP=strip EXE=tin linkit
  241. X
  242. X# SITE SPECIFIC - IGNORE
  243. Xestevax:
  244. X    @echo "Compiling for ESTEVAX with NNTP..."
  245. X    @$(MAKE) CFLAGS='-c -O -DBSD -DUSE_NNTP -DLIBDIR=\"/usr/lib/news\" -DSPOOLDIR=\"/usr/spool/news\"' \
  246. X             NNTPLIB=/others/mtz/bnews2/NNTP/common/clientlib.o \
  247. X             LIBS="-lcurses -ltermcap" \
  248. X             STRIP=strip EXE=tin linkit
  249. X
  250. Xlinkit: $(OBJECTS)
  251. X    @echo "Linking $(EXE)..."
  252. X#    $(CC) -o $(EXE) $(OBJECTS) alloca.o $(NNTPLIB) $(NETLIBS) $(LIBS) 
  253. X    $(CC) -o $(EXE) $(OBJECTS) $(NNTPLIB) $(NETLIBS) $(LIBS) 
  254. X    @$(STRIP) $(EXE)
  255. X    @ls -l $(EXE)
  256. X
  257. Xcflow:
  258. X    @echo "creating cflow for $(EXE)..."
  259. X    @cflow $(CFILES) > cflow.$(EXE) &
  260. X
  261. Xproto:
  262. X    @echo "generating function prototypes for proto.h..."
  263. X    @echo "#ifdef __STDC__" > PROTO.H
  264. X    @echo " " >> PROTO.H
  265. X    @cproto *.c >> PROTO.H
  266. X    @echo " " >> PROTO.H
  267. X    @echo "#else" >> PROTO.H
  268. X    @echo " " >> PROTO.H
  269. X    @cproto -f1 *.c >> PROTO.H
  270. X    @echo " " >> PROTO.H
  271. X    @echo "#endif" >> PROTO.H
  272. X    @-mv PROTO.H proto.h
  273. X
  274. Xinstall: all
  275. X    @echo "installing $(EXE)..."
  276. X    @-mv $(EXE) $(BINDIR)
  277. X    @chmod 755 $(BINDIR)/$(EXE)
  278. X
  279. Xshar:
  280. X    @-mv -f ../$(EXE).shar ../$(EXE).shar-
  281. X    @shar -a -n $(EXE) -s iain@estevax.uucp -L50 -o ../$(EXE).shar [A-Z]* [A-Za-z0-9]*.[ch] $(EXE).1
  282. X
  283. Xtar:
  284. X    @echo "archiving files to $(EXE).tar..."
  285. X    @-rm $(EXE).tar $(EXE).tar.Z > /dev/null 2>&1
  286. X    @tar cvf $(EXE).tar $(HFILES) $(CFILES) Makefile README TODO UPDATE_INDEX $(EXE).1
  287. X    @echo "compressing $(EXE).tar..."
  288. X    @compress $(EXE).tar 
  289. X    @ls -l $(EXE).tar.Z
  290. X
  291. Xzoo:
  292. X    @echo "archiving files to $(EXE).zoo..."
  293. X    @-rm $(EXE).zoo > /dev/null 2>&1
  294. X    @zoo ah $(EXE).zoo $(HFILES) $(CFILES) Makefile README TODO UPDATE_INDEX $(EXE).1
  295. X    @ls -l $(EXE).zoo
  296. X
  297. Xtags:
  298. X    @echo "generating tags (results in ./tags)..."
  299. X    @-rm tags
  300. X    @ctags $(HFILES) $(CFILES) 
  301. X
  302. Xlint:
  303. X    @echo "linting source (results in ./LINT)..."
  304. X    @lint $(LINTFLAGS) $(CFILES) > LINT
  305. X
  306. Xclean:
  307. X    @echo "cleaning..."
  308. X    @-rm -rf *.o #* $(EXE)
  309. X
  310. Xgrind:
  311. X    @echo "grinding tags index..."
  312. X    @ctags -v *.[ch] | sort -f > $(EXE).index
  313. X
  314. Xman:
  315. X    @echo "printing $(EXE) manual to $(PRINT)..."
  316. X    @+ $(TROFF) -F Helvetica -man3 $(PRINT) $(EXE).1
  317. X
  318. Xprint:
  319. X    @echo "printing to $(PRINT)..."
  320. X    @expand -4 art.c     | enscript -2r -h -G $(PRINT) -b art.c
  321. X    @expand -4 curses.c  | enscript -2r -h -G $(PRINT) -b curses.c
  322. X    @expand -4 debug.c   | enscript -2r -h -G $(PRINT) -b debug.c
  323. X    @expand -4 group.c   | enscript -2r -h -G $(PRINT) -b group.c
  324. X    @expand -4 hashstr.c | enscript -2r -h -G $(PRINT) -b hashstr.c
  325. X    @expand -4 help.c    | enscript -2r -h -G $(PRINT) -b help.c
  326. X    @expand -4 kill.c    | enscript -2r -h -G $(PRINT) -b kill.c
  327. X    @expand -4 lang.c    | enscript -2r -h -G $(PRINT) -b lang.c
  328. X    @expand -4 lang.h    | enscript -2r -h -G $(PRINT) -b lang.h
  329. X    @expand -4 mail.c    | enscript -2r -h -G $(PRINT) -b mail.c
  330. X    @expand -4 main.c    | enscript -2r -h -G $(PRINT) -b main.c 
  331. X    @expand -4 memory.c  | enscript -2r -h -G $(PRINT) -b memory.c
  332. X    @expand -4 misc.c    | enscript -2r -h -G $(PRINT) -b misc.c
  333. X    @expand -4 newsrc.c  | enscript -2r -h -G $(PRINT) -b newsrc.c
  334. X    @expand -4 nntp.h    | enscript -2r -h -G $(PRINT) -b nntp.h
  335. X    @expand -4 open.c    | enscript -2r -h -G $(PRINT) -b open.c
  336. X    @expand -4 page.c    | enscript -2r -h -G $(PRINT) -b page.c
  337. X    @expand -4 posted.c  | enscript -2r -h -G $(PRINT) -b posted.c
  338. X    @expand -4 prompt.c  | enscript -2r -h -G $(PRINT) -b prompt.c
  339. X    @expand -4 rcfile.c  | enscript -2r -h -G $(PRINT) -b rcfile.c
  340. X    @expand -4 save.c    | enscript -2r -h -G $(PRINT) -b save.c
  341. X    @expand -4 screen.c  | enscript -2r -h -G $(PRINT) -b screen.c
  342. X    @expand -4 search.c  | enscript -2r -h -G $(PRINT) -b search.c
  343. X    @expand -4 select.c  | enscript -2r -h -G $(PRINT) -b select.c
  344. X    @expand -4 tin.h     | enscript -2r -h -G $(PRINT) -b tin.h
  345. X    @expand -4 time.c    | enscript -2r -h -G $(PRINT) -b time.c
  346. X
  347. Xvaxb:
  348. X    @echo "copying to estevax..."
  349. X    @rcp $(EXE).tar.Z estevax:.src/tin &
  350. X
  351. Xkommu:
  352. X    @echo "copying to kommu..."
  353. X    @uncompress $(EXE).tar.Z 
  354. X    @rcp $(EXE).tar kommu:.src/tin &
  355. X    @compress $(EXE).tar 
  356. X
  357. Xart.o:        art.c $(HFILES)
  358. Xcurses.o:    curses.c
  359. Xdebug.o:    debug.c $(HFILES)
  360. Xgroup.o:    group.c $(HFILES)
  361. Xhashstr.o:    hashstr.c $(HFILES)
  362. Xhelp.o:        help.c $(HFILES)
  363. Xkill.o:        kill.c $(HFILES)
  364. Xlang.o:        lang.c $(HFILES)
  365. Xmail.o:        mail.c
  366. Xmain.o:        main.c $(HFILES)
  367. Xmemory.o:    memory.c $(HFILES)
  368. Xmisc.o:        misc.c $(HFILES)
  369. Xnewsrc.o:    newsrc.c $(HFILES)
  370. Xopen.o:        open.c $(HFILES)
  371. Xpage.o:        page.c $(HFILES)
  372. Xposted.o:    posted.c $(HFILES)
  373. Xprompt.o:    prompt.c $(HFILES)
  374. Xrcfile.o:    rcfile.c $(HFILES)
  375. Xsave.o:        save.c $(HFILES)
  376. Xscreen.o:    screen.c $(HFILES)
  377. Xsearch.o:    search.c $(HFILES)
  378. Xselect.o:    select.c $(HFILES)
  379. Xtime.o:        time.c
  380. Xwildmat.o:    wildmat.c $(HFILES)
  381. SHAR_EOF
  382. $TOUCH -am 0823153791 Makefile &&
  383. chmod 0600 Makefile ||
  384. echo "restore of Makefile failed"
  385. set `wc -c Makefile`;Wc_c=$1
  386. if test "$Wc_c" != "8147"; then
  387.     echo original size 8147, current size $Wc_c
  388. fi
  389. # ============= README ==============
  390. echo "x - extracting README (Text)"
  391. sed 's/^X//' << 'SHAR_EOF' > README &&
  392. XTin is a full screen threaded newsreader that uses the tass newsreader as 
  393. Xits base. Tass was developed by Rich Skrenta (skrenta@blekko.commodore.com).
  394. XTin can read news locally and also via an NNTP server (-r option). Tin 
  395. Xcontains more features than tass but they are still accessable to the
  396. Xbeginner and expert alike. I tried to follow the tass UI conventions as 
  397. Xmuch as possible.
  398. X
  399. XThis is a late beta release (I hope!). I am looking for people to test this
  400. Xand send me ideas/comments & bugs so that I can correct any and then send
  401. Xit off to comp.sources.misc sometime in the near future. 
  402. X
  403. XI find myself getting more done using this new reader than rn/vn and the like. 
  404. X
  405. XThis is the only newsreader that I know of that threads on the Archive-name:
  406. Xfield as used in comp.sources.* groups as well as on the more normal Subject:
  407. Xfield. Before anyone comments on Subject: threading not being right and I 
  408. Xshould look at trn, I have and its threads are neat but I get more done with
  409. Xtin than trn. It is especially good at saving and processing saved articles
  410. X& threads.
  411. X
  412. XI may be off the net for a couple of months at the end of September, but
  413. Xwill be contactable at the following address:
  414. X    Iain J. Lea
  415. X    BrueckenStr. 12
  416. X    8500 Nuernberg 90
  417. X    Germany.
  418. X    Phone. +49-911-331963
  419. X    Email. iain@estevax.uucp
  420. X
  421. XBugs and new features to be added are described in the file TODO
  422. X
  423. XBuilt & used on the following machines
  424. X--------------------------------------
  425. X    1) Vax 8850 & Ultrix 4.1 (Developed & most tested platform)
  426. X    2) Vax 11/785 & BSD 4.3
  427. X    3) 386 PC & Xenix 386
  428. X    4) 386 PC & ATT Unix SysVR4.0 (strange behaviour with inverse video)
  429. X    5) 386 PC & SCO Unix SysVR3.2 (strange behaviour with inverse video)
  430. X    6) 386 PC & ISC Unix SysVR3.2 with WINTCP (shakey ??)
  431. X
  432. XBuilding Tin
  433. X------------
  434. X    1)  type make and a few system types will be displayed
  435. X    2)  edit Makefile if you want to add/change -D DEFINES
  436. X    3)  type 'make <system type>' for your system
  437. X    4)  NOTE. the mmakefile needs rewriting (Any takers?) 
  438. X
  439. X    Note: the supplied Makefile will not run directly on BSD. It 
  440. X    requires a little work (Any takers to write a good Makefile?)
  441. X
  442. XInstalling Tin
  443. X--------------
  444. X    1)  make install
  445. X
  446. XCredits
  447. X-------
  448. XI wish to give credit to the following people for the routines
  449. Xthat they have written and I have used in tin:
  450. X
  451. XRich Skrenta  - tass v3.2 that tin is based upon.
  452. XSyd Weinstein - curses.c is taken from the elm mailreader
  453. XRich Salz     - wildmat regex pattern matching routine
  454. XWayne Brandt  - multi-part uudecode routine 
  455. X
  456. XI wish to thank the following people for comments & ideas:
  457. X
  458. XKlaus Arzig, Reiner Balling, Georg Biehler, Peter Dressler,
  459. XGerhard Ermer, Joachim Feld, Bernhard Gmelch, Joe Johnson,
  460. XCyrill Jung, Clifford Luke, Toni Metz, Klaus Neuberger,
  461. XOtto Niesser, Fredy Schwatz, Bernd Schwerin, Chris Smith
  462. X
  463. XFeatures of tass v3.2
  464. X---------------------
  465. Xo Organizes articles by threads.  Displays a really nice article
  466. X  selection page.
  467. X
  468. Xo Group selection page makes it easy to scan newsgroups, subscribe,
  469. X  unsubscribe, reorder your .newsrc
  470. X
  471. Xo If you've ever used Notes, this is the program for you.
  472. X  Tass looks a lot like Notes, but has a few improvements:
  473. X  visual group selection page, Notes didn't have one
  474. X  rn style unread article detection as opposed to single timeline
  475. X  uses standard /usr/spool/news article layout
  476. X
  477. XNewsreading style under Tass tends to be different than with rn.  Instead of
  478. Xplowing through each group reading everything unread, you may find yourself
  479. Xreading fewer articles in more groups.  It's easier to skip about and only
  480. Xread interesting threads with Tass.
  481. X
  482. XTass keeps an index file for each group.  The first time you enter a group,
  483. Xit will be a bit slow creating this file.  After that Tass will incrementally
  484. Xupdate the index file and there should be little delay.
  485. X
  486. XYou can also run Tass in "update mode" out of cron to update the indexes.
  487. X
  488. XFeatures New to Tin v1.00
  489. X-------------------------
  490. Xo  News can be read locally (ie. /usr/spool/news) or remotely by NNTP (-r option)
  491. Xo  User can config tin's options dynamically by 'M' command and have them
  492. X   saved to ~/.tin/tinrc.
  493. X
  494. Xo  Archive-name: mail header is used when saving and post processing 
  495. X   articles / threads.
  496. X
  497. Xo  Adjusts to size of screen for how much of Subject: & From: is displayed.
  498. X
  499. Xo  Post processes saved articles/threads. It will handle sh, uudecode,
  500. X   zoo, lharc, arc and zip (unzip) formats.
  501. X
  502. Xo  Articles can be sorted on Subject:, From:, Date: field or nothing. 
  503. X
  504. Xo  Killfile support (Not fully debugged). Kill articles at single group
  505. X   / all groups on Subject:,From: line or on user entered pattern.
  506. X
  507. Xo  Saves articles / threads to elm mailbox by pressing '=' when asked
  508. X   for name of saved file.
  509. X
  510. Xo  Displays history of user posted articles/replies & followups.
  511. X
  512. Xo  Higlighted bar / -> arrow can be used for selecting articles
  513. X
  514. Xo  Tagging of articles to save in a particular order
  515. X
  516. XAnd many other small changes.
  517. SHAR_EOF
  518. $TOUCH -am 0820185891 README &&
  519. chmod 0600 README ||
  520. echo "restore of README failed"
  521. set `wc -c README`;Wc_c=$1
  522. if test "$Wc_c" != "4930"; then
  523.     echo original size 4930, current size $Wc_c
  524. fi
  525. # ============= TODO ==============
  526. echo "x - extracting TODO (Text)"
  527. sed 's/^X//' << 'SHAR_EOF' > TODO &&
  528. XFIX FEATURES
  529. X------------
  530. Xo  Fix Makefile file to be more portable across platforms
  531. X
  532. Xo  Rewrite README and finish man page
  533. X
  534. Xo  Fix code to sort arts. At page level funny things happen.
  535. X
  536. Xo  Fix code to KILL articles. At page level funny things happen.
  537. X
  538. Xo  Fix code to KILL articles with 't' command.
  539. X
  540. Xo  Fix 'z' so that it stays unread even if a KILL is performed before
  541. X   leaving the group.
  542. X
  543. Xo  Fix job control? under SysVR4 where a ^Z makes the screen redraw
  544. X   itself and does not suspend the process as it should.
  545. X
  546. Xo  Fix help screens so that they understand if the terminal has more
  547. X   than 25 lines (ie. use LINES).
  548. X
  549. Xo  Fix -u -v -c that get malloc error sometimes on SysV machines
  550. X
  551. XADD FEATURES
  552. X------------
  553. Xo  Sort .newsrc according to preference.
  554. X
  555. Xo  Add 'H' context senstive level help screens
  556. X
  557. Xo  Add code to do unpack patches
  558. X
  559. Xo  Add '+' for saving in MH mail format
  560. X
  561. Xo  Add time period kill article
  562. X
  563. Xo  Add -s <dir> option to save new news to specifed spool dir for when
  564. X   one goes on holiday so that it can be read later by giving -S <dir>.
  565. X
  566. Xo  Add code to allow user to specify routine for post processing
  567. X   articles
  568. X
  569. XPIPEDREAMS
  570. X----------
  571. Xo  Add Virtual newsgroups (combination of newsgroups ie. virtual.ibm
  572. X   consists of comp.sys.ibm.* groups)
  573. X
  574. Xo  Add support for german text messages
  575. SHAR_EOF
  576. $TOUCH -am 0822182591 TODO &&
  577. chmod 0600 TODO ||
  578. echo "restore of TODO failed"
  579. set `wc -c TODO`;Wc_c=$1
  580. if test "$Wc_c" != "1305"; then
  581.     echo original size 1305, current size $Wc_c
  582. fi
  583. # ============= UPDATE_INDEX ==============
  584. echo "x - extracting UPDATE_INDEX (Text)"
  585. sed 's/^X//' << 'SHAR_EOF' > UPDATE_INDEX &&
  586. X#! /bin/csh -f
  587. X#  Iain Lea, 21-08-91
  588. X#  Script to update tin indexes from the at queue 
  589. X
  590. X# required for at
  591. Xsetenv HOME  /piez/iain
  592. Xsetenv NAME  'Iain J. Lea'
  593. Xsetenv GROUP 'piez'
  594. Xsetenv PATH  :/usr/ucb:/bin:/usr/bin:/usr/local
  595. X
  596. X# specific for this script
  597. Xsetenv SCRIPT /piez/iain/bin/UPDATE_INDEX
  598. Xsetenv TIME 1000
  599. Xsetenv TINDIR /piez/iain/bin
  600. X
  601. X# hangs update indexes onto system batch queue
  602. X+ $TINDIR/tin -u
  603. X
  604. X# sleeps and then submits this script again for tommorow
  605. X/usr/bin/sleep 120
  606. X/usr/local/at $TIME $SCRIPT
  607. SHAR_EOF
  608. $TOUCH -am 0821093891 UPDATE_INDEX &&
  609. chmod 0700 UPDATE_INDEX ||
  610. echo "restore of UPDATE_INDEX failed"
  611. set `wc -c UPDATE_INDEX`;Wc_c=$1
  612. if test "$Wc_c" != "512"; then
  613.     echo original size 512, current size $Wc_c
  614. fi
  615. # ============= alloca.c ==============
  616. echo "x - extracting alloca.c (Text)"
  617. sed 's/^X//' << 'SHAR_EOF' > alloca.c &&
  618. X/*
  619. X    alloca -- (mostly) portable public-domain implementation -- D A Gwyn
  620. X
  621. X    last edit:    86/05/30    rms
  622. X       include config.h, since on VMS it renames some symbols.
  623. X       Use xmalloc instead of malloc.
  624. X
  625. X    This implementation of the PWB library alloca() function,
  626. X    which is used to allocate space off the run-time stack so
  627. X    that it is automatically reclaimed upon procedure exit, 
  628. X    was inspired by discussions with J. Q. Johnson of Cornell.
  629. X
  630. X    It should work under any C implementation that uses an
  631. X    actual procedure stack (as opposed to a linked list of
  632. X    frames).  There are some preprocessor constants that can
  633. X    be defined when compiling for your specific system, for
  634. X    improved efficiency; however, the defaults should be okay.
  635. X
  636. X    The general concept of this implementation is to keep
  637. X    track of all alloca()-allocated blocks, and reclaim any
  638. X    that are found to be deeper in the stack than the current
  639. X    invocation.  This heuristic does not reclaim storage as
  640. X    soon as it becomes invalid, but it will do so eventually.
  641. X
  642. X    As a special case, alloca(0) reclaims storage without
  643. X    allocating any.  It is a good idea to use alloca(0) in
  644. X    your main control loop, etc. to force garbage collection.
  645. X*/
  646. X
  647. X#ifndef lint
  648. Xstatic char    SCCSid[] = "@(#)alloca.c    1.1";    /* for the "what" utility */
  649. X#endif
  650. X
  651. X#ifdef emacs
  652. X#include "config.h"
  653. X#ifdef static
  654. X/* actually, only want this if static is defined as ""
  655. X   -- this is for usg, in which emacs must undefine static
  656. X   in order to make unexec workable
  657. X   */
  658. X#ifndef STACK_DIRECTION
  659. Xyou
  660. Xlose
  661. X-- must know STACK_DIRECTION at compile-time
  662. X#endif /* STACK_DIRECTION undefined */
  663. X#endif /* static */
  664. X#endif /* emacs */
  665. X
  666. X#ifdef X3J11
  667. Xtypedef void    *pointer;        /* generic pointer type */
  668. X#else
  669. Xtypedef char    *pointer;        /* generic pointer type */
  670. X#endif
  671. X
  672. X#define    NULL    0            /* null pointer constant */
  673. X
  674. Xextern void    free();
  675. Xextern pointer    xmalloc();
  676. X
  677. X/*
  678. X    Define STACK_DIRECTION if you know the direction of stack
  679. X    growth for your system; otherwise it will be automatically
  680. X    deduced at run-time.
  681. X
  682. X    STACK_DIRECTION > 0 => grows toward higher addresses
  683. X    STACK_DIRECTION < 0 => grows toward lower addresses
  684. X    STACK_DIRECTION = 0 => direction of growth unknown
  685. X*/
  686. X
  687. X#ifndef STACK_DIRECTION
  688. X#define    STACK_DIRECTION    0        /* direction unknown */
  689. X#endif
  690. X
  691. X#if STACK_DIRECTION != 0
  692. X
  693. X#define    STACK_DIR    STACK_DIRECTION    /* known at compile-time */
  694. X
  695. X#else    /* STACK_DIRECTION == 0; need run-time code */
  696. X
  697. Xstatic int    stack_dir;        /* 1 or -1 once known */
  698. X#define    STACK_DIR    stack_dir
  699. X
  700. Xstatic void
  701. Xfind_stack_direction (/* void */)
  702. X{
  703. X  static char    *addr = NULL;    /* address of first
  704. X                   `dummy', once known */
  705. X  auto char    dummy;        /* to get stack address */
  706. X
  707. X  if (addr == NULL)
  708. X    {                /* initial entry */
  709. X      addr = &dummy;
  710. X
  711. X      find_stack_direction ();    /* recurse once */
  712. X    }
  713. X  else                /* second entry */
  714. X    if (&dummy > addr)
  715. X      stack_dir = 1;        /* stack grew upward */
  716. X    else
  717. X      stack_dir = -1;        /* stack grew downward */
  718. X}
  719. X
  720. X#endif    /* STACK_DIRECTION == 0 */
  721. X
  722. X/*
  723. X    An "alloca header" is used to:
  724. X    (a) chain together all alloca()ed blocks;
  725. X    (b) keep track of stack depth.
  726. X
  727. X    It is very important that sizeof(header) agree with malloc()
  728. X    alignment chunk size.  The following default should work okay.
  729. X*/
  730. X
  731. X#ifndef    ALIGN_SIZE
  732. X#define    ALIGN_SIZE    sizeof(double)
  733. X#endif
  734. X
  735. Xtypedef union hdr
  736. X{
  737. X  char    align[ALIGN_SIZE];    /* to force sizeof(header) */
  738. X  struct
  739. X    {
  740. X      union hdr *next;        /* for chaining headers */
  741. X      char *deep;        /* for stack depth measure */
  742. X    } h;
  743. X} header;
  744. X
  745. X/*
  746. X    alloca( size ) returns a pointer to at least `size' bytes of
  747. X    storage which will be automatically reclaimed upon exit from
  748. X    the procedure that called alloca().  Originally, this space
  749. X    was supposed to be taken from the current stack frame of the
  750. X    caller, but that method cannot be made to work for some
  751. X    implementations of C, for example under Gould's UTX/32.
  752. X*/
  753. X
  754. Xstatic header *last_alloca_header = NULL; /* -> last alloca header */
  755. X
  756. Xpointer
  757. Xalloca (size)            /* returns pointer to storage */
  758. X     unsigned    size;        /* # bytes to allocate */
  759. X{
  760. X  auto char    probe;        /* probes stack depth: */
  761. X  register char    *depth = &probe;
  762. X
  763. X#if STACK_DIRECTION == 0
  764. X  if (STACK_DIR == 0)        /* unknown growth direction */
  765. X    find_stack_direction ();
  766. X#endif
  767. X
  768. X                /* Reclaim garbage, defined as all alloca()ed storage that
  769. X                   was allocated from deeper in the stack than currently. */
  770. X
  771. X  {
  772. X    register header    *hp;    /* traverses linked list */
  773. X
  774. X    for (hp = last_alloca_header; hp != NULL;)
  775. X      if (STACK_DIR > 0 && hp->h.deep > depth
  776. X      || STACK_DIR < 0 && hp->h.deep < depth)
  777. X    {
  778. X      register header    *np = hp->h.next;
  779. X
  780. X      free ((pointer) hp);    /* collect garbage */
  781. X
  782. X      hp = np;        /* -> next header */
  783. X    }
  784. X      else
  785. X    break;            /* rest are not deeper */
  786. X
  787. X    last_alloca_header = hp;    /* -> last valid storage */
  788. X  }
  789. X
  790. X  if (size == 0)
  791. X    return NULL;        /* no allocation required */
  792. X
  793. X  /* Allocate combined header + user data storage. */
  794. X
  795. X  {
  796. X    register pointer    new = xmalloc (sizeof (header) + size);
  797. X    /* address of header */
  798. X
  799. X    ((header *)new)->h.next = last_alloca_header;
  800. X    ((header *)new)->h.deep = depth;
  801. X
  802. X    last_alloca_header = (header *)new;
  803. X
  804. X    /* User storage begins just after header. */
  805. X
  806. X    return (pointer)((char *)new + sizeof(header));
  807. X  }
  808. X}
  809. X
  810. Xpointer xmalloc(n)
  811. Xunsigned int n;
  812. X{
  813. X  extern pointer malloc();
  814. X  pointer cp;
  815. X  static char mesg[] = "xmalloc: no memory!\n";
  816. X
  817. X  cp = malloc(n);
  818. X  if (! cp) {
  819. X    write (2, mesg, sizeof(mesg) - 1);
  820. X    exit(1);
  821. X  }
  822. X  return cp;
  823. X}
  824. SHAR_EOF
  825. $TOUCH -am 0815172991 alloca.c &&
  826. chmod 0600 alloca.c ||
  827. echo "restore of alloca.c failed"
  828. set `wc -c alloca.c`;Wc_c=$1
  829. if test "$Wc_c" != "5457"; then
  830.     echo original size 5457, current size $Wc_c
  831. fi
  832. # ============= art.c ==============
  833. echo "x - extracting art.c (Text)"
  834. sed 's/^X//' << 'SHAR_EOF' > art.c &&
  835. X/*
  836. X *  Project   : tin - a visual threaded usenet newsreader
  837. X *  Module    : art.c
  838. X *  Author    : R.Skrenta / I.Lea
  839. X *  Created   : 01-04-91
  840. X *  Updated   : 22-08-91
  841. X *  Release   : 1.0
  842. X *  Notes     :
  843. X *  Copyright : (c) Copyright 1991 by Rich Skrenta & Iain Lea
  844. X *                You may  freely  copy or  redistribute  this software,
  845. X *              so  long as there is no profit made from its use, sale
  846. X *              trade or  reproduction.  You may not change this copy-
  847. X *              right notice, and it must be included in any copy made
  848. X */
  849. X
  850. X#include    "tin.h"
  851. X
  852. X#define HEADER_LEN    1024
  853. X
  854. Xextern int errno;
  855. X
  856. Xchar index_file[LEN+1];
  857. Xchar *glob_art_group;
  858. Xint index_file_killed = FALSE;
  859. Xlong last_read_article;
  860. X
  861. X#ifdef SIGTSTP
  862. Xvoid art_susp (sig)
  863. X    int sig;
  864. X{
  865. X    char buf[LEN];
  866. X    
  867. X    Raw(FALSE);
  868. X    putchar('\n');
  869. X    signal(SIGTSTP, SIG_DFL);
  870. X#ifdef BSD
  871. X    sigsetmask(sigblock(0) & ~(1 << (SIGTSTP -1)));
  872. X#endif
  873. X    kill(0, SIGTSTP);
  874. X
  875. X    signal(SIGTSTP, art_susp);
  876. X
  877. X    if (! update) {
  878. X        mail_setup ();
  879. X    
  880. X        Raw(TRUE);
  881. X
  882. X        ClearScreen();
  883. X        sprintf (buf, txt_group, glob_art_group);
  884. X        wait_message (buf);
  885. X    }
  886. X}
  887. X#endif
  888. X
  889. X
  890. X/*
  891. X *  Convert a string to a long, only look at first n characters
  892. X */
  893. X
  894. Xlong my_atol (s, n)
  895. X    char *s;
  896. X    int n;
  897. X{
  898. X    long ret = 0;
  899. X
  900. X    while (*s && n--) {
  901. X        if (*s >= '0' && *s <= '9')
  902. X            ret = ret * 10 + (*s - '0');
  903. X        else
  904. X            return -1;
  905. X        s++;
  906. X    }
  907. X
  908. X    return ret;
  909. X}
  910. X
  911. X
  912. X/*
  913. X *  Construct the pointers to the basenotes of each thread
  914. X *  arts[] contains every article in the group.  inthread is
  915. X *  set on each article that is after the first article in the
  916. X *  thread.  Articles which have been expired have their thread
  917. X *  set to -2 (ART_EXPIRED).
  918. X */
  919. X
  920. Xvoid find_base ()
  921. X{
  922. X    int i;
  923. X
  924. X    top_base = 0;
  925. X
  926. X    for (i = 0; i < top; i++)
  927. X        if (! arts[i].inthread && arts[i].thread != ART_EXPIRED) {
  928. X            if (top_base >= max_art)
  929. X                expand_art ();
  930. X            base[top_base++] = i;
  931. X        }
  932. X}
  933. X
  934. X/* 
  935. X *  Count the number of non-expired and non-killed articles in arts[]
  936. X */
  937. X
  938. Xint num_of_arts ()
  939. X{
  940. X    int sum = 0;
  941. X    register int i;
  942. X
  943. X    for (i = 0; i < top; i++) {
  944. X        if (arts[i].thread != ART_EXPIRED && ! arts[i].tagged) {
  945. X            sum++;
  946. X        }
  947. X    }
  948. X
  949. X    return sum;
  950. X}
  951. X
  952. X/*
  953. X *  Do we have an entry for article art?
  954. X */
  955. X
  956. Xint valid_artnum (art)
  957. X    long art;
  958. X{
  959. X    register int i;
  960. X
  961. X    for (i = 0; i < top; i++)
  962. X        if (arts[i].artnum == art)
  963. X            return i;
  964. X
  965. X    return -1;
  966. X}
  967. X
  968. X
  969. X/*
  970. X *  Return TRUE if arts[] contains any expired articles
  971. X *  (articles we have an entry for which don't have a corresponding
  972. X *   article file in the spool directory)
  973. X */
  974. X
  975. Xint purge_needed ()
  976. X{
  977. X    register int i;
  978. X
  979. X    for (i = 0; i < top; i++)
  980. X        if (arts[i].thread == ART_EXPIRED)
  981. X            return TRUE;
  982. X
  983. X    return FALSE;
  984. X}
  985. X
  986. X
  987. X/*
  988. X *  Main group indexing routine.  Group should be the name of the
  989. X *  newsgroup, i.e. "comp.unix.amiga".  group_path should be the
  990. X *  same but with the .'s turned into /'s: "comp/unix/amiga"
  991. X *
  992. X *  Will read any existing index, create or incrementally update
  993. X *  the index by looking at the articles in the spool directory,
  994. X *  and attempt to write a new index if necessary.
  995. X */
  996. X
  997. Xvoid index_group (group, group_path)
  998. X    char *group;
  999. X    char *group_path;
  1000. X{
  1001. X    int killed = FALSE;
  1002. X    int modified = FALSE;
  1003. X    glob_art_group = group;
  1004. X
  1005. X#ifdef SIGTSTP
  1006. X    signal(SIGTSTP, art_susp);
  1007. X#endif
  1008. X
  1009. X    if (! update) {
  1010. X        sprintf (msg, txt_group, group);
  1011. X        wait_message (msg);
  1012. X    }
  1013. X
  1014. X    hash_reclaim ();
  1015. X    free_art_array ();
  1016. X
  1017. X    if (local_index)
  1018. X        find_local_index (group);
  1019. X    else
  1020. X        sprintf (index_file, "%s/%s/%s", spooldir, group_path, INDEXDIR);
  1021. X
  1022. X    /*
  1023. X     *  load articles from index file if it exists
  1024. X     */
  1025. X    load_index ();
  1026. X
  1027. X    /*
  1028. X     *  load killed articles into arts[] because kill arts is OFF
  1029. X     */
  1030. X    if (! kill_articles && index_file_killed) {
  1031. X        index_file_killed = FALSE;
  1032. X        last_read_article = 0L;
  1033. X    }
  1034. X
  1035. X    /*
  1036. X     *  add any articles to arts[] that are new or were killed
  1037. X     */
  1038. X    modified = read_group (group, group_path);
  1039. X
  1040. X    /*
  1041. X     *  compare kill descriptions to arts[] and kill mark any that match
  1042. X     */
  1043. X    killed = kill_any_articles (group);
  1044. X    
  1045. X    if (modified || killed || purge_needed()) {
  1046. X        if (local_index) {        /* writing index in home directory */
  1047. X            setuid(real_uid);    /* so become them */
  1048. X            setgid(real_gid);
  1049. X        }
  1050. X
  1051. X        if (killed) {
  1052. X            reload_index_file (group, killed);
  1053. X        } else {
  1054. X            dump_index (group, FALSE);
  1055. X            make_threads (FALSE);
  1056. X            find_base ();
  1057. X        }
  1058. X
  1059. X        if (local_index) {
  1060. X            setuid(tin_uid);
  1061. X            setgid(tin_gid);
  1062. X        }
  1063. X    } else {
  1064. X        make_threads (FALSE);
  1065. X        find_base ();
  1066. X    }
  1067. X    
  1068. X    if ((modified || killed) && ! update) {
  1069. X        clear_message();
  1070. X    }
  1071. X}
  1072. X
  1073. X/*
  1074. X *  Index a group.  Assumes any existing index has already been
  1075. X *  loaded.
  1076. X */
  1077. X
  1078. Xint read_group (group, group_path)
  1079. X    char *group;
  1080. X    char *group_path;
  1081. X{
  1082. X    int fd;
  1083. X    long art;
  1084. X    int count;
  1085. X    int modified = FALSE;
  1086. X    int respnum;
  1087. X    register int i;
  1088. X
  1089. X    setup_base (group, group_path);    /* load article numbers into base[] */
  1090. X    count = 0;
  1091. X
  1092. X    for (i = 0; i < top_base; i++) {    /* for each article # */
  1093. X        art = base[i];
  1094. X
  1095. X/*
  1096. X *  Do we already have this article in our index?  Change thread from
  1097. X *  -2 (ART_EXPIRED) to -1 (ART_NORMAL) if so and skip the header eating.
  1098. X */
  1099. X
  1100. X        if ((respnum = valid_artnum (art)) >= 0 || art <= last_read_article) {
  1101. X            arts[respnum].thread = ART_NORMAL;
  1102. X            arts[respnum].unread = ART_UNREAD;
  1103. X            continue;
  1104. X        }
  1105. X
  1106. X        if (! modified) {
  1107. X            modified = TRUE;   /* we've modified the index */
  1108. X                               /* it will need to be re-written */
  1109. X        }
  1110. X
  1111. X        if ((fd = open_header_fd (group_path, art)) < 0) {
  1112. X            continue;
  1113. X        }
  1114. X        
  1115. X        /*
  1116. X         *  Add article to arts[]
  1117. X         */
  1118. X        if (top >= max_art)
  1119. X            expand_art();
  1120. X
  1121. X        arts[top].artnum = art;
  1122. X        arts[top].thread = ART_NORMAL;
  1123. X
  1124. X        set_article (&arts[top]);
  1125. X
  1126. X        if (! parse_headers (fd, &arts[top])) {
  1127. X            continue;
  1128. X        }
  1129. X        close (fd);
  1130. X        last_read_article = arts[top].artnum;    /* used if arts are killed */
  1131. X        top++;
  1132. X
  1133. X        if (++count % 10 == 0 && ! update) {
  1134. X            sprintf (msg, txt_indexing, count);
  1135. X            wait_message (msg);
  1136. X        }
  1137. X    }
  1138. X
  1139. X    return modified;
  1140. X}
  1141. X
  1142. X
  1143. X/*
  1144. X *  Go through the articles in arts[] and use .thread to snake threads
  1145. X *  through them.  Use the subject line to construct threads.  The
  1146. X *  first article in a thread should have .inthread set to FALSE, the
  1147. X *  rest TRUE.  Only do unexprired articles we haven't visited yet
  1148. X *  (arts[].thread == -1 ART_NORMAL).
  1149. X */
  1150. X
  1151. Xvoid make_threads (rethread)
  1152. X    int rethread;
  1153. X{
  1154. X    register int i;
  1155. X    register int j;
  1156. X
  1157. X    /*
  1158. X     *  .thread & .inthread need to be reset if re-threading arts[]
  1159. X     */
  1160. X    if (rethread) {
  1161. X        for (i=0 ; i < top ; i++) {
  1162. X            arts[i].thread = ART_NORMAL;
  1163. X            arts[i].inthread = FALSE;
  1164. X        }
  1165. X    }
  1166. X
  1167. X    switch (sort_art_type) {
  1168. X        case SORT_BY_NONE:        /* don't sort at all */
  1169. X            qsort (arts, top, sizeof (struct header), artnum_comp);
  1170. X            break;
  1171. X        case SORT_BY_SUBJ:
  1172. X            qsort (arts, top, sizeof (struct header), subj_comp);
  1173. X            break;
  1174. X        case SORT_BY_FROM:
  1175. X            qsort (arts, top, sizeof (struct header), from_comp);
  1176. X            break;
  1177. X        case SORT_BY_DATE:
  1178. X            qsort (arts, top, sizeof (struct header), date_comp);
  1179. X            break;
  1180. X        default:
  1181. X            break;
  1182. X    }
  1183. X
  1184. X    for (i = 0; i < top; i++) {
  1185. X        if (arts[i].thread == ART_NORMAL) {
  1186. X            for (j = i+1; j < top; j++) {
  1187. X                if (arts[j].thread != ART_EXPIRED &&
  1188. X                    ((arts[i].subject == arts[j].subject) ||
  1189. X                    ((arts[i].part || arts[i].patch) &&
  1190. X                    arts[i].archive == arts[j].archive))) {
  1191. X                        arts[i].thread = j;
  1192. X                        arts[j].inthread = TRUE;
  1193. X                        break;
  1194. X                }
  1195. X            }
  1196. X        }
  1197. X    }
  1198. X}
  1199. X
  1200. X/*
  1201. X *  Return a pointer into s eliminating any leading Re:'s.  Example:
  1202. X *
  1203. X *      Re: Reorganization of misc.jobs
  1204. X *      ^   ^
  1205. X */
  1206. X
  1207. Xchar *eat_re (s)
  1208. X    char *s;
  1209. X{
  1210. X
  1211. X    while (*s == 'r' || *s == 'R') {
  1212. X        if ((*(s+1) == 'e' || *(s+1) == 'E')) {
  1213. X            if (*(s+2) == ':')
  1214. X                s += 3;
  1215. X            else if (*(s+2) == '^' && isdigit(*(s+3)) && *(s+4) == ':')
  1216. X                s += 5;            /* hurray nn */
  1217. X            else
  1218. X                break;
  1219. X        } else
  1220. X            break;
  1221. X        while (*s == ' ')
  1222. X            s++;
  1223. X    }
  1224. X
  1225. X    return s;
  1226. X}
  1227. X
  1228. X/*
  1229. X *  Hash the subjects (after eating the Re's off) for a quicker
  1230. X *  thread search later.  We store the hashes for subjects in the
  1231. X *  index file for speed.
  1232. X */
  1233. X
  1234. Xlong hash_s(s)
  1235. X    char *s;
  1236. X{
  1237. X    char *t;
  1238. X    long h = 0;
  1239. X
  1240. X    t = s;
  1241. X
  1242. X    while (*t)
  1243. X        h = h * 64 + *t++;
  1244. X
  1245. X    return h;
  1246. X}
  1247. X
  1248. X
  1249. Xint parse_headers (fd, h)
  1250. X    int fd;
  1251. X    struct header *h;
  1252. X{
  1253. X    char buf[HEADER_LEN];
  1254. X    char buf2[HEADER_LEN];
  1255. X    char *ptr, *ptrline, *s;
  1256. X    int n = 0, len = 0, lineno = 0;
  1257. X    int flag;
  1258. X    int got_subject = FALSE;
  1259. X    int got_from = FALSE;
  1260. X    int got_date = FALSE;
  1261. X    int got_archive = FALSE;
  1262. X    
  1263. X    if ((n = read(fd, buf, HEADER_LEN)) <= 0)
  1264. X        return FALSE;
  1265. X
  1266. X    buf[n-1] = '\0';
  1267. X
  1268. X    ptr = buf;
  1269. X
  1270. X    while (1) {
  1271. X        for (ptrline = ptr; *ptr && *ptr != '\n'; ptr++) {
  1272. X            if (((*ptr) & 0x7F) < 32) {
  1273. X                *ptr = ' ';
  1274. X            }
  1275. X        }
  1276. X        flag = *ptr;
  1277. X        *ptr++ = '\0';
  1278. X        lineno++;
  1279. X
  1280. X        if (! got_from && strncmp(ptrline, "From: ", 6) == 0) {
  1281. X            my_strncpy(buf2, ptrline+6, max_from+1);
  1282. X            buf2[max_from] = '\0';
  1283. X            h->from = hash_str (buf2);
  1284. X            got_from = TRUE;
  1285. X        } else if (! got_subject && strncmp(ptrline, "Subject: ", 9) == 0) {
  1286. X            my_strncpy (buf2, ptrline+9, max_subj+max_from+1);
  1287. X            s = eat_re (buf2);
  1288. X            s[max_subj+max_from] = '\0';
  1289. X            h->subject = hash_str (eat_re (s));
  1290. X            got_subject = TRUE;
  1291. X        } else if (! got_date && strncmp(ptrline, "Date: ", 6) == 0) {
  1292. X            my_strncpy (buf2, ptrline+6, 32);
  1293. X            parse_date (buf2 ,h->date);
  1294. X            got_date = TRUE;
  1295. X        } else if (strncmp(ptrline, "Archive-name: ", 14) == 0) {
  1296. X            if ((s = (char *) strchr (ptrline+14, '/')) != NULL) {
  1297. X                my_strncpy(buf2, ptrline+14, MAX_ARCH);
  1298. X                if (strncmp (s+1,"part",4) == 0 ||
  1299. X                    strncmp (s+1,"Part",4) == 0) {
  1300. X                    h->part = str_dup (s+5);
  1301. X                    len = (int) strlen (h->part);
  1302. X                    if (h->part[len-1] == '\n') {
  1303. X                        h->part[len-1] = '\0';
  1304. X                    }
  1305. X                } else {
  1306. X                    if (strncmp (s+1,"patch",5) == 0 ||
  1307. X                        strncmp (s+1,"Patch",5) == 0) {
  1308. X                        h->patch = str_dup (s+6);
  1309. X                        len = (int) strlen (h->patch);
  1310. X                        if (h->patch[len-1] == '\n') {
  1311. X                            h->patch[len-1] = '\0';
  1312. X                        }
  1313. X                    }
  1314. X                }
  1315. X                if (h->part || h->patch) {
  1316. X                    s = buf2;
  1317. X                    while (*s && *s != '/')
  1318. X                        s++;
  1319. X                    *s = '\0';    
  1320. X                    s = buf2;
  1321. X                    h->archive = hash_str (s);
  1322. X                    got_archive = TRUE;
  1323. X                }
  1324. X            }
  1325. X        }
  1326. X
  1327. X        if (! flag || lineno > 25 || got_archive) {
  1328. X            debug_print_header (h);
  1329. X            return TRUE;
  1330. X        }
  1331. X    }
  1332. X}
  1333. X
  1334. X/* 
  1335. X *  Write out an index file.  Write the group name first so if
  1336. X *  local indexing is done we can disambiguate between group name
  1337. X *  hash collisions by looking at the index file.
  1338. X *
  1339. X *  NOTE: check out the add_string routine in hashstr.c to
  1340. X *  understand what *iptr is doing in this routine.
  1341. X */
  1342. X
  1343. Xvoid dump_index (group, killed)
  1344. X    char *group;
  1345. X    int killed;
  1346. X{
  1347. X    char nam[LEN+1];
  1348. X    FILE *fp;
  1349. X    int *iptr;
  1350. X    int realnum;
  1351. X    register int i;
  1352. X
  1353. X    sprintf (nam, "%s.%d", index_file, getpid());
  1354. X    if ((fp = fopen (nam, "w")) == NULL) {
  1355. X        error_message (txt_cannot_open, nam);
  1356. X        return;
  1357. X    }
  1358. X
  1359. X    /*
  1360. X     *  dump group header info.
  1361. X     */
  1362. X    if (sort_art_type != SORT_BY_NONE) {
  1363. X        qsort (arts, top, sizeof (struct header), artnum_comp);
  1364. X    }
  1365. X    fprintf(fp, "%s\n", group);
  1366. X    fprintf(fp, "%d\n", num_of_arts ());
  1367. X    if (last_read_article > arts[top-1].artnum) {
  1368. X        fprintf(fp, "%ld\n", last_read_article);
  1369. X    } else {
  1370. X        fprintf(fp, "%ld\n", arts[top-1].artnum);
  1371. X    }
  1372. X    if (index_file_killed && killed) {
  1373. X        fprintf (fp, "KILLED\n");
  1374. X    } else {
  1375. X        fprintf (fp, "COMPLETE\n");
  1376. X    }
  1377. X
  1378. X    /*
  1379. X     *  dump articles
  1380. X     */
  1381. X    realnum = 0; 
  1382. X    for (i = 0; i < top; i++) {
  1383. X        if (arts[i].thread != ART_EXPIRED && ! arts[i].tagged) { 
  1384. X            debug_print_header (&arts[i]);
  1385. X
  1386. X            fprintf(fp, "%ld\n", arts[i].artnum);
  1387. X
  1388. X            iptr = (int *) arts[i].subject;
  1389. X            iptr--;
  1390. X
  1391. X            if (! arts[i].subject) {
  1392. X                fprintf(fp, " \n");
  1393. X            } else if (*iptr < 0 || *iptr > top) {
  1394. X                fprintf(fp, " %s\n", arts[i].subject);
  1395. X                *iptr = realnum;
  1396. X/*
  1397. X            } else if (arts[*iptr].tagged) {
  1398. X                fprintf(fp, " %s\n", arts[i].subject);
  1399. X                *iptr = realnum;
  1400. X            } else if (killed && *iptr == i) {
  1401. X*/
  1402. X            } else if (killed || *iptr == i) {
  1403. X                fprintf(fp, " %s\n", arts[i].subject);
  1404. X            } else {
  1405. X                fprintf(fp, "%%%d\n", *iptr);
  1406. X            }
  1407. X    
  1408. X            iptr = (int *) arts[i].from;
  1409. X            iptr--;
  1410. X
  1411. X            if (! arts[i].from) {
  1412. X                fprintf (fp, " \n");
  1413. X            } else if (*iptr < 0 || *iptr > top) {
  1414. X                fprintf (fp, " %s\n", arts[i].from);
  1415. X                *iptr = realnum;
  1416. X/*
  1417. X            } else if (arts[*iptr].tagged) {
  1418. X                fprintf(fp, " %s\n", arts[i].from);
  1419. X                *iptr = realnum;
  1420. X            } else if (killed && *iptr == i) {
  1421. X*/            
  1422. X            } else if (killed || *iptr == i) {
  1423. X                fprintf(fp, " %s\n", arts[i].from);
  1424. X            } else {
  1425. X                fprintf(fp, "%%%d\n", *iptr);
  1426. X            }
  1427. X
  1428. X            fprintf (fp, "%s\n", arts[i].date);
  1429. X            
  1430. X            iptr = (int *) arts[i].archive;
  1431. X            iptr--;
  1432. X
  1433. X            if (! arts[i].archive) {
  1434. X                fprintf (fp, "\n");
  1435. X            } else if (*iptr < 0 || *iptr > top) {
  1436. X                fprintf (fp, " %s\n", arts[i].archive);
  1437. X                *iptr = realnum;
  1438. X/*
  1439. X            } else if (arts[*iptr].tagged) {
  1440. X                fprintf (fp, " %s\n", arts[i].archive);
  1441. X                *iptr = realnum;
  1442. X*/                
  1443. X            } else if (arts[i].part || arts[i].patch) {
  1444. X/*
  1445. X                if (killed && *iptr == i) {
  1446. X*/                
  1447. X                if (killed || *iptr == i) {
  1448. X                    fprintf(fp, " %s\n", arts[i].archive);
  1449. X                } else {
  1450. X                    fprintf (fp, "%%%d\n", *iptr);
  1451. X                }
  1452. X            } else {
  1453. X                fprintf (fp, "\n");
  1454. X            }
  1455. X            
  1456. X            if (! arts[i].part) {
  1457. X                fprintf (fp, " \n");
  1458. X            } else {
  1459. X                fprintf (fp, "%s\n", arts[i].part);
  1460. X            }
  1461. X
  1462. X            if (! arts[i].patch) {
  1463. X                fprintf (fp, " \n");
  1464. X            } else {
  1465. X                fprintf (fp, "%s\n", arts[i].patch);
  1466. X            }
  1467. X
  1468. X            realnum++;
  1469. X        }
  1470. X    }
  1471. X    fclose (fp);
  1472. X    chmod (index_file, 0644);
  1473. X    rename_file (nam, index_file);
  1474. X    if (debug) {
  1475. X        sprintf (msg, "/bin/cp %s INDEX", index_file);
  1476. X        system (msg);
  1477. X    }
  1478. X}
  1479. X
  1480. X/*
  1481. X *  strncpy that stops at a newline and null terminates
  1482. X */
  1483. X
  1484. Xvoid my_strncpy(p, q, n)
  1485. X    char *p;
  1486. X    char *q;
  1487. X    int n;
  1488. X{
  1489. X    while (n--) {
  1490. X        if (!*q || *q == '\n')
  1491. X            break;
  1492. X        *p++ = *q++;
  1493. X    }
  1494. X    *p = '\0';
  1495. X}
  1496. X
  1497. X/*
  1498. X *  Read in an index file.
  1499. X *
  1500. X *  index file header 
  1501. X *    1.  newsgroup name (ie. alt.sources)
  1502. X *    2.  number of articles (ie. 26)
  1503. X *    3.  number of last read article (ie. 210)
  1504. X *    4.  Is this a complete/killed index file (ie. COMPLETE/KILLED)
  1505. X *  index file record
  1506. X *    1.  article number   (ie. 183)                [mandatory]
  1507. X *    2.  Subject: line    (ie. Which newsreader?)  [mandatory]
  1508. X *    3.  From: line       (ie. iain@norisc)        [mandatory]
  1509. X *    4.  Date: of posting (ie. 911231125959)       [mandatory]
  1510. X *    5.  Archive: name    (ie. compiler)           [optional]
  1511. X *    6.  Part number of Archive: name  (ie. 01)    [optional]
  1512. X *    7.  Patch number of Archive: name (ie. 01)    [optional]
  1513. X */
  1514. X
  1515. Xint load_index ()
  1516. X{
  1517. X    int error = 0;
  1518. X    int i, n;
  1519. X    char buf[LEN+1], *p;
  1520. X    FILE *fp;
  1521. X
  1522. X    top = 0;
  1523. X    last_read_article = 0L;
  1524. X
  1525. X    if ((fp = fopen (index_file, "r")) == NULL) {
  1526. X        return FALSE;
  1527. X    }
  1528. X
  1529. X    debug_print_comment ("*** LOADING ***");
  1530. X
  1531. X    /*
  1532. X     *  load header - discard group name, num. of arts in index file after any arts were killed
  1533. X     */
  1534. X    if (fgets(buf, LEN, fp) == NULL ||
  1535. X        fgets(buf, LEN, fp) == NULL) {
  1536. X        error = 0;            
  1537. X        goto corrupt_index;    
  1538. X    }
  1539. X    i = atoi (buf);
  1540. X
  1541. X    /*
  1542. X     * num. of last_read_article including any that were killed
  1543. X     */
  1544. X    if (fgets(buf, LEN, fp) == NULL) {
  1545. X        error = 1;                
  1546. X        goto corrupt_index;    
  1547. X    }                            
  1548. X    last_read_article = atol (buf);
  1549. X    
  1550. X    /*
  1551. X     * is index file complete or were articles killed when it was dumped
  1552. X     */
  1553. X    if (fgets(buf, LEN, fp) == NULL) {
  1554. X        error = 2;                
  1555. X        goto corrupt_index;    
  1556. X    }
  1557. X    index_file_killed = (buf[0] == 'K' ? TRUE : FALSE);
  1558. X    
  1559. X    /*
  1560. X     *  load articles
  1561. X     */
  1562. X    for (; top < i ; top++) {
  1563. X        if (top >= max_art) {
  1564. X            expand_art ();
  1565. X        }
  1566. X
  1567. X        arts[top].thread = ART_EXPIRED;
  1568. X        set_article (&arts[top]);
  1569. X
  1570. X        /*
  1571. X         * Article no.
  1572. X         */
  1573. X        if (fgets(buf, LEN, fp) == NULL) {
  1574. X            error = 3;
  1575. X            goto corrupt_index;
  1576. X        }
  1577. X        arts[top].artnum = atol(buf);
  1578. X
  1579. X        /*
  1580. X         * Subject:
  1581. X         */
  1582. X        if (fgets(buf, LEN, fp) == NULL) {
  1583. X            error = 4;
  1584. X            goto corrupt_index;
  1585. X        }
  1586. X
  1587. X        if (buf[0] == '%') {
  1588. X            n = atoi (&buf[1]);
  1589. X            if (n >= top || n < 0) {
  1590. X                error = 5;
  1591. X                goto corrupt_index;
  1592. X            }
  1593. X            arts[top].subject = arts[n].subject;
  1594. X        } else if (buf[0] == ' ') {
  1595. X            for (p = &buf[1];  *p && *p != '\n'; p++) ;    
  1596. X            *p = '\0';
  1597. X            buf[max_subj+max_from] = '\0';
  1598. X            arts[top].subject = hash_str (&buf[1]);
  1599. X        } else {
  1600. X            error = 6;
  1601. X            goto corrupt_index;
  1602. X        }
  1603. X            
  1604. X        /*
  1605. X         * From:
  1606. X         */
  1607. X        if (fgets(buf, LEN, fp) == NULL) {
  1608. X            error = 7;
  1609. X            goto corrupt_index;
  1610. X        }
  1611. X
  1612. X        if (buf[0] == '%') {
  1613. X            n = atoi (&buf[1]);
  1614. X            if (n >= top || n < 0) {
  1615. X                error = 8;
  1616. X                goto corrupt_index;
  1617. X            }
  1618. X            arts[top].from = arts[n].from;
  1619. X        } else if (buf[0] == ' ') {
  1620. X            for (p = &buf[1];  *p && *p != '\n'; p++) ;
  1621. X            *p = '\0';
  1622. X            buf[max_from] = '\0';
  1623. X            arts[top].from = hash_str (&buf[1]);
  1624. X        } else {
  1625. X            error = 9;
  1626. X            goto corrupt_index;
  1627. X        }
  1628. X
  1629. X        /*
  1630. X         * Date:
  1631. X         */
  1632. X        if (fgets(buf, LEN, fp) == NULL) {
  1633. X            error = 10;
  1634. X            goto corrupt_index;
  1635. X        }
  1636. X
  1637. X        buf[strlen (buf)-1] = '\0';
  1638. X        my_strncpy (arts[top].date, buf, 12);
  1639. X
  1640. X        /*
  1641. X         * Archive-name:
  1642. X         */
  1643. X        if (fgets(buf, LEN, fp) == NULL) {
  1644. X            error = 11;
  1645. X            goto corrupt_index;
  1646. X        }
  1647. X
  1648. X        if (buf[0] == '\n') {
  1649. X            arts[top].archive = (char *) 0;
  1650. X        } else if (buf[0] == '%') {
  1651. X            n = atoi (&buf[1]);
  1652. X            if (n > top || n < 0) {
  1653. X                error = 12;
  1654. X                goto corrupt_index;
  1655. X            }
  1656. X            arts[top].archive = arts[n].archive;
  1657. X        } else if (buf[0] == ' ') {
  1658. X            for (p = &buf[1];  *p && *p != '\n'; p++) ;
  1659. X            *p = '\0';
  1660. X            buf[MAX_ARCH] = '\0';
  1661. X            arts[top].archive = hash_str (&buf[1]);
  1662. X        } else {
  1663. X            error = 13;
  1664. X            goto corrupt_index;
  1665. X        }
  1666. X
  1667. X        /*
  1668. X         * part no.
  1669. X         */
  1670. X        if (fgets(buf, LEN, fp) == NULL) {
  1671. X            error = 14;
  1672. X            goto corrupt_index;
  1673. X        }
  1674. X
  1675. X        if (buf[0] != ' ') { 
  1676. X            buf[strlen (buf)-1] = '\0';
  1677. X            arts[top].part = str_dup (buf);
  1678. X        }
  1679. X
  1680. X        /*
  1681. X         * patch no.
  1682. X         */
  1683. X        if (fgets(buf, LEN, fp) == NULL) {
  1684. X            error = 15;
  1685. X            goto corrupt_index;
  1686. X        }
  1687. X
  1688. X        if (buf[0] != ' ') { 
  1689. X            buf[strlen (buf)-1] = '\0';
  1690. X            arts[top].patch = str_dup (buf);
  1691. X        }
  1692. X
  1693. X        debug_print_header (&arts[top]);
  1694. X    }
  1695. X
  1696. X    fclose(fp);
  1697. X    return TRUE;
  1698. X
  1699. Xcorrupt_index:
  1700. X    if (! update) {
  1701. X        sprintf (msg, txt_corrupt_index, index_file, error, top); 
  1702. X        error_message (msg, NULL);
  1703. X    }
  1704. X
  1705. X    if (debug) {
  1706. X        sprintf (msg, "cp %s INDEX.BAD", index_file);
  1707. X        system (msg);
  1708. X    }
  1709. X
  1710. X    unlink (index_file);
  1711. X    top = 0;
  1712. X    return FALSE;
  1713. X}
  1714. X
  1715. X
  1716. X/*
  1717. X *  Look in the local $HOME/RCDIR/INDEXDIR (or wherever) directory for the
  1718. X *  index file for the given group.  Hashing the group name gets
  1719. X *  a number.  See if that #.1 file exists; if so, read first line.
  1720. X *  Group we want?  If no, try #.2.  Repeat until no such file or
  1721. X *  we find an existing file that matches our group.
  1722. X */
  1723. X
  1724. Xvoid find_local_index (group)
  1725. X    char *group;
  1726. X{
  1727. X    unsigned long h;
  1728. X    static char buf[LEN+1];
  1729. X    int i;
  1730. X    char *p;
  1731. X    FILE *fp;
  1732. X
  1733. X    h = hash_groupname (group);
  1734. X
  1735. X    i = 1;
  1736. X    while (1) {
  1737. X        sprintf(index_file, "%s/%lu.%d", indexdir, h, i);
  1738. X
  1739. X        if ((fp = fopen(index_file, "r")) == NULL) {
  1740. X            return;
  1741. X        }
  1742. X
  1743. X        if (fgets(buf, LEN, fp) == NULL) {
  1744. X            fclose(fp);
  1745. X            return;
  1746. X        }
  1747. X        fclose(fp);
  1748. X
  1749. X        for (p = buf; *p && *p != '\n'; p++) ;
  1750. X        *p = '\0';
  1751. X
  1752. X        if (strcmp(buf, group) == 0)
  1753. X            return;
  1754. X
  1755. X        i++;
  1756. X    }
  1757. X}
  1758. X
  1759. X
  1760. X/*
  1761. X *  Run the index file updater only for the groups we've loaded.
  1762. X */
  1763. X
  1764. Xvoid do_update()
  1765. X{
  1766. X    int i, j;
  1767. X    char group_path[LEN+1];
  1768. X    char *p;
  1769. X
  1770. X    for (i = 0; i < local_top; i++) {
  1771. X        strcpy(group_path, active[my_group[i]].name);
  1772. X        for (p = group_path; *p; p++) {
  1773. X            if (*p == '.') {
  1774. X                *p = '/';
  1775. X            }
  1776. X        }
  1777. X        if (verbose) {
  1778. X            printf ("%s %s\n", (catchup ? "catchup" : "updating"),
  1779. X                    active[my_group[i]].name);
  1780. X            fflush (stdout);
  1781. X        }
  1782. X        index_group (active[my_group[i]].name, group_path);
  1783. X        if (catchup) {
  1784. X            for (j = 0; j < top; j++) {
  1785. X                arts[j].unread = ART_READ;
  1786. X            }
  1787. X            update_newsrc (active[my_group[i]].name, my_group[i]);
  1788. X        }
  1789. X    }
  1790. X}
  1791. X
  1792. X/*
  1793. X *  reload index after any articles have been killed
  1794. X */
  1795. Xvoid reload_index_file (group, killed)
  1796. X    char *group;
  1797. X    int killed;
  1798. X{
  1799. X    char group_path[LEN+1];
  1800. X    char *p;
  1801. X    int i, respnum;
  1802. X    long art;
  1803. X
  1804. X    if (local_index) {        /* writing index in home directory */
  1805. X        setuid (real_uid);    /* so become them */
  1806. X        setgid (real_gid);
  1807. X    }
  1808. X
  1809. X    strcpy (group_path, group);            /* turn comp.unix.amiga into */
  1810. X    for (p = group_path; *p; p++)        /* comp/unix/amiga */
  1811. X        if (*p == '.')
  1812. X            *p = '/';
  1813. X
  1814. X    if (killed) {
  1815. X        if (! update) {
  1816. X            wait_message ("Killing...");
  1817. X        }
  1818. X        index_file_killed = TRUE;
  1819. X        setup_base (group, group_path);
  1820. X        dump_index (group, killed);
  1821. X        load_index ();
  1822. X    } else {
  1823. X        if (! update) {
  1824. X            wait_message ("Unkilling...");
  1825. X        }
  1826. X        if (local_index) {
  1827. X            find_local_index (group);
  1828. X        } else {
  1829. X            sprintf (index_file, "%s/%s/%s", spooldir, group_path, INDEXDIR);
  1830. X        }
  1831. X
  1832. X        unlink (index_file);    /* delete index file */
  1833. X
  1834. X        index_file_killed = FALSE;
  1835. X        last_read_article = 0L;
  1836. X
  1837. X        if (read_group (group, group_path)) {
  1838. X            dump_index (group, killed);
  1839. X        }
  1840. X    }
  1841. X
  1842. X    make_threads (TRUE);
  1843. X    find_base ();
  1844. X
  1845. X    if (local_index) {
  1846. X        setuid (tin_uid);
  1847. X        setgid (tin_gid);
  1848. X    }
  1849. X
  1850. X    return; 
  1851. X}
  1852. X
  1853. X/*
  1854. X * convert date from "24 Jul 91 12:59:59" to "910724125959"
  1855. X */
  1856. X
  1857. Xchar *parse_date (date, str)
  1858. X    char *date;
  1859. X    char *str;
  1860. X{
  1861. X    char buf[4];
  1862. X    int i = 3;
  1863. X
  1864. X    if (date[1] == ' ') {    /* ie. "2 Aug..." instead of "12 Aug... */
  1865. X        str[4] = '0';        /* day */
  1866. X        str[5] = date[0];
  1867. X        i = 2;
  1868. X    } else {
  1869. X        str[4] = date[0];        /* day */
  1870. X        str[5] = date[1];
  1871. X    }
  1872. X    
  1873. X    buf[0] = date[i++];        /* month in Jan,Feb,.. form */
  1874. X    buf[1] = date[i++];
  1875. X    buf[2] = date[i++];
  1876. X    buf[3] = '\0';
  1877. X
  1878. X    i++;
  1879. X    
  1880. X    str[0] = date[i++];        /* year */
  1881. X    str[1] = date[i++];
  1882. X    
  1883. X    i++;
  1884. X    
  1885. X    if (strcmp (buf, "Jan") == 0) {        /* convert Jan to 01 etc */
  1886. X        str[2] = '0';
  1887. X        str[3] = '1';
  1888. X    } else if (strcmp (buf, "Feb") == 0) {
  1889. X        str[2] = '0';
  1890. X        str[3] = '2';
  1891. X    } else if (strcmp (buf, "Mar") == 0) {
  1892. X        str[2] = '0';
  1893. X        str[3] = '3';
  1894. X    } else if (strcmp (buf, "Apr") == 0) {
  1895. X        str[2] = '0';
  1896. X        str[3] = '4';
  1897. X    } else if (strcmp (buf, "May") == 0) {
  1898. X        str[2] = '0';
  1899. X        str[3] = '5';
  1900. X    } else if (strcmp (buf, "Jun") == 0) {
  1901. X        str[2] = '0';
  1902. X        str[3] = '6';
  1903. X    } else if (strcmp (buf, "Jul") == 0) {
  1904. X        str[2] = '0';
  1905. X        str[3] = '7';
  1906. X    } else if (strcmp (buf, "Aug") == 0) {
  1907. X        str[2] = '0';
  1908. X        str[3] = '8';
  1909. X    } else if (strcmp (buf, "Sep") == 0) {
  1910. X        str[2] = '0';
  1911. X        str[3] = '9';
  1912. X    } else if (strcmp (buf, "Oct") == 0) {
  1913. X        str[2] = '1';
  1914. X        str[3] = '0';
  1915. X    } else if (strcmp (buf, "Nov") == 0) {
  1916. X        str[2] = '1';
  1917. X        str[3] = '1';
  1918. X    } else if (strcmp (buf, "Dec") == 0) {
  1919. X        str[2] = '1';
  1920. X        str[3] = '2';
  1921. X    } else {
  1922. X        str[2] = '0';
  1923. X        str[3] = '0';
  1924. X    }
  1925. X    
  1926. X    str[6] = date[i++];        /* hour */
  1927. X    str[7] = date[i++];
  1928. X
  1929. X    i++;
  1930. X    
  1931. X    str[8] = date[i++];        /* minutes */
  1932. X    str[9] = date[i++];
  1933. X    
  1934. X    i++;
  1935. X    
  1936. X    str[10] = date[i++];    /* seconds */
  1937. X    str[11] = date[i++];
  1938. X
  1939. X    str[12] = '\0';        /* terminate string */
  1940. X
  1941. X    return (str);
  1942. X}
  1943. X
  1944. X
  1945. Xint artnum_comp (s1, s2)
  1946. X    struct header *s1;
  1947. X    struct header *s2;
  1948. X{
  1949. X    /* s1->artnum less than s2->artnum */
  1950. X    if (s1->artnum < s2->artnum) {
  1951. X        return -1;
  1952. X    }
  1953. X    /* s1->artnum greater than s2->artnum */
  1954. X    if (s1->artnum > s2->artnum) {
  1955. X        return 1;
  1956. X    }
  1957. X    return 0;
  1958. X}
  1959. X
  1960. X
  1961. Xint subj_comp (s1, s2)
  1962. X    struct header *s1;
  1963. X    struct header *s2;
  1964. X{
  1965. X    /* s1->subject less than s2->subject */
  1966. X    if (strcmp (s1->subject, s2->subject) < 0) {
  1967. X        return -1;
  1968. X    }
  1969. X    /* s1->subject greater than s2->subject */
  1970. X    if (strcmp (s1->subject, s2->subject) > 0) {
  1971. X        return 1;
  1972. X    }
  1973. X    return 0;
  1974. X}
  1975. X
  1976. X
  1977. Xint from_comp (s1, s2)
  1978. X    struct header *s1;
  1979. X    struct header *s2;
  1980. X{
  1981. X    /* s1->from less than s2->from */
  1982. X    if (strcmp (s1->from, s2->from) < 0) {
  1983. SHAR_EOF
  1984. echo "End of tin part 1"
  1985. echo "File art.c is continued in part 2"
  1986. echo "2" > shar3_seq_.tmp
  1987. exit 0
  1988.  
  1989. --
  1990. NAME   Iain Lea
  1991. EMAIL  norisc!iain@estevax.UUCP  ...!unido!estevax!norisc!iain
  1992. SNAIL  Siemens AG, AUT 922C, Postfach 4848, Nuernberg, Germany
  1993. PHONE  +49-911-895-3853, +49-911-895-3877, +49-911-331963
  1994.