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