outof(): Mail NULL fix..
[s-mailx.git] / names.c
blobc58cffb049aed315e3e1cfcc70910ba1a7ab7c8d
1 /*
2 * S-nail - a mail user agent derived from Berkeley Mail.
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 * Copyright (c) 2012 Steffen "Daode" Nurpmeso.
6 */
7 /*
8 * Copyright (c) 1980, 1993
9 * The Regents of the University of California. All rights reserved.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
41 * Mail -- a mail program
43 * Handle name lists.
46 #include "rcv.h"
47 #include "extern.h"
49 #include <errno.h>
51 #include <fcntl.h>
52 #include <time.h>
53 #include <unistd.h>
54 #include <sys/stat.h>
56 static struct name * tailof(struct name *name);
57 static struct name * extract1(char *line, enum gfield ntype,
58 char *separators, int copypfx);
59 static char * yankword(char *ap, char *wbuf, char *separators,
60 int copypfx);
61 static int same_name(char *n1, char *n2);
62 static struct name * gexpand(struct name *nlist, struct grouphead *gh,
63 int metoo, int ntype);
64 static struct name * put(struct name *list, struct name *node);
65 static struct name * delname(struct name *np, char *name);
68 * Allocate a single element of a name list,
69 * initialize its name field to the passed
70 * name and return it.
72 struct name *
73 nalloc(char *str, enum gfield ntype)
75 struct addrguts ag;
76 struct str in, out;
77 struct name *np;
79 np = (struct name*)salloc(sizeof *np);
80 np->n_flink = NULL;
81 np->n_blink = NULL;
82 np->n_type = ntype;
83 np->n_flags = 0;
85 (void)addrspec_with_guts((ntype & (GFULL|GSKIN|GREF)) != 0, str, &ag);
86 if ((ag.ag_n_flags & NAME_NAME_SALLOC) == 0) {
87 ag.ag_n_flags |= NAME_NAME_SALLOC;
88 ag.ag_skinned = savestr(ag.ag_skinned);
90 np->n_fullname = np->n_name = ag.ag_skinned;
91 np->n_flags = ag.ag_n_flags;
93 if (ntype & GFULL) {
94 if (ag.ag_ilen != ag.ag_slen) {
95 in.s = str;
96 in.l = ag.ag_ilen;
97 mime_fromhdr(&in, &out, TD_ISPR|TD_ICONV);
98 np->n_fullname = savestr(out.s);
99 free(out.s);
100 np->n_flags |= NAME_FULLNAME_SALLOC;
102 } else if (ntype & GREF) { /* TODO LEGACY */
103 /* TODO Unfortunately we had to skin GREFerences i.e. the
104 * TODO surrounding angle brackets have been stripped away.
105 * TODO Necessarily since otherwise the plain address check
106 * TODO fails due to them; insert them back so that valid
107 * TODO headers will be created */
108 np->n_fullname = np->n_name = str = salloc(ag.ag_slen + 2 + 1);
109 *(str++) = '<';
110 memcpy(str, ag.ag_skinned, ag.ag_slen);
111 str += ag.ag_slen;
112 *(str++) = '>';
113 *str = '\0';
115 return (np);
118 struct name *
119 ndup(struct name *np, enum gfield ntype)
121 struct name *nnp;
123 if ((ntype & (GFULL|GSKIN)) && (np->n_flags & NAME_SKINNED) == 0) {
124 nnp = nalloc(np->n_name, ntype);
125 goto jleave;
128 nnp = (struct name*)salloc(sizeof *np);
129 nnp->n_flink = nnp->n_blink = NULL;
130 nnp->n_type = ntype;
131 nnp->n_flags = (np->n_flags &
132 ~(NAME_NAME_SALLOC | NAME_FULLNAME_SALLOC)) |
133 NAME_NAME_SALLOC;
134 nnp->n_name = savestr(np->n_name);
135 if (np->n_name == np->n_fullname || (ntype & (GFULL|GSKIN)) == 0)
136 nnp->n_fullname = nnp->n_name;
137 else {
138 nnp->n_flags |= NAME_FULLNAME_SALLOC;
139 nnp->n_fullname = savestr(np->n_fullname);
141 jleave:
142 return (nnp);
146 * Find the tail of a list and return it.
148 static struct name *
149 tailof(struct name *name)
151 struct name *np;
153 np = name;
154 if (np == NULL)
155 return(NULL);
156 while (np->n_flink != NULL)
157 np = np->n_flink;
158 return(np);
162 * Extract a list of names from a line,
163 * and make a list of names from it.
164 * Return the list or NULL if none found.
166 struct name *
167 extract(char *line, enum gfield ntype)
169 return extract1(line, ntype, " \t,(", 0);
172 struct name *
173 sextract(char *line, enum gfield ntype)
175 if (line && strpbrk(line, ",\"\\(<"))
176 return extract1(line, ntype, ",", 1);
177 else
178 return extract(line, ntype);
181 struct name *
182 lextract(char *line, enum gfield ntype)
184 return (extract1(line, ntype, ",", 1));
187 static struct name *
188 extract1(char *line, enum gfield ntype, char *separators, int copypfx)
190 char *cp, *nbuf;
191 struct name *top, *np, *t;
193 if (line == NULL || *line == '\0')
194 return NULL;
195 top = NULL;
196 np = NULL;
197 cp = line;
198 nbuf = ac_alloc(strlen(line) + 1);
199 while ((cp = yankword(cp, nbuf, separators, copypfx)) != NULL) {
200 t = nalloc(nbuf, ntype);
201 if (top == NULL)
202 top = t;
203 else
204 np->n_flink = t;
205 t->n_blink = np;
206 np = t;
208 ac_free(nbuf);
209 return top;
213 * Turn a list of names into a string of the same names.
215 char *
216 detract(struct name *np, enum gfield ntype)
218 int s;
219 char *cp, *top;
220 struct name *p;
221 int comma;
223 comma = ntype & GCOMMA;
224 if (np == NULL)
225 return(NULL);
226 ntype &= ~GCOMMA;
227 s = 0;
228 if ((debug || value("debug")) && comma)
229 fprintf(stderr, catgets(catd, CATSET, 145,
230 "detract asked to insert commas\n"));
231 for (p = np; p != NULL; p = p->n_flink) {
232 if (ntype && (p->n_type & GMASK) != ntype)
233 continue;
234 s += strlen(p->n_fullname) + 1;
235 if (comma)
236 s++;
238 if (s == 0)
239 return(NULL);
240 s += 2;
241 top = salloc(s);
242 cp = top;
243 for (p = np; p != NULL; p = p->n_flink) {
244 if (ntype && (p->n_type & GMASK) != ntype)
245 continue;
246 cp = sstpcpy(cp, p->n_fullname);
247 if (comma && p->n_flink != NULL)
248 *cp++ = ',';
249 *cp++ = ' ';
251 *--cp = 0;
252 if (comma && *--cp == ',')
253 *cp = 0;
254 return(top);
258 * Grab a single word (liberal word)
259 * Throw away things between ()'s, and take anything between <>.
260 * Strip trailing whitespace as *ap* may come directly from user.
262 static char *
263 yankword(char *ap, char *wbuf, char *separators, int copypfx)
265 char *cp, *pp, *wp;
267 cp = ap;
268 wp = wbuf;
269 while (blankspacechar(*cp) || *cp == ',')
270 ++cp;
271 pp = cp;
272 if ((cp = (char*)nexttoken((char*)cp)) == NULL)
273 return NULL;
274 if (copypfx)
275 while (pp < cp)
276 *wp++ = *pp++;
277 if (*cp == '<')
278 while (*cp && (*wp++ = *cp++) != '>');
279 else {
280 int incomm = 0;
282 while (*cp && (incomm || !strchr(separators, *cp))) {
283 if (*cp == '\"') {
284 if (cp == ap || *(cp - 1) != '\\') {
285 if (incomm)
286 incomm--;
287 else
288 incomm++;
289 *wp++ = '\"';
290 } else if (cp != ap) {
291 *(wp - 1) = '\"';
293 cp++;
294 continue;
296 *wp++ = *cp++;
299 while (wp > wbuf && blankspacechar(wp[-1]))
300 --wp;
301 *wp = '\0';
302 return cp;
306 * Check all addresses in np and delete invalid ones.
308 struct name *
309 checkaddrs(struct name *np)
311 struct name *n;
313 for (n = np; n != NULL;) {
314 if (is_addr_invalid(n, 1)) {
315 if (n->n_blink)
316 n->n_blink->n_flink = n->n_flink;
317 if (n->n_flink)
318 n->n_flink->n_blink = n->n_blink;
319 if (n == np)
320 np = n->n_flink;
322 n = n->n_flink;
324 return (np);
328 * For each recipient in the passed name list with a /
329 * in the name, append the message to the end of the named file
330 * and remove him from the recipient list.
332 * Recipients whose name begins with | are piped through the given
333 * program and removed.
335 struct name *
336 outof(struct name *names, FILE *fo, struct header *hp)
338 int pipecnt, xcnt, *fda, i;
339 char *shell, *date;
340 struct name *np;
341 time_t now;
342 FILE *fin = NULL, *fout;
343 (void)hp;
346 * Look through all recipients and do a quick return if no file or pipe
347 * addressee is found.
349 fda = NULL; /* Silence cc */
350 for (pipecnt = xcnt = 0, np = names; np != NULL; np = np->n_flink)
351 switch (np->n_flags & NAME_ADDRSPEC_ISFILEORPIPE) {
352 case NAME_ADDRSPEC_ISFILE:
353 ++xcnt;
354 break;
355 case NAME_ADDRSPEC_ISPIPE:
356 ++pipecnt;
357 break;
359 if (pipecnt == 0 && xcnt == 0)
360 goto jleave;
363 * Otherwise create an array of file descriptors for each found pipe
364 * addressee to get around the dup(2)-shared-file-offset problem, i.e.,
365 * each pipe subprocess needs its very own file descriptor, and we need
366 * to deal with that.
367 * To make our life a bit easier let's just use the auto-reclaimed
368 * string storage.
370 if (pipecnt == 0) {
371 fda = NULL;
372 shell = NULL;
373 } else {
374 fda = (int*)salloc(sizeof(int) * pipecnt);
375 for (i = 0; i < pipecnt; ++i)
376 fda[i] = -1;
377 if ((shell = value("SHELL")) == NULL)
378 shell = SHELL;
381 time(&now);
382 date = ctime(&now);
384 for (np = names; np != NULL;) {
385 if ((np->n_flags & (NAME_ADDRSPEC_ISFILE|NAME_ADDRSPEC_ISPIPE))
386 == 0) {
387 np = np->n_flink;
388 continue;
392 * See if we have copied the complete message out yet.
393 * If not, do so.
395 if (image < 0) {
396 int c;
397 char *tempEdit;
399 if ((fout = Ftemp(&tempEdit, "Re", "w", 0600, 1))
400 == NULL) {
401 perror(tr(146, "Creation of temporary image"));
402 ++senderr;
403 goto jcant;
405 image = open(tempEdit, O_RDWR);
406 if (image >= 0)
407 for (i = 0; i < pipecnt; ++i) {
408 int fd = open(tempEdit, O_RDONLY);
409 if (fd < 0) {
410 (void)close(image);
411 image = -1;
412 pipecnt = i;
413 break;
415 fda[i] = fd;
416 (void)fcntl(fd, F_SETFD, FD_CLOEXEC);
418 unlink(tempEdit);
419 Ftfree(&tempEdit);
420 if (image < 0) {
421 perror(tr(147, "Creating descriptor duplicate "
422 "of temporary image"));
423 ++senderr;
424 Fclose(fout);
425 goto jcant;
427 fcntl(image, F_SETFD, FD_CLOEXEC);
429 fprintf(fout, "From %s %s", myname, date);
430 c = EOF;
431 while (i = c, (c = getc(fo)) != EOF)
432 putc(c, fout);
433 rewind(fo);
434 if (i != '\n')
435 putc('\n', fout);
436 putc('\n', fout);
437 fflush(fout);
438 if (ferror(fout)) {
439 perror(tr(148, "Finalizing write of temporary "
440 "image"));
441 Fclose(fout);
442 goto jcantfout;
444 Fclose(fout);
446 /* If we have to serve file addressees, open reader */
447 if (xcnt != 0 && (fin = Fdopen(image, "r")) == NULL) {
448 perror(tr(149, "Failed to open a duplicate of "
449 "the temporary image"));
450 jcantfout: ++senderr;
451 (void)close(image);
452 image = -1;
453 goto jcant;
456 /* From now on use xcnt as a counter for pipecnt */
457 xcnt = 0;
461 * Now either copy "image" to the desired file
462 * or give it as the standard input to the desired
463 * program as appropriate.
466 if (np->n_flags & NAME_ADDRSPEC_ISPIPE) {
467 int pid;
468 sigset_t nset;
470 sigemptyset(&nset);
471 sigaddset(&nset, SIGHUP);
472 sigaddset(&nset, SIGINT);
473 sigaddset(&nset, SIGQUIT);
474 pid = start_command(shell, &nset,
475 fda[xcnt++], -1, "-c", np->n_name + 1, NULL);
476 if (pid < 0) {
477 fprintf(stderr, tr(281,
478 "Message piping to <%s> failed\n"),
479 np->n_name);
480 ++senderr;
481 goto jcant;
483 free_child(pid);
484 } else {
485 char *fname = file_expand(np->n_name);
486 if (fname == NULL) {
487 fprintf(stderr, tr(81,
488 "\"%s\": Expansion failed.\n"),
489 np->n_name);
490 ++senderr;
491 goto jcant;
493 if ((fout = Zopen(fname, "a", NULL)) == NULL) {
494 fprintf(stderr, tr(282,
495 "Message writing to <%s> failed: %s\n"),
496 fname, strerror(errno));
497 ++senderr;
498 goto jcant;
500 rewind(fin);
501 while ((i = getc(fin)) != EOF)
502 putc(i, fout);
503 if (ferror(fout)) {
504 fprintf(stderr, tr(282,
505 "Message writing to <%s> failed: %s\n"),
506 fname, tr(283, "write error"));
507 ++senderr;
509 Fclose(fout);
511 jcant:
513 * In days of old we removed the entry from the
514 * the list; now for sake of header expansion
515 * we leave it in and mark it as deleted.
517 np->n_type |= GDEL;
518 np = np->n_flink;
519 if (image < 0)
520 goto jdelall;
522 jleave:
523 if (fin != NULL)
524 Fclose(fin);
525 for (i = 0; i < pipecnt; ++i)
526 (void)close(fda[i]);
527 if (image >= 0) {
528 close(image);
529 image = -1;
531 return (names);
533 jdelall:
534 while (np != NULL) {
535 if ((np->n_flags & (NAME_ADDRSPEC_ISFILE|NAME_ADDRSPEC_ISPIPE))
536 != 0)
537 np->n_type |= GDEL;
538 np = np->n_flink;
540 goto jleave;
543 static int
544 same_name(char *n1, char *n2)
546 int c1, c2;
548 if (value("allnet") != NULL) {
549 do {
550 c1 = (*n1++ & 0377);
551 c2 = (*n2++ & 0377);
552 c1 = lowerconv(c1);
553 c2 = lowerconv(c2);
554 if (c1 != c2)
555 return 0;
556 } while (c1 != '\0' && c2 != '\0' && c1 != '@' && c2 != '@');
557 return 1;
558 } else
559 return asccasecmp(n1, n2) == 0;
563 * Map all of the aliased users in the invoker's mailrc
564 * file and insert them into the list.
565 * Changed after all these months of service to recursively
566 * expand names (2/14/80).
569 struct name *
570 usermap(struct name *names)
572 struct name *new, *np, *cp;
573 struct grouphead *gh;
574 int metoo;
576 new = NULL;
577 np = names;
578 metoo = (value("metoo") != NULL);
579 while (np != NULL) {
580 if (np->n_name[0] == '\\') {
581 cp = np->n_flink;
582 new = put(new, np);
583 np = cp;
584 continue;
586 gh = findgroup(np->n_name);
587 cp = np->n_flink;
588 if (gh != NULL)
589 new = gexpand(new, gh, metoo, np->n_type);
590 else
591 new = put(new, np);
592 np = cp;
594 return(new);
598 * Recursively expand a group name. We limit the expansion to some
599 * fixed level to keep things from going haywire.
600 * Direct recursion is not expanded for convenience.
603 static struct name *
604 gexpand(struct name *nlist, struct grouphead *gh, int metoo, int ntype)
606 struct group *gp;
607 struct grouphead *ngh;
608 struct name *np;
609 static int depth;
610 char *cp;
612 if (depth > MAXEXP) {
613 printf(catgets(catd, CATSET, 150,
614 "Expanding alias to depth larger than %d\n"), MAXEXP);
615 return(nlist);
617 depth++;
618 for (gp = gh->g_list; gp != NULL; gp = gp->ge_link) {
619 cp = gp->ge_name;
620 if (*cp == '\\')
621 goto quote;
622 if (strcmp(cp, gh->g_name) == 0)
623 goto quote;
624 if ((ngh = findgroup(cp)) != NULL) {
625 nlist = gexpand(nlist, ngh, metoo, ntype);
626 continue;
628 quote:
629 np = nalloc(cp, ntype|GFULL);
631 * At this point should allow to expand
632 * to self if only person in group
634 if (gp == gh->g_list && gp->ge_link == NULL)
635 goto skip;
636 if (!metoo && same_name(cp, myname))
637 np->n_type |= GDEL;
638 skip:
639 nlist = put(nlist, np);
641 depth--;
642 return(nlist);
646 * Concatenate the two passed name lists, return the result.
648 struct name *
649 cat(struct name *n1, struct name *n2)
651 struct name *tail;
653 if (n1 == NULL)
654 return(n2);
655 if (n2 == NULL)
656 return(n1);
657 tail = tailof(n1);
658 tail->n_flink = n2;
659 n2->n_blink = tail;
660 return(n1);
664 * Unpack the name list onto a vector of strings.
665 * Return an error if the name list won't fit.
667 char **
668 unpack(struct name *np)
670 char **ap, **top;
671 struct name *n;
672 int t, extra, metoo, verbose;
674 n = np;
675 if ((t = count(n)) == 0)
676 panic(catgets(catd, CATSET, 151, "No names to unpack"));
678 * Compute the number of extra arguments we will need.
679 * We need at least two extra -- one for "mail" and one for
680 * the terminating 0 pointer. Additional spots may be needed
681 * to pass along -f to the host mailer.
683 extra = 2;
684 extra++;
685 metoo = value("metoo") != NULL;
686 if (metoo)
687 extra++;
688 verbose = value("verbose") != NULL;
689 if (verbose)
690 extra++;
691 /*LINTED*/
692 top = (char **)salloc((t + extra) * sizeof *top);
693 ap = top;
694 *ap++ = "send-mail";
695 *ap++ = "-i";
696 if (metoo)
697 *ap++ = "-m";
698 if (verbose)
699 *ap++ = "-v";
700 for (; n != NULL; n = n->n_flink)
701 if ((n->n_type & GDEL) == 0)
702 *ap++ = n->n_name;
703 *ap = NULL;
704 return(top);
708 * Remove all of the duplicates from the passed name list by
709 * insertion sorting them, then checking for dups.
710 * Return the head of the new list.
712 struct name *
713 elide(struct name *names)
715 struct name *np, *t, *newn, *x;
717 if (names == NULL)
718 return (NULL);
719 /* Throw away all deleted nodes (XXX merge with plain sort below?) */
720 for (newn = np = NULL; names != NULL; names = names->n_flink)
721 if ((names->n_type & GDEL) == 0) {
722 names->n_blink = np;
723 if (np)
724 np->n_flink = names;
725 else
726 newn = names;
727 np = names;
729 if (newn == NULL)
730 return (NULL);
732 np = newn->n_flink;
733 if (np != NULL)
734 np->n_blink = NULL;
735 newn->n_flink = NULL;
737 while (np != NULL) {
738 t = newn;
739 while (asccasecmp(t->n_name, np->n_name) < 0) {
740 if (t->n_flink == NULL)
741 break;
742 t = t->n_flink;
746 * If we ran out of t's, put the new entry after
747 * the current value of t.
750 if (asccasecmp(t->n_name, np->n_name) < 0) {
751 t->n_flink = np;
752 np->n_blink = t;
753 t = np;
754 np = np->n_flink;
755 t->n_flink = NULL;
756 continue;
760 * Otherwise, put the new entry in front of the
761 * current t. If at the front of the list,
762 * the new guy becomes the new head of the list.
765 if (t == newn) {
766 t = np;
767 np = np->n_flink;
768 t->n_flink = newn;
769 newn->n_blink = t;
770 t->n_blink = NULL;
771 newn = t;
772 continue;
776 * The normal case -- we are inserting into the
777 * middle of the list.
780 x = np;
781 np = np->n_flink;
782 x->n_flink = t;
783 x->n_blink = t->n_blink;
784 t->n_blink->n_flink = x;
785 t->n_blink = x;
789 * Now the list headed up by new is sorted.
790 * Go through it and remove duplicates.
793 np = newn;
794 while (np != NULL) {
795 t = np;
796 while (t->n_flink != NULL &&
797 asccasecmp(np->n_name, t->n_flink->n_name) == 0)
798 t = t->n_flink;
799 if (t == np || t == NULL) {
800 np = np->n_flink;
801 continue;
805 * Now t points to the last entry with the same name
806 * as np. Make np point beyond t.
809 np->n_flink = t->n_flink;
810 if (t->n_flink != NULL)
811 t->n_flink->n_blink = np;
812 np = np->n_flink;
814 return (newn);
818 * Put another node onto a list of names and return
819 * the list.
821 static struct name *
822 put(struct name *list, struct name *node)
824 node->n_flink = list;
825 node->n_blink = NULL;
826 if (list != NULL)
827 list->n_blink = node;
828 return(node);
832 * Determine the number of undeleted elements in
833 * a name list and return it.
835 int
836 count(struct name *np)
838 int c;
840 for (c = 0; np != NULL; np = np->n_flink)
841 if ((np->n_type & GDEL) == 0)
842 c++;
843 return c;
847 * Delete the given name from a namelist.
849 static struct name *
850 delname(struct name *np, char *name)
852 struct name *p;
854 for (p = np; p != NULL; p = p->n_flink)
855 if (same_name(p->n_name, name)) {
856 if (p->n_blink == NULL) {
857 if (p->n_flink != NULL)
858 p->n_flink->n_blink = NULL;
859 np = p->n_flink;
860 continue;
862 if (p->n_flink == NULL) {
863 if (p->n_blink != NULL)
864 p->n_blink->n_flink = NULL;
865 continue;
867 p->n_blink->n_flink = p->n_flink;
868 p->n_flink->n_blink = p->n_blink;
870 return np;
874 * Pretty print a name list
875 * Uncomment it if you need it.
879 void
880 prettyprint(struct name *name)
882 struct name *np;
884 np = name;
885 while (np != NULL) {
886 fprintf(stderr, "%s(%d) ", np->n_name, np->n_type);
887 np = np->n_flink;
889 fprintf(stderr, "\n");
893 struct name *
894 delete_alternates(struct name *np)
896 struct name *xp;
897 char **ap;
899 np = delname(np, myname);
900 if (altnames)
901 for (ap = altnames; *ap; ap++)
902 np = delname(np, *ap);
903 if ((xp = sextract(value("from"), GEXTRA|GSKIN)) != NULL)
904 while (xp) {
905 np = delname(np, xp->n_name);
906 xp = xp->n_flink;
908 if ((xp = sextract(value("replyto"), GEXTRA|GSKIN)) != NULL)
909 while (xp) {
910 np = delname(np, xp->n_name);
911 xp = xp->n_flink;
913 if ((xp = sextract(value("sender"), GEXTRA|GSKIN)) != NULL)
914 while (xp) {
915 np = delname(np, xp->n_name);
916 xp = xp->n_flink;
918 return np;
922 is_myname(char *name)
924 struct name *xp;
925 char **ap;
927 if (same_name(myname, name))
928 return 1;
929 if (altnames)
930 for (ap = altnames; *ap; ap++)
931 if (same_name(*ap, name))
932 return 1;
933 if ((xp = sextract(value("from"), GEXTRA|GSKIN)) != NULL)
934 while (xp) {
935 if (same_name(xp->n_name, name))
936 return 1;
937 xp = xp->n_flink;
939 if ((xp = sextract(value("replyto"), GEXTRA|GSKIN)) != NULL)
940 while (xp) {
941 if (same_name(xp->n_name, name))
942 return 1;
943 xp = xp->n_flink;
945 if ((xp = sextract(value("sender"), GEXTRA|GSKIN)) != NULL)
946 while (xp) {
947 if (same_name(xp->n_name, name))
948 return 1;
949 xp = xp->n_flink;
951 return 0;