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