addrspec_with_guts(): always set ag_skinned, also for NULL arg case
[s-mailx.git] / names.c
blob87ca3e7fe1810c1f5690b92b6d6d099037d5f43a
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 ((fout = Zopen(fname, "a", NULL)) == NULL) {
487 fprintf(stderr, tr(282,
488 "Message writing to <%s> failed: %s\n"),
489 fname, strerror(errno));
490 ++senderr;
491 goto jcant;
493 rewind(fin);
494 while ((i = getc(fin)) != EOF)
495 putc(i, fout);
496 if (ferror(fout)) {
497 fprintf(stderr, tr(282,
498 "Message writing to <%s> failed: %s\n"),
499 fname, tr(283, "write error"));
500 ++senderr;
502 Fclose(fout);
504 jcant:
506 * In days of old we removed the entry from the
507 * the list; now for sake of header expansion
508 * we leave it in and mark it as deleted.
510 np->n_type |= GDEL;
511 np = np->n_flink;
512 if (image < 0)
513 goto jdelall;
515 jleave:
516 if (fin != NULL)
517 Fclose(fin);
518 for (i = 0; i < pipecnt; ++i)
519 (void)close(fda[i]);
520 if (image >= 0) {
521 close(image);
522 image = -1;
524 return (names);
526 jdelall:
527 while (np != NULL) {
528 if ((np->n_flags & (NAME_ADDRSPEC_ISFILE|NAME_ADDRSPEC_ISPIPE))
529 != 0)
530 np->n_type |= GDEL;
531 np = np->n_flink;
533 goto jleave;
536 static int
537 same_name(char *n1, char *n2)
539 int c1, c2;
541 if (value("allnet") != NULL) {
542 do {
543 c1 = (*n1++ & 0377);
544 c2 = (*n2++ & 0377);
545 c1 = lowerconv(c1);
546 c2 = lowerconv(c2);
547 if (c1 != c2)
548 return 0;
549 } while (c1 != '\0' && c2 != '\0' && c1 != '@' && c2 != '@');
550 return 1;
551 } else
552 return asccasecmp(n1, n2) == 0;
556 * Map all of the aliased users in the invoker's mailrc
557 * file and insert them into the list.
558 * Changed after all these months of service to recursively
559 * expand names (2/14/80).
562 struct name *
563 usermap(struct name *names)
565 struct name *new, *np, *cp;
566 struct grouphead *gh;
567 int metoo;
569 new = NULL;
570 np = names;
571 metoo = (value("metoo") != NULL);
572 while (np != NULL) {
573 if (np->n_name[0] == '\\') {
574 cp = np->n_flink;
575 new = put(new, np);
576 np = cp;
577 continue;
579 gh = findgroup(np->n_name);
580 cp = np->n_flink;
581 if (gh != NULL)
582 new = gexpand(new, gh, metoo, np->n_type);
583 else
584 new = put(new, np);
585 np = cp;
587 return(new);
591 * Recursively expand a group name. We limit the expansion to some
592 * fixed level to keep things from going haywire.
593 * Direct recursion is not expanded for convenience.
596 static struct name *
597 gexpand(struct name *nlist, struct grouphead *gh, int metoo, int ntype)
599 struct group *gp;
600 struct grouphead *ngh;
601 struct name *np;
602 static int depth;
603 char *cp;
605 if (depth > MAXEXP) {
606 printf(catgets(catd, CATSET, 150,
607 "Expanding alias to depth larger than %d\n"), MAXEXP);
608 return(nlist);
610 depth++;
611 for (gp = gh->g_list; gp != NULL; gp = gp->ge_link) {
612 cp = gp->ge_name;
613 if (*cp == '\\')
614 goto quote;
615 if (strcmp(cp, gh->g_name) == 0)
616 goto quote;
617 if ((ngh = findgroup(cp)) != NULL) {
618 nlist = gexpand(nlist, ngh, metoo, ntype);
619 continue;
621 quote:
622 np = nalloc(cp, ntype|GFULL);
624 * At this point should allow to expand
625 * to self if only person in group
627 if (gp == gh->g_list && gp->ge_link == NULL)
628 goto skip;
629 if (!metoo && same_name(cp, myname))
630 np->n_type |= GDEL;
631 skip:
632 nlist = put(nlist, np);
634 depth--;
635 return(nlist);
639 * Concatenate the two passed name lists, return the result.
641 struct name *
642 cat(struct name *n1, struct name *n2)
644 struct name *tail;
646 if (n1 == NULL)
647 return(n2);
648 if (n2 == NULL)
649 return(n1);
650 tail = tailof(n1);
651 tail->n_flink = n2;
652 n2->n_blink = tail;
653 return(n1);
657 * Unpack the name list onto a vector of strings.
658 * Return an error if the name list won't fit.
660 char **
661 unpack(struct name *np)
663 char **ap, **top;
664 struct name *n;
665 int t, extra, metoo, verbose;
667 n = np;
668 if ((t = count(n)) == 0)
669 panic(catgets(catd, CATSET, 151, "No names to unpack"));
671 * Compute the number of extra arguments we will need.
672 * We need at least two extra -- one for "mail" and one for
673 * the terminating 0 pointer. Additional spots may be needed
674 * to pass along -f to the host mailer.
676 extra = 2;
677 extra++;
678 metoo = value("metoo") != NULL;
679 if (metoo)
680 extra++;
681 verbose = value("verbose") != NULL;
682 if (verbose)
683 extra++;
684 /*LINTED*/
685 top = (char **)salloc((t + extra) * sizeof *top);
686 ap = top;
687 *ap++ = "send-mail";
688 *ap++ = "-i";
689 if (metoo)
690 *ap++ = "-m";
691 if (verbose)
692 *ap++ = "-v";
693 for (; n != NULL; n = n->n_flink)
694 if ((n->n_type & GDEL) == 0)
695 *ap++ = n->n_name;
696 *ap = NULL;
697 return(top);
701 * Remove all of the duplicates from the passed name list by
702 * insertion sorting them, then checking for dups.
703 * Return the head of the new list.
705 struct name *
706 elide(struct name *names)
708 struct name *np, *t, *newn, *x;
710 if (names == NULL)
711 return (NULL);
712 /* Throw away all deleted nodes (XXX merge with plain sort below?) */
713 for (newn = np = NULL; names != NULL; names = names->n_flink)
714 if ((names->n_type & GDEL) == 0) {
715 names->n_blink = np;
716 if (np)
717 np->n_flink = names;
718 else
719 newn = names;
720 np = names;
722 if (newn == NULL)
723 return (NULL);
725 np = newn->n_flink;
726 if (np != NULL)
727 np->n_blink = NULL;
728 newn->n_flink = NULL;
730 while (np != NULL) {
731 t = newn;
732 while (asccasecmp(t->n_name, np->n_name) < 0) {
733 if (t->n_flink == NULL)
734 break;
735 t = t->n_flink;
739 * If we ran out of t's, put the new entry after
740 * the current value of t.
743 if (asccasecmp(t->n_name, np->n_name) < 0) {
744 t->n_flink = np;
745 np->n_blink = t;
746 t = np;
747 np = np->n_flink;
748 t->n_flink = NULL;
749 continue;
753 * Otherwise, put the new entry in front of the
754 * current t. If at the front of the list,
755 * the new guy becomes the new head of the list.
758 if (t == newn) {
759 t = np;
760 np = np->n_flink;
761 t->n_flink = newn;
762 newn->n_blink = t;
763 t->n_blink = NULL;
764 newn = t;
765 continue;
769 * The normal case -- we are inserting into the
770 * middle of the list.
773 x = np;
774 np = np->n_flink;
775 x->n_flink = t;
776 x->n_blink = t->n_blink;
777 t->n_blink->n_flink = x;
778 t->n_blink = x;
782 * Now the list headed up by new is sorted.
783 * Go through it and remove duplicates.
786 np = newn;
787 while (np != NULL) {
788 t = np;
789 while (t->n_flink != NULL &&
790 asccasecmp(np->n_name, t->n_flink->n_name) == 0)
791 t = t->n_flink;
792 if (t == np || t == NULL) {
793 np = np->n_flink;
794 continue;
798 * Now t points to the last entry with the same name
799 * as np. Make np point beyond t.
802 np->n_flink = t->n_flink;
803 if (t->n_flink != NULL)
804 t->n_flink->n_blink = np;
805 np = np->n_flink;
807 return (newn);
811 * Put another node onto a list of names and return
812 * the list.
814 static struct name *
815 put(struct name *list, struct name *node)
817 node->n_flink = list;
818 node->n_blink = NULL;
819 if (list != NULL)
820 list->n_blink = node;
821 return(node);
825 * Determine the number of undeleted elements in
826 * a name list and return it.
828 int
829 count(struct name *np)
831 int c;
833 for (c = 0; np != NULL; np = np->n_flink)
834 if ((np->n_type & GDEL) == 0)
835 c++;
836 return c;
840 * Delete the given name from a namelist.
842 static struct name *
843 delname(struct name *np, char *name)
845 struct name *p;
847 for (p = np; p != NULL; p = p->n_flink)
848 if (same_name(p->n_name, name)) {
849 if (p->n_blink == NULL) {
850 if (p->n_flink != NULL)
851 p->n_flink->n_blink = NULL;
852 np = p->n_flink;
853 continue;
855 if (p->n_flink == NULL) {
856 if (p->n_blink != NULL)
857 p->n_blink->n_flink = NULL;
858 continue;
860 p->n_blink->n_flink = p->n_flink;
861 p->n_flink->n_blink = p->n_blink;
863 return np;
867 * Pretty print a name list
868 * Uncomment it if you need it.
872 void
873 prettyprint(struct name *name)
875 struct name *np;
877 np = name;
878 while (np != NULL) {
879 fprintf(stderr, "%s(%d) ", np->n_name, np->n_type);
880 np = np->n_flink;
882 fprintf(stderr, "\n");
886 struct name *
887 delete_alternates(struct name *np)
889 struct name *xp;
890 char **ap;
892 np = delname(np, myname);
893 if (altnames)
894 for (ap = altnames; *ap; ap++)
895 np = delname(np, *ap);
896 if ((xp = sextract(value("from"), GEXTRA|GSKIN)) != NULL)
897 while (xp) {
898 np = delname(np, xp->n_name);
899 xp = xp->n_flink;
901 if ((xp = sextract(value("replyto"), GEXTRA|GSKIN)) != NULL)
902 while (xp) {
903 np = delname(np, xp->n_name);
904 xp = xp->n_flink;
906 if ((xp = sextract(value("sender"), GEXTRA|GSKIN)) != NULL)
907 while (xp) {
908 np = delname(np, xp->n_name);
909 xp = xp->n_flink;
911 return np;
915 is_myname(char *name)
917 struct name *xp;
918 char **ap;
920 if (same_name(myname, name))
921 return 1;
922 if (altnames)
923 for (ap = altnames; *ap; ap++)
924 if (same_name(*ap, name))
925 return 1;
926 if ((xp = sextract(value("from"), GEXTRA|GSKIN)) != NULL)
927 while (xp) {
928 if (same_name(xp->n_name, name))
929 return 1;
930 xp = xp->n_flink;
932 if ((xp = sextract(value("replyto"), GEXTRA|GSKIN)) != NULL)
933 while (xp) {
934 if (same_name(xp->n_name, name))
935 return 1;
936 xp = xp->n_flink;
938 if ((xp = sextract(value("sender"), GEXTRA|GSKIN)) != NULL)
939 while (xp) {
940 if (same_name(xp->n_name, name))
941 return 1;
942 xp = xp->n_flink;
944 return 0;