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