home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume1 / vnews / part1 next >
Internet Message Format  |  1986-11-30  |  54KB

  1. From: decvax!vax135!hou3c!ka
  2. Date: Mon, 21 Jan 85 21:39:51 est
  3. Newsgroups: mod.sources
  4. Subject: Vnews part 1
  5.  
  6. # Welcome to release 2.11-B 1/17/85 of vnews.  The -B means that this is
  7. # a prerelease of 2.11 vnews; a release 2.11 of vnews will not be issued
  8. # until a complete release 2.11 of netnews is ready.  Most features pro-
  9. # mised for release 2.11 are here.
  10. # This file is the first of seven files containing the vnews source.  To
  11. # unpack these files, chdir to an empty directory and feed them into the
  12. # shell.  Use the regular shell, not csh.
  13.  
  14. if test ! -d artfile
  15. then    mkdir artfile
  16. fi
  17.  
  18. cat > install.doc <<\!E!O!F!
  19.  
  20.                       HOW TO INSTALL VNEWS
  21.  
  22.  
  23.  
  24. This release is designed to run with release 2.10 or 2.10.1 of
  25. netnews, but should also work with release 2.10.2.  The steps re-
  26. quired to install vnews are:
  27.  
  28. 1)  Modify the transmit routine in inews to support the H flag.
  29. The H flag causes inews to replace a %s in the command with the
  30. contents of the history line.  The directory artfile contains two
  31. versions of the file ifuncs.c.  Ifuncs.c.10.1 is based on release
  32. 2.10.1 while ifuncs.c.10.2 is based on release 2.10.2.  In both
  33. files, the changes can be found by grepping for KSA.  Rebuild
  34. inews with the appropriate version of ifuncs.c.
  35.  
  36. 2)  Vnews has its own configuration program called "setup" which
  37. works on a file named config.  Change directory to lib, and run
  38. the mkconfig program.  This program expects as its single argu-
  39. ment the name of the directory containing the netnews source.
  40. You should probably cat the resulting config file to make sure it
  41. looks reasonable.  Then run the setup shell procedure.  Read
  42. setup.doc if you have problems.
  43.  
  44. 3)  If you have terminals with more than 24 lines or more than 80
  45. columns, increase MAXPLEN and MAXLLEN in vnews/virtterm.c.
  46.  
  47. 4)  The next step is to compile and install all the programs.
  48. Changing directory back to .. and running the compile shell pro-
  49. cedure will compile everything.  Compile will complain if you
  50. have distributions which it doesn't have descriptions for.  If
  51. this happens, add the descriptions to the file postnews/distlist
  52. and run compile again.  Compile -i will install all the programs.
  53. It will also add an entry to your sys file to invoke afinsert
  54. when new articles arrive.
  55.  
  56. 5)  Run /usr/lib/news/afbuild to create artfile and groupfile
  57. from the history file.  (Put it in the background; it's slow.)
  58. Since you don't want artfile to grow without bound, you must re-
  59. build it periodically.  Modify crontab to invoke afbuild after it
  60. calls expire.
  61.  
  62. 6)  You may wish to install vnews/vnews.1 and postnews/postnm.1
  63. in /usr/man.  Also, if you run Gosling's or Warren Montgomery's
  64. EMACS, install postnews/gparent.ml or postnews/gparent.wm,
  65. respectively, in some suitable spot.
  66.                                 Kenneth Almquist
  67. !E!O!F!
  68.  
  69. cat > files.doc <<\!E!O!F!
  70. .. Run this file throuhg nroff without any macro packages.
  71. .hy
  72. .de f
  73. .sp
  74. .ti 0
  75. .if \\w'\\$2' \\$1, installed in \\$2
  76. .if !\\w'\\$2' \\$1
  77. .in 8
  78. ..
  79. .de e
  80. .in 0
  81. ..
  82. This lists the programs and files which are part of vnews.
  83. For each file, the directory where it is installed is given.
  84. .f vnews/vnews /usr/bin
  85. This is the vnews news reading program.
  86. .f postnews/gparent /usr/bin
  87. This simple shell procedure writes writes the body of the article
  88. specified by $A to the standard output.  It is intended for writing
  89. followups which reference the original article.  For example from vi
  90. you can say ":r !gparent" to include the body of the original article
  91. in your followup.  (This only works from vnews because postnews
  92. does not yet set $A.)
  93. .f postnews/postnews /usr/bin
  94. This program allows users to post news items to the network.
  95. This version of postnews is much more sophisticated than the
  96. 2.10.1 version of postnews.  It is rather similar to the 2.10.2
  97. version except that it allows you to search for specific titles
  98. or authors if you don't remember the number of an article you are
  99. writng a followup to.
  100. .f postnews/postnm /usr/bin
  101. This program acts as a front end for inews.  To post news you should
  102. use this program instead of invoking inews directly.
  103. .f lib/cgtdate /usr/lib/news
  104. This is program converts a date to UNIX* internal format.
  105. It is invoked by vnews to process the -a option.
  106. .f postnews/postreply /usr/lib/news
  107. Thie program handles replies and followups for vnews.
  108. .f postnews/distributions /usr/lib/news
  109. This file lists all the legal distributions that users can specify
  110. (world, na, usa, local, etc.).
  111. .f postnews/moderators /usr/lib/news
  112. This file lists the moderators of various moderated groups.
  113. .f artfile/afbuild /usr/lib/news
  114. This program rebuilds /usr/lib/news/artfile from the history file.
  115. It also creates /usr/lib/news/groupfile if that file does not
  116. already exist.  (/usr/lib/news/artfile and /usr/lib/news/groupfile
  117. are described below.)
  118. .f artfile/afinsert /usr/lib/news
  119. This program is invoked by an entry in the sys file every time an
  120. article is received.  Its single argument is the contents of the
  121. history line for the article.  This program adds an entry for the
  122. article to /usr/lib/news/artfile.
  123. .f artfile/dumprec
  124. This program writes out records in artfile.  Each record is specified
  125. either by a message-ID or by its offset from the beginning of artfile.
  126. This program is intended for debugging the artfile code.
  127. .f artfile/dumpng
  128. This program lists the contents of a newsgroup.  It is also intended
  129. for debugging the artfile code, but the information may prove useful
  130. for other purposes.
  131. .f /usr/lib/news/artfile
  132. This file contains one entry for each article in the system.
  133. It can be accessed by various routines in lib/rlib.a; see lib/routines.doc
  134. for details.
  135. .f /usr/lib/news/groupfile
  136. This file associates a small, unique integer with each newsgroup
  137. on the system.
  138. .f postnews/gparent.ml
  139. This is a macro for Gosling's EMACS that reads the body of the article
  140. specified by $A into the current buffer.  It is intended for writing
  141. followups which reference the original article.  Normally, this macro
  142. should be bound to ^X^Y.  Compile -i will not install this anywhere,
  143. but if you run Gosling's EMACS you should install it wherever you have
  144. your macro library.
  145. .f postnews/gparent.wm
  146. This file contains a version of the gparent macro rewritten to run
  147. under Warren Montgomery's EMACS.
  148. !E!O!F!
  149.  
  150. cat > compile <<\!E!O!F!
  151. #!/bin/sh
  152. : This file compiles all of vnews.
  153. : With the -i option, it also installs everything
  154. : The -f option forces a remake of everything.
  155. : The -n option is passed to make.
  156. : Arguments like DEBUG=-g are passed to make.
  157.  
  158. case "$0" in
  159. ../compile)    cd .. ;;
  160. esac
  161.  
  162. . lib/makedefs
  163.  
  164. dirs=
  165. install=
  166. frc=
  167. makedefs=
  168. for x 
  169. do    case "$x" in
  170.     -i)    install=install ;;
  171.     -f)    frc="FRC=FRC" ;;
  172.     -n)    makedefs="-n|$makedefs" ;;
  173.     *=*)    makedefs="$makedefs|$x" ;;
  174.     -*)    echo 'Usage: compile [ -i ] [ directories ]'
  175.         exit 1 ;;
  176.     *)    dirs="$dirs $x" ;;
  177.     esac
  178. done
  179. if test "$dirs" = ""
  180. then    dirs=lib
  181.     for x in *
  182.     do    if test "$x" != lib -a -f $x/genmakefile
  183.         then    dirs="$dirs $x"
  184.         fi
  185.     done
  186. fi
  187.  
  188. cd lib
  189. for x in $dirs
  190. do    echo "Making $x:"
  191.     cd ../$x
  192.     if test "$frc" != "" -o ! -f ../lib/newer || ../lib/newer genmakefile makefile
  193.     then    echo "    genmakefile"
  194.         genmakefile
  195.     fi
  196.     IFS='|'
  197.     echo "    make" $makedefs $frc $install
  198.     make $makedefs $frc $install || exit
  199.     IFS='     
  200. '
  201. done
  202.  
  203. if test "$install" = "" || grep '^artfile:' $LIBDIR/sys > /dev/null
  204. then    :
  205. else    echo adding artfile entry to sys file
  206.     echo "artfile:all:H:$LIBDIR/afinsert \"%s\"" >> $LIBDIR/sys
  207.     echo "Remember to update crontab to invoke $LIBDIR/afbuild every night"
  208. fi
  209. echo Compile all done
  210. !E!O!F!
  211. chmod +x compile
  212.  
  213. cat > artfile/addart.c <<\!E!O!F!
  214. #include <stdio.h>
  215. #include <sys/types.h>
  216. #include "config.h"
  217. #include "defs.h"
  218. #include "arthead.h"
  219. #include "af.h"
  220.  
  221.  
  222. #define equal(s1, s2)    (strcmp(s1, s2) == 0)
  223. char *rindex(), *savestr() ;
  224. char *getaddr() ;
  225. time_t cgtdate() ;
  226. DPTR addrec() ;
  227.  
  228. extern int newgroup ;
  229.  
  230.  
  231. /*
  232.  * Add an article to the data base.
  233.  * Glitches:
  234.  *    Ignore the message id <>, since it is clearly wrong (rn bug).
  235.  *    Ignore message ids without a trailing '>' since probably truncated.
  236.  */
  237.  
  238. addart(h, fname, groups)
  239.       struct arthead *h ;
  240.       char *fname ;
  241.       char *groups ;
  242.       {
  243.       struct artrec a ;
  244.       char buf[128] ;
  245.       char *parlist[32], **pp ;
  246.       struct artgroup *gp ;
  247.       register char *p, *q ;
  248.  
  249.       h->h_subtime = cgtdate(h->h_subdate) ;
  250.       h->h_rectime = cgtdate(h->h_recdate) ;
  251.       if (hset(h->h_expdate))
  252.             h->h_exptime = cgtdate(h->h_expdate) ;
  253.       else
  254.             h->h_exptime = 0L ;
  255.  
  256.       p = groups; gp = a.a_group ;
  257.       while (*p && gp < &a.a_group[MAXNG]) {
  258.             q = buf ;
  259.             while (*p == ' ')
  260.                   p++ ;
  261.             while (*p != '/') {
  262.                   if (*p == '\0')
  263.                         xerror("bad newsgroup list") ;
  264.                   *q++ = *p++ ;
  265.             }
  266.             *q = '\0' ;
  267.             if ((gp->a_ngnum = ngnum(buf)) <= 0) {
  268.                   gp->a_ngnum = newng(buf) ;
  269.                   newgroup++ ;
  270.             }
  271.             p++ ;
  272.             gp->a_artno = atoi(p) ;
  273.             while (*p != ' ' && *p)
  274.                   p++ ;
  275.             gp++ ;
  276.       }
  277.       a.a_ngroups = gp - a.a_group ;
  278.  
  279.       pp = parlist + 31 ; parlist[31] = NULL ;
  280.       p = h->h_references ;
  281.       while (p && *p) {
  282.             if (pp <= parlist)
  283.                   xerror("Too many references") ;
  284.             q = buf ;
  285.             while (*p && *p != ',' && *p != ' ')
  286.                   *q++ = *p++ ;
  287.             *q = '\0' ;
  288.             tomsgid(buf) ;
  289.             if (! equal(buf, "<>"))
  290.                   *--pp = savestr(buf) ;
  291.             while (*p == ' ' || *p == ',')
  292.                   p++ ;
  293.       }
  294.       while (*pp && index(*pp, '>') == 0)
  295.             pp++ ;
  296.       if (strlen(h->h_title) > 127)
  297.             h->h_title[127] = '\0' ;
  298.       getaddr(h->h_from, buf) ;
  299.  
  300.       a.a_subtime = h->h_subtime ;
  301.       a.a_rectime = h->h_rectime ;
  302.       a.a_exptime = h->h_exptime ;
  303.       a.a_parent = DNULL ;
  304.       a.a_children = DNULL ;
  305.       a.a_childchain = DNULL ;
  306.       a.a_nlines = h->h_intnumlines ;
  307.       a.a_flags = 0 ;
  308.       a.a_ident = h->h_ident ;
  309.       a.a_title = h->h_title ;
  310.       a.a_from = buf ;
  311.       a.a_file = fname ;
  312.       a.a_nkwords = 0 ;        /* fix this eventually */
  313.       addrec(&a, pp) ;
  314.  
  315.       while (*pp)
  316.             free(*pp++) ;
  317. }
  318. !E!O!F!
  319.  
  320. cat > artfile/addrec.c <<\!E!O!F!
  321. #include <stdio.h>
  322. #include "af.h"
  323.  
  324.  
  325. static int nchildren ;            /* number of orphaned children */
  326. static DPTR child[200] ;        /* list of orphans */
  327.  
  328. long lseek() ;
  329.  
  330.  
  331. /*
  332.  * Add a record to the data base.
  333.  */
  334.  
  335. DPTR
  336. addrec(a, parlist)
  337.       struct artrec *a ;
  338.       char **parlist ;
  339.       {
  340.       DPTR pos ;
  341.       DPTR idhash, thash ;
  342.       DPTR ngptr[MAXNG] ;
  343.       DPTR dp ;
  344.       int i, j ;
  345.       static char nuls[60] ;
  346.       DPTR htitle();
  347.  
  348.       dorelatives(a, parlist) ;
  349.       idhash = hashid(a->a_ident) ;
  350.       a->a_idchain = readptr(idhash) ;
  351.       if ((a->a_flags & A_DUMMY) == 0) {
  352.             thash = htitle(a->a_title) ;
  353.             a->a_titlechain = readptr(thash) ;
  354.       }
  355.       for (i = 0 ; i < a->a_ngroups ; i++) {
  356.             struct artrec a2 ;
  357.             int ng = a->a_group[i].a_ngnum ;
  358.  
  359.             /* insert record in proper place in chain */
  360.             dp = readptr(ngptr[i] = ngchain(ng)) ;
  361.             while (dp != DNULL) {
  362.                   readrec(dp, &a2) ;
  363.                   for (j = 0 ; ; j++) {
  364.                         if (j >= a2.a_ngroups)
  365.                               xerror("bad newsgroup chain for %d", ng) ;
  366.                         if (a2.a_group[j].a_ngnum == ng)
  367.                               break ;
  368.                   }
  369.                   if (a2.a_group[j].a_artno <= a->a_group[i].a_artno)
  370.                         break ;
  371.                   ngptr[i] = dp + GROUPOFF + stroff(a_ngchain, artgroup) + j * sizeof(struct artgroup) ;
  372.                   dp = a2.a_group[j].a_ngchain ;
  373.             }
  374.             a->a_group[i].a_ngchain = dp ;
  375.       }
  376.       pos = afhd.af_free ;
  377.       lseek(affd, (long)pos, 0) ;
  378.       writerec(a, affd) ;
  379.       afhd.af_free = lseek(affd, 0L, 1) ;
  380.       write(affd, nuls, 60) ;        /* readrec tends to overrun */
  381.       lseek(affd, 0L, 0) ;
  382.       write(affd, (char *)&afhd, sizeof afhd) ;
  383.       writeptr(pos, idhash) ;
  384.       if ((a->a_flags & A_DUMMY) == 0)
  385.             writeptr(pos, thash) ;
  386.       if (a->a_parent)
  387.             writeptr(pos, a->a_parent + CHILDRENOFF) ;
  388.       for (i = 0 ; i < nchildren ; i++) {
  389.             writeptr(pos, child[i] + PARENTOFF) ;
  390.       }
  391.       for (i = 0 ; i < a->a_ngroups ; i++) {
  392.             writeptr(pos, ngptr[i]) ;
  393.       }
  394.       return pos ;
  395. }
  396.  
  397.  
  398.  
  399. /*
  400.  * Find the parents and children of the article.
  401.  * If the references line is present,
  402.  *    create a dummy entry for parent if necessary.
  403.  * If no references line, guess at parent using title.
  404.  * Look for articles without references lines whose titles indicate that
  405.  *    this article might be the parent.
  406.  */
  407.  
  408. dorelatives(a, parlist)
  409.       register struct artrec *a ;
  410.       char **parlist ;
  411.       {
  412.       struct artrec a2 ;
  413.       DPTR dp, dp2, dummy ;
  414.       int i ;
  415.  
  416.       /* first look for parent */
  417.       if (parlist && parlist[0]) {
  418.             if ((a->a_parent = lookart(parlist[0], &a2)) == DNULL) {
  419.                   /* make dummy parent */
  420.                   bzero((char *) &a2, sizeof a2) ;
  421.                   a2.a_ident = parlist[0] ;
  422.                   a2.a_flags = A_DUMMY ;
  423.                   a2.a_rectime = a->a_rectime;
  424.                   a2.a_subtime = a->a_subtime;
  425.                   a->a_parent = addrec(&a2, parlist + 1) ;
  426.             }
  427.       } else if (a->a_title && isre(a->a_title)) {
  428.             for (dp = readptr(htitle(a->a_title)) ; dp != NULL ; dp = a2.a_titlechain) {
  429.                   readrec(dp, &a2) ;
  430.                   if (tparent(&a2, a)) {
  431.                         a->a_parent = dp ;
  432.                         break ;
  433.                   }
  434.             }
  435.       }
  436.       /* check for loops in parent relation */
  437.       if ((dummy = lookart(a->a_ident, &a2)) != DNULL) {
  438.             /* we are replacing a dummy entry with a real one */
  439.             i = 100 ;
  440.             for (dp2 = a->a_parent ; dp2 != DNULL ; dp2 = a2.a_parent) {
  441.                   readrec(dp2, &a2) ;
  442.                   if (dp2 == dummy) {
  443.                         a->a_parent = a2.a_parent ;
  444.                         printf("loop in parent chain for %s found\n", a->a_ident) ;
  445.                         break ;
  446.                   }
  447.                   if (--i < 0) {
  448.                         printf("loop containing %s discovered while updating %s\n",
  449.                               a2.a_ident, a->a_ident) ;
  450.                         break ;
  451.                   }
  452.             }
  453.       }
  454.  
  455.       /* now look for orphans */
  456.       nchildren = 0 ;
  457.       if (dummy != DNULL) {
  458.             /* we are replacing a dummy entry with a real one */
  459.             readrec(dummy, &a2) ;
  460.             if (a2.a_parent != DNULL)
  461.                   rmchain(a2.a_parent + CHILDRENOFF, CHILDCHOFF, dummy) ;
  462.             for (dp = a2.a_children ; dp != DNULL ; dp = a2.a_childchain) {
  463.                   child[nchildren++] = dp ;
  464.                   readrec(dp, &a2) ;
  465.             }
  466.             writeptr(DNULL, dp + CHILDRENOFF) ;
  467.       }
  468.       if (a->a_parent != DNULL) {
  469.             readrec(a->a_parent, &a2);
  470.             a->a_childchain = a2.a_children ;
  471.       } else
  472.             a->a_childchain = DNULL ;
  473.       if ((a->a_flags & A_DUMMY) == 0)
  474.          for (dp = readptr(htitle(a->a_title)) ; dp != DNULL ; dp = a2.a_titlechain) {
  475.             readrec(dp, &a2) ;
  476.             if (a2.a_parent == DNULL && tparent(a, &a2))
  477.                   child[nchildren++] = dp ;
  478.       }
  479.  
  480.       /* link the orhpans together into the child chain */
  481.       child[nchildren] = DNULL ;
  482.       for (i = 0 ; i < nchildren ; i++) {
  483.             DPTR pardp = readptr(child[i] + PARENTOFF) ;    /*DEBUG*/
  484.             if (pardp != DNULL && pardp != dummy)
  485.                   printf("bad orphan %ld: par %ld, dummy %ld\n", child[i], pardp, dummy) ;
  486.             writeptr(child[i + 1], child[i] + CHILDCHOFF) ;
  487.       }
  488.       a->a_children = child[0] ;
  489. }
  490.  
  491.  
  492.  
  493. /* remove an entry from a linked list */
  494.  
  495. rmchain(chain, offset, rec)
  496.       DPTR chain ;
  497.       DPTR rec ;
  498.       {
  499.       DPTR dp ;
  500.       int nremoved = 0 ;    /*DEBUG*/
  501.       DPTR svchain = chain ;    /*DEBUG*/
  502.  
  503.       dp = readptr(chain) ;
  504.       while (dp != DNULL) {
  505.             if (dp == rec) {
  506.                   writeptr(readptr(dp + offset), chain) ;
  507.                   nremoved++;
  508.             }
  509.             chain = dp + offset ;
  510.             dp = readptr(chain) ;
  511.       }
  512.       if (nremoved == 0)
  513.             printf("rmchain(%ld, %d, %ld) failed\n", svchain, offset, rec) ;
  514. }
  515. !E!O!F!
  516.  
  517. cat > artfile/afbuild.c <<\!E!O!F!
  518. #include <stdio.h>
  519. #include "config.h"
  520. #include <sys/types.h>
  521. #include <sys/stat.h>
  522. #include "newsdefs.h"
  523. #include "af.h"
  524.  
  525.  
  526. char *index() ;
  527. FILE *ckfopen() ;
  528.  
  529. static int idsize = 10007 ;    /* default size of message ID hash table */
  530. static int grpsize =  512 ;    /* default maximum newsgroup number */
  531. static int ttlsize = 5003 ;    /* default size of title hash table */
  532.  
  533. char progname[] = "afbuild" ;
  534. int newgroup ;
  535.  
  536.  
  537. main(argc, argv)
  538.       char **argv ;
  539.       {
  540.       int c ;
  541.       char curname[64], newname[64] ;
  542.       char buf[256] ;
  543.       char histname[64] ;
  544.       FILE *histfp ;
  545.       extern char LIB[], SPOOL[] ;
  546.       extern char *optarg ;
  547.  
  548.       setbuf(stdout, NULL) ;
  549. #if BSDREL >= 41
  550.       setbuf(stderr, NULL) ;
  551. #endif
  552.       pathinit() ;
  553.       sprintf(histname, "%s/history", LIB) ;
  554.       while ((c = getopt(argc, argv, "h:m:g:t:")) != EOF) switch (c) {
  555.             case 'h':
  556.                   scopyn(optarg, histname, 64) ;
  557.                   break ;
  558.             case 'm':
  559.                   idsize = numarg(c) ;
  560.                   break ;
  561.             case 'g':
  562.                   grpsize = numarg(c) ;
  563.                   break ;
  564.             case 't':
  565.                   ttlsize = numarg(c) ;
  566.                   break ;
  567.       }
  568.       sprintf(curname, "%s/artfile", LIB) ;
  569.       sprintf(newname, "%s.tmp", curname) ;
  570.       unlink(newname) ;
  571.       makeaf(newname, idsize, grpsize, ttlsize) ;
  572.       if (strcmp(histname, "none") != 0) {
  573.             readngtab() ;
  574.             genafopen(newname, "r+") ;
  575.             if ((histfp = fopen(histname, "r")) == NULL)
  576.                   xerror("Can't open history file") ;
  577.             if (chdir(SPOOL) < 0)
  578.                   xerror("Can't chdir to %s", SPOOL) ;
  579.             while (fgets(buf, 256, histfp) != NULL)
  580.                   doadd(buf, 0) ;
  581.             if (newgroup)
  582.                   writengfile() ;
  583.       }
  584.       aflock() ;
  585.       sleep(10) ;        /* let the dust settle */
  586.       while (fgets(buf, 256, histfp) != NULL)
  587.             doadd(buf, 0) ;
  588.       close(affd) ;
  589.       if (rename(newname, curname) < 0)
  590.             xerror("rename failed") ;
  591.       afunlock() ;
  592.       sync() ;
  593.       exit(0) ;
  594. }
  595.  
  596.  
  597.  
  598. numarg(c) {
  599.       extern char *optarg ;
  600.       register char *p ;
  601.  
  602.       for (p = optarg ; *p ; p++)
  603.             if (*p < '0' || *p > '9')
  604.                   xerror("Illegal number after -%c option", c) ;
  605.       return atoi(optarg) ;
  606. }
  607.  
  608.  
  609.  
  610. readngtab() {
  611.       char file[FPATHLEN] ;
  612.       FILE *fp ;
  613.       struct stat statb ;
  614.       char line[512] ;
  615.       register char *p ;
  616.       extern char LIB[] ;
  617.  
  618.       sprintf(file, "%s/groupfile", LIB) ;
  619.       if (stat(file, &statb) >= 0 && statb.st_size > 0) {
  620.             getngtab() ;
  621.       } else {
  622.             fprintf(stderr, "afbuild: reconstructing groupfile.\n") ;
  623.             ngtinit() ;
  624.             sprintf(file, "%s/active", LIB) ;
  625.             fp = ckfopen(file, "r") ;
  626.             while (fgets(line, 512, fp) != NULL) {
  627.                   if (line[0] == '\n')
  628.                         continue ;
  629.                   if ((p = index(line, ' ')) != NULL)
  630.                         *p = '\0' ;
  631.                   if ((p = index(line, '\n')) != NULL)
  632.                         *p = '\0' ;
  633.                   newng(line) ;
  634.                   newgroup++ ;
  635.             }
  636.       }
  637. }
  638.  
  639.  
  640.  
  641. xerror(msg, a1, a2, a3, a4)
  642.       char *msg ;
  643.       {
  644.       extern int errno ;
  645.       int e = errno ;
  646.  
  647.       fputs("afbuild: ", stderr) ;
  648.       fprintf(stderr, msg, a1, a2, a3, a4) ;
  649.       putc('\n', stderr) ;
  650.       fprintf(stderr, "errno=%d\n", e) ;
  651.       fflush(stderr) ;        /* 4.2 BSD buffers stderr! */
  652.       exit(2) ;
  653. }
  654. !E!O!F!
  655.  
  656. cat > artfile/afinsert.c <<\!E!O!F!
  657. /*
  658.  * This program inserts entries into the artfile.
  659.  */
  660.  
  661. #include <stdio.h>
  662. #include "af.h"
  663. #include <sys/types.h>
  664. #include "defs.h"
  665.  
  666. int newgroup ;
  667. char progname[] = "afinsert" ;
  668. extern char LIB[] ;
  669. extern char SPOOL[] ;
  670.  
  671.  
  672. main(argc, argv)
  673.       char **argv ;
  674.       {
  675.       int c ;
  676.       char afname[64] ;
  677.  
  678.       setbuf(stdout, NULL) ;
  679. #if BSDREL >= 41
  680.       setbuf(stderr, NULL) ;
  681. #endif
  682.       if (argc != 2)
  683.             xerror("Usage: afinsert hist-line") ;
  684.       sprintf(afname, "%s/artfile", LIB) ;
  685.       genafopen(afname, "r+") ;
  686.       getngtab() ;
  687.       if (chdir(SPOOL) < 0)
  688.             xerror("Can't chdir to spool") ;
  689.       doadd(argv[1], 1) ;
  690.       if (newgroup)
  691.             writengfile() ;
  692.       exit(0) ;
  693. }
  694.  
  695.  
  696.  
  697. xerror(msg, a1, a2, a3, a4)
  698.       char *msg ;
  699.       {
  700.       printf(msg, a1, a2, a3, a4) ;
  701.       putchar('\n') ;
  702.       abort() ;
  703. }
  704. !E!O!F!
  705.  
  706. cat > artfile/doadd.c <<\!E!O!F!
  707. #include <stdio.h>
  708. #include <sys/types.h>
  709. #include "config.h"
  710. #include "defs.h"
  711. #include "arthead.h"
  712.  
  713.  
  714. char *index() ;
  715.  
  716.  
  717. doadd(hist, lockit)
  718.       char *hist ;
  719.       {
  720.       FILE *artfp ;
  721.       char fname[64] ;
  722.       struct arthead h ;
  723.       register char *p ;
  724.       extern char progname[] ;
  725.  
  726.       bzero((char *)&h, sizeof h) ;
  727.       if ((p = index(hist, '\t')) == NULL) {
  728. bad:        printf("Bad history line") ;
  729.             return ;
  730.       }
  731.       p++ ;
  732.       if ((p = index(p, '\t')) == NULL)
  733.             goto bad ;
  734.       p++ ;
  735.       nstrip(p) ;
  736.       hist = p ;
  737.       scopyn(p, fname, 64) ;
  738.       if ((p = index(fname, ' ')) != NULL)
  739.             *p = '\0' ;
  740.       for (p = fname ; *p ; p++)
  741.             if (*p == '.')
  742.                   *p = '/' ;
  743.       if ((artfp = fopen(fname, "r")) == NULL) {
  744.             printf("%s: can't open %s\n", progname, fname) ;
  745.             return ;
  746.       }
  747.       if (gethead(&h, artfp) == NULL) {
  748.             printf("%s: bad header\n", fname) ;
  749.             return ;
  750.       }
  751.       h.h_intnumlines = countlines(artfp) ;
  752.       if (lockit)  aflock() ;
  753.       addart(&h, fname, hist) ;
  754.       if (lockit)  afunlock() ;
  755.       fclose(artfp) ;
  756.       hfree(&h) ;
  757. }
  758.  
  759.  
  760.  
  761. countlines(fp)
  762.       register FILE *fp ;
  763.       {
  764.       register c ;
  765.       int curline, nlines ;
  766.  
  767.       curline = 1 ;
  768.       nlines = 0 ;
  769.       while ((c = getc(fp)) != EOF) {
  770.             if (c == '\n')
  771.                   curline++ ;
  772.             else
  773.                   nlines = curline ;
  774.       }
  775.       return nlines ;
  776. }
  777. !E!O!F!
  778.  
  779. cat > artfile/dumpng.c <<\!E!O!F!
  780. #include <stdio.h>
  781. #include "af.h"
  782. #include "ng.h"
  783. #include <setjmp.h>
  784.  
  785. struct jump {
  786.       jmp_buf jbuf ;
  787.       struct jump *nextj ;
  788. } *jmp ;
  789.  
  790.  
  791.  
  792. main(argc, argv)
  793.       char **argv ;
  794.       {
  795.       char **ap = argv + 1 ;
  796.       char *gname ;
  797.       int gnum ;
  798.       struct artrec a ;
  799.       DPTR dp ;
  800.       char artfile[64] ;
  801.       struct jump j ;
  802.       extern int LIB[] ;
  803.       long atol() ;
  804.  
  805.       jmp = &j ;
  806.       if (setjmp(j.jbuf)) {
  807.             exit(2) ;
  808.       }
  809.       if (argc < 2)
  810.             xerror("Usage: dumpng -fartfile -n newsgroup...") ;
  811.       pathinit() ;
  812.       sprintf(artfile, "%s/artfile", LIB) ;
  813.       if (strncmp(*ap, "-f", 2) == 0) {
  814.             if (ap[0][2])     strcpy(artfile, *ap + 2) ;
  815.             else              strcpy(artfile, *++ap) ;
  816.             ap++ ;
  817.       }
  818.       genafopen(artfile, "r") ;
  819.       gfopen() ;
  820.  
  821.       while ((gname = *ap++) != NULL) {
  822.             if ((gnum = prtngheader(gname)) >= 0) {
  823.                   prtngchain(gname, gnum) ;
  824.             }
  825.       }
  826.       exit(0) ;
  827. }
  828.  
  829.  
  830.  
  831. prtngheader(gname)
  832.       char *gname ;
  833.       {
  834.       struct ngrec g ;
  835.  
  836.       ALL_GROUPS(g) {
  837.             if (strcmp(g.g_name, gname) == 0)
  838.                   goto found ;
  839.       }
  840.       printf("\nUnknown newsgroup %s\n", gname) ;
  841.       return -1 ;
  842.  
  843. found:
  844.       printf("\nNewsgroup %s (%d)", g.g_name, g.g_num) ;
  845.       if (g.g_flags & G_MOD)
  846.             printf("  moderated") ;
  847.       printf("\n\n") ;
  848.       return g.g_num ;
  849. }
  850.  
  851.  
  852.  
  853. prtngchain(gname, gnum)
  854.       char *gname ;
  855.       {
  856.       DPTR dp ;
  857.       struct artrec a ;
  858.       ARTNO an ;
  859.       int i ;
  860.  
  861.       BKWD_GROUP(gnum, an, dp, a) {
  862.             for (i = 0 ; ; i++) {
  863.                   if (i >= a.a_ngroups) {
  864.                         printf("???  ") ;
  865.                         break ;
  866.                   } else if (a.a_group[i].a_ngnum == gnum) {
  867.                         printf("%-5d", a.a_group[i].a_artno) ;
  868.                         break ;
  869.                   }
  870.             }
  871.             printf("%-22.22s %-30.30s %.20s\n",
  872.                    a.a_ident, a.a_title, a.a_from) ;
  873.       }
  874. }
  875.  
  876.  
  877.  
  878.  
  879. xerror(msg, a1, a2, a3, a4)
  880.       char *msg ;
  881.       {
  882.       putchar('\n') ;
  883.       printf(msg, a1, a2, a3, a4) ;
  884.       putchar('\n') ;
  885.       longjmp(jmp->jbuf, 1) ;
  886. }
  887. !E!O!F!
  888.  
  889. cat > artfile/dumprec.c <<\!E!O!F!
  890. #include <stdio.h>
  891. #include "af.h"
  892. #include <setjmp.h>
  893.  
  894. struct jump {
  895.       jmp_buf jbuf ;
  896.       struct jump *nextj ;
  897. } *jmp ;
  898.  
  899.  
  900.  
  901. main(argc, argv)
  902.       char **argv ;
  903.       {
  904.       char **ap = argv + 1 ;
  905.       char *msgid ;
  906.       struct artrec a ;
  907.       DPTR dp ;
  908.       char artfile[64] ;
  909.       struct jump j ;
  910.       extern int LIB[] ;
  911.       long atol() ;
  912.  
  913.       jmp = &j ;
  914.       if (setjmp(j.jbuf)) {
  915.             exit(2) ;
  916.       }
  917.       if (argc < 2)
  918.             xerror("Usage: dumprec -fartfile message-id...") ;
  919.       pathinit() ;
  920.       sprintf(artfile, "%s/artfile", LIB) ;
  921.       if (strncmp(*ap, "-f", 2) == 0) {
  922.             if (ap[0][2])     strcpy(artfile, *ap + 2) ;
  923.             else              strcpy(artfile, *++ap) ;
  924.             ap++ ;
  925.       }
  926.       genafopen(artfile, "r") ;
  927.       setjmp(j.jbuf) ;
  928.       while ((msgid = *ap++) != NULL) {
  929.             if (msgid[0] >= '0' && msgid[0] <= '9')
  930.                   readrec(dp = atol(msgid), &a) ;
  931.             else if ((dp = lookart(msgid, &a)) == DNULL) {
  932.                   printf("\nNo entry for %s\n", msgid) ;
  933.                   continue ;
  934.             }
  935.             prtentry(&a, dp, msgid) ;
  936.       }
  937.       exit(0) ;
  938. }
  939.  
  940.  
  941.  
  942. prtentry(a, dp, msgid)
  943.       register struct artrec *a ;
  944.       DPTR dp ;
  945.       char *msgid ;
  946.       {
  947.       char *ctime() ;
  948.  
  949.       printf("\nArticle: %ld %s\n", dp, a->a_ident) ;
  950.       if ((a->a_flags & A_DUMMY) == 0) {
  951.             printf("Subject: %s\n", a->a_title) ;
  952.             printf("From: %s\n", a->a_from) ;
  953.             printf("File: %s\n", a->a_file) ;
  954.       }
  955.       printf("Posted: %s", ctime(&a->a_subtime)) ;
  956.       printf("Received: %s", ctime(&a->a_rectime)) ;
  957.       if (a->a_exptime)
  958.             printf("Expires: %s", ctime(&a->a_exptime)) ;
  959.       printf("Lines: %d\n", a->a_nlines) ;
  960.       printf("Flags: %05o\n", a->a_flags) ;
  961.       prtgroups(a) ;
  962.       prtptr("Parent: ", a->a_parent) ;
  963.       prtchildren(a->a_children) ;
  964.       prtptr("Childchain: ", a->a_childchain) ;
  965.       prtptr("Idchain: ", a->a_idchain) ;
  966.       prtptr("Titlechain: ", a->a_titlechain) ;
  967. }
  968.  
  969.  
  970. prtchildren(dp)
  971.       DPTR dp ;
  972.       {
  973.       struct artrec a ;
  974.       char *msg ;
  975.  
  976.       msg = "Children: ";
  977.       while (dp != DNULL) {
  978.             prtptr(msg, dp) ;
  979.             readrec(dp, &a) ;
  980.             dp = a.a_childchain ;
  981.             msg = "\t  " ;
  982.       }
  983. }
  984.  
  985.  
  986. prtgroups(a)
  987.       struct artrec *a ;
  988.       {
  989.       register int i ;
  990.       char *msg = "Newsgroups: ";
  991.  
  992.       for (i = 0 ; i < a->a_ngroups ; i++) {
  993.             printf("%s%d/%d", msg, a->a_group[i].a_ngnum, a->a_group[i].a_artno);
  994.             prtptr(" ", a->a_group[i].a_ngchain) ;
  995.             msg = "\t    ";
  996.       }
  997. }
  998.  
  999.  
  1000. prtptr(msg, dp)
  1001.       char *msg ;
  1002.       DPTR dp ;
  1003.       {
  1004.       struct artrec a ;
  1005.  
  1006.       printf("%s", msg) ;
  1007.       if (dp == DNULL)
  1008.             printf("null") ;
  1009.       else {
  1010.             printf("%ld ", dp) ;
  1011.             readrec(dp, &a) ;
  1012.             printf("%s", a.a_ident) ;
  1013.       }
  1014.       putchar('\n') ;
  1015. }
  1016.  
  1017.  
  1018.  
  1019. xerror(msg, a1, a2, a3, a4)
  1020.       char *msg ;
  1021.       {
  1022.       putchar('\n') ;
  1023.       printf(msg, a1, a2, a3, a4) ;
  1024.       putchar('\n') ;
  1025.       longjmp(jmp->jbuf, 1) ;
  1026. }
  1027. !E!O!F!
  1028.  
  1029. cat > artfile/dumptree.c <<\!E!O!F!
  1030. #include <stdio.h>
  1031. #include "artfile.h"
  1032. #include "libextern.h"
  1033.  
  1034. char *savestr();
  1035.  
  1036. char *seen[2000];
  1037. char **seenp = seen;
  1038.  
  1039.  
  1040.  
  1041. main(argc, argv)
  1042.       char **argv;
  1043.       {
  1044.       char artfile[64] ;
  1045.       struct artrec a;
  1046.       DPTR dp;
  1047.       int i;
  1048.       int rootflg = 0;
  1049.       struct article *ap;
  1050.       char *msgid;
  1051.       struct article *rootid;
  1052.       char *title;
  1053.       extern int optind;
  1054.       extern char *optarg;
  1055.  
  1056.       pathinit();
  1057.       sprintf(artfile, "%s/artfile", LIB) ;
  1058.       while ((i = getopt(argc, argv, "f:r")) != EOF) {
  1059.             switch (i) {
  1060.             case 'f':
  1061.                   strcpy(artfile, optarg);
  1062.                   break;
  1063.             case 'r':
  1064.                   rootflg++;
  1065.                   break;
  1066.             }
  1067.       }
  1068.       if (optind >= argc)
  1069.             xerror("Usage: prttree message-id\n");
  1070.       msgid = argv[optind];
  1071.       genafopen(artfile, "r") ;
  1072.       if ((dp = lookart(msgid, &a)) == DNULL)
  1073.             xerror("No entry for %s", msgid);
  1074.       rootid = msgid;
  1075.       if ((a.a_flags & A_DUMMY) == 0)
  1076.             title = savestr(a.a_title);
  1077.       else
  1078.             title = "";
  1079.       if (rootflg) {
  1080.             seenp = seen;
  1081.             while (dp != DNULL) {
  1082.                   readrec(dp, &a);
  1083.                   rootid = savestr(a.a_ident);
  1084.                   if (lookid(rootid)) {
  1085.                         printf("loop discovered while searching for parent:\n");
  1086.                         printf("    %ld %s\n", dp, rootid);
  1087.                         do {
  1088.                               readrec(dp = a.a_parent, &a);
  1089.                               printf("    %ld %s\n", dp, a.a_ident);
  1090.                         } while (strcmp(rootid, a.a_ident) != 0);
  1091.                         break;
  1092.                   }
  1093.                   *seenp++ = rootid;
  1094.                   dp = a.a_parent;
  1095.             }
  1096.       }
  1097.       if ((dp = lookart(rootid, &a)) == DNULL)
  1098.             xerror("rootid");
  1099.       if ((a.a_flags & A_DUMMY) == 0)
  1100.             title = a.a_title;
  1101.       seenp = seen;
  1102.       printf("Discussion tree for %s\n", title);
  1103.       prttree(dp, &a, 0, DNULL);
  1104.       exit(0);
  1105. }
  1106.  
  1107.  
  1108. prttree(dp, a, indent, parent)
  1109.       DPTR dp;
  1110.       struct artrec *a;
  1111.       int indent;
  1112.       DPTR parent;
  1113.       {
  1114.       int i;
  1115.       char *p;
  1116.       DPTR dp2;
  1117.       struct artrec a2;
  1118.       struct article *ap;
  1119.  
  1120.       i = indent;
  1121.       while (i >= 8) {
  1122.             putchar('\t');
  1123.             i -= 8;
  1124.       }
  1125.       while (i >= 1) {
  1126.             putchar(' ');
  1127.             i--;
  1128.       }
  1129.       indent += 3;
  1130.       printf("%ld %s", dp, a->a_ident);
  1131.       p = savestr(a->a_ident);
  1132.       if (a->a_parent != parent) {
  1133.             printf(" (parent=%ld!)", a->a_parent);
  1134.       }
  1135.  
  1136.       if (lookid(p)) {
  1137.             printf(" (duplicate)\n");
  1138.             return;
  1139.       }
  1140.       *seenp++ = p;
  1141.       putchar('\n');
  1142.       for (dp2 = a->a_children ; dp2 != DNULL ; dp2 = a2.a_childchain) {
  1143.             readrec(dp2, &a2);
  1144.             prttree(dp2, &a2, indent, dp);
  1145.       }
  1146. }
  1147.  
  1148.  
  1149.  
  1150. xerror(fmt, a1, a2, a3, a4)
  1151.       char *fmt;
  1152.       {
  1153.       fprintf(stderr, fmt, a1, a2, a3, a4);
  1154.       putc('\n', stderr);
  1155.       exit(1);
  1156. }
  1157.  
  1158.  
  1159.  
  1160. lookid(id)
  1161.       register char *id;
  1162.       {
  1163.       register char **p;
  1164.  
  1165.       for (p = seen ; p < seenp ; p++)
  1166.             if (**p == *id && strcmp(*p, id) == 0)
  1167.                   return 1;
  1168.       return 0;
  1169. }
  1170. !E!O!F!
  1171.  
  1172. cat > artfile/genmakefile <<\!E!O!F!
  1173. LIB=../lib
  1174. . $LIB/makedefs
  1175. exec > makefile
  1176. cat <<!
  1177. # makefile 6/30/84
  1178.  
  1179. LIB = $LIB
  1180. !
  1181. cat $LIB/makedefs
  1182. cat <<\!
  1183.  
  1184. DEBUG = -O
  1185. CFLAGS = $(DEBUG) -I$(LIB)
  1186. LFLAGS = $(DEBUG)
  1187.  
  1188. AFBUILD = afbuild.o doadd.o addart.o addrec.o makeaf.o ngtab.o title.o $(LIB)/rpathinit.o $(LIB)/rlib.a
  1189.  
  1190. AFINSERT = afinsert.o doadd.o addart.o addrec.o ngtab.o title.o $(LIB)/rpathinit.o $(LIB)/rlib.a
  1191.  
  1192. DUMPREC = dumprec.o $(LIB)/rpathinit.o $(LIB)/rlib.a
  1193.  
  1194. DUMPNG = dumpng.o $(LIB)/rpathinit.o $(LIB)/rlib.a
  1195.  
  1196. DUMPTREE = dumptree.o $(LIB)/rpathinit.o $(LIB)/rlib.a
  1197.  
  1198. all: makefile afbuild afinsert
  1199.  
  1200. makefile: genmakefile
  1201.     genmakefile
  1202.     @echo 'Makefile changes, so restart makefile.'
  1203.     @sh -c 'exit 22'
  1204.  
  1205. install: all
  1206.     /bin/cp afbuild afinsert $(LIBDIR)
  1207.  
  1208. afbuild: $(AFBUILD)
  1209.     $(CC) -o $@ $(LFLAGS) $(AFBUILD)
  1210.  
  1211. afinsert: $(AFINSERT)
  1212.     $(CC) -o $@ $(LFLAGS) $(AFINSERT)
  1213.  
  1214. dumprec: $(DUMPREC)
  1215.     $(CC) -o $@ $(LFLAGS) $(DUMPREC)
  1216.  
  1217. dumpng: $(DUMPNG)
  1218.     $(CC) -o $@ $(LFLAGS) $(DUMPNG)
  1219.  
  1220. dumptree: $(DUMPTREE)
  1221.     $(CC) -o $@ $(LFLAGS) $(DUMPTREE)
  1222.  
  1223. addart.o addrec.o afbuild.o afinsert.o dumpng.o dumprec.o \
  1224. dumpng.o makeaf.o title.o write.o: $(LIB)/artfile.h $(LIB)/af.h $(FRC)
  1225.  
  1226. doadd.o ngtab.o dumprec.o dumpng.o: $(FRC)
  1227.  
  1228.  
  1229. FRC:
  1230. !
  1231. !E!O!F!
  1232. chmod +x artfile/genmakefile
  1233.  
  1234. cat > artfile/ifuncs.c.10.1 <<\!E!O!F!
  1235. /*
  1236.  * ifuncs - functions used by inews.
  1237.  */
  1238.  
  1239. static char *SccsId = "@(#)ifuncs.c    2.21    3/31/83";
  1240.  
  1241. #include "iparams.h"
  1242.  
  1243. static char histline[256];    /* Assumed initially zero (moved here 6/18/84 KSA) */
  1244.  
  1245. /*
  1246.  * Transmit this article to all interested systems.
  1247.  */
  1248.  
  1249. #ifdef u370
  1250. static struct srec srec;
  1251. static struct hbuf h;
  1252. #endif
  1253.  
  1254. broadcast()
  1255. {
  1256.     register char *nptr, *hptr;
  1257.     register FILE *fp;
  1258. #ifndef u370
  1259.     struct srec srec;
  1260.     struct hbuf h;
  1261. #endif
  1262.  
  1263.     /* h is a local copy of the header we can scribble on */
  1264.     fp = xfopen(ARTICLE, "r");
  1265.     if (hread(&h, fp, TRUE) == NULL)
  1266.         xerror("Cannot reread article");
  1267.     fclose(fp);
  1268.     if (h.distribution[0])
  1269.         strcpy(h.nbuf, h.distribution);
  1270.     ngcat(h.nbuf);
  1271.  
  1272.      /* break path into list of systems. */
  1273.     hptr = nptr = h.path;
  1274.     while (*hptr != '\0') {
  1275.         if (index(NETCHRS, *hptr)) {
  1276.             *hptr++ = '\0';
  1277.             nptr = hptr;
  1278.         } else
  1279.             hptr++;
  1280.     }
  1281.     *nptr = '\0';
  1282.  
  1283.     /* loop once per system. */
  1284.     lock();
  1285.     s_openr();
  1286.     while (s_read(&srec)) {
  1287.         if (strncmp(srec.s_name, FULLSYSNAME, SNLN) == 0)
  1288.             continue;
  1289.         hptr = h.path;
  1290.         while (*hptr != '\0') {
  1291.             if (strncmp(srec.s_name, hptr, SNLN) == 0)
  1292.                 goto contin;
  1293.             while (*hptr++ != '\0')
  1294.                 ;
  1295.         }
  1296.         if (ngmatch(h.nbuf, srec.s_nbuf)) {
  1297.             transmit(&srec, xfopen(ARTICLE, "r"), 1);
  1298.         }
  1299.     contin:;
  1300.     }
  1301.     s_close();
  1302.     unlock();
  1303. }
  1304.  
  1305. /*
  1306.  * Transmit file to system.
  1307.  */
  1308. #define PROC 0004
  1309. transmit(sp, ifp, maynotify)
  1310. register struct srec *sp;
  1311. register FILE *ifp;
  1312. int maynotify;
  1313. {
  1314.     register FILE *ofp;
  1315.     register int c;
  1316.     register char *ptr;
  1317.     struct hbuf hh;
  1318.     char TRANS[BUFLEN];
  1319.     char *argv[20];
  1320.     register int pid, fd;
  1321.     extern char firstbufname[];
  1322.  
  1323. /* A:    afmt: the other machine runs an A news, so we xmit in A format */
  1324.     int afmt = (index(sp->s_flags, 'A') != NULL);
  1325. /* B:    use B format (this is the default - don't use this letter elsewise). */
  1326. /* F:    append name to file */
  1327.     int appfile = (index(sp->s_flags, 'F') != NULL);
  1328. /* H:    history: expand %s into the history line (KSA) */
  1329.     int history = (index(sp->s_flags, 'H') != NULL);  /* (6/18/84 KSA) */
  1330. /* L:    local: don't send the article unless it was generated locally */
  1331.     int local = (index(sp->s_flags, 'L') != NULL);
  1332. /* N:    notify: don't send the article, just tell him we have it */
  1333.     int notify = maynotify && (index(sp->s_flags, 'N') != NULL);
  1334. /* S:    noshell: don't fork a shell to execute the xmit command */
  1335.     int noshell = (index(sp->s_flags, 'S') != NULL);
  1336. /* U:    useexist: use the -c option to uux to use the existing copy */
  1337.     int useexist = (index(sp->s_flags, 'U') != NULL);
  1338.  
  1339.     if (local && mode == PROC)
  1340.         return;
  1341. #ifdef DEBUG
  1342.     printf("Transmitting to '%s'\n", sp->s_name);
  1343. #endif
  1344.     if (!appfile && !useexist && !history) {    /* (6/18/84 KSA) */
  1345.         if (hread(&hh, ifp, TRUE) == NULL) {
  1346.             fprintf(stderr, "Bad header, not transmitting\n");
  1347.             log("Bad header, not transmitting %s re %s to %s",
  1348.                 hh.ident, hh.title, sp->s_name);
  1349.             return;
  1350.         }
  1351.         /* Taken out for obscure reasons - see the standard.
  1352.         ngsquash(hh.nbuf, sp->s_nbuf);
  1353.         */
  1354.         if (hh.nbuf[0] == '\0') {
  1355.             printf("Article not subscribed to by %s\n", sp->s_name);
  1356.             return;
  1357.         }
  1358.         sprintf(TRANS, "%s/trXXXXXX", SPOOL);
  1359.     }
  1360.  
  1361.     if (notify) {
  1362.         char oldid[50];
  1363.         sprintf(hh.title, "ihave %s %s", hh.ident, FULLSYSNAME);
  1364.         sprintf(hh.nbuf, "to.%s.ctl", sp->s_name);
  1365.         strcpy(oldid, hh.ident);
  1366.         getident(&hh);
  1367.         log("tell %s about %s, notif. id %s",
  1368.             sp->s_name, oldid, hh.ident);
  1369.     } else
  1370.         log("xmit article %s to %s",
  1371.             hh.ident, sp->s_name);
  1372.  
  1373.     if (appfile) {
  1374.         if (firstbufname[0] == '\0')
  1375.             xerror("No file name to xmit from");
  1376.         ofp = fopen(sp->s_xmit, "a");
  1377.         if (ofp == NULL)
  1378.             xerror("Cannot append to %s", sp->s_xmit);
  1379.         fprintf(ofp, "%s\n", firstbufname);
  1380.         fclose(ofp);
  1381.         return;
  1382.     }
  1383.     else
  1384. #ifdef UXMIT
  1385.     if (useexist) {
  1386.         if (firstbufname[0] == '\0')
  1387.             xerror("No file name to xmit from");
  1388.         if (*sp->s_xmit == '\0')
  1389.             sprintf(bfr, UXMIT, sp->s_name, firstbufname);
  1390.         else
  1391.             sprintf(bfr, sp->s_xmit, firstbufname);
  1392.     } else
  1393. #endif
  1394.     if (history) {        /* (6/18/84 KSA) */
  1395.         if (*sp->s_xmit == '\0')
  1396.             xerror("no xmit command with H flag");
  1397.         sprintf(bfr, sp->s_xmit, histline);
  1398.     } else
  1399.     {
  1400.         ofp = xfopen(mktemp(TRANS), "w");
  1401.         if (afmt)
  1402.             ohwrite(&hh, ofp);
  1403.         else 
  1404.             hwrite(&hh, ofp);
  1405.         if (!notify)
  1406.             while ((c = getc(ifp)) != EOF)
  1407.                 putc(c, ofp);
  1408.         fclose(ifp);
  1409.         fclose(ofp);
  1410.         if (*sp->s_xmit == '\0')
  1411.             sprintf(bfr, DFTXMIT, sp->s_name, TRANS);
  1412.         else
  1413.             sprintf(bfr, "(%s) < %s", sp->s_xmit, TRANS);
  1414.     }
  1415.  
  1416.     /* At this point, the command to be executed is in bfr. */
  1417.     if (noshell) {
  1418.         if (pid = fork())
  1419.             fwait(pid);
  1420.         else {
  1421.             close(0);
  1422.             open(TRANS, 0);
  1423.             ptr = sp->s_xmit;
  1424.             for (pid = 0; pid < 19; pid++) {
  1425.                 while (isspace(*ptr))
  1426.                     *ptr++ = 0;
  1427.                 argv[pid] = ptr;
  1428.                 while (!isspace(*++ptr) && *ptr)
  1429.                     ;
  1430.                 if (!*ptr)
  1431.                     break;
  1432.             }
  1433.             argv[++pid] = 0;
  1434.             execv(sp->s_xmit, argv);
  1435.             xerror("Can't execv\n");
  1436.         }
  1437.     } else
  1438.         system(bfr);
  1439.     if (!appfile && !useexist && !history)    /* 6/18/84 KSA) */
  1440.         unlink(TRANS);
  1441. }
  1442.  
  1443. typedef struct {
  1444.     char *dptr;
  1445.     int dsize;
  1446. } datum;
  1447.  
  1448. /*
  1449.  * Return TRUE if we have seen this file before, else FALSE.
  1450.  */
  1451. history(hp)
  1452. struct hbuf *hp;
  1453. {
  1454.     register FILE *hfp;
  1455.     register char *p;
  1456.     datum lhs, rhs;
  1457.     datum fetch();
  1458.  
  1459. #ifdef DEBUG
  1460.     fprintf(stderr,"history(%s)\n", hp->ident);
  1461. #endif
  1462.     idlock(hp->ident);
  1463. #ifdef DBM
  1464.     dbminit(ARTFILE);
  1465.     lhs.dptr = hp->ident;
  1466.     lhs.dsize = strlen(lhs.dptr) + 1;
  1467.     rhs = fetch(lhs);
  1468.     if (rhs.dptr)
  1469.         return(TRUE);
  1470. #else
  1471.     hfp = xfopen(ARTFILE, "r");
  1472.     while (fgets(bfr, BUFLEN, hfp) != NULL) {
  1473.         p = index(bfr, '\t');
  1474.         if (p == NULL)
  1475.             p = index(bfr, '\n');
  1476.         if (p != NULL)    /* can happen if nulls in file */
  1477.             *p = 0;
  1478.         if (strcmp(bfr, hp->ident)==0 ||
  1479.                 hp->oident[0] && strcmp(bfr, hp->oident)==0) {
  1480.             fclose(hfp);
  1481.             idunlock();
  1482. #ifdef DEBUG
  1483.             fprintf(stderr,"history returns true\n");
  1484. #endif
  1485.             return(TRUE);
  1486.         }
  1487.     }
  1488.     fclose(hfp);
  1489. #endif
  1490.     addhist(hp->ident);
  1491.     addhist("\t");
  1492. #ifdef DEBUG
  1493.     fprintf(stderr,"history returns false\n");
  1494. #endif
  1495.     return(FALSE);
  1496. }
  1497.  
  1498. /* (deleted by KSA) static char histline[256];    /* Assumed initially zero */
  1499.  
  1500. addhist(msg)
  1501. char *msg;
  1502. {
  1503.     strcat(histline, msg);
  1504. }
  1505.  
  1506. savehist()
  1507. {
  1508.     register FILE *hfp;
  1509.     datum lhs, rhs;
  1510.     long fpos;
  1511.     register char *p;
  1512.  
  1513.     hfp = xfopen(ARTFILE, "a");
  1514.     fpos = ftell(hfp);
  1515.     fprintf(hfp, "%s\n", histline);
  1516.     fclose(hfp);
  1517. #ifdef DBM
  1518.     /* We assume that history has already been called, calling dbminit. */
  1519.     p = index(histline, '\t');
  1520.     if (p)
  1521.         *p = 0;
  1522.     lhs.dptr = histline;
  1523.     lhs.dsize = strlen(lhs.dptr) + 1;
  1524.     rhs.dptr = (char *) &fpos;
  1525.     rhs.dsize = sizeof fpos;
  1526.     store(lhs, rhs);
  1527. #endif
  1528.     histline[0] = 0;
  1529.     idunlock();
  1530. }
  1531.  
  1532. /*
  1533.  * Save partial news.
  1534.  */
  1535. newssave(fd, dummy)
  1536. FILE *fd, *dummy;
  1537. {
  1538.     register FILE *tofd, *fromfd;
  1539.     char sfname[BUFLEN];
  1540.     register int c;
  1541.     struct hbuf h;
  1542.     time_t tim;
  1543.  
  1544.     if (fd == NULL)
  1545.         fromfd = xfopen(INFILE, "r");
  1546.     else
  1547.         fromfd = fd;
  1548.     umask(savmask);
  1549.     setgid(gid);
  1550.     setuid(uid);
  1551.  
  1552.     sprintf(sfname, "%s/%s", userhome, PARTIAL);
  1553.     if ((tofd = fopen(sfname, "a")) == NULL)
  1554.         xerror("Cannot save partial news");
  1555.     time(&tim);
  1556.     fprintf(tofd, "----- News saved at %s\n", arpadate(&tim));
  1557.     while ((c = getc(fromfd)) != EOF)
  1558.         putc(c, tofd);
  1559.     fclose(fromfd);
  1560.     fclose(tofd);
  1561.     printf("News saved in %s\n", sfname);
  1562.     xxit(0);
  1563. }
  1564.  
  1565. /*
  1566.  * Handle dates in header.
  1567.  */
  1568.  
  1569. dates(hp)
  1570. struct hbuf *hp;
  1571. {
  1572.     long edt;
  1573.  
  1574.     time(&hp->rectime);
  1575.     nstrip(strcpy(hp->recdate, arpadate(&hp->rectime)));
  1576.     if (*hp->subdate) {
  1577.         if (cgtdate(hp->subdate) < 0) {
  1578.             log("Bad sub date '%s'", hp->subdate);
  1579.             xerror("Cannot parse submittal date");
  1580.         }
  1581.     } else
  1582.         strcpy(hp->subdate, hp->recdate);
  1583.     if (*hp->expdate) {
  1584.         if ((edt = cgtdate(hp->expdate)) < 0)
  1585.             xerror("Cannot parse expiration date");
  1586.         nstrip(strcpy(hp->expdate, arpadate(&edt)));
  1587.     } else {
  1588.         defexp = TRUE;
  1589.         /*
  1590.          * Default is now applied in expire.c
  1591.         hp->exptime = hp->rectime + DFLTEXP;
  1592.         nstrip(strcpy(hp->expdate, arpadate(&hp->exptime)));
  1593.         */
  1594.     }
  1595. }
  1596.  
  1597. /*
  1598.  *    Exit and cleanup.
  1599.  */
  1600. xxit(status)
  1601. int status;
  1602. {
  1603.     unlink(INFILE);
  1604.     unlink(ARTICLE);
  1605.     while (lockcount > 0)
  1606.         unlock();
  1607.     idunlock();
  1608.     exit(status);
  1609. }
  1610.  
  1611. xerror(message, arg1, arg2)
  1612. char *message;
  1613. int arg1, arg2;
  1614. {
  1615.     char buffer[128];
  1616.  
  1617.     fflush(stdout);
  1618.     sprintf(buffer, message, arg1, arg2);
  1619.     fprintf(stderr, "inews: %s.\n", buffer);
  1620.     log(buffer);
  1621.     xxit(1);
  1622. }
  1623.  
  1624. #ifdef    VMS
  1625.  
  1626. #define    SUBLOCK    "/tmp/netnews.lck.1"
  1627.  
  1628. /*
  1629.  * Newsystem locking.
  1630.  * These routines are different for VMS because we can not
  1631.  * effectively simulate links, and VMS supports multiple
  1632.  * version numbers of files
  1633.  */
  1634. lock()
  1635. {
  1636.     register int i;
  1637.     register int fd;
  1638.  
  1639.     if (lockcount++ == 0) {
  1640.         i = DEADTIME;
  1641.         while ((fd = creat(SUBLOCK, 0444)) < 0) {
  1642.             if (--i < 0) {
  1643.                 unlink(SUBLOCK);
  1644.                 log("News system locked up");
  1645.             }
  1646.             if (i < -3)
  1647.                 xerror("Unable to unlock news system");
  1648.             sleep((unsigned)1);
  1649.         }
  1650.         close(fd);
  1651.     }
  1652. }
  1653.  
  1654. unlock()
  1655. {
  1656.     if (--lockcount == 0)
  1657.         unlink(SUBLOCK);
  1658. }
  1659.  
  1660. #else    VMS
  1661.  
  1662. /*
  1663.  * Newsystem locking.
  1664.  */
  1665.  
  1666. lock()
  1667. {
  1668.     register int i;
  1669.  
  1670.     if (lockcount++ == 0) {
  1671.         i = DEADTIME;
  1672.         while (link(SUBFILE, LOCKFILE)) {
  1673.             if (--i < 0)
  1674.                 xerror("News system locked up");
  1675.             sleep((unsigned)1);
  1676.         }
  1677.     }
  1678. }
  1679.  
  1680. unlock()
  1681. {
  1682.     if (--lockcount == 0)
  1683.         unlink(LOCKFILE);
  1684. }
  1685. #endif    VMS
  1686.  
  1687. char lockname[80];
  1688. idlock(str)
  1689. char *str;
  1690. {
  1691.     register int i;
  1692.     char tempname[80];
  1693.     long now;
  1694.     struct stat sbuf;
  1695.     int fd;
  1696.  
  1697. #ifdef    VMS
  1698.     sprintf(lockname, "/tmp/%s.l.1", str);
  1699.     if ((fd = creat(lockname, 0444)) < 0) {
  1700. #else    VMS
  1701.     sprintf(tempname, "/tmp/LTMP.%d", getpid());
  1702.     sprintf(lockname, "/tmp/L%s", str);
  1703. #ifdef FOURTEENMAX
  1704.     lockname[5 /* /tmp/ */ + 14] = '\0';
  1705. #endif
  1706.     close(creat(tempname, 0666));
  1707.     while (link(tempname, lockname)) {
  1708. #endif    VMS
  1709.         time(&now);
  1710.         i = stat(lockname, &sbuf);
  1711.         if (i < 0) {
  1712.             xerror("Directory permission problem in /tmp");
  1713.         }
  1714.         if (sbuf.st_mtime + 10*60 < now) {
  1715.             unlink(lockname);
  1716.             log("Article %s locked up", str);
  1717.             continue;
  1718.         }
  1719.         log("waiting on lock for %s", lockname);
  1720.         sleep((unsigned)60);
  1721.     }
  1722. #ifdef VMS
  1723.     close(fd);
  1724. #else
  1725.     unlink(tempname);
  1726. #endif
  1727.     unlink(tempname);
  1728. }
  1729.  
  1730. idunlock()
  1731. {
  1732.     unlink(lockname);
  1733. }
  1734.  
  1735. /*
  1736.  * Put a unique name into header.ident.
  1737.  */
  1738. getident(hp)
  1739. struct hbuf *hp;
  1740. {
  1741.     long seqn;
  1742.     register FILE *fp;
  1743.  
  1744.     lock();
  1745.     fp = xfopen(SEQFILE, "r");
  1746.     fgets(bfr, BUFLEN, fp);
  1747.     fclose(fp);
  1748.     seqn = atol(bfr) + 1;
  1749. #ifdef    VMS
  1750.     unlink(SEQFILE);
  1751. #endif    VMS
  1752.     fp = xfopen(SEQFILE, "w");
  1753.     fprintf(fp, "%ld\n", seqn);
  1754.     fclose(fp);
  1755.     unlock();
  1756.     sprintf(hp->ident, "<%ld@%s%s>", seqn, FULLSYSNAME, MYDOMAIN);
  1757. }
  1758.  
  1759. /*
  1760.  * Log the given message, with printf strings and parameters allowed,
  1761.  * on the log file, if it can be written.  The date and an attempt at
  1762.  * figuring out the remote system name are also logged.
  1763.  */
  1764. log(fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9)
  1765. char *fmt;
  1766. {
  1767.     FILE *logfile;
  1768.     char msg[256];
  1769.     char *logtime, *p, *q;
  1770.     char rmtsys[256];
  1771.     char c;
  1772.     long t;
  1773.  
  1774.     if (header.relayversion[0]) {
  1775.         for (p=header.relayversion; p; p=index(p+1, 's'))
  1776.             if (strncmp(p, "site ", 5) == 0)
  1777.                 break;
  1778.         if (p == NULL)
  1779.             goto crackpath;
  1780.         p += 4;
  1781.         while (*p == ' ' || *p == '\t')
  1782.             p++;
  1783.         for (q=p; *q && *q!=' ' && *q != '\t'; q++)
  1784.             ;
  1785.         c = *q;
  1786.         strcpy(rmtsys, p);
  1787.         *q = c;
  1788.     } else {
  1789. crackpath:
  1790.         strcpy(rmtsys, header.path);
  1791.         p = index(rmtsys, '!');
  1792.         if (p == NULL)
  1793.             p = index(rmtsys, ':');
  1794.         if (p)
  1795.             *p = 0;
  1796.         else {
  1797.             p = rindex(rmtsys, '@');
  1798.             if (p)
  1799.                 strcpy(rmtsys, p+1);
  1800.             else
  1801.                 strcpy(rmtsys, "local");
  1802.         }
  1803.     }
  1804.  
  1805.     time(&t);
  1806.     logtime = ctime(&t);
  1807.     logtime[16] = 0;
  1808.     logtime += 4;
  1809.  
  1810.     sprintf(msg, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9);
  1811.  
  1812.     lock();
  1813.     if (access(logfname, 0)) {
  1814.         unlock(0);
  1815.         return;
  1816.     }
  1817.     logfile = fopen(logfname, "a");
  1818.     if (logfile == NULL) {
  1819.         unlock(0);
  1820.         return;
  1821.     }
  1822.     fprintf(logfile, "%s %s\t%s\n", logtime, rmtsys, msg);
  1823.     fclose(logfile);
  1824.     unlock();
  1825. }
  1826.  
  1827. /*
  1828.  * Check if header.nbuf contains only valid newsgroup names;
  1829.  * exit with error if not valid.
  1830.  *
  1831.  * a == TRUE means header.nbuf is subscription list
  1832.  * a == FALSE means header.nbuf is newsgroup list
  1833.  */
  1834.  
  1835. ngfcheck(a)
  1836. int a;
  1837. {
  1838.     char ngcheck[NGFSIZ];    /* Hold NGFILE newsgroups */
  1839.     char tbuf[BUFLEN];    /* hold single header.nbuf news group */
  1840.     register char *s1, *s2;
  1841.     register FILE *f;
  1842.  
  1843.     s1 = ngcheck;
  1844.     f = xfopen(NGFILE, "r");
  1845.     while (fgets(bfr, BUFLEN, f) != NULL) {
  1846.         for (s2 = bfr; *s2 != '\0' &&
  1847.             *s2 != ' ' && *s2 != '\t' &&
  1848.             *s2 != ':' && *s2 != '\n';) {
  1849.             if (s1 >= &ngcheck[NGFSIZ-2])
  1850.                 xerror("NGFILE too long");
  1851.             *s1++ = *s2++;
  1852.         }
  1853.         *s1++ = NGDELIM;
  1854.     }
  1855.     *s1 = '\0';
  1856.     fclose(f);
  1857.     for (s1 = header.nbuf; *s1 != '\0';) {
  1858.         if (*s1 == NEGCHAR)
  1859.             s1++;
  1860.         s2 = tbuf;
  1861.         while ((*s2++ = *s1++) != NGDELIM)
  1862.             if (s1[-1] == ':')
  1863.                 xerror("Newsgroup cannot contain ':'");
  1864.         *s2 = '\0';
  1865.         s2 = tbuf;
  1866.         if (!ngmatch(s2, ngcheck) && (!a || !ngmatch(ngcheck, s2))) {
  1867.             ngdel(s2);
  1868.             sprintf(bfr, "Bad news group \"%s\"", s2);
  1869.             newssave(stdin, NULL);
  1870.             xerror(bfr);
  1871.         }
  1872.     }
  1873. }
  1874.  
  1875. /*
  1876.  * Figure out who posted the article (which is locally entered).
  1877.  * The results are placed in the header structure hp.
  1878.  */
  1879. gensender(hp, logname)
  1880. struct hbuf *hp;
  1881. char *logname;
  1882. {
  1883.     char *fn;
  1884.     static char buf[100];
  1885.     char buf2[100];
  1886.     char *fullname(), *getenv();
  1887.     char *p;
  1888.     int fd;
  1889.  
  1890.     fn = getenv("NAME");
  1891.  
  1892.     if (fn == NULL) {
  1893.         sprintf(buf, "%s/%s", getenv("HOME"), ".name");
  1894.         fd = open(buf, 0);
  1895.         if (fd >= 0) {
  1896.             read(fd, buf2, sizeof buf2);
  1897.             close(fd);
  1898.             if (buf2[0] >= 'A')
  1899.                 fn = buf2;
  1900.             for (p=fn; *p; p++)
  1901.                 if (*p < ' ')
  1902.                     *p = 0;
  1903.         }
  1904.     }
  1905.  
  1906.     if (fn == NULL)
  1907.         fn = fullname(logname);
  1908.  
  1909.     sprintf(hp->path, "%s", logname);
  1910.     sprintf(hp->from, "%s@%s%s (%s)", logname, FULLSYSNAME, MYDOMAIN, fn);
  1911. }
  1912.  
  1913. /*
  1914.  * Trap interrupts.
  1915.  */
  1916. onsig(n)
  1917. int n;
  1918. {
  1919.     static int numsigs = 0;
  1920.     /*
  1921.      * Most UNIX systems reset caught signals to SIG_DFL.
  1922.      * This bad design requires that the trap be set again here.
  1923.      * Unfortunately, if the signal recurs before the trap is set,
  1924.      * the program will die, possibly leaving the lock in place.
  1925.      */
  1926.     if (++numsigs > 100) {
  1927.         log("readnews ran away looping on signal %d", n);
  1928.         xxit(1);
  1929.     }
  1930.     signal(n, onsig);
  1931.     sigtrap = n;
  1932. }
  1933.  
  1934. /*
  1935.  * If the stdin begins with "#", we assume we have been fed a batched
  1936.  * shell script which looks like this:
  1937.  *    #! rnews 1234
  1938.  *    article with 1234 chars
  1939.  *    #! rnews 4321
  1940.  *    article with 4321 chars
  1941.  *
  1942.  * In this case we just exec the unbatcher and let it unpack and call us back.
  1943.  *
  1944.  * Note that there is a potential security hole here.  If the batcher is
  1945.  * /bin/sh, someone could ship you arbitrary stuff to run as shell commands.
  1946.  * The main protection you have is that the effective uid will be news, not
  1947.  * uucp and not the super user.  (That, plus the fact that BATCH is set to
  1948.  * "unbatch" as the system is distributed.)  If you want to run a batched link
  1949.  * and you are security concious, do not use /bin/sh as the unbatcher.
  1950.  * the thing to do is to change BATCH in your localize.sh file from /bin/sh
  1951.  * to some restricted shell which can only run rnews.
  1952.  */
  1953. checkbatch()
  1954. {
  1955.     int c;
  1956.  
  1957. #ifdef BATCH
  1958.     c = getc(stdin);
  1959.     ungetc(c, stdin);
  1960.     clearerr(stdin);
  1961.     if (c == '#') {
  1962.         reset_stdin();
  1963.         execl(BATCH, "news-unpack", 0);
  1964.         xerror("Unable to exec shell to unpack news.\n");
  1965.     }
  1966. #endif
  1967. }
  1968.  
  1969. /*
  1970.  * We've already done a read on stdin, and we want to seek back to the
  1971.  * beginning.  We want the real file descriptor (beyond buffers) to
  1972.  * reflect the true beginning.  Do whatever is necessary.
  1973.  */
  1974. reset_stdin()
  1975. {
  1976.     register FILE *ofd;
  1977.     register int c;
  1978.     char *ofdname;
  1979.  
  1980.     /* First try to seek back - if so, it's a cheap way back. */
  1981.     if (lseek(0, 0L, 0) == 0)
  1982.         return;
  1983.  
  1984.     /* Can't seek, so have to copy input to a file and use that. */
  1985.     ofdname = "/tmp/inewsXXXXX";
  1986.     mktemp(ofdname);
  1987.     ofd = fopen(ofdname, "w");
  1988.     while ((c=getc(stdin)) != EOF)
  1989.         putc(c, ofd);
  1990.     fclose(stdin);
  1991.     fclose(ofd);
  1992.  
  1993.     /* Now for a few lower level hacks to reopen stdin and make
  1994.      * absolutely sure that the right fd's are done for the exec.
  1995.      */
  1996.     close(0);        /* to make sure stdin is really closed. */
  1997.     open(ofdname, 0);    /* returns zero */
  1998.     unlink(ofdname);    /* to avoid cleaning it up later. */
  1999. }
  2000. !E!O!F!
  2001.  
  2002. cat > artfile/makeaf.c <<\!E!O!F!
  2003. #include <stdio.h>
  2004. #include "af.h"
  2005.  
  2006.  
  2007.  
  2008. /*
  2009.  * Create a new artfile.
  2010.  */
  2011.  
  2012. makeaf(name, idtlen, maxng, ttlen)
  2013.       char *name ;
  2014.       {
  2015.       register FILE *fp ;
  2016.       DPTR offset, count ;
  2017.       struct afheader afhd ;
  2018.  
  2019.       if ((fp = fopen(name, "w")) == NULL)
  2020.             xerror("Can't create %s", name) ;
  2021.       offset = count = sizeof afhd ;
  2022.       afhd.af_magic = AF_MAGIC ;
  2023.       afhd.af_version = AF_VERSION ;
  2024.       afhd.af_idtab = offset ;
  2025.       afhd.af_idtlen = idtlen ;
  2026.       offset += idtlen * sizeof (DPTR) ;
  2027.       afhd.af_nglist = offset ;
  2028.       afhd.af_maxng = maxng ;
  2029.       offset += maxng * sizeof (DPTR) ;
  2030.       afhd.af_titletab = offset ;
  2031.       afhd.af_ttlen = ttlen ;
  2032.       offset += ttlen * sizeof (DPTR) ;
  2033.       afhd.af_records = afhd.af_free = offset ;
  2034.       fwrite((char *)&afhd, sizeof afhd, 1, fp) ;
  2035.       while (count < offset) {
  2036.             putc('\0', fp) ;
  2037.             count++ ;
  2038.       }
  2039.       if (ferror(fp) || fclose(fp) == EOF)
  2040.             xerror("Write error in makeaf") ;
  2041. }
  2042. !E!O!F!
  2043.  
  2044. cat > artfile/mkngfile <<\!E!O!F!
  2045. # Construct the groupfile.
  2046. awk '{ print $1 " " NR }' ${1-/usr/lib/news/active} > /tmp/ng$$
  2047. wc -l < /tmp/ng$$
  2048. cat /tmp/ng$$
  2049. !E!O!F!
  2050. chmod +x artfile/mkngfile
  2051.  
  2052. cat > artfile/ngtab.c <<\!E!O!F!
  2053. #include <stdio.h>
  2054. #include "ng.h"
  2055.  
  2056.  
  2057. static char MODGROUPS[] = "all.announce,mod.all,all.mod,fa.all,control,junk" ;
  2058. struct ngrec *ngroup ;
  2059. extern int maxng ;
  2060.  
  2061.  
  2062.  
  2063. /*
  2064.  * Read in the newsgroup file.
  2065.  */
  2066.  
  2067. getngtab() {
  2068.       struct ngrec ng ;
  2069.       char *savestr(), *calloc(), *realloc() ;
  2070.  
  2071.       gfopen() ;
  2072.       if ((ngroup = calloc(sizeof(*ngroup), maxng)) == NULL)
  2073.             xerror("out of space") ;
  2074.       ALL_GROUPS(ng) {
  2075.             ngroup[ng.g_num - 1] = ng ;
  2076.       }
  2077.       gfclose() ;
  2078. }
  2079.  
  2080.  
  2081.  
  2082. /*
  2083.  * Initialize without reading in the newsgroup file.
  2084.  */
  2085.  
  2086. ngtinit() {
  2087.       char *ckmalloc() ;
  2088.  
  2089.       maxng = 0 ;
  2090.       ngroup = ckmalloc(sizeof(struct ngrec)) ;
  2091. }
  2092.  
  2093.  
  2094.  
  2095. /*
  2096.  * Convert a newsgroup number to a newsgroup name
  2097.  */
  2098.  
  2099. char *
  2100. ngname(num) {
  2101.       return ngroup[num - 1].g_name ;
  2102. }
  2103.  
  2104.  
  2105.  
  2106. /*
  2107.  * Convert a newsgroup name to a number
  2108.  */
  2109.  
  2110. int
  2111. ngnum(name)
  2112.       char *name ;
  2113.       {
  2114.       register i ;
  2115.       register struct ngrec *gp ;
  2116.       char n[MAXNGNAME] ;
  2117.  
  2118.       scopyn(name, n, MAXNGNAME) ;
  2119.       for (gp = ngroup, i = maxng ; --i >= 0 ; gp++)
  2120.             if (strcmp(gp->g_name, n) == 0)
  2121.                   return gp - ngroup + 1 ;
  2122.       printf("ngnum: %s not found\n", name) ;        /*DEBUG*/
  2123.       return -1 ;
  2124. }
  2125.  
  2126.  
  2127.  
  2128. newng(name)
  2129.       char *name ;
  2130.       {
  2131.       register int i ;
  2132.  
  2133.       for (i = 0 ; i < maxng ; i++) {
  2134.             if (ngroup[i].g_name[0] == '\0')
  2135.                   break ;
  2136.       }
  2137.       printf("newng %s assigns %d", name, i + 1) ;    /*DEBUG*/
  2138.       if (i == maxng) {
  2139.             if ((ngroup = realloc((char *)ngroup, (i + 1) * sizeof ngroup[0])) == NULL)
  2140.                   xerror("out of space") ;
  2141.             maxng++ ;
  2142.             printf(", maxng upped") ;            /*DEBUG*/
  2143.       }
  2144.       printf("\n") ;                    /*DEBUG*/
  2145.       scopyn(name, ngroup[i].g_name, MAXNGNAME) ;
  2146.       ngroup[i].g_flags = ngmatch(name, MODGROUPS)? G_MOD : 0 ;
  2147.       return ngroup[i].g_num = i + 1 ;
  2148. }
  2149.  
  2150.  
  2151.  
  2152. writengfile() {
  2153.       char newname[64], curname[64], oldname[64] ;
  2154.       FILE *fp ;
  2155.       int i ;
  2156.       register struct ngrec *gp ;
  2157.       extern char LIB[] ;
  2158.  
  2159.       printf("writeng called\n") ;        /*DEBUG*/
  2160.       sprintf(curname, "%s/groupfile", LIB) ;
  2161.       sprintf(newname, "%s.tmp", curname) ;
  2162.       sprintf(oldname, "%s.bak", curname) ;
  2163.       unlink(newname) ;
  2164.       if ((fp = fopen(newname, "w")) == NULL)
  2165.             xerror("Can't create %s", newname) ;
  2166.       fprintf(fp, "%d\n", maxng) ;
  2167.       for (i = maxng, gp = ngroup ; --i >= 0 ; gp++) {
  2168.             fprintf(fp, "%s %d", gp->g_name, gp->g_num) ;
  2169.             if (gp->g_flags & G_MOD)
  2170.                   fputs(" -m", fp) ;
  2171.             fputc('\n', fp) ;
  2172.       }
  2173.       if (ferror(fp) || fclose(fp) == EOF)
  2174.             xerror("Write error on %s", newname) ;
  2175.       rename(curname, oldname) ;
  2176.       if (rename(newname, curname) < 0)
  2177.             xerror("rename %s failed", newname) ;
  2178. }
  2179. !E!O!F!
  2180.  
  2181. cat > artfile/title.c <<\!E!O!F!
  2182. #include <stdio.h>
  2183. #include "af.h"
  2184.  
  2185. #define MAXTITLE 256    /* where does this belong? */
  2186. #define equal(s1, s2)    (strcmp(s1, s2) == 0)
  2187.  
  2188.  
  2189. /*
  2190.  * Return a pointer to the hash chain for this title.
  2191.  */
  2192.  
  2193. DPTR
  2194. htitle(title)
  2195.       register char *title ;
  2196.       {
  2197.       char buf[MAXTITLE] ;
  2198.  
  2199.       while (isre(title))
  2200.             for (title += 3 ; *title == ' ' ; title++) ;
  2201.       strcpy(buf, title) ;
  2202.       rmnf(buf) ;
  2203.       return afhd.af_titletab + hash(buf, afhd.af_ttlen) * sizeof(DPTR) ;
  2204. }
  2205.  
  2206.  
  2207.  
  2208. /*
  2209.  * Determine if a1 is the parent of a2 using titles.
  2210.  */
  2211.  
  2212. tparent(a1, a2)
  2213.       struct artrec *a1, *a2 ;
  2214.       {
  2215.       char t1[MAXTITLE], t2[MAXTITLE] ;
  2216.       char *p ;
  2217.  
  2218.       if (a1->a_subtime > a2->a_subtime || !isre(a2->a_title))
  2219.             return 0 ;
  2220.       strcpy(t1, a1->a_title), strcpy(t2, a2->a_title) ;
  2221.       if (rmnf(t1)) {
  2222.             if (!rmnf(t2))
  2223.                   return 0 ;
  2224.       } else {
  2225.             rmnf(t2) ;
  2226.       }
  2227.       for (p = t2 + 3 ; *p == ' ' ; p++) ;    /* skip over "Re:" */
  2228.       if (!equal(t1, p))
  2229.             return 0 ;
  2230.       return 1 ;
  2231. }
  2232. !E!O!F!
  2233.  
  2234. echo Part 1 of 7 extracted.
  2235.  
  2236.  
  2237.