xref: /netbsd-src/usr.bin/mail/cmd4.c (revision 27b54bd918aa8f9f3bd71fb181c2d013a92840d6)
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