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:  * <1569@emory.UUCP>	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, <lai@shadow.berkeley.edu> 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: }

Defined functions

compare defined in line 242; used 2 times
distmatch defined in line 405; used 1 times
get_histlist defined in line 477; used 1 times
get_nglist defined in line 508; used 1 times
  • in line 42
getword defined in line 254; used 2 times
newnews defined in line 17; used 1 times
ngmatch defined in line 317; used 1 times
restreql defined in line 359; used 3 times
seekuntil defined in line 184; used 1 times

Defined variables

sccsid defined in line 2; never used
Last modified: 1986-03-21
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1438
Valid CSS Valid XHTML 1.0 Strict