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