home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_disks / 300-399 / ff319.lzh / CNewsSrc / cnews.orig.lzh / nntpdiffs / src / newnews.c < prev    next >
C/C++ Source or Header  |  1989-06-27  |  11KB  |  515 lines

  1. #ifndef lint
  2. static char    *sccsid = "@(#)newnews.c    1.19    (Berkeley) 2/6/88";
  3. #endif
  4.  
  5. #include "common.h"
  6. #include "time.h"
  7.  
  8. #ifdef LOG
  9. int    nn_told = 0;
  10. int    nn_took = 0;
  11. #endif
  12.  
  13.  
  14. /*
  15.  * NEWNEWS newsgroups date time ["GMT"] [<distributions>]
  16.  *
  17.  * Return the message-id's of any news articles past
  18.  * a certain date and time, within the specified distributions.
  19.  *
  20.  */
  21.  
  22. newnews(argc, argv)
  23.     register int    argc;
  24.     char        *argv[];
  25. {
  26.     register char    *cp, *ngp;
  27.     char        *key;
  28.     char        datebuf[32];
  29.     char        line[MAXBUFLEN];
  30.     char        **distlist, **histlist;
  31.     static char    **nglist;
  32.     int        distcount, ngcount, histcount;
  33.     int        all;
  34.     FILE        *fp;
  35.     long        date;
  36.     long        dtol();
  37.     char        *ltod();
  38. #ifdef USG
  39.     FILE        *tmplst;
  40.     int        i;
  41.     char        *tmpfile;
  42. #endif USG
  43.  
  44.     if (argc < 4) {
  45.         printf("%d Usage: NEWNEWS newsgroups yymmdd hhmmss [\"GMT\"] [<distributions>
  46. .\r\n",
  47.             ERR_CMDSYN);
  48.         (void) fflush(stdout);
  49.         return;
  50.     }
  51.  
  52. #ifdef LOG
  53.     sprintf(line, "%s newnews %s %s %s %s %s",
  54.         hostname,
  55.         argv[1],
  56.         argv[2],
  57.         argv[3],
  58.         (argc >= 5 && *argv[4] == 'G') ? "GMT" : "local",
  59.         (argc >= 5 && *argv[argc-1] == '<') ? argv[argc-1] : "none");
  60.     syslog(LOG_INFO, line);
  61. #endif
  62.  
  63.     all = (argv[1][0] == '*' && argv[1][1] == '\0');
  64.     if (!all) {
  65.         ngcount = get_nglist(&nglist, argv[1]);
  66.         if (ngcount == 0) {
  67.             printf("%d Bogus newsgroup specifier: %s\r\n",
  68.                 ERR_CMDSYN, argv[1]);
  69.             (void) fflush(stdout);
  70.             return;
  71.         }
  72.     }
  73.  
  74.     /*        YYMMDD            HHMMSS    */
  75.     if (strlen(argv[2]) != 6 || strlen(argv[3]) != 6) {
  76.         printf("%d Date/time must be in form YYMMDD HHMMSS.\r\n",
  77.             ERR_CMDSYN);
  78.         (void) fflush(stdout);
  79.         return;
  80.     }
  81.  
  82.     (void) strcpy(datebuf, argv[2]);
  83.     (void) strcat(datebuf, argv[3]);
  84.  
  85.     argc -= 4;
  86.     argv += 4;
  87.  
  88.     /*
  89.      * Flame on.  The history file is not stored in GMT, but
  90.      * in local time.  So we have to convert GMT to local time
  91.      * if we're given GMT, otherwise we need only chop off the
  92.      * the seconds.  Such braindamage.
  93.      */
  94.  
  95.     key = datebuf;        /* Unless they specify GMT */
  96.  
  97.     if (argc > 0) {
  98.         if (!strcasecmp(*argv, "GMT")) { /* Which we handle here */
  99.             date = dtol(datebuf);
  100.             if (date < 0) {
  101.                 printf("%d Invalid date specification.\r\n",
  102.                     ERR_CMDSYN);
  103.                 (void) fflush(stdout);
  104.                 return;
  105.             }
  106.             date = gmt_to_local(date);
  107.             key = ltod(date);
  108.             ++argv;
  109.             --argc;
  110.         }
  111.     }
  112.  
  113.     /* So, key now points to the local time, but we need to zap secs */
  114.  
  115.     key[10] = '\0';
  116.  
  117.     distcount = 0;
  118.     if (argc > 0) {
  119.         distcount = get_distlist(&distlist, *argv);
  120.         if (distcount < 0) {
  121.             printf("%d Bad distribution list: %s\r\n", ERR_CMDSYN,
  122.                 *argv);
  123.             (void) fflush(stdout);
  124.             return;
  125.         }
  126.     }
  127.  
  128. #ifdef USG
  129.     if ((tmpfile = mktemp("/tmp/listXXXXXX")) == NULL ||
  130.         (tmplst = fopen(tmpfile, "w+")) == NULL) {
  131.     printf("%d Cannot process history file.\r\n", ERR_FAULT);
  132.     (void) fflush(stdout);
  133.     return;
  134.     }
  135.  
  136.     for (i = 0; i < 9; i++) {
  137.         sprintf(historyfile, "%s.d/%d", HISTORY_FILE, i);
  138. #endif USG
  139.  
  140.     fp = fopen(historyfile, "r");
  141.     if (fp == NULL) {
  142. #ifdef SYSLOG
  143.         syslog(LOG_ERR, "newnews: fopen %s: %m", historyfile);
  144. #endif
  145. #ifndef USG
  146.         printf("%d Cannot open history file.\r\n", ERR_FAULT);
  147.         (void) fflush(stdout);
  148.         return;
  149. #else USG
  150.         continue;
  151. #endif USG
  152.     }
  153.  
  154. #ifndef USG
  155.     printf("%d New news by message id follows.\r\n", OK_NEWNEWS);
  156. #endif not USG
  157.  
  158.     if (seekuntil(fp, key, line, sizeof (line)) < 0) {
  159. #ifndef USG
  160.         printf(".\r\n");
  161.         (void) fflush(stdout);
  162. #endif not USG
  163.         (void) fclose(fp);
  164. #ifndef USG
  165.         return;
  166. #else USG
  167.         continue;
  168. #endif USG
  169.     }
  170.  
  171. /*
  172.  * History file looks like:
  173.  *
  174.  * <1569@emory.UUCP>    01/22/86 09:19    net.micro.att/899 ucb.general/2545 
  175.  *             ^--tab            ^--tab         ^--space         ^sp\0
  176.  * Sometimes the newsgroups are missing; we try to be robust and
  177.  * ignore such bogosity.  We tackle this by our usual parse routine,
  178.  * and break the list of articles in the history file into an argv
  179.  * array with one newsgroup per entry.
  180.  */
  181.  
  182.     do {
  183.         if ((cp = index(line, '\t')) == NULL)
  184.             continue;
  185.  
  186.         if ((ngp = index(cp+1, '\t')) == NULL)    /* 2nd tab */
  187.             continue;
  188.         ++ngp;            /* Points at newsgroup list */
  189.         if (*ngp == '\n')
  190.             continue;
  191.         histcount = get_histlist(&histlist, ngp);
  192.         if (histcount == 0)
  193.             continue;
  194.  
  195.         /*
  196.          * For each newsgroup on this line in the history
  197.          * file, check it against the newsgroup names we're given.
  198.          * If it matches, then see if we're hacking distributions.
  199.          * If so, open the file and match the distribution line.
  200.          */
  201.  
  202.         if (!all)
  203.             if (!ngmatch(restreql, 0, nglist, ngcount,
  204.                 histlist, histcount))
  205.                 continue;
  206.  
  207.         if (distcount)
  208.             if (!distmatch(distlist, distcount, histlist, histcount))
  209.                 continue;
  210.  
  211.         *cp = '\0';
  212. #ifdef USG
  213.         fputs(line, tmplst);
  214.         fputc('\n', tmplst);
  215. #else not USG
  216.         putline(line);
  217. #endif not USG
  218. #ifdef LOG
  219.         nn_told++;
  220. #endif
  221.     } while (fgets(line, sizeof(line), fp) != NULL);
  222.  
  223. #ifndef USG
  224.     putchar('.');
  225.     putchar('\r');
  226.     putchar('\n');
  227.     (void) fflush(stdout);
  228. #endif
  229.     (void) fclose(fp);
  230. #ifdef USG
  231.     }
  232.     printf("%d New news by message id follows.\r\n", OK_NEWNEWS);
  233.     rewind(tmplst);
  234.     while (fgets(line, sizeof(line), tmplst) != NULL)
  235.             putline(line);
  236.     putchar('.');
  237.     putchar('\r');
  238.     putchar('\n');
  239.     (void) fflush(stdout);
  240.     (void) fclose(tmplst);
  241.     (void) unlink(tmpfile);
  242. #endif USG
  243. }
  244.  
  245.  
  246. /*
  247.  * seekuntil -- seek through the history file looking for
  248.  * a line with date "key".  Get that line, and return.
  249.  *
  250.  *    Parameters:    "fp" is the active file.
  251.  *            "key" is the date, in form YYMMDDHHMM (no SS)
  252.  *            "line" is storage for the first line we find.
  253.  *
  254.  *    Returns:    -1 on error, 0 otherwise.
  255.  *
  256.  *    Side effects:    Seeks in history file, modifies line.
  257.  */
  258.  
  259. seekuntil(fp, akey, line, linesize)
  260.     FILE        *fp;
  261.     char        *akey;
  262.     char        *line;
  263.     int        linesize;
  264. {
  265.     char        datetime[32];
  266.     register int    c;
  267.     register long    top, bot, mid;
  268.     extern long dtol();
  269.     char key[30];
  270.  
  271.     (void) sprintf(key, "%ld", dtol(akey));    /* akey -> time_t in ascii */
  272.     bot = 0;
  273.     (void) fseek(fp, 0L, 2);
  274.     top = ftell(fp);
  275.     for(;;) {
  276.         mid = (top+bot)/2;
  277.         (void) fseek(fp, mid, 0);
  278.         do {
  279.             c = getc(fp);
  280.             mid++;
  281.         } while (c != EOF && c!='\n');
  282.         if (!getword(fp, datetime, line, linesize)) {
  283.             return (-1);
  284.         }
  285.         switch (compare(key, datetime)) {
  286.         case -2:
  287.         case -1:
  288.         case 0:
  289.             if (top <= mid)
  290.                 break;
  291.             top = mid;
  292.             continue;
  293.         case 1:
  294.         case 2:
  295.             bot = mid;
  296.             continue;
  297.         }
  298.         break;
  299.     }
  300.     (void) fseek(fp, bot, 0);
  301.     while(ftell(fp) < top) {
  302.         if (!getword(fp, datetime, line, linesize)) {
  303.             return (-1);
  304.         }
  305.         switch(compare(key, datetime)) {
  306.         case -2:
  307.         case -1:
  308.         case 0:
  309.             break;
  310.         case 1:
  311.         case 2:
  312.             continue;
  313.         }
  314.         break;
  315.     }
  316.  
  317.     return (0);
  318. }
  319.  
  320.  
  321. compare(s, t)
  322.     register char *s, *t;
  323. {
  324.     for (; *s == *t; s++, t++)
  325.         if (*s == 0)
  326.             return(0);
  327.     return (*s == 0 ? -1:
  328.         *t == 0 ? 1:
  329.         *s < *t ? -2:
  330.         2);
  331. }
  332.  
  333.  
  334. /*
  335.  * C news version of getword.
  336.  */
  337. getword(fp, w, line, linesize)
  338.     FILE        *fp;
  339.     register char    *w;
  340.     char        *line;
  341.     int        linesize;
  342. {
  343.     register char    *cp;
  344.     extern char *index();
  345.  
  346.     if (fgets(line, linesize, fp) == NULL)
  347.         return (0);
  348.     w[0] = '\0';                /* in case of bad format */
  349.     if (cp = index(line, '\t')) {        /* find 2nd field */
  350.         register char *endp;
  351.  
  352.         *cp++ = '\0';
  353.         endp = index(cp, '~');        /* end of date-received */
  354.         if (endp == NULL)
  355.             endp = index(cp, '\t');    /* end of expiry */
  356.         if (endp != NULL) {
  357.             (void) strncpy(w, cp, endp - cp);
  358.             w[endp - cp] = '\0';
  359.         }
  360.     }
  361.     return (1);
  362. }
  363.  
  364.  
  365. /*
  366.  * distmatch -- see if a file matches a set of distributions.
  367.  * We have to do this by (yech!) opening the file, finding
  368.  * the Distribution: line, if it has one, and seeing if the
  369.  * things match.
  370.  *
  371.  *    Parameters:    "distlist" is the distribution list
  372.  *            we want.
  373.  *            "distcount" is the count of distributions in it.
  374.  *            "grouplist" is the list of groups (articles)
  375.  *            for this line of the history file.  Note that
  376.  *            this isn't quite a filename.
  377.  *            "groupcount" is the count of groups in it.
  378.  *            
  379.  *    Returns:    1 if the article is in the given distribution.
  380.  *            0 otherwise.
  381.  */
  382.  
  383. distmatch(distlist, distcount, grouplist, groupcount)
  384.     char        *distlist[];
  385.     int        distcount;
  386.     char        *grouplist[];
  387.     int        groupcount;
  388. {
  389.     register char    c;
  390.     register char    *cp;
  391.     register FILE    *fp;
  392.     register int    i, j;
  393.     char        buf[MAXBUFLEN];
  394.  
  395.     (void) strcpy(buf, spooldir);
  396.     (void) strcat(buf, "/");
  397.     (void) strcat(buf, grouplist[0]);
  398.  
  399.     for (cp = buf; *cp; cp++)
  400.         if (*cp == '.')
  401.             *cp = '/';
  402.  
  403.     fp = fopen(buf, "r");
  404.     if (fp == NULL) {
  405. #ifdef SYSLOG
  406.         syslog(LOG_ERR, "distmatch: fopen %s: %m", buf);
  407. #endif
  408.         return (0);
  409.     }
  410.  
  411.     while (fgets(buf, sizeof (buf), fp) != NULL) {
  412.         if ((c = buf[0]) == '\n')        /* End of header */
  413.             break;
  414.         if (c != 'd' && c != 'D')
  415.             continue;
  416.         cp = index(cp + 1, '\n');
  417.         if (cp)
  418.             *cp = '\0';
  419.         cp = index(buf, ':');
  420.         if (cp == NULL)
  421.             continue;
  422.         *cp = '\0';
  423.         if (!strcasecmp(buf, "distribution")) {
  424.             for (i = 0; i < distcount; ++i) {
  425.                 if (!strcasecmp(cp + 2, distlist[i])) {
  426.                     (void) fclose(fp);
  427.                     return (1);
  428.                 }
  429.             }
  430.             (void) fclose(fp);
  431.             return (0);
  432.         }
  433.     }
  434.  
  435.     (void) fclose(fp);
  436.  
  437.     /*
  438.      * We've finished the header with no distribution field.
  439.      * So we'll assume that the distribution is the characters
  440.      * up to the first dot in the newsgroup name.
  441.      */
  442.  
  443.     for (i = 0; i < groupcount; i++) {
  444.         cp = index(grouplist[i], '.');
  445.         if (cp)
  446.             *cp = '\0';
  447.         for (j = 0; j < distcount; j++)
  448.             if (!strcasecmp(grouplist[i], distlist[j]))
  449.                 return (1);
  450.     }
  451.         
  452.     return (0);
  453. }
  454.  
  455.  
  456. /*
  457.  * get_histlist -- return a nicely set up array of newsgroups
  458.  * (actually, net.foo.bar/article_num) along with a count.
  459.  *
  460.  *    Parameters:        "array" is storage for our array,
  461.  *                set to point at some static data.
  462.  *                "list" is the history file newsgroup list.
  463.  *
  464.  *    Returns:        Number of group specs found.
  465.  *
  466.  *    Side effects:        Changes static data area.
  467.  */
  468.  
  469. get_histlist(array, list)
  470.     char        ***array;
  471.     char        *list;
  472. {
  473.     register int    histcount;
  474.     register char    *cp;
  475.     static    char    **hist_list = (char **) NULL;
  476.  
  477.     cp = index(list, '\n');
  478.     if (cp)
  479.         *cp-- = '\0';
  480.     histcount = parsit(list, &hist_list);
  481.     *array = hist_list;
  482.     return (histcount);
  483. }
  484.  
  485.  
  486. /*
  487.  * get_nglist -- return a nicely set up array of newsgroups
  488.  * along with a count, when given an NNTP-spec newsgroup list
  489.  * in the form ng1,ng2,ng...
  490.  *
  491.  *    Parameters:        "array" is storage for our array,
  492.  *                set to point at some static data.
  493.  *                "list" is the NNTP newsgroup list.
  494.  *
  495.  *    Returns:        Number of group specs found.
  496.  *
  497.  *    Side effects:        Changes static data area.
  498.  */
  499.  
  500. get_nglist(array, list)
  501.     char        ***array;
  502.     char        *list;
  503. {
  504.     register char    *cp;
  505.     register int    ngcount;
  506.  
  507.     for (cp = list; *cp != '\0'; ++cp)
  508.         if (*cp == ',')
  509.             *cp = ' ';
  510.  
  511.     ngcount = parsit(list, array);
  512.  
  513.     return (ngcount);
  514. }
  515.