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