home *** CD-ROM | disk | FTP | other *** search
/ Super Net 1 / SUPERNET_1.iso / PC / OTROS / EXTRAS / UUCODE / UUPC / TEST / UPC12ES4.ZIP / RNEWS / rnews.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-11-20  |  53.1 KB  |  1,544 lines

  1. /*--------------------------------------------------------------------*/
  2. /*    r n e w s . c                                                   */
  3. /*                                                                    */
  4. /*    Receive incoming news into the news directory.                  */
  5. /*                                                                    */
  6. /*    Written by Mike Lipsie; modified for UUPC/extended 1.11s by     */
  7. /*    Andrew H., Derbyshire.                                          */
  8. /*                                                                    */
  9. /*    Changes and Compilation Copyright (c) 1992 by Andrew H.         */
  10. /*    Derbyshire.  All rights reserved except as granted by the       */
  11. /*    general UUPC/extended license.                                  */
  12. /*                                                                    */
  13. /*    This package has been substantially modified.  It will now      */
  14. /*    copy compressed articles (assumed batches but they could be     */
  15. /*    single articles) to the CMPRSSED directory and it will          */
  16. /*    unbatch (if necessary) and deliver articles to their            */
  17. /*    appropriate newsgroup directories.  At the end, if the file     */
  18. /*    was compressed it will invoke a batch file which will           */
  19. /*    uncompress the file and then feed it back to rnews.             */
  20. /*                                                                    */
  21. /*    Appropriate is defined as                                       */
  22. /*                                                                    */
  23. /*       (a) the newsgroup is in the active file and                  */
  24. /*       (b) the directory name is the group name with all            */
  25. /*           the"."s replaced with "/"s and all of that under the     */
  26. /*           news directory.                                          */
  27. /*                                                                    */
  28. /*    Names are insured to be valid by ImportNewsGroup, which maps    */
  29. /*    invalid characters and truncates names as required.             */
  30. /*--------------------------------------------------------------------*/
  31.  
  32. /*--------------------------------------------------------------------*/
  33. /*                          RCS Information                           */
  34. /*--------------------------------------------------------------------*/
  35.  
  36. /*
  37.  *       $Id: rnews.c 1.25 1993/11/20 13:47:06 rommel Exp $
  38.  *
  39.  *       $Log: rnews.c $
  40.  * Revision 1.25  1993/11/20  13:47:06  rommel
  41.  * Handle duplicate message ids caused by truncating keys at 80 characters
  42.  *
  43.  * Revision 1.24  1993/11/06  17:56:09  rhg
  44.  * Drive Drew nuts by submitting cosmetic changes mixed in with bug fixes
  45.  *
  46.  * Revision 1.22  1993/10/30  22:27:57  rommel
  47.  * News history support
  48.  *
  49.  * Revision 1.21  1993/10/28  00:18:10  ahd
  50.  * Drop unneeded tzset() call
  51.  *
  52.  * Revision 1.20  1993/10/24  21:51:14  ahd
  53.  * Use one token on Requestor line, per rhg
  54.  *
  55.  * Revision 1.19  1993/10/12  01:31:06  ahd
  56.  * Normalize comments to PL/I style
  57.  *
  58.  * Revision 1.18  1993/10/09  13:15:43  rhg
  59.  * Suppress compiler warnings
  60.  *
  61.  * Revision 1.17  1993/09/27  04:04:06  ahd
  62.  * Reduce buffer sizes to avoid 16 bit stack over flows
  63.  *
  64.  * Revision 1.16  1993/09/24  03:43:27  ahd
  65.  * Double buffers to avoid crashes during Disney Stock Flame War
  66.  *
  67.  * Revision 1.15  1993/09/21  01:42:13  ahd
  68.  * Suppress changes to body of delivered news
  69.  *
  70.  * Revision 1.14  1993/09/20  04:41:54  ahd
  71.  * OS/2 2.x support
  72.  *
  73.  * Revision 1.13  1993/07/31  16:26:01  ahd
  74.  * Changes in support of Robert Denny's Windows support
  75.  *
  76.  * Revision 1.12  1993/07/22  23:19:50  ahd
  77.  * First pass for Robert Denny's Windows 3.x support changes
  78.  *
  79.  * Revision 1.11  1993/05/03  02:41:57  ahd
  80.  * Correct name of file to set into binary mode
  81.  *
  82.  * Revision 1.10  1993/04/19  13:16:20  ahd
  83.  * Binary mode for snews
  84.  *
  85.  * Revision 1.9  1993/04/17  13:40:39  ahd
  86.  * fix compile errors for snews fix
  87.  *
  88.  * Revision 1.8  1993/04/17  13:23:37  ahd
  89.  * make snews option more compatible with snews (which is brain dead)
  90.  *
  91.  * Revision 1.7  1993/04/16  12:55:36  dmwatt
  92.  * Bounds check group lengths
  93.  *
  94.  * Revision 1.5  1993/04/11  00:33:54  ahd
  95.  * Global edits for year, TEXT, etc.
  96.  *
  97.  * Revision 1.4  1993/03/24  01:57:30  ahd
  98.  * Corrections for short articles
  99.  * Corrections for articles claimed to be zero length
  100.  * Resync gracefully after incorrect length descriptor
  101.  *
  102.  * Revision 1.3  1993/03/06  23:04:54  ahd
  103.  * Do not delete open files
  104.  *
  105.  * Revision 1.2  1992/11/22  21:14:21  ahd
  106.  * Reformat selected sections of code
  107.  * Check for premature end of articles in batched news
  108.  *
  109.  */
  110.  
  111. static const char rcsid[] =
  112.          "$Id: rnews.c 1.25 1993/11/20 13:47:06 rommel Exp $";
  113.  
  114. /*--------------------------------------------------------------------*/
  115. /*                        System include files                        */
  116. /*--------------------------------------------------------------------*/
  117.  
  118. #include <stdio.h>
  119. #include <stdlib.h>
  120. #include <string.h>
  121. #include <ctype.h>
  122. #include <time.h>
  123. #include <fcntl.h>
  124. #include <io.h>
  125. #include <process.h>
  126.  
  127. /*--------------------------------------------------------------------*/
  128. /*                    UUPC/extended include files                     */
  129. /*--------------------------------------------------------------------*/
  130.  
  131. #include "lib.h"
  132. #include "active.h"
  133. #include "getopt.h"
  134. #include "getseq.h"
  135. #include "history.h"
  136. #include "hlib.h"
  137. #include "import.h"
  138. #include "importng.h"
  139. #include "logger.h"
  140. #include "timestmp.h"
  141.  
  142. #include "execute.h"
  143.  
  144. /*--------------------------------------------------------------------*/
  145. /*                           Global defines                           */
  146. /*--------------------------------------------------------------------*/
  147.  
  148. #define MAGIC_FIRST       0x1F   /* Magic numbers for compressed batches */
  149. #define MAGIC_COMPRESS    0x9D
  150. #define MAGIC_FREEZE      0x9F
  151. #define MAGIC_GZIP        0x8B
  152.  
  153. #ifdef BIT32ENV
  154. #define DISNEY (BUFSIZ*2)
  155. #else
  156. #define DISNEY (BUFSIZ*4/3)
  157. #endif
  158.  
  159. /*--------------------------------------------------------------------*/
  160. /*                          Global variables                          */
  161. /*--------------------------------------------------------------------*/
  162.  
  163. currentfile();
  164.  
  165. extern struct grp *group_list;   /* List of all groups */
  166. time_t now;
  167. void *history;
  168.  
  169. /*--------------------------------------------------------------------*/
  170. /*                       Functions in this file                       */
  171. /*--------------------------------------------------------------------*/
  172.  
  173. static boolean deliver_article(char *art_fname, long art_size);
  174.                               /* Distribute the article to the
  175.                                  proper newsgroups                   */
  176.  
  177. static boolean copy_file(FILE *f, char *group,
  178.             char *xref);      /* Copy file (f) to newsgroup          */
  179.  
  180. static struct grp *find_newsgroup(const char *grp);
  181.                               /* Get the grp struct for the newsgroup */
  182.  
  183. static void add_newsgroup(const char *grp, boolean moderated);
  184.                               /* add new group to active file */
  185.  
  186. static void del_newsgroup(const char *grp);
  187.                               /* delete group from active file */
  188.  
  189. static void control_message(const char *control);
  190.                               /* process control message */
  191.  
  192. static int get_snum(const char *group, char *snum);
  193.                                     /* Get (and format) the next article
  194.                                        number in group                 */
  195.  
  196. static void fixEOF( char *buf, int bytes );
  197.  
  198. static int Single( char *filename , FILE *stream );
  199.  
  200. static int Compressed( char *filename , FILE *in_stream ,
  201.                        char *unpacker , char *suffix );
  202.  
  203. static int Batched( char *filename, FILE *stream);
  204.  
  205. static void xmit_news( char *sysname, FILE *in_stream );
  206.  
  207. static int copy_snews( char *filename, FILE *stream );
  208.  
  209. /*--------------------------------------------------------------------*/
  210. /*    m a i n                                                         */
  211. /*                                                                    */
  212. /*    Main program                                                    */
  213. /*                                                                    */
  214. /*    Exit conditions                                                 */
  215. /*                                                                    */
  216. /*    0 - Success                                                     */
  217. /*    1 - System configuration failed                                 */
  218. /*    2 - Unable to open working file                                 */
  219. /*    4 - out of memory                                               */
  220. /*    5 - Unable to create history dbm file                           */
  221. /*    6 - Problem decompressing news batch                            */
  222. /*    7 - Unable to create cmprssed directory                         */
  223. /*--------------------------------------------------------------------*/
  224.  
  225. void main( int argc, char **argv)
  226. {
  227.  
  228.    FILE *f;
  229.    char in_filename[FILENAME_MAX];
  230.    char filename[FILENAME_MAX];
  231.    int c;
  232.    int status;
  233.  
  234.    now = time(nil(time_t));
  235.  
  236. #if defined(__CORE__)
  237.    copywrong = strdup(copyright);
  238.    checkref(copywrong);
  239. #endif
  240.  
  241.    logfile = stderr;             /* Prevent redirection of error      */
  242.                                  /* messages during configuration     */
  243.  
  244.    banner( argv );
  245.  
  246.    if (!configure( B_NEWS ))
  247.       exit(1);    /* system configuration failed */
  248.  
  249.    openlog( NULL );           /* Begin logging to disk            */
  250.  
  251.    if (argc > 1)
  252.    {
  253.       int option;
  254.  
  255.     /*------------------------------------------------------------*/
  256.     /*                          parse arguments                   */
  257.     /*------------------------------------------------------------*/
  258.  
  259.        while ((option = getopt(argc, argv, "f:x:")) != EOF)
  260.        {
  261.            switch (option)
  262.            {
  263.                case 'f':
  264.                   strcpy(in_filename, optarg);
  265.                   f = freopen(in_filename, "r", stdin);
  266.                   if (f == NULL) {
  267.                      printerr( in_filename );
  268.                      panic();
  269.                   } else
  270.                      printmsg(2, "Opened %s as newsfile", in_filename);
  271.  
  272.                   break;
  273.  
  274.                case 'x':
  275.                   debuglevel = atoi(optarg);
  276.                   break;
  277.  
  278.                case '?':
  279.                   puts("\nUsage:\trnews [-f newsfile] [-x debug]");
  280.                   return;
  281.            } /* break */
  282.  
  283.        } /* while */
  284.     } /* if (argc > 1) */
  285.  
  286.    setmode(fileno(stdin), O_BINARY);   /* Don't die on control-Z, etc */
  287.  
  288. /*--------------------------------------------------------------------*/
  289. /*    If we are processing snews input, write it all out to the       */
  290. /*    news directory as one file and return gracefully.               */
  291. /*--------------------------------------------------------------------*/
  292.  
  293.    if ( bflag[F_SNEWS])
  294.    {
  295.       char *savetemp = E_tempdir;   /* Save the real temp directory  */
  296.  
  297.       if (bflag[F_HISTORY])
  298.       {
  299.          printmsg(0,
  300.                "rnews: Conflicting options snews and history specified!");
  301.          panic();
  302.       } /* else if */
  303.  
  304.  
  305.       E_tempdir = E_newsdir;        /* Generate this file in news    */
  306.       mktempname(filename, "ART");  /* Get the file name             */
  307.       E_tempdir = savetemp;         /* Restore true directory name   */
  308.       exit (copy_snews( filename, stdin ));
  309.                                     /* Dump news into NEWS directory */
  310.    }
  311.    else
  312.       mktempname(filename, "tmp");  /* Make normal temp name         */
  313.  
  314. /*--------------------------------------------------------------------*/
  315. /*             Load the active file and validate its data             */
  316. /*--------------------------------------------------------------------*/
  317.  
  318.    get_active();           /* Get sequence numbers for groups
  319.                               from active file                 */
  320.    validate_newsgroups();  /* Make sure all directories exist  */
  321.  
  322. /*--------------------------------------------------------------------*/
  323. /*                 Open (or create) the history file                  */
  324. /*--------------------------------------------------------------------*/
  325.  
  326.    if ( bflag[F_HISTORY] )
  327.      history = open_history("history");
  328.  
  329. /*--------------------------------------------------------------------*/
  330. /*    This loop copies the file to the NEWS directory.                */
  331. /*                                                                    */
  332. /*    A news article/batch either has a '#' character as its first    */
  333. /*    character or it does not.                                       */
  334. /*                                                                    */
  335. /*    If it does not it is a single (unbatched, uncompressed)         */
  336. /*    article.                                                        */
  337. /*                                                                    */
  338. /*    If the first character _is_ a '#', the first line is #!         */
  339. /*    cunbatch\n which means that it is a compressed batch; it        */
  340. /*    will be uncompressed and then re-fed to rnews or the first      */
  341. /*    line can be #! rnews nnn\n (where nnn is some number) which     */
  342. /*    means that the next nnn characters are an article and that      */
  343. /*    more might follow.                                              */
  344. /*                                                                    */
  345. /*    Due to a "feature" in the compressed batch, there may be        */
  346. /*    _no_ articles batched (an article destined for transmittal      */
  347. /*    is cancelled before being sent).                                */
  348. /*                                                                    */
  349. /*    Since this is a bit spread out, the various clauses of the      */
  350. /*    if statement will be marked with boxed 1, 2, or 3 (and a        */
  351. /*    brief explanation.                                              */
  352. /*--------------------------------------------------------------------*/
  353.  
  354. /*--------------------------------------------------------------------*/
  355. /*    Compressed files need to be read in BINARY mode so that         */
  356. /*    "magic" characters (like ^Z) don't upset it.  Batched files     */
  357. /*    need to be read in TEXT mode so that the character count is     */
  358. /*    correct.  The other case doesn't matter.                        */
  359. /*--------------------------------------------------------------------*/
  360.  
  361.    c = getc(stdin);
  362.    ungetc(c, stdin);
  363.  
  364.    if (c != '#' && c != MAGIC_FIRST) {
  365.  
  366.       /***********************************************/
  367.       /* 1  single (unbatched, uncompressed) article */
  368.       /***********************************************/
  369.  
  370.       status = Single(filename, stdin);
  371.  
  372.    }
  373.    else {
  374.  
  375.       unsigned char buf[BUFSIZ];
  376.       int bytes;
  377.       char *unpacker = NULL, *suffix = NULL;
  378.  
  379.       bytes = fread(buf, 1, 12, stdin);
  380.  
  381.       if (bytes == 12 && memcmp(buf, "#! ", 3) == 0
  382.                       && memcmp(buf + 4, "unbatch", 7) == 0 )
  383.       {
  384.         /* ignore headers like "#! cunbatch" where the 'c' can  *
  385.          * also be one of "fgz" for frozen or [g]zipped batches */
  386.         bytes = fread(buf, 2, 1, stdin);
  387.         fseek(stdin, 12L, SEEK_SET);
  388.       }
  389.       else
  390.         fseek(stdin, 0L, SEEK_SET);
  391.  
  392.       if (buf[0] == MAGIC_FIRST)
  393.         switch (buf[1])
  394.         {
  395.         case MAGIC_COMPRESS:
  396.           unpacker = "compress";
  397.           suffix = "Z";
  398.           break;
  399.         case MAGIC_FREEZE:
  400.           unpacker = "freeze";
  401.           suffix = "F";
  402.           break;
  403.         case MAGIC_GZIP:
  404.           unpacker = "gzip";
  405.           suffix = "z";
  406.           break;
  407.         }
  408.  
  409.       if (unpacker != NULL)
  410.       {
  411.  
  412.          /***********************************************/
  413.          /*  2  Compressed batch                        */
  414.          /***********************************************/
  415.  
  416.          status = Compressed(filename, stdin, unpacker, suffix);
  417.  
  418.       }
  419.       else {
  420.  
  421.          /***********************************************/
  422.          /* 3  Uncompressed batch                       */
  423.          /***********************************************/
  424.  
  425.          status = Batched( filename, stdin );
  426.       } /* else */
  427.    } /* else */
  428.  
  429. /*--------------------------------------------------------------------*/
  430. /*                     Close open files and exit                      */
  431. /*--------------------------------------------------------------------*/
  432.  
  433.    put_active();
  434.  
  435.    if ( bflag[F_HISTORY] )
  436.       close_history(history);
  437.  
  438.    exit(status);
  439.  
  440. } /*main*/
  441.  
  442. /*--------------------------------------------------------------------*/
  443. /*    S i n g l e                                                     */
  444. /*                                                                    */
  445. /*    Deliver a single article to the proper news group(s)            */
  446. /*--------------------------------------------------------------------*/
  447.  
  448. static int Single( char *filename , FILE *stream )
  449. {
  450.    char tmp_fname[FILENAME_MAX];
  451.    FILE *tmpf;
  452.    char buf[BUFSIZ];
  453.    unsigned chars_read;
  454.    unsigned chars_written;
  455.    long article_size = 0;
  456.  
  457.  
  458. /*--------------------------------------------------------------------*/
  459. /* Make a file name and then open the file to write the article into  */
  460. /*--------------------------------------------------------------------*/
  461.  
  462.    tmpf = FOPEN(filename, "w", BINARY_MODE);
  463.  
  464.    if ( tmpf == NULL )
  465.    {
  466.       printerr( tmp_fname );
  467.       panic();
  468.    }
  469.  
  470. /*--------------------------------------------------------------------*/
  471. /*              Now copy the input into our holding bin               */
  472. /*--------------------------------------------------------------------*/
  473.  
  474.    while ((chars_read = fread(buf,sizeof(char), BUFSIZ, stream)) != 0)
  475.    {
  476.  
  477.       chars_written = fwrite(buf, sizeof(char), chars_read, tmpf);
  478.       article_size += chars_written;
  479.       if (chars_written != chars_read)
  480.       {
  481.          printerr( filename );
  482.          printmsg(0, "rnews: Error writing single article to working file");
  483.          fclose( tmpf );
  484.          unlink( filename );
  485.          panic();
  486.       }
  487.    }
  488.  
  489. /*--------------------------------------------------------------------*/
  490. /*     Close the file, deliver the article, and return the caller     */
  491. /*--------------------------------------------------------------------*/
  492.  
  493.    fclose(tmpf);
  494.  
  495.    deliver_article(filename, article_size);
  496.    unlink( filename );
  497.    return 0;
  498.  
  499. } /* Single */
  500.  
  501. /*--------------------------------------------------------------------*/
  502. /*    C o m p r e s s e d                                             */
  503. /*                                                                    */
  504. /*    Decompress news                                                 */
  505. /*--------------------------------------------------------------------*/
  506.  
  507. static int Compressed( char *filename , FILE *in_stream ,
  508.                        char *unpacker , char *suffix )
  509. {
  510.  
  511.    FILE *work_stream;
  512.  
  513.    char zfile[FILENAME_MAX];
  514.    char unzfile[FILENAME_MAX];
  515.    char buf[BUFSIZ];
  516.  
  517.    boolean first_time = TRUE;
  518.    long cfile_size = 0L;
  519.    size_t chars_read, i;
  520.    int status = 0;
  521.    boolean needtemp = TRUE;
  522.  
  523.    char *sysname;             /* For reading systems to process   */
  524.  
  525. /*--------------------------------------------------------------------*/
  526. /*        Copy the compressed file to the "holding" directory         */
  527. /*--------------------------------------------------------------------*/
  528.  
  529.    while( needtemp )
  530.    {
  531.       mktempname( zfile , suffix );    /* Generate "compressed" file
  532.                                           name                       */
  533.       strcpy( unzfile, zfile );
  534.       unzfile[ strlen(unzfile)-2 ] = '\0';
  535.  
  536.       if ( access( unzfile, 0 ))  /* Does the host file exist?       */
  537.          needtemp = FALSE;        /* No, we have a good pair         */
  538.       else
  539.          printmsg(0,"Had compressed name %s, found %s already exists!",
  540.                   zfile, unzfile );
  541.  
  542.    } /* while */
  543.  
  544. /*--------------------------------------------------------------------*/
  545. /*                 Open the file, with error recovery                 */
  546. /*--------------------------------------------------------------------*/
  547.  
  548.    if ((work_stream = FOPEN(zfile, "w", BINARY_MODE)) == nil(FILE))
  549.    {
  550.       printmsg(0, "Compressed: Can't open %s (%d)", zfile, errno);
  551.       printerr(zfile);
  552.       return 2;
  553.    }
  554.  
  555.    printmsg(2, "Compressed: Copy to %s for later processing", zfile);
  556.  
  557. /*--------------------------------------------------------------------*/
  558. /*                 Main loop to copy compressed file                  */
  559. /*--------------------------------------------------------------------*/
  560.  
  561.    while ((chars_read = fread(buf,sizeof(char), BUFSIZ, in_stream)) != 0)
  562.    {
  563.       char *t_buf = buf;
  564.       i = fwrite(t_buf,sizeof(char),chars_read,work_stream);
  565.  
  566.       if (i != chars_read)
  567.       {
  568.          fclose( work_stream );
  569.          printerr( zfile );
  570.          unlink( zfile );     /* Kill the compressed input file      */
  571.          panic();
  572.       }
  573.  
  574.       cfile_size += (long)chars_read;
  575.    } /* while */
  576.  
  577.    fclose(work_stream);
  578.  
  579. /*--------------------------------------------------------------------*/
  580. /*             If the file is empty, delete it gracefully             */
  581. /*--------------------------------------------------------------------*/
  582.  
  583.    if (cfile_size == 3)
  584.    {
  585.       unlink(zfile); /* Get rid of null file */
  586.       printmsg(1, "Compressed: %s empty, deleted", zfile);
  587.       return status;
  588.    }
  589.    else
  590.       printmsg(2,"Compressed: Copy to %s complete, %ld characters",
  591.                zfile, cfile_size);
  592.  
  593. /*--------------------------------------------------------------------*/
  594. /*      Special hack for creating mirror images of the news feed      */
  595. /*--------------------------------------------------------------------*/
  596.  
  597.    sysname = getenv( "UUPCSHADOWS" );
  598.  
  599.    if ( sysname != NULL )
  600.    {
  601.       strcpy( buf, sysname);
  602.  
  603.       sysname = strtok( buf, WHITESPACE );
  604.  
  605.       while( sysname != NULL )
  606.       {
  607.          printmsg(1,"Compressed: Shadowing news to %s", sysname );
  608.          fseek(in_stream, 0L, SEEK_SET);      /* Back to the beginning */
  609.          xmit_news( sysname, in_stream );
  610.          sysname = strtok( NULL, WHITESPACE );
  611.       }
  612.  
  613.    } /* if */
  614.  
  615. /*--------------------------------------------------------------------*/
  616. /*          Uncompress the article and feed it back to rnews          */
  617. /*--------------------------------------------------------------------*/
  618.  
  619.    sprintf(buf, "-d %s", zfile);
  620.    status = execute( unpacker, buf, NULL, NULL, TRUE, FALSE);
  621.  
  622.    unlink( zfile );           /* Kill the compressed input file      */
  623.  
  624.    if (status != 0)
  625.    {
  626.       if (status == -1)
  627.       {
  628.           printmsg( 0, "Compress: spawn failed completely" );
  629.           printerr( unpacker );
  630.       }
  631.       else
  632.           printmsg(0, "%s command failed (exit code %d)",
  633.                         unpacker, status);
  634.       panic();
  635.    } /* if status != 0 */
  636.  
  637. /*--------------------------------------------------------------------*/
  638. /*            Now process the file as normal batched news             */
  639. /*--------------------------------------------------------------------*/
  640.  
  641.                               /* Create uncompressed output file name  */
  642.  
  643.    work_stream = FOPEN( unzfile, "r", BINARY_MODE);
  644.    if ( work_stream == NULL )
  645.    {
  646.       printerr( unzfile );
  647.       panic();
  648.    }
  649.  
  650.    status = Batched( filename, work_stream );
  651.  
  652. /*--------------------------------------------------------------------*/
  653. /*                   Clean up and return to caller                    */
  654. /*--------------------------------------------------------------------*/
  655.  
  656.    fclose( work_stream );
  657.    unlink( unzfile );
  658.  
  659.    return status;
  660.  
  661. } /* Compressed */
  662.  
  663. /*--------------------------------------------------------------------*/
  664. /*    B a t c h e d                                                   */
  665. /*                                                                    */
  666. /*    Handle batched, uncompressed news                               */
  667. /*--------------------------------------------------------------------*/
  668.  
  669. static int Batched( char *filename, FILE *stream)
  670. {
  671.  
  672.    char buf[BUFSIZ * 2];
  673.    int status = 0;
  674.    long article_size;
  675.    int articles = 0;
  676.    int ignored  = 0;
  677.    boolean gotsize = FALSE;
  678.    int chars_read;
  679.    int chars_written;
  680.  
  681. /*--------------------------------------------------------------------*/
  682. /*    This is an uncompressed batch.  Copy it to the working          */
  683. /*    directory and then distribute the individual articles.          */
  684. /*--------------------------------------------------------------------*/
  685.  
  686.    fseek(stream, 0L, SEEK_SET);        /* Back to the beginning       */
  687.  
  688.    while( ! feof( stream ) && ! ferror( stream ))
  689.    {
  690.       long article_left;
  691.       int  max_read = (long) sizeof buf;
  692.       long skipped_lines = 0;
  693.       long skipped_bytes = 0;
  694.       FILE *tmpf;
  695.  
  696.  /*--------------------------------------------------------------------*/
  697.  /*    Handle next article (articles are separated by the line        */
  698.  /*    indicating their size when they are batched.)                  */
  699.  /*--------------------------------------------------------------------*/
  700.  
  701.       while ( ! gotsize )
  702.       {
  703.          if (fgets( buf, sizeof buf, stream ) == NULL)
  704.             break;
  705.  
  706.          if ( equaln( "#! rnews", buf, 8) )
  707.          {
  708.             article_size = 0;
  709.             sscanf(buf, "#! rnews %ld \n", &article_size);
  710.             gotsize = TRUE;
  711.          }
  712.          else {
  713.             skipped_lines ++;
  714.             skipped_bytes += strlen( buf );
  715.          }
  716.       } /* while */
  717.  
  718.       if ( skipped_lines )
  719.          printmsg(0,
  720.                   "Batched: Skipped %ld bytes in %ld "
  721.                   "lines after article %d",
  722.                   skipped_bytes,
  723.                   skipped_lines,
  724.                   articles );
  725.  
  726. /*--------------------------------------------------------------------*/
  727. /*                          Trap end of file                          */
  728. /*--------------------------------------------------------------------*/
  729.  
  730.       if ( ! gotsize )
  731.       {
  732.          if ( ferror( stream ))
  733.             printerr( "stdin" );
  734.          break;
  735.       }
  736.  
  737.       article_left = article_size;
  738.       gotsize = FALSE;
  739.  
  740. /*--------------------------------------------------------------------*/
  741. /*                   Open up our next working file                    */
  742. /*--------------------------------------------------------------------*/
  743.  
  744.       tmpf = FOPEN(filename, "w", BINARY_MODE);
  745.       if ( tmpf == NULL )
  746.       {
  747.          printerr( filename );
  748.          panic();
  749.       }
  750.  
  751.  /*--------------------------------------------------------------------*/
  752.  /*   Copy this article to the temp file (except for the last block)  */
  753.  /*--------------------------------------------------------------------*/
  754.  
  755.       if ( article_size )
  756.       {
  757.          do {
  758.             if ( article_left < max_read )
  759.                max_read = (int) article_left;
  760.  
  761.             chars_read = fread(buf, sizeof(char), max_read, stream);
  762.  
  763.             if ( (chars_read < max_read) && ferror( stream ))
  764.             {
  765.                printerr("STDIN");
  766.                panic();
  767.             }
  768.  
  769.             if ( chars_read == 0)
  770.                break;
  771.  
  772.             fixEOF( buf , chars_read );
  773.  
  774.             chars_written = fwrite(buf, sizeof(char), chars_read, tmpf);
  775.             if (chars_read != chars_written)
  776.             {
  777.                printmsg(0,"Batched: Read %d bytes, only wrote %d bytes of article %d",
  778.                      chars_read, chars_written , articles + 1);
  779.                printerr(filename);
  780.             }
  781.  
  782.             article_left -= chars_read;
  783.  
  784.          } while (article_left > 0);
  785.  
  786.          if ( article_left )     /* Premature EOF?                    */
  787.             printmsg(0,"Batched: Unexpected EOF for article %d, "
  788.                      "read %ld bytes of expected %ld",
  789.                       articles + 1,
  790.                       article_size - article_left, article_size );
  791.  
  792.       } /* if */
  793.       else {
  794.  
  795.          long actual_size = 0;
  796.  
  797.          do {
  798.             if (fgets( buf, sizeof buf, stream ) == NULL)
  799.             {
  800.                if ( ferror( stream ))
  801.                   printerr( filename );
  802.                break;
  803.             }
  804.  
  805.             chars_read = strlen( buf );
  806.  
  807.             if ( equaln( "#! rnews", buf, 8) )
  808.             {
  809.                sscanf(buf, "#! rnews %ld \n", &article_size);
  810.                gotsize = TRUE;
  811.             }
  812.             else if ( chars_read > 0 )
  813.             {
  814.                actual_size += chars_read;
  815.  
  816.                chars_written = fwrite(buf,
  817.                                       sizeof(char),
  818.                                       chars_read,
  819.                                       tmpf);
  820.                if (chars_read != chars_written)
  821.                {
  822.                   printmsg(0,
  823.                        "Batched: Read %d bytes, only wrote %d bytes of article %d",
  824.                         chars_read, chars_written , articles + 1);
  825.                   printerr(filename);
  826.                }
  827.             } /* else */
  828.  
  829.          } while( ! gotsize );
  830.  
  831.          article_size = actual_size;
  832.          printmsg(2,"Batched: Article %d size %ld",
  833.                      articles + 1,
  834.                      actual_size );
  835.       } /* else */
  836.  
  837.  /*--------------------------------------------------------------------*/
  838.  /*      Close the file, deliver its contents, and get rid of it      */
  839.  /*--------------------------------------------------------------------*/
  840.  
  841.       fclose(tmpf);
  842.       if ( ! deliver_article(filename, article_size) )
  843.          ignored ++;
  844.       unlink( filename );
  845.       articles ++;
  846.  
  847.    } /* while */
  848.  
  849. /*--------------------------------------------------------------------*/
  850. /*                          Return to caller                          */
  851. /*--------------------------------------------------------------------*/
  852.  
  853.    if ( ignored )
  854.       printmsg(1,"Batched: Unbatched %d articles (discarded %d of these)",
  855.                articles , ignored);
  856.    else
  857.       printmsg(1,"Batched: Unbatched %d articles", articles );
  858.    return status;
  859.  
  860. } /* Batched */
  861.  
  862. /*--------------------------------------------------------------------*/
  863. /*    f i x E O F                                                     */
  864. /*                                                                    */
  865. /*    Zap Cntrl-Z characters in the input stream                      */
  866. /*--------------------------------------------------------------------*/
  867.  
  868. static void fixEOF( char *buf, int bytes )
  869. {
  870.    static warn = TRUE;
  871.  
  872.    while ( bytes-- )
  873.    {
  874.       if ( *buf == ('Z' - 'A'))
  875.       {
  876.          *buf = 'Z';
  877.          if ( warn )
  878.          {
  879.             printmsg(0,"Altered Cntl-Z to Z");
  880.             warn = FALSE;
  881.          } /* if */
  882.       } /* if */
  883.    } /* while */
  884.  
  885. } /* fixEOF */
  886.  
  887. /*--------------------------------------------------------------------*/
  888. /*    d e l i v e r _ a r t i c l e                                   */
  889. /*                                                                    */
  890. /*    Determine delivery of a posting                                 */
  891. /*--------------------------------------------------------------------*/
  892.  
  893. static boolean deliver_article(char *art_fname, long art_size)
  894. {
  895.  
  896.    char groupy[MAXGRP];
  897.  
  898.    char *newsgroups = NULL;   /* The Newsgroups: line */
  899.    char *messageID  = NULL;   /* The Message-ID: line */
  900.  
  901.    char *gc_ptr;           /* Scratch pointers.  Mostly used to go */
  902.    char *gc_ptr1;              /*   down the list of newsgroups.      */
  903.  
  904.    FILE *tfile;            /* The article file */
  905.  
  906.    int n_hdrs;             /* Number of desired headers seen */
  907.    int b_xref = FALSE;
  908.    int b_control = FALSE;
  909.    int b_saved = FALSE;
  910.  
  911.    int line_len, groups_found;
  912.  
  913.    char hist_record[DISNEY];  /* buffer for history file
  914.                                  (also used for article)             */
  915.    char groups[DISNEY];
  916.    char message_buf[DISNEY];
  917.    char snum[10];
  918.  
  919.    tfile = FOPEN(art_fname, "r", BINARY_MODE);
  920.    if ( tfile == NULL )
  921.    {
  922.       printerr( art_fname );
  923.       panic();
  924.    }
  925.  
  926. /*--------------------------------------------------------------------*/
  927. /*    Get fields necessary for distribution (Newsgroups:)  and the    */
  928. /*    history file (Message-ID:).  Also, if the article is going      */
  929. /*    to more than one newsgroup, flag the creation of Xref: fields.  */
  930. /*--------------------------------------------------------------------*/
  931.  
  932.    n_hdrs = b_xref = 0;
  933.    while (n_hdrs < 3)
  934.    {
  935.       /* Get the next line */
  936.       gc_ptr = fgets(hist_record, sizeof(hist_record), tfile);
  937.  
  938. /*--------------------------------------------------------------------*/
  939. /*                    Check for end of the headers                    */
  940. /*--------------------------------------------------------------------*/
  941.  
  942.       if ((gc_ptr == NULL) || (strlen(hist_record) == 1))
  943.       {
  944.          /* Ooops.  Missing Message-ID: or Newsgroups: */
  945.          if (messageID == NULL)
  946.             printmsg(0, "Article has no Message-ID:, discarded");
  947.          else {
  948.             if (newsgroups == NULL)
  949.                printmsg(0,
  950.                     "Article %s has no Newsgroups: line, discarded",
  951.                     messageID);
  952.             else
  953.                break;
  954.          } /* else */
  955.  
  956.          fclose(tfile);
  957.  
  958.          return FALSE;
  959.       } /* if ((gc_ptr == NULL) || (strlen(hist_record) == 1)) */
  960.  
  961.       line_len = strlen(hist_record);
  962.  
  963.       if (hist_record[line_len-1] == '\n')
  964.          hist_record[(line_len--)-1] = '\0';
  965.  
  966.       if (hist_record[line_len-1] == '\r')
  967.          hist_record[(line_len--)-1] = '\0';
  968.  
  969.       if (equalni(hist_record, "Newsgroups:", strlen("Newsgroups:")))
  970.       {
  971.          /* Handle Newsgroups: line*/
  972.          if (newsgroups == NULL)
  973.          {
  974.             gc_ptr += strlen("Newsgroups:") + 1;
  975.             while (isspace(*gc_ptr))
  976.               gc_ptr++;
  977.             newsgroups = strcpy(groups, gc_ptr);
  978.             newsgroups[strlen(newsgroups)+1] = '\0';/* Guard char for rescan */
  979.             n_hdrs++;
  980.             b_xref = (strchr(newsgroups, ',') != NULL); /* more than 1 group */
  981.      }                     /* i.e. do we need to create a Xrefs: line ? */
  982.          else
  983.             printmsg(0, "Article has multiple Newsgroups: lines");
  984.       }
  985.       else if (equalni(hist_record, "Message-ID:", strlen("Message-ID:")))
  986.       {
  987.          /* Handle Message-ID: line */
  988.          if (messageID == NULL)
  989.          {
  990.             gc_ptr += strlen("Message-ID:") + 1;
  991.             while (isspace(*gc_ptr))
  992.               gc_ptr++;
  993.             messageID = message_buf;
  994.             messageID[0] = '\0';
  995.             if (*gc_ptr != '<')
  996.               strcat(messageID, "<");
  997.                strcat(messageID, gc_ptr);
  998.             if (messageID[strlen(messageID)-1] != '>')
  999.                strcat(messageID,">");
  1000.             n_hdrs++;
  1001.          } /* if (messageID == NULL) */
  1002.       }
  1003.       else if (equalni(hist_record, "Control:", strlen("Control:")))
  1004.       {
  1005.          /* Handle Control: line*/
  1006.          if (!b_control)
  1007.          {
  1008.             control_message(hist_record);
  1009.             b_control = TRUE;
  1010.             n_hdrs++;
  1011.          }
  1012.          else
  1013.             printmsg(0, "Article has multiple Control: lines");
  1014.       }
  1015.    }  /* while getting Newsgroups: and Message-ID: */
  1016.  
  1017.    if (b_control)
  1018.    {
  1019.      memcpy(newsgroups, "control\0\0", 9);
  1020.      b_xref = FALSE;
  1021.    }
  1022.  
  1023. /*--------------------------------------------------------------------*/
  1024. /*           Check whether article has been received before           */
  1025. /*--------------------------------------------------------------------*/
  1026.  
  1027.    if ( bflag[ F_HISTORY ] )
  1028.    {
  1029.       if (get_histentry(history, messageID) != NULL)
  1030.       {
  1031.          printmsg(2, "rnews: Duplicate article %s", messageID);
  1032.          if (get_snum("duplicates",snum))
  1033.          {
  1034.             memcpy(newsgroups, "duplicates\0\0", 12);
  1035.             b_xref = FALSE;
  1036.          }
  1037.          else
  1038.          {
  1039.             fclose(tfile);
  1040.             return FALSE;
  1041.          }
  1042.       }
  1043.  
  1044.       /* Start building the history record for this article */
  1045.       sprintf(hist_record, "%ld %ld ", now, art_size);
  1046.       groups_found = 0;
  1047.  
  1048.       for (gc_ptr = newsgroups; gc_ptr != NULL; gc_ptr = gc_ptr1)
  1049.       {
  1050.          if ((gc_ptr1 = strchr(gc_ptr, ',')) != NULL)
  1051.             *gc_ptr1++ = '\0';
  1052.          if (strlen(gc_ptr) > MAXGRP - 1) {
  1053.             /* Bounds check the newsgroup length */
  1054.             printmsg(0, "rnews: newsgroup name too long -- %s", gc_ptr1);
  1055.             continue; /* Punt the newsgroup history record */
  1056.          }
  1057.          strcpy(groupy, gc_ptr);
  1058.          if (get_snum(groupy,snum)) {
  1059.            if (groups_found)
  1060.            strcat(hist_record, ",");
  1061.       strcat(hist_record, groupy);
  1062.       strcat(hist_record, ":");
  1063.       strcat(hist_record, snum);
  1064.            groups_found++;
  1065.          }
  1066.       }
  1067.  
  1068.       /* Restore the newsgroups line */
  1069.       while (newsgroups[strlen(newsgroups)+1] != '\0')
  1070.          newsgroups[strlen(newsgroups)] = ',';
  1071.  
  1072.       if (groups_found == 0) {
  1073.         printmsg(2, "rnews: no group to deliver to: %s", messageID);
  1074.         memcpy(newsgroups, "junk\0\0",6);
  1075.         b_xref = FALSE;
  1076.         /* try "junk" group if none of the target groups is known here */
  1077.         if (get_snum("junk",snum))
  1078.           sprintf(hist_record, "%ld %ld junk:%s", now, art_size, snum);
  1079.         else
  1080.           return fclose(tfile), FALSE;
  1081.       }
  1082.  
  1083.       /* Post the history record */
  1084.       add_histentry(history, messageID, hist_record);
  1085.    } /* if ( bflag[ F_HISTORY ] ) */
  1086.  
  1087. /*--------------------------------------------------------------------*/
  1088. /*              Now build the Xref: line (if we need to)              */
  1089. /*--------------------------------------------------------------------*/
  1090.  
  1091.    if (b_xref) {
  1092.       strcpy(hist_record, "Xref: ");
  1093.       strcat(hist_record, E_nodename);
  1094.  
  1095.       for (gc_ptr = newsgroups; gc_ptr != NULL; gc_ptr = gc_ptr1)
  1096.       {
  1097.          if ((gc_ptr1 = strchr(gc_ptr, ',')) != NULL)
  1098.             *gc_ptr1++ = '\0';
  1099.          if (strlen(gc_ptr) > MAXGRP - 1) {
  1100.             /* Bounds check the newsgroup length */
  1101.             printmsg(0, "rnews: newsgroup name too long -- %s", gc_ptr);
  1102.             continue; /* Punt the newsgroup history record */
  1103.          }
  1104.          strcpy(groupy, gc_ptr);
  1105.          if (get_snum(groupy,snum)) {
  1106.            strcat(hist_record, " ");
  1107.          strcat(hist_record, groupy);
  1108.          strcat(hist_record, ":");
  1109.          strcat(hist_record, snum);
  1110.          }
  1111.       }
  1112.  
  1113.       strcat(hist_record, "\n");
  1114.  
  1115.         /* Restore the newsgroups line */
  1116.       while (newsgroups[strlen(newsgroups)+1] != '\0')
  1117.          newsgroups[strlen(newsgroups)] = ',';
  1118.       }
  1119.  
  1120. /*--------------------------------------------------------------------*/
  1121. /*       We now need to copy the file to each group in groupys        */
  1122. /*--------------------------------------------------------------------*/
  1123.  
  1124.    for (gc_ptr = newsgroups; gc_ptr != NULL; gc_ptr = gc_ptr1)
  1125.    {
  1126.       if ((gc_ptr1 = strchr(gc_ptr, ',')) != NULL)
  1127.          *gc_ptr1++ = '\0';
  1128.       strcpy(groupy, gc_ptr);
  1129.       b_saved |= copy_file(tfile, groupy, b_xref ? hist_record : NULL);
  1130.    }
  1131.  
  1132.    fclose(tfile);
  1133.  
  1134.    return b_saved;
  1135. } /* deliver_article */
  1136.  
  1137. /*--------------------------------------------------------------------*/
  1138. /*    f i n d _ n e w s g r o u p                                     */
  1139. /*                                                                    */
  1140. /*    Locate a news group in our list                                 */
  1141. /*--------------------------------------------------------------------*/
  1142.  
  1143. static struct grp *find_newsgroup(const char *grp)
  1144. {
  1145.    struct grp *cur = group_list;
  1146.  
  1147.    while ((strcmp(grp,cur->grp_name) != 0)) {
  1148.       if (cur->grp_next != NULL) {
  1149.          cur = cur->grp_next;
  1150.       } else {
  1151.          return NULL;
  1152.       }
  1153.    }
  1154.  
  1155.    return cur;
  1156. }
  1157.  
  1158. /*--------------------------------------------------------------------*/
  1159. /*    a d d _ n e w s g r o u p                                       */
  1160. /*                                                                    */
  1161. /*    Add a news group to our list                                    */
  1162. /*--------------------------------------------------------------------*/
  1163.  
  1164. static void add_newsgroup(const char *grp, boolean moderated)
  1165. {
  1166.    struct grp *cur = group_list;
  1167.  
  1168.    while ((strcmp(grp,cur->grp_name) != 0)) {
  1169.       if (cur->grp_next != NULL) {
  1170.          cur = cur->grp_next;
  1171.       } else {
  1172.          cur->grp_next = (struct grp *) malloc(sizeof(struct grp));
  1173.          cur = cur->grp_next;
  1174.          checkref(cur);
  1175.          cur->grp_next = NULL;
  1176.          cur->grp_name = newstr(grp);
  1177.          cur->grp_high = 1;
  1178.          cur->grp_low  = 0;
  1179.          cur->grp_can_post = (char) (moderated ? 'n' : 'y');
  1180.          break;
  1181.       }
  1182.    }
  1183. }
  1184.  
  1185. /*--------------------------------------------------------------------*/
  1186. /*    d e l _ n e w s g r o u p                                       */
  1187. /*                                                                    */
  1188. /*    Remove a news group from our list                               */
  1189. /*--------------------------------------------------------------------*/
  1190.  
  1191. static void del_newsgroup(const char *grp)
  1192. {
  1193.    struct grp *cur = group_list;
  1194.    struct grp *prev = NULL;
  1195.  
  1196.    while ((strcmp(grp,cur->grp_name) != 0)) {
  1197.       if (cur->grp_next != NULL) {
  1198.          prev = cur;
  1199.          cur = cur->grp_next;
  1200.       } else {
  1201.          return;
  1202.       }
  1203.    }
  1204.  
  1205.    if (prev == NULL)
  1206.      group_list = cur->grp_next;
  1207.    else
  1208.      prev->grp_next = cur->grp_next;
  1209.  
  1210.    free(cur);
  1211.    /* name string is not free'ed because it's in the string pool */
  1212. }
  1213.  
  1214. /*--------------------------------------------------------------------*/
  1215. /*    c o n t r o l _ m e s s a g e                                   */
  1216. /*                                                                    */
  1217. /*    Handle control message                                          */
  1218. /*--------------------------------------------------------------------*/
  1219.  
  1220. static void control_message(const char *control)
  1221. {
  1222.   char *ctrl = strdup(control);
  1223.   char *cmd, *group, *mod, *msg;
  1224.   boolean moderated;
  1225.  
  1226.   strtok(ctrl, " \t");
  1227.   cmd = strtok(NULL, " \t");
  1228.  
  1229.   if (stricmp(cmd, "newgroup") == 0) {
  1230.     group = strtok(NULL, " \t");
  1231.     mod = strtok(NULL, " \t");
  1232.     moderated = (mod != NULL) && (strcmp(mod, "moderated") == 0);
  1233.     add_newsgroup(group, moderated);
  1234.     printmsg(1, "rnews: newsgroup added: %s", group);
  1235.   } else if (stricmp(cmd, "rmgroup") == 0) {
  1236.     group = strtok(NULL, " \t");
  1237.     del_newsgroup(group);
  1238.     printmsg(1, "rnews: newsgroup removed: %s", group);
  1239.   } else if (stricmp(cmd, "cancel") == 0) {
  1240.     msg = strtok(NULL, " \t");
  1241.     cancel_article(history, msg);
  1242.   } else if (stricmp(cmd, "ihave") == 0 || stricmp(cmd, "sendme") == 0 ||
  1243.              stricmp(cmd, "sendsys") == 0 || stricmp(cmd, "version") == 0 ||
  1244.              stricmp(cmd, "checkgroups") == 0) {
  1245.     printmsg(1, "rnews: control message not implemented: %s", cmd);
  1246.   } else {
  1247.     printmsg(1, "rnews: control message unknown: %s", cmd);
  1248.   }
  1249.  
  1250.   free(ctrl);
  1251. }
  1252.  
  1253. /*--------------------------------------------------------------------*/
  1254. /*    c o p y _ f i l e                                               */
  1255. /*                                                                    */
  1256. /*    Write an article to it's final resting place                    */
  1257. /*--------------------------------------------------------------------*/
  1258.  
  1259. static boolean copy_file(FILE *input,
  1260.                       char *group,
  1261.                       char *xref)
  1262. {
  1263.    struct grp *cur;
  1264.    char filename[FILENAME_MAX];
  1265.    char buf[BUFSIZ];
  1266.    FILE *output;
  1267.    boolean header = TRUE;
  1268.  
  1269. /*--------------------------------------------------------------------*/
  1270. /*           Determine if the news has been already posted            */
  1271. /*--------------------------------------------------------------------*/
  1272.  
  1273.    cur = find_newsgroup(group);
  1274.    if (cur == NULL)
  1275.    {
  1276.       printmsg(3, "rnews: Article cross-posted to %s", group);
  1277.       return FALSE;
  1278.    }
  1279.  
  1280. /*--------------------------------------------------------------------*/
  1281. /*                       Now build a file name                        */
  1282. /*--------------------------------------------------------------------*/
  1283.  
  1284.    ImportNewsGroup( filename, cur->grp_name, cur->grp_high++);
  1285.  
  1286. /*--------------------------------------------------------------------*/
  1287. /*                 We have a file name, open the file                 */
  1288. /*--------------------------------------------------------------------*/
  1289.  
  1290.    printmsg(2, "rnews: Saving %s article in %s",
  1291.                cur->grp_name, filename);
  1292.  
  1293.    if ((output = FOPEN(filename, "w",TEXT_MODE)) == nil(FILE))
  1294.    {
  1295.       printerr( filename );
  1296.       printmsg(0, "rnews: Unable to save article");
  1297.       return FALSE;
  1298.    }
  1299.  
  1300.    rewind(input);
  1301.  
  1302.    if (xref) /* write new Xref: line first */
  1303.    {
  1304.       if (fputs(xref, output) == EOF)
  1305.       {
  1306.          printerr( filename );
  1307.          panic();
  1308.       }
  1309.    }
  1310.  
  1311.    while (fgets(buf, sizeof buf, input) != NULL)
  1312.    {
  1313.  
  1314.       if ( ! header )
  1315.          ;                 /* No operation after end of header        */
  1316.       else if ( *buf == '\n' )
  1317.          header = FALSE;
  1318.       else if (equalni(buf, "Path:", strlen("Path:")))
  1319.       {
  1320.          fprintf(output, "Path: %s!%s", E_nodename,
  1321.                          buf + strlen("Path:") + 1);
  1322.          continue;
  1323.       }
  1324.       else if (equalni(buf, "Xref:", strlen("Xref:")))
  1325.          continue; /* skip possibly old Xref: line */
  1326.  
  1327.       if (fputs(buf, output) == EOF)
  1328.       {
  1329.          printerr( filename );
  1330.          panic();
  1331.       }
  1332.    } /* while */
  1333.  
  1334.    fclose(output);
  1335.  
  1336.    return TRUE;
  1337.  
  1338. } /* copy_file */
  1339.  
  1340. /*--------------------------------------------------------------------*/
  1341. /*    g e t _ s n u m                                                 */
  1342. /*                                                                    */
  1343. /*    Get highest article number of newsgroup                         */
  1344. /*--------------------------------------------------------------------*/
  1345.  
  1346. static int get_snum(const char *group, char *snum)
  1347. {
  1348.    struct grp *cur;
  1349.  
  1350.    strcpy(snum, "0");
  1351.    cur = find_newsgroup(group);
  1352.    if (cur == NULL)
  1353.    return FALSE;
  1354.  
  1355.    sprintf(snum, "%ld", cur->grp_high);
  1356.    return TRUE;
  1357.  
  1358. } /* snum */
  1359.  
  1360. /*--------------------------------------------------------------------*/
  1361. /*    x m i t _ n e w s                                               */
  1362. /*                                                                    */
  1363. /*    A cruel hack to transmit news to other systems                  */
  1364. /*--------------------------------------------------------------------*/
  1365.  
  1366. static void xmit_news( char *sysname, FILE *in_stream )
  1367. {
  1368.    static char *spool_fmt = SPOOLFMT;              /* spool file name */
  1369.    static char *dataf_fmt = DATAFFMT;
  1370.    static char *send_cmd  = "S %s %s %s - %s 0666\n";
  1371.    static long seqno = 0;
  1372.    FILE *out_stream;          /* For writing out data                */
  1373.  
  1374.    char buf[BUFSIZ];
  1375.    unsigned len;
  1376.  
  1377.    char msfile[FILENAME_MAX]; /* MS-DOS format name of files         */
  1378.    char msname[22];           /* MS-DOS format w/o path name         */
  1379.  
  1380.    char tmfile[15];           /* Call file, UNIX format name         */
  1381.    char ixfile[15];           /* eXecute file for remote system,
  1382.                                 UNIX format name for local system   */
  1383.    char idfile[15];           /* Data file, UNIX format name         */
  1384.    char rdfile[15];           /* Data file name on remote system,
  1385.                                  UNIX format                         */
  1386.    char rxfile[15];           /* Remote system UNIX name of eXecute
  1387.                                  file                                */
  1388.    char *seq;
  1389.  
  1390. /*--------------------------------------------------------------------*/
  1391. /*          Create the UNIX format of the file names we need          */
  1392. /*--------------------------------------------------------------------*/
  1393.  
  1394.    seqno = getseq();
  1395.    seq = JobNumber( seqno );
  1396.  
  1397.    sprintf(tmfile, spool_fmt, 'C', sysname,  'd' , seq);
  1398.    sprintf(idfile, dataf_fmt, 'D', E_nodename , seq, 'd');
  1399.    sprintf(rdfile, dataf_fmt, 'D', E_nodename , seq, 'r');
  1400.    sprintf(ixfile, dataf_fmt, 'D', E_nodename , seq, 'e');
  1401.    sprintf(rxfile, dataf_fmt, 'X', E_nodename , seq, 'r');
  1402.  
  1403. /*--------------------------------------------------------------------*/
  1404. /*                     create remote X (xqt) file                     */
  1405. /*--------------------------------------------------------------------*/
  1406.  
  1407.    importpath( msname, ixfile, sysname);
  1408.    mkfilename( msfile, E_spooldir, msname);
  1409.  
  1410.    out_stream = FOPEN(msfile, "w", BINARY_MODE);
  1411.    if ( out_stream == NULL )
  1412.    {
  1413.       printmsg(0, "xmit_news: cannot open X file %s", msfile);
  1414.       printerr(msfile);
  1415.       return ;
  1416.    } /* if */
  1417.  
  1418.    if (setvbuf( out_stream, NULL, _IONBF, 0))
  1419.    {
  1420.       printmsg(0, "xmit_news: Cannot unbuffer file %s (%s).",
  1421.                   ixfile, msfile);
  1422.       printerr(msfile);
  1423.       panic();
  1424.    } /* if */
  1425.  
  1426.    fprintf(out_stream, "R %s@%s\nU %s %s\nF %s\nI %s\nC rnews\n",
  1427.                "uucp", E_domain,
  1428.                "uucp", E_nodename,
  1429.                rdfile, rdfile);
  1430.    fclose(out_stream);
  1431.  
  1432. /*--------------------------------------------------------------------*/
  1433. /*  Create the data file with the mail to send to the remote system   */
  1434. /*--------------------------------------------------------------------*/
  1435.  
  1436.    importpath(msname, idfile, sysname);
  1437.    mkfilename( msfile, E_spooldir, msname);
  1438.  
  1439.    out_stream = FOPEN(msfile, "w", BINARY_MODE);
  1440.    if (out_stream == NULL )
  1441.    {
  1442.       printerr(msfile);
  1443.       printmsg(0,
  1444.                "xmit_news: Cannot open spool file \"%s\" for output",
  1445.                 msfile);
  1446.       return;
  1447.    }
  1448.  
  1449.    if (setvbuf( out_stream, NULL, _IONBF, 0))
  1450.    {
  1451.       printmsg(0, "xmit_news: Cannot unbuffer file %s (%s).",
  1452.                   idfile, msfile);
  1453.       printerr(msfile);
  1454.       panic();
  1455.    } /* if */
  1456.  
  1457. /*--------------------------------------------------------------------*/
  1458. /*                       Loop to copy the data                        */
  1459. /*--------------------------------------------------------------------*/
  1460.  
  1461.    while ( (len = fread( buf, 1, sizeof buf, in_stream)) != 0)
  1462.    {
  1463.       if (fwrite( buf, 1, len, out_stream ) != len)     /* I/O error?  */
  1464.       {
  1465.          printerr(msfile);
  1466.          fclose(out_stream);
  1467.          return;
  1468.       } /* if */
  1469.    } /* while */
  1470.  
  1471.    fclose( out_stream );
  1472.  
  1473. /*--------------------------------------------------------------------*/
  1474. /*                     create local C (call) file                     */
  1475. /*--------------------------------------------------------------------*/
  1476.  
  1477.    importpath( msname, tmfile, sysname);
  1478.    mkfilename( msfile, E_spooldir, msname);
  1479.  
  1480.    out_stream = FOPEN(msfile, "w",TEXT_MODE);
  1481.    if (out_stream == NULL)
  1482.    {
  1483.       printerr( msname );
  1484.       printmsg(0, "xmit_news: cannot open C file %s", msfile);
  1485.       return;
  1486.    }
  1487.  
  1488.    fprintf(out_stream, send_cmd, idfile, rdfile,
  1489.                   "uucp", idfile);
  1490.    fprintf(out_stream, send_cmd, ixfile, rxfile,
  1491.                   "uucp", ixfile);
  1492.    fclose(out_stream);
  1493.  
  1494. } /* xmit_news */
  1495.  
  1496. /*--------------------------------------------------------------------*/
  1497. /*    c o p y _ s n e w s                                             */
  1498. /*                                                                    */
  1499. /*    Process news destined for the simple news reader                */
  1500. /*--------------------------------------------------------------------*/
  1501.  
  1502. static int copy_snews( char *filename, FILE *stream )
  1503. {
  1504.    char buf[BUFSIZ];
  1505.    size_t len;
  1506.  
  1507.    FILE *out_stream = FOPEN(filename, "w", BINARY_MODE);
  1508.  
  1509.    if ( out_stream == NULL )
  1510.    {
  1511.       printerr(filename);
  1512.       panic();
  1513.    } /* if */
  1514.  
  1515.    if (setvbuf( out_stream, NULL, _IONBF, 0))
  1516.    {
  1517.       printmsg(0, "copy_snews: Cannot unbuffer file %s.", filename);
  1518.       printerr(filename);
  1519.       panic();
  1520.    } /* if */
  1521.  
  1522. /*--------------------------------------------------------------------*/
  1523. /*                          Perform the copy                          */
  1524. /*--------------------------------------------------------------------*/
  1525.  
  1526.    while ( (len = fread( buf, 1, sizeof buf, stream)) != 0)
  1527.    {
  1528.       if (fwrite( buf, 1, len, out_stream ) != len)     /* I/O error? */
  1529.       {
  1530.          printerr(filename);
  1531.          panic();
  1532.       } /* if */
  1533.    } /* while */
  1534.  
  1535. /*--------------------------------------------------------------------*/
  1536. /*                           Close the file                           */
  1537. /*--------------------------------------------------------------------*/
  1538.  
  1539.    fclose( out_stream );
  1540.    fclose( stream );
  1541.    return 0;
  1542.  
  1543. } /* copy_snews */
  1544.