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