|
|
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_name = savestr(str); ! 27: return(np); ! 28: } ! 29: ! 30: /* ! 31: * Find the tail of a list and return it. ! 32: */ ! 33: ! 34: struct name * ! 35: tailof(name) ! 36: struct name *name; ! 37: { ! 38: register struct name *np; ! 39: ! 40: np = name; ! 41: if (np == NIL) ! 42: return(NIL); ! 43: while (np->n_flink != NIL) ! 44: np = np->n_flink; ! 45: return(np); ! 46: } ! 47: ! 48: /* ! 49: * Extract a list of names from a line, ! 50: * and make a list of names from it. ! 51: * Return the list or NIL if none found. ! 52: */ ! 53: ! 54: struct name * ! 55: extract(line) ! 56: char line[]; ! 57: { ! 58: register char *cp; ! 59: register struct name *top, *np, *t; ! 60: char nbuf[BUFSIZ]; ! 61: ! 62: if (line == NOSTR || strlen(line) == 0) ! 63: return(NIL); ! 64: top = NIL; ! 65: np = NIL; ! 66: cp = line; ! 67: while ((cp = yankword(cp, nbuf)) != NOSTR) { ! 68: t = nalloc(nbuf); ! 69: if (top == NIL) ! 70: top = t; ! 71: else ! 72: np->n_flink = t; ! 73: t->n_blink = np; ! 74: np = t; ! 75: } ! 76: return(top); ! 77: } ! 78: ! 79: /* ! 80: * Turn a list of names into a string of the same names. ! 81: */ ! 82: ! 83: char * ! 84: detract(np) ! 85: register struct name *np; ! 86: { ! 87: register int s; ! 88: register char *cp, *top; ! 89: register struct name *p; ! 90: ! 91: if (np == NIL) ! 92: return(NOSTR); ! 93: s = 0; ! 94: for (p = np; p != NIL; p = p->n_flink) ! 95: s += strlen(p->n_name) + 1; ! 96: s += 2; ! 97: top = salloc(s); ! 98: cp = top; ! 99: for (p = np; p != NIL; p = p->n_flink) { ! 100: cp = copy(p->n_name, cp); ! 101: *cp++ = ' '; ! 102: } ! 103: *--cp = 0; ! 104: return(top); ! 105: } ! 106: ! 107: /* ! 108: * Grab a single word (liberal word) ! 109: * Throw away things between ()'s. ! 110: */ ! 111: ! 112: char * ! 113: yankword(ap, wbuf) ! 114: char *ap, wbuf[]; ! 115: { ! 116: register char *cp, *cp2; ! 117: ! 118: do { ! 119: for (cp = ap; *cp && any(*cp, " \t"); cp++) ! 120: ; ! 121: if (*cp == '(') { ! 122: while (*cp && *cp != ')') ! 123: cp++; ! 124: if (*cp) ! 125: cp++; ! 126: } ! 127: if (*cp == '\0') ! 128: return(NOSTR); ! 129: } while (any(*cp, " \t(")); ! 130: for (cp2 = wbuf; *cp && !any(*cp, " \t("); *cp2++ = *cp++) ! 131: ; ! 132: *cp2 = '\0'; ! 133: return(cp); ! 134: } ! 135: ! 136: /* ! 137: * Verify that all the users in the list of names are ! 138: * legitimate. Bitch about and delink those who aren't. ! 139: */ ! 140: ! 141: struct name * ! 142: verify(names) ! 143: struct name *names; ! 144: { ! 145: register struct name *np, *top, *t, *x; ! 146: ! 147: top = names; ! 148: np = names; ! 149: while (np != NIL) { ! 150: if (any(':', np->n_name) || getuserid(np->n_name) != -1 ! 151: || any('!', np->n_name) ! 152: || any('^', np->n_name) ! 153: || strcmp(np->n_name, "msgs") == 0) { ! 154: np = np->n_flink; ! 155: continue; ! 156: } ! 157: fprintf(stderr, "Can't send to %s\n", np->n_name); ! 158: senderr++; ! 159: if (np == top) { ! 160: top = np->n_flink; ! 161: if (top != NIL) ! 162: top->n_blink = NIL; ! 163: np = top; ! 164: continue; ! 165: } ! 166: x = np->n_blink; ! 167: t = np->n_flink; ! 168: x->n_flink = t; ! 169: if (t != NIL) ! 170: t->n_blink = x; ! 171: np = t; ! 172: } ! 173: return(top); ! 174: } ! 175: ! 176: /* ! 177: * For each recipient in the passed name list with a / ! 178: * in the name, append the message to the end of the named file ! 179: * and remove him from the recipient list. ! 180: * ! 181: * Recipients whose name begins with | are piped through the given ! 182: * program and removed. ! 183: */ ! 184: ! 185: struct name * ! 186: outof(names, fo, hp) ! 187: struct name *names; ! 188: FILE *fo; ! 189: struct header *hp; ! 190: { ! 191: register int c; ! 192: register struct name *np, *top, *t, *x; ! 193: long now; ! 194: char *date, *fname, *shell, *ctime(); ! 195: FILE *fout, *fin; ! 196: int ispipe, s, pid; ! 197: extern char tempEdit[]; ! 198: ! 199: top = names; ! 200: np = names; ! 201: time(&now); ! 202: date = ctime(&now); ! 203: while (np != NIL) { ! 204: if (!any('/', np->n_name) && np->n_name[0] != '|') { ! 205: np = np->n_flink; ! 206: continue; ! 207: } ! 208: ispipe = np->n_name[0] == '|'; ! 209: if (ispipe) ! 210: fname = np->n_name+1; ! 211: else ! 212: fname = expand(np->n_name); ! 213: ! 214: /* ! 215: * See if we have copied the complete message out yet. ! 216: * If not, do so. ! 217: */ ! 218: ! 219: if (image < 0) { ! 220: if ((fout = fopen(tempEdit, "a")) == NULL) { ! 221: perror(tempEdit); ! 222: senderr++; ! 223: goto cant; ! 224: } ! 225: image = open(tempEdit, 2); ! 226: unlink(tempEdit); ! 227: if (image < 0) { ! 228: perror(tempEdit); ! 229: senderr++; ! 230: goto cant; ! 231: } ! 232: else { ! 233: rewind(fo); ! 234: fprintf(fout, "From %s %s", myname, date); ! 235: puthead(hp, fout, GTO|GSUBJECT|GCC); ! 236: while ((c = getc(fo)) != EOF) ! 237: putc(c, fout); ! 238: putc('\n', fout); ! 239: fflush(fout); ! 240: if (ferror(fout)) ! 241: perror(tempEdit); ! 242: fclose(fout); ! 243: } ! 244: } ! 245: ! 246: /* ! 247: * Now either copy "image" to the desired file ! 248: * or give it as the standard input to the desired ! 249: * program as appropriate. ! 250: */ ! 251: ! 252: if (ispipe) { ! 253: wait(&s); ! 254: switch (pid = fork()) { ! 255: case 0: ! 256: if ((shell = value("SHELL")) == NOSTR) ! 257: shell = SHELL; ! 258: execl(shell, shell, "-c", fname, 0); ! 259: perror(shell); ! 260: exit(1); ! 261: break; ! 262: ! 263: case -1: ! 264: perror("fork"); ! 265: senderr++; ! 266: goto cant; ! 267: } ! 268: } ! 269: else { ! 270: if ((fout = fopen(fname, "a")) == NULL) { ! 271: perror(fname); ! 272: senderr++; ! 273: goto cant; ! 274: } ! 275: fin = Fdopen(image, "r"); ! 276: if (fin == NULL) { ! 277: fprintf(stderr, "Can't reopen image\n"); ! 278: fclose(fout); ! 279: senderr++; ! 280: goto cant; ! 281: } ! 282: rewind(fin); ! 283: while ((c = getc(fin)) != EOF) ! 284: putc(c, fout); ! 285: if (ferror(fout)) ! 286: senderr++, perror(fname); ! 287: fclose(fout); ! 288: fclose(fin); ! 289: } ! 290: ! 291: cant: ! 292: if (np == top) { ! 293: top = np->n_flink; ! 294: if (top != NIL) ! 295: top->n_blink = NIL; ! 296: np = top; ! 297: continue; ! 298: } ! 299: x = np->n_blink; ! 300: t = np->n_flink; ! 301: x->n_flink = t; ! 302: if (t != NIL) ! 303: t->n_blink = x; ! 304: np = t; ! 305: } ! 306: if (image >= 0) { ! 307: close(image); ! 308: image = -1; ! 309: } ! 310: return(top); ! 311: } ! 312: ! 313: /* ! 314: * Map all of the aliased users in the invoker's mailrc ! 315: * file and insert them into the list. ! 316: */ ! 317: ! 318: struct name * ! 319: usermap(names) ! 320: struct name *names; ! 321: { ! 322: register struct name *new, *np, *cp; ! 323: struct grouphead *gh; ! 324: struct group *gp; ! 325: register int metoo; ! 326: ! 327: new = NIL; ! 328: np = names; ! 329: metoo = (value("metoo") != NOSTR); ! 330: while (np != NIL) { ! 331: if (np->n_name[0] == '\\') { ! 332: while (*np->n_name == '\\') ! 333: (np->n_name)++; ! 334: cp = np->n_flink; ! 335: new = put(new, np); ! 336: np = cp; ! 337: continue; ! 338: } ! 339: if ((gh = findgroup(np->n_name)) != NOGRP) { ! 340: for (gp = gh->g_list; gp != NOGE; gp = gp->ge_link) { ! 341: if (!metoo && equal(gp->ge_name, myname)) ! 342: continue; ! 343: cp = nalloc(gp->ge_name); ! 344: new = put(new, cp); ! 345: } ! 346: np = np->n_flink; ! 347: continue; ! 348: } ! 349: else { ! 350: cp = np->n_flink; ! 351: new = put(new, np); ! 352: np = cp; ! 353: } ! 354: } ! 355: return(new); ! 356: } ! 357: ! 358: /* ! 359: * Compute the length of the passed name list and ! 360: * return it. ! 361: */ ! 362: ! 363: lengthof(name) ! 364: struct name *name; ! 365: { ! 366: register struct name *np; ! 367: register int c; ! 368: ! 369: for (c = 0, np = name; np != NIL; c++, np = np->n_flink) ! 370: ; ! 371: return(c); ! 372: } ! 373: ! 374: /* ! 375: * Concatenate the two passed name lists, return the result. ! 376: */ ! 377: ! 378: struct name * ! 379: cat(n1, n2) ! 380: struct name *n1, *n2; ! 381: { ! 382: register struct name *tail; ! 383: ! 384: if (n1 == NIL) ! 385: return(n2); ! 386: if (n2 == NIL) ! 387: return(n1); ! 388: tail = tailof(n1); ! 389: tail->n_flink = n2; ! 390: n2->n_blink = tail; ! 391: return(n1); ! 392: } ! 393: ! 394: /* ! 395: * Unpack the name list onto a vector of strings. ! 396: * Return an error if the name list won't fit. ! 397: */ ! 398: ! 399: char ** ! 400: unpack(np) ! 401: struct name *np; ! 402: { ! 403: register char **ap, **top; ! 404: register struct name *n; ! 405: char *cp; ! 406: char hbuf[10]; ! 407: int t, extra; ! 408: ! 409: n = np; ! 410: if ((t = lengthof(n)) == 0) ! 411: panic("No names to unpack"); ! 412: ! 413: /* ! 414: * Compute the number of extra arguments we will need. ! 415: * We need at least two extra -- one for "mail" and one for ! 416: * the terminating 0 pointer. Additional spots may be needed ! 417: * to pass along -r and -f to the host mailer. ! 418: */ ! 419: ! 420: extra = 2; ! 421: if (rflag != NOSTR) ! 422: extra += 2; ! 423: if (hflag) ! 424: extra += 2; ! 425: top = (char **) salloc((t + extra) * sizeof cp); ! 426: ap = top; ! 427: *ap++ = "mail"; ! 428: if (rflag != NOSTR) { ! 429: *ap++ = "-r"; ! 430: *ap++ = rflag; ! 431: } ! 432: if (hflag) { ! 433: *ap++ = "-h"; ! 434: sprintf(hbuf, "%d", hflag); ! 435: *ap++ = savestr(hbuf); ! 436: } ! 437: while (n != NIL) { ! 438: *ap++ = n->n_name; ! 439: n = n->n_flink; ! 440: } ! 441: *ap = NOSTR; ! 442: return(top); ! 443: } ! 444: ! 445: /* ! 446: * See if the user named himself as a destination ! 447: * for outgoing mail. If so, set the global flag ! 448: * selfsent so that we avoid removing his mailbox. ! 449: */ ! 450: ! 451: mechk(names) ! 452: struct name *names; ! 453: { ! 454: register struct name *np; ! 455: char myname[9]; ! 456: ! 457: if (getname(uid, myname) < 0) ! 458: return; ! 459: for (np = names; np != NIL; np = np->n_flink) ! 460: if (equal(myname, np->n_name)) { ! 461: selfsent++; ! 462: return; ! 463: } ! 464: } ! 465: ! 466: /* ! 467: * Remove all of the duplicates from the passed name list by ! 468: * insertion sorting them, then checking for dups. ! 469: * Return the head of the new list. ! 470: */ ! 471: ! 472: struct name * ! 473: elide(names) ! 474: struct name *names; ! 475: { ! 476: register struct name *np, *t, *new; ! 477: struct name *x; ! 478: ! 479: if (names == NIL) ! 480: return(NIL); ! 481: new = names; ! 482: np = names; ! 483: np = np->n_flink; ! 484: if (np != NIL) ! 485: np->n_blink = NIL; ! 486: new->n_flink = NIL; ! 487: while (np != NIL) { ! 488: t = new; ! 489: while (strcmp(t->n_name, np->n_name) > 0) { ! 490: if (t->n_flink == NIL) ! 491: break; ! 492: t = t->n_flink; ! 493: } ! 494: ! 495: /* ! 496: * If we ran out of t's, put the new entry after ! 497: * the current value of t. ! 498: */ ! 499: ! 500: if (strcmp(t->n_name, np->n_name) > 0) { ! 501: t->n_flink = np; ! 502: np->n_blink = t; ! 503: t = np; ! 504: np = np->n_flink; ! 505: t->n_flink = NIL; ! 506: continue; ! 507: } ! 508: ! 509: /* ! 510: * Otherwise, put the new entry in front of the ! 511: * current t. If at the front of the list, ! 512: * the new guy becomes the new head of the list. ! 513: */ ! 514: ! 515: if (t == new) { ! 516: t = np; ! 517: np = np->n_flink; ! 518: t->n_flink = new; ! 519: new->n_blink = t; ! 520: t->n_blink = NIL; ! 521: new = t; ! 522: continue; ! 523: } ! 524: ! 525: /* ! 526: * The normal case -- we are inserting into the ! 527: * middle of the list. ! 528: */ ! 529: ! 530: x = np; ! 531: np = np->n_flink; ! 532: x->n_flink = t; ! 533: x->n_blink = t->n_blink; ! 534: t->n_blink->n_flink = x; ! 535: t->n_blink = x; ! 536: } ! 537: ! 538: /* ! 539: * Now the list headed up by new is sorted. ! 540: * Go through it and remove duplicates. ! 541: */ ! 542: ! 543: np = new; ! 544: while (np != NIL) { ! 545: t = np; ! 546: while (t->n_flink!=NIL && equal(np->n_name,t->n_flink->n_name)) ! 547: t = t->n_flink; ! 548: if (t == np || t == NIL) { ! 549: np = np->n_flink; ! 550: continue; ! 551: } ! 552: ! 553: /* ! 554: * Now t points to the last entry with the same name ! 555: * as np. Make np point beyond t. ! 556: */ ! 557: ! 558: np->n_flink = t->n_flink; ! 559: if (t->n_flink != NIL) ! 560: t->n_flink->n_blink = np; ! 561: np = np->n_flink; ! 562: } ! 563: return(new); ! 564: } ! 565: ! 566: /* ! 567: * Put another node onto a list of names and return ! 568: * the list. ! 569: */ ! 570: ! 571: struct name * ! 572: put(list, node) ! 573: struct name *list, *node; ! 574: { ! 575: node->n_flink = list; ! 576: node->n_blink = NIL; ! 577: if (list != NIL) ! 578: list->n_blink = node; ! 579: return(node); ! 580: } ! 581: ! 582: /* ! 583: * Determine the number of elements in ! 584: * a name list and return it. ! 585: */ ! 586: ! 587: count(np) ! 588: register struct name *np; ! 589: { ! 590: register int c = 0; ! 591: ! 592: while (np != NIL) { ! 593: c++; ! 594: np = np->n_flink; ! 595: } ! 596: return(c); ! 597: } ! 598: ! 599: /* ! 600: * Delete the given name from a namelist. ! 601: */ ! 602: ! 603: struct name * ! 604: delname(np, name) ! 605: register struct name *np; ! 606: char name[]; ! 607: { ! 608: register struct name *p; ! 609: ! 610: for (p = np; p != NIL; p = p->n_flink) ! 611: if (equal(p->n_name, name)) { ! 612: if (p->n_blink == NIL) { ! 613: if (p->n_flink != NIL) ! 614: p->n_flink->n_blink = NIL; ! 615: np = p->n_flink; ! 616: continue; ! 617: } ! 618: if (p->n_flink == NIL) { ! 619: if (p->n_blink != NIL) ! 620: p->n_blink->n_flink = NIL; ! 621: continue; ! 622: } ! 623: p->n_blink->n_flink = p->n_flink; ! 624: p->n_flink->n_blink = p->n_blink; ! 625: } ! 626: return(np); ! 627: } ! 628: ! 629: /* ! 630: * Call the given routine on each element of the name ! 631: * list, replacing said value if need be. ! 632: */ ! 633: ! 634: mapf(np, from) ! 635: register struct name *np; ! 636: char *from; ! 637: { ! 638: register struct name *p; ! 639: ! 640: for (p = np; p != NIL; p = p->n_flink) ! 641: p->n_name = netmap(p->n_name, from); ! 642: } ! 643: ! 644: /* ! 645: * Pretty print a name list ! 646: * Uncomment it if you need it. ! 647: */ ! 648: ! 649: prettyprint(name) ! 650: struct name *name; ! 651: { ! 652: register struct name *np; ! 653: ! 654: np = name; ! 655: while (np != NIL) { ! 656: fprintf(stderr, "%s ", np->n_name); ! 657: np = np->n_flink; ! 658: } ! 659: fprintf(stderr, "\n"); ! 660: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.