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