Commit 38d688c1 38d688c17f9545c032e22f117189b970e858697d by Sergey Poznyakoff

Avoid using strtok(_r)

* TODO: Update.
* gnulib.modules: Remove strtok_r
* imap4d/auth_gsasl.c (auth_gsasl_capa_init): Use mu_wordsplit instead
of strtok.
* imap4d/imap4d.h (strtok_r): Remove declaration.
* lib/mailcap.c (mime_context) <no_ask_str>: Remove. All uses updated.
(mime_context_fill): Use mu_wordsplit instead
of strtok.
(mime_context_write_input): Tolerate ENOSYS return from mu_stream_seek.
(display_stream_mailcap): Use mu_wordsplit instead
of strtok.
* libmailutils/diag/gdebug.c (mu_debug_level_from_string)
(mu_global_debug_from_string): Use mu_wordsplit instead of strtok.
* libmu_cfg/sieve.c (_add_path): Likewise.
* libmu_sieve/extensions/list.c: Likewise.
* mail/escape.c (quote0): Likewise.

* mail/util.c (util_header_expand): Likewise.
(util_rfc2047_decode): Use mu_parse_lc_all.
* mh/mh_init.c (mh_charset): Use mu_parse_lc_all.
* frm/common.c (get_charset): Use mu_parse_lc_all.

* libmailutils/base/lcall.c: New file.
* libmailutils/base/Makefile.am (libbase_la_SOURCES): Add lcall.c
* libmailutils/string/strlst.c: New file.
* libmailutils/string/Makefile.am (libstring_la_SOURCES): Add strlst.c.
* include/mailutils/cstr.h: Include mailutils/types.h
(mu_string_split): New proto.
* include/mailutils/nls.h (MU_LC_LANG, MU_LC_TERR)
(MU_LC_CSET,MU_LC_MOD): New flags.
(mu_lc_all): New struct.
(mu_parse_lc_all, mu_lc_all_free): New protos.
(mu_charset_lookup): New proto (from util.h).
* include/mailutils/util.h (mu_charset_lookup): Move to nls.h

* libmailutils/base/tempfile.c (mu_tempname): Shut up compiler
warning.
1 parent 0fac46ab
1 GNU mailutils TODO list. 2010-12-01 1 GNU mailutils TODO list. 2010-12-02
2 Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2010 Free 2 Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2010 Free
3 Software Foundation, Inc. 3 Software Foundation, Inc.
4 4
...@@ -12,7 +12,9 @@ Software Foundation, Inc. ...@@ -12,7 +12,9 @@ Software Foundation, Inc.
12 12
13 * use the above in message_stream. 13 * use the above in message_stream.
14 14
15 * eliminate uses of strtok(_r) 15 * envelope: date returned by mu_envelope_?get_date must not end with a \n
16
17 See also mu_rfc2822_in_reply_to.
16 18
17 * mail: rewrite I/O support using streams. 19 * mail: rewrite I/O support using streams.
18 20
...@@ -51,6 +53,10 @@ See guimb/scm/Makefile.am for a discussion. ...@@ -51,6 +53,10 @@ See guimb/scm/Makefile.am for a discussion.
51 53
52 * lib/mailcap.c: rewrite using streams 54 * lib/mailcap.c: rewrite using streams
53 55
56 * sieve: needs an option to add directory at the head of the search path
57
58 * sieve: extension tests
59
54 * mu_address_createv: pass hints as in mu_address_create_hint? 60 * mu_address_createv: pass hints as in mu_address_create_hint?
55 61
56 * fix Python support 62 * fix Python support
......
...@@ -63,10 +63,6 @@ get_charset () ...@@ -63,10 +63,6 @@ get_charset ()
63 if (!output_charset) 63 if (!output_charset)
64 { 64 {
65 char *tmp; 65 char *tmp;
66 const char *str = NULL;
67 char locale[32];
68
69 memset (locale, 0, sizeof (locale));
70 66
71 /* Try to deduce the charset from LC_ALL or LANG variables */ 67 /* Try to deduce the charset from LC_ALL or LANG variables */
72 68
...@@ -76,24 +72,14 @@ get_charset () ...@@ -76,24 +72,14 @@ get_charset ()
76 72
77 if (tmp) 73 if (tmp)
78 { 74 {
79 char *sp = NULL; 75 struct mu_lc_all lc_all;
80 char *lang;
81 char *terr;
82
83 strncpy (locale, tmp, sizeof (locale) - 1);
84
85 lang = strtok_r (locale, "_", &sp);
86 terr = strtok_r (NULL, ".", &sp);
87 str = strtok_r (NULL, "@", &sp);
88 76
89 if (!str) 77 if (mu_parse_lc_all (tmp, &lc_all, MU_LC_CSET) == 0)
90 str = mu_charset_lookup (lang, terr); 78 output_charset = lc_all.charset;
91 } 79 }
92 80
93 if (!str) 81 if (!output_charset)
94 str = "ASCII"; 82 output_charset = xstrdup ("ASCII");
95
96 output_charset = xstrdup (str);
97 } 83 }
98 return output_charset; 84 return output_charset;
99 } 85 }
......
...@@ -21,5 +21,4 @@ obstack ...@@ -21,5 +21,4 @@ obstack
21 realloc 21 realloc
22 setenv 22 setenv
23 stdint 23 stdint
24 strtok_r
25 xalloc 24 xalloc
......
...@@ -181,21 +181,37 @@ static void ...@@ -181,21 +181,37 @@ static void
181 auth_gsasl_capa_init (int disable) 181 auth_gsasl_capa_init (int disable)
182 { 182 {
183 int rc; 183 int rc;
184 char *listmech, *name, *s; 184 char *listmech;
185 struct mu_wordsplit ws;
185 186
186 rc = gsasl_server_mechlist (ctx, &listmech); 187 rc = gsasl_server_mechlist (ctx, &listmech);
187 if (rc != GSASL_OK) 188 if (rc != GSASL_OK)
188 return; 189 return;
189 190
190 for (name = strtok_r (listmech, " ", &s); name; 191 ws.ws_delim = " ";
191 name = strtok_r (NULL, " ", &s)) 192 if (mu_wordsplit (listmech, &ws,
193 MU_WRDSF_DELIM|MU_WRDSF_SQUEEZE_DELIMS|
194 MU_WRDSF_NOVAR|MU_WRDSF_NOCMD))
195 {
196 mu_error (_("cannot split line `%s': %s"), listmech,
197 mu_wordsplit_strerror (&ws));
198 }
199 else
200 {
201 size_t i;
202
203 for (i = 0; i < ws.ws_wordc; i++)
192 { 204 {
193 if (disable) 205 if (disable)
194 auth_remove (name); 206 auth_remove (ws.ws_wordv[i]);
195 else 207 else
196 auth_add (strdup (name), auth_gsasl); 208 {
209 auth_add (ws.ws_wordv[i], auth_gsasl);
210 ws.ws_wordv[i] = NULL;
211 }
212 }
213 mu_wordsplit_free (&ws);
197 } 214 }
198
199 free (listmech); 215 free (listmech);
200 } 216 }
201 217
......
...@@ -201,10 +201,6 @@ extern mu_list_t imap4d_id_list; ...@@ -201,10 +201,6 @@ extern mu_list_t imap4d_id_list;
201 extern int imap4d_argc; 201 extern int imap4d_argc;
202 extern char **imap4d_argv; 202 extern char **imap4d_argv;
203 203
204 #ifndef HAVE_STRTOK_R
205 extern char *strtok_r (char *s, const char *delim, char **save_ptr);
206 #endif
207
208 /* Input functions */ 204 /* Input functions */
209 extern mu_stream_t iostream; 205 extern mu_stream_t iostream;
210 extern int io_untagged_response (int, const char *, ...) MU_PRINTFLIKE(2,3); 206 extern int io_untagged_response (int, const char *, ...) MU_PRINTFLIKE(2,3);
......
...@@ -22,6 +22,8 @@ ...@@ -22,6 +22,8 @@
22 extern "C" { 22 extern "C" {
23 #endif 23 #endif
24 24
25 # include <mailutils/types.h>
26
25 int mu_strlower (char *); 27 int mu_strlower (char *);
26 int mu_strupper (char *); 28 int mu_strupper (char *);
27 29
...@@ -42,6 +44,8 @@ char *mu_str_skip_cset_comp (const char *str, const char *cset); ...@@ -42,6 +44,8 @@ char *mu_str_skip_cset_comp (const char *str, const char *cset);
42 44
43 char *mu_str_stripws (char *string); 45 char *mu_str_stripws (char *string);
44 46
47 int mu_string_split (const char *string, char *delim, mu_list_t list);
48
45 #ifdef __cplusplus 49 #ifdef __cplusplus
46 } 50 }
47 #endif 51 #endif
......
...@@ -46,6 +46,24 @@ extern void mu_init_nls (void); ...@@ -46,6 +46,24 @@ extern void mu_init_nls (void);
46 extern char *mu_set_locale (const char *locale); 46 extern char *mu_set_locale (const char *locale);
47 void mu_restore_locale (void); 47 void mu_restore_locale (void);
48 48
49 #define MU_LC_LANG 0x01
50 #define MU_LC_TERR 0x02
51 #define MU_LC_CSET 0x04
52 #define MU_LC_MOD 0x08
53
54 struct mu_lc_all
55 {
56 int flags;
57 char *language;
58 char *territory;
59 char *charset;
60 char *modifier;
61 };
62
63 int mu_parse_lc_all (const char *arg, struct mu_lc_all *str, int flags);
64 void mu_lc_all_free (struct mu_lc_all *str);
65 const char *mu_charset_lookup (char *lang, char *terr);
66
49 #ifdef __cplusplus 67 #ifdef __cplusplus
50 } 68 }
51 #endif 69 #endif
......
...@@ -176,7 +176,6 @@ int mu_getpass (mu_stream_t in, mu_stream_t out, const char *prompt, ...@@ -176,7 +176,6 @@ int mu_getpass (mu_stream_t in, mu_stream_t out, const char *prompt,
176 /* Get the host name, doing a gethostbyname() if possible. */ 176 /* Get the host name, doing a gethostbyname() if possible. */
177 int mu_get_host_name (char **host); 177 int mu_get_host_name (char **host);
178 int mu_spawnvp(const char *prog, char *av[], int *stat); 178 int mu_spawnvp(const char *prog, char *av[], int *stat);
179 const char *mu_charset_lookup (char *lang, char *terr);
180 int mu_scheme_autodetect_p (mu_url_t); 179 int mu_scheme_autodetect_p (mu_url_t);
181 180
182 struct timeval; 181 struct timeval;
......
...@@ -53,7 +53,6 @@ struct mime_context ...@@ -53,7 +53,6 @@ struct mime_context
53 char *temp_file; 53 char *temp_file;
54 int unlink_temp_file; 54 int unlink_temp_file;
55 55
56 char *no_ask_str;
57 mu_list_t no_ask_types; 56 mu_list_t no_ask_types;
58 int debug_level; 57 int debug_level;
59 int flags; 58 int flags;
...@@ -66,7 +65,8 @@ mime_context_fill (struct mime_context *ctx, const char *file, ...@@ -66,7 +65,8 @@ mime_context_fill (struct mime_context *ctx, const char *file,
66 mu_stream_t input, mu_header_t hdr, const char *no_ask, 65 mu_stream_t input, mu_header_t hdr, const char *no_ask,
67 int interactive, int dry_run, int debug_level) 66 int interactive, int dry_run, int debug_level)
68 { 67 {
69 char *p, *sp; 68 struct mu_wordsplit ws;
69 size_t i;
70 70
71 memset (ctx, 0, sizeof *ctx); 71 memset (ctx, 0, sizeof *ctx);
72 ctx->input = input; 72 ctx->input = input;
...@@ -74,7 +74,19 @@ mime_context_fill (struct mime_context *ctx, const char *file, ...@@ -74,7 +74,19 @@ mime_context_fill (struct mime_context *ctx, const char *file,
74 if (mu_header_aget_value (hdr, MU_HEADER_CONTENT_TYPE, 74 if (mu_header_aget_value (hdr, MU_HEADER_CONTENT_TYPE,
75 &ctx->content_type_buffer)) 75 &ctx->content_type_buffer))
76 return 1; 76 return 1;
77 ctx->content_type = strtok_r (ctx->content_type_buffer, ";", &sp); 77 ws.ws_delim = ";";
78 if (mu_wordsplit (ctx->content_type_buffer, &ws,
79 MU_WRDSF_DELIM|MU_WRDSF_SQUEEZE_DELIMS|MU_WRDSF_WS|
80 MU_WRDSF_NOVAR|MU_WRDSF_NOCMD))
81 {
82 mu_error (_("cannot split line `%s': %s"),
83 ctx->content_type_buffer,
84 mu_wordsplit_strerror (&ws));
85 return 1;
86 }
87
88 ctx->content_type = ws.ws_wordv[0];
89 ws.ws_wordv[0] = NULL;
78 ctx->temp_file = file ? strdup (file) : NULL; 90 ctx->temp_file = file ? strdup (file) : NULL;
79 ctx->unlink_temp_file = 0; 91 ctx->unlink_temp_file = 0;
80 92
...@@ -85,24 +97,20 @@ mime_context_fill (struct mime_context *ctx, const char *file, ...@@ -85,24 +97,20 @@ mime_context_fill (struct mime_context *ctx, const char *file,
85 ctx->debug_level = debug_level; 97 ctx->debug_level = debug_level;
86 98
87 mu_list_create (&ctx->values); 99 mu_list_create (&ctx->values);
88 while ((p = strtok_r (NULL, ";", &sp))) 100
101 for (i = 1; i < ws.ws_wordc; i++)
89 { 102 {
90 while (*p && isspace (*p)) 103 mu_list_append (ctx->values, ws.ws_wordv[i]);
91 p++; 104 ws.ws_wordv[i] = NULL;
92 mu_list_append (ctx->values, p);
93 } 105 }
106 mu_wordsplit_free (&ws);
94 107
95 if (no_ask) 108 if (no_ask)
96 { 109 {
97 ctx->no_ask_str = xstrdup (no_ask);
98 mu_list_create (&ctx->no_ask_types); 110 mu_list_create (&ctx->no_ask_types);
99 for (p = strtok_r (ctx->no_ask_str, ",", &sp); p; 111 mu_list_set_destroy_item (ctx->no_ask_types, mu_list_free_item);
100 p = strtok_r (NULL, ",", &sp)) 112 if (mu_string_split (no_ask, ",", ctx->no_ask_types))
101 { 113 return 1;
102 while (*p && isspace (*p))
103 p++;
104 mu_list_append (ctx->no_ask_types, p);
105 }
106 } 114 }
107 return 0; 115 return 0;
108 } 116 }
...@@ -115,7 +123,6 @@ mime_context_release (struct mime_context *ctx) ...@@ -115,7 +123,6 @@ mime_context_release (struct mime_context *ctx)
115 unlink (ctx->temp_file); 123 unlink (ctx->temp_file);
116 free (ctx->temp_file); 124 free (ctx->temp_file);
117 mu_list_destroy (&ctx->values); 125 mu_list_destroy (&ctx->values);
118 free (ctx->no_ask_str);
119 mu_list_destroy (&ctx->no_ask_types); 126 mu_list_destroy (&ctx->no_ask_types);
120 } 127 }
121 128
...@@ -208,8 +215,11 @@ mime_context_write_input (struct mime_context *ctx, int fd) ...@@ -208,8 +215,11 @@ mime_context_write_input (struct mime_context *ctx, int fd)
208 215
209 mime_context_get_input (ctx, &input); 216 mime_context_get_input (ctx, &input);
210 status = mu_stream_seek (input, 0, SEEK_SET, NULL); 217 status = mu_stream_seek (input, 0, SEEK_SET, NULL);
211 if (status) 218 if (status && status != ENOSYS)
219 {
220 mu_diag_funcall (MU_DIAG_ERROR, "mu_stream_seek", NULL, status);
212 abort (); /* FIXME */ 221 abort (); /* FIXME */
222 }
213 while ((status = mu_stream_read (input, buf, sizeof buf, &n)) == 0 223 while ((status = mu_stream_read (input, buf, sizeof buf, &n)) == 0
214 && n) 224 && n)
215 write (fd, buf, n); 225 write (fd, buf, n);
...@@ -661,8 +671,8 @@ display_stream_mailcap (const char *ident, mu_stream_t stream, mu_header_t hdr, ...@@ -661,8 +671,8 @@ display_stream_mailcap (const char *ident, mu_stream_t stream, mu_header_t hdr,
661 const char *no_ask, int interactive, int dry_run, 671 const char *no_ask, int interactive, int dry_run,
662 int debug_level) 672 int debug_level)
663 { 673 {
664 char *p, *sp; 674 char *mailcap_path, *mailcap_path_tmp = NULL;
665 char *mailcap_path; 675 struct mu_wordsplit ws;
666 struct mime_context ctx; 676 struct mime_context ctx;
667 int rc = 1; 677 int rc = 1;
668 678
...@@ -673,24 +683,37 @@ display_stream_mailcap (const char *ident, mu_stream_t stream, mu_header_t hdr, ...@@ -673,24 +683,37 @@ display_stream_mailcap (const char *ident, mu_stream_t stream, mu_header_t hdr,
673 if (!mailcap_path) 683 if (!mailcap_path)
674 { 684 {
675 char *home = mu_get_homedir (); 685 char *home = mu_get_homedir ();
676 mu_asprintf (&mailcap_path, "%s/.mailcap:%s", home, DEFAULT_MAILCAP); 686 mailcap_path_tmp = mu_make_file_name_suf (home, ".mailcap:",
687 DEFAULT_MAILCAP);
677 free (home); 688 free (home);
678 if (!mailcap_path) 689 if (!mailcap_path_tmp)
679 return 1; 690 return 1;
691 mailcap_path = mailcap_path_tmp;
680 } 692 }
681 else
682 mailcap_path = strdup (mailcap_path);
683 693
684 obstack_init (&expand_stack); 694 obstack_init (&expand_stack);
685 695
686 for (p = strtok_r (mailcap_path, ":", &sp); p; p = strtok_r (NULL, ":", &sp)) 696 ws.ws_delim = ":";
697 if (mu_wordsplit (mailcap_path, &ws,
698 MU_WRDSF_DELIM|MU_WRDSF_SQUEEZE_DELIMS|
699 MU_WRDSF_NOVAR|MU_WRDSF_NOCMD))
687 { 700 {
688 if ((rc = find_entry (p, &ctx)) == 0) 701 mu_error (_("cannot split line `%s': %s"), mailcap_path,
689 break; 702 mu_wordsplit_strerror (&ws));
690 } 703 }
704 else
705 {
706 size_t i;
691 707
708 for (i = 0; i < ws.ws_wordc; i++)
709 {
710 if ((rc = find_entry (ws.ws_wordv[i], &ctx)) == 0)
711 break;
712 }
713 mu_wordsplit_free (&ws);
714 }
692 obstack_free (&expand_stack, NULL); 715 obstack_free (&expand_stack, NULL);
693 free (mailcap_path); 716 free (mailcap_path_tmp);
694 mime_context_release (&ctx); 717 mime_context_release (&ctx);
695 return rc; 718 return rc;
696 } 719 }
......
...@@ -36,6 +36,7 @@ libbase_la_SOURCES = \ ...@@ -36,6 +36,7 @@ libbase_la_SOURCES = \
36 hostname.c\ 36 hostname.c\
37 iterator.c\ 37 iterator.c\
38 kwd.c\ 38 kwd.c\
39 lcall.c\
39 list.c\ 40 list.c\
40 listlist.c\ 41 listlist.c\
41 locale.c\ 42 locale.c\
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2003, 2009, 2010 Free Software Foundation, Inc.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 3 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General
15 Public License along with this library. If not, see
16 <http://www.gnu.org/licenses/>. */
17
18 #ifdef HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21
22 #include <stdlib.h>
23 #include <string.h>
24 #include <errno.h>
25 #include <mailutils/nls.h>
26
27 static int
28 _parse_lc_all (const char *arg, struct mu_lc_all *str, int flags)
29 {
30 char *s;
31 size_t n;
32
33 n = strcspn (arg, "_.@");
34 if (flags & MU_LC_LANG)
35 {
36 s = malloc (n + 1);
37 if (!s)
38 return ENOMEM;
39 memcpy (s, arg, n);
40 s[n] = 0;
41 str->language = s;
42 str->flags |= MU_LC_LANG;
43 }
44 else
45 str->language = NULL;
46 arg += n;
47
48 if (arg[0] == '_')
49 {
50 arg++;
51
52 n = strcspn (arg, ".@");
53 if (flags & MU_LC_TERR)
54 {
55 s = malloc (n + 1);
56 if (!s)
57 return ENOMEM;
58 memcpy (s, arg, n);
59 s[n] = 0;
60 str->territory = s;
61 str->flags |= MU_LC_TERR;
62 }
63 else
64 str->territory = NULL;
65 arg += n;
66 }
67
68 if (arg[0] == '.')
69 {
70 arg++;
71
72 n = strcspn (arg, "@");
73 if (flags & MU_LC_CSET)
74 {
75 s = malloc (n + 1);
76 if (!s)
77 return ENOMEM;
78 memcpy (s, arg, n);
79 s[n] = 0;
80 str->charset = s;
81 str->flags |= MU_LC_CSET;
82 }
83 else
84 str->charset = NULL;
85 arg += n;
86 }
87
88 if (arg[0])
89 {
90 arg++;
91 if (flags & MU_LC_MOD)
92 {
93 str->modifier = strdup (arg);
94 if (!str->modifier)
95 return ENOMEM;
96 str->flags |= MU_LC_MOD;
97 }
98 }
99 return 0;
100 }
101
102 void
103 mu_lc_all_free (struct mu_lc_all *str)
104 {
105 free (str->language);
106 free (str->territory);
107 free (str->charset);
108 free (str->modifier);
109 }
110
111 int
112 mu_parse_lc_all (const char *arg, struct mu_lc_all *str, int flags)
113 {
114 int rc;
115
116 memset (str, 0, sizeof (str[0]));
117 rc = _parse_lc_all (arg, str, flags);
118 if (rc == 0 && !str->charset)
119 {
120 const char *charset = mu_charset_lookup (str->language, str->territory);
121 if (charset)
122 {
123 str->charset = strdup (charset);
124 if (!str->charset)
125 rc = ENOMEM;
126 }
127 }
128 if (rc)
129 mu_lc_all_free (str);
130 return rc;
131 }
...@@ -220,7 +220,7 @@ mu_tempname (const char *tmpdir) ...@@ -220,7 +220,7 @@ mu_tempname (const char *tmpdir)
220 struct mu_tempfile_hints hints; 220 struct mu_tempfile_hints hints;
221 char *filename = NULL; 221 char *filename = NULL;
222 int fd; 222 int fd;
223 hints.tmpdir = tmpdir; 223 hints.tmpdir = (char*)tmpdir;
224 if (mu_tempfile (&hints, MU_TEMPFILE_TMPDIR, &fd, &filename)) 224 if (mu_tempfile (&hints, MU_TEMPFILE_TMPDIR, &fd, &filename))
225 return NULL; 225 return NULL;
226 close (fd); 226 close (fd);
......
...@@ -118,15 +118,25 @@ mu_debug_level_from_string (const char *string, mu_log_level_t *plev, ...@@ -118,15 +118,25 @@ mu_debug_level_from_string (const char *string, mu_log_level_t *plev,
118 } 118 }
119 else 119 else
120 { 120 {
121 char *p = strdup (string); 121 size_t i;
122 size_t len = strlen (p); 122 struct mu_wordsplit ws;
123 if (len > 0 && p[len-1] == '\n') 123
124 p[len-1] = 0; 124 if (mu_wordsplit (string, &ws,
125 for (q = strtok (p, ","); q; q = strtok (NULL, ",")) 125 MU_WRDSF_DELIM|MU_WRDSF_SQUEEZE_DELIMS|
126 MU_WRDSF_WS|
127 MU_WRDSF_NOVAR|MU_WRDSF_NOCMD))
128 {
129 mu_error (_("cannot split line `%s': %s"), string,
130 mu_wordsplit_strerror (&ws));
131 return MU_ERR_FAILURE;
132 }
133
134 for (i = 0; i < ws.ws_wordc; i++)
126 { 135 {
127 int flag; 136 int flag;
128 int revert = 0; 137 int revert = 0;
129 int upto = 0; 138 int upto = 0;
139 const char *q = ws.ws_wordv[i];
130 140
131 if (*q == '!') 141 if (*q == '!')
132 { 142 {
...@@ -158,7 +168,7 @@ mu_debug_level_from_string (const char *string, mu_log_level_t *plev, ...@@ -158,7 +168,7 @@ mu_debug_level_from_string (const char *string, mu_log_level_t *plev,
158 level |= MU_DEBUG_LEVEL_MASK (flag); 168 level |= MU_DEBUG_LEVEL_MASK (flag);
159 } 169 }
160 } 170 }
161 free (p); 171 mu_wordsplit_free (&ws);
162 } 172 }
163 *plev = level; 173 *plev = level;
164 return 0; 174 return 0;
...@@ -207,12 +217,24 @@ mu_global_debug_from_string (const char *string, const char *errpfx) ...@@ -207,12 +217,24 @@ mu_global_debug_from_string (const char *string, const char *errpfx)
207 } 217 }
208 else 218 else
209 { 219 {
210 char *q; 220 size_t j;
211 for (q = strtok (p, ","); q; q = strtok (NULL, ",")) 221 struct mu_wordsplit ws1;
222
223 ws.ws_delim = ",";
224 if (mu_wordsplit (p, &ws1,
225 MU_WRDSF_DELIM|MU_WRDSF_NOVAR|MU_WRDSF_NOCMD))
226 {
227 mu_error (_("cannot split line `%s': %s"), p,
228 mu_wordsplit_strerror (&ws));
229 return MU_ERR_FAILURE;
230 }
231
232 for (j = 0; j < ws1.ws_wordc; j++)
212 { 233 {
213 int flag; 234 int flag;
214 int revert = 0; 235 int revert = 0;
215 int upto = 0; 236 int upto = 0;
237 const char *q = ws1.ws_wordv[j];
216 238
217 if (*q == '!') 239 if (*q == '!')
218 { 240 {
...@@ -243,6 +265,7 @@ mu_global_debug_from_string (const char *string, const char *errpfx) ...@@ -243,6 +265,7 @@ mu_global_debug_from_string (const char *string, const char *errpfx)
243 level |= MU_DEBUG_LEVEL_MASK (flag); 265 level |= MU_DEBUG_LEVEL_MASK (flag);
244 } 266 }
245 } 267 }
268 mu_wordsplit_free (&ws1);
246 } 269 }
247 } 270 }
248 else 271 else
......
...@@ -267,7 +267,7 @@ mu_streamref_create_abridged (mu_stream_t *pref, mu_stream_t str, ...@@ -267,7 +267,7 @@ mu_streamref_create_abridged (mu_stream_t *pref, mu_stream_t str,
267 int flags; 267 int flags;
268 struct _mu_streamref *sp; 268 struct _mu_streamref *sp;
269 269
270 rc = mu_stream_seek (str, 0, MU_SEEK_SET, &off); 270 rc = mu_stream_seek (str, 0, MU_SEEK_SET, &off);//FIXME: SEEK_CUR?
271 if (rc) 271 if (rc)
272 return rc; 272 return rc;
273 mu_stream_get_flags (str, &flags); 273 mu_stream_get_flags (str, &flags);
......
...@@ -27,6 +27,7 @@ libstring_la_SOURCES = \ ...@@ -27,6 +27,7 @@ libstring_la_SOURCES = \
27 strltrim.c\ 27 strltrim.c\
28 strskip.c\ 28 strskip.c\
29 stripws.c\ 29 stripws.c\
30 strlst.c\
30 strrtrim.c\ 31 strrtrim.c\
31 trueans.c\ 32 trueans.c\
32 unfold.c\ 33 unfold.c\
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999, 2000, 2001, 2002, 2003, 2005, 2006, 2007, 2009,
3 2010 Free 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 #if HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21
22 #include <errno.h>
23 #include <mailutils/errno.h>
24 #include <mailutils/list.h>
25 #include <mailutils/wordsplit.h>
26 #include <mailutils/cstr.h>
27
28 int
29 mu_string_split (const char *string, char *delim, mu_list_t list)
30 {
31 size_t i;
32 struct mu_wordsplit ws;
33 int rc = 0;
34
35 if (!string || !delim || !list)
36 return EINVAL;
37
38 /* Split the string */
39 ws.ws_delim = delim;
40 if (mu_wordsplit (string, &ws,
41 MU_WRDSF_DELIM|MU_WRDSF_SQUEEZE_DELIMS|
42 MU_WRDSF_NOVAR|MU_WRDSF_NOCMD))
43 return errno;
44
45 for (i = 0; i < ws.ws_wordc; i++)
46 {
47 rc = mu_list_append (list, ws.ws_wordv[i]);
48 if (rc)
49 break;
50 }
51
52 if (rc)
53 {
54 /* If failed, restore LIST to the state before entering this
55 function. */
56 size_t j;
57 mu_list_comparator_t cptr =
58 mu_list_set_comparator (list, NULL);
59 mu_list_destroy_item_t dptr =
60 mu_list_set_destroy_item (list, NULL);
61
62 for (j = 0; j < i; j++)
63 mu_list_remove (list, ws.ws_wordv[j]);
64 mu_list_set_destroy_item (list, dptr);
65 mu_list_set_comparator (list, cptr);
66 }
67 else
68 /* Make sure ws.ws_wordv[x] are not freed */
69 ws.ws_wordc = 0;
70 mu_wordsplit_free (&ws);
71 return rc;
72 }
...@@ -61,7 +61,6 @@ cb_clear_include_path (mu_debug_t debug, void *data, mu_config_value_t *val) ...@@ -61,7 +61,6 @@ cb_clear_include_path (mu_debug_t debug, void *data, mu_config_value_t *val)
61 static int 61 static int
62 _add_path (mu_debug_t debug, const char *arg, void *data) 62 _add_path (mu_debug_t debug, const char *arg, void *data)
63 { 63 {
64 char *p, *tmp;
65 mu_list_t *plist = data; 64 mu_list_t *plist = data;
66 65
67 if (!*plist) 66 if (!*plist)
...@@ -75,12 +74,7 @@ _add_path (mu_debug_t debug, const char *arg, void *data) ...@@ -75,12 +74,7 @@ _add_path (mu_debug_t debug, const char *arg, void *data)
75 } 74 }
76 mu_list_set_destroy_item (*plist, mu_list_free_item); 75 mu_list_set_destroy_item (*plist, mu_list_free_item);
77 } 76 }
78 /* FIXME: Use mu_argcv */ 77 return mu_string_split (arg, ":", *plist);
79 tmp = strdup (arg);
80 for (p = strtok (tmp, ":"); p; p = strtok (NULL, ":"))
81 mu_list_append (*plist, strdup (p));
82 free (tmp);
83 return 0;
84 } 78 }
85 79
86 static int 80 static int
......
...@@ -31,41 +31,63 @@ ...@@ -31,41 +31,63 @@
31 31
32 32
33 /* Auxiliary functions */ 33 /* Auxiliary functions */
34 struct header_closure { 34 struct header_closure
35 {
35 mu_header_t header; /* Message header */ 36 mu_header_t header; /* Message header */
36 int index; /* Header index */ 37 int index; /* Header index */
37 char *delim; /* List delimiter */ 38 char *delim; /* List delimiter */
38 char *value; /* Retrieved header value */ 39 char **valv; /* Retrieved and split-out header values */
39 char *save; /* Save pointer for strtok_r */ 40 size_t valc; /* Number of values in valv */
41 size_t vali; /* Current index in valv */
40 }; 42 };
41 43
42 static void 44 static void
43 cleanup (struct header_closure *hc) 45 cleanup (struct header_closure *hc)
44 { 46 {
45 free (hc->value); 47 mu_argcv_free (hc->valc, hc->valv);
46 hc->value = hc->save = NULL; 48 hc->valv = NULL;
49 hc->valc = hc->vali = 0;
47 } 50 }
48 51
49 static int 52 static int
50 retrieve_next_header (struct header_closure *hc, char *name, char **pval) 53 retrieve_next_header (struct header_closure *hc, char *name, char **pval)
51 { 54 {
52 char buf[512]; 55 const char *buf;
53 size_t n;
54 56
55 cleanup (hc); 57 cleanup (hc);
56 while (!mu_header_get_field_name (hc->header, hc->index, buf, sizeof(buf), &n)) 58 while (!mu_header_sget_field_name (hc->header, hc->index, &buf))
57 { 59 {
58 int i = hc->index++; 60 int i = hc->index++;
59 if (mu_c_strcasecmp (buf, name) == 0) 61 if (mu_c_strcasecmp (buf, name) == 0)
60 { 62 {
61 if (mu_header_aget_field_value (hc->header, i, &hc->value)) 63 const char *value;
64 struct mu_wordsplit ws;
65
66 if (mu_header_sget_field_value (hc->header, i, &value))
62 return 1; 67 return 1;
63 *pval = strtok_r (hc->value, hc->delim, &hc->save); 68 ws.ws_delim = hc->delim;
64 if (*pval == NULL) 69 if (mu_wordsplit (value, &ws,
70 MU_WRDSF_DELIM|MU_WRDSF_SQUEEZE_DELIMS|
71 MU_WRDSF_WS|
72 MU_WRDSF_NOVAR|MU_WRDSF_NOCMD))
73 {
74 mu_error (_("cannot split line `%s': %s"), value,
75 mu_wordsplit_strerror (&ws));
76 return 1;
77 }
78 if (ws.ws_wordc == 0)
65 { 79 {
66 cleanup (hc); 80 cleanup (hc);
81 mu_wordsplit_free (&ws);
67 return 1; 82 return 1;
68 } 83 }
84 hc->valv = ws.ws_wordv;
85 hc->valc = ws.ws_wordc;
86 hc->vali = 0;
87 ws.ws_wordv = NULL;
88 ws.ws_wordc = 0;
89 mu_wordsplit_free (&ws);
90 *pval = hc->valv[hc->vali++];
69 return 0; 91 return 0;
70 } 92 }
71 } 93 }
...@@ -84,20 +106,18 @@ list_retrieve_header (void *item, void *data, int idx, char **pval) ...@@ -84,20 +106,18 @@ list_retrieve_header (void *item, void *data, int idx, char **pval)
84 106
85 while (1) 107 while (1)
86 { 108 {
87 if (!hc->value) 109 if (!hc->valv)
88 { 110 {
89 if (retrieve_next_header (hc, (char*) item, &p)) 111 if (retrieve_next_header (hc, (char*) item, &p))
90 return 1; 112 return 1;
91 } 113 }
92 else 114 else if (hc->vali == hc->valc)
93 {
94 p = strtok_r (NULL, hc->delim, &hc->save);
95 if (!p)
96 { 115 {
97 cleanup (hc); 116 cleanup (hc);
98 continue; 117 continue;
99 } 118 }
100 } 119 else
120 p = hc->valv[hc->vali++];
101 121
102 *pval = strdup (p); 122 *pval = strdup (p);
103 return 0; 123 return 0;
...@@ -163,7 +183,8 @@ list_test (mu_sieve_machine_t mach, mu_list_t args, mu_list_t tags) ...@@ -163,7 +183,8 @@ list_test (mu_sieve_machine_t mach, mu_list_t args, mu_list_t tags)
163 } 183 }
164 184
165 mu_message_get_header (mu_sieve_get_message (mach), &clos.header); 185 mu_message_get_header (mu_sieve_get_message (mach), &clos.header);
166 result = mu_sieve_vlist_compare (h, v, comp, mu_sieve_get_relcmp (mach, tags), 186 result = mu_sieve_vlist_compare (h, v, comp,
187 mu_sieve_get_relcmp (mach, tags),
167 list_retrieve_header, 188 list_retrieve_header,
168 &clos, NULL) > 0; 189 &clos, NULL) > 0;
169 cleanup (&clos); 190 cleanup (&clos);
......
...@@ -443,7 +443,8 @@ quote0 (msgset_t *mspec, mu_message_t mesg, void *data) ...@@ -443,7 +443,8 @@ quote0 (msgset_t *mspec, mu_message_t mesg, void *data)
443 mu_header_t hdr; 443 mu_header_t hdr;
444 mu_body_t body; 444 mu_body_t body;
445 mu_stream_t stream; 445 mu_stream_t stream;
446 char buffer[512]; 446 char *buffer = NULL;
447 size_t size = 0;
447 size_t n = 0; 448 size_t n = 0;
448 char *prefix = "\t"; 449 char *prefix = "\t";
449 450
...@@ -465,22 +466,18 @@ quote0 (msgset_t *mspec, mu_message_t mesg, void *data) ...@@ -465,22 +466,18 @@ quote0 (msgset_t *mspec, mu_message_t mesg, void *data)
465 mu_header_sget_field_name (hdr, i, &sptr); 466 mu_header_sget_field_name (hdr, i, &sptr);
466 if (mail_header_is_visible (sptr)) 467 if (mail_header_is_visible (sptr))
467 { 468 {
468 char *value; 469 const char *value;
469 470
470 fprintf (ofile, "%s%s: ", prefix, sptr); 471 fprintf (ofile, "%s%s: ", prefix, sptr);
471 if (mu_header_aget_value (hdr, sptr, &value) == 0) 472 if (mu_header_sget_value (hdr, sptr, &value) == 0)
472 { 473 {
473 int i; 474 for (; *value; value++)
474 char *p, *s;
475
476 for (i = 0, p = strtok_r (value, "\n", &s); p;
477 p = strtok_r (NULL, "\n", &s), i++)
478 { 475 {
479 if (i) 476 fputc (*value, ofile);
477 if (*value == '\n')
480 fprintf (ofile, "%s", prefix); 478 fprintf (ofile, "%s", prefix);
481 fprintf (ofile, "%s\n", p);
482 } 479 }
483 free (value); 480 fputc ('\n', ofile);
484 } 481 }
485 } 482 }
486 } 483 }
...@@ -498,12 +495,9 @@ quote0 (msgset_t *mspec, mu_message_t mesg, void *data) ...@@ -498,12 +495,9 @@ quote0 (msgset_t *mspec, mu_message_t mesg, void *data)
498 } 495 }
499 496
500 /* FIXME: Use mu_stream_copy? */ 497 /* FIXME: Use mu_stream_copy? */
501 while (mu_stream_readline (stream, buffer, sizeof buffer - 1, &n) == 0 498 while (mu_stream_getline (stream, &buffer, &size, &n) == 0 && n != 0)
502 && n != 0)
503 {
504 buffer[n] = '\0';
505 fprintf (ofile, "%s%s", prefix, buffer); 499 fprintf (ofile, "%s%s", prefix, buffer);
506 } 500 free (buffer);
507 mu_stream_destroy (&stream); 501 mu_stream_destroy (&stream);
508 return 0; 502 return 0;
509 } 503 }
......
...@@ -935,36 +935,45 @@ util_header_expand (mu_header_t *phdr) ...@@ -935,36 +935,45 @@ util_header_expand (mu_header_t *phdr)
935 mu_header_get_field_count (*phdr, &nfields); 935 mu_header_get_field_count (*phdr, &nfields);
936 for (i = 1; i <= nfields; i++) 936 for (i = 1; i <= nfields; i++)
937 { 937 {
938 char *name, *value; 938 const char *name, *value;
939 939
940 if (mu_header_aget_field_name (*phdr, i, &name)) 940 if (mu_header_sget_field_name (*phdr, i, &name))
941 continue; 941 continue;
942 942
943 if (mu_header_aget_field_value (*phdr, i, &value)) 943 if (mu_header_sget_field_value (*phdr, i, &value))
944 {
945 free (name);
946 continue; 944 continue;
947 }
948 945
949 if (is_address_field (name)) 946 if (is_address_field (name))
950 { 947 {
951 char *p, *s, *exp = NULL; 948 const char *s;
952 mu_address_t addr = NULL; 949 mu_address_t addr = NULL;
950 struct mu_wordsplit ws;
951 size_t j;
952
953 if (mu_header_sget_value (hdr, name, &s) == 0)
954 mu_address_create (&addr, s);
953 955
954 if (mu_header_aget_value (hdr, name, &exp) == 0) 956 ws.ws_delim = ",";
957 if (mu_wordsplit (value, &ws,
958 MU_WRDSF_DELIM|MU_WRDSF_SQUEEZE_DELIMS|
959 MU_WRDSF_WS|
960 MU_WRDSF_NOVAR|MU_WRDSF_NOCMD))
955 { 961 {
956 mu_address_create (&addr, exp); 962 errcnt++;
957 free (exp); 963 mu_error (_("cannot split line `%s': %s"), value,
964 mu_wordsplit_strerror (&ws));
965 break;
958 } 966 }
959 967
960 for (p = strtok_r (value, ",", &s); p; p = strtok_r (NULL, ",", &s)) 968 for (j = 0; j < ws.ws_wordc; j++)
961 { 969 {
970 const char *exp;
962 mu_address_t new_addr; 971 mu_address_t new_addr;
972 char *p = ws.ws_wordv[j];
963 973
964 while (*p && mu_isspace (*p))
965 p++;
966 /* If inplacealiases was set, the value was already expanded */ 974 /* If inplacealiases was set, the value was already expanded */
967 if (mailvar_get (NULL, "inplacealiases", mailvar_type_boolean, 0)) 975 if (mailvar_get (NULL, "inplacealiases",
976 mailvar_type_boolean, 0))
968 exp = alias_expand (p); 977 exp = alias_expand (p);
969 rc = mu_address_create (&new_addr, exp ? exp : p); 978 rc = mu_address_create (&new_addr, exp ? exp : p);
970 if (rc) 979 if (rc)
...@@ -978,28 +987,25 @@ util_header_expand (mu_header_t *phdr) ...@@ -978,28 +987,25 @@ util_header_expand (mu_header_t *phdr)
978 p, mu_strerror (rc)); 987 p, mu_strerror (rc));
979 } 988 }
980 989
981 free (exp);
982 mu_address_union (&addr, new_addr); 990 mu_address_union (&addr, new_addr);
983 mu_address_destroy (&new_addr); 991 mu_address_destroy (&new_addr);
984 } 992 }
985 993
986 if (addr) 994 if (addr)
987 { 995 {
996 char *newvalue;
988 size_t n = 0; 997 size_t n = 0;
989 998
990 free (value);
991 mu_address_to_string (addr, NULL, 0, &n); 999 mu_address_to_string (addr, NULL, 0, &n);
992 value = xmalloc (n + 1); 1000 newvalue = xmalloc (n + 1);
993 mu_address_to_string (addr, value, n + 1, NULL); 1001 mu_address_to_string (addr, newvalue, n + 1, NULL);
994 mu_address_destroy (&addr); 1002 mu_address_destroy (&addr);
995 mu_header_set_value (hdr, name, value, 1); 1003 mu_header_set_value (hdr, name, newvalue, 1);
1004 free (newvalue);
996 } 1005 }
997 } 1006 }
998 else 1007 else
999 mu_header_set_value (hdr, name, value, 0); 1008 mu_header_set_value (hdr, name, value, 0);
1000
1001 free (value);
1002 free (name);
1003 } 1009 }
1004 1010
1005 if (errcnt == 0) 1011 if (errcnt == 0)
...@@ -1083,8 +1089,7 @@ util_run_cached_commands (mu_list_t *list) ...@@ -1083,8 +1089,7 @@ util_run_cached_commands (mu_list_t *list)
1083 void 1089 void
1084 util_rfc2047_decode (char **value) 1090 util_rfc2047_decode (char **value)
1085 { 1091 {
1086 char locale[32]; 1092 char *charset = NULL;
1087 const char *charset = NULL;
1088 char *tmp; 1093 char *tmp;
1089 int rc; 1094 int rc;
1090 1095
...@@ -1093,8 +1098,10 @@ util_rfc2047_decode (char **value) ...@@ -1093,8 +1098,10 @@ util_rfc2047_decode (char **value)
1093 1098
1094 if (mu_c_strcasecmp (charset, "auto") == 0) 1099 if (mu_c_strcasecmp (charset, "auto") == 0)
1095 { 1100 {
1096 memset (locale, 0, sizeof (locale)); 1101 static char *saved_charset;
1097 1102
1103 if (!saved_charset)
1104 {
1098 /* Try to deduce the charset from LC_ALL or LANG variables */ 1105 /* Try to deduce the charset from LC_ALL or LANG variables */
1099 1106
1100 tmp = getenv ("LC_ALL"); 1107 tmp = getenv ("LC_ALL");
...@@ -1103,19 +1110,13 @@ util_rfc2047_decode (char **value) ...@@ -1103,19 +1110,13 @@ util_rfc2047_decode (char **value)
1103 1110
1104 if (tmp) 1111 if (tmp)
1105 { 1112 {
1106 char *sp; 1113 struct mu_lc_all lc_all;
1107 char *lang;
1108 char *terr;
1109
1110 strncpy (locale, tmp, sizeof (locale) - 1);
1111 1114
1112 lang = strtok_r (locale, "_", &sp); 1115 if (mu_parse_lc_all (tmp, &lc_all, MU_LC_CSET) == 0)
1113 terr = strtok_r (NULL, ".", &sp); 1116 saved_charset = lc_all.charset;
1114 charset = strtok_r (NULL, "@", &sp); 1117 }
1115
1116 if (!charset)
1117 charset = mu_charset_lookup (lang, terr);
1118 } 1118 }
1119 charset = saved_charset; /* NOTE: a minor memory leak */
1119 } 1120 }
1120 1121
1121 if (!charset) 1122 if (!charset)
......
...@@ -930,25 +930,16 @@ mh_charset (const char *dfl) ...@@ -930,25 +930,16 @@ mh_charset (const char *dfl)
930 return NULL; 930 return NULL;
931 if (mu_c_strcasecmp (charset, "auto") == 0) 931 if (mu_c_strcasecmp (charset, "auto") == 0)
932 { 932 {
933 /* Try to deduce the charset from LC_ALL variable */ 933 static char *saved_charset;
934 934
935 char *lc_all = getenv ("LC_ALL"); 935 if (!saved_charset)
936 if (lc_all)
937 { 936 {
938 char *sp; 937 /* Try to deduce the charset from LC_ALL variable */
939 char *lang; 938 struct mu_lc_all lc_all;
940 char *terr; 939 if (mu_parse_lc_all (getenv ("LC_ALL"), &lc_all, MU_LC_CSET) == 0)
941 940 saved_charset = lc_all.charset; /* FIXME: Memory leak */
942 char *tmp = strdup (lc_all);
943 lang = strtok_r (tmp, "_", &sp);
944 terr = strtok_r (NULL, ".", &sp);
945 charset = strtok_r (NULL, "@", &sp);
946
947 if (!charset)
948 charset = mu_charset_lookup (lang, terr);
949
950 free (tmp);
951 } 941 }
942 charset = saved_charset;
952 } 943 }
953 return charset; 944 return charset;
954 } 945 }
......
...@@ -526,7 +526,7 @@ main (int argc, char *argv[]) ...@@ -526,7 +526,7 @@ main (int argc, char *argv[])
526 if (rc) 526 if (rc)
527 return EX_CONFIG; 527 return EX_CONFIG;
528 528
529 /* We can finish if its only a compilation check. */ 529 /* We can finish if it's only a compilation check. */
530 if (compile_only) 530 if (compile_only)
531 { 531 {
532 if (compile_only == 2) 532 if (compile_only == 2)
......