home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume17 / rkive / part02 < prev    next >
Internet Message Format  |  1991-02-24  |  56KB

  1. From: kent@sparky.imd.sterling.com (Kent Landfield)
  2. Newsgroups: comp.sources.misc
  3. Subject: v17i018:  rkive - Usenet sources archiver, Part02/06
  4. Message-ID: <1991Feb24.222503.26973@sparky.IMD.Sterling.COM>
  5. Date: 24 Feb 91 22:25:03 GMT
  6. Approved: kent@sparky.imd.sterling.com
  7. X-Checksum-Snefru: a0653cc2 6de1eff1 27e20a7f e94b5b43
  8.  
  9. Submitted-by: Kent Landfield <kent@sparky.imd.sterling.com>
  10. Posting-number: Volume 17, Issue 18
  11. Archive-name: rkive/part02
  12.  
  13. #! /bin/sh
  14. # This is a shell archive.  Remove anything before this line, then feed it
  15. # into a shell via "sh file" or similar.  To overwrite existing files,
  16. # type "sh file -c".
  17. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  18. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  19. # If this archive is complete, you will see the following message at the end:
  20. #        "End of archive 2 (of 6)."
  21. # Contents:  rkive/rkive.c rkive/setup.c
  22. # Wrapped by kent@sparky on Sun Feb 24 16:11:22 1991
  23. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  24. if test -f 'rkive/rkive.c' -a "${1}" != "-c" ; then 
  25.   echo shar: Will not clobber existing file \"'rkive/rkive.c'\"
  26. else
  27. echo shar: Extracting \"'rkive/rkive.c'\" \(27854 characters\)
  28. sed "s/^X//" >'rkive/rkive.c' <<'END_OF_FILE'
  29. X/*
  30. X**  Subsystem:   USENET Sources Archiver             
  31. X**  File Name:   rkive.c               
  32. X**                                                        
  33. X**  usage: rkive [-?dgstuvV] [-f config_file] [-n newsgroup] 
  34. X**                           [-B batchfile] [-S newsgroup]
  35. X**
  36. X**
  37. X** This software is Copyright (c) 1989, 1990, 1991 by Kent Landfield.
  38. X**
  39. X** Permission is hereby granted to copy, distribute or otherwise 
  40. X** use any part of this package as long as you do not try to make 
  41. X** money from it or pretend that you wrote it.  This copyright 
  42. X** notice must be maintained in any copy made.
  43. X**
  44. X** Use of this software constitutes acceptance for use in an AS IS 
  45. X** condition. There are NO warranties with regard to this software.  
  46. X** In no event shall the author be liable for any damages whatsoever 
  47. X** arising out of or in connection with the use or performance of this 
  48. X** software.  Any use of this software is at the user's own risk.
  49. X**
  50. X**  If you make modifications to this software that you feel 
  51. X**  increases it usefulness for the rest of the community, please 
  52. X**  email the changes, enhancements, bug fixes as well as any and 
  53. X**  all ideas to me. This software is going to be maintained and 
  54. X**  enhanced as deemed necessary by the community.
  55. X**
  56. X**              Kent Landfield
  57. X**              uunet!sparky!kent
  58. X**        kent@sparky.imd.sterling.com
  59. X*/
  60. X
  61. X#include <sys/types.h>
  62. X#include <sys/stat.h>
  63. X#include <stdio.h>
  64. X#include "article.h"
  65. X#include "cfg.h"
  66. X
  67. X#ifdef NNTP
  68. Xchar sccsid[] = "@(#)rkive.c    2.2 2/23/91 - NNTP Version";
  69. X#else
  70. Xchar sccsid[] = "@(#)rkive.c    2.2 2/23/91";
  71. X#endif /*!NNTP*/
  72. X
  73. X/* 
  74. X** This is necessary since the builtin makedir call uses
  75. X** mknod which is a superuser only call for directories.
  76. X*/
  77. X#if (!HAVE_MKDIR && !USE_SYSMKDIR)
  78. X#define ROOT_ONLY
  79. X#endif
  80. X
  81. X/* 
  82. X** The following define is use for compilation
  83. X** so that format_output can use the extended
  84. X** fomating characters that are not available
  85. X** in article.
  86. X*/
  87. X#define RKIVE
  88. X
  89. Xchar tmp_mailfile[] = "/tmp/rkive.mail";
  90. Xchar global_mailfile[] = "/tmp/gbl.mail";
  91. X
  92. Xchar *batch_file = NULL;
  93. Xchar article_name[MAXNAMLEN];
  94. X
  95. Xint retrieve = FROM_DISK;      /* default archiving is done from local disk */
  96. Xint overwrite;
  97. Xint status_only;
  98. X
  99. Xstruct stat sbuf;
  100. X
  101. XFILE *inputfp;
  102. X
  103. Xint needs_to_be_archived();
  104. Xchar *save_article();
  105. Xchar *compress_file();
  106. Xchar *do_compress();
  107. Xchar *basename();
  108. Xchar *suffix();
  109. Xchar *format_output();
  110. Xvoid archive();
  111. Xvoid build_index();
  112. Xvoid display_group_info();
  113. Xvoid logit();
  114. Xvoid log_activities();
  115. Xvoid mail_file();
  116. Xvoid notify_users();
  117. Xvoid record_problem();
  118. Xvoid set_ownership();
  119. X
  120. Xint fclose();
  121. Xint stat();
  122. Xint strcmp();
  123. Xint strlen();
  124. Xint system();
  125. Xint unlink();
  126. Xchar *strcpy();
  127. Xchar *strcat();
  128. Xchar *strchr();
  129. XFILE *efopen();
  130. Xvoid exit();
  131. X
  132. Xextern int yydebug;
  133. Xextern char inputstring[];
  134. Xextern parser_return_value;
  135. X
  136. Xextern int debug;
  137. Xextern int verbose;
  138. Xextern int test;
  139. Xextern int inum;
  140. Xextern int problem_article;
  141. Xextern char *nntp_server;
  142. X
  143. Xvoid usage()
  144. X{
  145. X    (void)fprintf(stderr,"usage: %s [-?dgstuvV] [-f config_file]\n", progname);
  146. X    (void)fprintf(stderr,"          [-n newsgroup] [-B batchfile] [-S newsgroup]\n");
  147. X    (void)fprintf(stderr,"options:\n");
  148. X    (void)fprintf(stderr,"  -?   Display this message.\n");
  149. X    (void)fprintf(stderr,"  -d   Debug, assumes verbose flag as well.\n");
  150. X    (void)fprintf(stderr,"  -g   Fill in default values with group display.\n"); 
  151. X    (void)fprintf(stderr,"       Only effective with verbose mode flag.\n");
  152. X    (void)fprintf(stderr,"  -s   Display status of article archiving.\n");
  153. X    (void)fprintf(stderr,"  -t   Test mode, display what would be done but do no archiving.\n");
  154. X    (void)fprintf(stderr,"  -u   Unconditionally overwrite dupliclate articles.\n");
  155. X    (void)fprintf(stderr,"  -v   Verbose archiving information printed.\n");
  156. X    (void)fprintf(stderr,"  -V   Display %s software version information.\n",
  157. X                  progname);
  158. X    (void)fprintf(stderr,"  -f config_file\n");
  159. X    (void)fprintf(stderr,"       Specify alternate configuration file to be used.\n");
  160. X    (void)fprintf(stderr,"  -n newsgroup\n");
  161. X    (void)fprintf(stderr,"       Specify newsgroup to archive or display status for.\n");
  162. X    (void)fprintf(stderr,"  -B batchfile\n");
  163. X    (void)fprintf(stderr,"       Read names of articles to archive from batchfile.\n");
  164. X    (void)fprintf(stderr,"       Note: Use of the -B option requires a newsgroup\n");
  165. X    (void)fprintf(stderr,"             be specified using the -n option.\n");
  166. X    (void)fprintf(stderr,"  -S newsgroup\n");
  167. X    (void)fprintf(stderr,"       Take the name of articles to archive from stdin.\n");
  168. X}
  169. X
  170. Xint main(argc, argv)
  171. Xint argc;
  172. Xchar **argv;
  173. X{
  174. X   int getopt();
  175. X   void version();
  176. X   void setup_defaults();
  177. X   void init_article();
  178. X
  179. X   int c;
  180. X   extern char *optarg;
  181. X   extern int opterr;
  182. X   char *nwsg = NULL;
  183. X
  184. X   yydebug = FALSE;
  185. X
  186. X   opterr = 0;
  187. X   progname = argv[0];
  188. X   inputfp = stdin;
  189. X   logfp = stdout;
  190. X   errfp = stderr;
  191. X
  192. X   status_only = debug = verbose = 0;
  193. X   test = overwrite = fill_in_defaults = 0;
  194. X
  195. X   /*
  196. X   ** Setup the default config file to be used
  197. X   ** unless the user specifies otherwise.
  198. X   */
  199. X   config_file = LOCATION;
  200. X
  201. X   if (argc > 1) {
  202. X      while ((c = getopt(argc, argv, "?dgstuvVn:f:B:S:y")) != EOF) {
  203. X         switch (c) {
  204. X             case 'B':   /* take filenames from batch file  */
  205. X                 retrieve = FROM_BATCHFILE;
  206. X                 batch_file = optarg;
  207. X                 break;
  208. X             case 'd':   /* for extremely verbose output    */
  209. X                 debug++;
  210. X                 verbose++;
  211. X                 break;
  212. X             case 'f':   /* alternate configuration file    */
  213. X                 config_file = optarg;  
  214. X                 break;  
  215. X             case 'g':   /* display defaults filled in      */
  216. X                 fill_in_defaults++;
  217. X                 break;
  218. X             case 'n':   /* specify an individual newsgroup */
  219. X                 nwsg = optarg;
  220. X                 break;
  221. X             case 's':   /* display article archive status  */
  222. X                 status_only++;
  223. X                 break;
  224. X             case 'S':   /* single article archiving        */
  225. X                 retrieve = FROM_NAME;
  226. X                 nwsg = optarg;
  227. X                 break;
  228. X             case 't':   /* test mode, show but do nothing  */
  229. X                 test++;
  230. X                 verbose++;
  231. X                 break;
  232. X             case 'u':   /* overwrite existing duplicates   */
  233. X                 overwrite++;
  234. X                 break;
  235. X             case 'v':   /* display expanded output         */
  236. X                 verbose++;
  237. X                 break;
  238. X             case 'V':   /* display software version only   */
  239. X                 version();
  240. X                 break;
  241. X             case 'y':   /* turn on yydebug facilities      */
  242. X                 yydebug++;
  243. X                 break;
  244. X             case '?':   /* display usage information       */
  245. X             default:    /* display usage, invalid option   */
  246. X                 usage();
  247. X                 return(1);
  248. X         }
  249. X      }
  250. X   }
  251. X
  252. X   /*
  253. X   ** If the user has specified that input is be filenames
  254. X   ** retrieved from a batch file, the user must specify a
  255. X   ** a newsgroup in addition to the batch filename.
  256. X   */
  257. X   if (retrieve == FROM_BATCHFILE) {
  258. X       if (nwsg == NULL) {
  259. X           (void) fprintf(errfp,
  260. X                  "%s: Must specify a newsgroup when using batchfile mode\n",
  261. X                  progname);
  262. X           (void) fprintf(errfp,"Sample command line...\n");
  263. X           (void) fprintf(errfp,"\t%s -B %s -n newsgroup-here\n",
  264. X                  progname, batch_file);
  265. X           return(1);
  266. X       }
  267. X   }
  268. X
  269. X   setup_defaults();
  270. X
  271. X   init_article();
  272. X
  273. X   for (c = 0; c <= num; c++)  {
  274. X       newsgrp = &group[c];
  275. X       /*
  276. X       ** Was a newsgroup specified on the command line ?
  277. X       */
  278. X       if (nwsg != NULL) {
  279. X          if (strcmp(nwsg, newsgrp->ng_name) != 0)
  280. X              continue;
  281. X       }
  282. X       archive();
  283. X   }
  284. X
  285. X   if (!status_only) {
  286. X       /*
  287. X       ** Mail notification of the archived members to the 
  288. X       ** list of users specified in the configuration file
  289. X       ** and remove the file containing the archived info.
  290. X       */
  291. X       mail_file(mail, global_mailfile, "Rkive results");
  292. X       (void) unlink(global_mailfile);
  293. X   }
  294. X   return(0);
  295. X}
  296. X
  297. Xvoid archive()
  298. X{
  299. X    char *get_archived_rec();
  300. X    int retrieve_article();
  301. X    void get_header();
  302. X
  303. X    int cct;
  304. X    int first;
  305. X    int val;
  306. X    char *rp, *rec;
  307. X    char *new_member;
  308. X    char *archived_file;
  309. X    
  310. X#ifdef ROOT_ONLY
  311. X    /*
  312. X    ** check to assure that the user is root if 
  313. X    ** actual archiving is to take place. This is necessary
  314. X    ** if there is no mkdir system call.
  315. X    */
  316. X
  317. X    if (!status_only && (getuid() != 0)) {
  318. X        (void) fprintf(errfp, "%s: Sorry, Must be root to rkive.\n",
  319. X                        progname);
  320. X        exit(1);
  321. X    }
  322. X#endif /* ROOT_ONLY */
  323. X
  324. X    inum = 0;  /* initialize chronological issue counter */
  325. X
  326. X    /* Remove any existing temporary mail file */
  327. X
  328. X    (void) unlink(tmp_mailfile);
  329. X    cct = 0;  /* counter for newsgroup message in global mail */
  330. X
  331. X    /*
  332. X    ** Assure that there something specified in the 
  333. X    ** archive location variable...
  334. X    */
  335. X    if (!*newsgrp->location) {
  336. X        (void) fprintf(errfp, "SKIPPING %s: No archive location specified..\n",
  337. X                        newsgrp->ng_name);
  338. X        return;
  339. X    }
  340. X
  341. X    /*
  342. X    ** print out the appropriate 
  343. X    ** header for the newsgroup.
  344. X    ** If the user wishes to see the newsgroup info as well as all the
  345. X    ** information about a file archived, the user must specify 
  346. X    ** rkive -svv to see it all... 
  347. X    */
  348. X
  349. X    if (debug || (verbose == 2 && status_only)) {
  350. X        (void) fprintf(logfp,"\n\n");
  351. X        display_group_info(newsgrp);
  352. X        (void) fprintf(logfp,"\n");
  353. X    }
  354. X    else if (status_only || verbose == 2)
  355. X        (void) fprintf(logfp, "%s\n",newsgrp->ng_name);
  356. X
  357. X    /*
  358. X    ** Create a path to the .archived file for the newsgroup's archive.
  359. X    ** This file is used to determine if an article has already been
  360. X    ** archived.  If the user did not specify one ...
  361. X    */
  362. X    if (!*newsgrp->arc_done)
  363. X       (void) sprintf(newsgrp->arc_done,"%s/.archived",newsgrp->location);
  364. X
  365. X    /*
  366. X    ** Create a path to the .patchlog file for the newsgroup's archive.
  367. X    ** This file is used to record patches to posted software so that
  368. X    ** it can easily be determined what the full set of software is.
  369. X    */
  370. X    if (!*newsgrp->patchlog)
  371. X       (void) sprintf(newsgrp->patchlog,"%s/.patchlog",newsgrp->location);
  372. X
  373. X    /*
  374. X    ** first indicates that archiving has just begun for this group
  375. X    ** so that any necessary setup can be done in retrieve_article().
  376. X    */
  377. X
  378. X    first = 1;
  379. X
  380. X#ifdef NNTP
  381. X    /* 
  382. X    ** Determine if the newsgroup being archived is to be accessed via
  383. X    ** nntp or via local disk access.
  384. X    */
  385. X    if (*newsgrp->nntp) {
  386. X        nntp_server = newsgrp->nntp;
  387. X        retrieve = FROM_NNTP;
  388. X    }
  389. X    else if (*nntp) {
  390. X        nntp_server = nntp;
  391. X        retrieve = FROM_NNTP;
  392. X    }
  393. X#endif /*NNTP*/
  394. X
  395. X    while ((val = retrieve_article(article_name,first)) != DONE) {
  396. X        first = 0;
  397. X        if (val == ERROR_ENCOUNTERED)
  398. X            return;
  399. X        else if (val != RETRIEVED) {
  400. X           /* 
  401. X           ** Invalid return value encountered, we're in truble now..
  402. X           */
  403. X           (void) fprintf(errfp,"Invalid return from retrieve_article..?? Skipping %s\n",
  404. X                          newsgrp->ng_path);
  405. X           return;
  406. X       }
  407. X
  408. X       /*
  409. X       ** Read the news article file to extract the
  410. X       ** header information and fill appropriate
  411. X       ** data structures.
  412. X       */
  413. X       get_header(article_name);
  414. X
  415. X       /* 
  416. X       ** If the user has specified that a quick status 
  417. X       ** listing should be produced then hop to it....
  418. X       */
  419. X
  420. X       if (status_only) {
  421. X            if ((rec = get_archived_rec(header.ident)) == NULL) {
  422. X                /*
  423. X                ** Assure that the article that we are going
  424. X                ** to give status on is one that would be archived
  425. X                ** if archiving was occuring. (e.g. does it match 
  426. X                ** the user supplied criteria for archiving...)
  427. X                */
  428. X                if (*newsgrp->match) {
  429. X                     parser_return_value = 0;
  430. X                     (void) strcpy(inputstring, newsgrp->match);
  431. X                     if (yyparse()) 
  432. X                         (void) fprintf(logfp, "Parse failed and returned %d\n",
  433. X                                                parser_return_value);
  434. X                     else {
  435. X                         /* Did match string produce true as result? */
  436. X
  437. X                        if (debug)
  438. X                            (void) fprintf(logfp, "Parser returned %d\n",
  439. X                                                   parser_return_value);
  440. X                    }
  441. X                    if (!parser_return_value) {
  442. X#ifdef NNTP
  443. X                        /*
  444. X                        ** Since they only want status, remove the 
  445. X                        ** nntp transfer tmpfile if newsgroup is
  446. X                        ** being archived via nntp.
  447. X                        */
  448. X                        if (retrieve == FROM_NNTP)
  449. X                            (void) unlink(article_name);
  450. X#endif /*NNTP*/
  451. X                        continue;
  452. X                    }
  453. X               }
  454. X#ifdef NNTP
  455. X               if (retrieve == FROM_NNTP)
  456. X                  (void) fprintf(logfp,
  457. X                                 "\t[%s] Awaiting Archiving\n",header.ident);
  458. X               else
  459. X                  (void) fprintf(logfp,
  460. X                                 "\t[%s] Awaiting Archiving\n",article_name);
  461. X#else /*!NNTP*/
  462. X               (void) fprintf(logfp,"\t[%s] Awaiting Archiving\n",article_name);
  463. X#endif /*NNTP*/
  464. X            }
  465. X            else if (verbose) {
  466. X                if ((rp = strchr(rec,' ')) == NULL) {
  467. X#ifdef NNTP
  468. X                   if (retrieve == FROM_NNTP)
  469. X                      (void) fprintf(logfp,"\t[%s] Archived\n",header.ident);
  470. X                   else
  471. X                      (void) fprintf(logfp,"\t[%s] Archived\n",article_name);
  472. X#else /*!NNTP*/
  473. X                   (void) fprintf(logfp,"\t[%s] Archived\n",article_name);
  474. X#endif /*NNTP*/
  475. X                }
  476. X                else {
  477. X                    rp++;
  478. X                    *(rp-1) = '\0';
  479. X                    (void) fprintf(logfp,"\t%s Archived as %s\n",rec,rp);
  480. X                }
  481. X            }
  482. X#ifdef NNTP
  483. X            /*
  484. X            ** Since they only want status, remove the 
  485. X            ** nntp transfer tmpfile if newsgroup is
  486. X            ** being archived via nntp.
  487. X            */
  488. X            if (retrieve == FROM_NNTP)
  489. X                (void) unlink(article_name);
  490. X#endif /*NNTP*/
  491. X            continue;
  492. X       }  /* End of status only... */
  493. X
  494. X       /* 
  495. X       **
  496. X       ** We have located a file that may need to be archived. 
  497. X       ** First read the header information from the found file.
  498. X       ** Next, determine if the file needs to be archived by
  499. X       ** doing a linear search of of the contents of the .archived file
  500. X       ** comparing the message-id of the new article with the message-ids
  501. X       ** recorded in the .archived file. If the new message-id is not
  502. X       ** specified in the .archived file, it has not been archived
  503. X       ** before and we can proceed with the archiving.
  504. X       ** Can we say slow... maybe dbm in the future ???
  505. X       */
  506. X
  507. X       if (!needs_to_be_archived(header.ident)) {
  508. X#ifdef NNTP
  509. X           /*
  510. X           ** Remove the nntp transfer tmpfile if the
  511. X           ** newsgroup is being archived via nntp.
  512. X           */
  513. X           if (retrieve == FROM_NNTP)
  514. X               (void) unlink(article_name);
  515. X#endif /*NNTP*/
  516. X           continue;
  517. X       }
  518. X          
  519. X       if (*newsgrp->match) {
  520. X           (void) strcpy(inputstring, newsgrp->match);
  521. X
  522. X           if (yyparse()) {
  523. X               (void) fprintf(logfp, "Parse failed and returned %d\n",
  524. X                                      parser_return_value);
  525. X#ifdef NNTP
  526. X               /*
  527. X               ** Remove the nntp transfer tmpfile if the
  528. X               ** newsgroup is being archived via nntp.
  529. X               */
  530. X               if (retrieve == FROM_NNTP)
  531. X                   (void) unlink(article_name);
  532. X#endif /*NNTP*/
  533. X               continue;
  534. X           }
  535. X
  536. X           /* Did match string produce true as result? */
  537. X
  538. X           if (debug)
  539. X               (void) fprintf(logfp, "Parser returned %d\n", parser_return_value);
  540. X
  541. X           if (!parser_return_value) {
  542. X#ifdef NNTP
  543. X               /*
  544. X               ** Remove the nntp transfer tmpfile if the
  545. X               ** newsgroup is being archived via nntp.
  546. X               */
  547. X               if (retrieve == FROM_NNTP)
  548. X                   (void) unlink(article_name);
  549. X#endif /*NNTP*/
  550. X               continue;
  551. X           }
  552. X       }
  553. X
  554. X       /*
  555. X       ** Archiving from here on out.
  556. X       */
  557. X       if ((new_member = save_article(article_name,newsgrp)) != NULL) {
  558. X           /*
  559. X           ** To not do any compression of setting of ownership
  560. X           ** for newsgroup articles that are archived by an
  561. X           ** external application.
  562. X           */
  563. X           if (newsgrp->type != EXTERNAL_COMMAND) {
  564. X               archived_file = compress_file(new_member,newsgrp);
  565. X               set_ownership(archived_file,new_member,newsgrp);
  566. X           }
  567. X           else
  568. X               archived_file = new_member;
  569. X           
  570. X           /*
  571. X           ** If a problem has been encountered,
  572. X           ** the function do_problem handles
  573. X           ** the logging, and notifying.
  574. X           */
  575. X
  576. X           if (!problem_article) {
  577. X               log_activities(archived_file,newsgrp);
  578. X               build_index(new_member,newsgrp);
  579. X               notify_users(archived_file,newsgrp,cct++);
  580. X           }
  581. X       }
  582. X       else {
  583. X           if (newsgrp->type != ONLY_ARCHIVE_NAME) {
  584. X               (void) fprintf(logfp,"Unable to archive %s/%s!!!\n",
  585. X                          newsgrp->ng_path, article_name);
  586. X           }
  587. X       }
  588. X#ifdef NNTP
  589. X       /*
  590. X       ** Remove the nntp transfer tmpfile if the
  591. X       ** newsgroup is being archived via nntp.
  592. X       */
  593. X       if (retrieve == FROM_NNTP)
  594. X           (void) unlink(article_name);
  595. X#endif /*NNTP*/
  596. X    }
  597. X
  598. X    if (!status_only) {
  599. X        /* Mail notification of the archived members to the   */
  600. X        /* list of users specified in the configuration file  */
  601. X        /* and remove the file containing the archived info.  */
  602. X
  603. X        mail_file(newsgrp->mail_list, tmp_mailfile, newsgrp->ng_name);
  604. X        (void) unlink(tmp_mailfile);
  605. X    }
  606. X    return;
  607. X}
  608. X
  609. X/* 
  610. X** Notify Users of Archiving.
  611. X**      If users have been specified to be informed, check to see
  612. X**      if they have requested a specific logging format. If so
  613. X**      use the specified format to notify the user. If not, use
  614. X**      "file archived at path" message.
  615. X*/
  616. Xvoid notify_users(filename,ng,num_msgs)
  617. Xchar *filename;
  618. Xstruct group_archive *ng;
  619. Xint num_msgs;
  620. X{
  621. X    /*
  622. X    ** Are there users specified in the 
  623. X    ** newsgroup section ? 
  624. X    */
  625. X    if ( *(ng->mail_list) ) {
  626. X        if ( *(ng->logformat) )
  627. X           logit(tmp_mailfile, ng->logformat, filename);
  628. X        else
  629. X           logit(tmp_mailfile, DEFAULT_LOG_FORMAT, filename);
  630. X    }
  631. X
  632. X    /* 
  633. X    ** Are there users specified in the 
  634. X    ** global section ? 
  635. X    */
  636. X    if ( *mail ) {
  637. X        if (num_msgs == 0) /* print the newsgroup name out */
  638. X            logit(global_mailfile, "\n\t\t:%G:\n",filename);
  639. X        if (*log_format)
  640. X            logit(global_mailfile, log_format,filename);
  641. X        else 
  642. X            logit(global_mailfile, DEFAULT_LOG_FORMAT, filename);
  643. X    }
  644. X}
  645. X
  646. X/*
  647. X** Log_activities
  648. X**
  649. X** There are two possible logfiles that need to be written. 
  650. X** The group specific logfile (ng->logfile) and the global 
  651. X** log. If it has been configured to use a specific format
  652. X** for the logging, do so. Else, just record the fact the
  653. X** file was sucessfully archived and the date.          
  654. X*/
  655. Xvoid log_activities(filename,ng)
  656. Xchar *filename;
  657. Xstruct group_archive *ng;
  658. X{
  659. X   long clock;
  660. X   long time();
  661. X   char *ctime();
  662. X   
  663. X   char logbuf[BUFSIZ];
  664. X   char dms_date[30];
  665. X   
  666. X   if ( !*(ng->logformat) || !*log_format) {
  667. X       clock = time((long *)0);
  668. X       (void) strcpy(dms_date, ctime(&clock));
  669. X       *(dms_date+(strlen(dms_date)-1)) = '\0';
  670. X       (void) sprintf(logbuf,"%s archived %s",filename, dms_date);
  671. X   }
  672. X
  673. X   if ( *(ng->logformat) )
  674. X       logit(ng->logfile, ng->logformat, filename);
  675. X   else
  676. X       logit(ng->logfile, logbuf, filename);
  677. X
  678. X   if ( *log_format )
  679. X       logit(log, log_format, filename);
  680. X   else
  681. X       logit(log, logbuf, filename);
  682. X}
  683. X
  684. X/*
  685. X** logit
  686. X**
  687. X** This function is used to append a logfile record 
  688. X** if there is a logfile name specified.
  689. X**
  690. X*/
  691. X
  692. Xvoid logit(filename, format_of_log, arch_file)
  693. Xchar *filename;
  694. Xchar *format_of_log;
  695. Xchar *arch_file;
  696. X{
  697. X    FILE *fp, *fopen();
  698. X    char *qp;
  699. X
  700. X    if (!test) {
  701. X        if ( *(filename) ) {   /* Is a logfile specified ? */
  702. X            if ((fp = fopen(filename,"a")) != NULL) {
  703. X                qp = format_output(format_of_log, arch_file, ARCHIVE);
  704. X                (void) fprintf(fp,"%s\n",qp);
  705. X                (void) fclose(fp);
  706. X            }
  707. X        }
  708. X    }
  709. X}    
  710. X
  711. X/*
  712. X** Set_ownership
  713. X**
  714. X**      This functions is responsible for setting the owner, group
  715. X**      and modes of a file just put into the archive. Two file names
  716. X**      are passed to this function. "filename" contains the compression
  717. X**      suffix if the file is to be compressed. "flname" is the name of
  718. X**      the file without the compression suffix. If the ownership or
  719. X**      modes can not be set on the target "filename", this function
  720. X**      then tries to set the original file, "flname". In this manner,
  721. X**      the file permissions get set even if the compression routine fails.
  722. X*/     
  723. X
  724. Xvoid set_ownership(filename,flname,ng)
  725. Xchar *filename;             /* filename with compression suffix    */ 
  726. Xchar *flname;               /* filename without compression suffix */
  727. Xstruct group_archive *ng;
  728. X{
  729. X    int chmod();
  730. X    int chown();
  731. X
  732. X    if (verbose)    /* Print out the actions about to be preformed */
  733. X        (void) fprintf(logfp,"chmod\t<%o> <%s>\n", ng->modes, filename);
  734. X
  735. X    if (!test) {    /* change the file modes to the specified modes */
  736. X        if (chmod(filename,ng->modes) != 0) {
  737. X            /* Assume the compress failed and try the original... */
  738. X            if (chmod(flname,ng->modes) != 0) 
  739. X                record_problem("Can't change modes of %O", filename, ng);
  740. X        }
  741. X    }
  742. X
  743. X    if (verbose) {  /* Print out the actions about to be preformed */
  744. X        (void) fprintf(logfp,"chown\t<%d> <%s>\n", ng->owner, filename);
  745. X        (void) fprintf(logfp,"chgrp\t<%d> <%s>\n", ng->group, filename);
  746. X    }
  747. X
  748. X    if (!test) {    /* chown the owner/group to the desired values */
  749. X        if (chown(filename, ng->owner, ng->group) != 0) {
  750. X            /* Assume the compress failed and try the original... */
  751. X            if (chown(flname, ng->owner, ng->group) != 0) { 
  752. X                /*
  753. X                ** Are we on a system that has a braindamaged chown 
  754. X                ** and does not let a general user give files away ?
  755. X                ** Assume so.  Quota be gone!!
  756. X                */
  757. X                if (getuid() == 0)
  758. X                    record_problem("Can't change ownership of %O",filename,ng);
  759. X            }
  760. X        }
  761. X    }
  762. X}
  763. X
  764. Xvoid mail_file(user_list, file_to_mail, nwsgrp)
  765. Xchar *user_list;
  766. Xchar *file_to_mail;
  767. Xchar *nwsgrp;
  768. X{
  769. X    char  *list, *name;
  770. X    char  cmdstr[80];
  771. X
  772. X    /* Is there a list of users to mail to ? */
  773. X    if ( !*user_list || (strlen(user_list) == 0))
  774. X        return;
  775. X
  776. X    /* Was there a notification file created ? */
  777. X    if (stat(file_to_mail, &sbuf) != 0) 
  778. X        return;
  779. X
  780. X    name = user_list;
  781. X    do {
  782. X       if ((list = strchr(name,',')) != NULL) {
  783. X            list++;
  784. X            *(list-1) = '\0';
  785. X        }
  786. X
  787. X#ifdef SUBJECT_LINE
  788. X        (void) sprintf(cmdstr, "%s -s '%s' %s < %s", 
  789. X                   MAIL, nwsgrp, name, file_to_mail);
  790. X#else
  791. X        (void) sprintf(cmdstr, "%s %s < %s", MAIL, name, file_to_mail);
  792. X#endif
  793. X        if (verbose)
  794. X            (void) fprintf(logfp,"Mailing %s to %s\n",
  795. X                           nwsgrp, name);
  796. X        if (!test) 
  797. X            (void) system(cmdstr);
  798. X
  799. X        name = list;
  800. X
  801. X    } while (name != NULL);
  802. X    return;
  803. X}
  804. X
  805. Xvoid build_index(filename,ng)
  806. Xchar *filename;
  807. Xstruct group_archive *ng;
  808. X{
  809. X    if (*(ng->index)) {        /* Is there a newsgroup index file ?  */
  810. X        if (*(ng->indformat))  /* Yes, Is there a index file format? */
  811. X            logit(ng->index, ng->indformat, filename);
  812. X        else if (*index_format)    /* No, is there a global format ? */
  813. X            logit(ng->index, index_format, filename);
  814. X        else                   /* No, use the default index format   */
  815. X            logit(ng->index, DEFAULT_INDEX_FORMAT, filename);
  816. X    }
  817. X
  818. X    if (*mindex) {            /* Is there a global index file ?       */
  819. X        if (*index_format)   /* Yes, Is there a global file format ? */
  820. X            logit(mindex, index_format, filename);
  821. X        else                 /* No, so use the default index format  */
  822. X            logit(ng->index, DEFAULT_INDEX_FORMAT , filename);
  823. X    }
  824. X}
  825. X
  826. X
  827. Xchar *compress_file(filename,ng)
  828. Xchar *filename;
  829. Xstruct group_archive *ng;
  830. X{
  831. X    static char compressed[MAXNAMLEN];
  832. X
  833. X    (void) strcpy(compressed, filename);  /* store the filename */
  834. X
  835. X    /* Check to see if a group specific compress was specified.      */
  836. X    /* If so, then execute the command with the filename passed in.  */
  837. X    /* Else check to see if a global compress was specified. If so,  */
  838. X    /* then execute the command with the filename passed in.         */
  839. X    /* If both are NULL, no compression is done.                     */
  840. X
  841. X    if (*(ng->compress) || (*compress)) { 
  842. X        if (*(ng->compress)) 
  843. X            (void) strcat(compressed, do_compress(ng->compress, filename));
  844. X        else if (*compress) 
  845. X            (void) strcat(compressed, do_compress(compress, filename));
  846. X
  847. X        /* Check to see if the compression worked. If not, return the */
  848. X        /* original file name passed to this function. The check is   */
  849. X        /* done by assuring the compressed file exists. If not then   */
  850. X        /* it is assumed that it failed.                              */
  851. X
  852. X        if (stat(compressed, &sbuf) == -1) 
  853. X            (void) strcpy(compressed, filename);   /* restore filename */
  854. X    }
  855. X    return(compressed);
  856. X}
  857. X
  858. Xchar *do_compress(packit,filename)
  859. Xchar *packit;
  860. Xchar *filename;
  861. X{
  862. X    char *comp_cmd;
  863. X    char *kp;
  864. X    char cmd[BUFSIZ];
  865. X
  866. X    (void) sprintf(cmd,"%s %s", packit, filename);
  867. X
  868. X    /* 
  869. X    ** get the basename of the command to use.
  870. X    */
  871. X    comp_cmd = basename(packit);
  872. X
  873. X    if (verbose)
  874. X       (void) fprintf(logfp,"%s %s\n", comp_cmd, filename);
  875. X
  876. X    if (!test) 
  877. X       (void) system(cmd);
  878. X
  879. X    /* 
  880. X    ** Need to remove any compression command 
  881. X    ** options if they exist. (compress -f)
  882. X    */
  883. X
  884. X    (void) sprintf(cmd,"%s", comp_cmd);
  885. X
  886. X    if ((kp = strchr(cmd,' ')) != NULL) {
  887. X         *kp = '\0';
  888. X    }
  889. X    return(suffix(cmd));
  890. X}
  891. X
  892. X
  893. X/*
  894. X** Record_problem()
  895. X**    This function is used to log problems encountered
  896. X**    to the designated parties.
  897. X*/
  898. X
  899. Xvoid record_problem(msg_fmt,filename,ng)
  900. Xchar *msg_fmt;
  901. Xchar *filename;
  902. Xstruct group_archive *ng;
  903. X{
  904. X    /* 
  905. X    ** This function is used in the event that a problem
  906. X    ** has occurred during archiving. It mails a message
  907. X    ** to the newsgroup speecified list and it mails a 
  908. X    ** message to the globally specified users.
  909. X    ** 
  910. X    ** It then logs the fact into both the newsgroup 
  911. X    ** and the global logfiles if they have been specified.
  912. X    */
  913. X
  914. X    if ( *(ng->mail_list) ) 
  915. X        logit(tmp_mailfile, msg_fmt, filename);
  916. X    
  917. X    if ( *mail ) 
  918. X        logit(global_mailfile, msg_fmt,filename);
  919. X    
  920. X    logit(ng->logfile, msg_fmt, filename);
  921. X    logit(log, msg_fmt, filename);
  922. X}
  923. END_OF_FILE
  924. if test 27854 -ne `wc -c <'rkive/rkive.c'`; then
  925.     echo shar: \"'rkive/rkive.c'\" unpacked with wrong size!
  926. fi
  927. # end of 'rkive/rkive.c'
  928. fi
  929. if test -f 'rkive/setup.c' -a "${1}" != "-c" ; then 
  930.   echo shar: Will not clobber existing file \"'rkive/setup.c'\"
  931. else
  932. echo shar: Extracting \"'rkive/setup.c'\" \(23815 characters\)
  933. sed "s/^X//" >'rkive/setup.c' <<'END_OF_FILE'
  934. X/*
  935. X** This software is Copyright (c) 1989, 1990, 1991 by Kent Landfield.
  936. X**
  937. X** Permission is hereby granted to copy, distribute or otherwise 
  938. X** use any part of this package as long as you do not try to make 
  939. X** money from it or pretend that you wrote it.  This copyright 
  940. X** notice must be maintained in any copy made.
  941. X**
  942. X*/
  943. X
  944. X#if !defined(lint) && !defined(SABER)
  945. Xstatic char SID[] = "@(#)setup.c    2.2 2/23/91";
  946. X#endif
  947. X
  948. X#include <sys/types.h>
  949. X#include <sys/stat.h>
  950. X#include <stdio.h>
  951. X#include <ctype.h>
  952. X#include <pwd.h>
  953. X#include <grp.h>
  954. X#include "cfg.h"
  955. X
  956. X#define GAG(b) ((void) fprintf(errfp,"%s invalid variable, ignoring.\n",b))
  957. X
  958. Xchar spooldir[MAXNAMLEN]     = { SPOOLDIR };
  959. Xchar problems_dir[MAXNAMLEN] = { PROBLEMS_DIR };
  960. X
  961. Xint default_owner = OWNER;
  962. Xint default_group = GROUP;
  963. Xint default_modes = MODES;
  964. Xint default_type = CHRONOLOGICAL;
  965. Xint default_patch_type = HISTORICAL;
  966. X
  967. Xchar default_match[MAXMATCHLEN];
  968. X
  969. X/*
  970. X** compress -
  971. X** Used to  determine whether or not articles should be compressed 
  972. X** to save space. The command to execute is stored in compress.
  973. X*/
  974. Xchar compress[MAXNAMLEN] = { '\0' };
  975. X
  976. X/*
  977. X** arch_command -
  978. X** Used to determine whether or not articles should be piped
  979. X** to an external command for the actual archiving.
  980. X*/
  981. Xchar arch_command[MAXNAMLEN] = { '\0' };
  982. X
  983. X/*
  984. X** mail -
  985. X** If specified, all actions logged are mailed to the list of users 
  986. X** specified.  The user names are a comma seperated list. 
  987. X*/
  988. Xchar mail[MAXNAMLEN] = { '\0' };
  989. X
  990. X/*
  991. X** checkhash -
  992. X** If specified, command to feed article to for transit damage.
  993. X*/
  994. Xchar checkhash[MAXNAMLEN] = { '\0' };
  995. X
  996. X#ifdef NNTP
  997. X/*
  998. X** nntp -
  999. X** If specified, nntp contains the system name of the nntp server.
  1000. X*/
  1001. Xchar nntp[MAXNAMLEN] = { '\0' };
  1002. X#endif /*NNTP*/
  1003. X
  1004. X/*
  1005. X** log -
  1006. X** The location of the master log in which all actions are logged. 
  1007. X** If not specified, all logged events are printed on stdout.
  1008. X*/
  1009. Xchar log[MAXNAMLEN] = { '\0' };
  1010. X
  1011. X/*
  1012. X** log_format -
  1013. X** The format of each individual log file record. The format is
  1014. X** then filled with information contained in the headers.
  1015. X*/
  1016. Xchar log_format[BUFSIZ] = { '\0' };
  1017. X
  1018. X/*
  1019. X** mindex -
  1020. X** The location of the master index.
  1021. X*/
  1022. Xchar mindex[MAXNAMLEN] = { '\0' };
  1023. X
  1024. X/*
  1025. X** index_format -
  1026. X** The format of each individual master index record. The format 
  1027. X** is then filled with information contained in the headers.
  1028. X*/
  1029. Xchar index_format[BUFSIZ] = { '\0' };
  1030. X
  1031. Xchar *config_file;
  1032. XFILE *config;
  1033. X
  1034. Xstruct stat stbuf;
  1035. Xstruct passwd *pwent;
  1036. X
  1037. Xint get_group();
  1038. Xint get_owner();
  1039. Xint correct_modes();
  1040. Xint get_patch_type();
  1041. Xint get_archive_type();
  1042. Xint fclose();
  1043. Xint sscanf();
  1044. Xint stat();
  1045. Xint strlen();
  1046. Xint strcmp();
  1047. Xint strncmp();
  1048. Xchar *strstrip();
  1049. Xchar *strchr();
  1050. Xchar *strcpy();
  1051. Xvoid error();
  1052. Xvoid get_spooldir();
  1053. Xvoid get_archive_basedir();
  1054. Xstruct passwd *getpwnam();
  1055. X
  1056. Xstruct restricted_dirs {
  1057. X    char   *dirstr;            /* path of restricted directory */
  1058. X};
  1059. X
  1060. Xstatic struct restricted_dirs base_dirs[] = {
  1061. X{  "/"               },
  1062. X{  "/bin"            },
  1063. X{  "/dev"            },
  1064. X{  "/dev/dsk"        },
  1065. X{  "/dev/rdsk"       },
  1066. X{  "/etc"            },
  1067. X{  "/lib"            },
  1068. X{  "/stand"          },
  1069. X{  "/sbin"           },
  1070. X{  "/sys"            },
  1071. X{  "/usr/5bin"       },
  1072. X{  "/usr/5include"   },
  1073. X{  "/usr/5lib"       },
  1074. X{  "/usr/adm"        },
  1075. X{  "/usr/adm"        },
  1076. X{  "/usr/boot"       },
  1077. X{  "/usr/diag"       },
  1078. X{  "/usr/etc"        },
  1079. X{  "/usr/include"    },
  1080. X{  "/usr/kvm"        },
  1081. X{  "/usr/spool/uucp" },
  1082. X{  "/usr/man"        },
  1083. X{  "/usr/sccs"       },
  1084. X{  "/usr/sys"        },
  1085. X{  "/usr/ucb"        },
  1086. X{  "/usr/ucbinclude" },
  1087. X{  "/usr/ucblib"     },
  1088. X{  "/usr/xpg2bin"    },
  1089. X{  "/usr/xpg2include" },
  1090. X{  "/usr/xpg2lib"    },
  1091. X{  NULL              },
  1092. X};
  1093. X
  1094. Xint config_line_count = 0;
  1095. X
  1096. X/*
  1097. X**  Reads lines from file, catting lines 
  1098. X**  ending with a backslash together. 
  1099. X*/
  1100. X
  1101. Xchar *long_fgets(buffer, size, fp)
  1102. Xchar *buffer;
  1103. Xint size;
  1104. XFILE *fp;
  1105. X{
  1106. X    static char buf[BUFSIZ];
  1107. X    extern char *strcat();
  1108. X    register char *p;
  1109. X
  1110. X    *buffer = 0;
  1111. X
  1112. X    for (;;) {
  1113. X        if (fgets(buf, BUFSIZ, fp) == NULL) {
  1114. X            if (*buffer) {
  1115. X                if ((p = strchr(buf, '\n')) != NULL) 
  1116. X                    *p = 0;
  1117. X                return buffer;
  1118. X            }
  1119. X            else
  1120. X                return NULL;
  1121. X        }
  1122. X
  1123. X        if ((p = strchr(buf, '\n')) != NULL)
  1124. X            *p = 0;
  1125. X
  1126. X        if (*buf) {
  1127. X            if (*(buf + strlen(buf) - 1) != '\\') {
  1128. X                /* 
  1129. X                ** If line would be too long,
  1130. X                ** print warning and return empty 
  1131. X                */
  1132. X                if (strlen(buffer) + strlen(buf) >= size) {
  1133. X                   (void) fprintf(errfp,"Config %d: Input line overflow, %d max\n",
  1134. X                             config_line_count, size);
  1135. X                    *buffer = 0;
  1136. X                    return buffer;
  1137. X                }
  1138. X                (void) strcat(buffer, buf);
  1139. X                return buffer;
  1140. X            }
  1141. X            else {
  1142. X                *(buf + strlen(buf) - 1) = 0; /* Remove backslash */
  1143. X
  1144. X                /* 
  1145. X                ** If too long, print warning, read 
  1146. X                ** all continuation lines and ignore 
  1147. X                ** them, return empty line 
  1148. X                */
  1149. X
  1150. X                if (strlen(buffer) + strlen(buf) >= size) {
  1151. X                    (void) fprintf(errfp,"Config %d: Input line overflow, %d max\n",
  1152. X                           config_line_count, size);
  1153. X                    while (*(buf + strlen(buf) - 1) == '\\' && fgets(buf, BUFSIZ, fp))
  1154. X                          ;
  1155. X                    *buffer = 0;
  1156. X                    return buffer;
  1157. X                }
  1158. X
  1159. X                /* Add new line and read next one */
  1160. X
  1161. X                (void) strcat(buffer, buf);
  1162. X             }
  1163. X         }
  1164. X         else
  1165. X             return buffer;
  1166. X
  1167. X       } /* End for(ever) */
  1168. X}
  1169. X
  1170. X
  1171. Xvoid setup_defaults()
  1172. X{
  1173. X    char *sp;
  1174. X    char *buf;
  1175. X    char buffer[BUFSIZ];
  1176. X    char mode_str[128];
  1177. X
  1178. X    char *sav_format();
  1179. X    char *get_cmd();
  1180. X    char *get_users();
  1181. X#ifdef NNTP
  1182. X    char *getnntp();
  1183. X#endif /*NNTP*/
  1184. X    FILE *efopen();
  1185. X
  1186. X    config = efopen(config_file,"r");
  1187. X
  1188. X    num = -1; /* initialize group structure index */
  1189. X    
  1190. X    while (long_fgets(buffer, sizeof buffer, config) != NULL) {
  1191. X        config_line_count++;
  1192. X        /* ignore comments and blank lines */
  1193. X        if (*buffer == '#' || !*buffer) 
  1194. X            continue;
  1195. X
  1196. X        buf = buffer;
  1197. X
  1198. X        /* strip leading spaces and tabs */
  1199. X    while(*buf == ' ' || *buf == '\t')
  1200. X             ++buf;
  1201. X
  1202. X        /* if embedded comments, truncate at the comment */
  1203. X        if ((sp = strchr(buf,'#')) != NULL)
  1204. X             *sp = '\0';
  1205. X    
  1206. X        /* check to see if newsgroup entry */
  1207. X
  1208. X        if (*buf == '$' && *(buf+1) == '$') {
  1209. X            if (++num >= NUM_NEWSGROUPS)
  1210. X               error("Maximum number of newsgroups exceeded!!\n", 
  1211. X                    "Please increase the NUM_NEWSGROUPS define...");
  1212. X
  1213. X            sp = buf+2;
  1214. X            while (*sp && !isspace(*sp))
  1215. X        ++sp;
  1216. X            *sp = '\0';
  1217. X
  1218. X            group[num].owner     = default_owner;
  1219. X            group[num].group     = default_group;
  1220. X            group[num].modes     = default_modes;
  1221. X            group[num].type      = default_type;
  1222. X            group[num].patch_type = default_patch_type;
  1223. X            (void) strcpy (group[num].ng_name, strstrip(buf+2));
  1224. X            group[num].location[0]  = '\0';
  1225. X            group[num].mail_list[0] = '\0';
  1226. X            group[num].arc_done[0]  = '\0';
  1227. X            group[num].logfile[0]   = '\0';
  1228. X            group[num].index[0]     = '\0';
  1229. X            group[num].patchlog[0]  = '\0';
  1230. X            group[num].logformat[0] = '\0';
  1231. X            group[num].indformat[0] = '\0';
  1232. X            group[num].compress[0]  = '\0';
  1233. X            group[num].checkhash[0]  = '\0';
  1234. X            group[num].match[0]     = '\0';
  1235. X            group[num].arch_command[0] = '\0';
  1236. X
  1237. X#ifdef NNTP
  1238. X            group[num].nntp[0]  = '\0';
  1239. X#endif /*NNTP*/
  1240. X        }
  1241. X
  1242. X        else if ((sp = strchr(buf,'=')) != NULL) {
  1243. X            sp++;
  1244. X                    /* Global assignment */
  1245. X            while (*sp == ' ' || *sp == '\t')
  1246. X                sp++;
  1247. X
  1248. X            if (!*sp)        /* is something still there ? */
  1249. X        continue;
  1250. X
  1251. X            switch(*buf) {
  1252. X               case 'A': if (strncmp(buf, "ARCHIVE_CMD", 11) == 0)
  1253. X                            (void) strcpy(arch_command, get_cmd(sp));
  1254. X                         else
  1255. X                            GAG(buf);
  1256. X                         break;
  1257. X               case 'C': if (strncmp(buf, "COMPRESS", 8) == 0)
  1258. X                            (void) strcpy(compress, get_cmd(sp));
  1259. X                         else if (strncmp(buf, "CHECKHASH", 9) == 0)
  1260. X                            (void) strcpy(checkhash, get_cmd(sp));
  1261. X                         else
  1262. X                            GAG(buf);
  1263. X                         break;
  1264. X               case 'G': if (strncmp(buf,"GROUP",5) == 0)
  1265. X                             default_group = get_group(sp);
  1266. X                         else
  1267. X                            GAG(buf);
  1268. X                         break;
  1269. X               case 'I': if (strncmp(buf, "INDEX_FORMAT", 12) == 0)
  1270. X                            (void) strcpy(index_format, sav_format(sp));
  1271. X                         else if (strncmp(buf, "INDEX", 3) == 0)
  1272. X                            (void) strcpy(mindex, strstrip(sp));
  1273. X                         else
  1274. X                            GAG(buf);
  1275. X                         break;
  1276. X               case 'L': if (strncmp(buf, "LOG_FORMAT", 10) == 0)
  1277. X                            (void) strcpy(log_format, sav_format(sp));
  1278. X                         else if (strncmp(buf, "LOG", 3) == 0)
  1279. X                            (void) strcpy(log, strstrip(sp));
  1280. X                         else
  1281. X                            GAG(buf);
  1282. X                         break;
  1283. X               case 'M': if (strncmp(buf, "MAIL",4) == 0) 
  1284. X                             (void) strcpy(mail,get_users(sp));
  1285. X                         else if (strncmp(buf, "MODE",4) == 0) 
  1286. X                             default_modes = correct_modes(sp, mode_str);
  1287. X                         else if (strncmp(buf, "MATCH", 5) == 0)
  1288. X                             (void) strcpy(default_match, sp);
  1289. X                         else
  1290. X                             GAG(buf);
  1291. X                         break;
  1292. X#ifdef NNTP
  1293. X               case 'N': if (strncmp(buf, "NNTP",4) == 0) 
  1294. X                             (void) strcpy(nntp, getnntp(sp));
  1295. X                         else 
  1296. X                             GAG(buf);
  1297. X                         break;
  1298. X#endif /*NNTP*/
  1299. X               case 'O': if (strncmp(buf,"OWNER",5) == 0)
  1300. X                             default_owner = get_owner(sp);
  1301. X                         else 
  1302. X                             GAG(buf);
  1303. X                         break;
  1304. X               case 'P': if (strncmp(buf, "PROBLEMS", 8) == 0)
  1305. X                           (void) strcpy(problems_dir, strstrip(sp));
  1306. X                         else if (strncmp(buf,"PATCHES",7) == 0)
  1307. X                           default_patch_type = get_patch_type("Global",sp);
  1308. X                         else 
  1309. X                             GAG(buf);
  1310. X                         break;
  1311. X               case 'S': if (strncmp(buf,"SPOOLDIR",8) == 0)
  1312. X                             get_spooldir(sp);
  1313. X                         else 
  1314. X                             GAG(buf);
  1315. X                         break;
  1316. X               case 'T': if (strncmp(buf,"TYPE",4) == 0)
  1317. X                             default_type = get_archive_type("Global", sp);
  1318. X                         else 
  1319. X                             GAG(buf);
  1320. X                         break;
  1321. X               default : (void) fprintf(errfp,
  1322. X                                  "%s invalid global assignment, ignoring.\n",
  1323. X                                  buf);
  1324. X            }
  1325. X        }
  1326. X        else if ((sp = strchr(buf,':')) != NULL) {
  1327. X            sp++;
  1328. X                /* group variable assignment */
  1329. X            while (*sp == ' ' || *sp == '\t')
  1330. X                sp++;
  1331. X
  1332. X            if (!*sp)        /* is something still there ? */
  1333. X        continue;
  1334. X
  1335. X            switch(*buf) {
  1336. X               case 'A': if (strncmp(buf, "ARCHIVE_CMD", 11) == 0)
  1337. X                            (void)strcpy(group[num].arch_command,get_cmd(sp));
  1338. X                         else if (strncmp(buf, "ARCHIVED_LOG", 11) == 0) 
  1339. X                            (void) sprintf(group[num].arc_done, strstrip(sp));
  1340. X                         else
  1341. X                            GAG(buf);
  1342. X                         break;
  1343. X               case 'B': if (strncmp(buf, "BASEDIR",7) == 0) 
  1344. X                            get_archive_basedir(sp);
  1345. X                         break;
  1346. X               case 'C': if (strncmp(buf, "COMPRESS", 8) == 0)
  1347. X                            (void) strcpy(group[num].compress,get_cmd(sp));
  1348. X                         else if (strncmp(buf, "CHECKHASH", 9) == 0)
  1349. X                            (void) strcpy(group[num].checkhash,get_cmd(sp));
  1350. X                         else
  1351. X                            GAG(buf);
  1352. X                         break;
  1353. X               case 'G': if (strncmp(buf,"GROUP",5) == 0)
  1354. X                             group[num].group = get_group(sp);
  1355. X                         else
  1356. X                            GAG(buf);
  1357. X                         break;
  1358. X               case 'I': if (strncmp(buf, "INDEX_FORMAT", 12) == 0)
  1359. X                            (void) strcpy(group[num].indformat,sav_format(sp));
  1360. X                         else if (strncmp(buf, "INDEX", 3) == 0)
  1361. X                             (void) strcpy(group[num].index, strstrip(sp));
  1362. X                         else
  1363. X                             GAG(buf);
  1364. X                         break;
  1365. X               case 'L': if (strncmp(buf, "LOG_FORMAT", 10) == 0)
  1366. X                            (void) strcpy(group[num].logformat, sav_format(sp));
  1367. X                         else if (strncmp(buf, "LOG", 3) == 0)
  1368. X                            (void) strcpy(group[num].logfile, strstrip(sp));
  1369. X                         else
  1370. X                            GAG(buf);
  1371. X                         break;
  1372. X               case 'M': if (strncmp(buf, "MAIL",4) == 0)
  1373. X                            (void) strcpy(group[num].mail_list, get_users(sp));
  1374. X                         else if (strncmp(buf, "MODE",4) == 0) 
  1375. X                             group[num].modes = correct_modes(sp, mode_str);
  1376. X                         else if (strncmp(buf, "MATCH", 5) == 0)
  1377. X                             /* Copy as it is! */
  1378. X                             (void) strcpy(group[num].match, sp);
  1379. X                         else 
  1380. X                             GAG(buf);
  1381. X                         break;
  1382. X#ifdef NNTP
  1383. X               case 'N': if (strncmp(buf, "NNTP",4) == 0) 
  1384. X                             (void) strcpy(group[num].nntp, getnntp(sp));
  1385. X                         else 
  1386. X                             GAG(buf);
  1387. X                         break;
  1388. X#endif /*NNTP*/
  1389. X               case 'O': if (strncmp(buf,"OWNER",5) == 0)
  1390. X                             group[num].owner = get_owner(sp);
  1391. X                         else 
  1392. X                             GAG(buf);
  1393. X                         break;
  1394. X               case 'P': if (strncmp(buf,"PATCHLOG",8) == 0)
  1395. X                             (void) sprintf(group[num].patchlog, strstrip(sp));
  1396. X                         else if (strncmp(buf,"PATCHES",7) == 0)
  1397. X                             group[num].patch_type = get_patch_type(group[num].ng_name,sp);
  1398. X                         else 
  1399. X                             GAG(buf);
  1400. X                         break;
  1401. X               case 'T': if (strncmp(buf,"TYPE",4) == 0)
  1402. X                             group[num].type = get_archive_type(group[num].ng_name,sp);
  1403. X                         else 
  1404. X                             GAG(buf);
  1405. X                         break;
  1406. X               default : (void) fprintf(errfp,
  1407. X                                  "%s invalid group assignment, ignoring.\n",
  1408. X                                  buf);
  1409. X            }
  1410. X        }
  1411. X        else /* no idea what it is */
  1412. X            error("unknown line type", buf);
  1413. X    }
  1414. X    (void) fclose(config);
  1415. X    config_line_count = 0;
  1416. X}
  1417. X
  1418. Xvoid error(msg1,msg2)
  1419. X   char *msg1;
  1420. X   char *msg2;
  1421. X{
  1422. X   if (config_line_count)
  1423. X      (void) fprintf(errfp,"%s: config line %d: %s %s\n",
  1424. X                   progname, config_line_count, msg1, msg2);
  1425. X   else
  1426. X      (void) fprintf(errfp,"%s: %s %s\n",progname,msg1, msg2);
  1427. X
  1428. X    exit(1);
  1429. X/*NOTREACHED*/
  1430. X}
  1431. X
  1432. X/*
  1433. X** valid_base_directory
  1434. X**
  1435. X** Assure the directory specified in the configuration file 
  1436. X** as the base directory for a newsgroup archive is not found 
  1437. X** in the table of restricted base directories. 
  1438. X**
  1439. X** This kind of checking is almost insulting to me as an 
  1440. X** administrator but, enough people asked me to put it in 
  1441. X** so "this duds for you"..
  1442. X*/
  1443. X
  1444. Xint valid_base_directory(argstr)
  1445. X    char *argstr;
  1446. X {
  1447. X    register char *rp;
  1448. X    register char *dp;
  1449. X    char wpath[MAXNAMLEN];
  1450. X    char lastchar;
  1451. X    struct restricted_dirs *pt;
  1452. X
  1453. X    /* 
  1454. X    ** First check to see if the base directory is any
  1455. X    ** character other than a slash. We need to assure
  1456. X    ** that "../../../etc" or ./etc is not allowed.  We
  1457. X    ** need a valid absolute path with which to do relative
  1458. X    ** path addressing. (Have I confused myself yet ?)
  1459. X    */
  1460. X
  1461. X    if (*argstr != '/') 
  1462. X            return(FALSE);
  1463. X
  1464. X    /* 
  1465. X    ** Strip the string of duplicate '/'s.
  1466. X    ** Also check to assure that the path specified
  1467. X    ** does not contain the '..' sequence.
  1468. X    */
  1469. X
  1470. X    dp = argstr;
  1471. X    rp = wpath;
  1472. X    lastchar = ' ';
  1473. X
  1474. X    while (*dp) {
  1475. X       if (*dp != '/' || lastchar != '/') {
  1476. X           lastchar = *dp;
  1477. X           *rp++ = *dp;
  1478. X       }
  1479. X       if (*dp == '.' && lastchar == '.') {
  1480. X           if ((*(dp+1) == '/') || (*(dp+1) == '\0'))
  1481. X               return(FALSE);
  1482. X       }
  1483. X       ++dp;
  1484. X    }
  1485. X    *rp = '\0';
  1486. X
  1487. X    /* 
  1488. X    ** strip the string of trailing '/'s so
  1489. X    ** I can use the simple checking below.
  1490. X    */
  1491. X
  1492. X    dp = wpath+(strlen(wpath)-1);
  1493. X    while(*dp == '/' && dp > wpath)
  1494. X        *dp = '\0';
  1495. X
  1496. X    /* 
  1497. X    ** check if they match 
  1498. X    */
  1499. X
  1500. X    pt = &base_dirs[0];
  1501. X    while ((pt->dirstr) != NULL) {
  1502. X
  1503. X        if (strcmp(wpath, pt->dirstr) == 0) 
  1504. X            return(FALSE);
  1505. X
  1506. X        pt++;
  1507. X    }
  1508. X    return(TRUE);
  1509. X}
  1510. X
  1511. Xvoid get_archive_basedir(s)
  1512. Xchar *s;
  1513. X{
  1514. X    (void) strcpy(group[num].location, strstrip(s));
  1515. X
  1516. X    if (!valid_base_directory(group[num].location))
  1517. X        error(group[num].ng_name," - Invalid archive base directory!");
  1518. X}
  1519. X
  1520. Xint correct_modes(s,mode_string)
  1521. Xchar *s;
  1522. Xchar *mode_string;
  1523. X{
  1524. X    register int c;
  1525. X    register int i;
  1526. X
  1527. X    i = 0;
  1528. X    (void) sscanf(s, "%s", mode_string);
  1529. X    while ((c = *mode_string++) >= '0' && c <= '7')
  1530. X        i = (i << 3) + (c - '0');
  1531. X    mode_string--;
  1532. X    return(i);
  1533. X}
  1534. X
  1535. X
  1536. Xchar *get_cmd(cmd)
  1537. Xchar *cmd;
  1538. X{
  1539. X    static char *rp;
  1540. X    char *kp;
  1541. X
  1542. X    rp = strstrip(cmd);
  1543. X
  1544. X    /*
  1545. X    ** Here an external command needs to be verified.
  1546. X    ** To do so, the options must be removed. I am being
  1547. X    ** real lazy here but what the hey..
  1548. X    ** If a space is found after the cmdline is striped
  1549. X    ** put a null there and then replace it with a 
  1550. X    ** space after the check... 
  1551. X    */
  1552. X   
  1553. X    if ((kp = strchr(rp,' ')) != NULL)
  1554. X        *kp = '\0';
  1555. X    else if ((kp = strchr(rp,'\t')) != NULL)
  1556. X        *kp = '\0';
  1557. X
  1558. X    /* need to assure the user has specified */
  1559. X    /* a valid executable path.              */
  1560. X
  1561. X    if (stat(rp, &stbuf) != 0) 
  1562. X        error("Can't find specified command -", rp);
  1563. X
  1564. X    if (kp != NULL)  /* replace the space.. */
  1565. X        *kp = ' ';
  1566. X
  1567. X    return(rp);
  1568. X}
  1569. X
  1570. X#ifdef NNTP
  1571. Xchar *getnntp(loc)
  1572. Xchar *loc;
  1573. X{
  1574. X    static char *rp;
  1575. X
  1576. X    rp = strstrip(loc);
  1577. X     
  1578. X    /*
  1579. X    ** check to assure that the user does not wish to negate 
  1580. X    ** a global declaration for the nntp server.
  1581. X    */
  1582. X
  1583. X    if ((strncmp(rp,"LOCAL",5) == 0) || (strncmp(rp, "local",5) == 0))
  1584. X        return("");
  1585. X
  1586. X    return(rp);
  1587. X}
  1588. X#endif /*NNTP*/
  1589. X        
  1590. X
  1591. X
  1592. Xint get_group(valstr)
  1593. Xchar *valstr;
  1594. X{
  1595. X    char *wp;
  1596. X    struct group *grent;
  1597. X    struct group *getgrnam();
  1598. X    
  1599. X    /* group specified by names but */
  1600. X    /* needs to be numbers          */
  1601. X
  1602. X    wp = strstrip(valstr);
  1603. X
  1604. X    if ((grent = getgrnam(wp)) == NULL)
  1605. X         error("Invalid system group:",wp);
  1606. X    return(grent->gr_gid);
  1607. X}
  1608. X
  1609. X
  1610. Xint get_owner(valstr)
  1611. Xchar *valstr;
  1612. X{
  1613. X    char *wp;
  1614. X
  1615. X    /* owner specified by names but */
  1616. X    /* needs to be numbers          */
  1617. X
  1618. X    wp = strstrip(valstr);
  1619. X
  1620. X    if ((pwent = getpwnam(wp)) == NULL)
  1621. X         error("Invalid user:",wp);
  1622. X    return(pwent->pw_uid);
  1623. X}
  1624. X
  1625. Xint get_archive_type(ngname, s)
  1626. Xchar *ngname;
  1627. Xchar *s;
  1628. X{
  1629. X    int return_type = default_type;
  1630. X
  1631. X    if (strcmp(s, "Archive-Name") == 0) 
  1632. X        return_type = ARCHIVE_NAME;
  1633. X    else if (strcmp(s, "Volume-Issue") == 0) 
  1634. X        return_type = VOLUME_ISSUE;
  1635. X    else if (strcmp(s, "Chronological") == 0) 
  1636. X        return_type = CHRONOLOGICAL;
  1637. X    else if (strcmp(s, "Article-Number") == 0) 
  1638. X        return_type = ARTICLE_NUMBER;
  1639. X    else if (strcmp(s, "Comp-Archives") == 0) 
  1640. X        return_type = COMP_ARCHIVES;
  1641. X    else if (strcmp(s, "External-Command") == 0) 
  1642. X        return_type = EXTERNAL_COMMAND;
  1643. X    else if (strcmp(s, "Only-Archive-Name") == 0) 
  1644. X        return_type = ONLY_ARCHIVE_NAME;
  1645. X    else {
  1646. X        (void) fprintf(errfp,"%s: %s: %s %s\n", progname,
  1647. X                   ngname, "Invalid Archive Type:", s);
  1648. X        (void) fprintf(errfp,"\tTYPE Must be %s, %s, %s, %s, %s, %s or %s\n",
  1649. X                   "Archive-Name",  "Volume-Issue", "Comp-Archives",
  1650. X                   "External-Command", "Only-Archive-Name", 
  1651. X                   "Chronological", "Article-Number");
  1652. X        exit(1);
  1653. X    }
  1654. X    return(return_type);
  1655. X}
  1656. X
  1657. Xvoid get_spooldir(s)
  1658. Xchar *s;
  1659. X{
  1660. X    static char *rp;
  1661. X
  1662. X    rp = strstrip(s);
  1663. X
  1664. X    /* need to assure the user has specified */
  1665. X    /* a valid directory path for the base   */
  1666. X    /* directory for the news subsystem..    */
  1667. X    
  1668. X    if (stat(rp, &stbuf) != 0) 
  1669. X        error("Can't find SPOOLDIR -", rp);
  1670. X    
  1671. X    (void) strcpy(spooldir, rp);
  1672. X}
  1673. X
  1674. Xchar *get_users(s)
  1675. Xchar *s;
  1676. X{
  1677. X    char *strcat();
  1678. X
  1679. X    static char users[512];
  1680. X    char tmp_users[512];
  1681. X    char *list, *name;
  1682. X    char *cp, *dp;
  1683. X    register int i;
  1684. X
  1685. X    /* prepare the string for saving by stripping any spaces */
  1686. X
  1687. X    for (i = 0; i < sizeof users; i++)
  1688. X       users[i] = '\0';
  1689. X
  1690. X    cp = s;
  1691. X    dp = users;
  1692. X    while (*cp) {
  1693. X          if (*cp != ' ' && *cp != '\t')
  1694. X              *dp++ = *cp;
  1695. X          ++cp;
  1696. X    }
  1697. X      
  1698. X    /* Need to check the specified user list */
  1699. X    /* to assure that all users are valid.   */
  1700. X
  1701. X    (void) strcpy(tmp_users, users);
  1702. X    *users = '\0';
  1703. X
  1704. X    name = tmp_users;
  1705. X
  1706. X    while (name != NULL) {
  1707. X        /* is there additional users specified ? */
  1708. X    if ((list = strchr(name,',')) != NULL) {
  1709. X             list++;
  1710. X             *(list-1) = '\0';
  1711. X        }
  1712. X
  1713. X#ifdef CHECK_LOGNAME 
  1714. X        /* check if user is found in passwd file */
  1715. X        if ((pwent = getpwnam(name)) == NULL) 
  1716. X            error("Invalid user:",name);
  1717. X#endif /* CHECK_LOGNAME */
  1718. X
  1719. X        if (*users != '\0') {
  1720. X            (void) strcat(users, ",");
  1721. X            (void) strcat(users, name);
  1722. X        }
  1723. X        else 
  1724. X            (void) strcpy(users, name);
  1725. X        name = list;
  1726. X    }
  1727. X    return(users);
  1728. X}
  1729. X
  1730. X/*
  1731. X** get a specified format from the buffer
  1732. X**    Must allow for spaces and tabs so they
  1733. X**      need to be passed intact in the format.
  1734. X*/
  1735. Xchar *sav_format(s)
  1736. X    char *s;
  1737. X{
  1738. X    static char *cp;
  1739. X    char *dp;
  1740. X    
  1741. X    if ((cp = strchr(s,'"')) != NULL && 
  1742. X        (dp = strchr(++cp,'"')) != NULL) {
  1743. X        *dp = '\0';
  1744. X    }
  1745. X    else
  1746. X        cp = NULL;
  1747. X    return(cp);
  1748. X}
  1749. X
  1750. Xint get_patch_type(ngname,s)
  1751. Xchar *ngname;
  1752. Xchar *s;
  1753. X{
  1754. X    int return_type = default_type;
  1755. X
  1756. X    if (strcmp(s, "Package") == 0) 
  1757. X        return_type = PACKAGE;
  1758. X    else if (strcmp(s, "Historical") == 0) 
  1759. X        return_type = HISTORICAL;
  1760. X    else {
  1761. X        (void) fprintf(errfp,"%s: %s: %s %s\n", progname,
  1762. X                   ngname, "Invalid Patches Type:", s);
  1763. X        (void) fprintf(errfp,"\tPATCHES Must be %s, or %s\n",
  1764. X                   "Historical", "Package");
  1765. X        exit(1);
  1766. X    }
  1767. X    return(return_type);
  1768. X}
  1769. END_OF_FILE
  1770. if test 23815 -ne `wc -c <'rkive/setup.c'`; then
  1771.     echo shar: \"'rkive/setup.c'\" unpacked with wrong size!
  1772. fi
  1773. # end of 'rkive/setup.c'
  1774. fi
  1775. echo shar: End of archive 2 \(of 6\).
  1776. cp /dev/null ark2isdone
  1777. MISSING=""
  1778. for I in 1 2 3 4 5 6 ; do
  1779.     if test ! -f ark${I}isdone ; then
  1780.     MISSING="${MISSING} ${I}"
  1781.     fi
  1782. done
  1783. if test "${MISSING}" = "" ; then
  1784.     echo You have unpacked all 6 archives.
  1785.     rm -f ark[1-9]isdone
  1786. else
  1787.     echo You still need to unpack the following archives:
  1788.     echo "        " ${MISSING}
  1789. fi
  1790. ##  End of shell archive.
  1791. exit 0
  1792. exit 0 # Just in case...
  1793. -- 
  1794. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  1795. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  1796. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  1797. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  1798.