Commit 9ba835fb 9ba835fbb5a937735f51925c2170bbc748820fcf by Sergey Poznyakoff

Provide functions for expanding string using mu_assoc_t table.

The functions are used wherever variables can be expected, most
notably in configuration statements, such as ldap, namespace (imap4d),
etc.  Apart from expanding variables it also provides command
expansion $(command args...)

The commands currently available are:

  domainpart ARG       splits its argument on the first occurrence of @
                       and returns the part after it.
  localpart ARG        splits its argument on the first occurrence of @
                       and returns the part before it.
  shell CMD ARG...     runs shell command CMD and returns its output

* include/mailutils/cstr.h (mu_str_expand, mu_str_vexpand): New protos.
* libmailutils/string/expvar.c: New file.
* libmailutils/string/Makefile.am: Add expvar.c

* libmailutils/tests/exp.c: New file.
* libmailutils/tests/Makefile.am: Add exp.c

* imap4d/imap4d.c (namespace_cfg_init): Fix docstring.
* imap4d/namespace.c (namespace_translate_name): Use mu_str_expand.

* libmailutils/mailbox/mbx_default.c (mu_construct_user_mailbox_url):
Use mu_str_vexpand.
* libmu_auth/ldap.c (_mu_ldap_search): Likewise.
* libmu_auth/radius.c (_expand_query): Likewise.
* libmu_auth/sql.c (mu_sql_expand_query): Likewise.

* mu/shell.c (mutool_prompt_env): Remove.
(shell_prompt): Rewrite
(input_line_interactive): Use mu_str_expand.
(mutool_shell_prompt_assoc): New function.
* mu/mu.h (mutool_shell_prompt_assoc): New proto.
* mu/imap.c (imap_prompt_env): Use mutool_shell_prompt_assoc.
* mu/pop.c (pop_prompt_env): Likewise.
* mu/smtp.c (smtp_prompt_env): Likewise.
1 parent 012c66dd
...@@ -517,6 +517,7 @@ namespace_cfg_init (void) ...@@ -517,6 +517,7 @@ namespace_cfg_init (void)
517 if (mu_create_canned_section ("prefix", &section)) 517 if (mu_create_canned_section ("prefix", &section))
518 abort (); 518 abort ();
519 section->docstring = N_("Define a single prefix"); 519 section->docstring = N_("Define a single prefix");
520 section->label = N_("string");
520 mu_cfg_section_add_params (section, prefix_param); 521 mu_cfg_section_add_params (section, prefix_param);
521 section->parser = prefix_section_parser; 522 section->parser = prefix_section_parser;
522 523
......
...@@ -153,28 +153,6 @@ namespace_init (void) ...@@ -153,28 +153,6 @@ namespace_init (void)
153 mu_assoc_sort_r (prefixes, cmplen, NULL); 153 mu_assoc_sort_r (prefixes, cmplen, NULL);
154 } 154 }
155 155
156 static int
157 expand_vars (char **env, char const *input, char **output)
158 {
159 struct mu_wordsplit ws;
160 size_t wordc;
161 char **wordv;
162
163 ws.ws_env = (const char **) env;
164 if (mu_wordsplit (input, &ws,
165 MU_WRDSF_NOSPLIT | MU_WRDSF_NOCMD |
166 MU_WRDSF_ENV | MU_WRDSF_ENV_KV))
167 {
168 mu_error (_("cannot expand line `%s': %s"), input,
169 mu_wordsplit_strerror (&ws));
170 return 1;
171 }
172 mu_wordsplit_get_words (&ws, &wordc, &wordv);
173 *output = wordv[0];
174 mu_wordsplit_free (&ws);
175 return 0;
176 }
177
178 static char * 156 static char *
179 prefix_translate_name (struct namespace_prefix const *pfx, char const *name, 157 prefix_translate_name (struct namespace_prefix const *pfx, char const *name,
180 size_t namelen, int url) 158 size_t namelen, int url)
...@@ -290,23 +268,12 @@ extract_username (char const *name, struct namespace_prefix const *pfx) ...@@ -290,23 +268,12 @@ extract_username (char const *name, struct namespace_prefix const *pfx)
290 return user; 268 return user;
291 } 269 }
292 270
293 enum
294 {
295 ENV_USER = 1,
296 ENV_HOME = 3,
297 ENV_NULL = 4
298 };
299
300 #define ENV_INITIALIZER \
301 { [ENV_USER-1] = "user", [ENV_HOME-1] = "home", [ENV_NULL] = NULL }
302
303 char * 271 char *
304 namespace_translate_name (char const *name, int url, 272 namespace_translate_name (char const *name, int url,
305 struct namespace_prefix const **return_pfx) 273 struct namespace_prefix const **return_pfx)
306 { 274 {
307 char *res = NULL; 275 char *res = NULL;
308 struct namespace_prefix const *pfx; 276 struct namespace_prefix const *pfx;
309 char *env[] = ENV_INITIALIZER;
310 277
311 if (mu_c_strcasecmp (name, "INBOX") == 0 && auth_data->change_uid) 278 if (mu_c_strcasecmp (name, "INBOX") == 0 && auth_data->change_uid)
312 { 279 {
...@@ -318,25 +285,37 @@ namespace_translate_name (char const *name, int url, ...@@ -318,25 +285,37 @@ namespace_translate_name (char const *name, int url,
318 285
319 if (res) 286 if (res)
320 { 287 {
288 mu_assoc_t assoc;
289 int rc;
321 char *dir; 290 char *dir;
322 291
292 rc = mu_assoc_create (&assoc, 0);
293 if (rc)
294 {
295 mu_diag_funcall (MU_DIAG_ERROR, "mu_assoc_create", NULL, rc);
296 free (res);
297 imap4d_bye (ERR_NO_MEM);
298 }
299
323 switch (pfx->ns) 300 switch (pfx->ns)
324 { 301 {
325 case NS_PRIVATE: 302 case NS_PRIVATE:
326 env[ENV_USER] = auth_data->name; 303 mu_assoc_install (assoc, "user", auth_data->name);
327 env[ENV_HOME] = real_homedir; 304 mu_assoc_install (assoc, "home", real_homedir);
328 break; 305 break;
329 306
330 case NS_OTHER: 307 case NS_OTHER:
331 { 308 {
332 struct mu_auth_data *adata; 309 struct mu_auth_data *adata;
333 env[ENV_USER] = extract_username (name, pfx); 310 char *user = extract_username (name, pfx);
334 adata = mu_get_auth_by_name (env[ENV_USER]); 311 mu_assoc_install (assoc, "user", user);
312 adata = mu_get_auth_by_name (user);
335 if (adata) 313 if (adata)
336 { 314 {
337 env[ENV_HOME] = mu_strdup (adata->dir); 315 mu_assoc_install (assoc, "home", mu_strdup (adata->dir));
338 mu_auth_data_free (adata); 316 mu_auth_data_free (adata);
339 } 317 }
318 mu_assoc_set_destroy_item (assoc, mu_list_free_item);
340 } 319 }
341 break; 320 break;
342 321
...@@ -344,18 +323,27 @@ namespace_translate_name (char const *name, int url, ...@@ -344,18 +323,27 @@ namespace_translate_name (char const *name, int url,
344 break; 323 break;
345 } 324 }
346 325
347 if (expand_vars (env, res, &dir)) 326 rc = mu_str_expand (&dir, res, assoc);
348 imap4d_bye (ERR_NO_MEM);
349 free (res); 327 free (res);
350 res = dir; 328 mu_assoc_destroy (&assoc);
351 trim_delim (res, '/'); 329 if (rc)
352 330 {
353 if (pfx->ns == NS_OTHER) 331 if (rc == MU_ERR_FAILURE)
332 {
333 mu_error (_("cannot expand line `%s': %s"), res, dir);
334 free (dir);
335 }
336 else
354 { 337 {
355 free (env[ENV_USER]); 338 mu_error (_("cannot expand line `%s': %s"), res,
356 free (env[ENV_HOME]); 339 mu_strerror (rc));
340 }
341 imap4d_bye (ERR_NO_MEM);
357 } 342 }
358 343
344 res = dir;
345 trim_delim (res, '/');
346
359 if (return_pfx) 347 if (return_pfx)
360 *return_pfx = pfx; 348 *return_pfx = pfx;
361 } 349 }
......
...@@ -59,6 +59,9 @@ int mu_c_str_unescape_trans (char const *str, char const *trans, ...@@ -59,6 +59,9 @@ int mu_c_str_unescape_trans (char const *str, char const *trans,
59 char **ret_str); 59 char **ret_str);
60 60
61 61
62 int mu_str_expand (char **output, char const *input, mu_assoc_t assoc);
63 int mu_str_vexpand (char **output, char const *input, ...);
64
62 #ifdef __cplusplus 65 #ifdef __cplusplus
63 } 66 }
64 #endif 67 #endif
......
...@@ -38,7 +38,7 @@ ...@@ -38,7 +38,7 @@
38 #include <mailutils/mu_auth.h> 38 #include <mailutils/mu_auth.h>
39 #include <mailutils/folder.h> 39 #include <mailutils/folder.h>
40 #include <mailutils/auth.h> 40 #include <mailutils/auth.h>
41 #include <mailutils/wordsplit.h> 41 #include <mailutils/cstr.h>
42 #include <mailutils/io.h> 42 #include <mailutils/io.h>
43 43
44 #include <mailutils/sys/mailbox.h> 44 #include <mailutils/sys/mailbox.h>
...@@ -158,32 +158,22 @@ mu_construct_user_mailbox_url (char **pout, const char *name) ...@@ -158,32 +158,22 @@ mu_construct_user_mailbox_url (char **pout, const char *name)
158 { 158 {
159 int rc; 159 int rc;
160 const char *pat = mu_mailbox_url (); 160 const char *pat = mu_mailbox_url ();
161 const char *env[3]; 161 char *result;
162 struct mu_wordsplit ws;
163
164 env[0] = "user";
165 env[1] = (char*) name;
166 env[2] = NULL;
167 ws.ws_env = env;
168 rc = mu_wordsplit (pat, &ws,
169 MU_WRDSF_NOSPLIT | MU_WRDSF_NOCMD |
170 MU_WRDSF_ENV | MU_WRDSF_ENV_KV);
171 162
163 rc = mu_str_vexpand (&result, pat, "user", name, NULL);
172 if (rc) 164 if (rc)
173 { 165 {
174 mu_error (_("cannot expand line `%s': %s"), pat, 166 if (rc == MU_ERR_FAILURE)
175 mu_wordsplit_strerror (&ws)); 167 {
168 mu_error (_("cannot expand line `%s': %s"), pat, result);
169 free (result);
170 }
171 else
172 mu_error (_("cannot expand line `%s': %s"), pat, mu_strerror (rc));
176 return rc; 173 return rc;
177 } 174 }
178 175
179 if (ws.ws_wordc == 0) 176 *pout = result;
180 /* FIXME: a special return code maybe? */
181 *pout = strdup ("");
182 else
183 *pout = strdup (ws.ws_wordv[0]);
184 mu_wordsplit_free (&ws);
185 if (!*pout)
186 return ENOMEM;
187 return 0; 177 return 0;
188 } 178 }
189 179
......
...@@ -25,6 +25,7 @@ libstring_la_SOURCES = \ ...@@ -25,6 +25,7 @@ libstring_la_SOURCES = \
25 cstrunescape.c\ 25 cstrunescape.c\
26 cstrlower.c\ 26 cstrlower.c\
27 cstrupper.c\ 27 cstrupper.c\
28 expvar.c\
28 hexstr.c\ 29 hexstr.c\
29 safefilename.c\ 30 safefilename.c\
30 stpcpy.c\ 31 stpcpy.c\
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999-2003, 2005-2007, 2009-2012, 2014-2017 Free
3 Software Foundation, Inc.
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 3 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General
16 Public License along with this library. If not, see
17 <http://www.gnu.org/licenses/>. */
18
19 #if HAVE_CONFIG_H
20 # include <config.h>
21 #endif
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <mailutils/errno.h>
26 #include <mailutils/error.h>
27 #include <mailutils/io.h>
28 #include <mailutils/nls.h>
29 #include <mailutils/assoc.h>
30 #include <mailutils/cstr.h>
31 #include <mailutils/cctype.h>
32 #include <mailutils/wordsplit.h>
33
34 static int
35 exp_getvar (char **ret, const char *vptr, size_t vlen, void *data)
36 {
37 int rc;
38 char *varname, *s = NULL;
39 mu_assoc_t assoc = data;
40
41 if (mu_assoc_is_empty (assoc))
42 return MU_WRDSE_UNDEF;
43
44 varname = malloc (vlen + 1);
45 if (!varname)
46 return MU_WRDSE_NOSPACE;
47 memcpy (varname, vptr, vlen);
48 varname[vlen] = 0;
49
50 rc = mu_assoc_lookup (assoc, varname, &s);
51 free (varname);
52
53 switch (rc)
54 {
55 case 0:
56 rc = MU_WRDSE_OK;
57 break;
58
59 case MU_ERR_NOENT:
60 rc = MU_WRDSE_UNDEF;
61 break;
62
63 case MU_ERR_BUFSPACE:
64 case ENOMEM:
65 rc = MU_WRDSE_NOSPACE;
66 break;
67
68 default:
69 s = (char*) mu_strerror (rc);
70 rc = MU_WRDSE_USERERR;
71 }
72
73 if (s)
74 {
75 s = strdup (s);
76 if (!s)
77 return MU_WRDSE_NOSPACE;
78 *ret = s;
79 }
80
81 return rc;
82 }
83
84 static int
85 exp_localpart (int argc, char **argv, char **result)
86 {
87 size_t len = strcspn (argv[1], "@");
88 char *s;
89
90 s = malloc (len + 1);
91 if (!s)
92 return MU_WRDSE_NOSPACE;
93 memcpy (s, argv[1], len);
94 s[len] = 0;
95
96 *result = s;
97 return MU_WRDSE_OK;
98 }
99
100 static int
101 exp_domainpart (int argc, char **argv, char **result)
102 {
103 char *s = strchr (argv[1], '@');
104
105 if (s)
106 s++;
107 else
108 s = "";
109
110 s = strdup (s);
111 if (!s)
112 return MU_WRDSE_NOSPACE;
113
114 *result = s;
115
116 return MU_WRDSE_OK;
117 }
118
119 static int
120 exp_shell (char **ret, char const *str, size_t len, void *closure)
121 {
122 FILE *fp;
123 char *cmd;
124 int c, lastc;
125 char *buffer = NULL;
126 size_t bufsize = 0;
127 size_t buflen = 0;
128
129 cmd = malloc (len + 1);
130 if (!cmd)
131 return MU_WRDSE_NOSPACE;
132 memcpy (cmd, str, len);
133 cmd[len] = 0;
134
135 fp = popen (cmd, "r");
136 if (!fp)
137 {
138 ret = NULL;
139 if (mu_asprintf (ret, "can't run %s: %s", cmd, mu_strerror (errno)))
140 return MU_WRDSE_NOSPACE;
141 else
142 return MU_WRDSE_USERERR;
143 }
144
145 while ((c = fgetc (fp)) != EOF)
146 {
147 lastc = c;
148 if (c == '\n')
149 c = ' ';
150 if (buflen == bufsize)
151 {
152 char *p;
153
154 if (bufsize == 0)
155 bufsize = 80;
156 else
157 bufsize *= 2;
158 p = realloc (buffer, bufsize);
159 if (!p)
160 {
161 free (buffer);
162 free (cmd);
163 return MU_WRDSE_NOSPACE;
164 }
165 buffer = p;
166 }
167 buffer[buflen++] = c;
168 }
169
170 if (buffer)
171 {
172 if (lastc == '\n')
173 --buflen;
174 buffer[buflen] = 0;
175 }
176
177 pclose (fp);
178 free (cmd);
179
180 *ret = buffer;
181 return MU_WRDSE_OK;
182 }
183
184 struct exp_command
185 {
186 char *name;
187 int minarg;
188 int maxarg;
189 int (*exp) (int argc, char **argv, char **ret);
190 };
191
192 static struct exp_command exp_command_tab[] = {
193 { "localpart", 2, 2, exp_localpart },
194 { "domainpart", 2, 2, exp_domainpart },
195 { NULL }
196 };
197
198 static struct exp_command *
199 findcom (char const *name)
200 {
201 struct exp_command *cp;
202
203 for (cp = exp_command_tab; cp->name; cp++)
204 if (strcmp (name, cp->name) == 0)
205 return cp;
206
207 return NULL;
208 }
209
210 static int
211 checkargc (struct exp_command *cmd, int argc)
212 {
213 if (cmd->minarg && argc < cmd->minarg)
214 return 1;
215 else if (cmd->maxarg && argc > cmd->maxarg)
216 return 1;
217 return 0;
218 }
219
220 #define SHELL_CMD "shell"
221
222 static int
223 exp_runcmd (char **ret, const char *str, size_t len, char **argv, void *closure)
224 {
225 int argc;
226 struct exp_command *cmd;
227 char *result = NULL;
228 int rc;
229
230 if (strcmp (argv[0], SHELL_CMD) == 0)
231 {
232 len -= sizeof SHELL_CMD;
233 str += sizeof SHELL_CMD;
234 while (len > 0 && mu_isspace (*str))
235 {
236 len--;
237 str++;
238 }
239
240 if (len == 0)
241 {
242 if (mu_asprintf (ret, _("%s: bad number of arguments"), argv[0]))
243 return MU_WRDSE_NOSPACE;
244 return MU_WRDSE_USERERR;
245 }
246 return exp_shell (ret, str, len, closure);
247 }
248
249 cmd = findcom (argv[0]);
250 if (!cmd)
251 {
252 if (mu_asprintf (ret, _("%s: unknown function"), argv[0]))
253 return MU_WRDSE_NOSPACE;
254 return MU_WRDSE_USERERR;
255 }
256
257 for (argc = 0; argv[argc]; argc++)
258 ;
259
260 if (checkargc (cmd, argc))
261 {
262 if (mu_asprintf (ret, _("%s: bad number of arguments"), argv[0]))
263 return MU_WRDSE_NOSPACE;
264 return MU_WRDSE_USERERR;
265 }
266
267 rc = cmd->exp (argc, argv, &result);
268 if (rc == MU_WRDSE_USERERR && result == NULL)
269 {
270 if (mu_asprintf (ret, _("%s: command expansion error"), argv[0]))
271 return MU_WRDSE_NOSPACE;
272 return MU_WRDSE_USERERR;
273 }
274
275 if (rc == MU_WRDSE_OK || rc == MU_WRDSE_USERERR)
276 *ret = result;
277
278 return rc;
279 }
280
281 int
282 mu_str_expand (char **output, char const *input, mu_assoc_t assoc)
283 {
284 struct mu_wordsplit ws;
285 size_t wordc;
286 char **wordv;
287
288 ws.ws_getvar = exp_getvar;
289 ws.ws_command = exp_runcmd;
290 ws.ws_closure = assoc;
291 ws.ws_options = MU_WRDSO_ARGV;
292
293 if (mu_wordsplit (input, &ws,
294 MU_WRDSF_NOSPLIT | MU_WRDSF_GETVAR | MU_WRDSF_CLOSURE
295 | MU_WRDSF_OPTIONS))
296 {
297 char *p = strdup (mu_wordsplit_strerror (&ws));
298 if (p)
299 *output = p;
300 return MU_ERR_FAILURE;
301 }
302 mu_wordsplit_get_words (&ws, &wordc, &wordv);
303 *output = wordv[0];
304 mu_wordsplit_free (&ws);
305 return 0;
306 }
307
308 int
309 mu_str_vexpand (char **output, char const *input, ...)
310 {
311 int rc;
312 mu_assoc_t assoc;
313 char *p[2];
314 int i;
315 va_list ap;
316
317 rc = mu_assoc_create (&assoc, 0);
318 if (rc)
319 return rc;
320
321 va_start (ap, input);
322 i = 0;
323 while ((p[i] = va_arg (ap, char *)) != NULL)
324 {
325 if (i == 1)
326 {
327 rc = mu_assoc_install (assoc, p[0], p[1]);
328 if (rc)
329 {
330 mu_assoc_destroy (&assoc);
331 return rc;
332 }
333 }
334 i = (i + 1) % 2;
335 }
336 va_end (ap);
337
338 rc = mu_str_expand (output, input, assoc);
339 mu_assoc_destroy (&assoc);
340 return rc;
341 }
...@@ -46,6 +46,7 @@ noinst_PROGRAMS = \ ...@@ -46,6 +46,7 @@ noinst_PROGRAMS = \
46 debugspec\ 46 debugspec\
47 decode2047\ 47 decode2047\
48 encode2047\ 48 encode2047\
49 exp\
49 fltst\ 50 fltst\
50 fsaf\ 51 fsaf\
51 fsaftomod\ 52 fsaftomod\
......
1 #include <mailutils/mailutils.h>
2
3 int
4 main (int argc, char **argv)
5 {
6 mu_assoc_t assc;
7 char *p;
8 int i;
9
10 MU_ASSERT (mu_assoc_create (&assc, 0));
11
12 for (i = 1; i < argc; i++)
13 {
14 p = strchr (argv[i], '=');
15 if (p)
16 {
17 *p++ = 0;
18 MU_ASSERT (mu_assoc_install (assc, argv[i], p));
19 }
20 else if (strcmp (argv[i], "--") == 0)
21 {
22 i++;
23 break;
24 }
25 else
26 break;
27 }
28
29 for (; i < argc; i++)
30 {
31 int rc = mu_str_expand (&p, argv[i], assc);
32 switch (rc)
33 {
34 case 0:
35 printf ("%s\n", p);
36 free (p);
37 break;
38
39 case MU_ERR_FAILURE:
40 mu_error ("%s", p);
41 free (p);
42 break;
43
44 default:
45 mu_error ("%s", mu_strerror (rc));
46 }
47 }
48
49 return 0;
50 }
51
...@@ -598,38 +598,34 @@ _mu_ldap_search (LDAP *ld, const char *filter_pat, const char *key, ...@@ -598,38 +598,34 @@ _mu_ldap_search (LDAP *ld, const char *filter_pat, const char *key,
598 size_t nattrs; 598 size_t nattrs;
599 LDAPMessage *res, *msg; 599 LDAPMessage *res, *msg;
600 ber_int_t msgid; 600 ber_int_t msgid;
601 const char *env[3]; 601 char *filter_str;
602 struct mu_wordsplit ws;
603 602
604 rc = _construct_attr_array (&nattrs, &attrs); 603 rc = _construct_attr_array (&nattrs, &attrs);
605 if (rc) 604 if (rc)
606 return rc; 605 return rc;
607 606
608 env[0] = "user"; 607 rc = mu_str_vexpand (&filter_str, filter_pat, "user", key, NULL);
609 env[1] = key; 608 if (rc)
610 env[2] = NULL; 609 {
611 610 mu_argcv_free (nattrs, attrs);
612 ws.ws_env = env; 611 if (rc == MU_ERR_FAILURE)
613 if (mu_wordsplit (filter_pat, &ws,
614 MU_WRDSF_NOSPLIT | MU_WRDSF_NOCMD |
615 MU_WRDSF_ENV | MU_WRDSF_ENV_KV))
616 { 612 {
617 mu_error (_("cannot expand line `%s': %s"), filter_pat, 613 mu_error (_("cannot expand line `%s': %s"), filter_pat,
618 mu_wordsplit_strerror (&ws)); 614 filter_str);
619 return MU_ERR_FAILURE; 615 free (filter_str);
620 } 616 }
621 else if (ws.ws_wordc == 0) 617 else
622 { 618 {
623 mu_error (_("expanding %s yields empty string"), filter_pat); 619 mu_error (_("cannot expand line `%s': %s"), filter_pat,
624 mu_wordsplit_free (&ws); 620 mu_strerror (rc));
625 mu_argcv_free (nattrs, attrs); 621 }
626 return MU_ERR_FAILURE; 622 return rc;
627 } 623 }
628 624
629 rc = ldap_search_ext (ld, ldap_param.base, LDAP_SCOPE_SUBTREE, 625 rc = ldap_search_ext (ld, ldap_param.base, LDAP_SCOPE_SUBTREE,
630 ws.ws_wordv[0], attrs, 0, 626 filter_str, attrs, 0,
631 NULL, NULL, NULL, -1, &msgid); 627 NULL, NULL, NULL, -1, &msgid);
632 mu_wordsplit_free (&ws); 628 free (filter_str);
633 mu_argcv_free (nattrs, attrs); 629 mu_argcv_free (nattrs, attrs);
634 630
635 if (rc != LDAP_SUCCESS) 631 if (rc != LDAP_SUCCESS)
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
35 #include <mailutils/iterator.h> 35 #include <mailutils/iterator.h>
36 #include <mailutils/mailbox.h> 36 #include <mailutils/mailbox.h>
37 #include <mailutils/radius.h> 37 #include <mailutils/radius.h>
38 #include <mailutils/cstr.h>
38 #include <mailutils/wordsplit.h> 39 #include <mailutils/wordsplit.h>
39 #include <mailutils/mu_auth.h> 40 #include <mailutils/mu_auth.h>
40 #include <mailutils/error.h> 41 #include <mailutils/error.h>
...@@ -275,35 +276,25 @@ module_init (void *ptr) ...@@ -275,35 +276,25 @@ module_init (void *ptr)
275 static char * 276 static char *
276 _expand_query (const char *query, const char *ustr, const char *passwd) 277 _expand_query (const char *query, const char *ustr, const char *passwd)
277 { 278 {
278 struct mu_wordsplit ws;
279 const char *env[2 * 2 + 1];
280 char *ret; 279 char *ret;
280 int rc;
281 281
282 env[0] = "user"; 282 rc = mu_str_vexpand (&ret, query,
283 env[1] = (char*) ustr; 283 "user", ustr,
284 env[2] = "passwd"; 284 "passwd", passwd,
285 env[3] = (char*) passwd; 285 NULL);
286 env[4] = NULL; 286 if (rc)
287
288 ws.ws_env = env;
289 if (mu_wordsplit (query, &ws,
290 MU_WRDSF_NOSPLIT | MU_WRDSF_NOCMD |
291 MU_WRDSF_ENV | MU_WRDSF_ENV_KV))
292 { 287 {
293 mu_error (_("cannot expand line `%s': %s"), query, 288 if (rc == MU_ERR_FAILURE)
294 mu_wordsplit_strerror (&ws));
295 return NULL;
296 }
297 else if (ws.ws_wordc == 0)
298 { 289 {
299 mu_error (_("expanding %s yields empty string"), query); 290 mu_error (_("cannot expand line `%s': %s"), query, ret);
300 mu_wordsplit_free (&ws); 291 free (ret);
292 }
293 else
294 mu_error (_("cannot expand line `%s': %s"), query, mu_strerror (rc));
301 return NULL; 295 return NULL;
302 } 296 }
303 297
304 ret = grad_emalloc (strlen (ws.ws_wordv[0]) + 1);
305 strcpy (ret, ws.ws_wordv[0]);
306 mu_wordsplit_free (&ws);
307 return ret; 298 return ret;
308 } 299 }
309 300
......
...@@ -187,37 +187,27 @@ sql_escape_string (const char *ustr) ...@@ -187,37 +187,27 @@ sql_escape_string (const char *ustr)
187 char * 187 char *
188 mu_sql_expand_query (const char *query, const char *ustr) 188 mu_sql_expand_query (const char *query, const char *ustr)
189 { 189 {
190 int rc;
190 char *res; 191 char *res;
191 char *esc_ustr; 192 char *esc_ustr;
192 struct mu_wordsplit ws;
193 const char *env[2 + 1];
194 193
195 if (!query) 194 if (!query)
196 return NULL; 195 return NULL;
197 196
198 esc_ustr = sql_escape_string (ustr); 197 esc_ustr = sql_escape_string (ustr);
199 env[0] = "user"; 198 rc = mu_str_vexpand (&res, query, "user", esc_ustr, NULL);
200 env[1] = (char*) ustr; 199 free (esc_ustr);
201 env[2] = NULL; 200 if (rc)
202
203 ws.ws_env = env;
204 if (mu_wordsplit (query, &ws,
205 MU_WRDSF_NOSPLIT | MU_WRDSF_NOCMD |
206 MU_WRDSF_ENV | MU_WRDSF_ENV_KV))
207 { 201 {
208 mu_error (_("cannot expand line `%s': %s"), query, 202 if (rc == MU_ERR_FAILURE)
209 mu_wordsplit_strerror (&ws));
210 return NULL;
211 }
212 else if (ws.ws_wordc == 0)
213 { 203 {
214 mu_error (_("expanding %s yields empty string"), query); 204 mu_error (_("cannot expand line `%s': %s"), query, res);
215 mu_wordsplit_free (&ws); 205 free (res);
206 }
207 else
208 mu_error (_("cannot expand line `%s': %s"), query, mu_strerror (rc));
216 return NULL; 209 return NULL;
217 } 210 }
218 res = strdup (ws.ws_wordv[0]);
219 mu_wordsplit_free (&ws);
220 free (esc_ustr);
221 return res; 211 return res;
222 } 212 }
223 213
......
...@@ -121,37 +121,20 @@ static char **connect_argv; ...@@ -121,37 +121,20 @@ static char **connect_argv;
121 static char *username; 121 static char *username;
122 122
123 static void 123 static void
124 imap_prompt_env () 124 imap_prompt_env (void)
125 { 125 {
126 mu_assoc_t assoc = mutool_shell_prompt_assoc ();
126 enum mu_imap_session_state state = current_imap_state (); 127 enum mu_imap_session_state state = current_imap_state ();
127 if (!mutool_prompt_env) 128 const char *p;
128 mutool_prompt_env = mu_calloc (2*7 + 1, sizeof(mutool_prompt_env[0]));
129 129
130 mutool_prompt_env[0] = "user"; 130 if (state >= MU_IMAP_SESSION_AUTH && username)
131 mutool_prompt_env[1] = (state >= MU_IMAP_SESSION_AUTH && username) ? 131 mu_assoc_install (assoc, "user", username);
132 username : "[nouser]";
133 132
134 mutool_prompt_env[2] = "host"; 133 if (connect_argv)
135 mutool_prompt_env[3] = connect_argv ? host : "[nohost]"; 134 mu_assoc_install (assoc, "host", host);
136 135
137 mutool_prompt_env[4] = "program-name"; 136 if (mu_imap_session_state_str (state, &p) == 0)
138 mutool_prompt_env[5] = (char*) mu_program_name; 137 mu_assoc_install (assoc, "status", (void*) p);
139
140 mutool_prompt_env[6] = "canonical-program-name";
141 mutool_prompt_env[7] = "mu";
142
143 mutool_prompt_env[8] = "package";
144 mutool_prompt_env[9] = PACKAGE;
145
146 mutool_prompt_env[10] = "version";
147 mutool_prompt_env[11] = PACKAGE_VERSION;
148
149 mutool_prompt_env[12] = "status";
150 if (mu_imap_session_state_str (state,
151 (const char **) &mutool_prompt_env[13]))
152 mutool_prompt_env[12] = NULL;
153
154 mutool_prompt_env[14] = NULL;
155 } 138 }
156 139
157 /* Callbacks */ 140 /* Callbacks */
...@@ -724,7 +707,11 @@ com_login (int argc, char **argv) ...@@ -724,7 +707,11 @@ com_login (int argc, char **argv)
724 memset (pwd, 0, strlen (pwd)); 707 memset (pwd, 0, strlen (pwd));
725 free (passbuf); 708 free (passbuf);
726 if (status == 0) 709 if (status == 0)
710 {
711 free (username);
712 username = mu_strdup (argv[1]);
727 imap_prompt_env (); 713 imap_prompt_env ();
714 }
728 else 715 else
729 report_failure ("login", status); 716 report_failure ("login", status);
730 return 0; 717 return 0;
......
...@@ -43,8 +43,8 @@ struct mutool_command ...@@ -43,8 +43,8 @@ struct mutool_command
43 }; 43 };
44 44
45 extern char *mutool_shell_prompt; 45 extern char *mutool_shell_prompt;
46 extern char **mutool_prompt_env;
47 extern int mutool_shell_interactive; 46 extern int mutool_shell_interactive;
47 mu_assoc_t mutool_shell_prompt_assoc (void);
48 int mutool_shell (const char *name, struct mutool_command *cmd); 48 int mutool_shell (const char *name, struct mutool_command *cmd);
49 mu_stream_t mutool_open_pager (void); 49 mu_stream_t mutool_open_pager (void);
50 50
......
...@@ -56,35 +56,17 @@ pop_session_str (enum pop_session_status stat) ...@@ -56,35 +56,17 @@ pop_session_str (enum pop_session_status stat)
56 } 56 }
57 57
58 static void 58 static void
59 pop_prompt_env () 59 pop_prompt_env (void)
60 { 60 {
61 if (!mutool_prompt_env) 61 mu_assoc_t assoc = mutool_shell_prompt_assoc ();
62 mutool_prompt_env = mu_calloc (2*7 + 1, sizeof(mutool_prompt_env[0]));
63 62
64 mutool_prompt_env[0] = "user"; 63 if (pop_session_status == pop_session_logged_in)
65 mutool_prompt_env[1] = (pop_session_status == pop_session_logged_in) ? 64 mu_assoc_install (assoc, "user", username);
66 username : "[nouser]"; 65 if (pop_session_status != pop_session_disconnected)
67 66 mu_assoc_install (assoc, "host", host);
68 mutool_prompt_env[2] = "host";
69 mutool_prompt_env[3] = (pop_session_status != pop_session_disconnected) ?
70 host : "[nohost]";
71
72 mutool_prompt_env[4] = "program-name";
73 mutool_prompt_env[5] = (char*) mu_program_name;
74
75 mutool_prompt_env[6] = "canonical-program-name";
76 mutool_prompt_env[7] = "mu";
77
78 mutool_prompt_env[8] = "package";
79 mutool_prompt_env[9] = PACKAGE;
80
81 mutool_prompt_env[10] = "version";
82 mutool_prompt_env[11] = PACKAGE_VERSION;
83
84 mutool_prompt_env[12] = "status";
85 mutool_prompt_env[13] = (char*) pop_session_str (pop_session_status);
86 67
87 mutool_prompt_env[14] = NULL; 68 mu_assoc_install (assoc, "status",
69 pop_session_str (pop_session_status));
88 } 70 }
89 71
90 72
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
24 #endif 24 #endif
25 25
26 char *mutool_shell_prompt; 26 char *mutool_shell_prompt;
27 char **mutool_prompt_env; 27 static mu_assoc_t mutool_prompt_assoc;
28 int mutool_shell_interactive; 28 int mutool_shell_interactive;
29 29
30 30
...@@ -63,7 +63,7 @@ static int shell_history (int, char **); ...@@ -63,7 +63,7 @@ static int shell_history (int, char **);
63 #endif 63 #endif
64 64
65 struct mutool_command default_comtab[] = { 65 struct mutool_command default_comtab[] = {
66 { "prompt", 1, 2, CMD_COALESCE_EXTRA_ARGS, shell_prompt, 66 { "prompt", 1, 2, 0, shell_prompt,
67 N_("STRING"), 67 N_("STRING"),
68 N_("set command prompt") }, 68 N_("set command prompt") },
69 { "exit", 1, 1, 0, shell_exit, NULL, N_("exit program") }, 69 { "exit", 1, 1, 0, shell_exit, NULL, N_("exit program") },
...@@ -244,16 +244,8 @@ shell_help (int argc, char **argv) ...@@ -244,16 +244,8 @@ shell_help (int argc, char **argv)
244 static int 244 static int
245 shell_prompt (int argc, char **argv) 245 shell_prompt (int argc, char **argv)
246 { 246 {
247 mu_wordsplit_t ws;
248
249 if (mu_wordsplit (argv[1], &ws, MU_WRDSF_NOSPLIT | MU_WRDSF_DEFFLAGS))
250 mu_error ("mu_wordsplit: %s", mu_wordsplit_strerror (&ws));
251 else
252 {
253 free (mutool_shell_prompt); 247 free (mutool_shell_prompt);
254 mutool_shell_prompt = mu_strdup (ws.ws_wordv[0]); 248 mutool_shell_prompt = mu_strdup (argv[1]);
255 }
256 mu_wordsplit_free (&ws);
257 return 0; 249 return 0;
258 } 250 }
259 251
...@@ -593,23 +585,22 @@ execute_line (char *line) ...@@ -593,23 +585,22 @@ execute_line (char *line)
593 static char * 585 static char *
594 input_line_interactive () 586 input_line_interactive ()
595 { 587 {
596 char *line; 588 char *line, *prompt;
597 int wsflags = MU_WRDSF_NOSPLIT | MU_WRDSF_NOCMD; 589 int rc;
598 struct mu_wordsplit ws;
599 590
600 report_signals (); 591 report_signals ();
601 if (mutool_prompt_env) 592 rc = mu_str_expand (&prompt, mutool_shell_prompt, mutool_prompt_assoc);
593 if (rc)
602 { 594 {
603 ws.ws_env = (const char **)mutool_prompt_env; 595 if (rc == MU_ERR_FAILURE)
604 wsflags |= MU_WRDSF_ENV | MU_WRDSF_ENV_KV; 596 mu_error (_("cannot expand prompt: %s"), prompt);
605 }
606 if (mu_wordsplit (mutool_shell_prompt, &ws, wsflags))
607 line = readline (mutool_shell_prompt);
608 else 597 else
609 { 598 mu_error (_("cannot expand prompt: %s"), mu_strerror (rc));
610 line = readline (ws.ws_wordv[0]); 599 exit (1);
611 mu_wordsplit_free (&ws);
612 } 600 }
601
602 line = readline (prompt);
603 free (prompt);
613 return line; 604 return line;
614 } 605 }
615 606
...@@ -634,6 +625,29 @@ shell_exit (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED) ...@@ -634,6 +625,29 @@ shell_exit (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED)
634 return 0; 625 return 0;
635 } 626 }
636 627
628 mu_assoc_t
629 mutool_shell_prompt_assoc (void)
630 {
631 if (mutool_prompt_assoc)
632 mu_assoc_clear (mutool_prompt_assoc);
633 else
634 {
635 int rc = mu_assoc_create (&mutool_prompt_assoc, 0);
636 if (rc)
637 {
638 mu_diag_funcall (MU_DIAG_ERROR, "mu_assoc_create", NULL, rc);
639 exit (1);
640 }
641 }
642 mu_assoc_install (mutool_prompt_assoc, "program-name", mu_program_name);
643 mu_assoc_install (mutool_prompt_assoc, "canonical-program-name",
644 "mailutils");
645 mu_assoc_install (mutool_prompt_assoc, "package", PACKAGE);
646 mu_assoc_install (mutool_prompt_assoc, "version", PACKAGE_VERSION);
647
648 return mutool_prompt_assoc;
649 }
650
637 int 651 int
638 mutool_shell (const char *name, struct mutool_command *cmd) 652 mutool_shell (const char *name, struct mutool_command *cmd)
639 { 653 {
......
...@@ -69,39 +69,18 @@ smtp_session_str (enum smtp_session_status stat) ...@@ -69,39 +69,18 @@ smtp_session_str (enum smtp_session_status stat)
69 } 69 }
70 70
71 static void 71 static void
72 smtp_prompt_env () 72 smtp_prompt_env (void)
73 { 73 {
74 mu_assoc_t assoc = mutool_shell_prompt_assoc ();
74 const char *value; 75 const char *value;
75 76
76 if (!mutool_prompt_env)
77 mutool_prompt_env = mu_calloc (2*7 + 1, sizeof(mutool_prompt_env[0]));
78
79 mutool_prompt_env[0] = "user";
80 mutool_prompt_env[1] = "[nouser]";
81 if (smtp_session_status == smtp_session_logged_in && 77 if (smtp_session_status == smtp_session_logged_in &&
82 mu_smtp_get_param (smtp, MU_SMTP_PARAM_USERNAME, &value) == 0) 78 mu_smtp_get_param (smtp, MU_SMTP_PARAM_USERNAME, &value) == 0)
83 mutool_prompt_env[1] = (char*) value; 79 mu_assoc_install (assoc, "user", value);
84
85 mutool_prompt_env[2] = "host";
86 mutool_prompt_env[3] = (smtp_session_status != smtp_session_disconnected) ?
87 host : "[nohost]";
88
89 mutool_prompt_env[4] = "program-name";
90 mutool_prompt_env[5] = (char*) mu_program_name;
91
92 mutool_prompt_env[6] = "canonical-program-name";
93 mutool_prompt_env[7] = "mu";
94 80
95 mutool_prompt_env[8] = "package"; 81 if (smtp_session_status != smtp_session_disconnected)
96 mutool_prompt_env[9] = PACKAGE; 82 mu_assoc_install (assoc, "host", host);
97 83 mu_assoc_install (assoc, "status", smtp_session_str (smtp_session_status));
98 mutool_prompt_env[10] = "version";
99 mutool_prompt_env[11] = PACKAGE_VERSION;
100
101 mutool_prompt_env[12] = "status";
102 mutool_prompt_env[13] = (char*) smtp_session_str (smtp_session_status);
103
104 mutool_prompt_env[14] = NULL;
105 } 84 }
106 85
107 static void 86 static void
......