|
|
1.1 ! root 1: /* ! 2: * header.c - header functions plus some other goodies ! 3: */ ! 4: ! 5: static char *SccsId = "@(#)header.c 2.20 6/24/83"; ! 6: ! 7: #include <stdio.h> ! 8: #include <sys/types.h> ! 9: #include "defs.h" ! 10: #include "header.h" ! 11: ! 12: extern char bfr[], FULLSYSNAME[], SYSNAME[], *index(); ! 13: extern time_t defexp; ! 14: ! 15: char *hfgets(); ! 16: ! 17: static int seenrelay; ! 18: ! 19: /* ! 20: * Read header from file fp into *hp. If wholething is FALSE, ! 21: * it's an incremental read, otherwise start from scratch. ! 22: * Return (FILE *) if header okay, else NULL. ! 23: */ ! 24: FILE * ! 25: hread(hp, fp, wholething) ! 26: register struct hbuf *hp; ! 27: FILE *fp; ! 28: int wholething; ! 29: { ! 30: register int len; ! 31: ! 32: if (wholething) ! 33: bclear((char *) hp, sizeof (*hp)); ! 34: ! 35: seenrelay = 0; ! 36: ! 37: /* Check that it's a B news style header. */ ! 38: if (((hfgets(bfr, PATHLEN, fp) != NULL && ! 39: *bfr >= 'A' && *bfr <= 'Z') && index(bfr, ':'))) ! 40: if (frmread(fp, hp)) ! 41: goto strip; ! 42: ! 43: /* It's not. Try A news (begins with PROTO). */ ! 44: if (*bfr != PROTO) ! 45: return(NULL); ! 46: ! 47: /* Read in an A news format article. */ ! 48: strncpy(hp->oident, &(bfr[1]), NAMELEN); /* file name */ ! 49: if (!nstrip(hp->oident)) ! 50: return(NULL); ! 51: hfgets(hp->nbuf, BUFLEN, fp); /* newsgroup list */ ! 52: if (!nstrip(hp->nbuf)) ! 53: return(NULL); ! 54: ngcat(hp->nbuf); ! 55: hfgets(hp->path, PATHLEN, fp); /* source path */ ! 56: if (!nstrip(hp->path)) ! 57: return(NULL); ! 58: hfgets(hp->subdate, DATELEN, fp); /* date */ ! 59: if (!nstrip(hp->subdate)) ! 60: return(NULL); ! 61: hfgets(hp->title, BUFLEN, fp); /* title */ ! 62: if (!nstrip(hp->title)) ! 63: return(NULL); ! 64: ! 65: strip: /* strip off sys! from front of path. */ ! 66: strcpy(bfr, FULLSYSNAME); ! 67: if (strncmp(bfr, hp->path, (len = strlen(bfr))) == 0 ! 68: && index(NETCHRS, hp->path[len])) ! 69: strcpy(hp->path, &(hp->path[len+1])); ! 70: lcase(hp->nbuf); ! 71: ! 72: /* Intuit the From: line if only a path was given. */ ! 73: if (wholething && hp->from[0] == '\0') ! 74: intuitfrom(hp); ! 75: ! 76: /* Get old and new style message ID's. */ ! 77: if (wholething) ! 78: fixid(hp); ! 79: ! 80: return(fp); ! 81: } ! 82: ! 83: ! 84: /* ! 85: * Get header info from mail-format file. ! 86: * Return non-zero on success. ! 87: */ ! 88: #include <ctype.h> ! 89: #define FROM 1 ! 90: #define NEWSGROUP 2 ! 91: #define TITLE 3 ! 92: #define SUBMIT 4 ! 93: #define RECEIVE 5 ! 94: #define EXPIRE 6 ! 95: #define ARTICLEID 7 ! 96: #define MESSAGEID 8 ! 97: #define REPLYTO 9 ! 98: #define FOLLOWID 10 ! 99: #define CONTROL 11 ! 100: #define SENDER 12 ! 101: #define FOLLOWTO 13 ! 102: #define PATH 14 ! 103: #define POSTVERSION 15 ! 104: #define RELAYVERSION 16 ! 105: #define DISTRIBUTION 17 ! 106: #define ORGANIZATION 18 ! 107: #define NUMLINES 19 ! 108: #define KEYWORDS 20 ! 109: #define APPROVED 21 ! 110: #define OTHER 99 ! 111: ! 112: char *malloc(); ! 113: ! 114: frmread(fp, hp) ! 115: register FILE *fp; ! 116: register struct hbuf *hp; ! 117: { ! 118: int unreccnt = 0; ! 119: register int i; ! 120: long curpos; ! 121: int hdrlineno = 0; ! 122: int iu; ! 123: ! 124: for (iu=0; iu<NUNREC; iu++) ! 125: hp->unrec[iu] = NULL; ! 126: ! 127: i = type(bfr); ! 128: do { ! 129: curpos = ftell(fp); ! 130: hdrlineno++; ! 131: switch (i) { ! 132: case PATH: ! 133: getfield(hp->path); ! 134: break; ! 135: case FROM: ! 136: getfield(hp->from); ! 137: break; ! 138: case NEWSGROUP: ! 139: getfield(hp->nbuf); ! 140: break; ! 141: case TITLE: ! 142: getfield(hp->title); ! 143: break; ! 144: case SUBMIT: ! 145: getfield(hp->subdate); ! 146: break; ! 147: case RECEIVE: ! 148: getfield(hp->recdate); ! 149: break; ! 150: case EXPIRE: ! 151: getfield(hp->expdate); ! 152: break; ! 153: case ARTICLEID: ! 154: getfield(hp->oident); ! 155: break; ! 156: case MESSAGEID: ! 157: getfield(hp->ident); ! 158: break; ! 159: case REPLYTO: ! 160: getfield(hp->replyto); ! 161: break; ! 162: case FOLLOWID: ! 163: getfield(hp->followid); ! 164: break; ! 165: case SENDER: ! 166: getfield(hp->sender); ! 167: break; ! 168: case FOLLOWTO: ! 169: getfield(hp->followto); ! 170: break; ! 171: case CONTROL: ! 172: getfield(hp->ctlmsg); ! 173: break; ! 174: case POSTVERSION: ! 175: getfield(hp->postversion); ! 176: break; ! 177: case DISTRIBUTION: ! 178: getfield(hp->distribution); ! 179: break; ! 180: case ORGANIZATION: ! 181: getfield(hp->organization); ! 182: break; ! 183: case NUMLINES: ! 184: getfield(hp->numlines); ! 185: hp->intnumlines = atoi(hp->numlines); ! 186: break; ! 187: case KEYWORDS: ! 188: getfield(hp->keywords); ! 189: break; ! 190: case APPROVED: ! 191: getfield(hp->approved); ! 192: break; ! 193: case RELAYVERSION: ! 194: /* ! 195: * Only believe a relay version if it's the first ! 196: * line, otherwise it probably got passed through ! 197: * by some old neighbor. ! 198: */ ! 199: if (hdrlineno == 1) { ! 200: getfield(hp->relayversion); ! 201: seenrelay = 1; ! 202: } ! 203: break; ! 204: case OTHER: ! 205: if (unreccnt < NUNREC) { ! 206: hp->unrec[unreccnt] = malloc(strlen(bfr) + 1); ! 207: strcpy(hp->unrec[unreccnt], bfr); ! 208: unreccnt++; ! 209: } ! 210: break; ! 211: } ! 212: } while ((i = type(hfgets(bfr, LBUFLEN, fp))) > 0); ! 213: ! 214: if (*bfr != '\n') ! 215: fseek(fp, curpos, 0); ! 216: if ((hp->from[0] || hp->path[0]) && hp->subdate[0] && (hp->ident[0] || hp->oident[0])) ! 217: return TRUE; ! 218: return FALSE; ! 219: } ! 220: ! 221: /* ! 222: * There was no From: line in the message (because it was generated by ! 223: * an old news program). Guess what it should have been and create it. ! 224: */ ! 225: intuitfrom(hp) ! 226: register struct hbuf *hp; ! 227: { ! 228: char *tp; ! 229: char *user, *host, *fullname; ! 230: char *tailpath(), *rindex(); ! 231: char *at, *dot; ! 232: ! 233: tp = tailpath(hp); ! 234: user = rindex(tp, '!'); ! 235: if (user == NULL) ! 236: user = tp; ! 237: else ! 238: *user++ = '\0'; ! 239: ! 240: /* Check for an existing Internet address on the end. */ ! 241: at = index(user, '@'); ! 242: if (at) { ! 243: dot = index(at, '.'); ! 244: if (dot) { ! 245: strcpy(hp->from, user); ! 246: return; ! 247: } ! 248: /* @ signs are illegal except for the biggie, so */ ! 249: *at = '%'; ! 250: } ! 251: ! 252: if (tp[0] == '.') ! 253: host = index(tp, '!') + 1; ! 254: else if (user == tp) ! 255: host = FULLSYSNAME; ! 256: else ! 257: host = tp; ! 258: ! 259: tp = index(host, '@'); ! 260: if (tp != NULL) ! 261: *tp = 0; ! 262: sprintf(hp->from, "%s@%s%s", user, host, MYDOMAIN); ! 263: ! 264: fullname = index(hp->path, '('); ! 265: if (fullname != NULL) { ! 266: fullname--; ! 267: strcat(hp->from, fullname); ! 268: *fullname = 0; ! 269: } ! 270: } ! 271: ! 272: /* ! 273: * If the message has only one of ident/oident, guess what ! 274: * the other one should be and fill them both in. ! 275: */ ! 276: fixid(hp) ! 277: register struct hbuf *hp; ! 278: { ! 279: char lbuf[100]; ! 280: char *p, *q; ! 281: ! 282: if (hp->ident[0] == '\0' && hp->oident[0] != '\0') { ! 283: strcpy(lbuf, hp->oident); ! 284: p = index(lbuf, '.'); ! 285: if (p == 0) { ! 286: strcpy(hp->ident, hp->oident); ! 287: return; ! 288: } ! 289: *p++ = '\0'; ! 290: /* ! 291: * It may seem strange that we hardwire ".UUCP" in ! 292: * here instead of MYDOMAIN. However, we are trying ! 293: * to guess what the domain was on the posting system, ! 294: * not the local system. Since we don't really know ! 295: * what the posting system does, we just go with the ! 296: * majority - almost everyone will be a .UUCP if they ! 297: * didn't fill in their Message-ID. ! 298: */ ! 299: sprintf(hp->ident, "<%s@%s%s>", p, lbuf, ".UUCP"); ! 300: } ! 301: ! 302: #ifdef OLD ! 303: if (hp->oident[0] == '\0' && hp->ident[0] != '\0') { ! 304: strcpy(lbuf, hp->ident); ! 305: p = index(lbuf, '@'); ! 306: if (p == 0) { ! 307: strcpy(hp->oident, hp->ident); ! 308: return; ! 309: } ! 310: *p++ = '\0'; ! 311: q = index(p, '.'); ! 312: if (!q) ! 313: q = index(p, '>'); ! 314: if (q) ! 315: *q++ = '\0'; ! 316: p[SNLN] = '\0'; ! 317: sprintf(hp->oident, "%s.%s", p, lbuf+1); ! 318: } ! 319: #endif ! 320: } ! 321: ! 322: /* ! 323: * Get the given field of a header (char * parm) from bfr, but only ! 324: * if there's something actually there (after the colon). Don't ! 325: * bother if we already have an entry for this field. ! 326: */ ! 327: getfield(hpfield) ! 328: char *hpfield; ! 329: { ! 330: char *ptr; ! 331: ! 332: if (hpfield[0]) ! 333: return; ! 334: for (ptr = index(bfr, ':'); isspace(*++ptr); ) ! 335: ; ! 336: if (*ptr != '\0') { ! 337: strcpy(hpfield, ptr); ! 338: nstrip(hpfield); ! 339: } ! 340: return; ! 341: } ! 342: ! 343: ! 344: #define its(type) (prefix(ptr, type)) ! 345: type(ptr) ! 346: char *ptr; ! 347: { ! 348: char *colon, *space; ! 349: ! 350: if (!isalpha(*ptr) && strncmp(ptr, "From ", 5)) ! 351: return FALSE; ! 352: colon = index(ptr, ':'); ! 353: space = index(ptr, ' '); ! 354: if (!colon || colon + 1 != space) ! 355: return FALSE; ! 356: if (its("From: ")) ! 357: if (index(ptr, '@') && !index(ptr, '!') && seenrelay) ! 358: return FROM; ! 359: else ! 360: return PATH; ! 361: if (its("Path: ")) ! 362: return PATH; ! 363: if (its("Newsgroups: ")) ! 364: return NEWSGROUP; ! 365: if (its("Subject: ") || its("Title: ")) ! 366: return TITLE; ! 367: if (its("Posted: ") || its("Date: ")) ! 368: return SUBMIT; ! 369: if (its("Date-Received: ") || its("Received: ")) ! 370: return RECEIVE; ! 371: if (its("Expires: ")) ! 372: return EXPIRE; ! 373: if (its("Article-I.D.: ")) ! 374: return ARTICLEID; ! 375: if (its("Message-ID: ")) ! 376: return MESSAGEID; ! 377: if (its("Reply-To: ")) ! 378: return REPLYTO; ! 379: if (its("References: ")) ! 380: return FOLLOWID; ! 381: if (its("Control: ")) ! 382: return CONTROL; ! 383: if (its("Sender: ")) ! 384: return SENDER; ! 385: if (its("Followup-To: ")) ! 386: return FOLLOWTO; ! 387: if (its("Posting-Version: ")) ! 388: return POSTVERSION; ! 389: if (its("Relay-Version: ")) ! 390: return RELAYVERSION; ! 391: if (its("Distribution: ")) ! 392: return DISTRIBUTION; ! 393: if (its("Organization: ")) ! 394: return ORGANIZATION; ! 395: if (its("Lines: ")) ! 396: return NUMLINES; ! 397: if (its("Keywords: ")) ! 398: return KEYWORDS; ! 399: if (its("Approved: ")) ! 400: return APPROVED; ! 401: return OTHER; ! 402: } ! 403: ! 404: /* ! 405: * Generate the current version of the news software. ! 406: */ ! 407: char * ! 408: genversion() ! 409: { ! 410: static char retbuf[32]; ! 411: char rb[100]; ! 412: register char *t; ! 413: ! 414: strcpy(rb, news_version); ! 415: while (t = index(rb, '\t')) ! 416: *t = ' '; ! 417: /* This is B news, so we say "B", the version, and the date. */ ! 418: sprintf(retbuf, "version %s; site %s%s", rb, FULLSYSNAME, MYDOMAIN); ! 419: return retbuf; ! 420: } ! 421: ! 422: /* ! 423: * Write header at 'hp' on stream 'fp' in B format. This goes out to ! 424: * some other system. ! 425: */ ! 426: hwrite(hp, fp) ! 427: register struct hbuf *hp; ! 428: register FILE *fp; ! 429: { ! 430: ihwrite(hp, fp, 0); ! 431: } ! 432: ! 433: ! 434: /* ! 435: * Same as above, except include receival date for local usage and ! 436: * an extra \n for looks. ! 437: */ ! 438: lhwrite(hp, fp) ! 439: register struct hbuf *hp; ! 440: register FILE *fp; ! 441: { ! 442: ihwrite(hp, fp, 1); ! 443: } ! 444: ! 445: ! 446: /* ! 447: * Write header at 'hp' on stream 'fp' in B+ format. Include received date ! 448: * if wr is 1. Leave off sysname if wr is 2. ! 449: */ ! 450: ihwrite(hp, fp, wr) ! 451: register struct hbuf *hp; ! 452: register FILE *fp; ! 453: int wr; ! 454: { ! 455: int iu; ! 456: time_t t; ! 457: time_t cgtdate(); ! 458: ! 459: fprintf(fp, "Relay-Version: %s\n", genversion()); ! 460: if (*hp->postversion) ! 461: fprintf(fp, "Posting-Version: %s\n", hp->postversion); ! 462: /* ! 463: * We're being tricky with Path/From because of upward compatibility ! 464: * issues. The new version considers From and Path to be separate. ! 465: * The old one thinks they both mean "Path" but only believes the ! 466: * first one it sees, so will ignore the second. ! 467: */ ! 468: if (prefix(hp->path, FULLSYSNAME)) ! 469: fprintf(fp, "Path: %s\n", hp->path); ! 470: else ! 471: fprintf(fp, "Path: %s!%s\n", FULLSYSNAME, hp->path); ! 472: if (hp->from[0]) ! 473: fprintf(fp, "From: %s\n", hp->from); ! 474: ! 475: ngdel(strcpy(bfr, hp->nbuf)); ! 476: fprintf(fp, "Newsgroups: %s\n", bfr); ! 477: fprintf(fp, "Subject: %s\n", hp->title); ! 478: fixid(hp); ! 479: fprintf(fp, "Message-ID: %s\n", hp->ident); ! 480: t = cgtdate(hp->subdate); ! 481: fprintf(fp, "Date: %s\n", arpadate(&t)); ! 482: #ifdef OLD ! 483: fprintf(fp, "Article-I.D.: %s\n", hp->oident); ! 484: fprintf(fp, "Posted: %s", ctime(&t)); ! 485: #endif ! 486: if (wr == 1) ! 487: fprintf(fp, "Date-Received: %s\n", hp->recdate); ! 488: if (*hp->expdate) ! 489: fprintf(fp, "Expires: %s\n", hp->expdate); ! 490: if (*hp->followid) ! 491: fprintf(fp, "References: %s\n", hp->followid); ! 492: if (*hp->ctlmsg) ! 493: fprintf(fp, "Control: %s\n", hp->ctlmsg); ! 494: if (*hp->sender) ! 495: fprintf(fp, "Sender: %s\n", hp->sender); ! 496: if (*hp->replyto) ! 497: fprintf(fp, "Reply-To: %s\n", hp->replyto); ! 498: if (*hp->followto) ! 499: fprintf(fp, "Followup-To: %s\n", hp->followto); ! 500: if (*hp->distribution) ! 501: fprintf(fp, "Distribution: %s\n", hp->distribution); ! 502: if (*hp->organization) ! 503: fprintf(fp, "Organization: %s\n", hp->organization); ! 504: if (*hp->numlines) ! 505: fprintf(fp, "Lines: %s\n", hp->numlines); ! 506: if (*hp->keywords) ! 507: fprintf(fp, "Keywords: %s\n", hp->keywords); ! 508: if (*hp->approved) ! 509: fprintf(fp, "Approved: %s\n", hp->approved); ! 510: for (iu = 0; iu < NUNREC; iu++) { ! 511: if (hp->unrec[iu]) ! 512: fprintf(fp, "%s", &hp->unrec[iu][0]); ! 513: } ! 514: putc('\n', fp); ! 515: } ! 516: ! 517: ! 518: /* ! 519: * Set nc bytes, starting at cp, to zero. ! 520: */ ! 521: bclear(cp, nc) ! 522: register char *cp; ! 523: register int nc; ! 524: { ! 525: while (nc--) ! 526: *cp++ = 0; ! 527: } ! 528: ! 529: /* ! 530: * hfgets is like fgets, but deals with continuation lines. ! 531: * It also ensures that even if a line that is too long is ! 532: * received, the remainder of the line is thrown away ! 533: * instead of treated like a second line. ! 534: */ ! 535: char * ! 536: hfgets(buf, len, fp) ! 537: char *buf; ! 538: int len; ! 539: FILE *fp; ! 540: { ! 541: register int c; ! 542: register char *cp, *tp; ! 543: ! 544: cp = fgets(buf, len, fp); ! 545: if (cp == NULL) ! 546: return NULL; ! 547: ! 548: tp = cp + strlen(cp); ! 549: if (tp[-1] != '\n') { ! 550: /* Line too long - part read didn't fit into a newline */ ! 551: while ((c = getc(fp)) != '\n' && c != EOF) ! 552: ; ! 553: } else ! 554: *--tp = '\0'; /* clobber newline */ ! 555: ! 556: while ((c = getc(fp)) == ' ' || c == '\t') { /* for each cont line */ ! 557: /* Continuation line. */ ! 558: while ((c = getc(fp)) == ' ' || c == 't') /* skip white space */ ! 559: ; ! 560: if (tp-cp < len) {*tp++ = ' '; *tp++ = c;} ! 561: while ((c = getc(fp)) != '\n' && c != EOF) ! 562: if (tp-cp < len) *tp++ = c; ! 563: } ! 564: *tp++ = '\n'; ! 565: *tp++ = '\0'; ! 566: if (c != EOF) ! 567: ungetc(c, fp); /* push back first char of next header */ ! 568: return cp; ! 569: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.