Silence longjmp() warnings and one harmless unused warning
[s-mailx.git] / names.c
blob51d149f705ce2904f94b329d701827425c098d48
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"
48 #include <sys/stat.h>
49 #include <fcntl.h>
50 #include <time.h>
51 #include <unistd.h>
53 static struct name * tailof(struct name *name);
54 static struct name * extract1(char *line, enum gfield ntype,
55 char *separators, int copypfx);
56 static char * yankword(char *ap, char *wbuf, char *separators,
57 int copypfx);
58 static int same_name(char *n1, char *n2);
59 static struct name * gexpand(struct name *nlist, struct grouphead *gh,
60 int metoo, int ntype);
61 static struct name * put(struct name *list, struct name *node);
62 static struct name * delname(struct name *np, char *name);
65 * Allocate a single element of a name list,
66 * initialize its name field to the passed
67 * name and return it.
69 struct name *
70 nalloc(char *str, enum gfield ntype)
72 struct addrguts ag;
73 struct str in, out;
74 struct name *np;
76 np = (struct name*)salloc(sizeof *np);
77 np->n_flink = NULL;
78 np->n_blink = NULL;
79 np->n_type = ntype;
80 np->n_flags = 0;
82 (void)addrspec_with_guts((ntype & (GFULL|GSKIN|GREF)) != 0, str, &ag);
83 if ((ag.ag_n_flags & NAME_NAME_SALLOC) == 0) {
84 ag.ag_n_flags |= NAME_NAME_SALLOC;
85 ag.ag_skinned = savestr(ag.ag_skinned);
87 np->n_fullname = np->n_name = ag.ag_skinned;
88 np->n_flags = ag.ag_n_flags;
90 if (ntype & GFULL) {
91 if (ag.ag_ilen != ag.ag_slen) {
92 in.s = str;
93 in.l = ag.ag_ilen;
94 mime_fromhdr(&in, &out, TD_ISPR|TD_ICONV);
95 np->n_fullname = savestr(out.s);
96 free(out.s);
97 np->n_flags |= NAME_FULLNAME_SALLOC;
99 } else if (ntype & GREF) { /* TODO LEGACY */
100 /* TODO Unfortunately we had to skin GREFerences i.e. the
101 * TODO surrounding angle brackets have been stripped away.
102 * TODO Necessarily since otherwise the plain address check
103 * TODO fails due to them; insert them back so that valid
104 * TODO headers will be created */
105 np->n_fullname = np->n_name = str = salloc(ag.ag_slen + 2 + 1);
106 *(str++) = '<';
107 memcpy(str, ag.ag_skinned, ag.ag_slen);
108 str += ag.ag_slen;
109 *(str++) = '>';
110 *str = '\0';
112 return (np);
115 struct name *
116 ndup(struct name *np, enum gfield ntype)
118 struct name *nnp;
120 if ((ntype & (GFULL|GSKIN)) && (np->n_flags & NAME_SKINNED) == 0) {
121 nnp = nalloc(np->n_name, ntype);
122 goto jleave;
125 nnp = (struct name*)salloc(sizeof *np);
126 nnp->n_flink = nnp->n_blink = NULL;
127 nnp->n_type = ntype;
128 nnp->n_flags = (np->n_flags &
129 ~(NAME_NAME_SALLOC | NAME_FULLNAME_SALLOC)) |
130 NAME_NAME_SALLOC;
131 nnp->n_name = savestr(np->n_name);
132 if (np->n_name == np->n_fullname || (ntype & (GFULL|GSKIN)) == 0)
133 nnp->n_fullname = nnp->n_name;
134 else {
135 nnp->n_flags |= NAME_FULLNAME_SALLOC;
136 nnp->n_fullname = savestr(np->n_fullname);
138 jleave:
139 return (nnp);
143 * Find the tail of a list and return it.
145 static struct name *
146 tailof(struct name *name)
148 struct name *np;
150 np = name;
151 if (np == NULL)
152 return(NULL);
153 while (np->n_flink != NULL)
154 np = np->n_flink;
155 return(np);
159 * Extract a list of names from a line,
160 * and make a list of names from it.
161 * Return the list or NULL if none found.
163 struct name *
164 extract(char *line, enum gfield ntype)
166 return extract1(line, ntype, " \t,(", 0);
169 struct name *
170 sextract(char *line, enum gfield ntype)
172 if (line && strpbrk(line, ",\"\\(<"))
173 return extract1(line, ntype, ",", 1);
174 else
175 return extract(line, ntype);
178 struct name *
179 lextract(char *line, enum gfield ntype)
181 return (extract1(line, ntype, ",", 1));
184 static struct name *
185 extract1(char *line, enum gfield ntype, char *separators, int copypfx)
187 char *cp, *nbuf;
188 struct name *top, *np, *t;
190 if (line == NULL || *line == '\0')
191 return NULL;
192 top = NULL;
193 np = NULL;
194 cp = line;
195 nbuf = ac_alloc(strlen(line) + 1);
196 while ((cp = yankword(cp, nbuf, separators, copypfx)) != NULL) {
197 t = nalloc(nbuf, ntype);
198 if (top == NULL)
199 top = t;
200 else
201 np->n_flink = t;
202 t->n_blink = np;
203 np = t;
205 ac_free(nbuf);
206 return top;
210 * Turn a list of names into a string of the same names.
212 char *
213 detract(struct name *np, enum gfield ntype)
215 int s;
216 char *cp, *top;
217 struct name *p;
218 int comma;
220 comma = ntype & GCOMMA;
221 if (np == NULL)
222 return(NULL);
223 ntype &= ~GCOMMA;
224 s = 0;
225 if ((debug || value("debug")) && comma)
226 fprintf(stderr, catgets(catd, CATSET, 145,
227 "detract asked to insert commas\n"));
228 for (p = np; p != NULL; p = p->n_flink) {
229 if (ntype && (p->n_type & GMASK) != ntype)
230 continue;
231 s += strlen(p->n_fullname) + 1;
232 if (comma)
233 s++;
235 if (s == 0)
236 return(NULL);
237 s += 2;
238 top = salloc(s);
239 cp = top;
240 for (p = np; p != NULL; p = p->n_flink) {
241 if (ntype && (p->n_type & GMASK) != ntype)
242 continue;
243 cp = sstpcpy(cp, p->n_fullname);
244 if (comma && p->n_flink != NULL)
245 *cp++ = ',';
246 *cp++ = ' ';
248 *--cp = 0;
249 if (comma && *--cp == ',')
250 *cp = 0;
251 return(top);
255 * Grab a single word (liberal word)
256 * Throw away things between ()'s, and take anything between <>.
257 * Strip trailing whitespace as *ap* may come directly from user.
259 static char *
260 yankword(char *ap, char *wbuf, char *separators, int copypfx)
262 char *cp, *pp, *wp;
264 cp = ap;
265 wp = wbuf;
266 while (blankspacechar(*cp) || *cp == ',')
267 ++cp;
268 pp = cp;
269 if ((cp = nexttoken(cp)) == NULL)
270 return NULL;
271 if (copypfx)
272 while (pp < cp)
273 *wp++ = *pp++;
274 if (*cp == '<')
275 while (*cp && (*wp++ = *cp++) != '>');
276 else {
277 int incomm = 0;
279 while (*cp && (incomm || !strchr(separators, *cp))) {
280 if (*cp == '\"') {
281 if (cp == ap || *(cp - 1) != '\\') {
282 if (incomm)
283 incomm--;
284 else
285 incomm++;
286 *wp++ = '\"';
287 } else if (cp != ap) {
288 *(wp - 1) = '\"';
290 cp++;
291 continue;
293 *wp++ = *cp++;
296 while (wp > wbuf && blankspacechar(wp[-1]))
297 --wp;
298 *wp = '\0';
299 return cp;
303 * Check all addresses in np and delete invalid ones.
305 struct name *
306 checkaddrs(struct name *np)
308 struct name *n;
310 for (n = np; n != NULL;) {
311 if (is_addr_invalid(n, 1)) {
312 if (n->n_blink)
313 n->n_blink->n_flink = n->n_flink;
314 if (n->n_flink)
315 n->n_flink->n_blink = n->n_blink;
316 if (n == np)
317 np = n->n_flink;
319 n = n->n_flink;
321 return (np);
325 * For each recipient in the passed name list with a /
326 * in the name, append the message to the end of the named file
327 * and remove him from the recipient list.
329 * Recipients whose name begins with | are piped through the given
330 * program and removed.
332 struct name *
333 outof(struct name *names, FILE *fo, struct header *hp)
335 int pipecnt, xcnt, *fda, i;
336 char *shell, *date;
337 struct name *np;
338 time_t now;
339 FILE *fin = NULL, *fout;
340 (void)hp;
343 * Look through all recipients and do a quick return if no file or pipe
344 * addressee is found.
346 fda = NULL; /* Silence cc */
347 for (pipecnt = xcnt = 0, np = names; np != NULL; np = np->n_flink)
348 switch (np->n_flags & NAME_ADDRSPEC_ISFILEORPIPE) {
349 case NAME_ADDRSPEC_ISFILE:
350 ++xcnt;
351 break;
352 case NAME_ADDRSPEC_ISPIPE:
353 ++pipecnt;
354 break;
356 if (pipecnt == 0 && xcnt == 0)
357 goto jleave;
360 * Otherwise create an array of file descriptors for each found pipe
361 * addressee to get around the dup(2)-shared-file-offset problem, i.e.,
362 * each pipe subprocess needs its very own file descriptor, and we need
363 * to deal with that.
364 * To make our life a bit easier let's just use the auto-reclaimed
365 * string storage.
367 if (pipecnt == 0) {
368 fda = NULL;
369 shell = NULL;
370 } else {
371 fda = (int*)salloc(sizeof(int) * pipecnt);
372 for (i = 0; i < pipecnt; ++i)
373 fda[i] = -1;
374 if ((shell = value("SHELL")) == NULL)
375 shell = SHELL;
378 time(&now);
379 date = ctime(&now);
381 for (np = names; np != NULL;) {
382 if ((np->n_flags & (NAME_ADDRSPEC_ISFILE|NAME_ADDRSPEC_ISPIPE))
383 == 0) {
384 np = np->n_flink;
385 continue;
389 * See if we have copied the complete message out yet.
390 * If not, do so.
392 if (image < 0) {
393 int c;
394 char *tempEdit;
396 if ((fout = Ftemp(&tempEdit, "Re", "w", 0600, 1))
397 == NULL) {
398 perror(tr(146, "Creation of temporary image"));
399 ++senderr;
400 goto jcant;
402 image = open(tempEdit, O_RDWR);
403 if (image >= 0)
404 for (i = 0; i < pipecnt; ++i) {
405 int fd = open(tempEdit, O_RDONLY);
406 if (fd < 0) {
407 (void)close(image);
408 image = -1;
409 pipecnt = i;
410 break;
412 fda[i] = fd;
413 (void)fcntl(fd, F_SETFD, FD_CLOEXEC);
415 unlink(tempEdit);
416 Ftfree(&tempEdit);
417 if (image < 0) {
418 perror(tr(147, "Creating descriptor duplicate "
419 "of temporary image"));
420 ++senderr;
421 Fclose(fout);
422 goto jcant;
424 fcntl(image, F_SETFD, FD_CLOEXEC);
426 fprintf(fout, "From %s %s", myname, date);
427 c = EOF;
428 while (i = c, (c = getc(fo)) != EOF)
429 putc(c, fout);
430 rewind(fo);
431 if (i != '\n')
432 putc('\n', fout);
433 putc('\n', fout);
434 fflush(fout);
435 if (ferror(fout))
436 perror(tr(148, "Finalizing write of temporary "
437 "image"));
438 Fclose(fout);
440 /* If we have to serve file addressees, open reader */
441 if (xcnt != 0 && (fin = Fdopen(image, "r")) == NULL) {
442 perror(tr(149, "Failed to open a duplicate of "
443 "the temporary image"));
444 ++senderr;
445 (void)close(image);
446 image = -1;
447 goto jcant;
450 /* From now on use xcnt as a counter for pipecnt */
451 xcnt = 0;
455 * Now either copy "image" to the desired file
456 * or give it as the standard input to the desired
457 * program as appropriate.
460 if (np->n_flags & NAME_ADDRSPEC_ISPIPE) {
461 int pid;
462 sigset_t nset;
464 sigemptyset(&nset);
465 sigaddset(&nset, SIGHUP);
466 sigaddset(&nset, SIGINT);
467 sigaddset(&nset, SIGQUIT);
468 pid = start_command(shell, &nset,
469 fda[xcnt++], -1, "-c", np->n_name + 1, NULL);
470 if (pid < 0) {
471 ++senderr;
472 goto jcant;
474 free_child(pid);
475 } else {
476 char *fname = expand(np->n_name);
477 if ((fout = Zopen(fname, "a", NULL)) == NULL) {
478 perror(fname);
479 ++senderr;
480 goto jcant;
482 rewind(fin);
483 while ((i = getc(fin)) != EOF)
484 putc(i, fout);
485 if (ferror(fout)) {
486 ++senderr;
487 perror(fname);
489 Fclose(fout);
491 jcant:
493 * In days of old we removed the entry from the
494 * the list; now for sake of header expansion
495 * we leave it in and mark it as deleted.
497 np->n_type |= GDEL;
498 np = np->n_flink;
499 if (image < 0)
500 goto jdelall;
502 jleave:
503 if (fin != NULL)
504 Fclose(fin);
505 for (i = 0; i < pipecnt; ++i)
506 (void)close(fda[i]);
507 if (image >= 0) {
508 close(image);
509 image = -1;
511 return (names);
513 jdelall:
514 while (np != NULL) {
515 if ((np->n_flags & (NAME_ADDRSPEC_ISFILE|NAME_ADDRSPEC_ISPIPE))
516 != 0)
517 np->n_type |= GDEL;
518 np = np->n_flink;
520 goto jleave;
523 static int
524 same_name(char *n1, char *n2)
526 int c1, c2;
528 if (value("allnet") != NULL) {
529 do {
530 c1 = (*n1++ & 0377);
531 c2 = (*n2++ & 0377);
532 c1 = lowerconv(c1);
533 c2 = lowerconv(c2);
534 if (c1 != c2)
535 return 0;
536 } while (c1 != '\0' && c2 != '\0' && c1 != '@' && c2 != '@');
537 return 1;
538 } else
539 return asccasecmp(n1, n2) == 0;
543 * Map all of the aliased users in the invoker's mailrc
544 * file and insert them into the list.
545 * Changed after all these months of service to recursively
546 * expand names (2/14/80).
549 struct name *
550 usermap(struct name *names)
552 struct name *new, *np, *cp;
553 struct grouphead *gh;
554 int metoo;
556 new = NULL;
557 np = names;
558 metoo = (value("metoo") != NULL);
559 while (np != NULL) {
560 if (np->n_name[0] == '\\') {
561 cp = np->n_flink;
562 new = put(new, np);
563 np = cp;
564 continue;
566 gh = findgroup(np->n_name);
567 cp = np->n_flink;
568 if (gh != NULL)
569 new = gexpand(new, gh, metoo, np->n_type);
570 else
571 new = put(new, np);
572 np = cp;
574 return(new);
578 * Recursively expand a group name. We limit the expansion to some
579 * fixed level to keep things from going haywire.
580 * Direct recursion is not expanded for convenience.
583 static struct name *
584 gexpand(struct name *nlist, struct grouphead *gh, int metoo, int ntype)
586 struct group *gp;
587 struct grouphead *ngh;
588 struct name *np;
589 static int depth;
590 char *cp;
592 if (depth > MAXEXP) {
593 printf(catgets(catd, CATSET, 150,
594 "Expanding alias to depth larger than %d\n"), MAXEXP);
595 return(nlist);
597 depth++;
598 for (gp = gh->g_list; gp != NULL; gp = gp->ge_link) {
599 cp = gp->ge_name;
600 if (*cp == '\\')
601 goto quote;
602 if (strcmp(cp, gh->g_name) == 0)
603 goto quote;
604 if ((ngh = findgroup(cp)) != NULL) {
605 nlist = gexpand(nlist, ngh, metoo, ntype);
606 continue;
608 quote:
609 np = nalloc(cp, ntype|GFULL);
611 * At this point should allow to expand
612 * to self if only person in group
614 if (gp == gh->g_list && gp->ge_link == NULL)
615 goto skip;
616 if (!metoo && same_name(cp, myname))
617 np->n_type |= GDEL;
618 skip:
619 nlist = put(nlist, np);
621 depth--;
622 return(nlist);
626 * Concatenate the two passed name lists, return the result.
628 struct name *
629 cat(struct name *n1, struct name *n2)
631 struct name *tail;
633 if (n1 == NULL)
634 return(n2);
635 if (n2 == NULL)
636 return(n1);
637 tail = tailof(n1);
638 tail->n_flink = n2;
639 n2->n_blink = tail;
640 return(n1);
644 * Unpack the name list onto a vector of strings.
645 * Return an error if the name list won't fit.
647 char **
648 unpack(struct name *np)
650 char **ap, **top;
651 struct name *n;
652 int t, extra, metoo, verbose;
654 n = np;
655 if ((t = count(n)) == 0)
656 panic(catgets(catd, CATSET, 151, "No names to unpack"));
658 * Compute the number of extra arguments we will need.
659 * We need at least two extra -- one for "mail" and one for
660 * the terminating 0 pointer. Additional spots may be needed
661 * to pass along -f to the host mailer.
663 extra = 2;
664 extra++;
665 metoo = value("metoo") != NULL;
666 if (metoo)
667 extra++;
668 verbose = value("verbose") != NULL;
669 if (verbose)
670 extra++;
671 /*LINTED*/
672 top = (char **)salloc((t + extra) * sizeof *top);
673 ap = top;
674 *ap++ = "send-mail";
675 *ap++ = "-i";
676 if (metoo)
677 *ap++ = "-m";
678 if (verbose)
679 *ap++ = "-v";
680 for (; n != NULL; n = n->n_flink)
681 if ((n->n_type & GDEL) == 0)
682 *ap++ = n->n_name;
683 *ap = NULL;
684 return(top);
688 * Remove all of the duplicates from the passed name list by
689 * insertion sorting them, then checking for dups.
690 * Return the head of the new list.
692 struct name *
693 elide(struct name *names)
695 struct name *np, *t, *newn, *x;
697 if (names == NULL)
698 return (NULL);
699 /* Throw away all deleted nodes (XXX merge with plain sort below?) */
700 for (np = NULL; names != NULL; names = names->n_flink)
701 if ((names->n_type & GDEL) == 0) {
702 names->n_blink = np;
703 if (np)
704 np->n_flink = names;
705 else
706 newn = names;
707 np = names;
709 if (newn == NULL)
710 return (NULL);
712 np = newn->n_flink;
713 if (np != NULL)
714 np->n_blink = NULL;
715 newn->n_flink = NULL;
717 while (np != NULL) {
718 t = newn;
719 while (asccasecmp(t->n_name, np->n_name) < 0) {
720 if (t->n_flink == NULL)
721 break;
722 t = t->n_flink;
726 * If we ran out of t's, put the new entry after
727 * the current value of t.
730 if (asccasecmp(t->n_name, np->n_name) < 0) {
731 t->n_flink = np;
732 np->n_blink = t;
733 t = np;
734 np = np->n_flink;
735 t->n_flink = NULL;
736 continue;
740 * Otherwise, put the new entry in front of the
741 * current t. If at the front of the list,
742 * the new guy becomes the new head of the list.
745 if (t == newn) {
746 t = np;
747 np = np->n_flink;
748 t->n_flink = newn;
749 newn->n_blink = t;
750 t->n_blink = NULL;
751 newn = t;
752 continue;
756 * The normal case -- we are inserting into the
757 * middle of the list.
760 x = np;
761 np = np->n_flink;
762 x->n_flink = t;
763 x->n_blink = t->n_blink;
764 t->n_blink->n_flink = x;
765 t->n_blink = x;
769 * Now the list headed up by new is sorted.
770 * Go through it and remove duplicates.
773 np = newn;
774 while (np != NULL) {
775 t = np;
776 while (t->n_flink != NULL &&
777 asccasecmp(np->n_name, t->n_flink->n_name) == 0)
778 t = t->n_flink;
779 if (t == np || t == NULL) {
780 np = np->n_flink;
781 continue;
785 * Now t points to the last entry with the same name
786 * as np. Make np point beyond t.
789 np->n_flink = t->n_flink;
790 if (t->n_flink != NULL)
791 t->n_flink->n_blink = np;
792 np = np->n_flink;
794 return (newn);
798 * Put another node onto a list of names and return
799 * the list.
801 static struct name *
802 put(struct name *list, struct name *node)
804 node->n_flink = list;
805 node->n_blink = NULL;
806 if (list != NULL)
807 list->n_blink = node;
808 return(node);
812 * Determine the number of undeleted elements in
813 * a name list and return it.
815 int
816 count(struct name *np)
818 int c;
820 for (c = 0; np != NULL; np = np->n_flink)
821 if ((np->n_type & GDEL) == 0)
822 c++;
823 return c;
827 * Delete the given name from a namelist.
829 static struct name *
830 delname(struct name *np, char *name)
832 struct name *p;
834 for (p = np; p != NULL; p = p->n_flink)
835 if (same_name(p->n_name, name)) {
836 if (p->n_blink == NULL) {
837 if (p->n_flink != NULL)
838 p->n_flink->n_blink = NULL;
839 np = p->n_flink;
840 continue;
842 if (p->n_flink == NULL) {
843 if (p->n_blink != NULL)
844 p->n_blink->n_flink = NULL;
845 continue;
847 p->n_blink->n_flink = p->n_flink;
848 p->n_flink->n_blink = p->n_blink;
850 return np;
854 * Pretty print a name list
855 * Uncomment it if you need it.
859 void
860 prettyprint(struct name *name)
862 struct name *np;
864 np = name;
865 while (np != NULL) {
866 fprintf(stderr, "%s(%d) ", np->n_name, np->n_type);
867 np = np->n_flink;
869 fprintf(stderr, "\n");
873 struct name *
874 delete_alternates(struct name *np)
876 struct name *xp;
877 char **ap;
879 np = delname(np, myname);
880 if (altnames)
881 for (ap = altnames; *ap; ap++)
882 np = delname(np, *ap);
883 if ((xp = sextract(value("from"), GEXTRA|GSKIN)) != NULL)
884 while (xp) {
885 np = delname(np, xp->n_name);
886 xp = xp->n_flink;
888 if ((xp = sextract(value("replyto"), GEXTRA|GSKIN)) != NULL)
889 while (xp) {
890 np = delname(np, xp->n_name);
891 xp = xp->n_flink;
893 if ((xp = sextract(value("sender"), GEXTRA|GSKIN)) != NULL)
894 while (xp) {
895 np = delname(np, xp->n_name);
896 xp = xp->n_flink;
898 return np;
902 is_myname(char *name)
904 struct name *xp;
905 char **ap;
907 if (same_name(myname, name))
908 return 1;
909 if (altnames)
910 for (ap = altnames; *ap; ap++)
911 if (same_name(*ap, name))
912 return 1;
913 if ((xp = sextract(value("from"), GEXTRA|GSKIN)) != NULL)
914 while (xp) {
915 if (same_name(xp->n_name, name))
916 return 1;
917 xp = xp->n_flink;
919 if ((xp = sextract(value("replyto"), GEXTRA|GSKIN)) != NULL)
920 while (xp) {
921 if (same_name(xp->n_name, name))
922 return 1;
923 xp = xp->n_flink;
925 if ((xp = sextract(value("sender"), GEXTRA|GSKIN)) != NULL)
926 while (xp) {
927 if (same_name(xp->n_name, name))
928 return 1;
929 xp = xp->n_flink;
931 return 0;