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

Defined functions

count defined in line 626; used 3 times
delname defined in line 640; used 5 times
detract defined in line 115; used 4 times
elide defined in line 512; used 4 times
gexpand defined in line 401; used 3 times
isfileaddr defined in line 343; used 1 times
nalloc defined in line 51; used 10 times
outof defined in line 209; used 2 times
put defined in line 611; used 4 times
tailof defined in line 68; used 1 times
unpack defined in line 467; used 2 times
usermap defined in line 366; used 2 times
yankword defined in line 161; used 2 times

Defined variables

sccsid defined in line 35; never used
Last modified: 1992-10-22
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3707
Valid CSS Valid XHTML 1.0 Strict