|
|
1.1 ! root 1: # ! 2: ! 3: #include "rcv.h" ! 4: #include <sys/stat.h> ! 5: #include <sgtty.h> ! 6: #include <ctype.h> ! 7: ! 8: /* ! 9: * Mail -- a mail program ! 10: * ! 11: * Auxiliary functions. ! 12: */ ! 13: ! 14: /* ! 15: * Return a pointer to a dynamic copy of the argument. ! 16: */ ! 17: ! 18: char * ! 19: savestr(str) ! 20: char *str; ! 21: { ! 22: register char *cp, *cp2, *top; ! 23: ! 24: for (cp = str; *cp; cp++) ! 25: ; ! 26: top = salloc(cp-str + 1); ! 27: if (top == NOSTR) ! 28: return(NOSTR); ! 29: for (cp = str, cp2 = top; *cp; cp++) ! 30: *cp2++ = *cp; ! 31: *cp2 = 0; ! 32: return(top); ! 33: } ! 34: ! 35: /* ! 36: * Copy the name from the passed header line into the passed ! 37: * name buffer. Null pad the name buffer. ! 38: */ ! 39: ! 40: copyname(linebuf, nbuf) ! 41: char *linebuf, *nbuf; ! 42: { ! 43: register char *cp, *cp2; ! 44: ! 45: for (cp = linebuf + 5, cp2 = nbuf; *cp != ' ' && cp2-nbuf < 8; cp++) ! 46: *cp2++ = *cp; ! 47: while (cp2-nbuf < 8) ! 48: *cp2++ = 0; ! 49: } ! 50: ! 51: /* ! 52: * Announce a fatal error and die. ! 53: */ ! 54: ! 55: panic(str) ! 56: char *str; ! 57: { ! 58: prs("panic: "); ! 59: prs(str); ! 60: prs("\n"); ! 61: exit(1); ! 62: } ! 63: ! 64: /* ! 65: * Catch stdio errors and report them more nicely. ! 66: */ ! 67: ! 68: _error(str) ! 69: char *str; ! 70: { ! 71: prs("Stdio Error: "); ! 72: prs(str); ! 73: prs("\n"); ! 74: abort(); ! 75: } ! 76: ! 77: /* ! 78: * Print a string on diagnostic output. ! 79: */ ! 80: ! 81: prs(str) ! 82: char *str; ! 83: { ! 84: register char *s; ! 85: ! 86: for (s = str; *s; s++) ! 87: ; ! 88: write(2, str, s-str); ! 89: } ! 90: ! 91: /* ! 92: * Touch the named message by setting its MTOUCH flag. ! 93: * Touched messages have the effect of not being sent ! 94: * back to the system mailbox on exit. ! 95: */ ! 96: ! 97: touch(mesg) ! 98: { ! 99: if (mesg >= 1 && mesg <= msgCount) ! 100: message[mesg-1].m_flag |= MTOUCH; ! 101: } ! 102: ! 103: /* ! 104: * Test to see if the passed file name is a directory. ! 105: * Return true if it is. ! 106: */ ! 107: ! 108: isdir(name) ! 109: char name[]; ! 110: { ! 111: struct stat sbuf; ! 112: ! 113: if (stat(name, &sbuf) < 0) ! 114: return(0); ! 115: return((sbuf.st_mode & S_IFMT) == S_IFDIR); ! 116: } ! 117: ! 118: /* ! 119: * Compute the size in characters of the passed message ! 120: */ ! 121: ! 122: unsigned int ! 123: msize(messp) ! 124: struct message *messp; ! 125: { ! 126: register struct message *mp; ! 127: ! 128: mp = messp; ! 129: return(mp->m_size); ! 130: } ! 131: ! 132: /* ! 133: * Count the number of arguments in the given string raw list. ! 134: */ ! 135: ! 136: argcount(argv) ! 137: char **argv; ! 138: { ! 139: register char **ap; ! 140: ! 141: for (ap = argv; *ap != NOSTR; ap++) ! 142: ; ! 143: return(ap-argv); ! 144: } ! 145: ! 146: /* ! 147: * Given a file address, determine the ! 148: * block number it represents. ! 149: */ ! 150: ! 151: blockof(off) ! 152: off_t off; ! 153: { ! 154: off_t a; ! 155: ! 156: a = off >> 9; ! 157: a &= 077777; ! 158: return((int) a); ! 159: } ! 160: ! 161: /* ! 162: * Take a file address, and determine ! 163: * its offset in the current block. ! 164: */ ! 165: ! 166: offsetof(off) ! 167: off_t off; ! 168: { ! 169: off_t a; ! 170: ! 171: a = off & 0777; ! 172: return((int) a); ! 173: } ! 174: ! 175: /* ! 176: * Determine if the passed file is actually a tty, via a call to ! 177: * gtty. This is not totally reliable, but . . . ! 178: */ ! 179: ! 180: isatty(f) ! 181: { ! 182: struct sgttyb buf; ! 183: ! 184: if (gtty(f, &buf) < 0) ! 185: return(0); ! 186: return(1); ! 187: } ! 188: ! 189: /* ! 190: * Return the desired header line from the passed message ! 191: * pointer (or NOSTR if the desired header field is not available). ! 192: */ ! 193: ! 194: char * ! 195: hfield(field, mp) ! 196: char field[]; ! 197: struct message *mp; ! 198: { ! 199: register FILE *ibuf; ! 200: char linebuf[LINESIZE]; ! 201: register int lc; ! 202: ! 203: ibuf = setinput(mp); ! 204: if ((lc = mp->m_lines) <= 0) ! 205: return(NOSTR); ! 206: if (readline(ibuf, linebuf) < 0) ! 207: return(NOSTR); ! 208: lc--; ! 209: do { ! 210: lc = gethfield(ibuf, linebuf, lc); ! 211: if (lc == -1) ! 212: return(NOSTR); ! 213: if (ishfield(linebuf, field)) ! 214: return(savestr(hcontents(linebuf))); ! 215: } while (lc > 0); ! 216: return(NOSTR); ! 217: } ! 218: ! 219: /* ! 220: * Return the next header field found in the given message. ! 221: * Return > 0 if something found, <= 0 elsewise. ! 222: * Must deal with \ continuations & other such fraud. ! 223: */ ! 224: ! 225: gethfield(f, linebuf, rem) ! 226: register FILE *f; ! 227: char linebuf[]; ! 228: register int rem; ! 229: { ! 230: char line2[LINESIZE]; ! 231: long loc; ! 232: register char *cp, *cp2; ! 233: register int c; ! 234: ! 235: ! 236: for (;;) { ! 237: if (rem <= 0) ! 238: return(-1); ! 239: if (readline(f, linebuf) < 0) ! 240: return(-1); ! 241: rem--; ! 242: if (strlen(linebuf) == 0) ! 243: return(-1); ! 244: if (isspace(linebuf[0])) ! 245: continue; ! 246: if (linebuf[0] == '>') ! 247: continue; ! 248: cp = index(linebuf, ':'); ! 249: if (cp == NOSTR) ! 250: continue; ! 251: for (cp2 = linebuf; cp2 < cp; cp2++) ! 252: if (isdigit(*cp2)) ! 253: continue; ! 254: ! 255: /* ! 256: * I guess we got a headline. ! 257: * Handle wraparounding ! 258: */ ! 259: ! 260: for (;;) { ! 261: if (rem <= 0) ! 262: break; ! 263: #ifdef CANTELL ! 264: loc = ftell(f); ! 265: if (readline(f, line2) < 0) ! 266: break; ! 267: rem--; ! 268: if (!isspace(line2[0])) { ! 269: fseek(f, loc, 0); ! 270: rem++; ! 271: break; ! 272: } ! 273: #else ! 274: c = getc(f); ! 275: ungetc(c, f); ! 276: if (!isspace(c) || c == '\n') ! 277: break; ! 278: if (readline(f, line2) < 0) ! 279: break; ! 280: rem--; ! 281: #endif ! 282: cp2 = line2; ! 283: for (cp2 = line2; *cp2 != 0 && isspace(*cp2); cp2++) ! 284: ; ! 285: if (strlen(linebuf) + strlen(cp2) >= LINESIZE-2) ! 286: break; ! 287: cp = &linebuf[strlen(linebuf)]; ! 288: while (cp > linebuf && ! 289: (isspace(cp[-1]) || cp[-1] == '\\')) ! 290: cp--; ! 291: *cp++ = ' '; ! 292: for (cp2 = line2; *cp2 != 0 && isspace(*cp2); cp2++) ! 293: ; ! 294: strcpy(cp, cp2); ! 295: } ! 296: if ((c = strlen(linebuf)) > 0) { ! 297: cp = &linebuf[c-1]; ! 298: while (cp > linebuf && isspace(*cp)) ! 299: cp--; ! 300: *++cp = 0; ! 301: } ! 302: return(rem); ! 303: } ! 304: /* NOTREACHED */ ! 305: } ! 306: ! 307: /* ! 308: * Check whether the passed line is a header line of ! 309: * the desired breed. ! 310: */ ! 311: ! 312: ishfield(linebuf, field) ! 313: char linebuf[], field[]; ! 314: { ! 315: register char *cp; ! 316: register int c; ! 317: ! 318: if ((cp = index(linebuf, ':')) == NOSTR) ! 319: return(0); ! 320: if (cp == linebuf) ! 321: return(0); ! 322: cp--; ! 323: while (cp > linebuf && isspace(*cp)) ! 324: cp--; ! 325: c = *++cp; ! 326: *cp = 0; ! 327: if (icequal(linebuf ,field)) { ! 328: *cp = c; ! 329: return(1); ! 330: } ! 331: *cp = c; ! 332: return(0); ! 333: } ! 334: ! 335: /* ! 336: * Extract the non label information from the given header field ! 337: * and return it. ! 338: */ ! 339: ! 340: char * ! 341: hcontents(hfield) ! 342: char hfield[]; ! 343: { ! 344: register char *cp; ! 345: ! 346: if ((cp = index(hfield, ':')) == NOSTR) ! 347: return(NOSTR); ! 348: cp++; ! 349: while (*cp && isspace(*cp)) ! 350: cp++; ! 351: return(cp); ! 352: } ! 353: ! 354: /* ! 355: * Compare two strings, ignoring case. ! 356: */ ! 357: ! 358: icequal(s1, s2) ! 359: register char *s1, *s2; ! 360: { ! 361: ! 362: while (raise(*s1++) == raise(*s2)) ! 363: if (*s2++ == 0) ! 364: return(1); ! 365: return(0); ! 366: } ! 367: ! 368: /* ! 369: * The following code deals with input stacking to do source ! 370: * commands. All but the current file pointer are saved on ! 371: * the stack. ! 372: */ ! 373: ! 374: static int ssp = -1; /* Top of file stack */ ! 375: static FILE *sstack[_NFILE]; /* Saved input files */ ! 376: ! 377: /* ! 378: * Pushdown current input file and switch to a new one. ! 379: * Set the global flag "sourcing" so that others will realize ! 380: * that they are no longer reading from a tty (in all probability). ! 381: */ ! 382: ! 383: source(name) ! 384: char name[]; ! 385: { ! 386: register FILE *fi; ! 387: ! 388: if ((fi = fopen(name, "r")) == NULL) { ! 389: perror(name); ! 390: return(1); ! 391: } ! 392: if (ssp >= _NFILE-2) { ! 393: printf("Too much \"sourcing\" going on.\n"); ! 394: fclose(fi); ! 395: return(1); ! 396: } ! 397: sstack[++ssp] = input; ! 398: input = fi; ! 399: sourcing++; ! 400: return(0); ! 401: } ! 402: ! 403: /* ! 404: * Source a file, but do nothing if the file cannot be opened. ! 405: */ ! 406: ! 407: source1(name) ! 408: char name[]; ! 409: { ! 410: register int f; ! 411: ! 412: if ((f = open(name, 0)) < 0) ! 413: return(0); ! 414: close(f); ! 415: source(name); ! 416: } ! 417: ! 418: /* ! 419: * Pop the current input back to the previous level. ! 420: * Update the "sourcing" flag as appropriate. ! 421: */ ! 422: ! 423: unstack() ! 424: { ! 425: if (ssp < 0) { ! 426: printf("\"Source\" stack over-pop.\n"); ! 427: sourcing = 0; ! 428: return(1); ! 429: } ! 430: fclose(input); ! 431: input = sstack[ssp--]; ! 432: if (ssp < 0) ! 433: sourcing = 0; ! 434: return(0); ! 435: } ! 436: ! 437: /* ! 438: * Touch the indicated file. ! 439: * This is nifty for the shell. ! 440: * If we have the utime() system call, this is better served ! 441: * by using that, since it will work for empty files. ! 442: * On non-utime systems, we must sleep a second, then read. ! 443: */ ! 444: ! 445: alter(name) ! 446: char name[]; ! 447: { ! 448: #ifdef UTIME ! 449: struct stat statb; ! 450: long time(); ! 451: time_t time_p[2]; ! 452: #else ! 453: register int pid, f; ! 454: char w; ! 455: #endif UTIME ! 456: ! 457: #ifdef UTIME ! 458: if (stat(name, &statb) < 0) ! 459: return; ! 460: time_p[0] = time((long *) 0) + 1; ! 461: time_p[1] = statb.st_mtime; ! 462: utime(name, time_p); ! 463: #else ! 464: if ((pid = fork()) != 0) ! 465: return; ! 466: clrbuf(stdout); ! 467: clrbuf(stderr); ! 468: clrbuf(stdin); ! 469: sleep(1); ! 470: if ((f = open(name, 0)) < 0) ! 471: exit(1); ! 472: read(f, &w, 1); ! 473: exit(0); ! 474: #endif ! 475: } ! 476: ! 477: /* ! 478: * Examine the passed line buffer and ! 479: * return true if it is all blanks and tabs. ! 480: */ ! 481: ! 482: blankline(linebuf) ! 483: char linebuf[]; ! 484: { ! 485: register char *cp; ! 486: ! 487: for (cp = linebuf; *cp; cp++) ! 488: if (!any(*cp, " \t")) ! 489: return(0); ! 490: return(1); ! 491: } ! 492: ! 493: /* ! 494: * Fetch the sender's name from the passed message. ! 495: */ ! 496: ! 497: char * ! 498: nameof(mp) ! 499: register struct message *mp; ! 500: { ! 501: char namebuf[LINESIZE]; ! 502: char linebuf[LINESIZE]; ! 503: register char *cp, *cp2; ! 504: register FILE *ibuf; ! 505: int first = 1; ! 506: ! 507: if ((cp = hfield("reply-to", mp)) != NOSTR) { ! 508: strcpy(namebuf, cp); ! 509: return(namebuf); ! 510: } ! 511: ibuf = setinput(mp); ! 512: copy("", namebuf); ! 513: if (readline(ibuf, linebuf) <= 0) ! 514: return(savestr(namebuf)); ! 515: newname: ! 516: for (cp = linebuf; *cp != ' '; cp++) ! 517: ; ! 518: while (any(*cp, " \t")) ! 519: cp++; ! 520: for (cp2 = &namebuf[strlen(namebuf)]; *cp && !any(*cp, " \t") && ! 521: cp2-namebuf < LINESIZE-1; *cp2++ = *cp++) ! 522: ; ! 523: *cp2 = '\0'; ! 524: if (readline(ibuf, linebuf) <= 0) ! 525: return(savestr(namebuf)); ! 526: if ((cp = index(linebuf, 'F')) == NULL) ! 527: return(savestr(namebuf)); ! 528: if (strncmp(cp, "From", 4) != 0) ! 529: return(savestr(namebuf)); ! 530: while ((cp = index(cp, 'r')) != NULL) { ! 531: if (strncmp(cp, "remote", 6) == 0) { ! 532: if ((cp = index(cp, 'f')) == NULL) ! 533: break; ! 534: if (strncmp(cp, "from", 4) != 0) ! 535: break; ! 536: if ((cp = index(cp, ' ')) == NULL) ! 537: break; ! 538: cp++; ! 539: if (first) { ! 540: copy(cp, namebuf); ! 541: first = 0; ! 542: } else ! 543: strcpy(rindex(namebuf, '!')+1, cp); ! 544: strcat(namebuf, "!"); ! 545: goto newname; ! 546: } ! 547: cp++; ! 548: } ! 549: return(savestr(namebuf)); ! 550: } ! 551: ! 552: /* ! 553: * Find the rightmost pointer to an instance of the ! 554: * character in the string and return it. ! 555: */ ! 556: ! 557: char * ! 558: rindex(str, c) ! 559: char str[]; ! 560: register int c; ! 561: { ! 562: register char *cp, *cp2; ! 563: ! 564: for (cp = str, cp2 = NOSTR; *cp; cp++) ! 565: if (c == *cp) ! 566: cp2 = cp; ! 567: return(cp2); ! 568: } ! 569: ! 570: /* ! 571: * See if the string is a number. ! 572: */ ! 573: ! 574: numeric(str) ! 575: char str[]; ! 576: { ! 577: register char *cp = str; ! 578: ! 579: while (*cp) ! 580: if (!isdigit(*cp++)) ! 581: return(0); ! 582: return(1); ! 583: } ! 584: ! 585: /* ! 586: * Are any of the characters in the two strings the same? ! 587: */ ! 588: ! 589: anyof(s1, s2) ! 590: register char *s1, *s2; ! 591: { ! 592: register int c; ! 593: ! 594: while (c = *s1++) ! 595: if (any(c, s2)) ! 596: return(1); ! 597: return(0); ! 598: } ! 599: ! 600: /* ! 601: * Determine the leftmost index of the character ! 602: * in the string. ! 603: */ ! 604: ! 605: char * ! 606: index(str, ch) ! 607: char *str; ! 608: { ! 609: register char *cp; ! 610: register int c; ! 611: ! 612: for (c = ch, cp = str; *cp; cp++) ! 613: if (*cp == c) ! 614: return(cp); ! 615: return(NOSTR); ! 616: } ! 617: ! 618: /* ! 619: * String compare two strings of bounded length. ! 620: */ ! 621: ! 622: strncmp(as1, as2, an) ! 623: char *as1, *as2; ! 624: { ! 625: register char *s1, *s2; ! 626: register int n; ! 627: ! 628: s1 = as1; ! 629: s2 = as2; ! 630: n = an; ! 631: while (--n >= 0 && *s1 == *s2++) ! 632: if (*s1++ == '\0') ! 633: return(0); ! 634: return(n<0 ? 0 : *s1 - *--s2); ! 635: } ! 636:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.