home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / N / TCPIP / NNTP-1.000 / NNTP-1 / nntp.1.5.11t / server / newnews.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-12-12  |  11.9 KB  |  557 lines

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