1 /*	$NetBSD: mail_parm_split.c,v 1.3 2020/03/18 19:05:16 christos Exp $	*/
2 
3 /*++
4 /* NAME
5 /*	mail_parm_split 3
6 /* SUMMARY
7 /*	split parameter list value
8 /* SYNOPSIS
9 /*	#include <mail_parm_split.h>
10 /*
11 /*	ARGV	*mail_parm_split(
12 /*	const char *name,
13 /*	const char *value)
14 /* DESCRIPTION
15 /*	mail_parm_split() splits a parameter list value into its
16 /*	elements, and extracts text from elements that are entirely
17 /*	enclosed in {}. It uses CHARS_COMMA_SP as list element
18 /*	delimiters, and CHARS_BRACE for grouping.
19 /*
20 /*	Arguments:
21 /* .IP name
22 /*	Parameter name. This is used to provide context for
23 /*	error messages.
24 /* .IP value
25 /*	Parameter value.
26 /* DIAGNOSTICS
27 /*	fatal: syntax error while extracting text from {}, such as:
28 /*	missing closing brace, or text after closing brace.
29 /* SEE ALSO
30 /*	argv_splitq(3), string array utilities
31 /*	extpar(3), extract text from parentheses
32 /* LICENSE
33 /* .ad
34 /* .fi
35 /*	The Secure Mailer license must be distributed with this software.
36 /* AUTHOR(S)
37 /*	Wietse Venema
38 /*	IBM T.J. Watson Research
39 /*	P.O. Box 704
40 /*	Yorktown Heights, NY 10598, USA
41 /*
42 /*	Wietse Venema
43 /*	Google, Inc.
44 /*	111 8th Avenue
45 /*	New York, NY 10011, USA
46 /*--*/
47 
48  /*
49   * System library.
50   */
51 #include <sys_defs.h>
52 
53  /*
54   * Utility library.
55   */
56 #include <msg.h>
57 #include <mymalloc.h>
58 #include <stringops.h>
59 
60  /*
61   * Global library.
62   */
63 #include <mail_params.h>
64 #include <mail_parm_split.h>
65 
66 /* mail_parm_split - split list, extract {text}, errors are fatal */
67 
mail_parm_split(const char * name,const char * value)68 ARGV   *mail_parm_split(const char *name, const char *value)
69 {
70     ARGV   *argvp = argv_alloc(1);
71     char   *saved_string = mystrdup(value);
72     char   *bp = saved_string;
73     char   *arg;
74     char   *err;
75 
76     /*
77      * The code that detects the error shall either signal or handle the
78      * error. In this case, mystrtokq() detects no error, extpar() signals
79      * the error to its caller, and this function handles the error.
80      */
81     while ((arg = mystrtokq(&bp, CHARS_COMMA_SP, CHARS_BRACE)) != 0) {
82 	if (*arg == CHARS_BRACE[0]
83 	    && (err = extpar(&arg, CHARS_BRACE, EXTPAR_FLAG_STRIP)) != 0) {
84 #ifndef TEST
85 	    msg_fatal("%s: %s", name, err);
86 #else
87 	    msg_warn("%s: %s", name, err);
88 	    myfree(err);
89 #endif
90 	}
91 	argv_add(argvp, arg, (char *) 0);
92     }
93     argv_terminate(argvp);
94     myfree(saved_string);
95     return (argvp);
96 }
97 
98 #ifdef TEST
99 
100  /*
101   * This function is security-critical so it better have a unit-test driver.
102   */
103 #include <string.h>
104 #include <vstream.h>
105 #include <vstream.h>
106 #include <vstring_vstream.h>
107 
main(void)108 int     main(void)
109 {
110     VSTRING *vp = vstring_alloc(100);
111     ARGV   *argv;
112     char   *start;
113     char   *str;
114     char  **cpp;
115 
116     while (vstring_fgets_nonl(vp, VSTREAM_IN) && VSTRING_LEN(vp) > 0) {
117 	start = vstring_str(vp);
118 	vstream_printf("Input:\t>%s<\n", start);
119 	vstream_fflush(VSTREAM_OUT);
120 	argv = mail_parm_split("stdin", start);
121 	for (cpp = argv->argv; (str = *cpp) != 0; cpp++)
122 	    vstream_printf("Output:\t>%s<\n", str);
123 	argv_free(argv);
124 	vstream_fflush(VSTREAM_OUT);
125     }
126     vstring_free(vp);
127     return (0);
128 }
129 
130 #endif
131