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