|
|
1.1 ! root 1: /* ! 2: ** Get header info from mail-format file. ! 3: ** Return non-zero on success. ! 4: */ ! 5: ! 6: #include "defs.h" ! 7: #include <ctype.h> ! 8: #include <sys/types.h> ! 9: #include <stdio.h> ! 10: #include "header.h" ! 11: #include "llist.h" ! 12: ! 13: #ifndef isblank ! 14: #define isblank(c) ((c) == ' ' || (c) == '\t') ! 15: #endif ! 16: ! 17: char *hfgets(); ! 18: char *arpadate(); ! 19: char *errmsg(); ! 20: char *strpbrk(); ! 21: time_t cgtdate(); ! 22: extern char *index(); ! 23: extern unsigned strlen(); ! 24: extern time_t time(); ! 25: ! 26: #define FROM 1 ! 27: #define NEWSGROUP 2 ! 28: #define TITLE 3 ! 29: #define SUBMIT 4 ! 30: #define RECEIVE 5 ! 31: #define EXPIRE 6 ! 32: #define ARTICLEID 7 ! 33: #define MESSAGEID 8 ! 34: #define REPLYTO 9 ! 35: #define FOLLOWID 10 ! 36: #define CONTROL 11 ! 37: #define SENDER 12 ! 38: #define FOLLOWTO 13 ! 39: #define PATH 14 ! 40: #define POSTVERSION 15 ! 41: #define RELAYVERSION 16 ! 42: #define DISTRIBUTION 17 ! 43: #define ORGANIZATION 18 ! 44: #define NUMLINES 19 ! 45: #define KEYWORDS 20 ! 46: #define APPROVED 21 ! 47: #define NFID 22 ! 48: #define NFFROM 23 ! 49: #define XREF 24 ! 50: #define SUMMARY 25 ! 51: #define FULLNAME 26 ! 52: #define OTHER 99 ! 53: ! 54: /* ! 55: ** This is the list of headers we recognize. ! 56: ** All others get stripped before they get to inews. ! 57: */ ! 58: struct htype { ! 59: char *hname; ! 60: int hid; ! 61: } htype[] = { ! 62: {"Approved:", APPROVED}, ! 63: {"Article-I.D.:", ARTICLEID}, ! 64: {"Control:", CONTROL}, ! 65: {"Date-Received:", RECEIVE}, ! 66: {"Date:", SUBMIT}, ! 67: {"Distribution:", DISTRIBUTION}, ! 68: {"Expires:", EXPIRE}, ! 69: {"Followup-To:", FOLLOWTO}, ! 70: {"From:", FROM}, ! 71: /* {"Full-Name:", FULLNAME}, */ ! 72: {"In-Reply-To:", FOLLOWID}, ! 73: {"Keywords:", KEYWORDS}, ! 74: {"Lines:", NUMLINES}, ! 75: {"Message-ID:", MESSAGEID}, ! 76: {"Newsgroups:", NEWSGROUP}, ! 77: {"Nf-From:", NFFROM}, ! 78: {"Nf-ID:", NFID}, ! 79: {"Organization:", ORGANIZATION}, ! 80: {"Path:", PATH}, ! 81: {"Posted:", SUBMIT}, ! 82: {"Posting-Version:", POSTVERSION}, ! 83: /* {"Received:", RECEIVE}, a bad name w.r.t. RFC822 */ ! 84: {"References:", FOLLOWID}, ! 85: {"Relay-Version:", RELAYVERSION}, ! 86: {"Reply-To:", REPLYTO}, ! 87: {"Sender:", SENDER}, ! 88: {"Subject:", TITLE}, ! 89: {"Summary:", SUMMARY}, ! 90: {"Title:", TITLE}, ! 91: {"Xref:", XREF}, ! 92: {(char *)NULL, NULL} ! 93: }; ! 94: ! 95: char *malloc(); ! 96: ! 97: rfc822read(hp, fp, bfr) ! 98: register struct hbuf *hp; ! 99: register FILE *fp; ! 100: char *bfr; ! 101: { ! 102: register int i = type(bfr); ! 103: long curpos; ! 104: ! 105: do { ! 106: curpos = ftell(fp); ! 107: switch (i) { ! 108: case FROM: ! 109: getfield(bfr, hp->from, sizeof(hp->from)); ! 110: break; ! 111: case NEWSGROUP: ! 112: getfield(bfr, hp->nbuf, sizeof(hp->nbuf)); ! 113: break; ! 114: case TITLE: ! 115: getfield(bfr, hp->title, sizeof(hp->title)); ! 116: break; ! 117: case SUBMIT: ! 118: getfield(bfr, hp->subdate, sizeof(hp->subdate)); ! 119: break; ! 120: case EXPIRE: ! 121: getfield(bfr, hp->expdate, sizeof(hp->expdate)); ! 122: break; ! 123: case MESSAGEID: ! 124: getfield(bfr, hp->ident, sizeof(hp->ident)); ! 125: break; ! 126: case REPLYTO: ! 127: getfield(bfr, hp->replyto, sizeof(hp->replyto)); ! 128: break; ! 129: case FOLLOWID: ! 130: getfield(bfr, hp->followid, sizeof(hp->followid)); ! 131: break; ! 132: case SENDER: ! 133: getfield(bfr, hp->sender, sizeof(hp->sender)); ! 134: break; ! 135: case FOLLOWTO: ! 136: getfield(bfr, hp->followto, sizeof(hp->followto)); ! 137: break; ! 138: case CONTROL: ! 139: getfield(bfr, hp->ctlmsg, sizeof(hp->ctlmsg)); ! 140: break; ! 141: case DISTRIBUTION: ! 142: getfield(bfr, hp->distribution, sizeof(hp->distribution)); ! 143: break; ! 144: case ORGANIZATION: ! 145: getfield(bfr, hp->organization, sizeof(hp->organization)); ! 146: break; ! 147: case KEYWORDS: ! 148: getfield(bfr, hp->keywords, sizeof(hp->keywords)); ! 149: break; ! 150: case APPROVED: ! 151: getfield(bfr, hp->approved, sizeof(hp->approved)); ! 152: break; ! 153: case SUMMARY: ! 154: getfield(bfr, hp->summary, sizeof(hp->summary)); ! 155: break; ! 156: } ! 157: } while ((i = type(hfgets(bfr, LBUFLEN, fp))) > 0); ! 158: ! 159: if (*bfr != '\n') ! 160: fseek(fp, curpos, 0); ! 161: return(TRUE); ! 162: } ! 163: ! 164: #define its(type) (prefix(ptr, type)) ! 165: ! 166: type(ptr) ! 167: register char *ptr; ! 168: { ! 169: register struct htype *hp; ! 170: register char *colon, *space; ! 171: static int lasthdr = FALSE; /* for continuation headers */ ! 172: ! 173: /* ! 174: ** some consistency checks (i.e. is this really a header line?) ! 175: */ ! 176: if ((ptr == NULL) || !isascii(*ptr) || (*ptr == '\n')) ! 177: return(lasthdr = FALSE); ! 178: ! 179: if (isblank(*ptr)) /* continuation line? */ ! 180: return(lasthdr); ! 181: ! 182: colon = index(ptr, ':'); ! 183: space = index(ptr, ' '); ! 184: if (!colon || space && space < colon) ! 185: return(lasthdr = FALSE); ! 186: ! 187: for(hp = htype; hp->hname; hp++) { ! 188: if (its(hp->hname)) ! 189: return(lasthdr = hp->hid); ! 190: } ! 191: return(lasthdr = OTHER); ! 192: } ! 193: ! 194: /* ! 195: ** Get the contents of the field of the header line, appending it, ! 196: ** with a space delimeter if it's a continuation line. ! 197: ** If there is already something in the header storage, skip this ! 198: ** header line and the continuations. ! 199: */ ! 200: getfield(src, dest, size) ! 201: register char *src, *dest; ! 202: int size; /* of dest (total bytes) */ ! 203: { ! 204: static int skip = FALSE; /* skip the continuation lines */ ! 205: ! 206: if (src == (char *)NULL || dest == (char *)NULL) ! 207: return(FALSE); ! 208: ! 209: if (isblank(*src)) { /* continuation line? */ ! 210: if (skip) ! 211: return(TRUE); ! 212: if ((size -= strlen(dest)) <= 0) /* any space left? */ ! 213: return(FALSE); ! 214: while(*src && isblank(*src)) /* eat whitespace */ ! 215: src++; ! 216: *--src = ' '; /* backup & add one */ ! 217: (void) strncat(dest, src, size - 1); /* append to hdr */ ! 218: } else { ! 219: skip = FALSE; ! 220: if (*dest) /* already got one? */ ! 221: return(skip = TRUE); /* skip continuation */ ! 222: if ((src = index(src, ':')) == (char *)NULL) /* impossible */ ! 223: return(FALSE); ! 224: src++; /* skip colon */ ! 225: while(*src && isblank(*src)) /* eat whitespace */ ! 226: src++; ! 227: (void) strncpy(dest, src, size - 1); ! 228: } ! 229: (void) nstrip(dest); ! 230: return(TRUE); ! 231: } ! 232: ! 233: /* ! 234: ** Write out an RFC822 header, paying no attention to line limits. ! 235: ** Ideally, we should do continuations in here... ! 236: */ ! 237: rfc822write(hp, fp) ! 238: register struct hbuf *hp; ! 239: register FILE *fp; ! 240: { ! 241: time_t t; ! 242: ! 243: if (hp->path[0]) ! 244: fprintf(fp, "Path: %s\n", hp->path); ! 245: if (hp->from[0]) ! 246: fprintf(fp, "From: %s\n", hp->from); ! 247: if (hp->nbuf[0]) ! 248: fprintf(fp, "Newsgroups: %s\n", hp->nbuf); ! 249: if (hp->title[0]) ! 250: fprintf(fp, "Subject: %s\n", hp->title); ! 251: if (hp->ident[0]) ! 252: fprintf(fp, "Message-ID: %s\n", hp->ident); ! 253: if (hp->subdate[0]) ! 254: t = cgtdate(hp->subdate); ! 255: else ! 256: time(&t); ! 257: fprintf(fp, "Date: %s\n", arpadate(&t)); ! 258: if (*hp->expdate) ! 259: fprintf(fp, "Expires: %s\n", hp->expdate); ! 260: if (*hp->followid) ! 261: fprintf(fp, "References: %s\n", hp->followid); ! 262: if (*hp->ctlmsg) ! 263: fprintf(fp, "Control: %s\n", hp->ctlmsg); ! 264: if (*hp->sender) ! 265: fprintf(fp, "Sender: %s\n", hp->sender); ! 266: if (*hp->replyto) ! 267: fprintf(fp, "Reply-To: %s\n", hp->replyto); ! 268: if (*hp->followto) ! 269: fprintf(fp, "Followup-To: %s\n", hp->followto); ! 270: if (*hp->distribution) ! 271: fprintf(fp, "Distribution: %s\n", hp->distribution); ! 272: if (*hp->organization) ! 273: fprintf(fp, "Organization: %s\n", hp->organization); ! 274: if (*hp->keywords) ! 275: fprintf(fp, "Keywords: %s\n", hp->keywords); ! 276: if (*hp->summary) ! 277: fprintf(fp, "Summary: %s\n", hp->summary); ! 278: if (*hp->approved) ! 279: fprintf(fp, "Approved: %s\n", hp->approved); ! 280: putc('\n', fp); ! 281: return(!ferror(fp)); ! 282: } ! 283: ! 284: /* ! 285: ** strip leading and trailing spaces ! 286: */ ! 287: char * ! 288: sp_strip(s) ! 289: register char *s; ! 290: { ! 291: register char *cp; ! 292: ! 293: if (s == NULL) ! 294: return(NULL); ! 295: ! 296: if (*s == '\0') ! 297: return(s); ! 298: ! 299: cp = &s[strlen(s) - 1]; ! 300: while(cp > s && isspace(*cp)) ! 301: cp--; ! 302: ! 303: *++cp = '\0'; /* zap trailing spaces */ ! 304: ! 305: for(cp = s; *cp && isspace(*cp); cp++) ! 306: continue; ! 307: ! 308: return(cp); /* return pointer to first non-space */ ! 309: } ! 310: ! 311: /* ! 312: ** crack an RFC822 from header field into address and fullname. ! 313: */ ! 314: crackfrom(addr,name,field) ! 315: char *addr, *name, *field; ! 316: { ! 317: char commbuf[LBUFLEN]; ! 318: char addrbuf[LBUFLEN]; ! 319: register char *p; ! 320: register char *ap = addrbuf; ! 321: register char *np; ! 322: short commfound = 0, comment = 0; ! 323: short addrfound = 0, address = 0; ! 324: struct llist comm, *cp = &comm; ! 325: ! 326: *name = '\0'; /* just make sure */ ! 327: *addr = '\0'; ! 328: ! 329: if ((p = field) == NULL) ! 330: return(FALSE); ! 331: ! 332: while(*p && isspace(*p)) /* eat leading white space */ ! 333: p++; ! 334: ! 335: while(*p) { ! 336: switch(*p) { ! 337: case '(': ! 338: if (comment == 0) { ! 339: np = commbuf; ! 340: *np = '\0'; ! 341: } ! 342: comment++; ! 343: break; ! 344: case ')': ! 345: if (comment > 0 && --comment == 0) { ! 346: *np++ = *p++; /* note incr; skip `)' */ ! 347: *np++ = '\0'; ! 348: if ((cp = l_alloc(cp, commbuf, strlen(commbuf) + 1)) == NULL) { ! 349: if (commfound) ! 350: l_free(comm); ! 351: return(FALSE); ! 352: } ! 353: commfound++; ! 354: np = NULL; ! 355: continue; ! 356: } ! 357: break; ! 358: case '<': ! 359: if (address) { ! 360: if (commfound) ! 361: l_free(comm); ! 362: return(FALSE); /* AWK! Abort! */ ! 363: } ! 364: if (!comment) { ! 365: address++; ! 366: *ap = '\0'; ! 367: ap = addr; ! 368: } ! 369: break; ! 370: case '>': ! 371: if (!comment && address) { ! 372: address--; ! 373: addrfound++; ! 374: *ap = '\0'; ! 375: ap = &addrbuf[strlen(addrbuf)]; ! 376: p++; /* skip the `>' */ ! 377: } ! 378: break; ! 379: } ! 380: ! 381: if (comment) { ! 382: *np++ = *p; ! 383: } else if (address) { ! 384: if (*p != '<') ! 385: *ap++ = *p; ! 386: } else { ! 387: *ap++ = *p; ! 388: } ! 389: if (*p) ! 390: p++; ! 391: else ! 392: break; ! 393: } ! 394: ! 395: *ap++ = '\0'; ! 396: ! 397: if (addrfound) { ! 398: (void) strcpy(name, sp_strip(addrbuf)); ! 399: (void) strcpy(addr, strcpy(commbuf, sp_strip(addr))); ! 400: } else { ! 401: (void) strcpy(addr, sp_strip(addrbuf)); ! 402: *name = '\0'; ! 403: } ! 404: /* ! 405: ** Just to be sure that we got the full name, ! 406: ** we'll take all of the comments! ! 407: */ ! 408: if (commfound) { ! 409: register int len; ! 410: register int flag = (*name != '\0' ? TRUE : FALSE); ! 411: ! 412: for(cp = &comm; cp->l_item; cp = cp->l_next) { ! 413: if (flag) ! 414: (void)strcat(name, ", "); ! 415: flag = TRUE; ! 416: if (cp->l_item[cp->l_len - 2] == ')') ! 417: cp->l_item[cp->l_len - 2] = '\0'; ! 418: (void)strcat(name, sp_strip(&cp->l_item[1])); ! 419: } ! 420: l_free(comm); ! 421: } ! 422: return(TRUE); ! 423: } ! 424: ! 425: /* ! 426: ** Check on the validity of an RFC822 message-id. ! 427: ** Check for enclosing `<>', an `@', and a `.' after ! 428: ** the `@'. Also make sure that everything is ASCII, ! 429: ** and non-control characters. ! 430: */ ! 431: msgid_ok(id) ! 432: register char *id; ! 433: { ! 434: register atdot = FALSE; ! 435: register closure = FALSE; ! 436: ! 437: if (id == NULL) ! 438: return(FALSE); /* don't waste my time! */ ! 439: ! 440: if (*id != '<') ! 441: return(FALSE); ! 442: ! 443: /* skip the first `<', cause we check for more */ ! 444: for(id++; *id; id++) { ! 445: switch(*id) { ! 446: case '<': ! 447: return(FALSE); /* we've already got one */ ! 448: case '>': ! 449: closure = TRUE; ! 450: goto end; /* djikstra is a wimp! */ ! 451: break; ! 452: case '.': ! 453: case '@': /* should be a domain spec */ ! 454: atdot = TRUE; ! 455: break; ! 456: default: ! 457: if (!isascii(*id) || iscntrl(*id) || isspace(*id)) ! 458: return(FALSE); /* quit immediately */ ! 459: break; ! 460: } ! 461: } ! 462: end: ! 463: return(atdot && closure); ! 464: } ! 465: ! 466: /* ! 467: ** hfgets is like fgets, but deals with continuation lines. ! 468: ** It also ensures that even if a line that is too long is ! 469: ** received, the remainder of the line is thrown away ! 470: ** instead of treated like a second line. ! 471: */ ! 472: char * ! 473: hfgets(buf, len, fp) ! 474: char *buf; ! 475: int len; ! 476: FILE *fp; ! 477: { ! 478: register int c; ! 479: register int n = 0; ! 480: register char *cp; ! 481: ! 482: cp = buf; ! 483: while (n < len && (c = getc(fp)) != EOF) { ! 484: if (c == '\n') ! 485: break; ! 486: if (!iscntrl(c) || c == '\b' || c == '\t') { ! 487: *cp++ = c; ! 488: n++; ! 489: } ! 490: } ! 491: if (c == EOF && cp == buf) ! 492: return NULL; ! 493: *cp = '\0'; ! 494: ! 495: if (c != '\n') { ! 496: /* Line too long - part read didn't fit into a newline */ ! 497: while ((c = getc(fp)) != '\n' && c != EOF) ! 498: ; ! 499: } else if (cp == buf) { ! 500: /* Don't look for continuation of blank lines */ ! 501: *cp++ = '\n'; ! 502: *cp = '\0'; ! 503: return buf; ! 504: } ! 505: ! 506: while ((c = getc(fp)) == ' ' || c == '\t') { /* for each cont line */ ! 507: /* Continuation line. */ ! 508: if ((n += 2) < len) { ! 509: *cp++ = '\n'; ! 510: *cp++ = c; ! 511: } ! 512: while ((c = getc(fp)) != '\n' && c != EOF) ! 513: if ((!iscntrl(c) || c == '\b' || c == '\t') && n++ < len) ! 514: *cp++ = c; ! 515: } ! 516: if (n >= len - 1) ! 517: cp = buf + len - 2; ! 518: *cp++ = '\n'; ! 519: *cp = '\0'; ! 520: if (c != EOF) ! 521: (void) ungetc(c, fp); /* push back first char of next header */ ! 522: return buf; ! 523: } ! 524: ! 525: /* ! 526: * arpadate is like ctime(3) except that the time is returned in ! 527: * an acceptable ARPANET time format instead of ctime format. ! 528: */ ! 529: char * ! 530: arpadate(longtime) ! 531: time_t *longtime; ! 532: { ! 533: register char *p, *q, *ud; ! 534: register int i; ! 535: static char b[40]; ! 536: extern struct tm *gmtime(); ! 537: extern char *asctime(); ! 538: ! 539: /* Get current time. This will be used resolve the timezone. */ ! 540: ud = asctime(gmtime(longtime)); ! 541: ! 542: /* Crack the UNIX date line in a singularly unoriginal way. */ ! 543: q = b; ! 544: ! 545: #ifdef notdef ! 546: /* until every site installs the fix to getdate.y, the day ! 547: of the week can cause time warps */ ! 548: p = &ud[0]; /* Mon */ ! 549: *q++ = *p++; ! 550: *q++ = *p++; ! 551: *q++ = *p++; ! 552: *q++ = ','; *q++ = ' '; ! 553: #endif ! 554: ! 555: p = &ud[8]; /* 16 */ ! 556: if (*p == ' ') ! 557: p++; ! 558: else ! 559: *q++ = *p++; ! 560: *q++ = *p++; *q++ = ' '; ! 561: ! 562: p = &ud[4]; /* Sep */ ! 563: *q++ = *p++; *q++ = *p++; *q++ = *p++; *q++ = ' '; ! 564: ! 565: p = &ud[22]; /* 1979 */ ! 566: *q++ = *p++; *q++ = *p++; *q++ = ' '; ! 567: ! 568: p = &ud[11]; /* 01:03:52 */ ! 569: for (i = 8; i > 0; i--) ! 570: *q++ = *p++; ! 571: ! 572: *q++ = ' '; ! 573: *q++ = 'G'; /* GMT */ ! 574: *q++ = 'M'; ! 575: *q++ = 'T'; ! 576: *q = '\0'; ! 577: ! 578: return b; ! 579: } ! 580: ! 581: time_t ! 582: cgtdate(datestr) ! 583: char *datestr; ! 584: { ! 585: char junk[40], month[40], day[30], tod[60], year[50], buf[BUFLEN]; ! 586: static time_t lasttime; ! 587: static char lastdatestr[BUFLEN] = ""; ! 588: extern time_t getdate(); ! 589: ! 590: if (lastdatestr[0] && strcmp(datestr, lastdatestr) == 0) ! 591: return(lasttime); ! 592: lasttime = getdate(datestr, (struct timeb *)NULL); ! 593: if (lasttime < 0 && ! 594: sscanf(datestr, "%s %s %s %s %s", junk, month, day, tod, year) == 5) { ! 595: (void) sprintf(buf, "%s %s, %s %s", month, day, year, tod); ! 596: lasttime = getdate(buf, (struct timeb *)NULL); ! 597: } ! 598: strncpy(lastdatestr, datestr, BUFLEN); ! 599: return(lasttime); ! 600: } ! 601: ! 602: char * ! 603: errmsg(code) ! 604: int code; ! 605: { ! 606: extern int sys_nerr; ! 607: extern char *sys_errlist[]; ! 608: static char ebuf[6+5+1]; ! 609: ! 610: if (code > sys_nerr) { ! 611: (void) sprintf(ebuf, "Error %d", code); ! 612: return ebuf; ! 613: } else ! 614: return sys_errlist[code]; ! 615: } ! 616: ! 617: /* ! 618: * Strip trailing newlines, blanks, and tabs from 's'. ! 619: * Return TRUE if newline was found, else FALSE. ! 620: */ ! 621: nstrip(s) ! 622: register char *s; ! 623: { ! 624: register char *p; ! 625: register int rc; ! 626: ! 627: rc = FALSE; ! 628: p = s; ! 629: while (*p) ! 630: if (*p++ == '\n') ! 631: rc = TRUE; ! 632: while (--p >= s && (*p == '\n' || *p == ' ' || *p == '\t')); ! 633: *++p = '\0'; ! 634: return rc; ! 635: } ! 636: ! 637: prefix(full, pref) ! 638: register char *full, *pref; ! 639: { ! 640: register char fc, pc; ! 641: ! 642: while ((pc = *pref++) != '\0') { ! 643: fc = *full++; ! 644: if (isupper(fc)) ! 645: fc = tolower(fc); ! 646: if (isupper(pc)) ! 647: pc = tolower(pc); ! 648: if (fc != pc) ! 649: return FALSE; ! 650: } ! 651: return TRUE; ! 652: } ! 653: ! 654: #ifndef USG ! 655: char * ! 656: strpbrk(str, chars) ! 657: register char *str, *chars; ! 658: { ! 659: register char *cp; ! 660: ! 661: do { ! 662: cp = chars - 1; ! 663: while (*++cp) { ! 664: if (*str == *cp) ! 665: return str; ! 666: } ! 667: } while (*str++); ! 668: return NULL; ! 669: } ! 670: #endif /* !USG */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.