home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume19 / cnews2 / part13 < prev    next >
Text File  |  1989-06-29  |  49KB  |  2,220 lines

  1. Subject:  v19i090:  Cnews production release, Part13/19
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: utzoo!henry
  7. Posting-number: Volume 19, Issue 90
  8. Archive-name: cnews2/part13
  9.  
  10. : ---CUT HERE---
  11. echo 'nntpdiffs/src/misc.c':
  12. sed 's/^X//' >'nntpdiffs/src/misc.c' <<'!'
  13. X#ifndef lint
  14. Xstatic char    *sccsid = "@(#)misc.c    1.25    (Berkeley) 2/6/88";
  15. X#endif
  16. X
  17. X#include "../common/conf.h"
  18. X
  19. X#include "common.h"
  20. X
  21. X/*
  22. X * open_valid_art -- determine if a given article name is valid;
  23. X *        if it is, return a file pointer to the open article,
  24. X *        along with a unique id of the article.
  25. X *
  26. X *    Parameters:    "artname" is a string containing the
  27. X *            name of the article.
  28. X *            "id" is space for us to put the article
  29. X *            id in.
  30. X *
  31. X *    Returns:    File pointer to the open article if the
  32. X *            article is valid; NULL otherwise
  33. X *
  34. X *    Side effects:    None.
  35. X */
  36. X
  37. XFILE *
  38. Xopen_valid_art(artname, id)
  39. X    char        *artname;
  40. X    char        *id;
  41. X{
  42. X    static int    crnt_art_num;
  43. X    static char    crnt_art_id[MAXBUFLEN];
  44. X    int        fd;
  45. X    struct stat    statbuf;
  46. X
  47. X    if (art_fp != NULL) {
  48. X        if (crnt_art_num == atoi(artname)) {
  49. X            if (fseek(art_fp, (long) 0, 0) < 0)
  50. X                close_crnt();
  51. X            else {
  52. X                (void) strcpy(id, crnt_art_id);
  53. X                return (art_fp);
  54. X            }
  55. X        } else 
  56. X            close_crnt();
  57. X    }
  58. X
  59. X    art_fp = fopen(artname, "r");
  60. X
  61. X    if (art_fp == NULL)
  62. X        return (NULL);
  63. X
  64. X    fd = fileno(art_fp);
  65. X
  66. X    if (fstat(fd, &statbuf) < 0) {
  67. X        close_crnt();
  68. X        return (NULL);
  69. X    }
  70. X
  71. X    if ((statbuf.st_mode & S_IFREG) != S_IFREG) {
  72. X        close_crnt();
  73. X        return (NULL);
  74. X    }
  75. X
  76. X    get_id(art_fp, id);
  77. X    (void) strcpy(crnt_art_id, id);
  78. X    crnt_art_num = atoi(artname);
  79. X    return (art_fp);
  80. X}
  81. X
  82. X
  83. X/*
  84. X * gethistent -- return the path name of an article if it's
  85. X * in the history file.
  86. X *
  87. X *    Parameters:    "msg_id" is the message ID of the
  88. X *            article, enclosed in <>'s.
  89. X *
  90. X *    Returns:    A char pointer to a static data area
  91. X *            containing the full pathname of the
  92. X *            article, or NULL if the message-id is not
  93. X *            in thef history file.
  94. X *
  95. X *    Side effects:    opens dbm database
  96. X *            (only once, keeps it open after that).
  97. X */
  98. X
  99. X#ifndef NDBM
  100. X# ifndef DBM
  101. X#  ifndef USGHIST
  102. X#   define USGHIST
  103. X#  endif not USGHIST
  104. X# endif not DBM
  105. X#endif not DBM
  106. X
  107. Xchar *
  108. Xgethistent(msg_id)
  109. X    char        *msg_id;
  110. X{
  111. X    char        line[MAXBUFLEN];
  112. X    char        *tmp;
  113. X    register char    *cp;
  114. X    long        ltmp;
  115. X    static char    path[MAXPATHLEN];
  116. X#ifdef USGHIST
  117. X    char        *histfile();
  118. X    register int    len;
  119. X#else not USGHIST
  120. X#ifdef DBM
  121. X    static int    dbopen = 0;
  122. X    datum        fetch();
  123. X#else not DBM
  124. X    static DBM    *db = NULL;    /* History file, dbm version */
  125. X#endif DBM
  126. X    datum         key, content;
  127. X#endif USGHIST
  128. X    static FILE    *hfp = NULL;    /* history file, text version */
  129. X
  130. X#ifdef USGHIST
  131. X    hfp = fopen(histfile(msg_id), "r");
  132. X    if (hfp == NULL) {
  133. X#ifdef SYSLOG
  134. X        syslog(LOG_ERR, "gethistent: histfile: %m");
  135. X#endif SYSLOG
  136. X        return (NULL);
  137. X    }
  138. X
  139. X    len = strlen(msg_id);
  140. X    while (fgets(line, sizeof (line), hfp))
  141. X        if (!strncasecmp(msg_id, line, len))
  142. X            break;
  143. X
  144. X    if (feof(hfp)) {
  145. X        (void) fclose(hfp);
  146. X        return (NULL);
  147. X    }
  148. X#else not USGHIST
  149. X#ifdef DBM
  150. X    if (!dbopen) {
  151. X        if (dbminit(historyfile) < 0) {
  152. X#ifdef SYSLOG
  153. X            syslog(LOG_ERR, "openartbyid: dbminit %s: %m",
  154. X                historyfile);
  155. X#endif SYSLOG
  156. X            return (NULL);
  157. X        } else
  158. X            dbopen = 1;
  159. X    }
  160. X#else    /* ndbm */
  161. X    if (db == NULL) {
  162. X        db = dbm_open(historyfile, O_RDONLY, 0);
  163. X        if (db == NULL) {
  164. X#ifdef SYSLOG
  165. X            syslog(LOG_ERR, "openartbyid: dbm_open %s: %m",
  166. X                historyfile);
  167. X#endif SYSLOG
  168. X            return (NULL);
  169. X        }
  170. X    }
  171. X#endif DBM
  172. X
  173. X    key.dptr = msg_id;
  174. X    key.dsize = strlen(msg_id) + 1;
  175. X
  176. X#ifdef DBM
  177. X    content = fetch(key);
  178. X#else    /* ndbm */
  179. X    content = dbm_fetch(db, key);
  180. X#endif DBM
  181. X    if (content.dptr == NULL)
  182. X        return (NULL);
  183. X
  184. X    if (hfp == NULL) {
  185. X        hfp = fopen(historyfile, "r");
  186. X        if (hfp == NULL) {
  187. X#ifdef SYSLOG
  188. X            syslog(LOG_ERR, "message: fopen %s: %m",
  189. X                historyfile);
  190. X#endif SYSLOG
  191. X            return (NULL);
  192. X        }
  193. X    }
  194. X
  195. X    bcopy(content.dptr, (char *)<mp, sizeof (long));
  196. X    if (fseek(hfp, ltmp, 0) < 0) {
  197. X#ifdef SYSLOG
  198. X        syslog(LOG_ERR, "message: fseek: %m");
  199. X#endif SYSLOG
  200. X        return (NULL);
  201. X    }
  202. X
  203. X    (void) fgets(line, sizeof(line), hfp);
  204. X#endif USGHIST
  205. X
  206. X    if ((cp = index(line, '\n')) != NULL)
  207. X        *cp = '\0';
  208. X    cp = index(line, '\t');
  209. X    if (cp != NULL)
  210. X        cp = index(cp+1, '\t');
  211. X    if (cp == NULL) {
  212. X#ifdef SYSLOG
  213. X        syslog(LOG_ERR,
  214. X        "message: malformed line in history file at %ld bytes, id %s",
  215. X            ltmp, msg_id);
  216. X#endif SYSLOG
  217. X        return (NULL);
  218. X    }
  219. X    tmp = cp+1;
  220. X
  221. X    if ((cp = index(tmp, ' ')) != NULL)
  222. X        *cp = '\0';
  223. X    
  224. X    while ((cp = index(tmp, '.')) != NULL)
  225. X        *cp = '/';
  226. X
  227. X    (void) strcpy(path, spooldir);
  228. X    (void) strcat(path, "/");
  229. X    (void) strcat(path, tmp);
  230. X
  231. X    return (path);
  232. X}
  233. X
  234. X/*
  235. X * openartbyid -- open an article by message-id.
  236. X *
  237. X *    Arguments:    "msg_id" is the message-id of the article
  238. X *            to open.
  239. X *
  240. X *    Returns:    File pointer to opened article, or NULL if
  241. X *            the article was not in the history file or
  242. X *            could not be opened.
  243. X *
  244. X *    Side effects:    Opens article.
  245. X */
  246. X
  247. XFILE *
  248. Xopenartbyid(msg_id)
  249. X    char    *msg_id;
  250. X{
  251. X    char    *path;
  252. X
  253. X    path = gethistent(msg_id);
  254. X    if (path != NULL)
  255. X        return (fopen(path, "r"));
  256. X    else
  257. X        return (NULL);
  258. X}
  259. X
  260. X
  261. X/*
  262. X * check_ngperm -- check to see if they're allowed to see this
  263. X * article by matching Newsgroups: and Distribution: line.
  264. X *
  265. X *    Parameters:    "fp" is the file pointer of this article.
  266. X *
  267. X *    Returns:    0 if they're not allowed to see it.
  268. X *            1 if they are.
  269. X *
  270. X *    Side effects:    None.
  271. X */
  272. X
  273. Xcheck_ngperm(fp)
  274. X    register FILE    *fp;
  275. X{
  276. X    char        buf[MAXBUFLEN];
  277. X    register char    *cp;
  278. X    static char    **ngarray;
  279. X    int        ngcount;
  280. X
  281. X    if (ngpermcount == 0)
  282. X        return (1);
  283. X
  284. X    while (fgets(buf, sizeof (buf), fp) != NULL) {
  285. X        if (buf[0] == '\n')        /* End of header */
  286. X            break;
  287. X        if (buf[0] != 'N' && buf[0] != 'n')
  288. X            continue;
  289. X        cp = index(buf, '\n');
  290. X        if (cp)
  291. X            *cp = '\0';
  292. X        cp = index(buf, ':');
  293. X        if (cp == NULL)
  294. X            continue;
  295. X        *cp = '\0';
  296. X        if (!strcasecmp(buf, "newsgroups")) {
  297. X            ngcount = get_nglist(&ngarray, cp+2);
  298. X            break;
  299. X        }
  300. X    }
  301. X
  302. X    (void) rewind(fp);
  303. X
  304. X    if (ngcount == 0)    /* Either no newgroups or null entry */
  305. X        return (1);
  306. X
  307. X    return (ngmatch(s1strneql, ALLBUT,
  308. X        ngpermlist, ngpermcount, ngarray, ngcount));
  309. X}
  310. X
  311. X
  312. X/*
  313. X * spew -- spew out the contents of a file to stdout, doing
  314. X * the necessary cr-lf additions at the end.  Finish with
  315. X * a "." on a line by itself, and an fflush(stdout).
  316. X *
  317. X *    Parameters:    "how" tells what part of the file we
  318. X *            want spewed:
  319. X *                ARTICLE   The entire thing.
  320. X *                HEAD      Just the first part.
  321. X *                BODY      Just the second part.
  322. X *            "fp" is the open file to spew from.
  323. X *
  324. X *    Returns:    Nothing.
  325. X *
  326. X *    Side effects:    Changes current position in file.
  327. X */
  328. X
  329. Xspew(fp, how)
  330. X    FILE        *fp;
  331. X    int        how;
  332. X{
  333. X    char        line[NNTP_STRLEN];
  334. X    register char    *cp;
  335. X
  336. X#ifdef LOG
  337. X    ++arts_acsd;
  338. X#endif
  339. X
  340. X    if (how == STAT) {
  341. X        (void) fflush(stdout);
  342. X        return;
  343. X    }
  344. X
  345. X    while (fgets(line, sizeof(line)-6, fp) != NULL && *line != '\n') {
  346. X        if (how == BODY)    /* We need to skip this anyway */
  347. X            continue;
  348. X        cp = index(line, '\n');
  349. X        if (cp != NULL)
  350. X            *cp = '\0';
  351. X        if (*line == '.')
  352. X            putchar('.');
  353. X        putline(line);
  354. X        if (cp == NULL) {
  355. X            for (;;) {
  356. X                if ((fgets(line, sizeof(line)-6, fp) == NULL)
  357. X                    || (index(line, '\n') != NULL))
  358. X                    break;
  359. X            }
  360. X        }
  361. X    }
  362. X
  363. X    if (how == HEAD) {
  364. X        putchar('.');
  365. X        putchar('\r');
  366. X        putchar('\n');
  367. X        (void) fflush(stdout);
  368. X        return;
  369. X    } else if (how == ARTICLE) {
  370. X        putchar('\r');
  371. X        putchar('\n');
  372. X    }
  373. X
  374. X    while (fgets(line, sizeof(line)-6, fp) != NULL) {
  375. X        cp = index(line, '\n');
  376. X        if (cp != NULL)
  377. X            *cp = '\0';
  378. X        if (*line == '.')
  379. X            putchar('.');
  380. X        putline(line);
  381. X
  382. X        if (cp == NULL) {
  383. X            for (;;) {
  384. X                if ((fgets(line, sizeof(line)-6, fp) == NULL)
  385. X                    || (index(line, '\n') != NULL))
  386. X                    break;
  387. X            }
  388. X        }
  389. X    }
  390. X    putchar('.');
  391. X    putchar('\r');
  392. X    putchar('\n');
  393. X    (void) fflush(stdout);
  394. X}
  395. X
  396. X
  397. X/*
  398. X * get_id -- get the message id of the current article.
  399. X *
  400. X *    Parameters:    "art_fp" is a pointer to the open file.
  401. X *            "id" is space for the message ID.
  402. X *
  403. X *    Returns:    Nothing.
  404. X *
  405. X *    Side effects:    Seeks and rewinds on "art_fp".
  406. X *            Changes space pointed to by "id".
  407. X */
  408. X
  409. Xget_id(art_fp, id)
  410. X    register FILE    *art_fp;
  411. X    char        *id;
  412. X{
  413. X    char        line[MAXBUFLEN];
  414. X    register char    *cp;
  415. X
  416. X    while (fgets(line, sizeof(line), art_fp) != NULL) {
  417. X        if (*line == '\n')
  418. X            break;
  419. X        if (*line == 'M' || *line == 'm') {    /* "Message-ID" */
  420. X            if ((cp = index(line, ' ')) != NULL) {
  421. X                *cp = '\0';
  422. X                if (!strcasecmp(line, "Message-ID:")) {
  423. X                    (void) strcpy(id, cp + 1);
  424. X                    if ((cp = index(id, '\n')) != NULL)
  425. X                        *cp = '\0';
  426. X                    (void) rewind(art_fp);
  427. X                    return;
  428. X                }
  429. X            }
  430. X        }
  431. X    }
  432. X    (void) rewind(art_fp);
  433. X    (void) strcpy(id, "<0>");
  434. X}
  435. X        
  436. X
  437. X/*
  438. X * close_crnt -- close the current article file pointer, if it's
  439. X *    open.
  440. X *
  441. X *    Parameters:    None.
  442. X *
  443. X *    Returns:    Nothing.
  444. X *
  445. X *    Side effects:    Closes "art_fp" if it's open; sets "art_fp" to NULL.
  446. X */
  447. X
  448. Xclose_crnt()
  449. X{
  450. X    if (art_fp != NULL)
  451. X        (void) fclose(art_fp);
  452. X    art_fp = NULL;
  453. X}
  454. X
  455. X
  456. X/*
  457. X * findart -- find an article number in the article array.
  458. X *
  459. X *    Parameters:    "artname" is a string containing
  460. X *            the name of the article.
  461. X *
  462. X *    Returns:    An index into "art_array",
  463. X *            or -1 if "artname" isn't in "art_array".
  464. X *            
  465. X *    Side effects:    None.
  466. X *
  467. X *    Improvement:    Replace this linear search with a binary one.
  468. X */
  469. X
  470. Xfindart(artname)
  471. X    char        *artname;
  472. X{
  473. X    register int    i, artnum;
  474. X
  475. X    artnum = atoi(artname);
  476. X
  477. X    for (i = 0; i < num_arts; ++i)
  478. X        if (art_array[i] == artnum)
  479. X            return(i);
  480. X
  481. X    return (-1);
  482. X}
  483. X
  484. X
  485. X/*
  486. X * get_distlist -- return a nicely set up array of distribution groups
  487. X * along with a count, when given an NNTP-spec distribution list
  488. X * in the form <dist1,dist2,...,distn>.
  489. X *
  490. X *    Parameters:        "array" is storage for our array,
  491. X *                set to point at some static data.
  492. X *                "list" is the NNTP distribution list.
  493. X *
  494. X *    Returns:        Number of distributions found.
  495. X *                -1 on error.
  496. X *
  497. X *    Side effects:        Changes static data area.
  498. X */
  499. X
  500. Xget_distlist(array, list)
  501. X    char        ***array;
  502. X    char        *list;
  503. X{
  504. X    char        *cp;
  505. X    int        distcount;
  506. X    static char    **dist_list = (char **) NULL;
  507. X
  508. X    if (list[0] != '<')
  509. X        return (-1);
  510. X
  511. X    cp = index(list + 1, '>');
  512. X    if (cp != NULL)
  513. X        *cp = '\0';
  514. X    else
  515. X        return (-1);
  516. X
  517. X    for (cp = list + 1; *cp != '\0'; ++cp)
  518. X        if (*cp == ',')
  519. X            *cp = ' ';
  520. X    distcount = parsit(list + 1, &dist_list);
  521. X    *array = dist_list;
  522. X    return (distcount);
  523. X}
  524. X
  525. X
  526. X/*
  527. X * lower -- convert a character to lower case, if it's upper case.
  528. X *
  529. X *    Parameters:    "c" is the character to be
  530. X *            converted.
  531. X *
  532. X *    Returns:    "c" if the character is not
  533. X *            upper case, otherwise the lower
  534. X *            case eqivalent of "c".
  535. X *
  536. X *    Side effects:    None.
  537. X */
  538. X
  539. Xchar
  540. Xlower(c)
  541. X    register char    c;
  542. X{
  543. X    if (isascii(c) && isupper(c))
  544. X        c = c - 'A' + 'a';
  545. X    return (c);
  546. X}
  547. X
  548. X
  549. X/* the following is from news 2.11 */
  550. X
  551. X#ifdef USG
  552. X/*
  553. X** Generate the appropriate history subfile name
  554. X*/
  555. Xchar *
  556. Xhistfile(hline)
  557. Xchar *hline;
  558. X{
  559. X    char chr;    /* least significant digit of article number */
  560. X    static char subfile[BUFSIZ];
  561. X
  562. X    chr = findhfdigit(hline);
  563. X    sprintf(subfile, "%s.d/%c", HISTORY_FILE, chr);
  564. X    return subfile;
  565. X}
  566. X
  567. Xfindhfdigit(fn)
  568. Xchar *fn;
  569. X{
  570. X    register char *p;
  571. X    register int chr;
  572. X
  573. X    p = index(fn, '@');
  574. X    if (p != NULL && p > fn)
  575. X        chr = *(p - 1);
  576. X    else
  577. X        chr = '0';
  578. X    if (!isdigit(chr))
  579. X        chr = '0';
  580. X    return chr;
  581. X}
  582. Xbcopy(s, d, l)
  583. X    register char *s, *d;
  584. X    register int l;
  585. X{
  586. X    while (l-- > 0)
  587. X        *d++ = *s++;
  588. X}
  589. X
  590. Xbcmp(s1, s2, l)
  591. X    register char *s1, *s2;
  592. X    register int l;
  593. X{
  594. X    if (l == 0)
  595. X        return (0);
  596. X
  597. X    do
  598. X        if (*s1++ != *s2++)
  599. X            break;
  600. X    while (--l);
  601. X
  602. X    return (l);
  603. X}
  604. X
  605. Xbzero(p, l)
  606. X    register char *p;
  607. X    register int l;
  608. X{
  609. X    while (l-- > 0)
  610. X        *p++ = 0;
  611. X}
  612. X
  613. Xdup2(x,y)
  614. Xint x,y;
  615. X{ 
  616. X    close(y); 
  617. X    return(fcntl(x, F_DUPFD,y ));
  618. X}
  619. X#endif USG
  620. !
  621. echo 'nntpdiffs/src/newnews.c':
  622. sed 's/^X//' >'nntpdiffs/src/newnews.c' <<'!'
  623. X#ifndef lint
  624. Xstatic char    *sccsid = "@(#)newnews.c    1.19    (Berkeley) 2/6/88";
  625. X#endif
  626. X
  627. X#include "common.h"
  628. X#include "time.h"
  629. X
  630. X#ifdef LOG
  631. Xint    nn_told = 0;
  632. Xint    nn_took = 0;
  633. X#endif
  634. X
  635. X
  636. X/*
  637. X * NEWNEWS newsgroups date time ["GMT"] [<distributions>]
  638. X *
  639. X * Return the message-id's of any news articles past
  640. X * a certain date and time, within the specified distributions.
  641. X *
  642. X */
  643. X
  644. Xnewnews(argc, argv)
  645. X    register int    argc;
  646. X    char        *argv[];
  647. X{
  648. X    register char    *cp, *ngp;
  649. X    char        *key;
  650. X    char        datebuf[32];
  651. X    char        line[MAXBUFLEN];
  652. X    char        **distlist, **histlist;
  653. X    static char    **nglist;
  654. X    int        distcount, ngcount, histcount;
  655. X    int        all;
  656. X    FILE        *fp;
  657. X    long        date;
  658. X    long        dtol();
  659. X    char        *ltod();
  660. X#ifdef USG
  661. X    FILE        *tmplst;
  662. X    int        i;
  663. X    char        *tmpfile;
  664. X#endif USG
  665. X
  666. X    if (argc < 4) {
  667. X        printf("%d Usage: NEWNEWS newsgroups yymmdd hhmmss [\"GMT\"] [<distributions>].\r\n",
  668. X            ERR_CMDSYN);
  669. X        (void) fflush(stdout);
  670. X        return;
  671. X    }
  672. X
  673. X#ifdef LOG
  674. X    sprintf(line, "%s newnews %s %s %s %s %s",
  675. X        hostname,
  676. X        argv[1],
  677. X        argv[2],
  678. X        argv[3],
  679. X        (argc >= 5 && *argv[4] == 'G') ? "GMT" : "local",
  680. X        (argc >= 5 && *argv[argc-1] == '<') ? argv[argc-1] : "none");
  681. X    syslog(LOG_INFO, line);
  682. X#endif
  683. X
  684. X    all = (argv[1][0] == '*' && argv[1][1] == '\0');
  685. X    if (!all) {
  686. X        ngcount = get_nglist(&nglist, argv[1]);
  687. X        if (ngcount == 0) {
  688. X            printf("%d Bogus newsgroup specifier: %s\r\n",
  689. X                ERR_CMDSYN, argv[1]);
  690. X            (void) fflush(stdout);
  691. X            return;
  692. X        }
  693. X    }
  694. X
  695. X    /*        YYMMDD            HHMMSS    */
  696. X    if (strlen(argv[2]) != 6 || strlen(argv[3]) != 6) {
  697. X        printf("%d Date/time must be in form YYMMDD HHMMSS.\r\n",
  698. X            ERR_CMDSYN);
  699. X        (void) fflush(stdout);
  700. X        return;
  701. X    }
  702. X
  703. X    (void) strcpy(datebuf, argv[2]);
  704. X    (void) strcat(datebuf, argv[3]);
  705. X
  706. X    argc -= 4;
  707. X    argv += 4;
  708. X
  709. X    /*
  710. X     * Flame on.  The history file is not stored in GMT, but
  711. X     * in local time.  So we have to convert GMT to local time
  712. X     * if we're given GMT, otherwise we need only chop off the
  713. X     * the seconds.  Such braindamage.
  714. X     */
  715. X
  716. X    key = datebuf;        /* Unless they specify GMT */
  717. X
  718. X    if (argc > 0) {
  719. X        if (!strcasecmp(*argv, "GMT")) { /* Which we handle here */
  720. X            date = dtol(datebuf);
  721. X            if (date < 0) {
  722. X                printf("%d Invalid date specification.\r\n",
  723. X                    ERR_CMDSYN);
  724. X                (void) fflush(stdout);
  725. X                return;
  726. X            }
  727. X            date = gmt_to_local(date);
  728. X            key = ltod(date);
  729. X            ++argv;
  730. X            --argc;
  731. X        }
  732. X    }
  733. X
  734. X    /* So, key now points to the local time, but we need to zap secs */
  735. X
  736. X    key[10] = '\0';
  737. X
  738. X    distcount = 0;
  739. X    if (argc > 0) {
  740. X        distcount = get_distlist(&distlist, *argv);
  741. X        if (distcount < 0) {
  742. X            printf("%d Bad distribution list: %s\r\n", ERR_CMDSYN,
  743. X                *argv);
  744. X            (void) fflush(stdout);
  745. X            return;
  746. X        }
  747. X    }
  748. X
  749. X#ifdef USG
  750. X    if ((tmpfile = mktemp("/tmp/listXXXXXX")) == NULL ||
  751. X        (tmplst = fopen(tmpfile, "w+")) == NULL) {
  752. X    printf("%d Cannot process history file.\r\n", ERR_FAULT);
  753. X    (void) fflush(stdout);
  754. X    return;
  755. X    }
  756. X
  757. X    for (i = 0; i < 9; i++) {
  758. X        sprintf(historyfile, "%s.d/%d", HISTORY_FILE, i);
  759. X#endif USG
  760. X
  761. X    fp = fopen(historyfile, "r");
  762. X    if (fp == NULL) {
  763. X#ifdef SYSLOG
  764. X        syslog(LOG_ERR, "newnews: fopen %s: %m", historyfile);
  765. X#endif
  766. X#ifndef USG
  767. X        printf("%d Cannot open history file.\r\n", ERR_FAULT);
  768. X        (void) fflush(stdout);
  769. X        return;
  770. X#else USG
  771. X        continue;
  772. X#endif USG
  773. X    }
  774. X
  775. X#ifndef USG
  776. X    printf("%d New news by message id follows.\r\n", OK_NEWNEWS);
  777. X#endif not USG
  778. X
  779. X    if (seekuntil(fp, key, line, sizeof (line)) < 0) {
  780. X#ifndef USG
  781. X        printf(".\r\n");
  782. X        (void) fflush(stdout);
  783. X#endif not USG
  784. X        (void) fclose(fp);
  785. X#ifndef USG
  786. X        return;
  787. X#else USG
  788. X        continue;
  789. X#endif USG
  790. X    }
  791. X
  792. X/*
  793. X * History file looks like:
  794. X *
  795. X * <1569@emory.UUCP>    01/22/86 09:19    net.micro.att/899 ucb.general/2545 
  796. X *             ^--tab            ^--tab         ^--space         ^sp\0
  797. X * Sometimes the newsgroups are missing; we try to be robust and
  798. X * ignore such bogosity.  We tackle this by our usual parse routine,
  799. X * and break the list of articles in the history file into an argv
  800. X * array with one newsgroup per entry.
  801. X */
  802. X
  803. X    do {
  804. X        if ((cp = index(line, '\t')) == NULL)
  805. X            continue;
  806. X
  807. X        if ((ngp = index(cp+1, '\t')) == NULL)    /* 2nd tab */
  808. X            continue;
  809. X        ++ngp;            /* Points at newsgroup list */
  810. X        if (*ngp == '\n')
  811. X            continue;
  812. X        histcount = get_histlist(&histlist, ngp);
  813. X        if (histcount == 0)
  814. X            continue;
  815. X
  816. X        /*
  817. X         * For each newsgroup on this line in the history
  818. X         * file, check it against the newsgroup names we're given.
  819. X         * If it matches, then see if we're hacking distributions.
  820. X         * If so, open the file and match the distribution line.
  821. X         */
  822. X
  823. X        if (!all)
  824. X            if (!ngmatch(restreql, 0, nglist, ngcount,
  825. X                histlist, histcount))
  826. X                continue;
  827. X
  828. X        if (distcount)
  829. X            if (!distmatch(distlist, distcount, histlist, histcount))
  830. X                continue;
  831. X
  832. X        *cp = '\0';
  833. X#ifdef USG
  834. X        fputs(line, tmplst);
  835. X        fputc('\n', tmplst);
  836. X#else not USG
  837. X        putline(line);
  838. X#endif not USG
  839. X#ifdef LOG
  840. X        nn_told++;
  841. X#endif
  842. X    } while (fgets(line, sizeof(line), fp) != NULL);
  843. X
  844. X#ifndef USG
  845. X    putchar('.');
  846. X    putchar('\r');
  847. X    putchar('\n');
  848. X    (void) fflush(stdout);
  849. X#endif
  850. X    (void) fclose(fp);
  851. X#ifdef USG
  852. X    }
  853. X    printf("%d New news by message id follows.\r\n", OK_NEWNEWS);
  854. X    rewind(tmplst);
  855. X    while (fgets(line, sizeof(line), tmplst) != NULL)
  856. X            putline(line);
  857. X    putchar('.');
  858. X    putchar('\r');
  859. X    putchar('\n');
  860. X    (void) fflush(stdout);
  861. X    (void) fclose(tmplst);
  862. X    (void) unlink(tmpfile);
  863. X#endif USG
  864. X}
  865. X
  866. X
  867. X/*
  868. X * seekuntil -- seek through the history file looking for
  869. X * a line with date "key".  Get that line, and return.
  870. X *
  871. X *    Parameters:    "fp" is the active file.
  872. X *            "key" is the date, in form YYMMDDHHMM (no SS)
  873. X *            "line" is storage for the first line we find.
  874. X *
  875. X *    Returns:    -1 on error, 0 otherwise.
  876. X *
  877. X *    Side effects:    Seeks in history file, modifies line.
  878. X */
  879. X
  880. Xseekuntil(fp, akey, line, linesize)
  881. X    FILE        *fp;
  882. X    char        *akey;
  883. X    char        *line;
  884. X    int        linesize;
  885. X{
  886. X    char        datetime[32];
  887. X    register int    c;
  888. X    register long    top, bot, mid;
  889. X    extern long dtol();
  890. X    char key[30];
  891. X
  892. X    (void) sprintf(key, "%ld", dtol(akey));    /* akey -> time_t in ascii */
  893. X    bot = 0;
  894. X    (void) fseek(fp, 0L, 2);
  895. X    top = ftell(fp);
  896. X    for(;;) {
  897. X        mid = (top+bot)/2;
  898. X        (void) fseek(fp, mid, 0);
  899. X        do {
  900. X            c = getc(fp);
  901. X            mid++;
  902. X        } while (c != EOF && c!='\n');
  903. X        if (!getword(fp, datetime, line, linesize)) {
  904. X            return (-1);
  905. X        }
  906. X        switch (compare(key, datetime)) {
  907. X        case -2:
  908. X        case -1:
  909. X        case 0:
  910. X            if (top <= mid)
  911. X                break;
  912. X            top = mid;
  913. X            continue;
  914. X        case 1:
  915. X        case 2:
  916. X            bot = mid;
  917. X            continue;
  918. X        }
  919. X        break;
  920. X    }
  921. X    (void) fseek(fp, bot, 0);
  922. X    while(ftell(fp) < top) {
  923. X        if (!getword(fp, datetime, line, linesize)) {
  924. X            return (-1);
  925. X        }
  926. X        switch(compare(key, datetime)) {
  927. X        case -2:
  928. X        case -1:
  929. X        case 0:
  930. X            break;
  931. X        case 1:
  932. X        case 2:
  933. X            continue;
  934. X        }
  935. X        break;
  936. X    }
  937. X
  938. X    return (0);
  939. X}
  940. X
  941. X
  942. Xcompare(s, t)
  943. X    register char *s, *t;
  944. X{
  945. X    for (; *s == *t; s++, t++)
  946. X        if (*s == 0)
  947. X            return(0);
  948. X    return (*s == 0 ? -1:
  949. X        *t == 0 ? 1:
  950. X        *s < *t ? -2:
  951. X        2);
  952. X}
  953. X
  954. X
  955. X/*
  956. X * C news version of getword.
  957. X */
  958. Xgetword(fp, w, line, linesize)
  959. X    FILE        *fp;
  960. X    register char    *w;
  961. X    char        *line;
  962. X    int        linesize;
  963. X{
  964. X    register char    *cp;
  965. X    extern char *index();
  966. X
  967. X    if (fgets(line, linesize, fp) == NULL)
  968. X        return (0);
  969. X    w[0] = '\0';                /* in case of bad format */
  970. X    if (cp = index(line, '\t')) {        /* find 2nd field */
  971. X        register char *endp;
  972. X
  973. X        *cp++ = '\0';
  974. X        endp = index(cp, '~');        /* end of date-received */
  975. X        if (endp == NULL)
  976. X            endp = index(cp, '\t');    /* end of expiry */
  977. X        if (endp != NULL) {
  978. X            (void) strncpy(w, cp, endp - cp);
  979. X            w[endp - cp] = '\0';
  980. X        }
  981. X    }
  982. X    return (1);
  983. X}
  984. X
  985. X
  986. X/*
  987. X * distmatch -- see if a file matches a set of distributions.
  988. X * We have to do this by (yech!) opening the file, finding
  989. X * the Distribution: line, if it has one, and seeing if the
  990. X * things match.
  991. X *
  992. X *    Parameters:    "distlist" is the distribution list
  993. X *            we want.
  994. X *            "distcount" is the count of distributions in it.
  995. X *            "grouplist" is the list of groups (articles)
  996. X *            for this line of the history file.  Note that
  997. X *            this isn't quite a filename.
  998. X *            "groupcount" is the count of groups in it.
  999. X *            
  1000. X *    Returns:    1 if the article is in the given distribution.
  1001. X *            0 otherwise.
  1002. X */
  1003. X
  1004. Xdistmatch(distlist, distcount, grouplist, groupcount)
  1005. X    char        *distlist[];
  1006. X    int        distcount;
  1007. X    char        *grouplist[];
  1008. X    int        groupcount;
  1009. X{
  1010. X    register char    c;
  1011. X    register char    *cp;
  1012. X    register FILE    *fp;
  1013. X    register int    i, j;
  1014. X    char        buf[MAXBUFLEN];
  1015. X
  1016. X    (void) strcpy(buf, spooldir);
  1017. X    (void) strcat(buf, "/");
  1018. X    (void) strcat(buf, grouplist[0]);
  1019. X
  1020. X    for (cp = buf; *cp; cp++)
  1021. X        if (*cp == '.')
  1022. X            *cp = '/';
  1023. X
  1024. X    fp = fopen(buf, "r");
  1025. X    if (fp == NULL) {
  1026. X#ifdef SYSLOG
  1027. X        syslog(LOG_ERR, "distmatch: fopen %s: %m", buf);
  1028. X#endif
  1029. X        return (0);
  1030. X    }
  1031. X
  1032. X    while (fgets(buf, sizeof (buf), fp) != NULL) {
  1033. X        if ((c = buf[0]) == '\n')        /* End of header */
  1034. X            break;
  1035. X        if (c != 'd' && c != 'D')
  1036. X            continue;
  1037. X        cp = index(cp + 1, '\n');
  1038. X        if (cp)
  1039. X            *cp = '\0';
  1040. X        cp = index(buf, ':');
  1041. X        if (cp == NULL)
  1042. X            continue;
  1043. X        *cp = '\0';
  1044. X        if (!strcasecmp(buf, "distribution")) {
  1045. X            for (i = 0; i < distcount; ++i) {
  1046. X                if (!strcasecmp(cp + 2, distlist[i])) {
  1047. X                    (void) fclose(fp);
  1048. X                    return (1);
  1049. X                }
  1050. X            }
  1051. X            (void) fclose(fp);
  1052. X            return (0);
  1053. X        }
  1054. X    }
  1055. X
  1056. X    (void) fclose(fp);
  1057. X
  1058. X    /*
  1059. X     * We've finished the header with no distribution field.
  1060. X     * So we'll assume that the distribution is the characters
  1061. X     * up to the first dot in the newsgroup name.
  1062. X     */
  1063. X
  1064. X    for (i = 0; i < groupcount; i++) {
  1065. X        cp = index(grouplist[i], '.');
  1066. X        if (cp)
  1067. X            *cp = '\0';
  1068. X        for (j = 0; j < distcount; j++)
  1069. X            if (!strcasecmp(grouplist[i], distlist[j]))
  1070. X                return (1);
  1071. X    }
  1072. X        
  1073. X    return (0);
  1074. X}
  1075. X
  1076. X
  1077. X/*
  1078. X * get_histlist -- return a nicely set up array of newsgroups
  1079. X * (actually, net.foo.bar/article_num) along with a count.
  1080. X *
  1081. X *    Parameters:        "array" is storage for our array,
  1082. X *                set to point at some static data.
  1083. X *                "list" is the history file newsgroup list.
  1084. X *
  1085. X *    Returns:        Number of group specs found.
  1086. X *
  1087. X *    Side effects:        Changes static data area.
  1088. X */
  1089. X
  1090. Xget_histlist(array, list)
  1091. X    char        ***array;
  1092. X    char        *list;
  1093. X{
  1094. X    register int    histcount;
  1095. X    register char    *cp;
  1096. X    static    char    **hist_list = (char **) NULL;
  1097. X
  1098. X    cp = index(list, '\n');
  1099. X    if (cp)
  1100. X        *cp-- = '\0';
  1101. X    histcount = parsit(list, &hist_list);
  1102. X    *array = hist_list;
  1103. X    return (histcount);
  1104. X}
  1105. X
  1106. X
  1107. X/*
  1108. X * get_nglist -- return a nicely set up array of newsgroups
  1109. X * along with a count, when given an NNTP-spec newsgroup list
  1110. X * in the form ng1,ng2,ng...
  1111. X *
  1112. X *    Parameters:        "array" is storage for our array,
  1113. X *                set to point at some static data.
  1114. X *                "list" is the NNTP newsgroup list.
  1115. X *
  1116. X *    Returns:        Number of group specs found.
  1117. X *
  1118. X *    Side effects:        Changes static data area.
  1119. X */
  1120. X
  1121. Xget_nglist(array, list)
  1122. X    char        ***array;
  1123. X    char        *list;
  1124. X{
  1125. X    register char    *cp;
  1126. X    register int    ngcount;
  1127. X
  1128. X    for (cp = list; *cp != '\0'; ++cp)
  1129. X        if (*cp == ',')
  1130. X            *cp = ' ';
  1131. X
  1132. X    ngcount = parsit(list, array);
  1133. X
  1134. X    return (ngcount);
  1135. X}
  1136. !
  1137. echo 'nntpdiffs/src/serve.c':
  1138. sed 's/^X//' >'nntpdiffs/src/serve.c' <<'!'
  1139. X#ifndef lint
  1140. Xstatic char    *sccsid = "@(#)serve.c    1.29    (Berkeley) 2/6/88";
  1141. X#endif
  1142. X
  1143. X/*
  1144. X * Main server routine
  1145. X */
  1146. X
  1147. X#include "common.h"
  1148. X#include <signal.h>
  1149. X#ifdef USG
  1150. X#include <sys/times.h>
  1151. X#else
  1152. X#include <sys/time.h>
  1153. X#endif
  1154. X
  1155. X#ifdef LOG
  1156. X# ifndef USG
  1157. X#  include <sys/resource.h>
  1158. X# endif not USG
  1159. X#endif
  1160. X
  1161. Xextern    int    ahbs(), group(), help(), ihave();
  1162. Xextern    int    list(), newgroups(), newnews(), nextlast(), post();
  1163. Xextern    int    slave(), stat(), xhdr();
  1164. X
  1165. Xstatic struct cmdent {
  1166. X    char    *cmd_name;
  1167. X    int    (*cmd_fctn)();
  1168. X} cmdtbl[] = {
  1169. X    "article",    ahbs,
  1170. X    "body",        ahbs,
  1171. X    "group",    group,
  1172. X    "head",        ahbs,
  1173. X    "help",        help,
  1174. X    "ihave",    ihave,
  1175. X    "last",        nextlast,
  1176. X    "list",        list,
  1177. X    "newgroups",    newgroups,
  1178. X    "newnews",    newnews,
  1179. X    "next",        nextlast,
  1180. X    "post",        post,
  1181. X    "slave",    slave,
  1182. X    "stat",        ahbs,
  1183. X#ifdef XHDR
  1184. X    "xhdr",        xhdr,
  1185. X#endif XHDR
  1186. X};
  1187. X#define NUMCMDS (sizeof(cmdtbl) / sizeof(struct cmdent))
  1188. X
  1189. X
  1190. X/*
  1191. X * serve -- given a connection on stdin/stdout, serve
  1192. X *    a client, executing commands until the client
  1193. X *    says goodbye.
  1194. X *
  1195. X *    Parameters:    None.
  1196. X *
  1197. X *    Returns:    Exits.
  1198. X *
  1199. X *    Side effects:    Talks to client, does a lot of
  1200. X *            stuff.
  1201. X */
  1202. X
  1203. Xserve()
  1204. X{
  1205. X    char        line[NNTP_STRLEN];
  1206. X    char        host[MAXHOSTNAMELEN];
  1207. X    char        gdbuf[MAXBUFLEN];
  1208. X    char        **argp;
  1209. X    char        *timeptr, *cp;
  1210. X    int        argnum, i;
  1211. X    double        Tstart, Tfinish;
  1212. X    double        user, sys;
  1213. X#ifdef USG
  1214. X    time_t        start, finish;
  1215. X#else not USG
  1216. X    struct timeval    start, finish;
  1217. X#endif not USG
  1218. X    extern char    *ctime();
  1219. X#ifdef POSTER
  1220. X    struct passwd    *pp;
  1221. X#endif
  1222. X#ifdef LOG
  1223. X# ifdef USG
  1224. X    struct tms    cpu;
  1225. X# else not USG
  1226. X    struct rusage    me, kids;
  1227. X# endif not USG
  1228. X# ifdef TIMEOUT
  1229. X    void        timeout();
  1230. X# endif
  1231. X    
  1232. X    grps_acsd = arts_acsd = 0;
  1233. X#endif
  1234. X
  1235. X    /* Not all systems pass fd's 1 and 2 from inetd */
  1236. X
  1237. X    (void) close(1);
  1238. X    (void) close(2);
  1239. X    (void) dup(0);
  1240. X    (void) dup(0);
  1241. X
  1242. X    /* If we're ALONE, then we've already opened syslog */
  1243. X
  1244. X#ifndef ALONE
  1245. X# ifdef SYSLOG
  1246. X#  ifdef BSD_42
  1247. X    openlog("nntpd", LOG_PID);
  1248. X#  else
  1249. X    openlog("nntpd", LOG_PID, SYSLOG);
  1250. X#  endif
  1251. X# endif
  1252. X#endif
  1253. X
  1254. X#ifdef ALONE
  1255. X#ifndef USG
  1256. X    (void) signal(SIGCHLD, SIG_IGN);
  1257. X#endif not USG
  1258. X#endif
  1259. X
  1260. X    /* Ignore SIGPIPE, since we'll see closed connections with read */
  1261. X
  1262. X    (void) signal(SIGPIPE, SIG_IGN);
  1263. X
  1264. X    /* Get permissions and see if we can talk to this client */
  1265. X
  1266. X    host_access(&canread, &canpost, &canxfer, gdbuf);
  1267. X
  1268. X    if (gethostname(host, sizeof(host)) < 0)
  1269. X        (void) strcpy(host, "Amnesiac");
  1270. X
  1271. X    if (!canread && !canxfer) {
  1272. X        printf("%d %s NNTP server can't talk to you.  Goodbye.\r\n",
  1273. X            ERR_ACCESS, host);
  1274. X        (void) fflush(stdout);
  1275. X#ifdef LOG
  1276. X        syslog(LOG_INFO, "%s refused connection", hostname);
  1277. X#endif
  1278. X        exit(1);
  1279. X    }
  1280. X
  1281. X    /* If we can talk, proceed with initialization */
  1282. X
  1283. X    ngpermcount = get_nglist(&ngpermlist, gdbuf);
  1284. X
  1285. X#ifdef POSTER
  1286. X    pp = getpwnam(POSTER);
  1287. X    if (pp != NULL) {
  1288. X        uid_poster = pp->pw_uid;
  1289. X        gid_poster = pp->pw_gid;
  1290. X    } else
  1291. X#endif
  1292. X        uid_poster = gid_poster = 0;
  1293. X
  1294. X#ifndef FASTFORK
  1295. X    num_groups = 0;
  1296. X    num_groups = read_groups();    /* Read in the active file */
  1297. X#else
  1298. X    signal(SIGALRM, SIG_IGN);    /* Children don't deal with */
  1299. X                    /* these things */
  1300. X#endif
  1301. X
  1302. X    art_fp = NULL;
  1303. X    argp = (char **) NULL;        /* for first time */
  1304. X
  1305. X#ifdef USG
  1306. X    (void) time(&start);
  1307. X    Tstart = (double) start;
  1308. X    timeptr = ctime(&start);
  1309. X#else not USG
  1310. X    (void) gettimeofday(&start, (struct timezone *)NULL);
  1311. X    Tstart = (double) start.tv_sec - ((double)start.tv_usec)/1000000.0;
  1312. X    timeptr = ctime(&start.tv_sec);
  1313. X#endif not USG
  1314. X    if ((cp = index(timeptr, '\n')) != NULL)
  1315. X        *cp = '\0';
  1316. X    else
  1317. X        timeptr = "Unknown date";
  1318. X
  1319. X    printf("%d %s NNTP server version %s ready at %s (%s).\r\n",
  1320. X        canpost ? OK_CANPOST : OK_NOPOST,
  1321. X        host, nntp_version,
  1322. X        timeptr,
  1323. X        canpost ? "posting ok" : "no posting");
  1324. X    (void) fflush(stdout);
  1325. X
  1326. X    /*
  1327. X     * Now get commands one at a time and execute the
  1328. X     * appropriate routine to deal with them.
  1329. X     */
  1330. X
  1331. X#ifdef TIMEOUT
  1332. X    (void) signal(SIGALRM, timeout);
  1333. X    (void) alarm(TIMEOUT);
  1334. X#endif TIMEOUT
  1335. X
  1336. X    while (fgets(line, sizeof(line), stdin) != NULL) {
  1337. X#ifdef TIMEOUT
  1338. X        (void) alarm(0);
  1339. X#endif TIMEOUT
  1340. X
  1341. X        cp = index(line, '\r');        /* Zap CR-LF */
  1342. X        if (cp != NULL)
  1343. X            *cp = '\0';
  1344. X        else {
  1345. X            cp = index(line, '\n');
  1346. X            if (cp != NULL)
  1347. X                *cp = '\0';
  1348. X        }
  1349. X
  1350. X        if ((argnum = parsit(line, &argp)) == 0)
  1351. X            continue;        /* Null command */
  1352. X        else {
  1353. X            for (i = 0; i < NUMCMDS; ++i)
  1354. X                if (!strcasecmp(cmdtbl[i].cmd_name, argp[0]))
  1355. X                    break;
  1356. X            if (i < NUMCMDS)
  1357. X                (*cmdtbl[i].cmd_fctn)(argnum, argp);
  1358. X            else {
  1359. X                if (!strcasecmp(argp[0], "quit"))
  1360. X                    break;
  1361. X#ifdef LOG
  1362. X                syslog(LOG_INFO, "%s unrecognized %s",
  1363. X                    hostname,
  1364. X                    line);
  1365. X#endif
  1366. X                printf("%d Command unrecognized.\r\n",
  1367. X                    ERR_COMMAND);
  1368. X                (void) fflush(stdout);
  1369. X            }
  1370. X        }
  1371. X#ifdef TIMEOUT
  1372. X        (void) alarm(TIMEOUT);
  1373. X#endif TIMEOUT
  1374. X    }
  1375. X
  1376. X    printf("%d %s closing connection.  Goodbye.\r\n", OK_GOODBYE, host);
  1377. X    (void) fflush(stdout);
  1378. X#ifndef UNBATCHED_INPUT
  1379. X    {
  1380. X        char errbuf[2 * NNTP_STRLEN];
  1381. X
  1382. X        enqpartbatch(CONT_XFER, ERR_XFERFAIL, errbuf);
  1383. X    }
  1384. X#endif
  1385. X
  1386. X
  1387. X#ifdef LOG
  1388. X    if (ferror(stdout))
  1389. X        syslog(LOG_ERR, "%s disconnect: %m", hostname);
  1390. X
  1391. X#ifdef USG
  1392. X    (void) time(&finish);
  1393. X    Tfinish = (double) finish;
  1394. X
  1395. X#ifndef HZ
  1396. X#define    HZ    60.0    /* typical system clock ticks - param.h */
  1397. X#endif not HZ
  1398. X
  1399. X    (void) times(&cpu);
  1400. X    user = (double)(cpu.tms_utime + cpu.tms_cutime) / HZ;
  1401. X    sys  = (double)(cpu.tms_stime + cpu.tms_cstime) / HZ;
  1402. X#else not USG
  1403. X    (void) gettimeofday(&finish, (struct timezone *)NULL);
  1404. X    Tfinish = (double) finish.tv_sec - ((double)finish.tv_usec)/1000000.0;
  1405. X
  1406. X    (void) getrusage(RUSAGE_SELF, &me);
  1407. X    (void) getrusage(RUSAGE_CHILDREN, &kids);
  1408. X
  1409. X    user = (double) me.ru_utime.tv_sec + me.ru_utime.tv_usec/1000000.0 +
  1410. X        kids.ru_utime.tv_sec + kids.ru_utime.tv_usec/1000000.0;
  1411. X    sys = (double) me.ru_stime.tv_sec + me.ru_stime.tv_usec/1000000.0 +
  1412. X        kids.ru_stime.tv_sec + kids.ru_stime.tv_usec/1000000.0;
  1413. X#endif not USG
  1414. X    if (grps_acsd)
  1415. X        syslog(LOG_INFO, "%s exit %d articles %d groups",
  1416. X            hostname, arts_acsd, grps_acsd);
  1417. X    if (nn_told)
  1418. X        syslog(LOG_INFO, "%s newnews_stats told %d took %d",
  1419. X            hostname, nn_told, nn_took);
  1420. X    if (ih_accepted || ih_rejected || ih_failed)
  1421. X        syslog(LOG_INFO,
  1422. X            "%s ihave_stats accepted %d rejected %d failed %d",
  1423. X            hostname,
  1424. X            ih_accepted,
  1425. X            ih_rejected,
  1426. X            ih_failed);
  1427. X    (void) sprintf(line, "user %.1f system %.1f elapsed %.1f",
  1428. X        user, sys, Tfinish - Tstart);
  1429. X    syslog(LOG_INFO, "%s times %s", hostname, line);
  1430. X#endif LOG
  1431. X
  1432. X#ifdef PROFILE
  1433. X    profile();
  1434. X#endif
  1435. X    exit(0);
  1436. X}
  1437. X
  1438. X
  1439. X#ifdef TIMEOUT
  1440. X/*
  1441. X * No activity for TIMEOUT seconds, so print an error message
  1442. X * and close the connection.
  1443. X */
  1444. X
  1445. Xvoid
  1446. Xtimeout()
  1447. X{
  1448. X    printf("%d Timeout after %d seconds, closing connection.\r\n",
  1449. X        ERR_FAULT, TIMEOUT);
  1450. X    (void) fflush(stdout);
  1451. X
  1452. X#ifdef LOG
  1453. X    syslog(LOG_ERR, "%s timeout", hostname);
  1454. X#endif LOG
  1455. X
  1456. X    exit(1);
  1457. X}
  1458. X#endif TIMEOUT
  1459. !
  1460. echo 'nntpdiffs/src.allnew/batch.c':
  1461. sed 's/^X//' >'nntpdiffs/src.allnew/batch.c' <<'!'
  1462. X/*
  1463. X * rnews - setuid-news fake rnews for nntp: appends article to a batch with
  1464. X *    a fixed name under in.coming.  if batch is too big or old, rename
  1465. X *    batch to be an input candidate and kick off a newsrun to process
  1466. X *    the batch.  the batch file is locked during appending.
  1467. X * Cooperates with C news input subsystem.
  1468. X *    newsboot must be told to run partial batches left at a crash.
  1469. X */
  1470. X#include "../common/conf.h"
  1471. X#include "common.h"
  1472. X#include <signal.h>
  1473. X
  1474. X#define TOOBIG 300000L        /* batch > TOOBIG bytes, kick rnews */
  1475. X#define TOOOLD (5*60)        /* batch > TOOOLD seconds old, kick rnews */
  1476. X#define COPYSIZE 8192        /* bytes to copy at one time */
  1477. X#define MAXDIGITS 25        /* lg(maxlongint) + epsilon */
  1478. X#define MAXSTR 1024
  1479. X
  1480. X#define INDIR        artfile("in.coming")
  1481. X#define BATCHFILE    artfile("in.coming/nntp.XXXXXX")
  1482. X#define NEWSRUN        binfile("input/newsrun")
  1483. X
  1484. X#define YES 1
  1485. X#define NO 0
  1486. X
  1487. X/* imports */
  1488. Xextern time_t time();
  1489. Xextern char *malloc(), *mktemp(), *index(), *rindex();
  1490. X
  1491. X/* forwards */
  1492. Xstatic char *artfile(), *binfile(), *strsave();
  1493. Xstatic void error(), warning();
  1494. Xstatic int xfer_timeout();
  1495. X
  1496. X/* private data */
  1497. Xstatic char tempfile[256];
  1498. Xstatic int xfer_lines, old_xfer_lines;
  1499. X
  1500. Xstatic char art[COPYSIZE];        /* entire article, if it fits */
  1501. Xstatic char *endart = art;        /* points just past end of article */
  1502. Xstatic int incore = YES;
  1503. X
  1504. Xstatic struct batch_file {
  1505. X    char *name;
  1506. X    FILE *file;
  1507. X    char isopen;
  1508. X    time_t start;            /* time of creation */
  1509. X    off_t size;            /* current size */
  1510. X} btch = { NULL, NULL, NO, 0, 0 };
  1511. X
  1512. Xchar *progname = "nntpd";
  1513. X
  1514. X#ifndef lint
  1515. Xstatic    char    *sccsid = "@(#)batch.c    1.5    (Toronto) 31/4/89";
  1516. X#endif
  1517. X
  1518. X/*
  1519. X * stash stdin (up to ".") on the end of the batch input file.
  1520. X * kick newsrun if the batch is non-empty and too big or too old.
  1521. X *
  1522. X * Parameters:
  1523. X *    "cont_code" is the response code to transmit on successful startup.
  1524. X *    "err_code" is the response code to transmit when something goes wrong.
  1525. X *
  1526. X * Returns: -1 on non-zero return from child, 0 on error before fork/exec, 1 else.
  1527. X * Side effects: Creates and removes temporary file; accepts input from client.
  1528. X *        Can time out if XFER_TIMEOUT is defined.
  1529. X */
  1530. Xint
  1531. Xbatch_input_article(cont_code, err_code, errbuf)
  1532. Xint cont_code, err_code;
  1533. Xchar *errbuf;
  1534. X{
  1535. X    int status = 1;            /* okay status */
  1536. X
  1537. X    /* protect locking */
  1538. X    signal(SIGINT, SIG_IGN);
  1539. X    signal(SIGQUIT, SIG_IGN);
  1540. X    signal(SIGHUP, SIG_IGN);
  1541. X
  1542. X    if (btch.name == NULL) {
  1543. X        /* BATCHFILE may trigger unprivileged() */
  1544. X        btch.name = mktemp(strsave(BATCHFILE));
  1545. X    }
  1546. X    if (btch.name == NULL)
  1547. X        return 0;
  1548. X#ifdef notdef
  1549. X    (void) setgid(getegid());
  1550. X    (void) setuid(geteuid());
  1551. X#endif
  1552. X    tempfile[0] = '\0';
  1553. X    if (!cpstdin(cont_code, err_code, errbuf))    /* may create tempfile */
  1554. X        return 0;
  1555. X#ifdef POSTER
  1556. X    (void) chown(tempfile, uid_poster, gid_poster);
  1557. X#endif
  1558. X    status = appbatch();
  1559. X    if (tempfile[0] != '\0')
  1560. X        (void) unlink(tempfile);
  1561. X    if (status == 1 && oktorunbatch())
  1562. X        status = enqueue(cont_code, err_code, errbuf);
  1563. X    return status;
  1564. X}
  1565. X
  1566. Xint                        /* boolean */
  1567. Xoktorunbatch()
  1568. X{
  1569. X    struct stat stbuf;
  1570. X
  1571. X    if (!btch.isopen || fstat(fileno(btch.file), &stbuf) < 0)
  1572. X        return NO;
  1573. X    btch.size = stbuf.st_size;
  1574. X    return btch.size > TOOBIG ||
  1575. X        btch.size > 0 && time((time_t *)NULL) - btch.start > TOOOLD;
  1576. X}
  1577. X
  1578. X/*
  1579. X * Copy standard input (up to a "." line) to art, if it fits,
  1580. X * else to a temporary file.
  1581. X */
  1582. X/* ARGSUSED errbuf */
  1583. Xstatic int                    /* boolean: got article ok? */
  1584. Xcpstdin(cont_code, err_code, errbuf)
  1585. Xint cont_code, err_code;
  1586. Xchar *errbuf;
  1587. X{
  1588. X    register FILE *tfp = NULL;
  1589. X    register char *cp, *realline;
  1590. X    char line[NNTP_STRLEN];
  1591. X    int toobig = NO;
  1592. X    int (*otimeout)();
  1593. X
  1594. X    /* TODO: is this right?  used to open here, with errors here */
  1595. X    printf("%d Ok\r\n", cont_code);
  1596. X    (void) fflush(stdout);
  1597. X
  1598. X    xfer_lines = old_xfer_lines = 0;
  1599. X    incore = YES;
  1600. X    art[0] = '\0';
  1601. X    endart = art;
  1602. X#ifdef XFER_TIMEOUT
  1603. X    otimeout = signal(SIGALRM, xfer_timeout);
  1604. X    (void) alarm(XFER_TIMEOUT);
  1605. X#endif
  1606. X    while (fgets(line, sizeof line, stdin) != NULL) {
  1607. X        xfer_lines++;
  1608. X        if ((cp = rindex(line, '\r')) != NULL ||
  1609. X            (cp = rindex(line, '\n')) != NULL)
  1610. X            *cp = '\0';            /* nuke CRLF */
  1611. X        if (line[0] == '.' && line[1] == '\0')
  1612. X            break;                /* article end: exit */
  1613. X        /* remove hidden dot if present */
  1614. X        realline = (line[0] == '.'? line+1: line);
  1615. X        if (toobig) {                /* straight to disk */
  1616. X            (void) fputs(realline, tfp);
  1617. X            (void) putc('\n', tfp);
  1618. X        } else {
  1619. X            int len = strlen(realline);
  1620. X
  1621. X            /*
  1622. X             * Does art have room to append realline + \n\0?
  1623. X             * If not, open temp file and dump art & realline there.
  1624. X             */
  1625. X            if (sizeof art - (endart - art) < len + 1 + 1) {
  1626. X                (void) strcpy(tempfile, "/tmp/rpostXXXXXX");
  1627. X                (void) mktemp(tempfile);
  1628. X                tfp = fopen(tempfile, "w");
  1629. X                if (tfp == NULL) {
  1630. X                    printf("%d Cannot create temporary file.\r\n",
  1631. X                        err_code);
  1632. X                    (void) fflush(stdout);
  1633. X                    return 0;
  1634. X                }
  1635. X#ifdef OK_IN_MIDDLE_OKAY
  1636. X                else {
  1637. X                    printf("%d Ok\r\n", cont_code);
  1638. X                    (void) fflush(stdout);
  1639. X                }
  1640. X#endif
  1641. X                (void) fwrite(art, 1, endart - art, tfp);
  1642. X                toobig = YES;
  1643. X                incore = NO;
  1644. X                art[0] = '\0';
  1645. X                endart = art;
  1646. X                (void) fputs(realline, tfp);
  1647. X                (void) putc('\n', tfp);
  1648. X            } else {
  1649. X                /* fits: append realline\n to art at endart */
  1650. X                (void) strcpy(endart, realline);
  1651. X                endart += len;
  1652. X                *endart++ = '\n';
  1653. X                *endart = '\0';
  1654. X            }
  1655. X        }
  1656. X    }
  1657. X    if (tfp != NULL)
  1658. X        (void) fclose(tfp);
  1659. X#ifdef XFER_TIMEOUT
  1660. X    (void) alarm(0);
  1661. X    (void) signal(SIGALRM, otimeout);
  1662. X#endif
  1663. X
  1664. X    /* See if the connection got closed somehow... */
  1665. X    if (line[0] != '.' && line[1] != '\0') {
  1666. X        if (tempfile[0] != '\0')
  1667. X            (void) unlink(tempfile);
  1668. X#ifdef LOG
  1669. X        syslog(LOG_ERR, "%s spawn: EOF before period on line by itself",
  1670. X            hostname);
  1671. X#else
  1672. X        syslog(LOG_ERR, "spawn: EOF before period on line by itself");
  1673. X#endif
  1674. X        return 0;
  1675. X    }
  1676. X    return 1;
  1677. X}
  1678. X
  1679. Xstatic int
  1680. Xxfer_timeout()
  1681. X{
  1682. X#ifdef XFER_TIMEOUT
  1683. X    if (old_xfer_lines < xfer_lines) {
  1684. X        old_xfer_lines = xfer_lines;
  1685. X        (void) alarm(XFER_TIMEOUT);
  1686. X        return;
  1687. X    }
  1688. X    /* Timed out. */
  1689. X    printf("%d timeout after %d seconds, closing connection.\r\n",
  1690. X        ERR_FAULT, XFER_TIMEOUT);
  1691. X    fflush(stdout);
  1692. X#ifdef LOG
  1693. X    syslog(LOG_ERR, "%s transfer_timeout", hostname);
  1694. X#endif LOG
  1695. X    (void) unlink(tempfile);
  1696. X    exit(1);
  1697. X#endif XFER_TIMEOUT
  1698. X}
  1699. X
  1700. X/*
  1701. X * Append "#! rnews count" and art (or tempfile) to batch file, locking assumed.
  1702. X * If batch file is too big or too old (but not empty), feed it to newsrun.
  1703. X */
  1704. Xstatic int                    /* same as batch_input_article */
  1705. Xappbatch()
  1706. X{
  1707. X    register FILE *tfp = NULL;
  1708. X    register int bytes = 0;
  1709. X    int status = 1;                /* okay status */
  1710. X    long size = 0;
  1711. X    char artbuf[COPYSIZE];
  1712. X    struct stat stbuf;
  1713. X
  1714. X    if (btch.file == NULL) {
  1715. X        btch.file = fopen(btch.name, "a");
  1716. X        if (btch.file == NULL)
  1717. X            return 0;
  1718. X        btch.isopen = YES;
  1719. X        btch.size = 0;
  1720. X        btch.start = time(&btch.start);
  1721. X    }
  1722. X
  1723. X    /* find article size and write the article */
  1724. X    if (incore)
  1725. X        size = endart - art;
  1726. X    else {
  1727. X        tfp = fopen(tempfile, "r");
  1728. X        if (tfp == NULL)
  1729. X            return 0;
  1730. X        if (fstat(fileno(tfp), &stbuf) >= 0)
  1731. X            size = stbuf.st_size;
  1732. X    }
  1733. X    (void) fprintf(btch.file, "#! rnews %ld\n", size);
  1734. X
  1735. X    /* copy the article to the batch file */
  1736. X    if (incore)
  1737. X        (void) fwrite(art, 1, endart - art, btch.file);
  1738. X    else {
  1739. X        while ((bytes = fread(artbuf, 1, sizeof artbuf, tfp)) > 0)
  1740. X            if (fwrite(artbuf, 1, bytes, btch.file) != bytes) {
  1741. X                warning("can't write %s", btch.name);
  1742. X                status = 0;    /* hmm, #! count is off */
  1743. X                break;
  1744. X            }
  1745. X        (void) fclose(tfp);
  1746. X    }
  1747. X    if (fflush(btch.file) == EOF) {
  1748. X        warning("can't write %s", btch.name);
  1749. X        status = 0;
  1750. X    }
  1751. X    return status;
  1752. X}
  1753. X
  1754. X/*
  1755. X * Enqueue any partial batch.  Called before exit.
  1756. X */
  1757. Xenqpartbatch(cont_code, err_code, errbuf)
  1758. Xint cont_code, err_code;
  1759. Xchar *errbuf;
  1760. X{
  1761. X    struct stat stbuf;
  1762. X
  1763. X    if (btch.isopen && fstat(fileno(btch.file), &stbuf) >= 0) {
  1764. X        if (btch.size > 0)
  1765. X            enqueue(cont_code, err_code, errbuf);
  1766. X        else {
  1767. X            (void) fclose(btch.file);
  1768. X            btch.file = NULL;
  1769. X            btch.isopen = NO;
  1770. X            (void) unlink(btch.name);    /* remove empty batch */
  1771. X        }
  1772. X    }
  1773. X}
  1774. X
  1775. X/* 
  1776. X * insert the batch file into the input subsystem queue by renaming
  1777. X * it to an all-numeric name, then kick newsrun to process it.
  1778. X * locks btch.name as appropriate.
  1779. X */
  1780. Xstatic int                    /* same as batch_input_article */
  1781. Xenqueue(cont_code, err_code, errbuf)
  1782. Xint cont_code, err_code;
  1783. Xchar *errbuf;
  1784. X{
  1785. X    time_t now;
  1786. X    int pid, wpid, status, fd, exitstat;
  1787. X    char permname[MAXDIGITS], *number = permname, *newsrun;
  1788. X    struct stat stbuf;
  1789. X
  1790. X    (void) fclose(btch.file);
  1791. X    btch.file = NULL;
  1792. X    btch.isopen = NO;
  1793. X    btch.start = 0;
  1794. X    btch.size = 0;
  1795. X
  1796. X    (void) fflush(stdout);
  1797. X    (void) fflush(stderr);
  1798. X    pid = fork();
  1799. X    if (pid == -1) {
  1800. X        warning("can't fork", "");
  1801. X        return 0;
  1802. X    } else if (pid != 0) {            /* parent */
  1803. X        while ((wpid = wait(&status)) != -1 && wpid != pid)
  1804. X            ;
  1805. X        exitstat = (status>>8)&0377;
  1806. X        if (exitstat != 0) {
  1807. X            syslog(LOG_ERR, "%s: enqueue returned exit status 0%o",
  1808. X                progname, exitstat);
  1809. X            strcpy(errbuf, "enqueue failed to run newsrun\n");
  1810. X        }
  1811. X        return exitstat != 0? -1 :1;
  1812. X    }
  1813. X
  1814. X    /* child: must exit */
  1815. X    for (fd = 3; fd < 20; fd++)
  1816. X        (void) close(fd);
  1817. X    if (chdir(INDIR) < 0) {
  1818. X        syslog(LOG_ERR, "%s: chdir(%s) failed", progname, INDIR);
  1819. X        nerror("can't change directory to %s", INDIR);
  1820. X    }
  1821. X
  1822. X    /* rename btch.name to a number so newsrun will see it */
  1823. X    sprintf(number, "%ld", (long)time(&now));
  1824. X    while (link(btch.name, permname) < 0) {
  1825. X        if (stat(btch.name, &stbuf) < 0)
  1826. X            break;
  1827. X        sleep(2);
  1828. X        sprintf(number, "%ld", (long)time(&now));
  1829. X    }
  1830. X    if (unlink(btch.name) < 0)
  1831. X        vanished(btch.name);
  1832. X
  1833. X    signal(SIGINT, SIG_IGN);
  1834. X    signal(SIGQUIT, SIG_IGN);
  1835. X    signal(SIGHUP, SIG_IGN);
  1836. X    (void) fflush(stdout);
  1837. X    (void) fflush(stderr);
  1838. X    newsrun = strsave(NEWSRUN);
  1839. X    if (newsrun == NULL)
  1840. X        newsrun = "/usr/lib/newsbin/input/newsrun";
  1841. X    execl(newsrun, newsrun, (char *)NULL);
  1842. X    syslog(LOG_ERR, "%s: can't run %s", progname, newsrun);
  1843. X    error("attempt to run %s failed!", newsrun);
  1844. X    exit(1);
  1845. X    /* NOTREACHED */
  1846. X}
  1847. X
  1848. Xvanished(s)                    /* grieve for s, nerror [exit] */
  1849. Xchar *s;
  1850. X{
  1851. X    syslog(LOG_ERR, "%s: %s vanished underfoot!", progname, s);
  1852. X    nerror("%s vanished underfoot!", s);    /* unlocks, exits */
  1853. X}
  1854. X
  1855. Xstatic
  1856. Xnerror(fmt, s)                /* error, unused to be with unlock */
  1857. Xchar *fmt, *s;
  1858. X{
  1859. X    error(fmt, s);
  1860. X}
  1861. X
  1862. X/* C news library starts here */
  1863. X
  1864. X/*
  1865. X * error - print best error message possible and exit
  1866. X */
  1867. Xstatic void warning();
  1868. X
  1869. Xstatic void
  1870. Xerror(s1, s2)
  1871. Xchar *s1;
  1872. Xchar *s2;
  1873. X{
  1874. X    warning(s1, s2);
  1875. X    exit(1);
  1876. X}
  1877. X
  1878. X/*
  1879. X * warning - print best error message possible and clear errno
  1880. X */
  1881. Xextern int errno, sys_nerr;
  1882. Xextern char *sys_errlist[];
  1883. Xextern char *progname;
  1884. Xextern char *getenv();
  1885. X
  1886. Xstatic void
  1887. Xwarning(s1, s2)
  1888. Xchar *s1;
  1889. Xchar *s2;
  1890. X{
  1891. X    char *cmdname;
  1892. X
  1893. X    (void) fflush(stdout);                /* hack */
  1894. X    cmdname = getenv("CMDNAME");
  1895. X    if (cmdname != NULL && *cmdname != '\0')
  1896. X        fprintf(stderr, "%s:", cmdname);    /* No space after :. */
  1897. X    if (progname != NULL)
  1898. X        fprintf(stderr, "%s: ", progname);
  1899. X    fprintf(stderr, s1, s2);
  1900. X    if (errno > 0 && errno < sys_nerr)
  1901. X        fprintf(stderr, " (%s)", sys_errlist[errno]);
  1902. X    fprintf(stderr, "\n");
  1903. X    errno = 0;
  1904. X}
  1905. X
  1906. Xvoid
  1907. Xunprivileged()
  1908. X{
  1909. X    (void) setgid(getgid());
  1910. X    (void) setuid(getuid());
  1911. X}
  1912. X
  1913. Xstatic char *
  1914. Xartfile(s)
  1915. Xchar *s;
  1916. X{
  1917. X    static char name[MAXSTR];
  1918. X
  1919. X    strcpy(name, "/usr/spool/news/");
  1920. X    strcat(name, s);
  1921. X    return name;
  1922. X}
  1923. X
  1924. Xstatic char *
  1925. Xbinfile(s)
  1926. Xchar *s;
  1927. X{
  1928. X    static char name[MAXSTR];
  1929. X
  1930. X    strcpy(name, "/usr/lib/newsbin/");
  1931. X    strcat(name, s);
  1932. X    return name;
  1933. X}
  1934. X
  1935. X#ifdef notdef
  1936. Xstatic char *
  1937. Xctlfile(s)
  1938. Xchar *s;
  1939. X{
  1940. X    static char name[MAXSTR];
  1941. X
  1942. X    strcpy(name, "/usr/lib/news/");
  1943. X    strcat(name, s);
  1944. X    return name;
  1945. X}
  1946. X#endif
  1947. X
  1948. Xstatic char *
  1949. Xstrsave(s)
  1950. Xregister char *s;
  1951. X{
  1952. X    register char *news = malloc((unsigned)(strlen(s) + 1));
  1953. X
  1954. X    if (news != NULL)
  1955. X        strcpy(news, s);
  1956. X    return news;
  1957. X}
  1958. X
  1959. X#ifndef SYSLOG
  1960. X/* VARARGS 2 */
  1961. Xstatic
  1962. Xsyslog(level, fmt)
  1963. Xint level;
  1964. Xchar *fmt;
  1965. X{
  1966. X}
  1967. X#endif
  1968. X
  1969. !
  1970. echo 'nntpdiffs/cdiff.1.5.0':
  1971. sed 's/^X//' >'nntpdiffs/cdiff.1.5.0' <<'!'
  1972. XCommon subdirectories: ../nntp.1.5.0/common and ./common
  1973. XCommon subdirectories: ../nntp.1.5.0/doc and ./doc
  1974. XCommon subdirectories: ../nntp.1.5.0/inews and ./inews
  1975. XOnly in .: nntp.1.5.C.diff
  1976. XCommon subdirectories: ../nntp.1.5.0/rrnpatches and ./rrnpatches
  1977. XCommon subdirectories: ../nntp.1.5.0/server and ./server
  1978. XCommon subdirectories: ../nntp.1.5.0/support and ./support
  1979. XCommon subdirectories: ../nntp.1.5.0/xfer and ./xfer
  1980. XCommon subdirectories: ../nntp.1.5.0/xmit and ./xmit
  1981. Xdiff -r -c ../nntp.1.5.0/server/Makefile ./server/Makefile
  1982. X*** ../nntp.1.5.0/server/Makefile    Fri Feb 26 02:47:58 1988
  1983. X--- ./server/Makefile    Tue Jun  6 23:15:49 1989
  1984. X***************
  1985. X*** 3,8 ****
  1986. X--- 3,9 ----
  1987. X  #
  1988. X  
  1989. X  SRVROBJ = main.o serve.o access.o access_inet.o access_dnet.o active.o \
  1990. X+     batch.o \
  1991. X      ahbs.o globals.o group.o help.o ihave.o list.o misc.o netaux.o \
  1992. X      newgroups.o newnews.o nextlast.o ngmatch.o post.o parsit.o scandir.o \
  1993. X      slave.o spawn.o strcasecmp.o subnet.o time.o xhdr.o fakesyslog.o \
  1994. X***************
  1995. X*** 9,14 ****
  1996. X--- 10,16 ----
  1997. X      ../common/version.o
  1998. X  
  1999. X  SRVRSRC = main.c serve.c access.c access_inet.c access_dnet.c active.c \
  2000. X+     batch.c \
  2001. X      ahbs.c globals.c group.c help.c ihave.c list.c misc.c netaux.c \
  2002. X      newgroups.c newnews.c nextlast.c ngmatch.c post.c parsit.c scandir.c \
  2003. X      slave.c spawn.c strcasecmp.c subnet.c time.c xhdr.c fakesyslog.c \
  2004. X***************
  2005. X*** 19,25 ****
  2006. X  SRCS    = ${SRVRSRC}
  2007. X  
  2008. X  # -ldbm here if you've #define'ed DBM in ../common/conf.h
  2009. X! LIBS    =
  2010. X  
  2011. X  CFLAGS    = -O
  2012. X  
  2013. X--- 21,27 ----
  2014. X  SRCS    = ${SRVRSRC}
  2015. X  
  2016. X  # -ldbm here if you've #define'ed DBM in ../common/conf.h
  2017. X! LIBS    = -ldbm
  2018. X  
  2019. X  CFLAGS    = -O
  2020. X  
  2021. XOnly in ./server: batch.c
  2022. Xdiff -r -c ../nntp.1.5.0/server/ihave.c ./server/ihave.c
  2023. X*** ../nntp.1.5.0/server/ihave.c    Tue Jan 12 02:53:11 1988
  2024. X--- ./server/ihave.c    Tue Jun  6 23:15:52 1989
  2025. X***************
  2026. X*** 43,49 ****
  2027. X          return;
  2028. X      }
  2029. X          
  2030. X!     retcode = spawn(rnews, "rnews", (char *) 0, CONT_XFER, ERR_XFERFAIL, errbuf);
  2031. X      if (retcode <= 0)
  2032. X          printf("%d %s\r\n", ERR_XFERFAIL, errbuf);
  2033. X      else if (retcode > 0)
  2034. X--- 43,55 ----
  2035. X          return;
  2036. X      }
  2037. X          
  2038. X! #ifdef UNBATCHED_INPUT
  2039. X!     retcode = spawn(rnews, "rnews", (char *) 0, CONT_XFER,
  2040. X!         ERR_XFERFAIL, errbuf);
  2041. X! #else
  2042. X!     /* C news input hook */
  2043. X!     retcode = batch_input_article(CONT_XFER, ERR_XFERFAIL, errbuf);
  2044. X! #endif
  2045. X      if (retcode <= 0)
  2046. X          printf("%d %s\r\n", ERR_XFERFAIL, errbuf);
  2047. X      else if (retcode > 0)
  2048. Xdiff -r -c ../nntp.1.5.0/server/misc.c ./server/misc.c
  2049. X*** ../nntp.1.5.0/server/misc.c    Sun Feb  7 01:29:33 1988
  2050. X--- ./server/misc.c    Tue Jun  6 23:15:54 1989
  2051. X***************
  2052. X*** 82,88 ****
  2053. X   *
  2054. X   *    Side effects:    opens dbm database
  2055. X   *            (only once, keeps it open after that).
  2056. X-  *            Converts "msg_id" to lower case.
  2057. X   */
  2058. X  
  2059. X  #ifndef NDBM
  2060. X--- 82,87 ----
  2061. X***************
  2062. X*** 115,124 ****
  2063. X      datum         key, content;
  2064. X  #endif USGHIST
  2065. X      static FILE    *hfp = NULL;    /* history file, text version */
  2066. X- 
  2067. X-     for (cp = msg_id; *cp != '\0'; ++cp)
  2068. X-         if (isupper(*cp))
  2069. X-             *cp = tolower(*cp);
  2070. X  
  2071. X  #ifdef USGHIST
  2072. X      hfp = fopen(histfile(msg_id), "r");
  2073. X--- 114,119 ----
  2074. Xdiff -r -c ../nntp.1.5.0/server/newnews.c ./server/newnews.c
  2075. X*** ../nntp.1.5.0/server/newnews.c    Sat Feb  6 20:29:07 1988
  2076. X--- ./server/newnews.c    Tue Jun  6 23:15:57 1989
  2077. X***************
  2078. X*** 255,263 ****
  2079. X   *    Side effects:    Seeks in history file, modifies line.
  2080. X   */
  2081. X  
  2082. X! seekuntil(fp, key, line, linesize)
  2083. X      FILE        *fp;
  2084. X!     char        *key;
  2085. X      char        *line;
  2086. X      int        linesize;
  2087. X  {
  2088. X--- 255,263 ----
  2089. X   *    Side effects:    Seeks in history file, modifies line.
  2090. X   */
  2091. X  
  2092. X! seekuntil(fp, akey, line, linesize)
  2093. X      FILE        *fp;
  2094. X!     char        *akey;
  2095. X      char        *line;
  2096. X      int        linesize;
  2097. X  {
  2098. X***************
  2099. X*** 264,270 ****
  2100. X--- 264,273 ----
  2101. X      char        datetime[32];
  2102. X      register int    c;
  2103. X      register long    top, bot, mid;
  2104. X+     extern long dtol();
  2105. X+     char key[30];
  2106. X  
  2107. X+     (void) sprintf(key, "%ld", dtol(akey));    /* akey -> time_t in ascii */
  2108. X      bot = 0;
  2109. X      (void) fseek(fp, 0L, 2);
  2110. X      top = ftell(fp);
  2111. X***************
  2112. X*** 327,332 ****
  2113. X--- 330,338 ----
  2114. X  }
  2115. X  
  2116. X  
  2117. X+ /*
  2118. X+  * C news version of getword.
  2119. X+  */
  2120. X  getword(fp, w, line, linesize)
  2121. X      FILE        *fp;
  2122. X      register char    *w;
  2123. X***************
  2124. X*** 334,369 ****
  2125. X      int        linesize;
  2126. X  {
  2127. X      register char    *cp;
  2128. X  
  2129. X      if (fgets(line, linesize, fp) == NULL)
  2130. X          return (0);
  2131. X!     if (cp = index(line, '\t')) {
  2132. X! /*
  2133. X!  * The following gross hack is present because the history file date
  2134. X!  * format is braindamaged.  They like "mm/dd/yy hh:mm", which is useless
  2135. X!  * for relative comparisons of dates using something like atoi() or
  2136. X!  * strcmp.  So, this changes their format into yymmddhhmm.  Sigh.
  2137. X!  *
  2138. X!  * 12345678901234    ("x" for cp[x])
  2139. X!  * mm/dd/yy hh:mm     (their lousy representation)
  2140. X!  * yymmddhhmm        (our good one)
  2141. X!  * 0123456789        ("x" for w[x])
  2142. X!  */
  2143. X!         *cp = '\0';
  2144. X!         (void) strncpy(w, cp+1, 15);
  2145. X!         w[0] = cp[7];        /* Years */
  2146. X!         w[1] = cp[8];
  2147. X!         w[2] = cp[1];        /* Months */
  2148. X!         w[3] = cp[2];
  2149. X!         w[4] = cp[4];        /* Days */
  2150. X!         w[5] = cp[5];
  2151. X!         w[6] = cp[10];        /* Hours */
  2152. X!         w[7] = cp[11];
  2153. X!         w[8] = cp[13];        /* Minutes */
  2154. X!         w[9] = cp[14];
  2155. X!         w[10] = '\0';
  2156. X!     } else
  2157. X!         w[0] = '\0';
  2158. X      return (1);
  2159. X  }
  2160. X  
  2161. X--- 340,362 ----
  2162. X      int        linesize;
  2163. X  {
  2164. X      register char    *cp;
  2165. X+     extern char *index();
  2166. X  
  2167. X      if (fgets(line, linesize, fp) == NULL)
  2168. X          return (0);
  2169. X!     w[0] = '\0';                /* in case of bad format */
  2170. X!     if (cp = index(line, '\t')) {        /* find 2nd field */
  2171. X!         register char *endp;
  2172. X! 
  2173. X!         *cp++ = '\0';
  2174. X!         endp = index(cp, '~');        /* end of date-received */
  2175. X!         if (endp == NULL)
  2176. X!             endp = index(cp, '\t');    /* end of expiry */
  2177. X!         if (endp != NULL) {
  2178. X!             (void) strncpy(w, cp, endp - cp);
  2179. X!             w[endp - cp] = '\0';
  2180. X!         }
  2181. X!     }
  2182. X      return (1);
  2183. X  }
  2184. X  
  2185. Xdiff -r -c ../nntp.1.5.0/server/serve.c ./server/serve.c
  2186. X*** ../nntp.1.5.0/server/serve.c    Thu Feb 25 22:49:21 1988
  2187. X--- ./server/serve.c    Tue Jun  6 23:16:00 1989
  2188. X***************
  2189. X*** 237,244 ****
  2190. X--- 237,251 ----
  2191. X  
  2192. X      printf("%d %s closing connection.  Goodbye.\r\n", OK_GOODBYE, host);
  2193. X      (void) fflush(stdout);
  2194. X+ #ifndef UNBATCHED_INPUT
  2195. X+     {
  2196. X+         char errbuf[2 * NNTP_STRLEN];
  2197. X  
  2198. X+         enqpartbatch(CONT_XFER, ERR_XFERFAIL, errbuf);
  2199. X+     }
  2200. X+ #endif
  2201. X  
  2202. X+ 
  2203. X  #ifdef LOG
  2204. X      if (ferror(stdout))
  2205. X          syslog(LOG_ERR, "%s disconnect: %m", hostname);
  2206. X***************
  2207. X*** 287,293 ****
  2208. X  #ifdef PROFILE
  2209. X      profile();
  2210. X  #endif
  2211. X- 
  2212. X      exit(0);
  2213. X  }
  2214. X  
  2215. X--- 294,299 ----
  2216. !
  2217. echo done
  2218.  
  2219.  
  2220.