xref: /netbsd/usr.bin/mail/cmd4.c (revision 6550d01e)
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
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(next_np);
253 	}
254 }
255 
256 static void
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
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 *
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
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
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