|
|
1.1 ! root 1: # ! 2: ! 3: /* ! 4: * Mail -- a mail program ! 5: * ! 6: * Handle name lists. ! 7: */ ! 8: ! 9: #include "rcv.h" ! 10: ! 11: /* ! 12: * Allocate a single element of a name list, ! 13: * initialize its name field to the passed ! 14: * name and return it. ! 15: */ ! 16: ! 17: struct name * ! 18: nalloc(str) ! 19: char str[]; ! 20: { ! 21: register struct name *np; ! 22: ! 23: np = (struct name *) salloc(sizeof *np); ! 24: np->n_flink = NIL; ! 25: np->n_blink = NIL; ! 26: np->n_type = -1; ! 27: np->n_name = savestr(str); ! 28: return(np); ! 29: } ! 30: ! 31: /* ! 32: * Find the tail of a list and return it. ! 33: */ ! 34: ! 35: struct name * ! 36: tailof(name) ! 37: struct name *name; ! 38: { ! 39: register struct name *np; ! 40: ! 41: np = name; ! 42: if (np == NIL) ! 43: return(NIL); ! 44: while (np->n_flink != NIL) ! 45: np = np->n_flink; ! 46: return(np); ! 47: } ! 48: ! 49: /* ! 50: * Extract a list of names from a line, ! 51: * and make a list of names from it. ! 52: * Return the list or NIL if none found. ! 53: */ ! 54: ! 55: struct name * ! 56: extract(line, ntype) ! 57: char line[]; ! 58: { ! 59: register char *cp; ! 60: register struct name *top, *np, *t; ! 61: char nbuf[BUFSIZ], abuf[BUFSIZ]; ! 62: ! 63: if (line == NOSTR || strlen(line) == 0) ! 64: return(NIL); ! 65: top = NIL; ! 66: np = NIL; ! 67: cp = line; ! 68: while ((cp = yankword(cp, nbuf)) != NOSTR) { ! 69: if (np != NIL && equal(nbuf, "at")) { ! 70: strcpy(abuf, nbuf); ! 71: if ((cp = yankword(cp, nbuf)) == NOSTR) { ! 72: strcpy(nbuf, abuf); ! 73: goto normal; ! 74: } ! 75: strcpy(abuf, np->n_name); ! 76: stradd(abuf, '@'); ! 77: strcat(abuf, nbuf); ! 78: np->n_name = savestr(abuf); ! 79: continue; ! 80: } ! 81: normal: ! 82: t = nalloc(nbuf); ! 83: t->n_type = ntype; ! 84: if (top == NIL) ! 85: top = t; ! 86: else ! 87: np->n_flink = t; ! 88: t->n_blink = np; ! 89: np = t; ! 90: } ! 91: return(top); ! 92: } ! 93: ! 94: /* ! 95: * Turn a list of names into a string of the same names. ! 96: */ ! 97: ! 98: char * ! 99: detract(np, ntype) ! 100: register struct name *np; ! 101: { ! 102: register int s; ! 103: register char *cp, *top; ! 104: register struct name *p; ! 105: register int comma; ! 106: ! 107: comma = ntype & GCOMMA; ! 108: if (np == NIL) ! 109: return(NOSTR); ! 110: ntype &= ~GCOMMA; ! 111: s = 0; ! 112: if (debug && comma) ! 113: fprintf(stderr, "detract asked to insert commas\n"); ! 114: for (p = np; p != NIL; p = p->n_flink) { ! 115: if (ntype && (p->n_type & GMASK) != ntype) ! 116: continue; ! 117: s += strlen(p->n_name) + 1; ! 118: if (comma) ! 119: s++; ! 120: } ! 121: if (s == 0) ! 122: return(NOSTR); ! 123: s += 2; ! 124: top = salloc(s); ! 125: cp = top; ! 126: for (p = np; p != NIL; p = p->n_flink) { ! 127: if (ntype && (p->n_type & GMASK) != ntype) ! 128: continue; ! 129: cp = copy(p->n_name, cp); ! 130: if (comma && p->n_flink != NIL) ! 131: *cp++ = ','; ! 132: *cp++ = ' '; ! 133: } ! 134: *--cp = 0; ! 135: if (comma && *--cp == ',') ! 136: *cp = 0; ! 137: return(top); ! 138: } ! 139: ! 140: /* ! 141: * Grab a single word (liberal word) ! 142: * Throw away things between ()'s. ! 143: */ ! 144: ! 145: char * ! 146: yankword(ap, wbuf) ! 147: char *ap, wbuf[]; ! 148: { ! 149: register char *cp, *cp2; ! 150: ! 151: do { ! 152: for (cp = ap; *cp && any(*cp, " \t,"); cp++) ! 153: ; ! 154: if (*cp == '(') { ! 155: while (*cp && *cp != ')') ! 156: cp++; ! 157: if (*cp) ! 158: cp++; ! 159: } ! 160: if (*cp == '\0') ! 161: return(NOSTR); ! 162: } while (any(*cp, " \t,(")); ! 163: for (cp2 = wbuf; *cp && !any(*cp, " \t,("); *cp2++ = *cp++) ! 164: ; ! 165: *cp2 = '\0'; ! 166: return(cp); ! 167: } ! 168: ! 169: /* ! 170: * Verify that all the users in the list of names are ! 171: * legitimate. Bitch about and delink those who aren't. ! 172: */ ! 173: ! 174: struct name * ! 175: verify(names) ! 176: struct name *names; ! 177: { ! 178: register struct name *np, *top, *t, *x; ! 179: register char *cp; ! 180: ! 181: #ifdef DELIVERMAIL ! 182: return(names); ! 183: #else ! 184: top = names; ! 185: np = names; ! 186: while (np != NIL) { ! 187: if (np->n_type & GDEL) { ! 188: np = np->n_flink; ! 189: continue; ! 190: } ! 191: for (cp = "!:@^"; *cp; cp++) ! 192: if (any(*cp, np->n_name)) ! 193: break; ! 194: if (*cp != 0) { ! 195: np = np->n_flink; ! 196: continue; ! 197: } ! 198: cp = np->n_name; ! 199: while (*cp == '\\') ! 200: cp++; ! 201: if (equal(cp, "msgs") || ! 202: getuserid(cp) != -1) { ! 203: np = np->n_flink; ! 204: continue; ! 205: } ! 206: fprintf(stderr, "Can't send to %s\n", np->n_name); ! 207: senderr++; ! 208: if (np == top) { ! 209: top = np->n_flink; ! 210: if (top != NIL) ! 211: top->n_blink = NIL; ! 212: np = top; ! 213: continue; ! 214: } ! 215: x = np->n_blink; ! 216: t = np->n_flink; ! 217: x->n_flink = t; ! 218: if (t != NIL) ! 219: t->n_blink = x; ! 220: np = t; ! 221: } ! 222: return(top); ! 223: #endif ! 224: } ! 225: ! 226: /* ! 227: * For each recipient in the passed name list with a / ! 228: * in the name, append the message to the end of the named file ! 229: * and remove him from the recipient list. ! 230: * ! 231: * Recipients whose name begins with | are piped through the given ! 232: * program and removed. ! 233: */ ! 234: ! 235: struct name * ! 236: outof(names, fo, hp) ! 237: struct name *names; ! 238: FILE *fo; ! 239: struct header *hp; ! 240: { ! 241: register int c; ! 242: register struct name *np, *top, *t, *x; ! 243: long now; ! 244: char *date, *fname, *shell, *ctime(); ! 245: FILE *fout, *fin; ! 246: int ispipe, s, pid; ! 247: extern char tempEdit[]; ! 248: ! 249: top = names; ! 250: np = names; ! 251: time(&now); ! 252: date = ctime(&now); ! 253: while (np != NIL) { ! 254: if (!any('/', np->n_name) && np->n_name[0] != '|') { ! 255: np = np->n_flink; ! 256: continue; ! 257: } ! 258: ispipe = np->n_name[0] == '|'; ! 259: if (ispipe) ! 260: fname = np->n_name+1; ! 261: else ! 262: fname = expand(np->n_name); ! 263: ! 264: /* ! 265: * See if we have copied the complete message out yet. ! 266: * If not, do so. ! 267: */ ! 268: ! 269: if (image < 0) { ! 270: if ((fout = fopen(tempEdit, "a")) == NULL) { ! 271: perror(tempEdit); ! 272: senderr++; ! 273: goto cant; ! 274: } ! 275: image = open(tempEdit, 2); ! 276: unlink(tempEdit); ! 277: if (image < 0) { ! 278: perror(tempEdit); ! 279: senderr++; ! 280: goto cant; ! 281: } ! 282: else { ! 283: rewind(fo); ! 284: fprintf(fout, "From %s %s", myname, date); ! 285: puthead(hp, fout, GTO|GSUBJECT|GCC|GNL); ! 286: while ((c = getc(fo)) != EOF) ! 287: putc(c, fout); ! 288: rewind(fo); ! 289: putc('\n', fout); ! 290: fflush(fout); ! 291: if (ferror(fout)) ! 292: perror(tempEdit); ! 293: fclose(fout); ! 294: } ! 295: } ! 296: ! 297: /* ! 298: * Now either copy "image" to the desired file ! 299: * or give it as the standard input to the desired ! 300: * program as appropriate. ! 301: */ ! 302: ! 303: if (ispipe) { ! 304: wait(&s); ! 305: switch (pid = fork()) { ! 306: case 0: ! 307: signal(SIGHUP, SIG_IGN); ! 308: signal(SIGINT, SIG_IGN); ! 309: signal(SIGQUIT, SIG_IGN); ! 310: close(0); ! 311: dup(image); ! 312: close(image); ! 313: if ((shell = value("SHELL")) == NOSTR) ! 314: shell = SHELL; ! 315: execl(shell, shell, "-c", fname, 0); ! 316: perror(shell); ! 317: exit(1); ! 318: break; ! 319: ! 320: case -1: ! 321: perror("fork"); ! 322: senderr++; ! 323: goto cant; ! 324: } ! 325: } ! 326: else { ! 327: if ((fout = fopen(fname, "a")) == NULL) { ! 328: perror(fname); ! 329: senderr++; ! 330: goto cant; ! 331: } ! 332: fin = Fdopen(image, "r"); ! 333: if (fin == NULL) { ! 334: fprintf(stderr, "Can't reopen image\n"); ! 335: fclose(fout); ! 336: senderr++; ! 337: goto cant; ! 338: } ! 339: rewind(fin); ! 340: while ((c = getc(fin)) != EOF) ! 341: putc(c, fout); ! 342: if (ferror(fout)) ! 343: senderr++, perror(fname); ! 344: fclose(fout); ! 345: fclose(fin); ! 346: } ! 347: ! 348: cant: ! 349: ! 350: /* ! 351: * In days of old we removed the entry from the ! 352: * the list; now for sake of header expansion ! 353: * we leave it in and mark it as deleted. ! 354: */ ! 355: ! 356: #ifdef CRAZYWOW ! 357: if (np == top) { ! 358: top = np->n_flink; ! 359: if (top != NIL) ! 360: top->n_blink = NIL; ! 361: np = top; ! 362: continue; ! 363: } ! 364: x = np->n_blink; ! 365: t = np->n_flink; ! 366: x->n_flink = t; ! 367: if (t != NIL) ! 368: t->n_blink = x; ! 369: np = t; ! 370: #endif ! 371: ! 372: np->n_type |= GDEL; ! 373: np = np->n_flink; ! 374: } ! 375: if (image >= 0) { ! 376: close(image); ! 377: image = -1; ! 378: } ! 379: return(top); ! 380: } ! 381: ! 382: /* ! 383: * Map all of the aliased users in the invoker's mailrc ! 384: * file and insert them into the list. ! 385: * Changed after all these months of service to recursively ! 386: * expand names (2/14/80). ! 387: */ ! 388: ! 389: struct name * ! 390: usermap(names) ! 391: struct name *names; ! 392: { ! 393: register struct name *new, *np, *cp; ! 394: struct name *getto; ! 395: struct grouphead *gh; ! 396: register int metoo; ! 397: ! 398: new = NIL; ! 399: np = names; ! 400: getto = NIL; ! 401: metoo = (value("metoo") != NOSTR); ! 402: while (np != NIL) { ! 403: if (np->n_name[0] == '\\') { ! 404: cp = np->n_flink; ! 405: new = put(new, np); ! 406: np = cp; ! 407: continue; ! 408: } ! 409: gh = findgroup(np->n_name); ! 410: cp = np->n_flink; ! 411: if (gh != NOGRP) ! 412: new = gexpand(new, gh, metoo, np->n_type); ! 413: else ! 414: new = put(new, np); ! 415: np = cp; ! 416: } ! 417: return(new); ! 418: } ! 419: ! 420: /* ! 421: * Recursively expand a group name. We limit the expansion to some ! 422: * fixed level to keep things from going haywire. ! 423: * Direct recursion is not expanded for convenience. ! 424: */ ! 425: ! 426: struct name * ! 427: gexpand(nlist, gh, metoo, ntype) ! 428: struct name *nlist; ! 429: struct grouphead *gh; ! 430: { ! 431: struct group *gp; ! 432: struct grouphead *ngh; ! 433: struct name *np; ! 434: static int depth; ! 435: char *cp; ! 436: ! 437: if (depth > MAXEXP) { ! 438: printf("Expanding alias to depth larger than %d\n", MAXEXP); ! 439: return(nlist); ! 440: } ! 441: depth++; ! 442: for (gp = gh->g_list; gp != NOGE; gp = gp->ge_link) { ! 443: cp = gp->ge_name; ! 444: if (*cp == '\\') ! 445: goto quote; ! 446: if (strcmp(cp, gh->g_name) == 0) ! 447: goto quote; ! 448: if ((ngh = findgroup(cp)) != NOGRP) { ! 449: nlist = gexpand(nlist, ngh, metoo, ntype); ! 450: continue; ! 451: } ! 452: quote: ! 453: np = nalloc(cp); ! 454: np->n_type = ntype; ! 455: /* ! 456: * At this point should allow to expand ! 457: * to self if only person in group ! 458: */ ! 459: if (gp == gh->g_list && gp->ge_link == NOGE) ! 460: goto skip; ! 461: if (!metoo && strcmp(cp, myname) == 0) ! 462: np->n_type |= GDEL; ! 463: skip: ! 464: nlist = put(nlist, np); ! 465: } ! 466: depth--; ! 467: return(nlist); ! 468: } ! 469: ! 470: ! 471: ! 472: /* ! 473: * Compute the length of the passed name list and ! 474: * return it. ! 475: */ ! 476: ! 477: lengthof(name) ! 478: struct name *name; ! 479: { ! 480: register struct name *np; ! 481: register int c; ! 482: ! 483: for (c = 0, np = name; np != NIL; c++, np = np->n_flink) ! 484: ; ! 485: return(c); ! 486: } ! 487: ! 488: /* ! 489: * Concatenate the two passed name lists, return the result. ! 490: */ ! 491: ! 492: struct name * ! 493: cat(n1, n2) ! 494: struct name *n1, *n2; ! 495: { ! 496: register struct name *tail; ! 497: ! 498: if (n1 == NIL) ! 499: return(n2); ! 500: if (n2 == NIL) ! 501: return(n1); ! 502: tail = tailof(n1); ! 503: tail->n_flink = n2; ! 504: n2->n_blink = tail; ! 505: return(n1); ! 506: } ! 507: ! 508: /* ! 509: * Unpack the name list onto a vector of strings. ! 510: * Return an error if the name list won't fit. ! 511: */ ! 512: ! 513: char ** ! 514: unpack(np) ! 515: struct name *np; ! 516: { ! 517: register char **ap, **top; ! 518: register struct name *n; ! 519: char *cp; ! 520: char hbuf[10]; ! 521: int t, extra, metoo; ! 522: ! 523: n = np; ! 524: if ((t = lengthof(n)) == 0) ! 525: panic("No names to unpack"); ! 526: ! 527: /* ! 528: * Compute the number of extra arguments we will need. ! 529: * We need at least two extra -- one for "mail" and one for ! 530: * the terminating 0 pointer. Additional spots may be needed ! 531: * to pass along -r and -f to the host mailer. ! 532: */ ! 533: ! 534: extra = 2; ! 535: if (rflag != NOSTR) ! 536: extra += 2; ! 537: #ifdef DELIVERMAIL ! 538: extra++; ! 539: metoo = value("metoo") != NOSTR; ! 540: if (metoo) ! 541: extra++; ! 542: #endif DELIVERMAIL ! 543: if (hflag) ! 544: extra += 2; ! 545: top = (char **) salloc((t + extra) * sizeof cp); ! 546: ap = top; ! 547: *ap++ = "send-mail"; ! 548: if (rflag != NOSTR) { ! 549: *ap++ = "-r"; ! 550: *ap++ = rflag; ! 551: } ! 552: #ifdef DELIVERMAIL ! 553: *ap++ = "-i"; ! 554: if (metoo) ! 555: *ap++ = "-m"; ! 556: #endif DELIVERMAIL ! 557: if (hflag) { ! 558: *ap++ = "-h"; ! 559: sprintf(hbuf, "%d", hflag); ! 560: *ap++ = savestr(hbuf); ! 561: } ! 562: while (n != NIL) { ! 563: if (n->n_type & GDEL) { ! 564: n = n->n_flink; ! 565: continue; ! 566: } ! 567: cp = n->n_name; ! 568: while (*cp == '\\') ! 569: cp++; ! 570: *ap++ = cp; ! 571: n = n->n_flink; ! 572: } ! 573: *ap = NOSTR; ! 574: return(top); ! 575: } ! 576: ! 577: /* ! 578: * See if the user named himself as a destination ! 579: * for outgoing mail. If so, set the global flag ! 580: * selfsent so that we avoid removing his mailbox. ! 581: */ ! 582: ! 583: mechk(names) ! 584: struct name *names; ! 585: { ! 586: register struct name *np; ! 587: ! 588: for (np = names; np != NIL; np = np->n_flink) ! 589: if ((np->n_type & GDEL) == 0 && equal(myname, np->n_name)) { ! 590: selfsent++; ! 591: return; ! 592: } ! 593: } ! 594: ! 595: /* ! 596: * Remove all of the duplicates from the passed name list by ! 597: * insertion sorting them, then checking for dups. ! 598: * Return the head of the new list. ! 599: */ ! 600: ! 601: struct name * ! 602: elide(names) ! 603: struct name *names; ! 604: { ! 605: register struct name *np, *t, *new; ! 606: struct name *x; ! 607: ! 608: if (names == NIL) ! 609: return(NIL); ! 610: new = names; ! 611: np = names; ! 612: np = np->n_flink; ! 613: if (np != NIL) ! 614: np->n_blink = NIL; ! 615: new->n_flink = NIL; ! 616: while (np != NIL) { ! 617: t = new; ! 618: while (nstrcmp(t->n_name, np->n_name) < 0) { ! 619: if (t->n_flink == NIL) ! 620: break; ! 621: t = t->n_flink; ! 622: } ! 623: ! 624: /* ! 625: * If we ran out of t's, put the new entry after ! 626: * the current value of t. ! 627: */ ! 628: ! 629: if (nstrcmp(t->n_name, np->n_name) < 0) { ! 630: t->n_flink = np; ! 631: np->n_blink = t; ! 632: t = np; ! 633: np = np->n_flink; ! 634: t->n_flink = NIL; ! 635: continue; ! 636: } ! 637: ! 638: /* ! 639: * Otherwise, put the new entry in front of the ! 640: * current t. If at the front of the list, ! 641: * the new guy becomes the new head of the list. ! 642: */ ! 643: ! 644: if (t == new) { ! 645: t = np; ! 646: np = np->n_flink; ! 647: t->n_flink = new; ! 648: new->n_blink = t; ! 649: t->n_blink = NIL; ! 650: new = t; ! 651: continue; ! 652: } ! 653: ! 654: /* ! 655: * The normal case -- we are inserting into the ! 656: * middle of the list. ! 657: */ ! 658: ! 659: x = np; ! 660: np = np->n_flink; ! 661: x->n_flink = t; ! 662: x->n_blink = t->n_blink; ! 663: t->n_blink->n_flink = x; ! 664: t->n_blink = x; ! 665: } ! 666: ! 667: /* ! 668: * Now the list headed up by new is sorted. ! 669: * Go through it and remove duplicates. ! 670: */ ! 671: ! 672: np = new; ! 673: while (np != NIL) { ! 674: t = np; ! 675: while (t->n_flink!=NIL && ! 676: icequal(np->n_name,t->n_flink->n_name)) ! 677: t = t->n_flink; ! 678: if (t == np || t == NIL) { ! 679: np = np->n_flink; ! 680: continue; ! 681: } ! 682: ! 683: /* ! 684: * Now t points to the last entry with the same name ! 685: * as np. Make np point beyond t. ! 686: */ ! 687: ! 688: np->n_flink = t->n_flink; ! 689: if (t->n_flink != NIL) ! 690: t->n_flink->n_blink = np; ! 691: np = np->n_flink; ! 692: } ! 693: return(new); ! 694: } ! 695: ! 696: /* ! 697: * Version of strcmp which ignores case differences. ! 698: */ ! 699: ! 700: nstrcmp(s1, s2) ! 701: register char *s1, *s2; ! 702: { ! 703: register int c1, c2; ! 704: ! 705: do { ! 706: c1 = *s1++; ! 707: c2 = *s2++; ! 708: } while (c1 && c1 == c2); ! 709: return(c1 - c2); ! 710: } ! 711: ! 712: /* ! 713: * Put another node onto a list of names and return ! 714: * the list. ! 715: */ ! 716: ! 717: struct name * ! 718: put(list, node) ! 719: struct name *list, *node; ! 720: { ! 721: node->n_flink = list; ! 722: node->n_blink = NIL; ! 723: if (list != NIL) ! 724: list->n_blink = node; ! 725: return(node); ! 726: } ! 727: ! 728: /* ! 729: * Determine the number of elements in ! 730: * a name list and return it. ! 731: */ ! 732: ! 733: count(np) ! 734: register struct name *np; ! 735: { ! 736: register int c = 0; ! 737: ! 738: while (np != NIL) { ! 739: c++; ! 740: np = np->n_flink; ! 741: } ! 742: return(c); ! 743: } ! 744: ! 745: /* ! 746: * Delete the given name from a namelist. ! 747: */ ! 748: ! 749: struct name * ! 750: delname(np, name) ! 751: register struct name *np; ! 752: char name[]; ! 753: { ! 754: register struct name *p; ! 755: ! 756: for (p = np; p != NIL; p = p->n_flink) ! 757: if (equal(p->n_name, name)) { ! 758: if (p->n_blink == NIL) { ! 759: if (p->n_flink != NIL) ! 760: p->n_flink->n_blink = NIL; ! 761: np = p->n_flink; ! 762: continue; ! 763: } ! 764: if (p->n_flink == NIL) { ! 765: if (p->n_blink != NIL) ! 766: p->n_blink->n_flink = NIL; ! 767: continue; ! 768: } ! 769: p->n_blink->n_flink = p->n_flink; ! 770: p->n_flink->n_blink = p->n_blink; ! 771: } ! 772: return(np); ! 773: } ! 774: ! 775: /* ! 776: * Call the given routine on each element of the name ! 777: * list, replacing said value if need be. ! 778: */ ! 779: ! 780: mapf(np, from) ! 781: register struct name *np; ! 782: char *from; ! 783: { ! 784: register struct name *p; ! 785: ! 786: for (p = np; p != NIL; p = p->n_flink) ! 787: p->n_name = netmap(p->n_name, from); ! 788: } ! 789: ! 790: /* ! 791: * Pretty print a name list ! 792: * Uncomment it if you need it. ! 793: */ ! 794: ! 795: prettyprint(name) ! 796: struct name *name; ! 797: { ! 798: register struct name *np; ! 799: ! 800: np = name; ! 801: while (np != NIL) { ! 802: fprintf(stderr, "%s(%d) ", np->n_name, np->n_type); ! 803: np = np->n_flink; ! 804: } ! 805: fprintf(stderr, "\n"); ! 806: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.