home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume39 / slurp / part01 < prev    next >
Encoding:
Text File  |  1993-08-21  |  52.8 KB  |  2,031 lines

  1. Newsgroups: comp.sources.misc
  2. From: steveh@orbital.demon.co.uk (Stephen Hebditch)
  3. Subject: v39i037:  slurp - A passive NNTP transfer client, v1.08, Part01/03
  4. Message-ID: <csm-v39i037=slurp.203136@sparky.Sterling.COM>
  5. X-Md4-Signature: 6fe75fa2542d5203e350bbb4395214fc
  6. Sender: kent@sparky.sterling.com (Kent Landfield)
  7. Organization: Sterling Software
  8. Date: Sun, 22 Aug 1993 01:31:54 GMT
  9. Approved: kent@sparky.sterling.com
  10.  
  11. Submitted-by: steveh@orbital.demon.co.uk (Stephen Hebditch)
  12. Posting-number: Volume 39, Issue 37
  13. Archive-name: slurp/part01
  14. Environment: ANSI-C, UNIX
  15. Supersedes: slurp: Volume 36, Issue 13-14
  16.  
  17. Slurp is an advanced passive NNTP client for UNIX. It will connect to a
  18. remote NNTP server and retrieve articles in a specified set of Usenet
  19. newsgroups that have arrived after a particular date (typically the
  20. last time it was invoked) for processing by your local news system or
  21. forwarding on via UUCP to another news system. It replaces nntpxfer
  22. from the NNTP 1.5.11 reference implementation and nntpget from the INN
  23. distribution.
  24.  
  25. Slurp was written in ANSI C under Dell's SVR4/386, but ports easily to
  26. SunOs 4.x, Linux, BSDI BSD/386, HPUX, NeXT, SCO, ISC, Ultrix and most
  27. other recent versions of UNIX.
  28.  
  29. If you are running a previous version of Slurp it is *strongly*
  30. recommended that you upgrade to this new version. Full details of
  31. changes are given in the HISTORY file included in this archive.
  32. ----
  33. #! /bin/sh
  34. # This is a shell archive.  Remove anything before this line, then feed it
  35. # into a shell via "sh file" or similar.  To overwrite existing files,
  36. # type "sh file -c".
  37. # Contents:  README Makefile articles.c newnews.c slurp.c
  38. # Wrapped by kent@sparky on Sat Aug 21 20:28:14 1993
  39. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
  40. echo If this archive is complete, you will see the following message:
  41. echo '          "shar: End of archive 1 (of 3)."'
  42. if test -f 'README' -a "${1}" != "-c" ; then 
  43.   echo shar: Will not clobber existing file \"'README'\"
  44. else
  45.   echo shar: Extracting \"'README'\" \(8690 characters\)
  46.   sed "s/^X//" >'README' <<'END_OF_FILE'
  47. X                SLURP - An advanced passive NNTP client
  48. X                =======================================
  49. X
  50. X                             Version 1.08
  51. X                      Written by Stephen Hebditch
  52. X                     (C) 1992/3 TQM Communications
  53. X                                    
  54. X                                 ------
  55. X
  56. XSlurp is an advanced passive NNTP client for UNIX. It will connect to a
  57. Xremote NNTP server and retrieve articles in a specified set of Usenet
  58. Xnewsgroups that have arrived after a particular date (typically the
  59. Xlast time it was invoked) for processing by your local news system or
  60. Xforwarding on via UUCP to another news system. It replaces nntpxfer
  61. Xfrom the NNTP 1.5.11 reference implementation and nntpget from the INN
  62. Xdistribution.
  63. X
  64. X
  65. XThe Feature List.
  66. X
  67. X- No restriction on the number of newsgroups that can be retrieved in a
  68. X  session. The client does a series of NEWNEWS requests if necessary to
  69. X  build up a list of articles which need to be retrieved from the
  70. X  server.
  71. X
  72. X- Compatible with C News and INN.
  73. X
  74. X- No lost articles due to unsynchronised clocks. By default, the time
  75. X  for the next NEWNEWS is set by a call to the tcp time service on the
  76. X  remote machine. This fixes a problem in nntpxfer and nntpget where
  77. X  articles can be missed if the clock on the server is behind that on
  78. X  the client.
  79. X
  80. X- Faster article throughput. If configured to do so, slurp stacks up
  81. X  the next article request before the current article is received,
  82. X  decreasing the total article transfer time by around 30%. Unlike
  83. X  nntpget, article batches can be written to the rnews spool directory
  84. X  for processing with 'rnews -U' later, rather than being offered to
  85. X  innd in turn. When used with C News, batches are written to the
  86. X  in.coming directory. This provides a big speedup over nntpxfer which
  87. X  created a new pipe to rnews for each article, lowering the transfer
  88. X  speed and increasing the load on the client machine. These speed
  89. X  improvements are of most use to the growing number of people
  90. X  retrieving news over a dialup SLIP/PPP connection.
  91. X
  92. X- Error recovery. In the event of an error occurring while articles are
  93. X  being fetched, the message IDs of unretrieved articles are dumped to
  94. X  a file. The next session can then retrieve the remaining articles
  95. X  without having to restart from the previous start time.
  96. X
  97. X- Easy configuration.
  98. X
  99. X  slurp.sys defines which groups you wish to get from which server in a
  100. X  similar way to the normal C News sys file, e.g.
  101. X
  102. X    news.demon.co.uk:demon.*,!demon.msdos.announce,uk.*,\
  103. X    !uk.net.maps/world,uk
  104. X
  105. X  slurp.<hostname> contains the time to be used for the NEWNEWS request
  106. X  at each server.
  107. X
  108. X  The newsgroups list, start time and distributions can be overridden
  109. X  on the command line. There are also settings to enable debugging
  110. X  output, prevent writing the time for the next NEWNEWS to
  111. X  slurp.<hostname>, issue a 'MODE READER' command to switch innd to
  112. X  nnrpd, not dump unfetched message IDs in the event of an error, and
  113. X  use the local time for the next NEWNEWS rather than the time at the
  114. X  server.
  115. X
  116. X- Support for the NNTP simple authorisation protocol.
  117. X
  118. X- Logging to syslog of the number of new, missing and duplicate
  119. X  articles at the end of a session plus, if required, the transfer
  120. X  speed of the article fetching stage.
  121. X
  122. X- Independent of the NNTP 1.5.11 code.
  123. X
  124. XSlurp was written in ANSI C under Dell's SVR4/386, but ports easily to
  125. XSunOs 4.x, Linux, BSDI BSD/386, HPUX, SCO, ISC, NeXT, Ultrix and most
  126. Xother recent versions of UNIX.
  127. X
  128. X
  129. X
  130. XCONTENTS
  131. X--------
  132. X
  133. XIn this archive you should have the following files:-
  134. X
  135. XHISTORY        How we got from there to here.
  136. XMakefile    The Makefile (yes, really!)
  137. XREADME        What you're reading now
  138. Xarticles.c    Routines for reading articles and batching them up
  139. Xconf.h        Compilation configuration file
  140. Xfakesyslog.c    Fake version of syslog for those without
  141. Xfakesyslog.h    Definitions needed for the above
  142. Xhistory.c    Routines to open and interrogate the news history file
  143. Xmisc.c        Miscellaneous routines
  144. Xnewnews.c    Routines to retrieve new message ids from the server
  145. Xnntp.h        Definitions of nntp response codes
  146. Xslurp.1        Slurp manual page
  147. Xslurp.c        Main program
  148. Xslurp.h        Definitions used by everything
  149. Xslurp.sys    Configuration file for groups to take from a server
  150. Xsockets.c    Server interface routines
  151. Xspace.c        Determines space available on news disk
  152. Xtime.c        Retrieves current time at remote server
  153. X
  154. X
  155. X
  156. XCOMPILATION AND INSTALLATION
  157. X----------------------------
  158. X
  159. X1. Edit conf.h to reflect your reflect your local configuration. This
  160. Xfile contains full details about each item that you may need to change.
  161. X
  162. X2. Edit Makefile. If you have not installed dbz.h in /usr/include then
  163. Xyou will need to add -Ipathname to CFLAGS so that the compiler does a
  164. Xsearch of the directory where it can be found. LIBS will need to
  165. Xcontain entries to pick up the dbz library and possibly the sockets
  166. Xlibrary depending on your system. If you don't have syslog then you
  167. Xwill need to uncomment the FAKESRC and FAKEOBJ lines.
  168. X
  169. X3. Type 'make' and hopefully you will get the slurp executable.
  170. X
  171. X4. Copy slurp to wherever it is that you store your news binaries.
  172. X
  173. X5. Copy slurp.sys to whichever location you selected for it in conf.h.
  174. X
  175. X6. Copy the manual page to wherever you keep your manual pages.
  176. X
  177. X
  178. X
  179. XQUICK START
  180. X-----------
  181. X
  182. XThe slurp manual page contains full details on how to operate slurp. As
  183. Xa quick start all you need to do is:-
  184. X
  185. X1. Edit slurp.sys to set the hostname of the server you wish to connect
  186. Xto for retrieving articles and the groups you wish to receive.
  187. X
  188. X2. Edit slurp.<hostname> and enter a single line containing the time a
  189. Xcouple of days previously, say, in 'YYMMDD HHMMSS' format.
  190. X
  191. X3. Run 'slurp <hostname>' and sit back while the articles flood into
  192. Xyour local news system.
  193. X
  194. XIf you are running C News, then the next time that newsrun is invoked
  195. Xfrom cron, the articles in the in.coming directory will be added to the
  196. Xnews system.
  197. X
  198. XIf you are running INN and do not have RNEWS defined, then it will be
  199. Xnecessary to run 'rnews -U' to have the files from the rnews spool
  200. Xdirectory processed by the news system. If RNEWS is defined then they
  201. Xwill be piped to innd as they arrive - doing this will lower the speed
  202. Xat which articles are transferred from the remote server.
  203. X
  204. XPatches for the NNTP 1.5.11 server are available on request which
  205. Ximplement caching of article locations during a NEWNEWS so that a
  206. Xfurther access of the history file is not required when an article is
  207. Xretrieved. I hope to have an equivalent patch available for INN soon.
  208. X
  209. X
  210. X
  211. XCONDITIONS OF USE
  212. X-----------------
  213. X
  214. XThe Slurp package and individual code as detailed is Copyright 1992/3
  215. XTQM Communications, BCM Box 225, London, WC1N 3XX. All rights reserved.
  216. X
  217. XThis package may be freely distributed provided the following
  218. Xconditions are met. The files detailed in the contents section of this
  219. Xfile must all be included. No charge, other than basic online charges
  220. Xor media costs, may be levied. You are permitted to make alterations to
  221. Xthe code for your own personal use, but please feed back any bug fixes
  222. Xor enhancements to us so they may be included in any future releases.
  223. X
  224. X
  225. X
  226. XDISCLAIMER
  227. X----------
  228. X
  229. XTQM Communications makes no warranty of any kind in respect to this
  230. Xdocumentation and the software described. The user assumes any risk as
  231. Xto the quality and performance of this product. In no event will TQM
  232. XCommunications be liable for direct, indirect, incidental or
  233. Xconsequential damages arising from any defect in the performance and
  234. Xuse of this product.
  235. X
  236. XAll trademarks acknowledged.
  237. X
  238. X
  239. X
  240. XACKNOWLEDGEMENTS
  241. X----------------
  242. X
  243. XThe original inspiration for slurp came from nntpxfer, written by Brian
  244. XKantor. The article batching code is inspired by batch.c in the NNTP
  245. X1.5.11 package, written by Stan Barber and 'based on work by Henry
  246. XSpencer and Geoff Collyer'. The fakesyslog code is taken from the NNTP
  247. X1.5.11 package where it is credited to John Robert LoVerso and Paul
  248. XMcKenny. The space code to determine whether there is enough space on
  249. Xthe news disk was originally taken from the NNTP 1.5.11 package where
  250. Xit is credited to Stan Barber, Tad Guy, Chris Jepeway and Tom Lane.
  251. XRegular expression expansion courtesy of Nick Lai. Network knowledge
  252. Xthanks to W. Richard Stevens, author of the most readable UNIX books
  253. Xaround. For bug fixing, porting and enhancement ideas, thanks go to Tim
  254. XRylance, Pete Bentley, Stefan Schwarz, David Clunie, David Boyce,
  255. XBarrie Spence and Philip Shearer.
  256. X
  257. X
  258. X
  259. XCONTACT INFORMATION
  260. X-------------------
  261. X
  262. XAll comments, bug reports, bug fixes, etc. should be sent to
  263. Xsteveh@orbital.demon.co.uk. I'm also available for consultancy work if
  264. Xyou want help in getting news and mail working.
  265. X
  266. X
  267. X---- END OF DOCUMENTATION
  268. END_OF_FILE
  269.   if test 8690 -ne `wc -c <'README'`; then
  270.     echo shar: \"'README'\" unpacked with wrong size!
  271.   fi
  272.   # end of 'README'
  273. fi
  274. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  275.   echo shar: Will not clobber existing file \"'Makefile'\"
  276. else
  277.   echo shar: Extracting \"'Makefile'\" \(1398 characters\)
  278.   sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  279. X#
  280. X# Makefile for slurp
  281. X#
  282. X
  283. X# C compiler
  284. XCC=cc
  285. X
  286. X# C compilation flags
  287. XCFLAGS= -O -Xa -I/usr/local/src/cnews/dbz
  288. X
  289. X# Loader flags
  290. XLDFLAGS=
  291. X
  292. X# Libraries needed
  293. XLIBS= /usr/local/src/cnews/dbz/dbz.o -lnsl -lsocket
  294. X
  295. X# If you don't have syslog then uncomment these two lines
  296. X#FAKESRC=fakesyslog.c
  297. X#FAKEOBJ=fakesyslog.o
  298. X
  299. X
  300. X# Everything else probably doesn't need changing
  301. X
  302. XSOURCE = slurp.c newnews.c articles.c history.c time.c sockets.c misc.c \
  303. X     space.c ${FAKESRC}
  304. X
  305. XOBJECT = slurp.o newnews.o articles.o history.o time.o sockets.o misc.o \
  306. X     space.o ${FAKEOBJ}
  307. X
  308. XMANIFEST = README slurp.c newnews.c articles.c history.c time.c sockets.c \
  309. X       misc.c space.c fakesyslog.c conf.h slurp.h nntp.h fakesyslog.h \
  310. X       Makefile slurp.sys slurp.1 HISTORY
  311. X
  312. X
  313. Xslurp: ${OBJECT}
  314. X    ${CC} ${LDFLAGS} ${OBJECT} -o slurp ${LIBS}
  315. X
  316. Xslurp.o: slurp.c slurp.h conf.h nntp.h
  317. Xnewnews.o: newnews.c slurp.h conf.h nntp.h
  318. Xarticles.o: articles.c slurp.h conf.h nntp.h
  319. Xhistory.o: history.c slurp.h conf.h nntp.h
  320. Xtime.o: time.c slurp.h conf.h
  321. Xsockets.o: sockets.c slurp.h conf.h nntp.h
  322. Xmisc.o: misc.c slurp.h conf.h
  323. Xspace.o: space.c slurp.h conf.h
  324. Xfakesyslog.o: fakesyslog.c slurp.h conf.h
  325. X
  326. Xlint:
  327. X    lint -p ${CFLAGS} ${SOURCE} > slurp.lint
  328. X
  329. Xclean:
  330. X    -rm -f *.o slurp
  331. X
  332. Xshar:
  333. X    shar -v -s -l60 -oslurp.shar ${MANIFEST}
  334. X
  335. Xtaz:
  336. X    tar -cf - ${MANIFEST} | compress > slurp.tar.Z
  337. X
  338. Xdiff:
  339. X    rcsdiff -q -r1.7 -C 1 ${MANIFEST} > slurp.diff
  340. X
  341. X# END-OF-FILE
  342. END_OF_FILE
  343.   if test 1398 -ne `wc -c <'Makefile'`; then
  344.     echo shar: \"'Makefile'\" unpacked with wrong size!
  345.   fi
  346.   # end of 'Makefile'
  347. fi
  348. if test -f 'articles.c' -a "${1}" != "-c" ; then 
  349.   echo shar: Will not clobber existing file \"'articles.c'\"
  350. else
  351.   echo shar: Extracting \"'articles.c'\" \(9558 characters\)
  352.   sed "s/^X//" >'articles.c' <<'END_OF_FILE'
  353. X/*
  354. X * articles - handle retrieval and batching of articles
  355. X *
  356. X * Copyright (C) 1992/93 Stephen Hebditch. All rights reserved.
  357. X * TQM Communications, BCM Box 225, London, WC1N 3XX.
  358. X * steveh@orbital.demon.co.uk  +44 836 825962
  359. X *
  360. X * See README for more information and disclaimers
  361. X *
  362. X * This file provides a set of routines to retrieve articles from the
  363. X * remote NNTP server and add to a batch of articles being piped to
  364. X * the local news system via rnews.
  365. X *
  366. X * $Id: articles.c,v 1.7 1993/06/14 15:20:52 root Exp $
  367. X *
  368. X * $Log: articles.c,v $
  369. X * Revision 1.7  1993/06/14  15:20:52  root
  370. X * Removed some unnecessary initialisation.
  371. X *
  372. X * Revision 1.6  1993/04/22  18:24:21  root
  373. X * Treat ERR_ACCESS result code when retrieving an article the same
  374. X * as if the article was missing.
  375. X *
  376. X * Revision 1.5  1993/03/01  17:36:51  root
  377. X * Removed stray text after an endif.
  378. X *
  379. X * Revision 1.4  1993/02/14  14:44:25  root
  380. X * Fixed problem with newline being added to article line buffer which
  381. X * could already be at its maximum length.
  382. X * Support for writing out batch files as well as piping batches to
  383. X * rnews.
  384. X * If BATCHSIZE is zero then keep pipe open to rnews indefinitely.
  385. X * If error occurs then submit batch and dump unretrieved ids.
  386. X *
  387. X * Revision 1.3  1992/12/15
  388. X * Minor tidy-ups, plus fixed flushing of tfp every time after it had
  389. X * been opened once.
  390. X *
  391. X * Revision 1.1  1992/12/04
  392. X * Print line before it is sent to server when debugging is on.
  393. X *
  394. X * Revision 1.0  1992/11/27
  395. X * Adapted from nntpxfer-e code.
  396. X * Pipe batches to rnews instead of creating in in.coming directory,
  397. X * so can be used with INN.
  398. X *
  399. X */
  400. X
  401. X#include "slurp.h"
  402. X
  403. X
  404. Xstatic struct mnode *last_article = NULL; /* last article requested */
  405. Xstatic char artbuf [COPYSIZE];        /* temp storage for article in memory */
  406. Xstatic char *endart = artbuf;        /* points to just past end of article */
  407. Xstatic int incore = TRUE;            /* article in memory, not temp file */
  408. Xstatic FILE *tfp;                    /* temporary file descriptor */
  409. X
  410. Xstatic FILE *batchfp = NULL;        /* file descriptor for batch */
  411. Xstatic size_t batchsize = 0;        /* size of current batch */
  412. Xstatic char batchname [PATH_MAX];    /* name of current batch */
  413. X
  414. Xstatic void new_batch ();
  415. Xstatic void read_article ();
  416. Xstatic void batch_article ();
  417. Xstatic void fetch_article ();
  418. Xstatic void get_article ();
  419. Xstatic void request_article (char *msgid);
  420. Xstatic void traverse_tree ();
  421. X
  422. X
  423. X/*
  424. X * new_batch - Determines if there is enough room for the batch on the
  425. X * disk containing the news spool directories. If there is, then a pipe
  426. X * is opened to rnews and the batch variable initialised with the
  427. X * details.
  428. X */
  429. X
  430. X    static void
  431. Xnew_batch ()
  432. X    {
  433. X    /* Make sure there is enough room for batch */
  434. X#ifdef MINFREE
  435. X    if (!space (MINFREE))
  436. X        {
  437. X        log_msg ("new_batch: Not enough space for incoming batch");
  438. X        if ((root != NULL) && (!no_time_flag) && (!no_id_load_flag))
  439. X            set_ntime ();
  440. X        exit (5);
  441. X        }
  442. X#endif
  443. X
  444. X#ifdef RNEWS
  445. X    /* Open a pipe to rnews for the batch */
  446. X    if ((batchfp = popen (RNEWS, "w")) == NULL)
  447. X        log_sys ("new_batch: Can't open pipe to %s", RNEWS);
  448. X#else
  449. X    /* Open a file in incoming news directory with temporary name */
  450. X    (void) strcpy (batchname, BATCHNAME);
  451. X    (void) mktemp (batchname);
  452. X    if ((batchfp = fopen (batchname, "w")) == NULL)
  453. X        log_sys ("new_batch: Can't open file %s", batchname);
  454. X#endif
  455. X    }
  456. X
  457. X
  458. X/*
  459. X * read_article - Read an article into artbuf or, if too large, into a
  460. X * temporary file from the currently open NNTP server socket, reading up
  461. X * to the end-of-article marker, a '.' on a single line. If it is stored
  462. X * in memory, then incore will be TRUE, otherwise it will be FALSE and the
  463. X * temporary file name will be stored in tempfile.
  464. X */
  465. X
  466. X    static void
  467. Xread_article ()
  468. X    {
  469. X    char *realline;
  470. X    char line [NNTP_STRLEN];
  471. X    int lines = 0;
  472. X    int len;
  473. X
  474. X    incore = TRUE;
  475. X    endart = artbuf;
  476. X
  477. X    /* Read in the article */
  478. X    for (;;)
  479. X        {
  480. X        get_server (line, sizeof (line));
  481. X
  482. X        /* Dot on its own means article end reached */
  483. X        if (!strcmp (line, "."))
  484. X            break;
  485. X
  486. X        /* remove hidden dot if present */
  487. X        realline = (line [0] == '.' ? line + 1 : line);
  488. X
  489. X        /* Article is currently stored in memory */
  490. X        if (incore)
  491. X            {
  492. X            /* If no room in artbuf, open tempfile and copy article there */
  493. X            len = strlen (realline);
  494. X            if ((endart + len + 2 ) > (artbuf + sizeof (artbuf)))
  495. X                {
  496. X                if ((tfp = tmpfile ()) == NULL)
  497. X                    log_sys ("read_article: Can't create temporary file");
  498. X                (void) fwrite (artbuf, 1, endart - artbuf, tfp);
  499. X                if (ferror (tfp))
  500. X                    log_sys ("read_article: Can't write to tempfile");
  501. X                (void) fputs (realline, tfp);
  502. X                (void) putc ('\n', tfp);
  503. X                if (ferror (tfp))
  504. X                    log_sys ("read_article: Can't write to tempfile");
  505. X                incore = FALSE;
  506. X                }
  507. X            else
  508. X                {
  509. X                /* If fits, append realline to artbuf at endart */
  510. X                (void) strcpy (endart, realline);
  511. X                endart += len;
  512. X                *endart++ = '\n';
  513. X                *endart = '\0';
  514. X                }
  515. X            }
  516. X
  517. X        /* Already writing article to temp file */
  518. X        else
  519. X            {
  520. X            (void) fputs (realline, tfp);
  521. X            (void) putc ('\n', tfp);
  522. X            if (ferror (tfp))
  523. X                log_sys ("read_article: Can't write to tempfile");
  524. X            }
  525. X
  526. X        lines++;
  527. X        }
  528. X
  529. X    /* Article successfully read in */
  530. X    if (debug_flag)
  531. X        (void) fprintf (stderr, "-> %d lines\n", lines);
  532. X    }
  533. X
  534. X
  535. X/* batch_article - Append "#! rnews <count>" and the article from artbuf
  536. X * or temporary file to the batch file.
  537. X */
  538. X
  539. X    static void
  540. Xbatch_article ()
  541. X    {
  542. X    size_t bytes;
  543. X    size_t size;
  544. X
  545. X    /* Find article size */
  546. X    if (incore)
  547. X        size = endart - artbuf;
  548. X    else
  549. X        size = ftell (tfp);
  550. X
  551. X    totalsize += size;
  552. X    batchsize += size;
  553. X
  554. X    /* Print the article header */
  555. X    (void) fprintf (batchfp, "#! rnews %ld %s\n", (long) size, hostname);
  556. X
  557. X    /* Copy the article to the batch file */
  558. X    if (incore)
  559. X        {
  560. X        (void) fwrite (artbuf, 1, size, batchfp);
  561. X        if (ferror (batchfp))
  562. X            log_sys ("batch_article: Can't write to batch");
  563. X        }
  564. X    else
  565. X        {
  566. X        rewind (tfp);
  567. X        while ((bytes = fread (artbuf, 1, sizeof (artbuf), tfp)) > 0)
  568. X            {
  569. X            (void) fwrite (artbuf, 1, bytes, batchfp);
  570. X            if (ferror (batchfp))
  571. X                log_sys ("batch_article: Can't write to batch");
  572. X            }
  573. X        (void) fclose (tfp);
  574. X
  575. X        }
  576. X    }
  577. X
  578. X
  579. X/*
  580. X * fetch_article - Retrieve an article from the currently open NNTP
  581. X * server socket which has already been requested. The article is written
  582. X * to the end of the current batch. If there is not already a batch
  583. X * then a new pipe to rnews for the batch will be opened. If the current
  584. X * batch is too large or has too many articles then the pipe will be
  585. X * closed so that the batch may be submitted to the news system.
  586. X */
  587. X
  588. X    static void
  589. Xfetch_article ()
  590. X    {
  591. X    /* Open a new batch if required */
  592. X    if (batchfp == NULL)
  593. X        new_batch ();
  594. X
  595. X    /* Read in article */
  596. X    read_article ();
  597. X
  598. X    /* Add it to the batch */
  599. X    batch_article ();
  600. X
  601. X    /* Submit batch if ready */
  602. X    if ((batchsize > BATCHSIZEMAX) && (BATCHSIZEMAX != 0))
  603. X        enqueue_batch ();
  604. X    }
  605. X
  606. X
  607. X/*
  608. X * get_article
  609. X */
  610. X
  611. X    static void
  612. Xget_article ()
  613. X    {
  614. X    char status [NNTP_STRLEN];
  615. X
  616. X    /* Read status line from server */
  617. X    get_server (status, sizeof (status));
  618. X    if (debug_flag)
  619. X        (void) fprintf (stderr, "-> %s\n", status);
  620. X
  621. X    switch (atoi (status))
  622. X        {
  623. X        /* If missing, then add to missing list */
  624. X        case ERR_NOART:
  625. X        case ERR_ACCESS:
  626. X            misart++;
  627. X            newart--;
  628. X            return;
  629. X
  630. X        /* If present, then fetch and add to batch */
  631. X        case OK_ARTICLE:
  632. X            fetch_article ();
  633. X            break;
  634. X
  635. X        /* Otherwise must be a protocol error */
  636. X        default:
  637. X            log_msg ("get_article: NNTP protocol error: got '%s'", status);
  638. X            if ((root != NULL) && (!no_time_flag) && (!no_id_load_flag))
  639. X                set_ntime ();
  640. X            exit (4);
  641. X        }
  642. X    }
  643. X
  644. X
  645. X/*
  646. X * request_article - Request an article with specified id from the server
  647. X */
  648. X
  649. X    static void
  650. Xrequest_article (char *msgid)
  651. X    {
  652. X    char request [NNTP_STRLEN];
  653. X
  654. X    (void) sprintf (request, "ARTICLE %s", msgid);
  655. X    if (debug_flag)
  656. X        (void) fprintf (stderr, "<- %s\n", request);
  657. X    put_server (request);
  658. X    }
  659. X
  660. X
  661. X/*
  662. X * traverse_tree - Traverse the tree requesting and getting each article
  663. X */
  664. X
  665. X    static void
  666. Xtraverse_tree (struct mnode *p)
  667. X    {
  668. X    if (p != NULL)    
  669. X        {
  670. X        traverse_tree (p->left);
  671. X        request_article (p->msgid);
  672. X#ifdef SPEEDUP
  673. X        if (last_article != NULL)
  674. X            {
  675. X            get_article ();
  676. X            last_article->used = TRUE;
  677. X            }
  678. X        last_article = p;
  679. X#else
  680. X        get_article ();
  681. X        p->used = TRUE;
  682. X#endif /* SPEEDUP */
  683. X        traverse_tree (p->right);
  684. X        }
  685. X    }
  686. X
  687. X
  688. X/*
  689. X * get_articles - Get the articles from the server whose message ids
  690. X * were previously collected with do_newnews.
  691. X */
  692. X
  693. X    void
  694. Xget_articles ()
  695. X    {
  696. X    traverse_tree (root);
  697. X#ifdef SPEEDUP
  698. X    get_article ();
  699. X    last_article->used = TRUE;
  700. X#endif
  701. X    }
  702. X
  703. X
  704. X/*
  705. X * enqueue_batch - Submit the batch to the new system by closing the
  706. X * currently open pipe to rnews or renaming the temporary file in the
  707. X * incoming news directory so it can be seen by the news system.
  708. X */
  709. X
  710. X    void
  711. Xenqueue_batch ()
  712. X    {
  713. X#ifndef RNEWS
  714. X    char permname [PATH_MAX];
  715. X    time_t now;
  716. X#endif
  717. X
  718. X    /* Return if there is no currently open batch */
  719. X    if (batchfp == NULL)
  720. X        return;
  721. X
  722. X#ifdef RNEWS
  723. X    /* Close the pipe to rnews */
  724. X    if (pclose (batchfp))
  725. X        log_sys ("enqueue_batch: Can't close pipe to %s", RNEWS);
  726. X#else
  727. X    /* Close the temporary file */
  728. X    if (fclose (batchfp))
  729. X        log_sys ("enqueue_batch: Can't close %s", batchname);
  730. X
  731. X    /* Rename it so it can be seen by news */
  732. X    for (;;)
  733. X        {
  734. X        (void) sprintf (permname, "%ld.t", (long) time (&now));
  735. X        if (link (batchname, permname) == 0)
  736. X            break;
  737. X        if (errno != EEXIST)
  738. X            log_sys ("enqueue_batch: Error linking %s to %s", batchname, permname);
  739. X        (void) sleep (2);
  740. X        }
  741. X    if (unlink (batchname))
  742. X            log_sys ("enqueue_batch: Error unlinking %s", batchname);
  743. X#endif /* RNEWS */
  744. X
  745. X    /* Reset the batch descriptor for a new batch */
  746. X    batchfp = NULL;
  747. X    batchsize = 0;
  748. X    }
  749. X
  750. X/* END-OF-FILE */
  751. END_OF_FILE
  752.   if test 9558 -ne `wc -c <'articles.c'`; then
  753.     echo shar: \"'articles.c'\" unpacked with wrong size!
  754.   fi
  755.   # end of 'articles.c'
  756. fi
  757. if test -f 'newnews.c' -a "${1}" != "-c" ; then 
  758.   echo shar: Will not clobber existing file \"'newnews.c'\"
  759. else
  760.   echo shar: Extracting \"'newnews.c'\" \(9772 characters\)
  761.   sed "s/^X//" >'newnews.c' <<'END_OF_FILE'
  762. X/*
  763. X * newnews - Read in list of ids of new articles
  764. X *
  765. X * Copyright (C) 1992/93 Stephen Hebditch. All rights reserved.
  766. X * TQM Communications, BCM Box 225, London, WC1N 3XX.
  767. X * steveh@orbital.demon.co.uk  +44 836 825962
  768. X *
  769. X * See README for more information and disclaimers
  770. X *
  771. X * Using a previously initialised list of newsgroups, carries out a series
  772. X * of NEWNEWS requests to the connected NNTP server, storing the message
  773. X * ids of new articles in a binary tree in memory.
  774. X *
  775. X * $Id: newnews.c,v 1.7 1993/06/14 15:22:24 root Exp $
  776. X *
  777. X * $Log: newnews.c,v $
  778. X * Revision 1.7  1993/06/14  15:22:24  root
  779. X * Modified parse_groups to only malloc enough space for arrays.
  780. X * Rewrote get_ids, incorporating the get_not_groups function. This
  781. X * makes the algorithm neater, fixes a problem with using memset on a
  782. X * zero length block, and fixes a problem whereby with certain
  783. X * newsgroup combinations a line could overflow its buffer.
  784. X * In process_id when in debug mode print after a message ID if ID
  785. X * discarded due to hitting maximum number of articles or was already
  786. X * present in the tree.
  787. X *
  788. X * Revision 1.5  1993/03/01  17:45:16  root
  789. X * Added cast to bzeroing of used_not_group_array.
  790. X *
  791. X * Revision 1.4  1993/02/14  14:55:41  root
  792. X * Malloc msgid space separately from mnode.
  793. X * Split-out process_id from do_newnews so it can be used in get_ntime
  794. X * to load the tree with the unretrieved message ids.
  795. X *
  796. X * Revision 1.3  1992/12/14
  797. X * Only malloc enough space for msgid, not whole mnode structure.
  798. X * Minor tidy-ups.
  799. X *
  800. X * Revision 1.1  1992/12/06
  801. X * Set no_time_flag if hit max no of messages
  802. X * Print line before it is sent to server when debugging is on.
  803. X * No longer need to handle null nn_distributions.
  804. X *
  805. X * Revision 1.0  1992/11/30
  806. X * Transferred functions from slurp.c
  807. X *
  808. X */
  809. X
  810. X#include "slurp.h"
  811. X
  812. Xstatic int hit_max = FALSE;
  813. X
  814. Xstatic char **group_array;
  815. Xstatic char **not_group_array;
  816. Xstatic int  *used_not_group_array;
  817. X
  818. Xstatic int  groups_no = 1;
  819. Xstatic int  not_groups_no = 0;
  820. X
  821. X
  822. Xstatic void parse_groups ();
  823. Xstatic int  add_id (char *msgid);
  824. Xstatic void do_newnews (char *line);
  825. Xstatic int  restreql (register char *w, register char *s);
  826. X
  827. X
  828. X/*
  829. X * parse_groups - Turn list of groups into two arrays containing 
  830. X * pointers to groups to include and groups to exclude.
  831. X */
  832. X
  833. X    static void
  834. Xparse_groups ()
  835. X    {
  836. X    int g = 0;
  837. X    int n = 0;
  838. X    int got = TRUE;
  839. X    int not = FALSE;
  840. X    char *cp;
  841. X
  842. X    /* Calculate number of group entries */
  843. X    for (cp = nn_newsgroups; *cp != '\0'; cp++)
  844. X        {
  845. X        if (*cp == ',')
  846. X            groups_no++;
  847. X        if (*cp == '!')
  848. X            {
  849. X             not_groups_no++;
  850. X             groups_no--;
  851. X             }
  852. X         }
  853. X
  854. X    /* Malloc space for include and exclude group arrays */
  855. X    if ((group_array = (char **) malloc ((size_t) groups_no * sizeof (char *))) == NULL)
  856. X        log_sys ("parse_groups: malloc %d bytes", groups_no * sizeof (char **));
  857. X
  858. X    if (not_groups_no > 0)
  859. X        {
  860. X        if ((not_group_array = (char **) malloc ((size_t) not_groups_no * sizeof (char *))) == NULL)
  861. X            log_sys ("parse_groups: malloc %d bytes", not_groups_no * sizeof (char **));
  862. X
  863. X        if ((used_not_group_array = (int *) malloc ((size_t) not_groups_no * sizeof (int))) == NULL)
  864. X            log_sys ("parse_groups: malloc %d bytes", not_groups_no * sizeof (int));
  865. X        }
  866. X
  867. X    /* Now start parsing the newsgroup list */
  868. X    for (cp = nn_newsgroups; *cp != '\0'; cp++)
  869. X        {
  870. X        if (*cp == '!')
  871. X            got = FALSE;
  872. X
  873. X        if (got)
  874. X            {
  875. X            group_array [g++] = cp;
  876. X            got = FALSE;
  877. X            }
  878. X
  879. X        if (not)
  880. X            {
  881. X            not_group_array [n++] = cp;
  882. X            not = FALSE;
  883. X            }
  884. X
  885. X        if (*cp == ',')
  886. X            {
  887. X            *cp = '\0';
  888. X            got = TRUE;
  889. X            }
  890. X
  891. X        if (*cp == '!')
  892. X            not = TRUE;
  893. X        }
  894. X    }
  895. X
  896. X
  897. X/*
  898. X * store_node - Store a new node in the binary tree
  899. X */
  900. X
  901. X    static struct mnode *
  902. Xstore_node (char *msgid)
  903. X    {
  904. X    struct mnode *node;
  905. X
  906. X    if ((node = (struct mnode *) malloc (sizeof (struct mnode))) == NULL)
  907. X        log_sys ("add_id: malloc %d bytes", sizeof (struct mnode));
  908. X    node->left = NULL;
  909. X    node->right = NULL;
  910. X    node->used = FALSE;
  911. X    if ((node->msgid = (char *) malloc (strlen (msgid) + sizeof (char))) == NULL)
  912. X        log_sys ("store_node: malloc %d bytes", strlen (msgid) + sizeof (char));
  913. X    (void) strcpy (node->msgid, msgid);
  914. X    entries++;
  915. X    return (node);
  916. X    }
  917. X
  918. X
  919. X/*
  920. X * add_id - Add a message id to the binary tree if not already present.
  921. X * Returns -1 if the maximum number of entries in the tree has been
  922. X * reached, 0 if the item is added okay, 1 if an entry with that 
  923. X * particular message id already exists.
  924. X */
  925. X
  926. X    static int
  927. Xadd_id (char *msgid)
  928. X    {
  929. X    struct mnode *current;
  930. X    int test;
  931. X
  932. X    /* Test if hit the maximum number of entries in the cache */
  933. X    if (entries >= MAXCACHE)
  934. X        return (-1);
  935. X
  936. X    /* Handle the case when the tree is empty */
  937. X    if (root == NULL)
  938. X        {
  939. X        root = store_node (msgid);
  940. X        return (0);
  941. X        }
  942. X
  943. X    /* Search the tree for correct position to insert node */
  944. X    current = root;
  945. X    
  946. X    for (;;)
  947. X        {
  948. X        test = strcmp (msgid, current->msgid);
  949. X        if (test < 0)
  950. X            {
  951. X            if (current->left == NULL)
  952. X                {
  953. X                current->left = store_node (msgid);
  954. X                return (0);
  955. X                }
  956. X            else
  957. X                current = current->left;
  958. X            }
  959. X        else if (test > 0)
  960. X            {
  961. X            if (current->right == NULL)
  962. X                {
  963. X                current->right = store_node (msgid);
  964. X                return (0);
  965. X                }
  966. X            else
  967. X                current = current->right;
  968. X            }
  969. X        else
  970. X            return (1);
  971. X        }
  972. X    }
  973. X
  974. X
  975. X/*
  976. X * process_id - Check if id already exists in local history file, if not
  977. X * then add it to the message id tree if it isn't already in there.
  978. X */
  979. X
  980. X    void
  981. Xprocess_id (char *msgid)
  982. X    {
  983. X    char *cp;
  984. X
  985. X    /* Modify the message id appropriate to C-News history files */
  986. X    if ((cp = strchr (msgid, '@')) != NULL)
  987. X        {
  988. X        for (; *cp != '\0'; cp++)
  989. X            if (isupper (*cp))
  990. X                *cp = tolower (*cp);
  991. X        }
  992. X
  993. X    if (debug_flag)
  994. X        (void) fprintf (stderr, "-> %s", msgid);
  995. X
  996. X    if (check_id (msgid))
  997. X        {
  998. X        switch (add_id (msgid))
  999. X            {
  1000. X            case -1 :
  1001. X                hit_max = TRUE;
  1002. X                if (debug_flag)
  1003. X                    (void) fprintf (stderr, " discarded\n");
  1004. X                break;
  1005. X            case  0 :
  1006. X                newart++;
  1007. X                if (debug_flag)
  1008. X                    (void) fprintf (stderr, " new\n");
  1009. X                break;
  1010. X            default :
  1011. X                if (debug_flag)
  1012. X                    (void) fprintf (stderr, " present\n");
  1013. X                break;
  1014. X            }
  1015. X        }
  1016. X    else
  1017. X        {
  1018. X        dupart++;
  1019. X        if (debug_flag)
  1020. X            (void) fprintf (stderr, " duplicate\n");
  1021. X        }
  1022. X    }
  1023. X
  1024. X
  1025. X/*
  1026. X * do_newnews - Process a newnews for supplied list of groups, adding the
  1027. X * resultant data to the message id tree.
  1028. X */
  1029. X
  1030. X    static void
  1031. Xdo_newnews (char *line)
  1032. X    {
  1033. X    char buf [NNTP_STRLEN];
  1034. X
  1035. X    /* Create a full string to send to the server */
  1036. X    (void) sprintf (buf, "NEWNEWS %s %s GMT %s", line, nn_time,
  1037. X                    nn_distributions);
  1038. X
  1039. X    /* Do the actual NEWNEWS */
  1040. X    if (debug_flag)
  1041. X        (void) fprintf (stderr, "<- %s\n", buf);
  1042. X    put_server (buf);
  1043. X    
  1044. X    /* Get the response and check it's okay */
  1045. X    get_server (buf, sizeof (buf));
  1046. X    if (debug_flag)
  1047. X        (void) fprintf (stderr, "-> %s\n", buf);
  1048. X    if (atoi (buf) != OK_NEWNEWS)
  1049. X        {
  1050. X        log_msg ("do_newnews: NNTP protocol error: got '%s'", buf);
  1051. X        exit (4);
  1052. X        }
  1053. X                    
  1054. X    /* Now get the data and stick it in the tree */
  1055. X    for (;;)
  1056. X        {
  1057. X        get_server (buf, sizeof (buf));
  1058. X        if (!strcmp (buf, "."))
  1059. X            break;
  1060. X
  1061. X        process_id (buf);
  1062. X        }
  1063. X    }
  1064. X
  1065. X
  1066. X/*
  1067. X * restreql -- A small regular expression string equivalence routine
  1068. X * purloined from nntp 1.5.11 which credits <lai@shadow.berkeley.edu>
  1069. X * for its creation. Returns 1 if the string pointed to by 's' matches
  1070. X * the asterisk-broadened regexp string pointed to by 'w', otherwise
  1071. X * returns 0.
  1072. X */
  1073. X
  1074. X    static int
  1075. Xrestreql (register char *w, register char *s)
  1076. X    {
  1077. X    while (*s && *w)
  1078. X        {
  1079. X        switch (*w)
  1080. X            {
  1081. X            case '*':
  1082. X                for (w++; *s; s++)
  1083. X                    if (restreql(w, s))
  1084. X                        return (1);
  1085. X                break;
  1086. X            default:
  1087. X                if (*w != *s)
  1088. X                    return (0);
  1089. X                w++, s++;
  1090. X                break;
  1091. X            }
  1092. X        }
  1093. X    if (*s)
  1094. X        return (0);
  1095. X    while (*w)
  1096. X        if (*w++ != '*')
  1097. X            return 0;
  1098. X
  1099. X    return (1);
  1100. X    }
  1101. X
  1102. X
  1103. X/*
  1104. X * get_ids - Store in memory a tree of the message ids of new article at
  1105. X * the server which match the specified set of groups and distributions
  1106. X * for the currently connected host.
  1107. X */
  1108. X
  1109. X    void
  1110. Xget_ids ()
  1111. X    {
  1112. X    char line [NNTP_STRLEN];
  1113. X    char newgroups [NNTP_STRLEN];
  1114. X    int i, j, add_comma;
  1115. X    size_t newlen, linelen;
  1116. X    size_t startlen = 30 + strlen (nn_distributions);
  1117. X
  1118. X    /* Turn comma-separated list of groups into 2 arrays */
  1119. X    parse_groups ();
  1120. X
  1121. X    /* Initialiase for first list of groups to send to server */
  1122. X    *line = '\0';
  1123. X    linelen = startlen;
  1124. X    if (not_groups_no)
  1125. X        (void) memset (used_not_group_array, 0, not_groups_no * sizeof (int));
  1126. X    add_comma = FALSE;
  1127. X
  1128. X    for (i = 0 ; i < groups_no ; i++)
  1129. X        {
  1130. X        /* Check group isn't so big it doesn't fit at all */
  1131. X        newlen = strlen (group_array [i]);
  1132. X        if ((newlen + startlen) > NNTP_STRLEN)
  1133. X            {
  1134. X            log_msg ("get_ids: Not enough room in NNTP line for newsgroup %s",
  1135. X                     group_array [i]);
  1136. X            exit (2);
  1137. X            }
  1138. X
  1139. X        /* Get list containing new group and matching ! groups */
  1140. X        (void) strcpy (newgroups, group_array [i]);
  1141. X        for (j = 0 ; j < not_groups_no ; j++)
  1142. X            if (!used_not_group_array [j])
  1143. X                if (restreql (group_array [i], not_group_array [j]))
  1144. X                    {
  1145. X                    newlen += strlen (not_group_array [j]) + 2;
  1146. X                    if ((newlen + startlen) > NNTP_STRLEN)
  1147. X                        {
  1148. X                        log_msg ("get_ids: Not enough room in NNTP line for exclusion list %s",
  1149. X                                 newgroups);
  1150. X                        exit (2);
  1151. X                        }
  1152. X                    (void) strcat (newgroups, ",!");
  1153. X                    (void) strcat (newgroups, not_group_array [j]);
  1154. X                    used_not_group_array [j] = TRUE;
  1155. X                    }
  1156. X
  1157. X        /* If can't add new groups to existing list, then do a newnews */
  1158. X        if ((linelen + newlen + add_comma) > NNTP_STRLEN)
  1159. X            {
  1160. X            do_newnews (line);
  1161. X            *line = '\0';
  1162. X            linelen = startlen;
  1163. X            if (not_groups_no)
  1164. X                (void) memset (used_not_group_array, 0, not_groups_no * sizeof (int));
  1165. X            add_comma = FALSE;
  1166. X            }
  1167. X
  1168. X        linelen += newlen + add_comma;
  1169. X        if (add_comma)
  1170. X            (void) strcat (line, ",");
  1171. X        else
  1172. X            add_comma = TRUE;
  1173. X        (void) strcat (line, newgroups);
  1174. X        }
  1175. X
  1176. X    do_newnews (line);
  1177. X
  1178. X    /* Report if couldn't fit everything in the tree */
  1179. X    if (hit_max)
  1180. X        {
  1181. X        log_msg ("Maximum limit of %d messages hit", MAXCACHE);
  1182. X        no_time_flag++;
  1183. X        }
  1184. X    }
  1185. X
  1186. X/* END-OF-FILE */
  1187. END_OF_FILE
  1188.   if test 9772 -ne `wc -c <'newnews.c'`; then
  1189.     echo shar: \"'newnews.c'\" unpacked with wrong size!
  1190.   fi
  1191.   # end of 'newnews.c'
  1192. fi
  1193. if test -f 'slurp.c' -a "${1}" != "-c" ; then 
  1194.   echo shar: Will not clobber existing file \"'slurp.c'\"
  1195. else
  1196.   echo shar: Extracting \"'slurp.c'\" \(18680 characters\)
  1197.   sed "s/^X//" >'slurp.c' <<'END_OF_FILE'
  1198. X/*
  1199. X * slurp - a passive nntp news client
  1200. X *
  1201. X * Copyright (C) 1992/93 Stephen Hebditch. All rights reserved.
  1202. X * TQM Communications, BCM Box 225, London, WC1N 3XX.
  1203. X * steveh@orbital.demon.co.uk  +44 836 825962
  1204. X *
  1205. X * See README for more information and disclaimers
  1206. X *
  1207. X * This is the main routine for slurp together with the routines to
  1208. X * handle the configuration files and command line arguments.
  1209. X *
  1210. X *
  1211. X * $Id: slurp.c,v 1.8 1993/08/20 10:34:50 root Exp root $
  1212. X *
  1213. X * $Log: slurp.c,v $
  1214. X * Revision 1.8  1993/08/20  10:34:50  root
  1215. X * Unlink backup time file before renaming or an error occurs
  1216. X * with the rename under SVR3.
  1217. X *
  1218. X * Revision 1.7  1993/06/07  11:15:00  root
  1219. X * Added support for users to supply a filename for the time file
  1220. X * on the command line, for use with machines with short filenames.
  1221. X * Rewrote read_sys (again!) for a much cleaner implementation.
  1222. X * Fixed problem of time file being wrongly set if slurp was
  1223. X * interrupted before the newnews phase had completed.
  1224. X * If can't rename time file then don't abort, just write the new
  1225. X * file.
  1226. X *
  1227. X * Revision 1.6  1993/04/22  18:22:20  root
  1228. X * Added signal handler to catch SIGHUP, SIGINT, SIGQUIT and SIGTERM.
  1229. X * If occur then report signal in syslog and possibly submit open
  1230. X * batch to news and dump message ids of uncollected articles to
  1231. X * slurp.<hostname>
  1232. X *
  1233. X * Revision 1.5  1993/03/01  17:51:33  root
  1234. X * read_sys can cope with lines longer than BUFSIZ.
  1235. X * report when attempting to load unretrieved message ids.
  1236. X * Move sublist to a parameter after the hostname, separate by a slash.
  1237. X * Changed some system error checking.
  1238. X *
  1239. X * Revision 1.4  1993/02/14  14:57:43  root
  1240. X * Added support for simple authorisation protocol.
  1241. X * Added support for INN's 'MODE READER' command.
  1242. X * Re-arranged command line options.
  1243. X * Rewrote read_sys and added flags and authorisation options to it.
  1244. X * Rewrote get_ntime and set_ntime to use a filename of slurp.<hostname>
  1245. X * instead of slurp.tim, solving lack of locking and allowing the file
  1246. X * to contain a list of unretrieved message ids on the lines following
  1247. X * the time.
  1248. X * Don't care if slurp.<hostname> doesn't exist already.
  1249. X * If RNEWS is not defined, then change to INDIR for writing out batch
  1250. X * files.
  1251. X *
  1252. X * Revision 1.3  1992/12/15
  1253. X * Open syslog *before* we start doing things that might write to it.
  1254. X * Informational messages logged as LOG_INFO.
  1255. X * Assorted minor tidy-ups.
  1256. X *
  1257. X * Revision 1.2  1992/12/07
  1258. X * Corrected test for 4.2/4.3 BSD syslog open.
  1259. X *
  1260. X * Revision 1.1  1992/12/06
  1261. X * Made no_time_flag global.
  1262. X * Fixed null dereferencing of nn_distributions.
  1263. X *
  1264. X * Revision 1.0  1992/08/07
  1265. X * Initial coding.
  1266. X *
  1267. X */
  1268. X
  1269. X#include "slurp.h"
  1270. X#include <signal.h>
  1271. X
  1272. Xchar *hostname = NULL;
  1273. Xchar *pname;
  1274. X
  1275. Xint debug_flag = FALSE;
  1276. Xint no_time_flag = FALSE;
  1277. Xint no_id_load_flag = FALSE;
  1278. Xstatic int local_time_flag = FALSE;
  1279. Xstatic int mode_reader_flag = FALSE;
  1280. X
  1281. Xint  dupart = 0;
  1282. Xint  misart = 0;
  1283. Xint  newart = 0;
  1284. Xlong totalsize = 0;
  1285. X
  1286. Xchar *nn_newsgroups    = NULL;
  1287. Xchar *nn_time          = NULL;
  1288. Xchar *nn_distributions = NULL;
  1289. X
  1290. Xstatic char *ai_username = NULL;
  1291. Xstatic char *ai_password = NULL;
  1292. X
  1293. Xstatic char *sublist = NULL;
  1294. Xstatic char *timefile = NULL;
  1295. X
  1296. Xstruct mnode *root = NULL;
  1297. Xint entries = 0;
  1298. X
  1299. Xstatic long newdate, newtime;
  1300. X
  1301. X
  1302. X/*
  1303. X * test_time - Check NEWNEWS time string is in the right format (ish)
  1304. X */
  1305. X
  1306. X    static int
  1307. Xtest_time ()
  1308. X    {
  1309. X    return (!(isdigit (nn_time [0]) &&
  1310. X              isdigit (nn_time [1]) &&
  1311. X              isdigit (nn_time [2]) &&
  1312. X              isdigit (nn_time [3]) &&
  1313. X              isdigit (nn_time [4]) &&
  1314. X              isdigit (nn_time [5]) &&
  1315. X              isspace (nn_time [6]) &&
  1316. X              isdigit (nn_time [7]) &&
  1317. X              isdigit (nn_time [8]) &&
  1318. X              isdigit (nn_time [9]) &&
  1319. X              isdigit (nn_time [10]) &&
  1320. X              isdigit (nn_time [11]) &&
  1321. X              isdigit (nn_time [12])));
  1322. X    }
  1323. X
  1324. X
  1325. X/*
  1326. X * parse_args - Parse the command line arguments. Returns 1 if there is
  1327. X * an error, otherwise returns 0.
  1328. X */
  1329. X
  1330. X    static int
  1331. Xparse_args (int argc, char **argv)
  1332. X    {
  1333. X    int c;
  1334. X    extern int optind;
  1335. X    extern char *optarg;
  1336. X    char *pos;
  1337. X    
  1338. X    while ((c = getopt (argc, argv, "a:g:t:dilrw")) != EOF)
  1339. X        switch (c)
  1340. X            {
  1341. X            case 'a':    /* Do an authinfo */
  1342. X                if (pos = strchr (optarg, '/'))
  1343. X                    {
  1344. X                    ai_username = optarg;
  1345. X                    *pos++ = '\0';
  1346. X                    ai_password = pos;
  1347. X                    }
  1348. X                else
  1349. X                    {
  1350. X                    (void) fprintf (stderr, "Invalid authinfo username/password");
  1351. X                    return (1);
  1352. X                    }
  1353. X                break;
  1354. X            case 'g':    /* Newsgroups list */
  1355. X                if (pos = strchr (optarg, '/'))
  1356. X                    {
  1357. X                    *pos++ = '\0';
  1358. X                    nn_distributions = pos;
  1359. X                    }
  1360. X                else
  1361. X                    nn_distributions = "";
  1362. X                nn_newsgroups = optarg;
  1363. X                no_time_flag++;
  1364. X                break;
  1365. X            case 't':    /* Start time */
  1366. X                nn_time = optarg;
  1367. X                break;
  1368. X            case 'd':    /* Debugging on */
  1369. X                debug_flag++;
  1370. X                break;
  1371. X            case 'i':    /* Don't load unprocessed ids */
  1372. X                no_id_load_flag++;
  1373. X                break;
  1374. X            case 'l':    /* Use local time */
  1375. X                local_time_flag++;
  1376. X                break;
  1377. X            case 'r':    /* Do a 'MODE READER' */
  1378. X                mode_reader_flag++;
  1379. X                break;
  1380. X            case 'w':    /* Don't set next time */
  1381. X                no_time_flag++;
  1382. X                break;
  1383. X            default:
  1384. X                return (1);
  1385. X            }
  1386. X
  1387. X    /* Get server name */
  1388. X    if (optind < argc)
  1389. X        {
  1390. X        hostname = argv [optind];
  1391. X        if (pos = strchr (hostname, ':'))
  1392. X            {
  1393. X            *pos++ = '\0';
  1394. X            timefile = pos;
  1395. X            }
  1396. X        if (pos = strchr (hostname, '/'))
  1397. X            {
  1398. X            *pos++ = '\0';
  1399. X            sublist = pos;
  1400. X            }
  1401. X        }
  1402. X    else
  1403. X        {
  1404. X        (void) fprintf (stderr, "No server name supplied\n");
  1405. X        return (1);
  1406. X        }
  1407. X
  1408. X    /* If groups are specified, then must have a time */
  1409. X    if ((nn_newsgroups != NULL) && (nn_time == NULL))
  1410. X        {
  1411. X        (void) fprintf (stderr, "Time must be specified for -g option\n");
  1412. X        return (1);
  1413. X        }
  1414. X
  1415. X    /* Verify that the time is in something like the right format */
  1416. X    if (nn_time)
  1417. X        if (test_time ())
  1418. X            {
  1419. X            (void) fprintf (stderr, "Invalid time specification - should be 'YYMMDD HHMMSS'\n");
  1420. X            return (1);
  1421. X            }
  1422. X
  1423. X    return (0);
  1424. X    }
  1425. X
  1426. X
  1427. X/*
  1428. X * read_sys_line - Read a line from the slurp.sys file, skipping lines
  1429. X * which are blank or all comments, truncating lines at comments.
  1430. X * If the line has not yet all been read or the continued-on-next-line
  1431. X * token '\' is present, then returns 1; if eof then returns -1, otherwise
  1432. X * returns 0.
  1433. X */
  1434. X
  1435. X    static int
  1436. Xread_sys_line (char *line, int size, FILE *sysfp)
  1437. X    {
  1438. X    int status;
  1439. X    char *pos;
  1440. X
  1441. X    for (;;)
  1442. X        {
  1443. X        status = 0;
  1444. X
  1445. X        (void) fgets (line, size, sysfp);
  1446. X        if (feof (sysfp))
  1447. X            return (-1);
  1448. X        if (ferror (sysfp))
  1449. X            log_sys ("read_sys_line: Error reading %s", SYSFILE);
  1450. X
  1451. X        if (pos = strchr (line, '\n'))
  1452. X            *pos = '\0';
  1453. X        else
  1454. X            status = 1;
  1455. X
  1456. X        if (pos = strchr (line, '\\'))
  1457. X            {
  1458. X            *pos = '\0';
  1459. X            status = 1;
  1460. X            }
  1461. X
  1462. X        if (pos = strchr (line, '#'))
  1463. X            *pos = '\0';
  1464. X
  1465. X        if (strlen (line))
  1466. X            return (status);
  1467. X        }
  1468. X    }
  1469. X
  1470. X
  1471. X/*
  1472. X * read_sys - Read in the appropriate entry from the slurp.sys file
  1473. X * for the specified hostname. Stores the relevant newsgroups for that
  1474. X * host in nn_newsgroups and the relevant distribution in nn_distributions.
  1475. X * Returns 0 if an appropriate entry for the current host is found, 
  1476. X * otherwise returns 1.
  1477. X */
  1478. X
  1479. X    static int
  1480. Xread_sys ()
  1481. X    {
  1482. X    FILE *sysfp;
  1483. X    char buf [BUFSIZ];
  1484. X    char searchname [BUFSIZ];
  1485. X    size_t tlen;
  1486. X    char *pos;
  1487. X    int status;
  1488. X    int object;
  1489. X
  1490. X    /* Attempt to open the sys file */
  1491. X    if ((sysfp = fopen (SYSFILE, "r")) == NULL)
  1492. X        log_sys ("read_sys: Error opening %s", SYSFILE);
  1493. X
  1494. X    /* Create pattern to search for in the sys file */
  1495. X    (void) strcpy (searchname, hostname);
  1496. X    if (sublist)
  1497. X        {
  1498. X        (void) strcat (searchname, "/");
  1499. X        (void) strcat (searchname, sublist);
  1500. X        }
  1501. X    (void) strcat (searchname, ":");
  1502. X    tlen = strlen (searchname);
  1503. X
  1504. X    /* Read in file until we find hostname */
  1505. X    for (;;)
  1506. X        {
  1507. X        if ((status = read_sys_line (buf, sizeof (buf), sysfp)) == -1)
  1508. X            {
  1509. X            log_msg ("read_sys: Host %s not found in %s",
  1510. X                     hostname, SYSFILE);
  1511. X            return (1);
  1512. X            }
  1513. X        if (strncmp (buf, searchname, tlen) == 0)
  1514. X            break;
  1515. X        }
  1516. X
  1517. X    /* Strip off hostname stuff from front of line */
  1518. X    (void) strcpy (buf, buf + tlen);
  1519. X
  1520. X    /* Start with the newsgroups list */
  1521. X    object = 1;
  1522. X
  1523. X    /* Loop through entry */
  1524. X    for (;;)
  1525. X        {
  1526. X        /* Currently adding newsgroups */
  1527. X        if (object == 1)
  1528. X            {
  1529. X            if (pos = strchr (buf, '/'))        /* Distributions next */
  1530. X                {
  1531. X                *pos++ = '\0';
  1532. X                nn_newsgroups = stradd (nn_newsgroups, buf);
  1533. X                (void) strcpy (buf, pos);
  1534. X                object = 2;
  1535. X                }
  1536. X            else if (pos = strchr (buf, ':'))    /* Flags next */
  1537. X                {
  1538. X                *pos++ = '\0';
  1539. X                nn_newsgroups = stradd (nn_newsgroups, buf);
  1540. X                (void) strcpy (buf, pos);
  1541. X                object = 3;
  1542. X                }
  1543. X            else                                /* Nothing else this line */
  1544. X                nn_newsgroups = stradd (nn_newsgroups, buf);
  1545. X            }
  1546. X
  1547. X        /* Currently adding distributions */
  1548. X        if (object == 2)
  1549. X            {
  1550. X            if (pos = strchr (buf, ':'))        /* Flags next */
  1551. X                {
  1552. X                *pos++ = '\0';
  1553. X                nn_distributions = stradd (nn_distributions, buf);
  1554. X                (void) strcpy (buf, pos);
  1555. X                object = 3;
  1556. X                }
  1557. X            else                                /* Nothing else this line */
  1558. X                nn_distributions = stradd (nn_distributions, buf);
  1559. X            }
  1560. X
  1561. X        /* Currently setting flags */
  1562. X        if (object == 3)
  1563. X            {
  1564. X            if (pos = strchr (buf, ':'))        /* authinfo user next */
  1565. X                *pos++ = '\0';
  1566. X            if (strchr (buf, 'i'))
  1567. X                no_id_load_flag++;
  1568. X            if (strchr (buf, 'l'))
  1569. X                local_time_flag++;
  1570. X            if (strchr (buf, 'r'))
  1571. X                mode_reader_flag++;
  1572. X            if (pos)
  1573. X                {
  1574. X                (void) strcpy (buf, pos);
  1575. X                object = 4;
  1576. X                }
  1577. X            }
  1578. X
  1579. X        /* Currently setting username */
  1580. X        if (object == 4)
  1581. X            {
  1582. X            if (pos = strchr (buf, '/'))        /* authinfo pass next */
  1583. X                {
  1584. X                *pos++ = '\0';
  1585. X                ai_username = stradd (ai_username, buf);
  1586. X                (void) strcpy (buf, pos);
  1587. X                object = 5;
  1588. X                }
  1589. X            else
  1590. X                {
  1591. X                ai_username = stradd (ai_username, buf);
  1592. X                break;
  1593. X                }
  1594. X            }
  1595. X
  1596. X        /* Currently setting password */
  1597. X        if (object == 5)
  1598. X            {
  1599. X            ai_password = stradd (ai_password, buf);
  1600. X            }
  1601. X
  1602. X        if (status != 1)
  1603. X            break;
  1604. X
  1605. X        status = read_sys_line (buf, sizeof (buf), sysfp);
  1606. X        }
  1607. X
  1608. X    (void) fclose (sysfp);
  1609. X
  1610. X    if (nn_distributions == NULL)
  1611. X        nn_distributions = "";
  1612. X
  1613. X    return (0);
  1614. X    }
  1615. X
  1616. X
  1617. X/*
  1618. X * get_ntime - Get the start time for this NEWNEWS for system. Returns 0
  1619. X * if an appropriate entry for the current host is found, otherwise 1.
  1620. X */
  1621. X
  1622. X    static int
  1623. Xget_ntime ()
  1624. X    {
  1625. X    FILE *timefp;
  1626. X    char buf [BUFSIZ];
  1627. X    char filename [PATH_MAX];
  1628. X    char *pos;
  1629. X
  1630. X    /* Attempt to open the time file */
  1631. X    (void) strcpy (filename, TIMFILE);
  1632. X    if (timefile == NULL)
  1633. X        (void) strcat (filename, hostname);
  1634. X    else
  1635. X        (void) strcat (filename, timefile);
  1636. X    if (sublist)
  1637. X        {
  1638. X        (void) strcat (filename, ".");
  1639. X        (void) strcat (filename, sublist);
  1640. X        }
  1641. X    if ((timefp = fopen (filename, "r")) == NULL)
  1642. X        log_sys ("get_ntime: error opening %s", filename);
  1643. X
  1644. X    /* Read in the time and store it */
  1645. X    if ((nn_time = (char *) malloc ((size_t) 14)) == NULL)
  1646. X        log_sys ("get_ntime: malloc 14 bytes");
  1647. X    (void) fgets (nn_time, (size_t) 14, timefp);
  1648. X    if (ferror (timefp))
  1649. X        log_sys ("get_ntime: Error reading %s", filename);
  1650. X    
  1651. X    /* Return if time doesn't look ok */
  1652. X    if (test_time ())
  1653. X        return (1);
  1654. X
  1655. X    /* Load in any message ids following */
  1656. X    if (!no_id_load_flag)
  1657. X        {
  1658. X        if (debug_flag)
  1659. X            (void) fprintf (stderr, "Loading any unretrieved message IDs\n");
  1660. X        for (;;)
  1661. X            {
  1662. X            (void) fgets (buf, sizeof (buf), timefp);
  1663. X            if (feof (timefp))
  1664. X                break;
  1665. X            if (ferror (timefp))
  1666. X                log_sys ("get_ntime: Error reading %s", filename);
  1667. X            if (pos = strchr (buf, '\n'))
  1668. X                *pos = '\0';
  1669. X            if (strlen (buf))
  1670. X                if ((buf [0] == '<') && (buf [strlen (buf) - 1] == '>'))
  1671. X                    process_id (buf);
  1672. X            }
  1673. X        }
  1674. X
  1675. X    (void) fclose (timefp);
  1676. X    return (0);
  1677. X    }
  1678. X
  1679. X
  1680. X/*
  1681. X * write_tree - Traverse the tree writing out ids of articles that were
  1682. X * not successfully retrieved.
  1683. X */
  1684. X
  1685. X    static void
  1686. Xwrite_tree (struct mnode *p, FILE *timefp)
  1687. X    {
  1688. X    if (p != NULL)    
  1689. X        {
  1690. X        write_tree (p->left, timefp);
  1691. X        if (!p->used)
  1692. X            {
  1693. X            (void) fprintf (timefp, "%s\n", p->msgid);
  1694. X            if (ferror (timefp))
  1695. X                log_sys ("write_tree: Error writing ids");
  1696. X            }
  1697. X        write_tree (p->right, timefp);
  1698. X        }
  1699. X    }
  1700. X
  1701. X
  1702. X/*
  1703. X * set_ntime - Set the start time for the next NEWNEWS for system
  1704. X */
  1705. X
  1706. X    void
  1707. Xset_ntime ()
  1708. X    {
  1709. X    FILE *timefp;
  1710. X    char filename [PATH_MAX];
  1711. X    char backup [PATH_MAX];
  1712. X
  1713. X    /* Copy the file to a backup */
  1714. X    (void) strcpy (filename, TIMFILE);
  1715. X    if (timefile == NULL)
  1716. X        (void) strcat (filename, hostname);
  1717. X    else
  1718. X        (void) strcat (filename, timefile);
  1719. X    if (sublist)
  1720. X        {
  1721. X        (void) strcat (filename, ".");
  1722. X        (void) strcat (filename, sublist);
  1723. X        }
  1724. X    (void) strcpy (backup, filename);
  1725. X    (void) strcat (backup, ".o");
  1726. X    if (unlink (backup))
  1727. X        if (errno != ENOENT)
  1728. X            log_ret ("set_ntime: Error unlinking %s", backup);
  1729. X    if (rename (filename, backup))
  1730. X        if (errno != ENOENT)
  1731. X            log_ret ("set_ntime: Error renaming %s to %s", filename, backup);
  1732. X
  1733. X    /* Open new file */
  1734. X    if ((timefp = fopen (filename, "w")) == NULL)
  1735. X        {
  1736. X        log_ret ("get_ntime: Error opening %s", filename);
  1737. X        exit (1);
  1738. X        }
  1739. X
  1740. X    /* Write the new time for current host */
  1741. X    (void) fprintf (timefp, "%06ld %06ld\n", newdate, newtime);
  1742. X    if (ferror (timefp))
  1743. X        {
  1744. X        log_ret ("set_ntime: Error writing %s", filename);
  1745. X        exit (1);
  1746. X        }
  1747. X
  1748. X    /* Write out any message ids not read in */
  1749. X    write_tree (root, timefp);
  1750. X
  1751. X    (void) fclose (timefp);
  1752. X    }
  1753. X
  1754. X
  1755. X/*
  1756. X * do_authinfo - Check in the authinfo username and password with the
  1757. X * server.
  1758. X */
  1759. X
  1760. X    static void
  1761. Xdo_authinfo ()
  1762. X    {
  1763. X    char buf [NNTP_STRLEN];
  1764. X
  1765. X    /* Send the username to the server */
  1766. X    (void) sprintf (buf, "AUTHINFO USER %s", ai_username);
  1767. X    if (debug_flag)
  1768. X        (void) fprintf (stderr, "<- %s\n", buf);
  1769. X    put_server (buf);
  1770. X
  1771. X    /* Get the response and check it's okay */
  1772. X    get_server (buf, sizeof (buf));
  1773. X    if (debug_flag)
  1774. X        (void) fprintf (stderr, "-> %s\n", buf);
  1775. X    if (atoi (buf) != NEED_AUTHDATA)
  1776. X        {
  1777. X        log_msg ("do_authinfo: NNTP protocol error: got '%s'", buf);
  1778. X        exit (4);
  1779. X        }
  1780. X                    
  1781. X    /* Send the password to the server */
  1782. X    (void) sprintf (buf, "AUTHINFO PASS %s", ai_password);
  1783. X    if (debug_flag)
  1784. X        (void) fprintf (stderr, "<- %s\n", buf);
  1785. X    put_server (buf);
  1786. X
  1787. X    /* Get the response and check it's okay */
  1788. X    get_server (buf, sizeof (buf));
  1789. X    if (debug_flag)
  1790. X        (void) fprintf (stderr, "-> %s\n", buf);
  1791. X    if (atoi (buf) != OK_AUTH)
  1792. X        {
  1793. X        log_msg ("do_authinfo: NNTP protocol error: got '%s'", buf);
  1794. X        exit (4);
  1795. X        }
  1796. X    }
  1797. X
  1798. X
  1799. X/*
  1800. X * do_mode_reader - Send mode reader command to INN to switch to nnrpd
  1801. X * so we can do a NEWNEWS.
  1802. X */
  1803. X
  1804. X    static void
  1805. Xdo_mode_reader ()
  1806. X    {
  1807. X    char buf [NNTP_STRLEN];
  1808. X
  1809. X    /* Send the command to the server */
  1810. X    if (debug_flag)
  1811. X        (void) fprintf (stderr, "<- MODE reader\n");
  1812. X    put_server ("MODE READER");
  1813. X
  1814. X    /* Get the response and check it's okay */
  1815. X    get_server (buf, sizeof (buf));
  1816. X    if (debug_flag)
  1817. X        (void) fprintf (stderr, "-> %s\n", buf);
  1818. X    switch (atoi (buf))
  1819. X        {
  1820. X        case OK_CANPOST :
  1821. X        case OK_NOPOST :
  1822. X            break;
  1823. X        default :
  1824. X            log_msg ("do_authinfo: NNTP protocol error: got '%s'", buf);
  1825. X            exit (4);
  1826. X        }
  1827. X    }
  1828. X
  1829. X
  1830. X/*
  1831. X * interrupt - signal handler to report signal in log and possibly
  1832. X * submit remaining batch to news and dump uncollected message ids.
  1833. X */
  1834. X
  1835. X    static void
  1836. Xinterrupt (int signo)
  1837. X    {
  1838. X    log_msg ("interrupt: received signal %d", signo);
  1839. X
  1840. X    enqueue_batch ();
  1841. X    if ((!no_time_flag) && (!no_id_load_flag))
  1842. X        set_ntime ();
  1843. X    exit (1);
  1844. X    }
  1845. X
  1846. X
  1847. X/*
  1848. X * set_signals - set up signal handler to catch appropriate signals.
  1849. X */
  1850. X
  1851. X    static void
  1852. Xset_signals ()
  1853. X    {
  1854. X    if (signal (SIGHUP, interrupt) == SIG_ERR)
  1855. X        log_sys ("set_signals: can't catch SIGHUP");
  1856. X    if (signal (SIGINT, interrupt) == SIG_ERR)
  1857. X        log_sys ("set_signals: can't catch SIGINT");
  1858. X    if (signal (SIGQUIT, interrupt) == SIG_ERR)
  1859. X        log_sys ("set_signals: can't catch SIGQUIT");
  1860. X    if (signal (SIGTERM, interrupt) == SIG_ERR)
  1861. X        log_sys ("set_signals: can't catch SIGTERM");
  1862. X    }
  1863. X
  1864. X
  1865. X/*
  1866. X * MAIN PROCEDURE
  1867. X */
  1868. X
  1869. X    int
  1870. Xmain (int argc, char **argv)
  1871. X    {
  1872. X    int ret;
  1873. X    time_t clock, starttime, endtime;
  1874. X    struct tm *now;
  1875. X
  1876. X    /* Set the name of the program and parse the args */
  1877. X    pname = (pname = (char *) strrchr (argv [0], '/')) ? pname + 1 : argv [0];
  1878. X    if (parse_args (argc, argv))
  1879. X        {
  1880. X        (void) fprintf (stderr, "Usage: %s [-g newsgroups/distribution] [-t time] [-a username/password]\n", pname);
  1881. X        (void) fprintf (stderr, "       [-d] [-i] [-l] [-r] [-w] server[/sublist][:timefile]\n");
  1882. X        exit (2);
  1883. X        }
  1884. X
  1885. X    /* Open syslog if required with appropriate BSD 4.2/4.3 call */
  1886. X#ifdef SYSLOG
  1887. X#ifdef LOG_AUTH
  1888. X    openlog(pname, LOG_PID, SYSLOG);
  1889. X#else
  1890. X    openlog(pname, LOG_PID);
  1891. X#endif
  1892. X#endif
  1893. X
  1894. X    /* If groups not supplied in args, then get from slurp.sys file */
  1895. X    if (nn_newsgroups == NULL)
  1896. X        if (read_sys ())
  1897. X            exit (2);
  1898. X
  1899. X    /* If start time not supplied in args, then get from slurp.tim file */
  1900. X    if (nn_time == NULL)
  1901. X        if (get_ntime ())
  1902. X            exit (2);
  1903. X
  1904. X    if (debug_flag)
  1905. X        {
  1906. X        (void) fprintf (stderr, "server: %s\n", hostname);
  1907. X        (void) fprintf (stderr, "time: %s\n", nn_time);
  1908. X        (void) fprintf (stderr, "newsgroups: '%s'\n", nn_newsgroups);
  1909. X        (void) fprintf (stderr, "distributions: '%s'\n", nn_distributions);
  1910. X        }
  1911. X
  1912. X    /* Unless don't write flag set, get time for next NEWNEWS */
  1913. X    if (!no_time_flag)
  1914. X        {
  1915. X        if (local_time_flag)
  1916. X            clock = time ((time_t *) 0);
  1917. X        else
  1918. X            if ((clock = server_time (hostname)) == 0)
  1919. X                exit (3);
  1920. X
  1921. X        now = gmtime (&clock);
  1922. X        newdate = (now->tm_year * 10000) +
  1923. X                 ((now->tm_mon + 1) * 100) +
  1924. X                   now->tm_mday;
  1925. X        newtime = (now->tm_hour * 10000) +
  1926. X                  (now->tm_min * 100) +
  1927. X                   now->tm_sec;
  1928. X        }
  1929. X
  1930. X    /* Open the history file */
  1931. X    if (open_history ())
  1932. X        log_sys ("Can't open history file %s", HISTORY_FILE);
  1933. X
  1934. X#ifndef RNEWS
  1935. X    /* Change to the incoming batch directory */
  1936. X    if (chdir (INDIR))
  1937. X        log_sys ("Can't change directory to %s", INDIR);
  1938. X#endif
  1939. X
  1940. X    /* Set up the connection to the server */
  1941. X    switch (ret = server_init (hostname))
  1942. X        {
  1943. X        case -1 :
  1944. X            exit (3);
  1945. X        case OK_CANPOST :
  1946. X        case OK_NOPOST :
  1947. X            break;
  1948. X        default :
  1949. X            log_msg ("Can't talk to %s: got response code %d", hostname, ret);
  1950. X            exit (4);
  1951. X        }
  1952. X
  1953. X    /* If authinfo details supplied, then use 'em */
  1954. X    if (ai_username)
  1955. X        do_authinfo ();
  1956. X
  1957. X    /* Switch INN to nnrpd instead of innd if needed */
  1958. X    if (mode_reader_flag)
  1959. X        do_mode_reader ();
  1960. X
  1961. X    /* Get a list of the new articles */
  1962. X    get_ids ();
  1963. X
  1964. X    /* Now get the actual articles */
  1965. X    starttime = time ((time_t *) 0);
  1966. X    if (entries > 0)
  1967. X        {
  1968. X        set_signals ();
  1969. X        get_articles ();
  1970. X        }
  1971. X    endtime = time ((time_t *) 0);
  1972. X
  1973. X    /* Time to say goodbye */
  1974. X    close_server ();
  1975. X    close_history ();
  1976. X
  1977. X    /* Submit the remaining batch, if present */
  1978. X    enqueue_batch ();
  1979. X
  1980. X    /* do we want to update the timestamp file? */
  1981. X    if (!no_time_flag)
  1982. X        set_ntime ();
  1983. X
  1984. X#ifdef SYSLOG
  1985. X    if (!debug_flag)
  1986. X        syslog (LOG_INFO,"Processed %d new, %d duplicate, %d missing articles",
  1987. X                newart, dupart, misart);
  1988. X    else
  1989. X#endif
  1990. X        (void) fprintf (stderr, "Processed %d new, %d duplicate, %d missing articles\n",
  1991. X                        newart, dupart, misart);
  1992. X
  1993. X#ifdef SPEEDSTATS
  1994. X  #ifdef SYSLOG
  1995. X    if (!debug_flag)
  1996. X        syslog (LOG_INFO, "Average transfer speed %ld cps",
  1997. X                totalsize / (starttime == endtime ? 1 : endtime - starttime));
  1998. X    else
  1999. X  #endif
  2000. X        (void) fprintf (stderr, "Average transfer speed %ld cps\n",
  2001. X                totalsize / (starttime == endtime ? 1 : endtime - starttime));
  2002. X#endif
  2003. X
  2004. X    exit (0);
  2005. X    }
  2006. X
  2007. X/* END-OF-FILE */
  2008. END_OF_FILE
  2009.   if test 18680 -ne `wc -c <'slurp.c'`; then
  2010.     echo shar: \"'slurp.c'\" unpacked with wrong size!
  2011.   fi
  2012.   # end of 'slurp.c'
  2013. fi
  2014. echo shar: End of archive 1 \(of 3\).
  2015. cp /dev/null ark1isdone
  2016. MISSING=""
  2017. for I in 1 2 3 ; do
  2018.     if test ! -f ark${I}isdone ; then
  2019.     MISSING="${MISSING} ${I}"
  2020.     fi
  2021. done
  2022. if test "${MISSING}" = "" ; then
  2023.     echo You have unpacked all 3 archives.
  2024.     rm -f ark[1-9]isdone
  2025. else
  2026.     echo You still must unpack the following archives:
  2027.     echo "        " ${MISSING}
  2028. fi
  2029. exit 0
  2030. exit 0 # Just in case...
  2031.