1 /* $NetBSD: cmd4.c,v 1.6 2009/04/11 14:22:32 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2006 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Anon Ymous. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 33 #include <sys/cdefs.h> 34 #ifndef lint 35 #if 0 36 static char sccsid[] = "@(#)cmd3.c 8.2 (Berkeley) 4/20/95"; 37 #else 38 __RCSID("$NetBSD: cmd4.c,v 1.6 2009/04/11 14:22:32 christos Exp $"); 39 #endif 40 #endif /* not lint */ 41 42 #include "rcv.h" 43 #include <util.h> 44 #include "extern.h" 45 46 /* 47 * Mail -- a mail program 48 * 49 * Still more user commands. 50 * XXX - should this be renamed smopts.c? 51 */ 52 53 #if 0 /* XXX - debugging stuff - to be removed */ 54 void showname(struct name *); 55 void 56 showname(struct name *np) 57 { 58 59 for (/*EMPTY*/; np; np = np->n_flink) 60 (void)printf("np: %p np->n_type: %d np->n_name: '%s' (%p)\n", 61 np, np->n_type, np->n_name, np->n_name); 62 } 63 64 __unused 65 static void 66 showsmopts(struct smopts_s *sp) 67 { 68 69 (void)printf("%s (%p)\n", sp->s_name, sp); 70 showname(sp->s_smopts); 71 } 72 #endif /* XXX - debugging stuff - to be removed */ 73 74 75 static int 76 hashcase(const char *key) 77 { 78 char *lckey; 79 80 lckey = salloc(strlen(key) + 1); 81 istrcpy(lckey, key); 82 return hash(lckey); 83 } 84 85 static struct smopts_s * 86 findsmopts_core(const char *name) 87 { 88 struct smopts_s *sh; 89 90 for (sh = smoptstbl[hashcase(name)]; sh; sh = sh->s_link) 91 if (strcasecmp(sh->s_name, name) == 0) 92 return sh; 93 return NULL; 94 } 95 96 /* 97 * The exported smopts lookup routine. 98 */ 99 PUBLIC struct smopts_s * 100 findsmopts(const char *name, int top_only) 101 { 102 const char *cp; 103 struct smopts_s *sh; 104 105 if ((sh = findsmopts_core(name)) != NULL) 106 return sh; 107 108 if (top_only) 109 return NULL; 110 111 for (cp = strchr(name, '@'); cp; cp = strchr(cp + 1, '.')) 112 if ((sh = findsmopts_core(cp)) != NULL) 113 return sh; 114 115 return findsmopts_core("."); 116 } 117 118 static void 119 printsmopts(const char *name) 120 { 121 struct smopts_s *sp; 122 123 if ((sp = findsmopts(name, 1)) == NULL) { 124 (void)printf("%s:\n", name); 125 return; 126 } 127 (void)printf("%s:\t%s\n", sp->s_name, detract(sp->s_smopts, GSMOPTS)); 128 } 129 130 static void 131 printsmoptstbl(void) 132 { 133 struct smopts_s *sp; 134 const char **argv; 135 const char **ap; 136 int h; 137 int cnt; 138 139 cnt = 1; 140 for (h = 0; h < (int)__arraycount(smoptstbl); h++) 141 for (sp = smoptstbl[h]; sp && sp->s_name != NULL; sp = sp->s_link) 142 cnt++; 143 144 argv = salloc(cnt * sizeof(*argv)); 145 ap = argv; 146 for (h = 0; h < (int)__arraycount(smoptstbl); h++) 147 for (sp = smoptstbl[h]; sp && sp->s_name != NULL; sp = sp->s_link) 148 *ap++ = sp->s_name; 149 *ap = NULL; 150 sort(argv); 151 for (ap = argv; *ap != NULL; ap++) 152 printsmopts(*ap); 153 } 154 155 static struct name * 156 name_expand(char *sname, int ntype) 157 { 158 struct grouphead *gh; 159 struct name *np; 160 161 if ((gh = findgroup(sname)) != NULL) { 162 np = gexpand(NULL, gh, 0, ntype); 163 } 164 else { 165 np = csalloc(1, sizeof(*np)); 166 np->n_name = sname; 167 np->n_type = ntype; 168 } 169 return np; 170 } 171 172 static struct name * 173 ncalloc(char *str, int ntype) 174 { 175 struct name *np; 176 177 np = ecalloc(1, sizeof(*np)); 178 np->n_type = ntype; 179 np->n_name = vcopy(str); 180 return np; 181 } 182 183 static void 184 smopts_core(const char *sname, char **argv) 185 { 186 struct smopts_s *sp; 187 struct name *np; 188 struct name *t; 189 int h; 190 char **ap; 191 192 if ((sp = findsmopts(sname, 1)) != NULL) { 193 char *cp; 194 cp = detract(sp->s_smopts, GSMOPTS); 195 (void)printf("%s already defined as: %s\n", sname, cp); 196 return; 197 } 198 h = hashcase(sname); 199 sp = ecalloc(1, sizeof(*sp)); 200 sp->s_name = vcopy(sname); 201 if (smoptstbl[h]) 202 sp->s_link = smoptstbl[h]; 203 smoptstbl[h] = sp; 204 205 np = NULL; 206 for (ap = argv + 1; *ap != NULL; ap++) { 207 t = ncalloc(*ap, GSMOPTS); 208 if (sp->s_smopts == NULL) 209 sp->s_smopts = t; 210 else 211 np->n_flink = t; 212 t->n_blink = np; 213 np = t; 214 } 215 } 216 217 /* 218 * Takes a list of entries, expands them, and adds the results to the 219 * smopts table. 220 */ 221 PUBLIC int 222 smoptscmd(void *v) 223 { 224 struct name *np; 225 char **argv; 226 227 argv = v; 228 if (*argv == NULL) { 229 printsmoptstbl(); 230 return 0; 231 } 232 np = name_expand(argv[0], GTO); 233 234 if (argv[1] == NULL) { 235 for (/*EMPTY*/; np; np = np->n_flink) 236 printsmopts(np->n_name); 237 return 0; 238 } 239 for (/*EMPTY*/; np; np = np->n_flink) 240 smopts_core(np->n_name, argv); 241 242 return 0; 243 } 244 245 static void 246 free_name(struct name *np) 247 { 248 struct name *next_np; 249 250 for (/*EMPTY*/; np; np = next_np) { 251 next_np = np->n_flink; 252 free(next_np); 253 } 254 } 255 256 static void 257 delsmopts(char *name) 258 { 259 struct smopts_s *sp; 260 struct smopts_s **last_link; 261 262 last_link = &smoptstbl[hashcase(name)]; 263 for (sp = *last_link; sp; sp = sp->s_link) { 264 if (strcasecmp(sp->s_name, name) == 0) { 265 *last_link = sp->s_link; 266 free_name(sp->s_smopts); 267 free(sp); 268 } 269 } 270 } 271 272 /* 273 * Takes a list of entries and removes them from the smoptstbl. 274 */ 275 PUBLIC int 276 unsmoptscmd(void *v) 277 { 278 struct name *np; 279 char **ap; 280 281 for (ap = v; *ap != NULL; ap++) 282 for (np = name_expand(*ap, GTO); np; np = np->n_flink) 283 delsmopts(np->n_name); 284 return 0; 285 } 286 287 static struct name * 288 alloc_Header(char *str) 289 { 290 struct name *np; 291 292 /* 293 * Don't use salloc() routines here as these strings must persist. 294 */ 295 np = ecalloc(1, sizeof(*np)); 296 np->n_name = estrdup(str); 297 np->n_type = GMISC; 298 return np; 299 } 300 301 static int 302 free_Header(char *str) 303 { 304 struct name *np; 305 struct name *next_np; 306 size_t len; 307 308 len = strlen(str); 309 for (np = extra_headers; np != NULL; np = next_np) { 310 next_np = np->n_flink; 311 if (strncasecmp(np->n_name, str, len) == 0) { 312 if (np == extra_headers) { 313 extra_headers = np->n_flink; 314 if (extra_headers) 315 extra_headers->n_blink = NULL; 316 } 317 else { 318 struct name *bp; 319 struct name *fp; 320 321 bp = np->n_blink; 322 fp = np->n_flink; 323 if (bp) 324 bp->n_flink = fp; 325 if (fp) 326 fp->n_blink = bp; 327 } 328 if (np->n_name) 329 free(np->n_name); 330 free(np); 331 } 332 } 333 return 0; 334 } 335 336 /* 337 * Takes a string and includes it in the header. 338 */ 339 PUBLIC int 340 Header(void *v) 341 { 342 struct name *np; 343 char *str; 344 char *p; 345 346 str = v; 347 if (str == NULL) 348 return 0; 349 350 (void)strip_WSP(str); /* strip trailing whitespace */ 351 352 if (str[0] == '\0') { /* Show the extra headers */ 353 for (np = extra_headers; np != NULL; np = np->n_flink) 354 (void)printf("%s\n", np->n_name); 355 return 0; 356 } 357 358 /* 359 * Check for a valid header line: find the end of its name. 360 */ 361 for (p = str; *p != '\0' && *p != ':' && !is_WSP(*p); p++) 362 continue; 363 364 if (p[0] == ':' && p[1] == '\0') /* free headers of this type */ 365 return free_Header(str); 366 367 /* 368 * Check for a valid header name. 369 */ 370 if (*p != ':' || !is_WSP(p[1])) { 371 (void)printf("invalid header string: `%s'\n", str); 372 return 0; 373 } 374 375 np = alloc_Header(str); 376 if (extra_headers == NULL) 377 extra_headers = np; 378 else { 379 struct name *tp; 380 381 for (tp = extra_headers; tp->n_flink; tp = tp->n_flink) 382 continue; 383 tp->n_flink = np; 384 np->n_blink = tp; 385 } 386 return 0; 387 } 388