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