|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1980 Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution and use in source and binary forms are permitted provided ! 6: * that: (1) source distributions retain this entire copyright notice and ! 7: * comment, and (2) distributions including binaries display the following ! 8: * acknowledgement: ``This product includes software developed by the ! 9: * University of California, Berkeley and its contributors'' in the ! 10: * documentation or other materials provided with the distribution and in ! 11: * all advertising materials mentioning features or use of this software. ! 12: * Neither the name of the University nor the names of its contributors may ! 13: * be used to endorse or promote products derived from this software without ! 14: * specific prior written permission. ! 15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED ! 16: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF ! 17: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 18: */ ! 19: ! 20: #ifndef lint ! 21: static char sccsid[] = "@(#)names.c 5.16 (Berkeley) 6/25/90"; ! 22: #endif /* not lint */ ! 23: ! 24: /* ! 25: * Mail -- a mail program ! 26: * ! 27: * Handle name lists. ! 28: */ ! 29: ! 30: #include "rcv.h" ! 31: ! 32: /* ! 33: * Allocate a single element of a name list, ! 34: * initialize its name field to the passed ! 35: * name and return it. ! 36: */ ! 37: struct name * ! 38: nalloc(str, ntype) ! 39: char str[]; ! 40: { ! 41: register struct name *np; ! 42: ! 43: np = (struct name *) salloc(sizeof *np); ! 44: np->n_flink = NIL; ! 45: np->n_blink = NIL; ! 46: np->n_type = ntype; ! 47: np->n_name = savestr(str); ! 48: return(np); ! 49: } ! 50: ! 51: /* ! 52: * Find the tail of a list and return it. ! 53: */ ! 54: struct name * ! 55: tailof(name) ! 56: struct name *name; ! 57: { ! 58: register struct name *np; ! 59: ! 60: np = name; ! 61: if (np == NIL) ! 62: return(NIL); ! 63: while (np->n_flink != NIL) ! 64: np = np->n_flink; ! 65: return(np); ! 66: } ! 67: ! 68: /* ! 69: * Extract a list of names from a line, ! 70: * and make a list of names from it. ! 71: * Return the list or NIL if none found. ! 72: */ ! 73: struct name * ! 74: extract(line, ntype) ! 75: char line[]; ! 76: { ! 77: register char *cp; ! 78: register struct name *top, *np, *t; ! 79: char nbuf[BUFSIZ]; ! 80: ! 81: if (line == NOSTR || *line == '\0') ! 82: return NIL; ! 83: top = NIL; ! 84: np = NIL; ! 85: cp = line; ! 86: while ((cp = yankword(cp, nbuf)) != NOSTR) { ! 87: t = nalloc(nbuf, ntype); ! 88: if (top == NIL) ! 89: top = t; ! 90: else ! 91: np->n_flink = t; ! 92: t->n_blink = np; ! 93: np = t; ! 94: } ! 95: return top; ! 96: } ! 97: ! 98: /* ! 99: * Turn a list of names into a string of the same names. ! 100: */ ! 101: char * ! 102: detract(np, ntype) ! 103: register struct name *np; ! 104: { ! 105: register int s; ! 106: register char *cp, *top; ! 107: register struct name *p; ! 108: register int comma; ! 109: ! 110: comma = ntype & GCOMMA; ! 111: if (np == NIL) ! 112: return(NOSTR); ! 113: ntype &= ~GCOMMA; ! 114: s = 0; ! 115: if (debug && comma) ! 116: fprintf(stderr, "detract asked to insert commas\n"); ! 117: for (p = np; p != NIL; p = p->n_flink) { ! 118: if (ntype && (p->n_type & GMASK) != ntype) ! 119: continue; ! 120: s += strlen(p->n_name) + 1; ! 121: if (comma) ! 122: s++; ! 123: } ! 124: if (s == 0) ! 125: return(NOSTR); ! 126: s += 2; ! 127: top = salloc(s); ! 128: cp = top; ! 129: for (p = np; p != NIL; p = p->n_flink) { ! 130: if (ntype && (p->n_type & GMASK) != ntype) ! 131: continue; ! 132: cp = copy(p->n_name, cp); ! 133: if (comma && p->n_flink != NIL) ! 134: *cp++ = ','; ! 135: *cp++ = ' '; ! 136: } ! 137: *--cp = 0; ! 138: if (comma && *--cp == ',') ! 139: *cp = 0; ! 140: return(top); ! 141: } ! 142: ! 143: /* ! 144: * Grab a single word (liberal word) ! 145: * Throw away things between ()'s, and take anything between <>. ! 146: */ ! 147: char * ! 148: yankword(ap, wbuf) ! 149: char *ap, wbuf[]; ! 150: { ! 151: register char *cp, *cp2; ! 152: ! 153: cp = ap; ! 154: for (;;) { ! 155: if (*cp == '\0') ! 156: return NOSTR; ! 157: if (*cp == '(') { ! 158: register int nesting = 0; ! 159: ! 160: while (*cp != '\0') { ! 161: switch (*cp++) { ! 162: case '(': ! 163: nesting++; ! 164: break; ! 165: case ')': ! 166: --nesting; ! 167: break; ! 168: } ! 169: if (nesting <= 0) ! 170: break; ! 171: } ! 172: } else if (*cp == ' ' || *cp == '\t' || *cp == ',') ! 173: cp++; ! 174: else ! 175: break; ! 176: } ! 177: if (*cp == '<') ! 178: for (cp2 = wbuf; *cp && (*cp2++ = *cp++) != '>';) ! 179: ; ! 180: else ! 181: for (cp2 = wbuf; *cp && !index(" \t,(", *cp); *cp2++ = *cp++) ! 182: ; ! 183: *cp2 = '\0'; ! 184: return cp; ! 185: } ! 186: ! 187: /* ! 188: * For each recipient in the passed name list with a / ! 189: * in the name, append the message to the end of the named file ! 190: * and remove him from the recipient list. ! 191: * ! 192: * Recipients whose name begins with | are piped through the given ! 193: * program and removed. ! 194: */ ! 195: struct name * ! 196: outof(names, fo, hp) ! 197: struct name *names; ! 198: FILE *fo; ! 199: struct header *hp; ! 200: { ! 201: register int c; ! 202: register struct name *np, *top; ! 203: time_t now, time(); ! 204: char *date, *fname, *ctime(); ! 205: FILE *fout, *fin; ! 206: int ispipe; ! 207: extern char tempEdit[]; ! 208: ! 209: top = names; ! 210: np = names; ! 211: (void) time(&now); ! 212: date = ctime(&now); ! 213: while (np != NIL) { ! 214: if (!isfileaddr(np->n_name) && np->n_name[0] != '|') { ! 215: np = np->n_flink; ! 216: continue; ! 217: } ! 218: ispipe = np->n_name[0] == '|'; ! 219: if (ispipe) ! 220: fname = np->n_name+1; ! 221: else ! 222: fname = expand(np->n_name); ! 223: ! 224: /* ! 225: * See if we have copied the complete message out yet. ! 226: * If not, do so. ! 227: */ ! 228: ! 229: if (image < 0) { ! 230: if ((fout = Fopen(tempEdit, "a")) == NULL) { ! 231: perror(tempEdit); ! 232: senderr++; ! 233: goto cant; ! 234: } ! 235: image = open(tempEdit, 2); ! 236: (void) unlink(tempEdit); ! 237: if (image < 0) { ! 238: perror(tempEdit); ! 239: senderr++; ! 240: (void) Fclose(fout); ! 241: goto cant; ! 242: } ! 243: fprintf(fout, "From %s %s", myname, date); ! 244: puthead(hp, fout, GTO|GSUBJECT|GCC|GNL); ! 245: while ((c = getc(fo)) != EOF) ! 246: (void) putc(c, fout); ! 247: rewind(fo); ! 248: (void) putc('\n', fout); ! 249: (void) fflush(fout); ! 250: if (ferror(fout)) ! 251: perror(tempEdit); ! 252: (void) Fclose(fout); ! 253: } ! 254: ! 255: /* ! 256: * Now either copy "image" to the desired file ! 257: * or give it as the standard input to the desired ! 258: * program as appropriate. ! 259: */ ! 260: ! 261: if (ispipe) { ! 262: int pid; ! 263: char *shell; ! 264: ! 265: /* ! 266: * XXX ! 267: * We can't really reuse the same image file, ! 268: * because multiple piped recipients will ! 269: * share the same lseek location and trample ! 270: * on one another. ! 271: */ ! 272: if ((shell = value("SHELL")) == NOSTR) ! 273: shell = _PATH_CSHELL; ! 274: pid = start_command(shell, sigmask(SIGHUP)| ! 275: sigmask(SIGINT)|sigmask(SIGQUIT), ! 276: image, -1, "-c", fname, NOSTR); ! 277: if (pid < 0) { ! 278: senderr++; ! 279: goto cant; ! 280: } ! 281: free_child(pid); ! 282: } else { ! 283: int f; ! 284: if ((fout = Fopen(fname, "a")) == NULL) { ! 285: perror(fname); ! 286: senderr++; ! 287: goto cant; ! 288: } ! 289: if ((f = dup(image)) < 0) { ! 290: perror("dup"); ! 291: fin = NULL; ! 292: } else ! 293: fin = Fdopen(f, "r"); ! 294: if (fin == NULL) { ! 295: fprintf(stderr, "Can't reopen image\n"); ! 296: (void) Fclose(fout); ! 297: senderr++; ! 298: goto cant; ! 299: } ! 300: rewind(fin); ! 301: while ((c = getc(fin)) != EOF) ! 302: (void) putc(c, fout); ! 303: if (ferror(fout)) ! 304: senderr++, perror(fname); ! 305: (void) Fclose(fout); ! 306: (void) Fclose(fin); ! 307: } ! 308: cant: ! 309: /* ! 310: * In days of old we removed the entry from the ! 311: * the list; now for sake of header expansion ! 312: * we leave it in and mark it as deleted. ! 313: */ ! 314: np->n_type |= GDEL; ! 315: np = np->n_flink; ! 316: } ! 317: if (image >= 0) { ! 318: (void) close(image); ! 319: image = -1; ! 320: } ! 321: return(top); ! 322: } ! 323: ! 324: /* ! 325: * Determine if the passed address is a local "send to file" address. ! 326: * If any of the network metacharacters precedes any slashes, it can't ! 327: * be a filename. We cheat with .'s to allow path names like ./... ! 328: */ ! 329: isfileaddr(name) ! 330: char *name; ! 331: { ! 332: register char *cp; ! 333: ! 334: if (*name == '+') ! 335: return 1; ! 336: for (cp = name; *cp; cp++) { ! 337: if (*cp == '!' || *cp == '%' || *cp == '@') ! 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: struct name * ! 388: gexpand(nlist, gh, metoo, ntype) ! 389: struct name *nlist; ! 390: struct grouphead *gh; ! 391: { ! 392: struct group *gp; ! 393: struct grouphead *ngh; ! 394: struct name *np; ! 395: static int depth; ! 396: char *cp; ! 397: ! 398: if (depth > MAXEXP) { ! 399: printf("Expanding alias to depth larger than %d\n", MAXEXP); ! 400: return(nlist); ! 401: } ! 402: depth++; ! 403: for (gp = gh->g_list; gp != NOGE; gp = gp->ge_link) { ! 404: cp = gp->ge_name; ! 405: if (*cp == '\\') ! 406: goto quote; ! 407: if (strcmp(cp, gh->g_name) == 0) ! 408: goto quote; ! 409: if ((ngh = findgroup(cp)) != NOGRP) { ! 410: nlist = gexpand(nlist, ngh, metoo, ntype); ! 411: continue; ! 412: } ! 413: quote: ! 414: np = nalloc(cp, ntype); ! 415: /* ! 416: * At this point should allow to expand ! 417: * to self if only person in group ! 418: */ ! 419: if (gp == gh->g_list && gp->ge_link == NOGE) ! 420: goto skip; ! 421: if (!metoo && strcmp(cp, myname) == 0) ! 422: np->n_type |= GDEL; ! 423: skip: ! 424: nlist = put(nlist, np); ! 425: } ! 426: depth--; ! 427: return(nlist); ! 428: } ! 429: ! 430: /* ! 431: * Concatenate the two passed name lists, return the result. ! 432: */ ! 433: struct name * ! 434: cat(n1, n2) ! 435: struct name *n1, *n2; ! 436: { ! 437: register struct name *tail; ! 438: ! 439: if (n1 == NIL) ! 440: return(n2); ! 441: if (n2 == NIL) ! 442: return(n1); ! 443: tail = tailof(n1); ! 444: tail->n_flink = n2; ! 445: n2->n_blink = tail; ! 446: return(n1); ! 447: } ! 448: ! 449: /* ! 450: * Unpack the name list onto a vector of strings. ! 451: * Return an error if the name list won't fit. ! 452: */ ! 453: char ** ! 454: unpack(np) ! 455: struct name *np; ! 456: { ! 457: register char **ap, **top; ! 458: register struct name *n; ! 459: int t, extra, metoo, verbose; ! 460: ! 461: n = np; ! 462: if ((t = count(n)) == 0) ! 463: panic("No names to unpack"); ! 464: /* ! 465: * Compute the number of extra arguments we will need. ! 466: * We need at least two extra -- one for "mail" and one for ! 467: * the terminating 0 pointer. Additional spots may be needed ! 468: * to pass along -f to the host mailer. ! 469: */ ! 470: extra = 2; ! 471: extra++; ! 472: metoo = value("metoo") != NOSTR; ! 473: if (metoo) ! 474: extra++; ! 475: verbose = value("verbose") != NOSTR; ! 476: if (verbose) ! 477: extra++; ! 478: top = (char **) salloc((t + extra) * sizeof *top); ! 479: ap = top; ! 480: *ap++ = "send-mail"; ! 481: *ap++ = "-i"; ! 482: if (metoo) ! 483: *ap++ = "-m"; ! 484: if (verbose) ! 485: *ap++ = "-v"; ! 486: for (; n != NIL; n = n->n_flink) ! 487: if ((n->n_type & GDEL) == 0) ! 488: *ap++ = n->n_name; ! 489: *ap = NOSTR; ! 490: return(top); ! 491: } ! 492: ! 493: /* ! 494: * Remove all of the duplicates from the passed name list by ! 495: * insertion sorting them, then checking for dups. ! 496: * Return the head of the new list. ! 497: */ ! 498: struct name * ! 499: elide(names) ! 500: struct name *names; ! 501: { ! 502: register struct name *np, *t, *new; ! 503: struct name *x; ! 504: ! 505: if (names == NIL) ! 506: return(NIL); ! 507: new = names; ! 508: np = names; ! 509: np = np->n_flink; ! 510: if (np != NIL) ! 511: np->n_blink = NIL; ! 512: new->n_flink = NIL; ! 513: while (np != NIL) { ! 514: t = new; ! 515: while (strcasecmp(t->n_name, np->n_name) < 0) { ! 516: if (t->n_flink == NIL) ! 517: break; ! 518: t = t->n_flink; ! 519: } ! 520: ! 521: /* ! 522: * If we ran out of t's, put the new entry after ! 523: * the current value of t. ! 524: */ ! 525: ! 526: if (strcasecmp(t->n_name, np->n_name) < 0) { ! 527: t->n_flink = np; ! 528: np->n_blink = t; ! 529: t = np; ! 530: np = np->n_flink; ! 531: t->n_flink = NIL; ! 532: continue; ! 533: } ! 534: ! 535: /* ! 536: * Otherwise, put the new entry in front of the ! 537: * current t. If at the front of the list, ! 538: * the new guy becomes the new head of the list. ! 539: */ ! 540: ! 541: if (t == new) { ! 542: t = np; ! 543: np = np->n_flink; ! 544: t->n_flink = new; ! 545: new->n_blink = t; ! 546: t->n_blink = NIL; ! 547: new = t; ! 548: continue; ! 549: } ! 550: ! 551: /* ! 552: * The normal case -- we are inserting into the ! 553: * middle of the list. ! 554: */ ! 555: ! 556: x = np; ! 557: np = np->n_flink; ! 558: x->n_flink = t; ! 559: x->n_blink = t->n_blink; ! 560: t->n_blink->n_flink = x; ! 561: t->n_blink = x; ! 562: } ! 563: ! 564: /* ! 565: * Now the list headed up by new is sorted. ! 566: * Go through it and remove duplicates. ! 567: */ ! 568: ! 569: np = new; ! 570: while (np != NIL) { ! 571: t = np; ! 572: while (t->n_flink != NIL && ! 573: strcasecmp(np->n_name, t->n_flink->n_name) == 0) ! 574: t = t->n_flink; ! 575: if (t == np || t == NIL) { ! 576: np = np->n_flink; ! 577: continue; ! 578: } ! 579: ! 580: /* ! 581: * Now t points to the last entry with the same name ! 582: * as np. Make np point beyond t. ! 583: */ ! 584: ! 585: np->n_flink = t->n_flink; ! 586: if (t->n_flink != NIL) ! 587: t->n_flink->n_blink = np; ! 588: np = np->n_flink; ! 589: } ! 590: return(new); ! 591: } ! 592: ! 593: /* ! 594: * Put another node onto a list of names and return ! 595: * the list. ! 596: */ ! 597: struct name * ! 598: put(list, node) ! 599: struct name *list, *node; ! 600: { ! 601: node->n_flink = list; ! 602: node->n_blink = NIL; ! 603: if (list != NIL) ! 604: list->n_blink = node; ! 605: return(node); ! 606: } ! 607: ! 608: /* ! 609: * Determine the number of undeleted elements in ! 610: * a name list and return it. ! 611: */ ! 612: count(np) ! 613: register struct name *np; ! 614: { ! 615: register int c; ! 616: ! 617: for (c = 0; np != NIL; np = np->n_flink) ! 618: if ((np->n_type & GDEL) == 0) ! 619: c++; ! 620: return c; ! 621: } ! 622: ! 623: /* ! 624: * Delete the given name from a namelist. ! 625: */ ! 626: struct name * ! 627: delname(np, name) ! 628: register struct name *np; ! 629: char name[]; ! 630: { ! 631: register struct name *p; ! 632: ! 633: for (p = np; p != NIL; p = p->n_flink) ! 634: if (strcasecmp(p->n_name, name) == 0) { ! 635: if (p->n_blink == NIL) { ! 636: if (p->n_flink != NIL) ! 637: p->n_flink->n_blink = NIL; ! 638: np = p->n_flink; ! 639: continue; ! 640: } ! 641: if (p->n_flink == NIL) { ! 642: if (p->n_blink != NIL) ! 643: p->n_blink->n_flink = NIL; ! 644: continue; ! 645: } ! 646: p->n_blink->n_flink = p->n_flink; ! 647: p->n_flink->n_blink = p->n_blink; ! 648: } ! 649: return np; ! 650: } ! 651: ! 652: /* ! 653: * Pretty print a name list ! 654: * Uncomment it if you need it. ! 655: */ ! 656: ! 657: /* ! 658: prettyprint(name) ! 659: struct name *name; ! 660: { ! 661: register struct name *np; ! 662: ! 663: np = name; ! 664: while (np != NIL) { ! 665: fprintf(stderr, "%s(%d) ", np->n_name, np->n_type); ! 666: np = np->n_flink; ! 667: } ! 668: fprintf(stderr, "\n"); ! 669: } ! 670: */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.