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