/* $NetBSD: cmd4.c,v 1.6 2009/04/11 14:22:32 christos Exp $ */ /*- * Copyright (c) 2006 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Anon Ymous. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #ifndef lint #if 0 static char sccsid[] = "@(#)cmd3.c 8.2 (Berkeley) 4/20/95"; #else __RCSID("$NetBSD: cmd4.c,v 1.6 2009/04/11 14:22:32 christos Exp $"); #endif #endif /* not lint */ #include "rcv.h" #include #include "extern.h" /* * Mail -- a mail program * * Still more user commands. * XXX - should this be renamed smopts.c? */ #if 0 /* XXX - debugging stuff - to be removed */ void showname(struct name *); void showname(struct name *np) { for (/*EMPTY*/; np; np = np->n_flink) (void)printf("np: %p np->n_type: %d np->n_name: '%s' (%p)\n", np, np->n_type, np->n_name, np->n_name); } __unused static void showsmopts(struct smopts_s *sp) { (void)printf("%s (%p)\n", sp->s_name, sp); showname(sp->s_smopts); } #endif /* XXX - debugging stuff - to be removed */ static int hashcase(const char *key) { char *lckey; lckey = salloc(strlen(key) + 1); istrcpy(lckey, key); return hash(lckey); } static struct smopts_s * findsmopts_core(const char *name) { struct smopts_s *sh; for (sh = smoptstbl[hashcase(name)]; sh; sh = sh->s_link) if (strcasecmp(sh->s_name, name) == 0) return sh; return NULL; } /* * The exported smopts lookup routine. */ PUBLIC struct smopts_s * findsmopts(const char *name, int top_only) { const char *cp; struct smopts_s *sh; if ((sh = findsmopts_core(name)) != NULL) return sh; if (top_only) return NULL; for (cp = strchr(name, '@'); cp; cp = strchr(cp + 1, '.')) if ((sh = findsmopts_core(cp)) != NULL) return sh; return findsmopts_core("."); } static void printsmopts(const char *name) { struct smopts_s *sp; if ((sp = findsmopts(name, 1)) == NULL) { (void)printf("%s:\n", name); return; } (void)printf("%s:\t%s\n", sp->s_name, detract(sp->s_smopts, GSMOPTS)); } static void printsmoptstbl(void) { struct smopts_s *sp; const char **argv; const char **ap; int h; int cnt; cnt = 1; for (h = 0; h < (int)__arraycount(smoptstbl); h++) for (sp = smoptstbl[h]; sp && sp->s_name != NULL; sp = sp->s_link) cnt++; argv = salloc(cnt * sizeof(*argv)); ap = argv; for (h = 0; h < (int)__arraycount(smoptstbl); h++) for (sp = smoptstbl[h]; sp && sp->s_name != NULL; sp = sp->s_link) *ap++ = sp->s_name; *ap = NULL; sort(argv); for (ap = argv; *ap != NULL; ap++) printsmopts(*ap); } static struct name * name_expand(char *sname, int ntype) { struct grouphead *gh; struct name *np; if ((gh = findgroup(sname)) != NULL) { np = gexpand(NULL, gh, 0, ntype); } else { np = csalloc(1, sizeof(*np)); np->n_name = sname; np->n_type = ntype; } return np; } static struct name * ncalloc(char *str, int ntype) { struct name *np; np = ecalloc(1, sizeof(*np)); np->n_type = ntype; np->n_name = vcopy(str); return np; } static void smopts_core(const char *sname, char **argv) { struct smopts_s *sp; struct name *np; struct name *t; int h; char **ap; if ((sp = findsmopts(sname, 1)) != NULL) { char *cp; cp = detract(sp->s_smopts, GSMOPTS); (void)printf("%s already defined as: %s\n", sname, cp); return; } h = hashcase(sname); sp = ecalloc(1, sizeof(*sp)); sp->s_name = vcopy(sname); if (smoptstbl[h]) sp->s_link = smoptstbl[h]; smoptstbl[h] = sp; np = NULL; for (ap = argv + 1; *ap != NULL; ap++) { t = ncalloc(*ap, GSMOPTS); if (sp->s_smopts == NULL) sp->s_smopts = t; else np->n_flink = t; t->n_blink = np; np = t; } } /* * Takes a list of entries, expands them, and adds the results to the * smopts table. */ PUBLIC int smoptscmd(void *v) { struct name *np; char **argv; argv = v; if (*argv == NULL) { printsmoptstbl(); return 0; } np = name_expand(argv[0], GTO); if (argv[1] == NULL) { for (/*EMPTY*/; np; np = np->n_flink) printsmopts(np->n_name); return 0; } for (/*EMPTY*/; np; np = np->n_flink) smopts_core(np->n_name, argv); return 0; } static void free_name(struct name *np) { struct name *next_np; for (/*EMPTY*/; np; np = next_np) { next_np = np->n_flink; free(next_np); } } static void delsmopts(char *name) { struct smopts_s *sp; struct smopts_s **last_link; last_link = &smoptstbl[hashcase(name)]; for (sp = *last_link; sp; sp = sp->s_link) { if (strcasecmp(sp->s_name, name) == 0) { *last_link = sp->s_link; free_name(sp->s_smopts); free(sp); } } } /* * Takes a list of entries and removes them from the smoptstbl. */ PUBLIC int unsmoptscmd(void *v) { struct name *np; char **ap; for (ap = v; *ap != NULL; ap++) for (np = name_expand(*ap, GTO); np; np = np->n_flink) delsmopts(np->n_name); return 0; } static struct name * alloc_Header(char *str) { struct name *np; /* * Don't use salloc() routines here as these strings must persist. */ np = ecalloc(1, sizeof(*np)); np->n_name = estrdup(str); np->n_type = GMISC; return np; } static int free_Header(char *str) { struct name *np; struct name *next_np; size_t len; len = strlen(str); for (np = extra_headers; np != NULL; np = next_np) { next_np = np->n_flink; if (strncasecmp(np->n_name, str, len) == 0) { if (np == extra_headers) { extra_headers = np->n_flink; if (extra_headers) extra_headers->n_blink = NULL; } else { struct name *bp; struct name *fp; bp = np->n_blink; fp = np->n_flink; if (bp) bp->n_flink = fp; if (fp) fp->n_blink = bp; } if (np->n_name) free(np->n_name); free(np); } } return 0; } /* * Takes a string and includes it in the header. */ PUBLIC int Header(void *v) { struct name *np; char *str; char *p; str = v; if (str == NULL) return 0; (void)strip_WSP(str); /* strip trailing whitespace */ if (str[0] == '\0') { /* Show the extra headers */ for (np = extra_headers; np != NULL; np = np->n_flink) (void)printf("%s\n", np->n_name); return 0; } /* * Check for a valid header line: find the end of its name. */ for (p = str; *p != '\0' && *p != ':' && !is_WSP(*p); p++) continue; if (p[0] == ':' && p[1] == '\0') /* free headers of this type */ return free_Header(str); /* * Check for a valid header name. */ if (*p != ':' || !is_WSP(p[1])) { (void)printf("invalid header string: `%s'\n", str); return 0; } np = alloc_Header(str); if (extra_headers == NULL) extra_headers = np; else { struct name *tp; for (tp = extra_headers; tp->n_flink; tp = tp->n_flink) continue; tp->n_flink = np; np->n_blink = tp; } return 0; }