|
|
1.1 ! root 1: /* $Header: bits.c,v 4.3 85/05/01 11:36:15 lwall Exp $ ! 2: * ! 3: * $Log: bits.c,v $ ! 4: * Revision 4.3 85/05/01 11:36:15 lwall ! 5: * Baseline for release with 4.3bsd. ! 6: * ! 7: */ ! 8: ! 9: #include "EXTERN.h" ! 10: #include "common.h" ! 11: #include "rcstuff.h" ! 12: #include "head.h" ! 13: #include "util.h" ! 14: #include "final.h" ! 15: #include "rn.h" ! 16: #include "cheat.h" ! 17: #include "ng.h" ! 18: #include "artio.h" ! 19: #include "intrp.h" ! 20: #include "ngdata.h" ! 21: #include "rcln.h" ! 22: #include "kfile.h" ! 23: #include "INTERN.h" ! 24: #include "bits.h" ! 25: ! 26: #ifdef DBM ! 27: # ifdef NULL ! 28: # undef NULL ! 29: # endif NULL ! 30: # include <dbm.h> ! 31: #endif DBM ! 32: MEM_SIZE ctlsize; /* size of bitmap in bytes */ ! 33: ! 34: void ! 35: bits_init() ! 36: { ! 37: #ifdef DELAYMARK ! 38: dmname = savestr(filexp(RNDELNAME)); ! 39: #else ! 40: ; ! 41: #endif ! 42: } ! 43: ! 44: /* checkpoint the .newsrc */ ! 45: ! 46: void ! 47: checkpoint_rc() ! 48: { ! 49: #ifdef DEBUGGING ! 50: if (debug & DEB_CHECKPOINTING) { ! 51: fputs("(ckpt)",stdout); ! 52: fflush(stdout); ! 53: } ! 54: #endif ! 55: if (doing_ng) ! 56: restore_ng(); /* do not restore M articles */ ! 57: if (rc_changed) ! 58: write_rc(); ! 59: #ifdef DEBUGGING ! 60: if (debug & DEB_CHECKPOINTING) { ! 61: fputs("(done)",stdout); ! 62: fflush(stdout); ! 63: } ! 64: #endif ! 65: } ! 66: ! 67: /* reconstruct the .newsrc line in a human readable form */ ! 68: ! 69: void ! 70: restore_ng() ! 71: { ! 72: register char *s, *mybuf = buf; ! 73: register ART_NUM i; ! 74: ART_NUM count=0; ! 75: int safelen = LBUFLEN - 16; ! 76: ! 77: strcpy(buf,rcline[ng]); /* start with the newsgroup name */ ! 78: s = buf + rcnums[ng] - 1; /* use s for buffer pointer */ ! 79: *s++ = rcchar[ng]; /* put the requisite : or !*/ ! 80: *s++ = ' '; /* put the not-so-requisite space */ ! 81: for (i=1; i<=lastart; i++) { /* for each article in newsgroup */ ! 82: if (s-mybuf > safelen) { /* running out of room? */ ! 83: safelen *= 2; ! 84: if (mybuf == buf) { /* currently static? */ ! 85: *s = '\0'; ! 86: mybuf = safemalloc((MEM_SIZE)safelen + 16); ! 87: strcpy(mybuf,buf); /* so we must copy it */ ! 88: s = mybuf + (s-buf); ! 89: /* fix the pointer, too */ ! 90: } ! 91: else { /* just grow in place, if possible */ ! 92: char *newbuf; ! 93: ! 94: newbuf = saferealloc(mybuf,(MEM_SIZE)safelen + 16); ! 95: s = newbuf + (s-mybuf); ! 96: mybuf = newbuf; ! 97: } ! 98: } ! 99: if (!was_read(i)) /* still unread? */ ! 100: count++; /* then count it */ ! 101: else { /* article was read */ ! 102: ART_NUM oldi; ! 103: ! 104: sprintf(s,"%ld",(long)i); /* put out the min of the range */ ! 105: s += strlen(s); /* keeping house */ ! 106: oldi = i; /* remember this spot */ ! 107: do i++; while (i <= lastart && was_read(i)); ! 108: /* find 1st unread article or end */ ! 109: i--; /* backup to last read article */ ! 110: if (i > oldi) { /* range of more than 1? */ ! 111: sprintf(s,"-%ld,",(long)i); ! 112: /* then it out as a range */ ! 113: s += strlen(s); /* and housekeep */ ! 114: } ! 115: else ! 116: *s++ = ','; /* otherwise, just a comma will do */ ! 117: } ! 118: } ! 119: if (*(s-1) == ',') /* is there a final ','? */ ! 120: s--; /* take it back */ ! 121: *s++ = '\0'; /* and terminate string */ ! 122: #ifdef DEBUGGING ! 123: if (debug & DEB_NEWSRC_LINE && !panic) { ! 124: printf("%s: %s\n",rcline[ng],rcline[ng]+rcnums[ng]) FLUSH; ! 125: printf("%s\n",mybuf) FLUSH; ! 126: } ! 127: #endif ! 128: free(rcline[ng]); /* return old rc line */ ! 129: if (mybuf == buf) { ! 130: rcline[ng] = safemalloc((MEM_SIZE)(s-buf)+1); ! 131: /* grab a new rc line */ ! 132: strcpy(rcline[ng], buf); /* and load it */ ! 133: } ! 134: else { ! 135: mybuf = saferealloc(mybuf,(MEM_SIZE)(s-mybuf)+1); ! 136: /* be nice to the heap */ ! 137: rcline[ng] = mybuf; ! 138: } ! 139: *(rcline[ng] + rcnums[ng] - 1) = '\0'; ! 140: if (rcchar[ng] == NEGCHAR) { /* did they unsubscribe? */ ! 141: printf(unsubto,ngname) FLUSH; ! 142: toread[ng] = TR_UNSUB; /* make line invisible */ ! 143: } ! 144: else ! 145: /*NOSTRICT*/ ! 146: toread[ng] = (ART_UNREAD)count; /* remember how many unread there are */ ! 147: } ! 148: ! 149: /* mark an article unread, keeping track of toread[] */ ! 150: ! 151: void ! 152: onemore(artnum) ! 153: ART_NUM artnum; ! 154: { ! 155: #ifdef DEBUGGING ! 156: if (debug && artnum < firstart) { ! 157: printf("onemore: %d < %d\n",artnum,firstart) FLUSH; ! 158: return; ! 159: } ! 160: #endif ! 161: if (ctl_read(artnum)) { ! 162: ctl_clear(artnum); ! 163: ++toread[ng]; ! 164: } ! 165: } ! 166: ! 167: /* mark an article read, keeping track of toread[] */ ! 168: ! 169: void ! 170: oneless(artnum) ! 171: ART_NUM artnum; ! 172: { ! 173: #ifdef DEBUGGING ! 174: if (debug && artnum < firstart) { ! 175: printf("oneless: %d < %d\n",artnum,firstart) FLUSH; ! 176: return; ! 177: } ! 178: #endif ! 179: if (!ctl_read(artnum)) { ! 180: ctl_set(artnum); ! 181: if (toread[ng] > TR_NONE) ! 182: --toread[ng]; ! 183: } ! 184: } ! 185: ! 186: /* mark an article as unread, making sure that firstart is properly handled */ ! 187: /* cross-references are left as read in the other newsgroups */ ! 188: ! 189: void ! 190: unmark_as_read(artnum) ! 191: ART_NUM artnum; ! 192: { ! 193: check_first(artnum); ! 194: onemore(artnum); ! 195: #ifdef MCHASE ! 196: if (!parse_maybe(artnum)) ! 197: chase_xrefs(artnum,FALSE); ! 198: #endif ! 199: } ! 200: ! 201: #ifdef DELAYMARK ! 202: /* temporarily mark article as read. When newsgroup is exited, articles */ ! 203: /* will be marked as unread. Called via M command */ ! 204: ! 205: void ! 206: delay_unmark(artnum) ! 207: ART_NUM artnum; ! 208: { ! 209: if (dmfp == Nullfp) { ! 210: dmfp = fopen(dmname,"w"); ! 211: if (dmfp == Nullfp) { ! 212: printf(cantcreate,dmname) FLUSH; ! 213: sig_catcher(0); ! 214: } ! 215: } ! 216: oneless(artnum); /* set the correct bit */ ! 217: dmcount++; ! 218: fprintf(dmfp,"%ld\n",(long)artnum); ! 219: } ! 220: #endif ! 221: ! 222: /* mark article as read. If article is cross referenced to other */ ! 223: /* newsgroups, mark them read there also. */ ! 224: ! 225: void ! 226: mark_as_read(artnum) ! 227: ART_NUM artnum; ! 228: { ! 229: oneless(artnum); /* set the correct bit */ ! 230: checkcount++; /* get more worried about crashes */ ! 231: chase_xrefs(artnum,TRUE); ! 232: } ! 233: ! 234: /* make sure we have bits set correctly down to firstart */ ! 235: ! 236: void ! 237: check_first(min) ! 238: ART_NUM min; ! 239: { ! 240: register ART_NUM i = firstart; ! 241: ! 242: if (min < absfirst) ! 243: min = absfirst; ! 244: if (min < i) { ! 245: for (i--; i>=min; i--) ! 246: ctl_set(i); /* mark as read */ ! 247: firstart = min; ! 248: } ! 249: } ! 250: ! 251: /* bring back articles marked with M */ ! 252: ! 253: #ifdef DELAYMARK ! 254: void ! 255: yankback() ! 256: { ! 257: register ART_NUM anum; ! 258: ! 259: if (dmfp) { /* delayed unmarks pending? */ ! 260: #ifdef VERBOSE ! 261: printf("\nReturning %ld Marked article%s...\n",(long)dmcount, ! 262: dmcount == 1 ? nullstr : "s") FLUSH; ! 263: #endif ! 264: fclose(dmfp); ! 265: if (dmfp = fopen(dmname,"r")) { ! 266: while (fgets(buf,sizeof buf,dmfp) != Nullch) { ! 267: anum = (ART_NUM)atol(buf); ! 268: /*NOSTRICT*/ ! 269: onemore(anum); /* then unmark them */ ! 270: #ifdef MCHASE ! 271: chase_xrefs(anum,FALSE); ! 272: #endif ! 273: } ! 274: fclose(dmfp); ! 275: dmfp = Nullfp; ! 276: UNLINK(dmname); /* and be tidy */ ! 277: } ! 278: else { ! 279: printf(cantopen,dmname) FLUSH; ! 280: sig_catcher(0); ! 281: } ! 282: } ! 283: dmcount = 0; ! 284: } ! 285: #endif ! 286: ! 287: /* run down xref list and mark as read or unread */ ! 288: ! 289: int ! 290: chase_xrefs(artnum,markread) ! 291: ART_NUM artnum; ! 292: int markread; ! 293: { ! 294: #ifdef ASYNC_PARSE ! 295: if (parse_maybe(artnum)) /* make sure we have right header */ ! 296: return -1; ! 297: #endif ! 298: #ifdef DBM ! 299: { ! 300: datum lhs, rhs; ! 301: datum fetch(); ! 302: register char *idp; ! 303: char *ident_buf; ! 304: static FILE * hist_file = Nullfp; ! 305: #else ! 306: if ( ! 307: #ifdef DEBUGGING ! 308: debug & DEB_FEED_XREF || ! 309: #endif ! 310: htype[XREF_LINE].ht_minpos >= 0) { ! 311: /* are there article# xrefs? */ ! 312: #endif DBM ! 313: char *xref_buf, *curxref; ! 314: register char *xartnum; ! 315: char *rver_buf = Nullch; ! 316: static char *inews_site = Nullch; ! 317: register ART_NUM x; ! 318: char tmpbuf[128]; ! 319: ! 320: #ifdef DBM ! 321: rver_buf = fetchlines(artnum,NGS_LINE); ! 322: /* get Newsgroups */ ! 323: if (!index(rver_buf,',')) /* if no comma, no Xref! */ ! 324: return 0; ! 325: if (hist_file == Nullfp) { /* Init. file accesses */ ! 326: #ifdef DEBUGGING ! 327: if (debug) ! 328: printf ("chase_xref: opening files\n"); ! 329: #endif ! 330: dbminit(filexp(ARTFILE)); ! 331: if ((hist_file = fopen (filexp(ARTFILE), "r")) == Nullfp) ! 332: return 0; ! 333: } ! 334: xref_buf = safemalloc((MEM_SIZE)BUFSIZ); ! 335: ident_buf = fetchlines(artnum,MESSID_LINE); ! 336: /* get Message-ID */ ! 337: #ifdef DEBUGGING ! 338: if (debug) ! 339: printf ("chase_xref: Message-ID: %s\n", ident_buf); ! 340: #endif ! 341: idp = ident_buf; ! 342: while (*++idp) /* make message-id case insensitive */ ! 343: if (isupper(*idp)) ! 344: *idp = tolower (*idp); ! 345: lhs.dptr = ident_buf; /* look up article by id */ ! 346: lhs.dsize = strlen(lhs.dptr) + 1; ! 347: rhs = fetch(lhs); /* fetch the record */ ! 348: if (rhs.dptr == NULL) /* if null, nothing there */ ! 349: goto wild_goose; ! 350: fseek (hist_file, *((long *)rhs.dptr), 0); ! 351: /* datum returned is position in hist file */ ! 352: fgets (xref_buf, BUFSIZ, hist_file); ! 353: #ifdef DEBUGGING ! 354: if (debug) ! 355: printf ("Xref from history: %s\n", xref_buf); ! 356: #endif ! 357: curxref = cpytill(tmpbuf, xref_buf, '\t') + 1; ! 358: curxref = cpytill(tmpbuf, curxref, '\t') + 1; ! 359: #ifdef DEBUGGING ! 360: if (debug) ! 361: printf ("chase_xref: curxref: %s\n", curxref); ! 362: #endif ! 363: #else !DBM ! 364: #ifdef DEBUGGING ! 365: if (htype[XREF_LINE].ht_minpos >= 0) ! 366: #endif ! 367: xref_buf = fetchlines(artnum,XREF_LINE); ! 368: /* get xrefs list */ ! 369: #ifdef DEBUGGING ! 370: else { ! 371: xref_buf = safemalloc((MEM_SIZE)100); ! 372: printf("Give Xref: ") FLUSH; ! 373: gets(xref_buf); ! 374: } ! 375: #endif ! 376: #ifdef DEBUGGING ! 377: if (debug & DEB_XREF_MARKER) ! 378: printf("Xref: %s\n",xref_buf) FLUSH; ! 379: #endif ! 380: curxref = cpytill(tmpbuf,xref_buf,' ') + 1; ! 381: ! 382: /* Make sure site name on Xref matches what inews thinks site is. ! 383: * Check first against last inews_site. If it matches, fine. ! 384: * If not, fetch inews_site from current Relay-Version line and ! 385: * check again. This is so that if the new administrator decides ! 386: * to change the system name as known to inews, rn will still do ! 387: * Xrefs correctly--each article need only match itself to be valid. ! 388: */ ! 389: if (inews_site == Nullch || strNE(tmpbuf,inews_site)) { ! 390: char *t; ! 391: ! 392: if (inews_site != Nullch) ! 393: free(inews_site); ! 394: #ifndef NORELAY ! 395: rver_buf = fetchlines(artnum,RVER_LINE); ! 396: if ((t = instr(rver_buf,"; site ")) == Nullch) ! 397: #else NORELAY ! 398: ! 399: /* In version 2.10.3 of news or afterwards, the Relay-Version ! 400: * and Posting-Version header lines have been removed. For ! 401: * the code below to work as intended, I have modified it to ! 402: * extract the first component of the Path header line. This ! 403: * should give the same effect as did the old code with respect ! 404: * to the use of the Relay-Version site name. ! 405: */ ! 406: rver_buf = fetchlines(artnum,PATH_LINE); ! 407: if ((t = instr(rver_buf,"!")) == Nullch) ! 408: #endif NORELAY ! 409: inews_site = savestr(nullstr); ! 410: else { ! 411: char new_site[128]; ! 412: ! 413: #ifndef NORELAY ! 414: cpytill(new_site,t + 7,'.'); ! 415: #else NORELAY ! 416: cpytill(new_site,rver_buf,'!'); ! 417: #endif NORELAY ! 418: inews_site = savestr(new_site); ! 419: } ! 420: if (strNE(tmpbuf,inews_site)) { ! 421: #ifdef DEBUGGING ! 422: if (debug) ! 423: printf("Xref not from %s--ignoring\n",inews_site) FLUSH; ! 424: #endif ! 425: goto wild_goose; ! 426: } ! 427: } ! 428: #endif DBM ! 429: while (*curxref) { ! 430: /* for each newsgroup */ ! 431: curxref = cpytill(tmpbuf,curxref,' '); ! 432: #ifdef DBM ! 433: xartnum = index(tmpbuf,'/'); ! 434: #else ! 435: xartnum = index(tmpbuf,':'); ! 436: #endif DBM ! 437: if (!xartnum) /* probably an old-style Xref */ ! 438: break; ! 439: *xartnum++ = '\0'; ! 440: if (strNE(tmpbuf,ngname)) {/* not the current newsgroup? */ ! 441: x = atol(xartnum); ! 442: if (x) ! 443: if (markread) { ! 444: if (addartnum(x,tmpbuf)) ! 445: goto wild_goose; ! 446: } ! 447: #ifdef MCHASE ! 448: else ! 449: subartnum(x,tmpbuf); ! 450: #endif ! 451: } ! 452: while (*curxref && isspace(*curxref)) ! 453: curxref++; ! 454: } ! 455: wild_goose: ! 456: free(xref_buf); ! 457: #ifdef DBM ! 458: free(ident_buf); ! 459: #endif DBM ! 460: if (rver_buf != Nullch) ! 461: free(rver_buf); ! 462: } ! 463: return 0; ! 464: } ! 465: ! 466: int ! 467: initctl() ! 468: { ! 469: char *mybuf = buf; /* place to decode rc line */ ! 470: register char *s, *c, *h; ! 471: register long i; ! 472: register ART_NUM unread; ! 473: ! 474: #ifdef DELAYMARK ! 475: dmcount = 0; ! 476: #endif ! 477: if ((lastart = getngsize(ng)) < 0) /* this cannot happen (laugh here) */ ! 478: return -1; ! 479: ! 480: absfirst = getabsfirst(ng,lastart); /* remember first existing article */ ! 481: if (!absfirst) /* no articles at all? */ ! 482: absfirst = 1; /* pretend there is one */ ! 483: #ifndef lint ! 484: ctlsize = (MEM_SIZE)(OFFSET(lastart)/BITSPERBYTE+20); ! 485: #endif lint ! 486: ctlarea = safemalloc(ctlsize); /* allocate control area */ ! 487: ! 488: /* now modify ctlarea to reflect what has already been read */ ! 489: ! 490: for (s = rcline[ng] + rcnums[ng]; *s == ' '; s++) ; ! 491: /* find numbers in rc line */ ! 492: i = strlen(s); ! 493: #ifndef lint ! 494: if (i >= LBUFLEN-2) /* bigger than buf? */ ! 495: mybuf = safemalloc((MEM_SIZE)(i+2)); ! 496: #endif lint ! 497: strcpy(mybuf,s); /* make scratch copy of line */ ! 498: mybuf[i++] = ','; /* put extra comma on the end */ ! 499: mybuf[i] = '\0'; ! 500: s = mybuf; /* initialize the for loop below */ ! 501: if (strnEQ(s,"1-",2)) { /* can we save some time here? */ ! 502: firstart = atol(s+2)+1; /* ignore first range thusly */ ! 503: s=index(s,',') + 1; ! 504: } ! 505: else ! 506: firstart = 1; /* all the bits are valid for now */ ! 507: if (absfirst > firstart) { /* do we know already? */ ! 508: firstart = absfirst; /* no point calling getngmin again */ ! 509: } ! 510: else if (artopen(firstart) == Nullfp) { ! 511: /* first unread article missing? */ ! 512: i = getngmin(".",firstart); /* see if expire has been busy */ ! 513: if (i) { /* avoid a bunch of extra opens */ ! 514: firstart = i; ! 515: } ! 516: } ! 517: #ifdef PENDING ! 518: # ifdef CACHESUBJ ! 519: subj_to_get = firstart; ! 520: # endif ! 521: #endif ! 522: unread = lastart - firstart + 1; /* assume this range unread */ ! 523: for (i=OFFSET(firstart)/BITSPERBYTE; i<ctlsize; i++) ! 524: ctlarea[i] = 0; /* assume unread */ ! 525: #ifdef DEBUGGING ! 526: if (debug & DEB_CTLAREA_BITMAP) { ! 527: printf("\n%s\n",mybuf) FLUSH; ! 528: for (i=1; i <= lastart; i++) ! 529: if (! was_read(i)) ! 530: printf("%ld ",(long)i) FLUSH; ! 531: } ! 532: #endif ! 533: for ( ; (c = index(s,',')) != Nullch; s = ++c) { ! 534: /* for each range */ ! 535: ART_NUM min, max; ! 536: ! 537: *c = '\0'; /* do not let index see past comma */ ! 538: if ((h = index(s,'-')) != Nullch) { /* is there a -? */ ! 539: min = atol(s); ! 540: max = atol(h+1); ! 541: if (min < firstart) /* make sure range is in range */ ! 542: min = firstart; ! 543: if (max > lastart) ! 544: max = lastart; ! 545: if (min <= max) /* non-null range? */ ! 546: unread -= max - min + 1;/* adjust unread count */ ! 547: for (i=min; i<=max; i++) /* for all articles in range */ ! 548: ctl_set(i); /* mark them read */ ! 549: } ! 550: else if ((i = atol(s)) >= firstart && i <= lastart) { ! 551: /* is single number reasonable? */ ! 552: ctl_set(i); /* mark it read */ ! 553: unread--; /* decrement articles to read */ ! 554: } ! 555: #ifdef DEBUGGING ! 556: if (debug & DEB_CTLAREA_BITMAP) { ! 557: printf("\n%s\n",s) FLUSH; ! 558: for (i=1; i <= lastart; i++) ! 559: if (! was_read(i)) ! 560: printf("%ld ",(long)i) FLUSH; ! 561: } ! 562: #endif ! 563: } ! 564: #ifdef DEBUGGING ! 565: if (debug & DEB_CTLAREA_BITMAP) { ! 566: fputs("\n(hit CR)",stdout) FLUSH; ! 567: gets(cmd_buf); ! 568: } ! 569: #endif ! 570: if (mybuf != buf) ! 571: free(mybuf); ! 572: toread[ng] = unread; ! 573: return 0; ! 574: } ! 575: ! 576: void ! 577: grow_ctl() ! 578: { ! 579: ART_NUM newlast; ! 580: ART_NUM tmpfirst; ! 581: MEM_SIZE newsize; ! 582: register ART_NUM i; ! 583: ! 584: forcegrow = FALSE; ! 585: newlast = getngsize(ng); ! 586: if (newlast > lastart) { ! 587: ART_NUM tmpart = art; ! 588: #ifndef lint ! 589: newsize = (MEM_SIZE)(OFFSET(newlast)/BITSPERBYTE+2); ! 590: #else ! 591: newsize = Null(MEM_SIZE); ! 592: #endif lint ! 593: if (newsize > ctlsize) { ! 594: newsize += 20; ! 595: ctlarea = saferealloc(ctlarea,newsize); ! 596: ctlsize = newsize; ! 597: } ! 598: toread[ng] += (ART_UNREAD)(newlast-lastart); ! 599: for (i=lastart+1; i<=newlast; i++) ! 600: ctl_clear(i); /* these articles are unread */ ! 601: #ifdef CACHESUBJ ! 602: if (subj_list != Null(char**)) { ! 603: #ifndef lint ! 604: subj_list = (char**)saferealloc((char*)subj_list, ! 605: (MEM_SIZE)((OFFSET(newlast)+2)*sizeof(char *)) ); ! 606: #endif lint ! 607: for (i=lastart+1; i<=newlast; i++) ! 608: subj_list[OFFSET(i)] = Nullch; ! 609: } ! 610: #endif ! 611: tmpfirst = lastart+1; ! 612: lastart = newlast; ! 613: #ifdef KILLFILES ! 614: #ifdef VERBOSE ! 615: IF(verbose) ! 616: sprintf(buf, ! 617: "%ld more article%s arrived--looking for more to kill...\n\n", ! 618: (long)(lastart - firstart + 1), ! 619: (lastart > firstart ? "s have" : " has" ) ); ! 620: ELSE /* my, my, how clever we are */ ! 621: #endif ! 622: #ifdef TERSE ! 623: strcpy(buf, "More news--killing...\n\n"); ! 624: #endif ! 625: kill_unwanted(tmpfirst,buf,TRUE); ! 626: #endif ! 627: art = tmpart; ! 628: } ! 629: } ! 630:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.