xref: /netbsd-src/usr.bin/mail/cmd4.c (revision ce099b40997c43048fb78bd578195f81d2456523)
1 /*	$NetBSD: cmd4.c,v 1.4 2008/04/28 20:24:14 martin 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.4 2008/04/28 20:24:14 martin 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 	for (/*EMPTY*/; np; np = np->n_flink)
59 		(void)printf("np: %p  np->n_type: %d  np->n_name: '%s' (%p)\n",
60 		    np, np->n_type, np->n_name, np->n_name);
61 }
62 
63 __unused
64 static void
65 showsmopts(struct smopts_s *sp)
66 {
67 	(void)printf("%s (%p)\n", sp->s_name, sp);
68 	showname(sp->s_smopts);
69 }
70 #endif	/* XXX - debugging stuff - to be removed */
71 
72 
73 static int
74 hashcase(const char *key)
75 {
76 	char *lckey;
77 	lckey = salloc(strlen(key) + 1);
78 	istrcpy(lckey, key);
79 	return hash(lckey);
80 }
81 
82 static struct smopts_s *
83 findsmopts_core(const char *name)
84 {
85 	struct smopts_s *sh;
86 
87 	for (sh = smoptstbl[hashcase(name)]; sh; sh = sh->s_link)
88 		if (strcasecmp(sh->s_name, name) == 0)
89 			return sh;
90 	return NULL;
91 }
92 
93 /*
94  * The exported smopts lookup routine.
95  */
96 PUBLIC struct smopts_s *
97 findsmopts(const char *name, int top_only)
98 {
99 	const char *cp;
100 	struct smopts_s *sh;
101 
102 	if ((sh = findsmopts_core(name)) != NULL)
103 		return sh;
104 
105 	if (top_only)
106 		return NULL;
107 
108 	for (cp = strchr(name, '@'); cp; cp = strchr(cp + 1, '.'))
109 		if ((sh = findsmopts_core(cp)) != NULL)
110 			return sh;
111 
112 	return findsmopts_core(".");
113 }
114 
115 static void
116 printsmopts(const char *name)
117 {
118 	struct smopts_s *sp;
119 
120 	if ((sp = findsmopts(name, 1)) == NULL) {
121 		(void)printf("%s:\n", name);
122 		return;
123 	}
124 	(void)printf("%s:\t%s\n", sp->s_name, detract(sp->s_smopts, GSMOPTS));
125 }
126 
127 static void
128 printsmoptstbl(void)
129 {
130 	struct smopts_s *sp;
131 	const char **argv, **ap;
132 	int h;
133 	int cnt;
134 
135 	cnt = 1;
136 	for (h = 0; h < (int)sizeofarray(smoptstbl); h++ )
137 		for (sp = smoptstbl[h]; sp && sp->s_name != NULL; sp = sp->s_link)
138 			cnt++;
139 
140 	argv = salloc(cnt * sizeof(*argv));
141 	ap = argv;
142 	for (h = 0; h < (int)sizeofarray(smoptstbl); h++ )
143 		for (sp = smoptstbl[h]; sp && sp->s_name != NULL; sp = sp->s_link)
144 			*ap++ = sp->s_name;
145 	*ap = NULL;
146 	sort(argv);
147 	for (ap = argv; *ap != NULL; ap++)
148 		printsmopts(*ap);
149 }
150 
151 static struct name *
152 name_expand(char *sname, int ntype)
153 {
154 	struct grouphead *gh;
155 	struct name *np;
156 
157 	if ((gh = findgroup(sname)) != NULL) {
158 		np = gexpand(NULL, gh, 0, ntype);
159 	}
160 	else {
161 		np = csalloc(1, sizeof(*np));
162 		np->n_name = sname;
163 		np->n_type = ntype;
164 	}
165 	return np;
166 }
167 
168 static struct name *
169 ncalloc(char *str, int ntype)
170 {
171 	struct name *np;
172 
173 	np = ecalloc(1, sizeof(*np));
174 	np->n_type = ntype;
175 	np->n_name = vcopy(str);
176 	return np;
177 }
178 
179 static void
180 smopts_core(const char *sname, char **argv)
181 {
182 	struct smopts_s *sp;
183 	struct name *np, *t;
184 	int h;
185 	char **ap;
186 
187 	if ((sp = findsmopts(sname, 1)) != NULL) {
188 		char *cp;
189 		cp = detract(sp->s_smopts, GSMOPTS);
190 		(void)printf("%s already defined as: %s\n", sname, cp);
191 		return;
192 	}
193 	h = hashcase(sname);
194 	sp = ecalloc(1, sizeof(*sp));
195 	sp->s_name = vcopy(sname);
196 	if (smoptstbl[h])
197 		sp->s_link = smoptstbl[h];
198 	smoptstbl[h] = sp;
199 
200 	np = NULL;
201 	for (ap = argv + 1; *ap != NULL; ap++) {
202 		t = ncalloc(*ap, GSMOPTS);
203 		if (sp->s_smopts == NULL)
204 			sp->s_smopts = t;
205 		else
206 			np->n_flink = t;
207 		t->n_blink = np;
208 		np = t;
209 	}
210 }
211 
212 /*
213  * Takes a list of entries, expands them, and adds the results to the
214  * smopts table.
215  */
216 PUBLIC int
217 smoptscmd(void *v)
218 {
219 	struct name *np;
220 	char **argv = v;
221 
222 	if (*argv == NULL) {
223 		printsmoptstbl();
224 		return 0;
225 	}
226 	np = name_expand(argv[0], GTO);
227 
228 	if (argv[1] == NULL) {
229 		for (/*EMPTY*/; np; np = np->n_flink)
230 			printsmopts(np->n_name);
231 		return 0;
232 	}
233 	for (/*EMPTY*/; np; np = np->n_flink)
234 		smopts_core(np->n_name, argv);
235 
236 	return 0;
237 }
238 
239 static void
240 free_name(struct name *np)
241 {
242 	struct name *next_np;
243 	for (/*EMPTY*/; np; np = next_np) {
244 		next_np = np->n_flink;
245 		free(next_np);
246 	}
247 }
248 
249 static void
250 delsmopts(char *name)
251 {
252 	struct smopts_s *sp;
253 	struct smopts_s **last_link;
254 
255 	last_link = &smoptstbl[hashcase(name)];
256 	for (sp = *last_link; sp; sp = sp->s_link) {
257 		if (strcasecmp(sp->s_name, name) == 0) {
258 			*last_link = sp->s_link;
259 			free_name(sp->s_smopts);
260 			free(sp);
261 		}
262 	}
263 }
264 
265 /*
266  * Takes a list of entries and removes them from the smoptstbl.
267  */
268 PUBLIC int
269 unsmoptscmd(void *v)
270 {
271 	struct name *np;
272 	char **argv, **ap;
273 
274 	argv = v;
275 	for (ap = argv; *ap != NULL; ap++)
276 		for (np = name_expand(*ap, GTO); np; np = np->n_flink)
277 			delsmopts(np->n_name);
278 	return 0;
279 }
280