home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume36 / slurp / part01 < prev    next >
Encoding:
Text File  |  1993-03-11  |  51.8 KB  |  2,006 lines

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