|
|
1.1 root 1: #ident "@(#)names.c 1.5 'attmail mail(1) command'"
2: #ident "@(#)mailx:names.c 1.10.1.2"
3: /* Copyright (c) 1984 AT&T */
4: /* All Rights Reserved */
5:
6: /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
7: /* The copyright notice above does not evidence any */
8: /* actual or intended publication of such source code. */
9:
10: #ident "@(#)mailx:names.c 1.10.1.1"
11:
12: /*
13: * mailx -- a modified version of a University of California at Berkeley
14: * mail program
15: *
16: * Handle name lists.
17: */
18:
19: #include "rcv.h"
20:
21: static struct name *nalloc();
22: static int isfileaddr();
23: static int lengthof();
24: static struct name *gexpand();
25: static char *norm();
26: static struct name *put();
27:
28: /*
29: * Allocate a single element of a name list,
30: * initialize its name field to the passed
31: * name and return it.
32: */
33:
34: static struct name *
35: nalloc(str)
36: char str[];
37: {
38: register struct name *np;
39:
40: np = (struct name *) salloc(sizeof *np);
41: np->n_flink = NIL;
42: np->n_blink = NIL;
43: np->n_type = -1;
44: np->n_full = savestr(str);
45: np->n_name = skin(np->n_full);
46: return(np);
47: }
48:
49: /*
50: * Find the tail of a list and return it.
51: */
52:
53: struct name *
54: tailof(name)
55: struct name *name;
56: {
57: register struct name *np;
58:
59: np = name;
60: if (np == NIL)
61: return(NIL);
62: while (np->n_flink != NIL)
63: np = np->n_flink;
64: return(np);
65: }
66:
67: /*
68: * Extract a list of names from a line,
69: * and make a list of names from it.
70: * Return the list or NIL if none found.
71: */
72:
73: struct name *
74: extract(line, arg_ntype)
75: char line[];
76: {
77: short ntype = (short)arg_ntype;
78: register char *cp;
79: register struct name *top, *np, *t;
80: char nbuf[BUFSIZ], abuf[BUFSIZ];
81: int comma;
82:
83: if (line == NOSTR || strlen(line) == 0)
84: return(NIL);
85: comma = docomma(line);
86: top = NIL;
87: np = NIL;
88: cp = line;
89: while ((cp = yankword(cp, nbuf, comma)) != NOSTR) {
90: if (np != NIL && equal(nbuf, "at")) {
91: strcpy(abuf, nbuf);
92: if ((cp = yankword(cp, nbuf, comma)) == NOSTR) {
93: strcpy(nbuf, abuf);
94: goto normal;
95: }
96: strcpy(abuf, np->n_name);
97: strcat(abuf, "@");
98: strcat(abuf, nbuf);
99: np->n_name = savestr(abuf);
100: continue;
101: }
102: normal:
103: t = nalloc(nbuf);
104: t->n_type = ntype;
105: if (top == NIL)
106: top = t;
107: else
108: np->n_flink = t;
109: t->n_blink = np;
110: np = t;
111: }
112: return(top);
113: }
114:
115: /*
116: * Turn a list of names into a string of the same names.
117: */
118:
119: char *
120: detract(np, ntype)
121: register struct name *np;
122: {
123: register int s;
124: register char *cp, *top;
125: register struct name *p;
126:
127: if (np == NIL)
128: return(NOSTR);
129: s = 0;
130: for (p = np; p != NIL; p = p->n_flink) {
131: if ((ntype && (p->n_type & GMASK) != ntype)
132: || (p->n_type & GDEL))
133: continue;
134: s += strlen(p->n_full) + 2;
135: }
136: if (s == 0)
137: return(NOSTR);
138: top = salloc((unsigned)(++s));
139: cp = top;
140: for (p = np; p != NIL; p = p->n_flink) {
141: if ((ntype && (p->n_type & GMASK) != ntype)
142: || (p->n_type & GDEL))
143: continue;
144: cp = copy(p->n_full, cp);
145: *cp++ = ',';
146: *cp++ = ' ';
147: }
148: *cp = 0;
149: return(top);
150: }
151:
152: struct name *
153: outpre(to)
154: struct name *to;
155: {
156: register struct name *np;
157:
158: for (np = to; np; np = np->n_flink)
159: if (any(*np->n_name, "+|"))
160: np->n_type |= GDEL;
161: return to;
162: }
163:
164: /*
165: * For each recipient in the passed name list with a /
166: * in the name, append the message to the end of the named file
167: * and remove him from the recipient list.
168: *
169: * Recipients whose name begins with | are piped through the given
170: * program and removed.
171: */
172:
173: int
174: outof(names, fo)
175: struct name *names;
176: FILE *fo;
177: {
178: register int c;
179: register struct name *np;
180: long now;
181: char *date, *fname, *shell;
182: FILE *fout, *fin;
183: int ispipe, s;
184: char line[BUFSIZ];
185: int nout = 0;
186:
187: for (np = names; np != NIL; np = np->n_flink) {
188: if (!isfileaddr(np->n_name) && np->n_name[0] != '|')
189: continue;
190: nout++;
191: ispipe = np->n_name[0] == '|';
192: if (ispipe)
193: fname = np->n_name+1;
194: else
195: fname = expand(np->n_name);
196:
197: /*
198: * See if we have copied the complete message out yet.
199: * If not, do so.
200: */
201:
202: if (image < 0) {
203: if ((fout = fopen(tempEdit, "a")) == NULL) {
204: perror(tempEdit);
205: senderr++;
206: goto cant;
207: }
208: image = open(tempEdit, 2); /* adb */
209: unlink(tempEdit);
210: if (image < 0) {
211: perror(tempEdit);
212: senderr++;
213: goto cant;
214: }
215: else {
216: rewind(fo);
217: time(&now);
218: date = ctime(&now);
219: fprintf(fout, "From %s %s", myname, date);
220: while ((c = getc(fo)) != EOF)
221: putc(c, fout);
222: rewind(fo);
223: fflush(fout);
224: if (ferror(fout))
225: perror(tempEdit);
226: fclose(fout);
227: }
228: }
229:
230: /*
231: * Now either copy "image" to the desired file
232: * or give it as the standard input to the desired
233: * program as appropriate.
234: */
235:
236: if (ispipe) {
237: wait(&s);
238: switch (fork()) {
239: case 0:
240: sigchild();
241: sigset(SIGHUP, SIG_IGN);
242: sigset(SIGINT, SIG_IGN);
243: sigset(SIGQUIT, SIG_IGN);
244: close(0);
245: dup(image);
246: close(image);
247: lseek(0, 0L, 0);
248: if ((shell = value("SHELL")) == NOSTR || *shell=='\0')
249: shell = SHELL;
250: execlp(shell, shell, "-c", fname, (char *)0);
251: perror(shell);
252: exit(1);
253: break;
254:
255: case (pid_t)-1:
256: perror("fork");
257: senderr++;
258: goto cant;
259: }
260: }
261: else {
262: if ((fout = fopen(fname, "a")) == NULL) {
263: perror(fname);
264: senderr++;
265: goto cant;
266: }
267: fin = Fdopen(image, "r");
268: if (fin == NULL) {
269: fprintf(stderr, "Can't reopen image\n");
270: fclose(fout);
271: senderr++;
272: goto cant;
273: }
274: rewind(fin);
275: putc(getc(fin), fout);
276: while (fgets(line, sizeof line, fin)) {
277: if (!strncmp(line, "From ", 5))
278: putc('>', fout);
279: fputs(line, fout);
280: }
281: putc('\n', fout);
282: if (ferror(fout))
283: senderr++, perror(fname);
284: fclose(fout);
285: fclose(fin);
286: }
287: cant:
288: /*
289: * In days of old we removed the entry from the
290: * the list; now for sake of header expansion
291: * we leave it in and mark it as deleted.
292: */
293:
294: #ifdef CRAZYWOW
295: if (np == top) {
296: top = np->n_flink;
297: if (top != NIL)
298: top->n_blink = NIL;
299: np = top;
300: continue;
301: }
302: x = np->n_blink;
303: t = np->n_flink;
304: x->n_flink = t;
305: if (t != NIL)
306: t->n_blink = x;
307: np = t;
308: #endif
309:
310: np->n_type |= GDEL;
311: }
312: if (image >= 0) {
313: close(image);
314: image = -1;
315: }
316: return(nout);
317: }
318:
319: /*
320: * Determine if the passed address is a local "send to file" address.
321: * If any of the network metacharacters precedes any slashes, it can't
322: * be a filename. We cheat with .'s to allow path names like ./...
323: */
324: static int
325: isfileaddr(name)
326: char *name;
327: {
328: register char *cp;
329:
330: if (any('@', name))
331: return(0);
332: if (*name == '+')
333: return(1);
334: for (cp = name; *cp; cp++) {
335: if (*cp == '.')
336: continue;
337: if (any(*cp, metanet))
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: static struct name *
388: gexpand(nlist, gh, metoo, arg_ntype)
389: struct name *nlist;
390: struct grouphead *gh;
391: {
392: short ntype = (short)arg_ntype;
393: struct mgroup *gp;
394: struct grouphead *ngh;
395: struct name *np;
396: static int depth;
397: char *cp;
398:
399: if (depth > MAXEXP) {
400: printf("Expanding alias to depth larger than %d\n", MAXEXP);
401: return(nlist);
402: }
403: depth++;
404: for (gp = gh->g_list; gp != NOGE; gp = gp->ge_link) {
405: cp = gp->ge_name;
406: if (*cp == '\\')
407: goto quote;
408: if (strcmp(cp, gh->g_name) == 0)
409: goto quote;
410: if ((ngh = findgroup(cp)) != NOGRP) {
411: nlist = gexpand(nlist, ngh, metoo, ntype);
412: continue;
413: }
414: quote:
415: np = nalloc(cp);
416: np->n_type = ntype;
417: /*
418: * At this point should allow to expand
419: * to self if only person in group
420: */
421: if (gp == gh->g_list && gp->ge_link == NOGE)
422: goto skip;
423: if (!metoo && samebody(myname, gp->ge_name))
424: np->n_type |= GDEL;
425: skip:
426: nlist = put(nlist, np);
427: }
428: depth--;
429: return(nlist);
430: }
431:
432: /*
433: * Normalize a network name for comparison purposes.
434: */
435: static char *
436: norm(user, ubuf, nbangs)
437: register char *user, *ubuf;
438: {
439: register char *cp;
440:
441: while (*user++ == '!');
442: user--;
443: if (!strchr(user, '!')) {
444: sprintf(ubuf, "%s!%s", host, user);
445: user = ubuf;
446: }
447: if (nbangs) {
448: cp = user + strlen(user);
449: while (nbangs--)
450: while (cp > user && *--cp != '!');
451: user = (cp > user) ? ++cp : cp;
452: }
453: return user;
454: }
455:
456: /*
457: * Implement allnet options.
458: */
459: samebody(user, addr)
460: register char *user, *addr;
461: {
462: char ubuf[500], abuf[500];
463: char *allnet = value("allnet");
464: int nbangs = allnet ? !strcmp(allnet, "uucp") ? 2 : 1 : 0;
465:
466: if( strcmp(allnet, "header") == 0) { /* adb */
467: /* match user string anywhere in header, case-independent */ /* adb */
468: return icsubstr(addr, user); /* adb */
469: } /* adb */
470: user = norm(user, ubuf, nbangs);
471: addr = norm(addr, abuf, nbangs);
472: return strcmp(user, addr) == 0;
473: }
474:
475: /*
476: * Compute the length of the passed name list and
477: * return it.
478: */
479: static int
480: lengthof(name)
481: struct name *name;
482: {
483: register struct name *np;
484: register int c;
485:
486: for (c = 0, np = name; np != NIL; c++, np = np->n_flink)
487: ;
488: return(c);
489: }
490:
491: /*
492: * Concatenate the two passed name lists, return the result.
493: */
494:
495: struct name *
496: cat(n1, n2)
497: struct name *n1, *n2;
498: {
499: register struct name *tail;
500:
501: if (n1 == NIL)
502: return(n2);
503: if (n2 == NIL)
504: return(n1);
505: tail = tailof(n1);
506: tail->n_flink = n2;
507: n2->n_blink = tail;
508: return(n1);
509: }
510:
511: /*
512: * Unpack the name list onto a vector of strings.
513: * Return an error if the name list won't fit.
514: */
515:
516: char **
517: unpack(np)
518: struct name *np;
519: {
520: register char **ap, **top;
521: register struct name *n;
522: char hbuf[10];
523: int t, extra;
524: #ifdef DELIVERMAIL
525: int metoo;
526: #endif
527:
528: n = np;
529: if ((t = lengthof(n)) == 0)
530: panic("No names to unpack");
531:
532: /*
533: * Compute the number of extra arguments we will need.
534: * We need at least 2 extra -- one for "mail" and one for
535: * the terminating 0 pointer.
536: * Additional spots may be needed to pass along -r and -f to
537: * the host mailer.
538: */
539:
540: extra = 2;
541:
542: if (rflag != NOSTR)
543: extra += 2;
544: #ifdef DELIVERMAIL
545: extra++;
546: metoo = value("metoo") != NOSTR;
547: if (metoo)
548: extra++;
549: #endif /* DELIVERMAIL */
550: if (hflag)
551: extra += 2;
552: top = (char **) salloc((t + extra) * sizeof (char *));
553: ap = top;
554: *ap++ = "mail";
555: if (rflag != NOSTR) {
556: *ap++ = "-r";
557: *ap++ = rflag;
558: }
559: #ifdef DELIVERMAIL
560: *ap++ = "-i";
561: if (metoo)
562: *ap++ = "-m";
563: #endif /* DELIVERMAIL */
564: if (hflag) {
565: *ap++ = "-h";
566: sprintf(hbuf, "%d", hflag);
567: *ap++ = savestr(hbuf);
568: }
569: while (n != NIL) {
570: if (n->n_type & GDEL) {
571: n = n->n_flink;
572: continue;
573: }
574: *ap++ = n->n_name;
575: n = n->n_flink;
576: }
577: *ap = NOSTR;
578: return(top);
579: }
580:
581: /*
582: * See if the user named himself as a destination
583: * for outgoing mail. If so, set the global flag
584: * selfsent so that we avoid removing his mailbox.
585: */
586:
587: void
588: mechk(names)
589: struct name *names;
590: {
591: register struct name *np;
592:
593: for (np = names; np != NIL; np = np->n_flink)
594: if ((np->n_type & GDEL) == 0 && samebody(np->n_name, myname)) {
595: selfsent++;
596: return;
597: }
598: }
599:
600: /*
601: * Remove all of the duplicates from the passed name list by
602: * insertion sorting them, then checking for dups.
603: * Return the head of the new list.
604: */
605:
606: struct name *
607: elide(names)
608: struct name *names;
609: {
610: register struct name *np, *t, *new;
611: struct name *x;
612:
613: if (names == NIL)
614: return(NIL);
615: new = names;
616: np = names;
617: np = np->n_flink;
618: if (np != NIL)
619: np->n_blink = NIL;
620: new->n_flink = NIL;
621: while (np != NIL) {
622: t = new;
623: while (strcmp(t->n_name, np->n_name) < 0) {
624: if (t->n_flink == NIL)
625: break;
626: t = t->n_flink;
627: }
628:
629: /*
630: * If we ran out of t's, put the new entry after
631: * the current value of t.
632: */
633:
634: if (strcmp(t->n_name, np->n_name) < 0) {
635: t->n_flink = np;
636: np->n_blink = t;
637: t = np;
638: np = np->n_flink;
639: t->n_flink = NIL;
640: continue;
641: }
642:
643: /*
644: * Otherwise, put the new entry in front of the
645: * current t. If at the front of the list,
646: * the new guy becomes the new head of the list.
647: */
648:
649: if (t == new) {
650: t = np;
651: np = np->n_flink;
652: t->n_flink = new;
653: new->n_blink = t;
654: t->n_blink = NIL;
655: new = t;
656: continue;
657: }
658:
659: /*
660: * The normal case -- we are inserting into the
661: * middle of the list.
662: */
663:
664: x = np;
665: np = np->n_flink;
666: x->n_flink = t;
667: x->n_blink = t->n_blink;
668: t->n_blink->n_flink = x;
669: t->n_blink = x;
670: }
671:
672: /*
673: * Now the list headed up by new is sorted.
674: * Go through it and remove duplicates.
675: */
676:
677: np = new;
678: while (np != NIL) {
679: t = np;
680: while (t->n_flink!=NIL &&
681: strcmp(np->n_name, t->n_flink->n_name) == 0)
682: t = t->n_flink;
683: if (t == np || t == NIL) {
684: np = np->n_flink;
685: continue;
686: }
687:
688: /*
689: * Now t points to the last entry with the same name
690: * as np. Make np point beyond t.
691: */
692:
693: np->n_flink = t->n_flink;
694: if (t->n_flink != NIL)
695: t->n_flink->n_blink = np;
696: np = np->n_flink;
697: }
698: return(new);
699: }
700:
701: /*
702: * Put another node onto a list of names and return
703: * the list.
704: */
705:
706: static struct name *
707: put(list, node)
708: struct name *list, *node;
709: {
710: node->n_flink = list;
711: node->n_blink = NIL;
712: if (list != NIL)
713: list->n_blink = node;
714: return(node);
715: }
716:
717:
718: /*
719: * Delete the given name from a namelist.
720: */
721: struct name *
722: delname(np, name)
723: register struct name *np;
724: char name[];
725: {
726: register struct name *p;
727:
728: for (p = np; p != NIL; p = p->n_flink)
729: if (samebody(name, p->n_name)) {
730: if (p->n_blink == NIL) {
731: if (p->n_flink != NIL)
732: p->n_flink->n_blink = NIL;
733: np = p->n_flink;
734: continue;
735: }
736: if (p->n_flink == NIL) {
737: if (p->n_blink != NIL)
738: p->n_blink->n_flink = NIL;
739: continue;
740: }
741: p->n_blink->n_flink = p->n_flink;
742: p->n_flink->n_blink = p->n_blink;
743: }
744: return(np);
745: }
746:
747: /*
748: * Call the given routine on each element of the name
749: * list, replacing said value if need be.
750: */
751:
752: void
753: mapf(np, from)
754: register struct name *np;
755: char *from;
756: {
757: register struct name *p;
758:
759: if (debug) fprintf(stderr, "mapf %lx, %s\n", (long)np, from);
760: for (p = np; p != NIL; p = p->n_flink)
761: if ((p->n_type & GDEL) == 0) {
762: p->n_name = netmap(p->n_name, from);
763: p->n_full = splice(p->n_name, p->n_full);
764: }
765: if (debug) fprintf(stderr, "mapf %s done\n", from);
766: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.