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