Home | History | Annotate | Line # | Download | only in mail
      1 /*	$NetBSD: cmd4.c,v 1.8 2025/09/18 21:26:44 rillig 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.8 2025/09/18 21:26:44 rillig 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(np);
    253 	}
    254 }
    255 
    256 static void
    257 delsmopts(char *name)
    258 {
    259 	struct smopts_s *sp, *next;
    260 	struct smopts_s **last_link;
    261 
    262 	last_link = &smoptstbl[hashcase(name)];
    263 	for (sp = *last_link; sp; sp = next) {
    264 		next = sp->s_link;
    265 		if (strcasecmp(sp->s_name, name) == 0) {
    266 			*last_link = sp->s_link;
    267 			free_name(sp->s_smopts);
    268 			free(sp);
    269 		}
    270 	}
    271 }
    272 
    273 /*
    274  * Takes a list of entries and removes them from the smoptstbl.
    275  */
    276 PUBLIC int
    277 unsmoptscmd(void *v)
    278 {
    279 	struct name *np;
    280 	char **ap;
    281 
    282 	for (ap = v; *ap != NULL; ap++)
    283 		for (np = name_expand(*ap, GTO); np; np = np->n_flink)
    284 			delsmopts(np->n_name);
    285 	return 0;
    286 }
    287 
    288 static struct name *
    289 alloc_Header(char *str)
    290 {
    291 	struct name *np;
    292 
    293 	/*
    294 	 * Don't use salloc() routines here as these strings must persist.
    295 	 */
    296 	np = ecalloc(1, sizeof(*np));
    297 	np->n_name = estrdup(str);
    298 	np->n_type = GMISC;
    299 	return np;
    300 }
    301 
    302 static int
    303 free_Header(char *str)
    304 {
    305 	struct name *np;
    306 	struct name *next_np;
    307 	size_t len;
    308 
    309 	len = strlen(str);
    310 	for (np = extra_headers; np != NULL; np = next_np) {
    311 		next_np = np->n_flink;
    312 		if (strncasecmp(np->n_name, str, len) == 0) {
    313 			if (np == extra_headers) {
    314 				extra_headers = np->n_flink;
    315 				if (extra_headers)
    316 					extra_headers->n_blink = NULL;
    317 			}
    318 			else {
    319 				struct name *bp;
    320 				struct name *fp;
    321 
    322 				bp = np->n_blink;
    323 				fp = np->n_flink;
    324 				if (bp)
    325 					bp->n_flink = fp;
    326 				if (fp)
    327 					fp->n_blink = bp;
    328 			}
    329 			if (np->n_name)
    330 				free(np->n_name);
    331 			free(np);
    332 		}
    333 	}
    334 	return 0;
    335 }
    336 
    337 /*
    338  * Takes a string and includes it in the header.
    339  */
    340 PUBLIC int
    341 Header(void *v)
    342 {
    343 	struct name *np;
    344 	char *str;
    345 	char *p;
    346 
    347 	str = v;
    348 	if (str == NULL)
    349 		return 0;
    350 
    351 	(void)strip_WSP(str);	/* strip trailing whitespace */
    352 
    353 	if (str[0] == '\0') {	/* Show the extra headers */
    354 		for (np = extra_headers; np != NULL; np = np->n_flink)
    355 			(void)printf("%s\n", np->n_name);
    356 		return 0;
    357 	}
    358 
    359 	/*
    360 	 * Check for a valid header line: find the end of its name.
    361 	 */
    362 	for (p = str; *p != '\0' && *p != ':' && !is_WSP(*p); p++)
    363 		continue;
    364 
    365 	if (p[0] == ':' && p[1] == '\0') /* free headers of this type */
    366 		return free_Header(str);
    367 
    368 	/*
    369 	 * Check for a valid header name.
    370 	 */
    371 	if (*p != ':' || !is_WSP(p[1])) {
    372 		(void)printf("invalid header string: `%s'\n", str);
    373 		return 0;
    374 	}
    375 
    376 	np = alloc_Header(str);
    377 	if (extra_headers == NULL)
    378 		extra_headers = np;
    379 	else {
    380 		struct name *tp;
    381 
    382 		for (tp = extra_headers; tp->n_flink; tp = tp->n_flink)
    383 			continue;
    384 		tp->n_flink = np;
    385 		np->n_blink = tp;
    386 	}
    387 	return 0;
    388 }
    389