home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume12 / cnews / part10 < prev    next >
Text File  |  1987-10-22  |  51KB  |  2,252 lines

  1. Subject:  v12i035:  C News alpha release, Part10/14
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rs@uunet.UU.NET
  5.  
  6. Submitted-by: utzoo!henry (Henry Spencer)
  7. Posting-number: Volume 12, Issue 35
  8. Archive-name: cnews/part10
  9.  
  10.  
  11. #! /bin/sh
  12. # This is a shell archive.  Remove anything before this line, then unpack
  13. # it by saving it into a file and typing "sh file".  To overwrite existing
  14. # files, type "sh file -c".  You can also feed this as standard input via
  15. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  16. # will see the following message at the end:
  17. #        "End of archive 10 (of 14)."
  18. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  19. if test -f 'rna/funcs.c' -a "${1}" != "-c" ; then 
  20.   echo shar: Will not clobber existing file \"'rna/funcs.c'\"
  21. else
  22. echo shar: Extracting \"'rna/funcs.c'\" \(9767 characters\)
  23. sed "s/^X//" >'rna/funcs.c' <<'END_OF_FILE'
  24. X#include "defs.h"
  25. X
  26. X/*
  27. X * string handling functions
  28. X */
  29. Xchar *
  30. Xmyalloc(size)
  31. Xint size;
  32. X{
  33. X    register char *cp;
  34. X
  35. X    extern char *malloc();
  36. X
  37. X    if ((cp = malloc((unsigned) size)) == NIL(char))
  38. X        error("No more memory.");
  39. X    return cp;
  40. X}
  41. X
  42. X
  43. Xchar *
  44. Xmyrealloc(ptr, size)
  45. Xchar *ptr;
  46. Xint size;
  47. X{
  48. X    register char *cp;
  49. X
  50. X    extern char *realloc();
  51. X
  52. X    if ((cp = realloc(ptr, (unsigned) size)) == NIL(char))
  53. X        error("No more memory.");
  54. X    return cp;
  55. X}
  56. X
  57. X
  58. Xchar *
  59. Xnewstr(s)
  60. Xchar *s;
  61. X{
  62. X    return strcpy(myalloc(strlen(s) + 1), s);
  63. X}
  64. X
  65. X
  66. Xchar *
  67. Xnewstr2(s1, s2)
  68. Xchar *s1, *s2;
  69. X{
  70. X    return strcat(strcpy(myalloc(strlen(s1) + strlen(s2) + 1), s1), s2);
  71. X}
  72. X
  73. X
  74. Xchar *
  75. Xnewstr3(s1, s2, s3)
  76. Xchar *s1, *s2, *s3;
  77. X{
  78. X    return strcat(strcat(strcpy(myalloc(strlen(s1) + strlen(s2) + strlen(s3) +
  79. X        1), s1), s2), s3);
  80. X}
  81. X
  82. X
  83. Xchar *
  84. Xnewstr4(s1, s2, s3, s4)
  85. Xchar *s1, *s2, *s3, *s4;
  86. X{
  87. X    return strcat(strcat(strcat(strcpy(myalloc(strlen(s1) + strlen(s2) +
  88. X        strlen(s3) + strlen(s4) + 1), s1), s2), s3), s4);
  89. X}
  90. X
  91. X
  92. Xchar *
  93. Xnewstr5(s1, s2, s3, s4, s5)
  94. Xchar *s1, *s2, *s3, *s4, *s5;
  95. X{
  96. X    return strcat(strcat(strcat(strcat(strcpy(myalloc(strlen(s1) + strlen(s2) +
  97. X        strlen(s3) + strlen(s4) + strlen(s5) + 1), s1), s2), s3), s4), s5);
  98. X}
  99. X
  100. X
  101. Xchar *
  102. Xnewstr6(s1, s2, s3, s4, s5, s6)
  103. Xchar *s1, *s2, *s3, *s4, *s5, *s6;
  104. X{
  105. X    return strcat(strcat(strcat(strcat(strcat(strcpy(myalloc(strlen(s1) +
  106. X        strlen(s2) + strlen(s3) + strlen(s4) + strlen(s5) + strlen(s6) + 1),
  107. X         s1), s2), s3), s4), s5), s6);
  108. X}
  109. X
  110. X
  111. Xchar *
  112. Xcatstr(old, s)
  113. Xchar *old, *s;
  114. X{
  115. X    return strcat(myrealloc(old, strlen(old) + strlen(s) + 1), s);
  116. X}
  117. X
  118. X
  119. Xchar *
  120. Xcatstr2(old, s1, s2)
  121. Xchar *old, *s1, *s2;
  122. X{
  123. X    return strcat(strcat(myrealloc(old, strlen(old) + strlen(s1) + strlen(s2) +
  124. X        1), s1), s2);
  125. X}
  126. X
  127. X
  128. X/*
  129. X * News group matching.
  130. X *
  131. X * nglist is a list of newsgroups.
  132. X * sublist is a list of subscriptions.
  133. X * sublist may have "meta newsgroups" in it.
  134. X * All fields are NGSEPCHAR separated.
  135. X *
  136. X * sublist uses "all" like shell uses "*", and "." like shell uses "/"
  137. X * if subscription X matches Y, it also matches Y.anything
  138. X */
  139. Xngmatch(nglist, sublist)
  140. Xchar *nglist, *sublist;
  141. X{
  142. X    register char *n, *s, *nd, *sd;
  143. X    register int rc;
  144. X
  145. X    rc = 0;
  146. X    n = nglist;
  147. X    while (*n && rc == 0) {
  148. X        if (nd = strchr(n, NGSEPCHAR))
  149. X            *nd = '\0';
  150. X        s = sublist;
  151. X        while (*s) {
  152. X            if (sd = strchr(s, NGSEPCHAR))
  153. X                *sd = '\0';
  154. X            if (*s != NEGCHAR)
  155. X                rc |= ptrncmp(s, n);
  156. X            else
  157. X                rc &= ~ptrncmp(s + 1, n);
  158. X            if (sd)
  159. X                *sd = NGSEPCHAR, s = sd + 1;
  160. X            else
  161. X                break;
  162. X        }
  163. X        if (nd)
  164. X            *nd = NGSEPCHAR, n = nd + 1;
  165. X        else
  166. X            break;
  167. X    }
  168. X    return rc;
  169. X}
  170. X
  171. X
  172. X/*
  173. X * Compare two newsgroups for equality.
  174. X * The first one may be a "meta" newsgroup.
  175. X */
  176. Xstatic
  177. Xptrncmp(ng1, ng2)
  178. Xregister char *ng1, *ng2;
  179. X{
  180. X
  181. X    while (1) {
  182. X        if (ng1[0] == 'a' && ng1[1] == 'l' && ng1[2] == 'l' && (ng1[3] ==
  183. X            '\0' || ng1[3] == '.')) {
  184. X            if (ng1[3] == '\0')    /* "all" matches anything */
  185. X                return 1;
  186. X            while (*ng2 && *ng2 != '.')
  187. X                ng2++;
  188. X            if (*ng2 != '.')        /* "all." doesn't match "xx" */
  189. X                return 0;
  190. X            ng1 += 4, ng2++;
  191. X            continue;
  192. X        }
  193. X        while (*ng1 && *ng1 != '.' && *ng1 == *ng2)
  194. X            ng1++, ng2++;
  195. X        if (*ng1 == '.') {
  196. X            if (*ng2 != '.' && *ng2 != '\0')
  197. X                return 0;    /* "."'s don't line up */
  198. X            if (*ng2)
  199. X                ng2++;
  200. X            ng1++;            /* "."'s line up - keep going */
  201. X        } else if (*ng1 == '\0')
  202. X            return (*ng2 == '\0' || *ng2 == '.');
  203. X            /* full match or X matching X.thing */
  204. X        else
  205. X            return 0;
  206. X    }
  207. X    /* NOTREACHED */
  208. X}
  209. X
  210. X
  211. X/*
  212. X * return new newsgroup composed of only those from 'nglist'
  213. X * subscribed to by 'sublist'
  214. X * return NULL for empty list
  215. X */
  216. Xchar *
  217. Xngsquash(nglist, sublist)
  218. Xregister char *nglist, *sublist;
  219. X{
  220. X    register char *delim;
  221. X    register char *newg;
  222. X
  223. X    newg = NIL(char);
  224. X    while (*nglist) {
  225. X        if (delim = strchr(nglist, NGSEPCHAR))
  226. X            *delim = '\0';
  227. X        if (ngmatch(nglist, sublist))
  228. X            newg = (newg ? catstr2(newg, NGSEPS, nglist) : newstr(nglist));
  229. X        if (delim)
  230. X            *delim = NGSEPCHAR, nglist = delim + 1;
  231. X        else
  232. X            break;
  233. X    }
  234. X    return newg;
  235. X}
  236. X
  237. X
  238. X/*
  239. X * get unique sequence number from SEQ
  240. X */
  241. Xchar *
  242. Xgetunique()
  243. X{
  244. X    register long number;
  245. X    register FILE    *f;
  246. X    static char buf[12];
  247. X
  248. X    f = fopenl(SEQ);
  249. X    if (fread(buf, 1, sizeof(buf), f) > 0)
  250. X        number = atol(buf);
  251. X    else
  252. X        number = 1;
  253. X
  254. X    rewind(f);
  255. X    (void) fprintf(f, "%ld\n", number + 1);
  256. X    fclose(f);
  257. X#if !AUSAM
  258. X    unlock(SEQ);
  259. X#endif
  260. X
  261. X    sprintf(buf, "%ld", number);
  262. X    return buf;
  263. X}
  264. X
  265. X
  266. X/*
  267. X * open a locked file (or create) for reading and writing
  268. X */
  269. XFILE *
  270. Xfopenl(fname)
  271. Xchar *fname;
  272. X{
  273. X    register FILE    *f;
  274. X#ifdef AUSAM
  275. X    struct stat sbuf;
  276. X#endif
  277. X
  278. X    extern uid_t    newsuid;
  279. X
  280. X    if ((f = fopen(fname, "r+")) == NIL(FILE) && (f = fopen(fname, "w+")) ==
  281. X        NIL(FILE))
  282. X        error("Can't open %s", fname);
  283. X
  284. X#if AUSAM
  285. X    if (fstat(fileno(f), &sbuf) != 0)
  286. X        error("Can't stat %s", fname);
  287. X    if ((sbuf.st_mode & S_IFMT) != S_IFALK && (chmod(fname, (int) (sbuf.st_mode
  288. X        &~S_IFMT) | S_IFALK) != 0 || chown(fname, (int) newsuid, (int) newsuid) !=
  289. X        0 || fclose(f) == EOF || (f = fopen(fname, "r+")) == NIL(FILE)))
  290. X        error("Can't create %s", fname);
  291. X#else
  292. X    chown(fname, (int) newsuid, (int) newsuid);
  293. X    lock(fname);
  294. X#endif
  295. X
  296. X    return f;
  297. X}
  298. X
  299. X
  300. X#if !AUSAM
  301. X
  302. X#define LSUFFIX    ".lock"        /* suffix for lock files */
  303. X
  304. Xlock(fname)
  305. Xchar *fname;
  306. X{
  307. X    register char *lname;
  308. X    register int i, f;
  309. X
  310. X    lname = newstr2(fname, LSUFFIX);
  311. X    for (i = 0; i < 10; i++) {
  312. X        if ((f = creat(lname, 0)) != -1) {
  313. X            close(f);
  314. X            free(lname);
  315. X            return;
  316. X        }
  317. X        sleep(2);
  318. X    }
  319. X    error("Can't creat %s after %d tries", lname, i);
  320. X}
  321. X
  322. X
  323. Xunlock(fname)
  324. Xchar *fname;
  325. X{
  326. X    register char *lname;
  327. X
  328. X    lname = newstr2(fname, LSUFFIX);
  329. X    unlink(lname);
  330. X    free(lname);
  331. X}
  332. X
  333. X
  334. X#endif
  335. X
  336. X/*
  337. X * open a file
  338. X */
  339. XFILE *
  340. Xfopenf(name, mode)
  341. Xchar *name, *mode;
  342. X{
  343. X    register FILE    *f;
  344. X
  345. X    if ((f = fopen(name, mode)) == NIL(FILE))
  346. X        error("Can't %s %s", *mode == 'r' ? "open" : "create", name);
  347. X    return f;
  348. X}
  349. X
  350. X
  351. X/*
  352. X * replace all '.''s with '/'
  353. X */
  354. Xchar *
  355. Xconvg(s)
  356. Xregister char *s;
  357. X{
  358. X    register char *sav;
  359. X
  360. X    sav = s;
  361. X    while (s = strchr(s, '.'))
  362. X        *s = '/';
  363. X    return sav;
  364. X}
  365. X
  366. X
  367. X/*
  368. X * replace all '/''s with '.'
  369. X */
  370. Xchar *
  371. Xrconvg(s)
  372. Xregister char *s;
  373. X{
  374. X    register char *sav;
  375. X
  376. X    sav = s;
  377. X    while (s = strchr(s, '/'))
  378. X        *s = '.';
  379. X    return sav;
  380. X}
  381. X
  382. X
  383. X/*
  384. X * get a line from stdin
  385. X * trim leading and trailing blanks
  386. X */
  387. Xchar *
  388. Xmgets()
  389. X{
  390. X    register char *s;
  391. X    static char buf[BUFSIZ];
  392. X
  393. X    fflush(stdout);
  394. X    if (fgets(buf, sizeof(buf), stdin) == NIL(char)) {
  395. X        (void) printf("\n");
  396. X        return NIL(char);
  397. X    }
  398. X    if (s = strchr(buf, '\n'))
  399. X        while (isspace(*s) && s > buf)
  400. X            *s-- = '\0';
  401. X    else
  402. X     {
  403. X        (void) printf("Input line too long.\n");
  404. X        return NIL(char);
  405. X    }
  406. X    s = buf;
  407. X    while (isspace(*s))
  408. X        s++;
  409. X    return s;
  410. X}
  411. X
  412. X
  413. Xreadln(f)
  414. XFILE *f;
  415. X{
  416. X    register int c;
  417. X
  418. X    if (feof(f) || ferror(f))
  419. X        return;
  420. X    while ((c = getc(f)) != '\n' && c != EOF)
  421. X        ;
  422. X}
  423. X
  424. X
  425. X/*
  426. X * compare string pointers
  427. X */
  428. Xstrpcmp(a, b)
  429. Xchar **a, **b;
  430. X{
  431. X    return CMP(*a, *b);
  432. X}
  433. X
  434. X
  435. X/*
  436. X * apply the given function to each member in the newsgroup
  437. X */
  438. X/* VARARGS2 */
  439. Xapplyng(ng, func, arg1)
  440. Xregister char *ng;
  441. Xregister int (*func)();
  442. Xchar *arg1;
  443. X{
  444. X    register char *delim;
  445. X    register int err;
  446. X
  447. X    err = 0;
  448. X    while (*ng) {
  449. X        if (delim = strchr(ng, NGSEPCHAR))
  450. X            *delim = '\0';
  451. X        err += (*func)(ng, arg1);
  452. X        if (delim)
  453. X            *delim = NGSEPCHAR, ng = delim + 1;
  454. X        else
  455. X            break;
  456. X    }
  457. X    return err;
  458. X}
  459. X
  460. X
  461. X/*
  462. X * generate a return address
  463. X */
  464. Xchar *
  465. Xgetretaddr(hp)
  466. Xheader *hp;
  467. X{
  468. X    register char *ra;
  469. X
  470. X    extern char *getpath(), *exaddress();
  471. X#ifdef NETPATH
  472. X    extern char *getnetpath();
  473. X#endif
  474. X
  475. X    if (hp->h_replyto)
  476. X        ra = exaddress(hp->h_replyto);
  477. X    else if (hp->h_from)
  478. X        ra = exaddress(hp->h_from);
  479. X    else
  480. X        ra = NIL(char);
  481. X    if (hp->h_path && !ra)
  482. X        ra = getpath(hp->h_path);
  483. X#ifdef NETPATH
  484. X    if (CMPN(ra, PATHPREF, sizeof(PATHPREF) - 1) == 0)
  485. X        ra = getnetpath(ra);
  486. X#endif
  487. X    return ra;
  488. X}
  489. X
  490. X
  491. X/*
  492. X * try and make a proper address
  493. X */
  494. Xchar *
  495. Xexaddress(addr)
  496. Xchar *addr;
  497. X{
  498. X    register char *space, *dot, *at;
  499. X    register char *raddr;
  500. X
  501. X    raddr = NIL(char);
  502. X    if (space = strchr(addr, ' '))
  503. X        *space = '\0';
  504. X    if (at = strchr(addr, '@')) {
  505. X        *at = '\0';
  506. X        if (dot = strchr(at + 1, '.')) {
  507. X            *dot = '\0';
  508. X#if OZ
  509. X            if (CMP(dot + 1, MYDOMAIN) == 0)
  510. X                raddr = newstr3(addr, ":", at + 1);
  511. X            else
  512. X#endif
  513. X                raddr = newstr4(PATHPREF, at + 1, PSEPS, addr);
  514. X            *dot = '.';
  515. X        }
  516. X        *at = '@';
  517. X    }
  518. X    if (space)
  519. X        *space = ' ';
  520. X    return raddr;
  521. X
  522. X}
  523. X
  524. X
  525. X/*
  526. X * return the last two components of the path
  527. X */
  528. Xchar *
  529. Xgetpath(path)
  530. Xchar *path;
  531. X{
  532. X    register char *exlast, *ex;
  533. X    register char *raddr;
  534. X
  535. X    if (exlast = strrchr(path, PSEPCHAR)) {
  536. X        *exlast = '\0';
  537. X        if (ex = strrchr(path, PSEPCHAR))
  538. X            raddr = newstr4(PATHPREF, ex + 1, PSEPS, exlast + 1);
  539. X        else
  540. X            raddr = newstr3(path, PSEPS, exlast + 1);
  541. X        *exlast = PSEPCHAR;
  542. X    } else
  543. X        raddr = NIL(char);
  544. X    return raddr;
  545. X}
  546. X
  547. X
  548. X#ifdef NETPATH
  549. X/*
  550. X * try and work out a path from our "netpath" database
  551. X */
  552. Xchar *
  553. Xgetnetpath(path)
  554. Xchar *path;
  555. X{
  556. X    FILE         * f;
  557. X    register char *ex1, *ex2, *com, *new;
  558. X    char buf[BUFSIZ];
  559. X
  560. X    if ((ex1 = strchr(path, PSEPCHAR)) && (ex2 = strchr(ex1 + 1, PSEPCHAR))) {
  561. X        *ex2 = '\0';
  562. X        com = newstr4("exec ", NETPATH, " mulga ", ex1 + 1);
  563. X        if ((f = popen(com, "r")) == NIL(FILE))
  564. X            (void) printf("Couldn't run \"%s\"\n", com);
  565. X        else
  566. X         {
  567. X            fread(buf, sizeof(buf), 1, f);
  568. X            if (pclose(f) != 0) {
  569. X                (void) printf("Error in running \"%s\"\n", com);
  570. X                fflush(stdout);
  571. X            } else if (CMPN(buf, "mulga!", 6) == 0) {
  572. X                if (ex1 = strchr(buf, '\n'))
  573. X                    *ex1 = '\0';
  574. X                new = newstr4(buf + 6, PSEPS, ex2 + 1, ":mulga");
  575. X                free(path);
  576. X                path = new;
  577. X            }
  578. X        }
  579. X        free(com);
  580. X        *ex2 = PSEPCHAR;
  581. X    }
  582. X    return path;
  583. X
  584. X}
  585. X
  586. X
  587. X#endif
  588. X
  589. X/*
  590. X * remove extra spaces, and insert separators if necessary in
  591. X * newsgroups specification
  592. X */
  593. Xconvgrps(sp)
  594. Xregister char *sp;
  595. X{
  596. X    register char *sep;
  597. X
  598. X    sep = NIL(char);
  599. X    while (*sp) {
  600. X        if (sep)
  601. X            sp++;
  602. X        while (*sp && (isspace(*sp) || *sp == NGSEPCHAR))
  603. X            strcpy(sp, sp + 1);
  604. X        if (sep)
  605. X            *sep = (*sp ? NGSEPCHAR : '\0');
  606. X        while (*sp && !isspace(*sp) && *sp != NGSEPCHAR)
  607. X            sp++;
  608. X        sep = sp;
  609. X    }
  610. X}
  611. X
  612. X
  613. END_OF_FILE
  614. if test 9767 -ne `wc -c <'rna/funcs.c'`; then
  615.     echo shar: \"'rna/funcs.c'\" unpacked with wrong size!
  616. fi
  617. # end of 'rna/funcs.c'
  618. fi
  619. if test -f 'rna/header.c' -a "${1}" != "-c" ; then 
  620.   echo shar: Will not clobber existing file \"'rna/header.c'\"
  621. else
  622. echo shar: Extracting \"'rna/header.c'\" \(10079 characters\)
  623. sed "s/^X//" >'rna/header.c' <<'END_OF_FILE'
  624. X/*
  625. X * extract/output headers
  626. X */
  627. X
  628. X#include "defs.h"
  629. X
  630. X#if AUSAM
  631. Xextern struct pwent pe;
  632. X#else
  633. Xextern struct passwd *pp;
  634. X#endif
  635. Xextern char systemid[];
  636. Xextern long now;
  637. X
  638. Xchar tzone[]         = TIMEZONE;
  639. Xchar hform[]         = "%s: %s\n";
  640. X
  641. X/* Mandatory Headers */
  642. Xchar t_relayversion[]     = "Relay-Version";
  643. Xchar t_postversion[]     = "Posting-Version";
  644. Xchar t_from[]         = "From";
  645. Xchar t_date[]         = "Date";
  646. Xchar t_newsgroups[]     = "Newsgroups";
  647. Xchar t_subject[]     = "Subject";
  648. Xchar t_messageid[]     = "Message-ID";
  649. Xchar t_path[]         = "Path";
  650. X
  651. X/* Optional Headers */
  652. Xchar t_replyto[]     = "Reply-To";
  653. Xchar t_sender[]         = "Sender";
  654. Xchar t_followupto[]     = "Followup-To";
  655. Xchar t_datereceived[]     = "Date-Received";
  656. Xchar t_expires[]     = "Expires";
  657. Xchar t_references[]     = "References";
  658. Xchar t_control[]     = "Control";
  659. Xchar t_distribution[]     = "Distribution";
  660. Xchar t_organization[]     = "Organization";
  661. Xchar t_lines[]         = "Lines";
  662. X
  663. Xtypedef enum ft
  664. X{
  665. X    f_control, f_date, f_datereceived, f_distribution,
  666. X    f_expires, f_followupto, f_from, f_lines, f_messageid,
  667. X    f_newsgroups, f_organization, f_path, f_postversion,
  668. X    f_references, f_relayversion, f_replyto, f_sender,
  669. X    f_subject
  670. X}
  671. X
  672. X
  673. Xftype;
  674. X
  675. Xtypedef struct field {
  676. X    char *f_name;
  677. X    ftype    f_type;
  678. X} field;
  679. X
  680. Xstatic field fields[] = 
  681. X{
  682. X    { t_control,     f_control     },
  683. X    { t_date,         f_date         },
  684. X    { t_datereceived,     f_datereceived     },
  685. X    { t_distribution,     f_distribution     },
  686. X    { t_expires,     f_expires     },
  687. X    { t_followupto,     f_followupto     },
  688. X    { t_from,         f_from         },
  689. X    { t_lines,     f_lines         },
  690. X    { t_messageid,     f_messageid     },
  691. X    { t_newsgroups,     f_newsgroups     },
  692. X    { t_organization,     f_organization     },
  693. X    { t_path,         f_path         },
  694. X    { t_postversion,     f_postversion     },
  695. X    { t_references,     f_references     },
  696. X    { t_relayversion,     f_relayversion     },
  697. X    { t_replyto,     f_replyto     },
  698. X    { t_sender,     f_sender     },
  699. X    { t_subject,     f_subject     }
  700. X};
  701. X
  702. X
  703. Xchar *weekdays[7] = 
  704. X{
  705. X    "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
  706. X};
  707. X
  708. X
  709. Xchar *months[12] = 
  710. X{
  711. X    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  712. X    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
  713. X};
  714. X
  715. X
  716. Xstatic
  717. Xfieldcmp(a, b)
  718. Xfield *a, *b;
  719. X{
  720. X    return CMP(a->f_name, b->f_name);
  721. X}
  722. X
  723. X
  724. X/*
  725. X * extract headers from file,
  726. X * position file to start of body
  727. X */
  728. Xgethead(f, hp)
  729. XFILE *f;
  730. Xheader *hp;
  731. X{
  732. X    register char *colon, *space, *s;
  733. X    register field    *fp;
  734. X    field        af;
  735. X    char buf[BUFLEN*2];
  736. X
  737. X    char *hfgets();
  738. X
  739. X    memset((char *) hp, 0, sizeof(header));
  740. X    while (hfgets(buf, sizeof(buf), f)) {
  741. X        if (buf[0] == '\n')
  742. X            return;
  743. X        if (isupper(buf[0]) && (colon = strchr(buf, ':')) && (space =
  744. X            strchr(buf, ' ')) && (colon + 1 == space)) {
  745. X            *colon = '\0';
  746. X            af.f_name = buf;
  747. X            fp = (field * ) bsearch((char *) & af, (char *) fields,
  748. X                                 sizeof(fields) / sizeof(fields[0]), sizeof(fields[0]),
  749. X                 fieldcmp);
  750. X            *colon = ':';
  751. X        } else
  752. X            fp = NIL(field);
  753. X        if (!fp)
  754. X            if (hp->h_others)
  755. X                hp->h_others = catstr(hp->h_others, buf);
  756. X            else
  757. X                hp->h_others = newstr(buf);
  758. X        else
  759. X         {
  760. X            if (colon = strchr(space + 1, '\n'))
  761. X                *colon = '\0';
  762. X            s = newstr(space + 1);
  763. X            switch (fp->f_type) {
  764. X            case f_control:        
  765. X                hp->h_control = s;    
  766. X                break;
  767. X            case f_date:        
  768. X                hp->h_date = s;        
  769. X                break;
  770. X            case f_datereceived:    
  771. X                hp->h_datereceived = s;    
  772. X                break;
  773. X            case f_distribution:    
  774. X                hp->h_distribution = s;    
  775. X                break;
  776. X            case f_expires:        
  777. X                hp->h_expires = s;    
  778. X                break;
  779. X            case f_followupto:    
  780. X                hp->h_followupto = s;    
  781. X                break;
  782. X            case f_from:        
  783. X                hp->h_from = s;        
  784. X                break;
  785. X            case f_lines:        
  786. X                hp->h_lines = s;    
  787. X                break;
  788. X            case f_messageid:    
  789. X                hp->h_messageid = s;    
  790. X                break;
  791. X            case f_newsgroups:    
  792. X                hp->h_newsgroups = s;    
  793. X                break;
  794. X            case f_organization:    
  795. X                hp->h_organisation = s;    
  796. X                break;
  797. X            case f_path:        
  798. X                hp->h_path = s;        
  799. X                break;
  800. X            case f_postversion:    
  801. X                hp->h_postversion = s;    
  802. X                break;
  803. X            case f_references:    
  804. X                hp->h_references = s;    
  805. X                break;
  806. X            case f_relayversion:    
  807. X                hp->h_relayversion = s;    
  808. X                break;
  809. X            case f_replyto:        
  810. X                hp->h_replyto = s;    
  811. X                break;
  812. X            case f_sender:        
  813. X                hp->h_sender = s;    
  814. X                break;
  815. X            case f_subject:        
  816. X                hp->h_subject = s;    
  817. X                break;
  818. X            }
  819. X        }
  820. X    }
  821. X}
  822. X
  823. X
  824. X/*
  825. X * put headers to file
  826. X */
  827. Xputhead(hp, f, com)
  828. Xheader *hp;
  829. XFILE *f;
  830. Xpheadcom com;
  831. X{
  832. X    register char *s;
  833. X    char *getunique();
  834. X    extern char *getenv();
  835. X
  836. X    if (hp->h_relayversion && com == printing)
  837. X        (void) fprintf(f, hform, t_relayversion, hp->h_relayversion);
  838. X    else if (com != printing)
  839. X        (void) fprintf(f, "%s: version %s; site %s.%s\n", t_relayversion, NEWSVERSION,
  840. X             systemid, MYDOMAIN);
  841. X
  842. X    if (hp->h_postversion)
  843. X        (void) fprintf(f, hform, t_postversion, hp->h_postversion);
  844. X    else if (com == making)
  845. X        (void) fprintf(f, "%s: version %s; site %s.%s\n", t_postversion, NEWSVERSION,
  846. X             systemid, MYDOMAIN);
  847. X
  848. X
  849. X    if (hp->h_from)
  850. X        (void) fprintf(f, hform, t_from, hp->h_from);
  851. X    else if(com == making) {
  852. X        if(s = getenv("NAME"))
  853. X            (void) fprintf(f, "%s: %s@%s.%s (%s)\n", t_from,
  854. X#if AUSAM
  855. X                pe.pw_strings[LNAME],
  856. X#else
  857. X                pp->pw_name,
  858. X#endif
  859. X                systemid, MYDOMAIN, s);
  860. X        else
  861. X            (void) fprintf(f,
  862. X#if AUSAM
  863. X                "%s: %s@%s.%s (%s %s)\n",
  864. X#else
  865. X                "%s: %s@%s.%s\n",
  866. X#endif
  867. X                t_from,
  868. X#if AUSAM
  869. X                pe.pw_strings[LNAME],
  870. X#else
  871. X                pp->pw_name,
  872. X#endif
  873. X                systemid, MYDOMAIN
  874. X#if AUSAM
  875. X                ,
  876. X                pe.pw_strings[FIRSTNAME],
  877. X                pe.pw_strings[LASTNAME]
  878. X#endif
  879. X            );
  880. X    }
  881. X
  882. X    if (hp->h_date)
  883. X        (void) fprintf(f, hform, t_date, hp->h_date);
  884. X    else if (com == making)
  885. X        (void) fprintf(f, hform, t_date, ttoa(now));
  886. X
  887. X    if (hp->h_newsgroups)
  888. X        (void) fprintf(f, hform, t_newsgroups, hp->h_newsgroups);
  889. X    else if (com == making)
  890. X        (void) fprintf(f, hform, t_newsgroups, DFLTGRP);
  891. X
  892. X    if (hp->h_subject)
  893. X        (void) fprintf(f, hform, t_subject, hp->h_subject);
  894. X    else if (com == making)
  895. X        error("No subject field.");
  896. X
  897. X    if (hp->h_messageid)
  898. X        (void) fprintf(f, hform, t_messageid, hp->h_messageid);
  899. X    else if (com == making)
  900. X        error("No messageid.");
  901. X
  902. X    if (hp->h_path && com == passing)
  903. X        (void) fprintf(f, "%s: %s!%s\n", t_path, systemid, hp->h_path);
  904. X    else if (hp->h_path)
  905. X        (void) fprintf(f, hform, t_path, hp->h_path);
  906. X    else if(com == making)
  907. X        (void) fprintf(f, "%s: %s!%s\n", t_path, systemid,
  908. X#if AUSAM
  909. X            pe.pw_strings[LNAME]
  910. X#else
  911. X            pp->pw_name
  912. X#endif
  913. X        );
  914. X
  915. X    /* optional */
  916. X
  917. X    if (hp->h_replyto)
  918. X        (void) fprintf(f, hform, t_replyto, hp->h_replyto);
  919. X
  920. X    if (hp->h_sender)
  921. X        (void) fprintf(f, hform, t_sender, hp->h_sender);
  922. X
  923. X    if (hp->h_followupto)
  924. X        (void) fprintf(f, hform, t_followupto, hp->h_followupto);
  925. X
  926. X    if (hp->h_datereceived && com == printing)
  927. X        (void) fprintf(f, hform, t_datereceived, hp->h_datereceived);
  928. X    else if (com != printing)
  929. X        (void) fprintf(f, hform, t_datereceived, ttoa(now));
  930. X
  931. X    if (hp->h_expires)
  932. X        (void) fprintf(f, hform, t_expires, hp->h_expires);
  933. X
  934. X    if (hp->h_references)
  935. X        (void) fprintf(f, hform, t_references, hp->h_references);
  936. X
  937. X    if (hp->h_control)
  938. X        (void) fprintf(f, hform, t_control, hp->h_control);
  939. X
  940. X    if (hp->h_distribution)
  941. X        (void) fprintf(f, hform, t_distribution, hp->h_distribution);
  942. X
  943. X    if (hp->h_organisation)
  944. X        (void) fprintf(f, hform, t_organization, hp->h_organisation);
  945. X    else if (com == making)
  946. X        (void) fprintf(f, hform, t_organization, (s = getenv("ORGANIZATION")) ?
  947. X            s : MYORG);
  948. X
  949. X    if (hp->h_lines)
  950. X        (void) fprintf(f, hform, t_lines, hp->h_lines);
  951. X
  952. X    if (hp->h_others)
  953. X        fputs(hp->h_others, f);
  954. X}
  955. X
  956. X
  957. X/*
  958. X * free all strings allocated to header
  959. X */
  960. Xfreehead(hp)
  961. Xregister header *hp;
  962. X{
  963. X    if (hp->h_relayversion)    
  964. X        free(hp->h_relayversion);
  965. X    if (hp->h_postversion)    
  966. X        free(hp->h_postversion);
  967. X    if (hp->h_from)        
  968. X        free(hp->h_from);
  969. X    if (hp->h_date)        
  970. X        free(hp->h_date);
  971. X    if (hp->h_newsgroups)    
  972. X        free(hp->h_newsgroups);
  973. X    if (hp->h_subject)    
  974. X        free(hp->h_subject);
  975. X    if (hp->h_messageid)    
  976. X        free(hp->h_messageid);
  977. X    if (hp->h_path)        
  978. X        free(hp->h_path);
  979. X    if (hp->h_replyto)    
  980. X        free(hp->h_replyto);
  981. X    if (hp->h_sender)    
  982. X        free(hp->h_sender);
  983. X    if (hp->h_followupto)    
  984. X        free(hp->h_followupto);
  985. X    if (hp->h_datereceived)    
  986. X        free(hp->h_datereceived);
  987. X    if (hp->h_expires)    
  988. X        free(hp->h_expires);
  989. X    if (hp->h_references)    
  990. X        free(hp->h_references);
  991. X    if (hp->h_control)    
  992. X        free(hp->h_control);
  993. X    if (hp->h_distribution)    
  994. X        free(hp->h_distribution);
  995. X    if (hp->h_organisation)    
  996. X        free(hp->h_organisation);
  997. X    if (hp->h_lines)        
  998. X        free(hp->h_lines);
  999. X    if (hp->h_others)    
  1000. X        free(hp->h_others);
  1001. X}
  1002. X
  1003. X
  1004. X/*
  1005. X * hfgets is like fgets, but deals with continuation lines.
  1006. X * It also ensures that even if a line that is too long is
  1007. X * received, the remainder of the line is thrown away
  1008. X * instead of treated like a second line.
  1009. X */
  1010. Xchar *
  1011. Xhfgets(buf, len, fp)
  1012. Xchar *buf;
  1013. Xint len;
  1014. XFILE *fp;
  1015. X{
  1016. X    register int c;
  1017. X    register char *cp, *tp;
  1018. X
  1019. X    if ((cp = fgets(buf, len, fp)) == NIL(char))
  1020. X        return NIL(char);
  1021. X
  1022. X    if (*cp == '\n')
  1023. X        return cp;
  1024. X
  1025. X    tp = cp + strlen(cp);
  1026. X    if (tp[-1] != '\n') {
  1027. X        /* Line too long - part read didn't fit into a newline */
  1028. X        while ((c = getc(fp)) != '\n' && c != EOF)
  1029. X            ;
  1030. X    } else
  1031. X        *--tp = '\0';    /* clobber newline */
  1032. X
  1033. X    while ((c = getc(fp)) == ' ' || c == '\t') {
  1034. X        /* Continuation line. */
  1035. X        while ((c = getc(fp)) == ' ' || c == '\t')
  1036. X            ;
  1037. X        if (tp - cp < len) {
  1038. X            *tp++ = ' ';
  1039. X            *tp++ = c;
  1040. X        }
  1041. X        while ((c = getc(fp)) != '\n' && c != EOF)
  1042. X            if (tp - cp < len)
  1043. X                *tp++ = c;
  1044. X    }
  1045. X    *tp++ = '\n';
  1046. X    *tp++ = '\0';
  1047. X    if (c != EOF)
  1048. X        ungetc(c, fp);    /* push back first char of next header */
  1049. X    return cp;
  1050. X}
  1051. X
  1052. X
  1053. X/*
  1054. X * time to ascii
  1055. X *    leave time in static var
  1056. X */
  1057. Xchar *
  1058. Xttoa(t)
  1059. Xlong t;
  1060. X{
  1061. X    static char buf[40];
  1062. X    struct tm *tp;
  1063. X    extern struct tm *localtime();
  1064. X
  1065. X    tp = localtime(&t);
  1066. X    sprintf(buf, "%s, %d %s %d %02d:%02d:%02d %s", weekdays[tp->tm_wday],
  1067. X         tp->tm_mday, months[tp->tm_mon], tp->tm_year, tp->tm_hour, tp->tm_min,
  1068. X         tp->tm_sec, tzone);
  1069. X    return buf;
  1070. X
  1071. X}
  1072. X
  1073. X
  1074. X/*
  1075. X * ascii to time
  1076. X * return 0L on error
  1077. X */
  1078. Xlong
  1079. Xatot(s)
  1080. Xchar *s;
  1081. X{
  1082. X    char *argv[4];
  1083. X    int day, year, hour, min, sec;
  1084. X    char month[10], sday[10], stime[10], syear[10];
  1085. X    extern long maketime();
  1086. X
  1087. X    if (sscanf(s, "%*s %d %*[ -] %9[^ -] %*[ -] %d %2d:%2d:%2d", &day, month,
  1088. X         &year, &hour, &min, &sec) != 6)
  1089. X        return 0L;
  1090. X    sprintf(sday, "%d", day);
  1091. X    sprintf(stime, "%d:%d:%d", hour, min, sec);
  1092. X    sprintf(syear, "%d", 1900 + year);
  1093. X    argv[0] = sday;
  1094. X    argv[1] = month;
  1095. X    argv[2] = stime;
  1096. X    argv[3] = syear;
  1097. X    return maketime(4, argv, STIMES);
  1098. X}
  1099. X
  1100. X
  1101. END_OF_FILE
  1102. if test 10079 -ne `wc -c <'rna/header.c'`; then
  1103.     echo shar: \"'rna/header.c'\" unpacked with wrong size!
  1104. fi
  1105. # end of 'rna/header.c'
  1106. fi
  1107. if test -f 'rna/maketime.c' -a "${1}" != "-c" ; then 
  1108.   echo shar: Will not clobber existing file \"'rna/maketime.c'\"
  1109. else
  1110. echo shar: Extracting \"'rna/maketime.c'\" \(8785 characters\)
  1111. sed "s/^X//" >'rna/maketime.c' <<'END_OF_FILE'
  1112. X/*
  1113. X * long
  1114. X * maketime(argc, argv, type)
  1115. X *
  1116. X * A standard routine to convert a future time (in English) to seconds.
  1117. X * Arguments are order-independent (except for suffixes), and words
  1118. X * may be shortened to a non-ambiguous abbreviation.
  1119. X * As the time must be in the future, unspecified years, months and days default
  1120. X * to the "next" year, month or day if necessary; otherwise the current
  1121. X * month, day and hour are used.
  1122. X *
  1123. X * type is either TIMES in which days, times are recognised, or just DAYS.
  1124. X *
  1125. X * Tries hard to give meaningful messages, and make sure the user
  1126. X * gets the time she/he wanted!
  1127. X *
  1128. X * Return is in seconds or 0 if error.
  1129. X * Error messages to stderr.
  1130. X *
  1131. X * Michael Rourke (UNSW) Christmas 1982
  1132. X *
  1133. X * Syntax:
  1134. X *
  1135. X *    timespec ::= { time | day | month | year } .
  1136. X *    
  1137. X *    time ::= [ hour [ ":" min [ ":" second ] ] ] [ timemodifier ] .
  1138. X *    
  1139. X *    timemodifier ::= "am" | "pm" | "noon" | "midday" | "midnight" | "now" .
  1140. X *    
  1141. X *    day ::= ( dayofweek [ "week" ] ) | number .
  1142. X *    
  1143. X *    dayofweek ::= "sunday" | "monday" | "tuesday" | "wednesday" |
  1144. X *              "thursday" | "friday" | "saturday" | "tomorrow" |
  1145. X *              "today" .
  1146. X *    
  1147. X *    month ::= "january" | "february" | "march" | "april" | "may" | "june" |
  1148. X *          "july" | "august" | "september" | "october" | "november" |
  1149. X *          "december" .
  1150. X *    
  1151. X *    year ::= "19" number .
  1152. X *
  1153. X */
  1154. X
  1155. X#include "defs.h"
  1156. X
  1157. X#define    NOW     -1
  1158. X
  1159. Xstatic timemod(), noonmid(), daymod(), weekday(), smonth();
  1160. X
  1161. Xstatic struct slist {
  1162. X    char *s_name;
  1163. X    int (*s_action)();
  1164. X    char s_val;
  1165. X    char s_type;
  1166. X} slist[] = 
  1167. X{
  1168. X    { "am",         timemod,     0,     TIMES,      },
  1169. X    { "pm",         timemod,     12,     TIMES,      },
  1170. X    { "noon",         noonmid,     12,     TIMES,      },
  1171. X    { "midday",     noonmid,     12,     TIMES,      },
  1172. X    { "midnight",     noonmid,     0,     TIMES,      },
  1173. X    { "now",         noonmid,     NOW,     TIMES,      },
  1174. X    { "week",         daymod,         0,     DAYS,      },
  1175. X    { "sunday",     weekday,     0,     DAYS,      },
  1176. X    { "monday",     weekday,     1,     DAYS,      },
  1177. X    { "tuesday",     weekday,     2,     DAYS,      },
  1178. X    { "wednesday",     weekday,     3,     DAYS,      },
  1179. X    { "thursday",     weekday,     4,     DAYS,      },
  1180. X    { "friday",     weekday,     5,     DAYS,      },
  1181. X    { "saturday",     weekday,     6,     DAYS,      },
  1182. X    { "tomorrow",     weekday,     7,     DAYS,      },
  1183. X    { "today",     weekday,     8,     DAYS,      },
  1184. X    { "january",     smonth,         0,     DAYS,      },
  1185. X    { "february",     smonth,         1,     DAYS,      },
  1186. X    { "march",     smonth,         2,     DAYS,      },
  1187. X    { "april",     smonth,         3,     DAYS,      },
  1188. X    { "may",         smonth,         4,     DAYS,      },
  1189. X    { "june",         smonth,         5,     DAYS,      },
  1190. X    { "july",         smonth,         6,     DAYS,      },
  1191. X    { "august",     smonth,         7,     DAYS,      },
  1192. X    { "september",     smonth,         8,     DAYS,      },
  1193. X    { "october",     smonth,         9,     DAYS,      },
  1194. X    { "november",     smonth,         10,     DAYS,      },
  1195. X    { "december",     smonth,         11,     DAYS,      },
  1196. X    { "",         0,         0,     0,      }
  1197. X};
  1198. X
  1199. X
  1200. Xstatic char daysinmonth[12] = 
  1201. X{
  1202. X    31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  1203. X};
  1204. X
  1205. X
  1206. Xstatic int hour, minute, second, day, year, dayofweek, month;
  1207. Xstatic int settime, setday, setyear, setdayofweek, setmonth;
  1208. Xstatic int setweek, err, setmod;
  1209. Xstatic char *curarg;
  1210. Xstatic struct tm *tim;
  1211. Xstatic int gtype;        /* global `type' arg */
  1212. Xstatic short silent;
  1213. X
  1214. Xlong
  1215. Xmaketime(argc, argv, type)
  1216. Xint argc;
  1217. Xchar **argv;
  1218. Xint type;
  1219. X{
  1220. X    struct tm *localtime();
  1221. X    long time(), construct(), now, then;
  1222. X
  1223. X    if (type == STIMES)
  1224. X        type = TIMES, silent = 1;
  1225. X    else
  1226. X        silent = 0;
  1227. X    gtype = type;
  1228. X    now = time((long *) 0);
  1229. X    tim = localtime(&now);
  1230. X
  1231. X    /*
  1232. X     * set defaults 
  1233. X     */
  1234. X    hour = tim->tm_hour;
  1235. X    minute = tim->tm_min;
  1236. X    second = tim->tm_sec;
  1237. X    day = tim->tm_mday;
  1238. X    year = tim->tm_year + 1900;
  1239. X    dayofweek = tim->tm_wday;
  1240. X    month = tim->tm_mon;
  1241. X
  1242. X    settime = setday = setyear = setdayofweek = setmonth = 0;
  1243. X    setweek = err = setmod = 0;
  1244. X
  1245. X    while (argc--)
  1246. X        timearg(curarg = *argv++);
  1247. X    if (err)
  1248. X        return (long) 0;
  1249. X
  1250. X    checktime();
  1251. X    if (err)
  1252. X        return (long) 0;
  1253. X
  1254. X    then = construct();
  1255. X    /*
  1256. X    if(now > then)
  1257. X    {
  1258. X        error("Time specified has passed.");
  1259. X        return (long) 0;
  1260. X    }
  1261. X*/
  1262. X    return then;
  1263. X}
  1264. X
  1265. X
  1266. Xstatic
  1267. Xtimearg(s)
  1268. Xchar *s;
  1269. X{
  1270. X    lower(s);
  1271. X    if (isdigit(*s))
  1272. X        numbers(s);
  1273. X    else
  1274. X        words(s);
  1275. X}
  1276. X
  1277. X
  1278. Xstatic
  1279. Xlower(s)
  1280. Xregister char *s;
  1281. X{
  1282. X    while (*s) {
  1283. X        *s = tolower(*s);
  1284. X        s++;
  1285. X    }
  1286. X}
  1287. X
  1288. X
  1289. Xstatic
  1290. Xnumbers(s)
  1291. Xregister char *s;
  1292. X{
  1293. X    register int val;
  1294. X
  1295. X    val = 0;
  1296. X    while (isdigit(*s))
  1297. X        val = val * 10 + *s++ - '0';
  1298. X    if (val > 1900)
  1299. X        if (setyear++)
  1300. X            reperror("year");
  1301. X        else
  1302. X            year = val;
  1303. X    else if (*s == '\0')
  1304. X        if (setday++)
  1305. X            reperror("day");
  1306. X        else
  1307. X            day = val;
  1308. X    else if (settime++)
  1309. X        reperror("time");
  1310. X    else
  1311. X     {
  1312. X        hour = val;
  1313. X        if (*s == ':') {
  1314. X            s++;
  1315. X            val = 0;
  1316. X            while (isdigit(*s))
  1317. X                val = val * 10 + *s++ - '0';
  1318. X            minute = val;
  1319. X            if (*s == ':') {
  1320. X                s++;
  1321. X                val = 0;
  1322. X                while (isdigit(*s))
  1323. X                    val = val * 10 + *s++ - '0';
  1324. X                second = val;
  1325. X            } else
  1326. X                second = 0;
  1327. X        } else
  1328. X            minute = second = 0;
  1329. X    }
  1330. X    if (*s)
  1331. X        words(curarg = s);
  1332. X}
  1333. X
  1334. X
  1335. Xstatic
  1336. Xreperror(s)
  1337. Xchar *s;
  1338. X{
  1339. X    error("Repeated %s argument: \"%s\"", s, curarg);
  1340. X}
  1341. X
  1342. X
  1343. X/* VARARGS1 */
  1344. Xstatic
  1345. Xerror(s, a1, a2, a3, a4)
  1346. Xchar *s;
  1347. Xint a1, a2, a3, a4;
  1348. X{
  1349. X    err++;
  1350. X    if (silent)
  1351. X        return;
  1352. X    (void) fprintf(stderr, "Error in time specification: ");
  1353. X    (void) fprintf(stderr, s, a1, a2, a3, a4);
  1354. X    (void) fprintf(stderr, "\n");
  1355. X}
  1356. X
  1357. X
  1358. Xstatic
  1359. Xwords(s)
  1360. Xchar *s;
  1361. X{
  1362. X    register struct slist *sp, *found;
  1363. X    register int size;
  1364. X    register char *wstart;
  1365. X
  1366. X    sp = slist;
  1367. X    wstart = s;
  1368. X    size = 0;
  1369. X    while (*s && !isdigit(*s))
  1370. X        size++, s++;
  1371. X    found = (struct slist *) 0;
  1372. X    while (*(sp->s_name)) {
  1373. X        if (sp->s_type <= gtype && CMPN(sp->s_name, wstart, size) ==
  1374. X            0)
  1375. X            if (!found) {
  1376. X                found = sp;
  1377. X                if (strlen(sp->s_name) == size)
  1378. X                    break;    /* otherwise an abbreviation */
  1379. X            }
  1380. X            else
  1381. X             {
  1382. X                error("Ambiguous abbreviation: \"%.*s\"", size,
  1383. X                     wstart);
  1384. X                return;
  1385. X            }
  1386. X        sp++;
  1387. X    }
  1388. X    if (found)
  1389. X        (*(found->s_action))(found->s_val);
  1390. X    else
  1391. X        error("Unknown word: \"%.*s\"", size, wstart);
  1392. X    if (*s)
  1393. X        numbers(curarg = s);
  1394. X}
  1395. X
  1396. X
  1397. Xstatic
  1398. Xtimemod(val)
  1399. Xint val;
  1400. X{
  1401. X    if (!settime)
  1402. X        error("Can only use \"am\" or \"pm\" after a time.");
  1403. X    else if (setmod++)
  1404. X        reperror("time modifier");
  1405. X    else if (hour < 12)
  1406. X        hour += val;
  1407. X    else if (hour > 12)
  1408. X        error("Can't use \"am\" or \"pm\" with 24 hour clock.");
  1409. X    else if (val == 0) /* am && hour == 12 */
  1410. X        hour = 0;    /* 12am correction */
  1411. X}
  1412. X
  1413. X
  1414. Xstatic
  1415. Xnoonmid(val)
  1416. Xint val;
  1417. X{
  1418. X    if (val < 0)    /* NOW */ {
  1419. X        if (settime++)
  1420. X            reperror("time");
  1421. X        /* let defaults work */
  1422. X    } else if (setmod++) /* noon, midnight */
  1423. X        reperror("time modifier");
  1424. X    else
  1425. X     {
  1426. X        if (!settime)
  1427. X            settime++;
  1428. X        else if (hour != 12 || minute != 0 || second != 0)
  1429. X            error("Illegal time: %02d:%02d:%02d %s", hour, minute,
  1430. X                 second, curarg);
  1431. X        hour = val;
  1432. X        minute = second = 0;
  1433. X    }
  1434. X}
  1435. X
  1436. X
  1437. Xstatic
  1438. Xdaymod()
  1439. X{
  1440. X    if (setweek++)
  1441. X        reperror("\b");
  1442. X    else if (!setdayofweek)
  1443. X        error("Can only use \"week\" after a weekday name.");
  1444. X    else
  1445. X        dayofweek += 7;
  1446. X}
  1447. X
  1448. X
  1449. Xstatic
  1450. Xweekday(val)
  1451. Xint val;
  1452. X{
  1453. X    if (setday++)
  1454. X        reperror("day");
  1455. X    else
  1456. X     {
  1457. X        setdayofweek++;
  1458. X        if (val < 7) {
  1459. X            dayofweek = val - dayofweek;    /* now a displacement */
  1460. X            if (dayofweek <= 0)
  1461. X                dayofweek += 7;
  1462. X        } else if (val == 7) /* tomorrow */
  1463. X            dayofweek = 1;
  1464. X        else    /* today */
  1465. X            dayofweek = 0;
  1466. X    }
  1467. X}
  1468. X
  1469. X
  1470. Xstatic
  1471. Xsmonth(val)
  1472. Xint val;
  1473. X{
  1474. X    if (setmonth++)
  1475. X        reperror("day of month");
  1476. X    else
  1477. X        month = val;
  1478. X}
  1479. X
  1480. X
  1481. Xstatic
  1482. Xchecktime()
  1483. X{
  1484. X    register int dim;
  1485. X
  1486. X    if (gtype == DAYS && settime)
  1487. X        error("Times are not accepted.");
  1488. X    if (year < 1983 || year > 2038)
  1489. X        error("Year out of range.");
  1490. X    if (hour > 23 || minute > 59 || second > 59)
  1491. X        error("Illegal time: %02d:%02d:%02d", hour, minute, second);
  1492. X    if (!setdayofweek) {
  1493. X        dim = daysinmonth[month] + (month == 1 ? leapyear(year) : 0);
  1494. X        if (day > dim)
  1495. X            error("Month day out of range. (> %d)", dim);
  1496. X    }
  1497. X    if (setdayofweek && (setmonth || setyear))
  1498. X        error("Can't specify a weekday as well as a month or year.");
  1499. X}
  1500. X
  1501. X
  1502. Xstatic
  1503. Xleapyear(y)
  1504. Xint y;
  1505. X{
  1506. X    return ((y % 4) == 0 && (y % 100) != 0) || (y % 400 == 0);
  1507. X}
  1508. X
  1509. X
  1510. Xstatic long 
  1511. Xconstruct()
  1512. X{
  1513. X    register int i, days;
  1514. X
  1515. X    adjust();
  1516. X    days = DAYSTO1983;
  1517. X    for (i = 1983; i < year; i++)
  1518. X        days += 365 + leapyear(i);
  1519. X    for (i = 0; i < month; i++)
  1520. X        days += daysinmonth[i] + (i == 1 ? leapyear(year) : 0);
  1521. X    days += day - 1;    /* days since 1 Jan 1970 */
  1522. X    if (setdayofweek)
  1523. X        days += dayofweek;
  1524. X    return days * SECINDAY + hour * SECINHOUR + minute * SECINMIN + second;
  1525. X}
  1526. X
  1527. X
  1528. Xstatic
  1529. Xadjust()
  1530. X{
  1531. X    register int dim;
  1532. X
  1533. X    /*
  1534. X     * make sure time defaults to the future
  1535. X     */
  1536. X    if (setdayofweek || setyear || month > tim->tm_mon)
  1537. X        return;
  1538. X    if (month < tim->tm_mon) {
  1539. X        year++;
  1540. X        return;
  1541. X    }
  1542. X    /*
  1543. X     * month == tim->tm_mon
  1544. X     */
  1545. X    if (day > tim->tm_mday)
  1546. X        return;
  1547. X    if (day < tim->tm_mday) {
  1548. X        if (setmonth || ++month / 12)
  1549. X            year++, month %= 12;
  1550. X        return;
  1551. X    }
  1552. X    /*
  1553. X     * month == tim->tm_mon && day == tim->tm_mday
  1554. X     */
  1555. X    if ((long)(hour*SECINHOUR + minute*SECINMIN + second) <
  1556. X        (long)(tim->tm_hour*SECINHOUR + tim->tm_min*SECINMIN + tim->tm_sec)) {
  1557. X        dim = daysinmonth[month] + (month == 1? leapyear(month): 0);
  1558. X        if (setday || ++day / dim) {
  1559. X            if (setmonth || ++month / 12)
  1560. X                year++, month %= 12;
  1561. X            day %= dim;
  1562. X        }
  1563. X        return;
  1564. X    }
  1565. X}
  1566. X
  1567. X
  1568. END_OF_FILE
  1569. if test 8785 -ne `wc -c <'rna/maketime.c'`; then
  1570.     echo shar: \"'rna/maketime.c'\" unpacked with wrong size!
  1571. fi
  1572. # end of 'rna/maketime.c'
  1573. fi
  1574. if test -f 'rnews/relaynews.c' -a "${1}" != "-c" ; then 
  1575.   echo shar: Will not clobber existing file \"'rnews/relaynews.c'\"
  1576. else
  1577. echo shar: Extracting \"'rnews/relaynews.c'\" \(9783 characters\)
  1578. sed "s/^X//" >'rnews/relaynews.c' <<'END_OF_FILE'
  1579. X/*
  1580. X * relaynews - relay Usenet news (version C)
  1581. X * See the file COPYRIGHT for the copyright notice.
  1582. X *
  1583. X * relaynews should be setuid-news, setgid-news.  You'll need to install
  1584. X * setnewsids setuid-root if setuid(geteuid()) doesn't work on your
  1585. X * machine (e.g. on V7 and possibly SystemIII).
  1586. X *
  1587. X * Written by Geoff Collyer, 15-20 November 1985 and revised periodically
  1588. X * since.
  1589. X *
  1590. X * relaynews parses Newsgroups: headers, rejects articles by newsgroup &
  1591. X * message-id, files articles, updates the active & history files,
  1592. X * transmits articles, and honours (infrequent) control messages, which do
  1593. X * all sorts of varied and rococo things.  Control messages are implemented
  1594. X * by separate programs.  relaynews reads a "sys" file to control the
  1595. X * transmission of articles but can function as a promiscuous leaf node
  1596. X * without one.
  1597. X *
  1598. X * A truly radical notion: people may over-ride via environment variables
  1599. X * the compiled-in default directories so IHCC kludges are not needed and
  1600. X * testing is possible (and encouraged) in alternate directories.  This
  1601. X * does cause a loss of privilege, to avoid spoofing.
  1602. X *
  1603. X * The disused I-have/send-me protocol is going to work; it's been broken
  1604. X * in B news for ages but no one has noticed because it's essentially
  1605. X * useless on the uucp network, especially when batching news articles,
  1606. X * but NNTP may breathe new life into it.
  1607. X *
  1608. X * Portability vs SystemV.  relaynews uses dbm(3) and makes no apologies
  1609. X * for so doing.  Imitation UNIX (registered trademark of AT&T in the
  1610. X * United States) brand operating systems that lack dbm are going to
  1611. X * have to use my incredibly slow dbm simulation.
  1612. X */
  1613. X
  1614. X#include <stdio.h>
  1615. X#include <ctype.h>
  1616. X#include <errno.h>
  1617. X#include <signal.h>        /* to make locking safe */
  1618. X#include <sys/types.h>
  1619. X
  1620. X#include "news.h"
  1621. X#include "newspaths.h"
  1622. X#include "active.h"
  1623. X#include "cpu.h"
  1624. X#include "headers.h"
  1625. X#include "system.h"
  1626. X
  1627. X/*
  1628. X * setuid-root program to set ids to news/news & rexec rnews with
  1629. X * NEWSPERMS in the environment to break loops.
  1630. X */
  1631. X#ifndef SETNEWSIDS
  1632. X#define SETNEWSIDS "setnewsids"
  1633. X#endif
  1634. X
  1635. X#ifndef NEWSUSER
  1636. X#define NEWSUSER "news"
  1637. X#endif
  1638. X#ifndef NEWSGROUP
  1639. X#define NEWSGROUP "news"
  1640. X#endif
  1641. X
  1642. Xchar *progname;
  1643. X
  1644. Xint remote = NO;            /* articles are being relayed? */
  1645. X
  1646. Xchar *exclude = NULL;            /* site to exclude, for erik */
  1647. Xstatic int userealids = NO;
  1648. X
  1649. X/*
  1650. X * main - parse arguments and handle options, lock & unlock news system.
  1651. X */
  1652. Xmain(argc, argv)
  1653. Xint argc;
  1654. Xchar *argv[];
  1655. X{
  1656. X    int c, errflg = 0;
  1657. X    int status = ST_OKAY;
  1658. X    char origdir[MAXFILE];        /* current directory at start */
  1659. X    char *newpath;
  1660. X    extern int optind;
  1661. X    extern char *optarg;
  1662. X
  1663. X    progname = argv[0];
  1664. X
  1665. X    /* setuid daemon prelude; various precautions */
  1666. X    (void) umask(newsumask());    /* undo silly umasks */
  1667. X    (void) alarm(0);        /* cancel any pending alarm */
  1668. X    /*
  1669. X     * Reset certain environment variables to sane values.
  1670. X     */
  1671. X    newpath = malloc(STRLEN("PATH=") + STRLEN(STDPATH) + 1);
  1672. X    if (newpath == NULL)
  1673. X        exit(1);        /* no chatter until stdfdopen */
  1674. X    (void) strcpy(newpath, "PATH=");
  1675. X    (void) strcat(newpath, STDPATH);
  1676. X    if (!putenv(newpath) ||
  1677. X        !putenv("IFS= \t\n"))
  1678. X        exit(1);        /* no chatter until stdfdopen */
  1679. X    closeall(1);            /* closes all but std descriptors */
  1680. X    stdfdopen();            /* ensure standard descriptors are open */
  1681. X
  1682. X    setids(argv);            /* change of real and effective ids */
  1683. X    /* we are now running as news, so you can all relax */
  1684. X
  1685. X    /* ignore signals (for locking). relaynews runs quickly, so don't worry. */
  1686. X    (void) signal(SIGINT, (sigarg_t)SIG_IGN);
  1687. X    (void) signal(SIGQUIT, (sigarg_t)SIG_IGN);
  1688. X    (void) signal(SIGHUP, (sigarg_t)SIG_IGN);
  1689. X    (void) signal(SIGTERM, (sigarg_t)SIG_IGN);
  1690. X
  1691. X    /* parse options & set flags */
  1692. X    while ((c = getopt(argc, argv, "pd:x:")) != EOF)
  1693. X        switch (c) {
  1694. X        case 'p':        /* "rnews" mode: */
  1695. X            ++remote;    /* just relay, don't fuck about */
  1696. X            break;
  1697. X        /* all options below are new in C news */
  1698. X        case 'd':        /* -d debug-options; thanks, henry */
  1699. X            if (!debugon(optarg))
  1700. X                errflg++;    /* debugon already complained */
  1701. X            break;
  1702. X        case 'x':            /* -x site: don't send to site */
  1703. X            /* you're welcome, erik */
  1704. X            if (exclude != NULL) {
  1705. X                (void) fprintf(stderr,
  1706. X                    "%s: more than one -x site (%s)\n",
  1707. X                    progname, optarg);
  1708. X                errflg++;
  1709. X            } else
  1710. X                exclude = optarg;
  1711. X            break;
  1712. X        default:
  1713. X            errflg++;
  1714. X            break;
  1715. X        }
  1716. X    if (errflg) {
  1717. X        (void) fprintf(stderr, "usage: %s [-p][-d fhlmt][-x site]\n",
  1718. X            progname);
  1719. X        exit(2);
  1720. X    }
  1721. X
  1722. X    /* lock the news system, set up log files */
  1723. X    newslock();            /* done here due to dbm internal cacheing */
  1724. X    if (remote) {        /* TODO: test this some other way */
  1725. X        redirectlogs();        /* rnews daemon: redirect to logs */
  1726. X#ifdef MANYERRORS
  1727. X        (void) putc('\n', stderr);    /* leave a blank line */
  1728. X        /* prints "Jun  5 12:34:56" */
  1729. X        timestamp(stderr, (time_t *)NULL, (char **)NULL);
  1730. X        (void) putc('\n', stderr);
  1731. X#endif
  1732. X    }
  1733. X
  1734. X    /* process file name arguments */
  1735. X#ifdef RELATIVE_FILES_ALLOWED
  1736. X    if (getwd(origdir) == 0)
  1737. X#endif
  1738. X        (void) strncpy(origdir, "/dunno/man/like/somewhere.", MAXFILE);
  1739. X    cd(fullartfile((char *)NULL));        /* move to spool directory */
  1740. X
  1741. X    if (optind == argc)
  1742. X        status |= process(stdin, "stdin");
  1743. X    else
  1744. X        for (; optind < argc; optind++)
  1745. X            status |= relnmprocess(argv[optind], origdir);
  1746. X
  1747. X    trclose();            /* close open batch files */
  1748. X    status |= synccaches();        /* just being cautious */
  1749. X    newsunlock();            /* unlock the news system */
  1750. X    exit(status);
  1751. X}
  1752. X
  1753. Xsetids(argv)                /* change of real and effective ids */
  1754. Xchar **argv;
  1755. X{
  1756. X    int newsuid = getuid(), newsgid = getgid();    /* default to real ids */
  1757. X
  1758. X    (void) ctlfile((char *)NULL);    /* trigger unprivileged(), set userealids */
  1759. X    if (!userealids) {
  1760. X        /*
  1761. X         * If setuid(geteuid()) fails, try execing a small,
  1762. X         * setuid-root program to just do getpwnam(), getgrnam()
  1763. X         * (with NEWSPERMS set), setgid(), setuid(),
  1764. X         * and exec this program again.  If NEWSPERMS is set,
  1765. X         * the failure is a fatal error (recursive loop).
  1766. X         * Then this program can be setuid-news.
  1767. X         */
  1768. X        (void) setgid(getegid());
  1769. X        if (setuid(geteuid()) < 0) {
  1770. X            if (getenv("NEWSPERMS") != 0)
  1771. X                error("recursive loop setting ids", "");
  1772. X            execv(libfile(SETNEWSIDS), argv);
  1773. X            error("can't exec %s to set ids", libfile(SETNEWSIDS));
  1774. X            /* NOTREACHED */
  1775. X        }
  1776. X        /* you can relax, we are now running as news */
  1777. X    } else {
  1778. X        (void) setgid(newsgid);
  1779. X        (void) setuid(newsuid);
  1780. X    }
  1781. X    /* we are now running as news, so you can all relax */
  1782. X}
  1783. X
  1784. Xvoid
  1785. Xunprivileged()            /* called if NEWSARTS, NEWSCTL or NEWSBIN present */
  1786. X{
  1787. X    userealids = YES;
  1788. X}
  1789. X
  1790. Xint                    /* YES/NO */
  1791. Xdebugon(dbopt)
  1792. Xregister char *dbopt;
  1793. X{
  1794. X    int status = YES;
  1795. X
  1796. X    for (; *dbopt != '\0'; dbopt++)
  1797. X        switch (*dbopt) {
  1798. X        case 'f':
  1799. X            filedebug(YES);
  1800. X            break;
  1801. X        case 'h':
  1802. X            hdrdebug(YES);
  1803. X            break;
  1804. X        case 'l':
  1805. X            lockdebug(YES);
  1806. X            break;
  1807. X        case 'm':
  1808. X            matchdebug(YES);
  1809. X            break;
  1810. X        case 't':
  1811. X            transdebug(YES);
  1812. X            break;
  1813. X        default:
  1814. X            status = NO;    /* unknown debugging option */
  1815. X            (void) fprintf(stderr, "%s: bad -d %c\n",
  1816. X                progname, *dbopt);
  1817. X            break;
  1818. X        }
  1819. X    return status;
  1820. X}
  1821. X
  1822. X/*
  1823. X * Redirect stdout and stderr into log files at known locations.
  1824. X */
  1825. Xredirectlogs()
  1826. X{
  1827. X    logfile(stdout, libfile("log"));
  1828. X    logfile(stderr, libfile("errlog"));
  1829. X}
  1830. X
  1831. Xlogfile(stream, name)            /* redirect stream into name */
  1832. XFILE *stream;
  1833. Xchar *name;
  1834. X{
  1835. X    if (freopen(name, "a", stream) == NULL)
  1836. X        errunlock("can't redirect standard stream to %s", name);
  1837. X}
  1838. X
  1839. Xint                    /* status */
  1840. Xrelnmprocess(name, origdir)        /* process a (relative) file name */
  1841. Xchar *name, *origdir;
  1842. X{
  1843. X    register int status = ST_OKAY;
  1844. X    register FILE *in;
  1845. X    register char *fullname;
  1846. X
  1847. X    fullname = emalloc((unsigned)strlen(origdir) + STRLEN(SFNDELIM) +
  1848. X        strlen(name) + 1);
  1849. X    fullname[0] = '\0';
  1850. X
  1851. X    if (name[0] != FNDELIM) {    /* relative path */
  1852. X        (void) strcat(fullname, origdir);
  1853. X        (void) strcat(fullname, SFNDELIM);
  1854. X    }
  1855. X    (void) strcat(fullname, name);
  1856. X
  1857. X    in = fopen(fullname, "r");
  1858. X    if (in == NULL)
  1859. X        warning("can't open argument `%s'", fullname);
  1860. X    else {
  1861. X        status |= process(in, fullname);
  1862. X        (void) fclose(in);
  1863. X    }
  1864. X    free(fullname);
  1865. X    return status;
  1866. X}
  1867. X
  1868. X/*
  1869. X * process - process input file
  1870. X * If it starts with '#', assume it's a batch and unravel it,
  1871. X * else it's a single article, so just inject it.
  1872. X */
  1873. Xint
  1874. Xprocess(in, inname)
  1875. XFILE *in;
  1876. Xchar *inname;
  1877. X{
  1878. X    register int c;
  1879. X
  1880. X    if ((c = getc(in)) == EOF)
  1881. X        return ST_OKAY;         /* normal EOF */
  1882. X    (void) ungetc(c, in);
  1883. X    if (c == '#')
  1884. X        return unbatch(in, inname);
  1885. X    else
  1886. X        /* ST_SHORT should always come on with a count of MAXLONG */
  1887. X        return cpinsart(in, inname, MAXLONG) & ~ST_SHORT;
  1888. X}
  1889. X
  1890. X/*
  1891. X * Unwind in and insert each article.
  1892. X * For each article, call cpinsart to copy the article
  1893. X * from in into a temporary file and rename the temp file
  1894. X * into the news spool directory.
  1895. X */
  1896. Xint
  1897. Xunbatch(in, inname)
  1898. XFILE *in;
  1899. Xchar *inname;
  1900. X{
  1901. X    register int c;
  1902. X    long charcnt;
  1903. X    int status = ST_OKAY;
  1904. X    char line[MAXLINE];
  1905. X
  1906. X    while (!(status&ST_DISKFULL) && (c = getc(in)) != EOF) {
  1907. X        (void) ungetc(c, in);
  1908. X        /*
  1909. X         * While out of sync, eat input lines,
  1910. X         * then eat the tail end of the "#! rnews" line.
  1911. X         */
  1912. X        while (fgets(line, sizeof line, in) != NULL &&
  1913. X            !batchln(line, &charcnt)) {
  1914. X            status |= ST_DROPPED;        /* argh! a bad batch */
  1915. X            (void) fprintf(stderr, "%s: unbatcher out of synch, tossing: ",
  1916. X                progname);
  1917. X                (void) fputs(line, stderr);
  1918. X        }
  1919. X        if (!feof(in))
  1920. X            status |= cpinsart(in, inname, charcnt);
  1921. X    }
  1922. X    return status;
  1923. X}
  1924. X
  1925. X/*
  1926. X * Is line a batcher-produced line (#! rnews count)?
  1927. X * If so, return the count through charcntp.
  1928. X * This is slightly less convenient than sscanf, but a lot smaller.
  1929. X */
  1930. Xint                    /* YES/NO */
  1931. Xbatchln(line, charcntp)
  1932. Xregister char *line;
  1933. Xregister long *charcntp;
  1934. X{
  1935. X    register char *countp;
  1936. X    static char batchtext[] = "#! rnews ";
  1937. X
  1938. X    countp = line + STRLEN(batchtext);
  1939. X    if (STREQN(line, batchtext, STRLEN(batchtext)) &&
  1940. X        isascii(*countp) && isdigit(*countp)) {
  1941. X        *charcntp = atol(countp);
  1942. X        return YES;
  1943. X    } else {
  1944. X        *charcntp = 0;
  1945. X        return NO;
  1946. X    }
  1947. X}
  1948. END_OF_FILE
  1949. if test 9783 -ne `wc -c <'rnews/relaynews.c'`; then
  1950.     echo shar: \"'rnews/relaynews.c'\" unpacked with wrong size!
  1951. fi
  1952. # end of 'rnews/relaynews.c'
  1953. fi
  1954. if test -f 'rnews/transmit.c' -a "${1}" != "-c" ; then 
  1955.   echo shar: Will not clobber existing file \"'rnews/transmit.c'\"
  1956. else
  1957. echo shar: Extracting \"'rnews/transmit.c'\" \(7923 characters\)
  1958. sed "s/^X//" >'rnews/transmit.c' <<'END_OF_FILE'
  1959. X/*
  1960. X * transmit - transmit incoming articles to neighbouring machines
  1961. X * TODO: deal with multiple references to the same batch file.
  1962. X */
  1963. X
  1964. X#include <stdio.h>
  1965. X#include <ctype.h>
  1966. X#include <sys/types.h>
  1967. X#include "news.h"
  1968. X#include "newspaths.h"
  1969. X#include "headers.h"
  1970. X#include "system.h"
  1971. X
  1972. X#define NOPENTFS 10    /* # of file descriptors kept open for batching */
  1973. X
  1974. Xstatic FILE *tfs[NOPENTFS];            /* keep these open always */
  1975. Xstatic int debug = NO;
  1976. X
  1977. Xtransdebug(state)
  1978. Xint state;
  1979. X{
  1980. X    debug = state;
  1981. X}
  1982. X
  1983. X/*
  1984. X * For each system in "sys" other than this one,
  1985. X * transmit this article when its ng pattern matches
  1986. X * hdrs->h_distr (which may be just a copy of hdrs->h_ngs).
  1987. X */
  1988. Xint
  1989. Xtransmit(hdrs, rmt, exclude)
  1990. Xregister struct headers *hdrs;
  1991. Xint rmt;                    /* inews/rnews flag */
  1992. Xchar *exclude;                    /* no copy to him */
  1993. X{
  1994. X    register struct system *sys;
  1995. X    register int fno = 0;
  1996. X    int status = 0;
  1997. X
  1998. X    rewsys();
  1999. X    if (debug)
  2000. X        (void) fprintf(stderr, "just rewound sys file\n");
  2001. X    while ((sys = nextsys()) != NULL) {
  2002. X        if (debug) {
  2003. X            (void) fprintf(stderr, "hdrs->h_distr=%s\n",
  2004. X                hdrs->h_distr);
  2005. X            (void) fprintf(stderr, "sy_name=%s sy_ngs=%s\n",
  2006. X                sys->sy_name, sys->sy_ngs);
  2007. X        }
  2008. X        if (oktransmit(hdrs, sys, sys->sy_flags, rmt, exclude))
  2009. X            status |= ejaculate(hdrs, sys, fno);
  2010. X        if (sys->sy_flags&(FLG_BATCH|FLG_SZBATCH))
  2011. X            ++fno;        /* count lines with F or f flag */
  2012. X    }
  2013. X    if (debug)
  2014. X        (void) fprintf(stderr, "just finished reading sys file\n");
  2015. X    return status;             
  2016. X}
  2017. X
  2018. X/*
  2019. X * Is it okay to send the article corresponding to hdrs to sys,
  2020. X * given flags (derived from sys) and rmt?
  2021. X *
  2022. X * Never send to this host, nor any host named in Path:.
  2023. X * Newsgroups must match sys's subscription list.
  2024. X * Also, Distribution: must match sys's distribution list.
  2025. X * If L flag is on, must be a local posting.
  2026. X *
  2027. X * TODO: implement Ln restriction:
  2028. X *    forward articles generated within sysp->sy_lochops hops of here.
  2029. X * TODO: implement exclusions by site, from sy_excl (can be NULL).
  2030. X */
  2031. Xstatic int
  2032. Xoktransmit(hdrs, sys, flags, rmt, exclude)
  2033. Xregister struct headers *hdrs;
  2034. Xregister struct system *sys;
  2035. Xint flags, rmt;
  2036. Xchar *exclude;                /* no copy to him */
  2037. X{
  2038. X    return (!(flags&FLG_LOCAL) || !rmt) &&        /* local & */
  2039. X        !STREQ(hostname(), sys->sy_name) &&        /* not to ME & */
  2040. X        (exclude == NULL || !STREQ(exclude, sys->sy_name)) &&    /* not excluded & */
  2041. X        (hdrs->h_path == NULL || !hostin(hdrs->h_path, sys->sy_name)) &&    /* not been here & */
  2042. X        ngmatch(sys->sy_ngs, hdrs->h_ngs) &&    /* ngs match & */
  2043. X        /* RFC 850 is wrong, yea, verily: Distribution:s are *not* patterns */
  2044. X        ngmatch(sys->sy_distr, hdrs->h_distr);    /* distrs match! */
  2045. X}
  2046. X
  2047. X/*
  2048. X * send the article denoted by hdrs to the system denoted by sys.
  2049. X */
  2050. XSTATIC int                /* status */
  2051. Xejaculate(hdrs, sys, fno)        /* kick the article to its reward */
  2052. Xregister struct headers *hdrs;
  2053. Xregister struct system *sys;
  2054. Xint fno;
  2055. X{
  2056. X    int status = ST_OKAY;
  2057. X    char filename[MAXLINE];
  2058. X    char *fullname;
  2059. X
  2060. X        /* can't use hdrs->h_tmpf because we need a permanent name */
  2061. X    first(hdrs->h_files, filename);
  2062. X    mkfilenm(filename);
  2063. X        (void) printf(" %s", sys->sy_name);    /* logging */
  2064. X    if (debug)
  2065. X        (void) fprintf(stderr, "transmitting %s to %s\n",
  2066. X            hdrs->h_msgid, sys->sy_name);
  2067. X
  2068. X        /* must supply a full pathname to the outside world */
  2069. X        fullname = fullspoolfile(filename);
  2070. X    if (sys->sy_flags&(FLG_BATCH|FLG_SZBATCH))
  2071. X            status |= trbatch(sys, hdrs, fullname, fno);
  2072. X    else
  2073. X            status |= trcmd(sys, fullname);
  2074. X    return status;
  2075. X}
  2076. X
  2077. X/*
  2078. X * Append filename to sys->sy_cmd. fno is the ordinal number of this sys line.
  2079. X * If fno is low enough, use the tfs cache of batch file descriptors.
  2080. X */
  2081. Xint
  2082. Xtrbatch(sys, hdrs, filename, fno)
  2083. Xstruct system *sys;
  2084. Xstruct headers *hdrs;
  2085. Xchar *filename;
  2086. Xregister int fno;
  2087. X{
  2088. X    register int status = 0;
  2089. X    char *batfile = sys->sy_cmd;
  2090. X
  2091. X    if (fno >= NOPENTFS) {                /* not cachable */
  2092. X        register FILE *batchf = fopenclex(batfile, "a");
  2093. X
  2094. X        if (batchf == NULL) {
  2095. X            warning("can't open batch file %s", batfile);
  2096. X            status |= ST_DROPPED;
  2097. X        } else {
  2098. X            status |= trappend(batchf, sys, hdrs, filename);
  2099. X            if (fclose(batchf) == EOF)
  2100. X                status = fulldisk(status|ST_DROPPED, batfile);
  2101. X        }
  2102. X    } else {                    /* cachable */
  2103. X        if (tfs[fno] == NULL) {            /* closed */
  2104. X            tfs[fno] = fopenclex(batfile, "a");
  2105. X            if (tfs[fno] == NULL) {        /* didn't open */
  2106. X                register int openf;
  2107. X
  2108. X                /*
  2109. X                 * Assume open failed due to lack of file
  2110. X                 * descriptors.  Find an open one and close it,
  2111. X                 * then retry the open.  Honk at someone too?
  2112. X                 */
  2113. X                for (openf = 0; openf < NOPENTFS; openf++)
  2114. X                    if (tfs[openf] != NULL)    /* open */
  2115. X                        break;
  2116. X                if (openf < NOPENTFS && tfs[openf] != NULL) {
  2117. X                    if (fclose(tfs[openf]) == EOF)
  2118. X                        status = fulldisk(status|ST_DROPPED,
  2119. X                            "some batch file");
  2120. X                    tfs[openf] = NULL;    /* mark closed */
  2121. X                    tfs[fno] = fopenclex(batfile, "a");
  2122. X                }
  2123. X            }
  2124. X        }
  2125. X        if (tfs[fno] == NULL) {            /* still closed! */
  2126. X            warning("can't open batch file %s", batfile);
  2127. X            status |= ST_DROPPED;
  2128. X        } else
  2129. X            status |= trappend(tfs[fno], sys, hdrs, filename);
  2130. X    }
  2131. X    return status;
  2132. X}
  2133. X
  2134. Xstatic int
  2135. Xtrappend(fp, sys, hdrs, name)            /* write name\n on fp */
  2136. Xregister FILE *fp;
  2137. Xregister struct system *sys;
  2138. Xregister struct headers *hdrs;
  2139. Xchar *name;
  2140. X{
  2141. X    int status = ST_OKAY;
  2142. X
  2143. X    if (fputs(name, fp) == EOF)    /* append to batch file */
  2144. X        status = fulldisk(status|ST_DROPPED, "some batch file");
  2145. X    /* for Henry's new batcher */
  2146. X    if (sys->sy_flags&FLG_SZBATCH &&
  2147. X        fprintf(fp, " %ld", hdrs->h_charswritten) == EOF)
  2148. X        status = fulldisk(status|ST_DROPPED, "some batch file");
  2149. X    /* don't check putc return value for portability; use ferror */
  2150. X    (void) putc('\n', fp);
  2151. X    (void) fflush(fp);        /* for crash-proofness */
  2152. X    if (ferror(fp))
  2153. X        status = fulldisk(status|ST_DROPPED, "some batch file");
  2154. X    return status;
  2155. X}
  2156. X
  2157. X/*
  2158. X * Execute sys->sy_cmd with the current article as stdin
  2159. X * and filename substituted for %s in sys->sy_cmd (if any).
  2160. X */
  2161. Xint
  2162. Xtrcmd(sys, filename)
  2163. Xstruct system *sys;
  2164. Xchar *filename;
  2165. X{
  2166. X    int status = ST_OKAY, exitstat;
  2167. X    char *cmd;
  2168. X    char *syscmd = sys->sy_cmd;
  2169. X
  2170. X    cmd = emalloc((unsigned)STRLEN("PATH=") + STRLEN(STDPATH) + STRLEN(" <") +
  2171. X        strlen(filename) + STRLEN(" ") + strlen(syscmd) +
  2172. X        strlen(filename) + 1);
  2173. X    (void) strcpy(cmd, "PATH=");
  2174. X    (void) strcat(cmd, STDPATH);
  2175. X    (void) strcat(cmd, " <");
  2176. X    /*
  2177. X     * redirect stdin to prevent consuming my stdin & so cmd's stdin
  2178. X     * is filename by default.
  2179. X     */
  2180. X    (void) strcat(cmd, filename);
  2181. X    (void) strcat(cmd, " ");
  2182. X    (void) sprintf(cmd+strlen(cmd), syscmd, filename);
  2183. X    exitstat = system(cmd);
  2184. X    if (exitstat != 0) {
  2185. X        extern char *progname;
  2186. X
  2187. X        status |= ST_DROPPED;
  2188. X        (void) fprintf(stderr, "%s: `%s' returned exit status 0%o\n",
  2189. X            progname, cmd, exitstat);
  2190. X    }
  2191. X    free(cmd);
  2192. X    return status;
  2193. X}
  2194. X
  2195. Xtrclose()
  2196. X{
  2197. X    register int fno;
  2198. X
  2199. X    for (fno = 0; fno < NOPENTFS; fno++)
  2200. X        if (tfs[fno] != NULL) {
  2201. X            (void) fclose(tfs[fno]);
  2202. X            tfs[fno] = NULL;
  2203. X        }
  2204. X}
  2205. X
  2206. X/*
  2207. X * Return true iff host appears in s, with no characters from the alphabet
  2208. X * of legal hostname characters immediately adjacent.
  2209. X * This function is a profiling hot spot, so it has been optimised.
  2210. X */
  2211. Xint
  2212. Xhostin(s, host)
  2213. Xregister char *s, *host;
  2214. X{
  2215. X    register int hostlen = strlen(host);
  2216. X    register int ch;        /* use by hostchar macro */
  2217. X
  2218. X/* If c is NUL, hostchar will be false, so don't test (optimisation: ==). */
  2219. X#define nothostchar(c) (!hostchar(c) /* || (c) == '\0' */ )    /* ! or EOS */
  2220. X/*
  2221. X * True if c can be part of a hostname. RFC 850 allows letters, digits, periods,
  2222. X * and hyphens and specifically disallows blanks. False may mean c is NUL.
  2223. X */
  2224. X#define hostchar(c) (ch = (c) , \
  2225. X    (isascii(ch) && (isalnum(ch) || (ch) == '.' || (ch) == '-')))
  2226. X
  2227. X    /*
  2228. X     * Special case: match host!path or host.
  2229. X     */
  2230. X    if (STREQN(s, host, hostlen) && nothostchar(s[hostlen]))
  2231. X        return YES;
  2232. X    /*
  2233. X     * Match path2!host!path or path2!host.
  2234. X     */
  2235. X    while (*s != '\0')
  2236. X        if (hostchar(s[0]))        /* can't start after here */
  2237. X            ++s;
  2238. X        else if ((++s, STREQN(s, host, hostlen)) &&
  2239. X            nothostchar(s[hostlen]))
  2240. X            return YES;
  2241. X    return NO;
  2242. X}
  2243. END_OF_FILE
  2244. if test 7923 -ne `wc -c <'rnews/transmit.c'`; then
  2245.     echo shar: \"'rnews/transmit.c'\" unpacked with wrong size!
  2246. fi
  2247. # end of 'rnews/transmit.c'
  2248. fi
  2249. echo shar: End of archive 10 \(of 14\).
  2250. ##  End of shell archive.
  2251. exit 0
  2252.