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