Implement RFC 5228, 2.4.2.4 (Encoding Characters Using "encoded-character")
* libmu_sieve/encoded.c: New file. * libmu_sieve/strexp.c: New file. * libmu_sieve/Makefile.am: Add new files. * libmu_sieve/require.c (mu_sieve_require): Understand "encoded-character". * libmu_sieve/sieve-priv.h (mu_i_sv_interp_t): New typedef. (mu_i_sv_expand_encoded_char): New proto. (mu_sieve_require_encoded_character): New proto. * libmu_sieve/sieve.l (string): Rewrite via line_.* functions. This fixes memory leaks on mu_sieve_machine_destroy. (line_finish): Expand ${} sequences before returning. (mu_sieve_require_encoded_character): New function. * sieve/tests/enc-char.at: New file. * sieve/tests/Makefile.am: Add enc-char.at * sieve/tests/testsuite.at: Likewise.
Showing
10 changed files
with
619 additions
and
26 deletions
... | @@ -123,10 +123,10 @@ void mu_sieve_debug_init (void); | ... | @@ -123,10 +123,10 @@ void mu_sieve_debug_init (void); |
123 | 123 | ||
124 | /* Memory allocation functions */ | 124 | /* Memory allocation functions */ |
125 | void *mu_sieve_alloc (size_t size); | 125 | void *mu_sieve_alloc (size_t size); |
126 | void *mu_sieve_palloc (mu_list_t * pool, size_t size); | 126 | void *mu_sieve_palloc (mu_list_t *pool, size_t size); |
127 | void *mu_sieve_prealloc (mu_list_t * pool, void *ptr, size_t size); | 127 | void *mu_sieve_prealloc (mu_list_t *pool, void *ptr, size_t size); |
128 | void mu_sieve_pfree (mu_list_t * pool, void *ptr); | 128 | void mu_sieve_pfree (mu_list_t *pool, void *ptr); |
129 | char *mu_sieve_pstrdup (mu_list_t * pool, const char *str); | 129 | char *mu_sieve_pstrdup (mu_list_t *pool, const char *str); |
130 | 130 | ||
131 | void *mu_sieve_malloc (mu_sieve_machine_t mach, size_t size); | 131 | void *mu_sieve_malloc (mu_sieve_machine_t mach, size_t size); |
132 | char *mu_sieve_mstrdup (mu_sieve_machine_t mach, const char *str); | 132 | char *mu_sieve_mstrdup (mu_sieve_machine_t mach, const char *str); |
... | @@ -134,7 +134,7 @@ void *mu_sieve_mrealloc (mu_sieve_machine_t mach, void *ptr, size_t size); | ... | @@ -134,7 +134,7 @@ void *mu_sieve_mrealloc (mu_sieve_machine_t mach, void *ptr, size_t size); |
134 | void mu_sieve_mfree (mu_sieve_machine_t mach, void *ptr); | 134 | void mu_sieve_mfree (mu_sieve_machine_t mach, void *ptr); |
135 | 135 | ||
136 | mu_sieve_value_t *mu_sieve_value_create (mu_sieve_data_type type, void *data); | 136 | mu_sieve_value_t *mu_sieve_value_create (mu_sieve_data_type type, void *data); |
137 | void mu_sieve_slist_destroy (mu_list_t * plist); | 137 | void mu_sieve_slist_destroy (mu_list_t *plist); |
138 | 138 | ||
139 | /* Symbol space functions */ | 139 | /* Symbol space functions */ |
140 | mu_sieve_register_t *mu_sieve_test_lookup (mu_sieve_machine_t mach, | 140 | mu_sieve_register_t *mu_sieve_test_lookup (mu_sieve_machine_t mach, |
... | @@ -148,8 +148,8 @@ int mu_sieve_register_test_ext (mu_sieve_machine_t mach, | ... | @@ -148,8 +148,8 @@ int mu_sieve_register_test_ext (mu_sieve_machine_t mach, |
148 | mu_sieve_tag_group_t *tags, int required); | 148 | mu_sieve_tag_group_t *tags, int required); |
149 | int mu_sieve_register_test (mu_sieve_machine_t mach, | 149 | int mu_sieve_register_test (mu_sieve_machine_t mach, |
150 | const char *name, mu_sieve_handler_t handler, | 150 | const char *name, mu_sieve_handler_t handler, |
151 | mu_sieve_data_type * arg_types, | 151 | mu_sieve_data_type *arg_types, |
152 | mu_sieve_tag_group_t * tags, int required); | 152 | mu_sieve_tag_group_t *tags, int required); |
153 | 153 | ||
154 | int mu_sieve_register_action_ext (mu_sieve_machine_t mach, | 154 | int mu_sieve_register_action_ext (mu_sieve_machine_t mach, |
155 | const char *name, mu_sieve_handler_t handler, | 155 | const char *name, mu_sieve_handler_t handler, |
... | @@ -158,8 +158,8 @@ int mu_sieve_register_action_ext (mu_sieve_machine_t mach, | ... | @@ -158,8 +158,8 @@ int mu_sieve_register_action_ext (mu_sieve_machine_t mach, |
158 | mu_sieve_tag_group_t *tags, int required); | 158 | mu_sieve_tag_group_t *tags, int required); |
159 | int mu_sieve_register_action (mu_sieve_machine_t mach, | 159 | int mu_sieve_register_action (mu_sieve_machine_t mach, |
160 | const char *name, mu_sieve_handler_t handler, | 160 | const char *name, mu_sieve_handler_t handler, |
161 | mu_sieve_data_type * arg_types, | 161 | mu_sieve_data_type *arg_types, |
162 | mu_sieve_tag_group_t * tags, int required); | 162 | mu_sieve_tag_group_t *tags, int required); |
163 | int mu_sieve_register_comparator (mu_sieve_machine_t mach, const char *name, | 163 | int mu_sieve_register_comparator (mu_sieve_machine_t mach, const char *name, |
164 | int required, mu_sieve_comparator_t is, | 164 | int required, mu_sieve_comparator_t is, |
165 | mu_sieve_comparator_t contains, | 165 | mu_sieve_comparator_t contains, |
... | @@ -177,8 +177,8 @@ mu_sieve_comparator_t mu_sieve_comparator_lookup (mu_sieve_machine_t mach, | ... | @@ -177,8 +177,8 @@ mu_sieve_comparator_t mu_sieve_comparator_lookup (mu_sieve_machine_t mach, |
177 | 177 | ||
178 | mu_sieve_comparator_t mu_sieve_get_comparator (mu_sieve_machine_t mach, | 178 | mu_sieve_comparator_t mu_sieve_get_comparator (mu_sieve_machine_t mach, |
179 | mu_list_t tags); | 179 | mu_list_t tags); |
180 | int mu_sieve_str_to_relcmp (const char *str, mu_sieve_relcmp_t * test, | 180 | int mu_sieve_str_to_relcmp (const char *str, mu_sieve_relcmp_t *test, |
181 | mu_sieve_relcmpn_t * stest); | 181 | mu_sieve_relcmpn_t *stest); |
182 | mu_sieve_relcmp_t mu_sieve_get_relcmp (mu_sieve_machine_t mach, | 182 | mu_sieve_relcmp_t mu_sieve_get_relcmp (mu_sieve_machine_t mach, |
183 | mu_list_t tags); | 183 | mu_list_t tags); |
184 | 184 | ||
... | @@ -195,12 +195,12 @@ int mu_sieve_match_part_checker (mu_sieve_machine_t mach, | ... | @@ -195,12 +195,12 @@ int mu_sieve_match_part_checker (mu_sieve_machine_t mach, |
195 | mu_list_t args); | 195 | mu_list_t args); |
196 | /* Operations in value lists */ | 196 | /* Operations in value lists */ |
197 | mu_sieve_value_t *mu_sieve_value_get (mu_list_t vlist, size_t index); | 197 | mu_sieve_value_t *mu_sieve_value_get (mu_list_t vlist, size_t index); |
198 | int mu_sieve_vlist_do (mu_sieve_value_t * val, mu_list_action_t ac, | 198 | int mu_sieve_vlist_do (mu_sieve_value_t *val, mu_list_action_t ac, |
199 | void *data); | 199 | void *data); |
200 | int mu_sieve_vlist_compare (mu_sieve_value_t * a, mu_sieve_value_t * b, | 200 | int mu_sieve_vlist_compare (mu_sieve_value_t *a, mu_sieve_value_t *b, |
201 | mu_sieve_comparator_t comp, | 201 | mu_sieve_comparator_t comp, |
202 | mu_sieve_relcmp_t test, mu_sieve_retrieve_t ac, | 202 | mu_sieve_relcmp_t test, mu_sieve_retrieve_t ac, |
203 | void *data, size_t * count); | 203 | void *data, size_t *count); |
204 | 204 | ||
205 | /* Functions to create and destroy sieve machine */ | 205 | /* Functions to create and destroy sieve machine */ |
206 | int mu_sieve_machine_init (mu_sieve_machine_t *mach); | 206 | int mu_sieve_machine_init (mu_sieve_machine_t *mach); |
... | @@ -208,7 +208,7 @@ int mu_sieve_machine_dup (mu_sieve_machine_t const in, | ... | @@ -208,7 +208,7 @@ int mu_sieve_machine_dup (mu_sieve_machine_t const in, |
208 | mu_sieve_machine_t *out); | 208 | mu_sieve_machine_t *out); |
209 | int mu_sieve_machine_inherit (mu_sieve_machine_t const in, | 209 | int mu_sieve_machine_inherit (mu_sieve_machine_t const in, |
210 | mu_sieve_machine_t *out); | 210 | mu_sieve_machine_t *out); |
211 | void mu_sieve_machine_destroy (mu_sieve_machine_t * pmach); | 211 | void mu_sieve_machine_destroy (mu_sieve_machine_t *pmach); |
212 | int mu_sieve_machine_add_destructor (mu_sieve_machine_t mach, | 212 | int mu_sieve_machine_add_destructor (mu_sieve_machine_t mach, |
213 | mu_sieve_destructor_t destr, void *ptr); | 213 | mu_sieve_destructor_t destr, void *ptr); |
214 | 214 | ... | ... |
... | @@ -30,6 +30,7 @@ libmu_sieve_la_SOURCES = \ | ... | @@ -30,6 +30,7 @@ libmu_sieve_la_SOURCES = \ |
30 | actions.c\ | 30 | actions.c\ |
31 | conf.c\ | 31 | conf.c\ |
32 | comparator.c\ | 32 | comparator.c\ |
33 | encoded.c\ | ||
33 | load.c\ | 34 | load.c\ |
34 | prog.c\ | 35 | prog.c\ |
35 | register.c\ | 36 | register.c\ |
... | @@ -39,6 +40,7 @@ libmu_sieve_la_SOURCES = \ | ... | @@ -39,6 +40,7 @@ libmu_sieve_la_SOURCES = \ |
39 | sieve-gram.c\ | 40 | sieve-gram.c\ |
40 | sieve-gram.h\ | 41 | sieve-gram.h\ |
41 | sieve-lex.c\ | 42 | sieve-lex.c\ |
43 | strexp.c\ | ||
42 | tests.c\ | 44 | tests.c\ |
43 | util.c | 45 | util.c |
44 | libmu_sieve_la_LIBADD = ${MU_LIB_MAILUTILS} @LTDL_LIB@ | 46 | libmu_sieve_la_LIBADD = ${MU_LIB_MAILUTILS} @LTDL_LIB@ | ... | ... |
libmu_sieve/encoded.c
0 → 100644
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 2016 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 | /* The enchoded-character extension for Sieve (RFC 5228, 2.4.2.4) */ | ||
19 | #ifdef HAVE_CONFIG_H | ||
20 | # include <config.h> | ||
21 | #endif | ||
22 | #include <sieve-priv.h> | ||
23 | #include <mailutils/cctype.h> | ||
24 | |||
25 | typedef int (*convfun) (char const *str, size_t len, size_t *ncons, mu_opool_t pool); | ||
26 | |||
27 | static int hexconv (char const *str, size_t len, size_t *ncons, mu_opool_t pool); | ||
28 | static int uniconv (char const *str, size_t len, size_t *ncons, mu_opool_t pool); | ||
29 | |||
30 | struct convertor | ||
31 | { | ||
32 | char const *pfx; | ||
33 | size_t len; | ||
34 | convfun fun; | ||
35 | }; | ||
36 | |||
37 | static struct convertor conv[] = { | ||
38 | { "hex", 3, hexconv }, | ||
39 | { "unicode", 7, uniconv }, | ||
40 | { NULL } | ||
41 | }; | ||
42 | |||
43 | static convfun | ||
44 | findconv (char const **pstr, size_t *plen) | ||
45 | { | ||
46 | struct convertor *cp; | ||
47 | char const *str = *pstr; | ||
48 | size_t len = *plen; | ||
49 | |||
50 | for (cp = conv; cp->pfx; cp++) | ||
51 | { | ||
52 | if (len > cp->len && strncasecmp (str, cp->pfx, cp->len) == 0 && | ||
53 | str[cp->len] == ':') | ||
54 | { | ||
55 | *pstr += cp->len + 1; | ||
56 | *plen -= cp->len + 1; | ||
57 | return cp->fun; | ||
58 | } | ||
59 | } | ||
60 | return NULL; | ||
61 | } | ||
62 | |||
63 | int | ||
64 | mu_i_sv_expand_encoded_char (char const *input, size_t len, | ||
65 | char **exp, void *data) | ||
66 | { | ||
67 | int rc; | ||
68 | convfun fn; | ||
69 | mu_opool_t pool; | ||
70 | |||
71 | fn = findconv (&input, &len); | ||
72 | if (!fn) | ||
73 | return MU_ERR_NOENT; | ||
74 | |||
75 | rc = mu_opool_create (&pool, MU_OPOOL_DEFAULT); | ||
76 | if (rc) | ||
77 | return rc; | ||
78 | |||
79 | while (rc == 0 && len > 0) | ||
80 | { | ||
81 | if (mu_isblank (*input)) | ||
82 | { | ||
83 | ++input; | ||
84 | --len; | ||
85 | } | ||
86 | else if (mu_isxdigit (*input)) | ||
87 | { | ||
88 | size_t n; | ||
89 | rc = fn (input, len, &n, pool); | ||
90 | if (rc) | ||
91 | break; | ||
92 | input += n; | ||
93 | len -= n; | ||
94 | } | ||
95 | else | ||
96 | { | ||
97 | rc = EILSEQ; | ||
98 | break; | ||
99 | } | ||
100 | } | ||
101 | |||
102 | if (rc == 0) | ||
103 | { | ||
104 | size_t len; | ||
105 | char *p = mu_opool_finish (pool, &len); | ||
106 | char *res; | ||
107 | |||
108 | res = malloc (len + 1); | ||
109 | if (!res) | ||
110 | rc = errno; | ||
111 | else | ||
112 | { | ||
113 | memcpy (res, p, len); | ||
114 | res[len] = 0; | ||
115 | *exp = res; | ||
116 | } | ||
117 | } | ||
118 | mu_opool_destroy (&pool); | ||
119 | return rc; | ||
120 | } | ||
121 | |||
122 | static int | ||
123 | hexconv (char const *str, size_t len, size_t *ncons, mu_opool_t pool) | ||
124 | { | ||
125 | char c; | ||
126 | |||
127 | if (len < 2) | ||
128 | return EILSEQ; | ||
129 | else | ||
130 | { | ||
131 | c = mu_hex2ul (*str); | ||
132 | ++str; | ||
133 | if (!mu_isxdigit (*str)) | ||
134 | return EILSEQ; | ||
135 | c = (c << 4) + mu_hex2ul (*str); | ||
136 | mu_opool_append_char (pool, c); | ||
137 | } | ||
138 | *ncons = 2; | ||
139 | return 0; | ||
140 | } | ||
141 | |||
142 | static int | ||
143 | utf8_wctomb (unsigned int wc, mu_opool_t pool) | ||
144 | { | ||
145 | int count; | ||
146 | char r[6]; | ||
147 | |||
148 | /* FIXME: This implementation allows for full UTF-8 range. RFC 5228 | ||
149 | states on page 10, that "It is an error for a script to use a hexadecimal | ||
150 | value that isn't in either the range 0 to D7FF or the range E000 to | ||
151 | 10FFFF". I'm not sure that this limitation should be honored */ | ||
152 | |||
153 | if (wc < 0x80) | ||
154 | count = 1; | ||
155 | else if (wc < 0x800) | ||
156 | count = 2; | ||
157 | else if (wc < 0x10000) | ||
158 | count = 3; | ||
159 | else if (wc < 0x200000) | ||
160 | count = 4; | ||
161 | else if (wc < 0x4000000) | ||
162 | count = 5; | ||
163 | else if (wc <= 0x7fffffff) | ||
164 | count = 6; | ||
165 | else | ||
166 | return EILSEQ; | ||
167 | |||
168 | switch (count) | ||
169 | { | ||
170 | /* Note: code falls through cases! */ | ||
171 | case 6: | ||
172 | r[5] = 0x80 | (wc & 0x3f); | ||
173 | wc = wc >> 6; | ||
174 | wc |= 0x4000000; | ||
175 | case 5: | ||
176 | r[4] = 0x80 | (wc & 0x3f); | ||
177 | wc = wc >> 6; | ||
178 | wc |= 0x200000; | ||
179 | case 4: | ||
180 | r[3] = 0x80 | (wc & 0x3f); | ||
181 | wc = wc >> 6; | ||
182 | wc |= 0x10000; | ||
183 | case 3: | ||
184 | r[2] = 0x80 | (wc & 0x3f); | ||
185 | wc = wc >> 6; | ||
186 | wc |= 0x800; | ||
187 | case 2: | ||
188 | r[1] = 0x80 | (wc & 0x3f); | ||
189 | wc = wc >> 6; | ||
190 | wc |= 0xc0; | ||
191 | case 1: | ||
192 | r[0] = wc; | ||
193 | } | ||
194 | mu_opool_append (pool, r, count); | ||
195 | return 0; | ||
196 | } | ||
197 | |||
198 | static int | ||
199 | uniconv (char const *str, size_t len, size_t *ncons, mu_opool_t pool) | ||
200 | { | ||
201 | unsigned int wc = 0; | ||
202 | size_t i; | ||
203 | |||
204 | for (i = 0; i < len; i++) | ||
205 | { | ||
206 | if (i >= 12) | ||
207 | return EILSEQ; | ||
208 | if (!mu_isxdigit (str[i])) | ||
209 | break; | ||
210 | wc = (wc << 4) + mu_hex2ul (str[i]); | ||
211 | } | ||
212 | *ncons = i; | ||
213 | return utf8_wctomb (wc, pool); | ||
214 | } | ||
215 |
... | @@ -68,6 +68,11 @@ mu_sieve_require (mu_sieve_machine_t mach, mu_list_t slist) | ... | @@ -68,6 +68,11 @@ mu_sieve_require (mu_sieve_machine_t mach, mu_list_t slist) |
68 | reqfn = mu_sieve_require_relational; | 68 | reqfn = mu_sieve_require_relational; |
69 | text = ""; | 69 | text = ""; |
70 | } | 70 | } |
71 | else if (strcmp (name, "encoded-character") == 0) /* RFC 5228, 2.4.2.4 */ | ||
72 | { | ||
73 | reqfn = mu_sieve_require_encoded_character; | ||
74 | text = ""; | ||
75 | } | ||
71 | else | 76 | else |
72 | { | 77 | { |
73 | reqfn = mu_sieve_require_action; | 78 | reqfn = mu_sieve_require_action; | ... | ... |
... | @@ -203,4 +203,15 @@ void mu_i_sv_trace (mu_sieve_machine_t mach, const char *what, | ... | @@ -203,4 +203,15 @@ void mu_i_sv_trace (mu_sieve_machine_t mach, const char *what, |
203 | 203 | ||
204 | void mu_i_sv_argf (mu_stream_t str, mu_list_t list); | 204 | void mu_i_sv_argf (mu_stream_t str, mu_list_t list); |
205 | void mu_i_sv_valf (mu_stream_t str, mu_sieve_value_t *val); | 205 | void mu_i_sv_valf (mu_stream_t str, mu_sieve_value_t *val); |
206 | |||
207 | typedef int (*mu_i_sv_interp_t) (char const *, size_t, char **, void *); | ||
208 | |||
209 | int mu_i_sv_string_expand (char const *input, | ||
210 | mu_i_sv_interp_t interp, void *data, char **ret); | ||
211 | |||
212 | int mu_i_sv_expand_encoded_char (char const *input, size_t len, char **exp, void *data); | ||
213 | |||
214 | int mu_sieve_require_encoded_character (mu_sieve_machine_t mach, | ||
215 | const char *name); | ||
216 | |||
206 | 217 | ... | ... |
... | @@ -529,11 +529,11 @@ number () | ... | @@ -529,11 +529,11 @@ number () |
529 | } | 529 | } |
530 | 530 | ||
531 | static int | 531 | static int |
532 | string () | 532 | string (void) |
533 | { | 533 | { |
534 | yylval.string = mu_sieve_malloc (mu_sieve_machine, yyleng - 1); | 534 | line_begin (); |
535 | memcpy (yylval.string, yytext + 1, yyleng - 2); | 535 | line_add (yytext + 1, yyleng - 2); |
536 | yylval.string[yyleng - 2] = 0; | 536 | line_finish (); |
537 | return STRING; | 537 | return STRING; |
538 | } | 538 | } |
539 | 539 | ||
... | @@ -615,13 +615,6 @@ multiline_begin (void) | ... | @@ -615,13 +615,6 @@ multiline_begin (void) |
615 | } | 615 | } |
616 | 616 | ||
617 | static void | 617 | static void |
618 | line_finish (void) | ||
619 | { | ||
620 | mu_opool_append_char (mu_sieve_machine->string_pool, 0); | ||
621 | yylval.string = mu_opool_finish (mu_sieve_machine->string_pool, NULL); | ||
622 | } | ||
623 | |||
624 | static void | ||
625 | multiline_finish (void) | 618 | multiline_finish (void) |
626 | { | 619 | { |
627 | line_finish (); | 620 | line_finish (); |
... | @@ -648,3 +641,56 @@ str_unescape (char *text, size_t len) | ... | @@ -648,3 +641,56 @@ str_unescape (char *text, size_t len) |
648 | str[len - 1] = 0; | 641 | str[len - 1] = 0; |
649 | return str; | 642 | return str; |
650 | } | 643 | } |
644 | |||
645 | enum | ||
646 | { | ||
647 | interp_encoded_character, | ||
648 | interp_variable | ||
649 | }; | ||
650 | |||
651 | #define MAXINTERP (interp_variable+1) | ||
652 | mu_i_sv_interp_t interpreter[MAXINTERP]; | ||
653 | |||
654 | static void | ||
655 | line_finish (void) | ||
656 | { | ||
657 | int i; | ||
658 | char *str; | ||
659 | |||
660 | mu_opool_append_char (mu_sieve_machine->string_pool, 0); | ||
661 | str = mu_opool_finish (mu_sieve_machine->string_pool, NULL); | ||
662 | for (i = 0; i < MAXINTERP; i++) | ||
663 | { | ||
664 | if (interpreter[i]) | ||
665 | { | ||
666 | char *exp; | ||
667 | int rc = mu_i_sv_string_expand (str, interpreter[i], NULL, &exp); | ||
668 | if (rc == 0) | ||
669 | { | ||
670 | mu_opool_free (mu_sieve_machine->string_pool, str); | ||
671 | mu_opool_appendz (mu_sieve_machine->string_pool, exp); | ||
672 | mu_opool_append_char (mu_sieve_machine->string_pool, 0); | ||
673 | free (exp); | ||
674 | str = mu_opool_finish (mu_sieve_machine->string_pool, NULL); | ||
675 | } | ||
676 | else if (rc == MU_ERR_CANCELED) | ||
677 | continue; | ||
678 | else | ||
679 | { | ||
680 | mu_diag_at_locus (MU_LOG_ERROR, &mu_sieve_locus, | ||
681 | _("error expandind string: %s"), | ||
682 | mu_strerror (rc)); | ||
683 | break; | ||
684 | } | ||
685 | } | ||
686 | } | ||
687 | yylval.string = str; | ||
688 | } | ||
689 | |||
690 | int | ||
691 | mu_sieve_require_encoded_character (mu_sieve_machine_t mach, | ||
692 | const char *name) | ||
693 | { | ||
694 | interpreter[interp_encoded_character] = mu_i_sv_expand_encoded_char; | ||
695 | return 0; | ||
696 | } | ... | ... |
libmu_sieve/strexp.c
0 → 100644
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 2016 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 | /* String expander */ | ||
19 | #ifdef HAVE_CONFIG_H | ||
20 | # include <config.h> | ||
21 | #endif | ||
22 | #include <sieve-priv.h> | ||
23 | |||
24 | enum segm_type | ||
25 | { | ||
26 | segm_copy, /* reference to a fragment of the source string */ | ||
27 | segm_repl /* replacement */ | ||
28 | }; | ||
29 | |||
30 | struct string_segment | ||
31 | { | ||
32 | enum segm_type type; /* Segment type */ | ||
33 | size_t beg; /* Beginning of the source string fragmen */ | ||
34 | size_t end; /* End of it */ | ||
35 | char *repl; /* Replacement, if type == segm_repl */ | ||
36 | }; | ||
37 | |||
38 | struct stringbuf | ||
39 | { | ||
40 | char const *string; /* Source string */ | ||
41 | size_t length; /* Length of the source */ | ||
42 | size_t pos; /* Offset of the current character */ | ||
43 | |||
44 | mu_list_t seglist; /* List of segments */ | ||
45 | jmp_buf errbuf; /* Return location on failure */ | ||
46 | |||
47 | char *expansion; /* Expanded string */ | ||
48 | char *endptr; /* Used when assembling expansion */ | ||
49 | |||
50 | mu_i_sv_interp_t interp; | ||
51 | void *data; | ||
52 | }; | ||
53 | |||
54 | static struct string_segment * | ||
55 | segment_alloc (struct stringbuf *buf, size_t beg, enum segm_type type) | ||
56 | { | ||
57 | int rc; | ||
58 | struct string_segment *segm; | ||
59 | |||
60 | segm = malloc (sizeof *segm); | ||
61 | if (!segm) | ||
62 | longjmp (buf->errbuf, ENOMEM); | ||
63 | segm->type = type; | ||
64 | segm->beg = beg; | ||
65 | segm->end = buf->pos - 1; | ||
66 | rc = mu_list_append (buf->seglist, segm); | ||
67 | if (rc) | ||
68 | longjmp (buf->errbuf, rc); | ||
69 | return segm; | ||
70 | } | ||
71 | |||
72 | static void | ||
73 | segm_free (void *data) | ||
74 | { | ||
75 | struct string_segment *segm = data; | ||
76 | if (segm->type == segm_repl) | ||
77 | free (segm->repl); | ||
78 | free (segm); | ||
79 | } | ||
80 | |||
81 | static void | ||
82 | string_next_fragment (struct stringbuf *buf) | ||
83 | { | ||
84 | size_t beg; | ||
85 | struct string_segment *segm; | ||
86 | char *exp; | ||
87 | |||
88 | beg = buf->pos; | ||
89 | while (buf->pos < buf->length) | ||
90 | { | ||
91 | if (buf->string[buf->pos] == '$' && buf->pos + 1 < buf->length | ||
92 | && buf->string[buf->pos + 1] == '{') | ||
93 | break; | ||
94 | buf->pos++; | ||
95 | } | ||
96 | segm = segment_alloc (buf, beg, segm_copy); | ||
97 | if (buf->pos == buf->length) | ||
98 | return; | ||
99 | |||
100 | beg = buf->pos; | ||
101 | buf->pos += 2; | ||
102 | /* Look for closing brace */ | ||
103 | while (buf->pos < buf->length) | ||
104 | { | ||
105 | if (buf->string[buf->pos] == '$' && buf->pos + 1 < buf->length | ||
106 | && buf->string[buf->pos + 1] == '{') | ||
107 | { | ||
108 | /* Found nested reference. Update verbatim segment and restart */ | ||
109 | segm->end = buf->pos - 1; | ||
110 | beg = buf->pos; | ||
111 | buf->pos++; | ||
112 | } | ||
113 | else if (buf->string[buf->pos] == '}') | ||
114 | break; | ||
115 | buf->pos++; | ||
116 | } | ||
117 | |||
118 | if (buf->pos == buf->length) | ||
119 | { | ||
120 | /* No references found */ | ||
121 | segm->end = buf->pos - 1; | ||
122 | return; | ||
123 | } | ||
124 | |||
125 | if (buf->interp (buf->string + beg + 2, buf->pos - beg - 2, &exp, | ||
126 | buf->data) == 0) | ||
127 | { | ||
128 | segm = segment_alloc (buf, beg, segm_repl); | ||
129 | segm->repl = exp; | ||
130 | } | ||
131 | else | ||
132 | segm->end = buf->pos; | ||
133 | |||
134 | buf->pos++; | ||
135 | } | ||
136 | |||
137 | struct segm_stat | ||
138 | { | ||
139 | size_t end; | ||
140 | size_t len; | ||
141 | }; | ||
142 | |||
143 | static int | ||
144 | update_len (void *item, void *data) | ||
145 | { | ||
146 | struct string_segment *segm = item; | ||
147 | struct segm_stat *st = data; | ||
148 | |||
149 | switch (segm->type) | ||
150 | { | ||
151 | case segm_copy: | ||
152 | if (segm->beg == st->end) | ||
153 | st->end = segm->end; | ||
154 | st->len += segm->end - segm->beg + 1; | ||
155 | break; | ||
156 | |||
157 | case segm_repl: | ||
158 | st->len += strlen (segm->repl); | ||
159 | break; | ||
160 | } | ||
161 | return 0; | ||
162 | } | ||
163 | |||
164 | static int | ||
165 | append_segm (void *item, void *data) | ||
166 | { | ||
167 | struct string_segment *segm = item; | ||
168 | struct stringbuf *buf = data; | ||
169 | size_t len; | ||
170 | |||
171 | switch (segm->type) | ||
172 | { | ||
173 | case segm_copy: | ||
174 | len = segm->end - segm->beg + 1; | ||
175 | memcpy (buf->endptr, buf->string + segm->beg, len); | ||
176 | break; | ||
177 | |||
178 | case segm_repl: | ||
179 | len = strlen (segm->repl); | ||
180 | memcpy (buf->endptr, segm->repl, len); | ||
181 | } | ||
182 | |||
183 | buf->endptr += len; | ||
184 | return 0; | ||
185 | } | ||
186 | |||
187 | static void | ||
188 | string_split (struct stringbuf *buf) | ||
189 | { | ||
190 | while (buf->pos < buf->length) | ||
191 | string_next_fragment (buf); | ||
192 | } | ||
193 | |||
194 | static int | ||
195 | string_assemble (struct stringbuf *buf) | ||
196 | { | ||
197 | struct segm_stat st; | ||
198 | st.len = 0; | ||
199 | st.end = 0; | ||
200 | |||
201 | mu_list_foreach (buf->seglist, update_len, &st); | ||
202 | if (st.end == buf->length - 1) | ||
203 | return MU_ERR_CANCELED; | ||
204 | |||
205 | buf->expansion = malloc (st.len + 1); | ||
206 | if (!buf->expansion) | ||
207 | longjmp (buf->errbuf, ENOMEM); | ||
208 | buf->endptr = buf->expansion; | ||
209 | mu_list_foreach (buf->seglist, append_segm, buf); | ||
210 | *buf->endptr = 0; | ||
211 | |||
212 | return 0; | ||
213 | } | ||
214 | |||
215 | int | ||
216 | mu_i_sv_string_expand (char const *input, | ||
217 | mu_i_sv_interp_t interp, void *data, char **ret) | ||
218 | { | ||
219 | struct stringbuf sb; | ||
220 | int rc; | ||
221 | |||
222 | sb.string = input; | ||
223 | sb.length = strlen (input); | ||
224 | sb.pos = 0; | ||
225 | |||
226 | rc = mu_list_create (&sb.seglist); | ||
227 | if (rc) | ||
228 | return rc; | ||
229 | mu_list_set_destroy_item (sb.seglist, segm_free); | ||
230 | |||
231 | sb.expansion = NULL; | ||
232 | sb.endptr = NULL; | ||
233 | |||
234 | sb.interp = interp; | ||
235 | sb.data = data; | ||
236 | |||
237 | rc = setjmp (sb.errbuf); | ||
238 | if (rc == 0) | ||
239 | { | ||
240 | string_split (&sb); | ||
241 | rc = string_assemble (&sb); | ||
242 | if (rc == 0) | ||
243 | *ret = sb.expansion; | ||
244 | } | ||
245 | mu_list_destroy (&sb.seglist); | ||
246 | return rc; | ||
247 | } | ||
248 | |||
249 | |||
250 |
sieve/tests/enc-char.at
0 → 100644
1 | # This file is part of GNU Mailutils. -*- Autotest -*- | ||
2 | # Copyright (C) 2016 Free Software Foundation, Inc. | ||
3 | # | ||
4 | # GNU Mailutils is free software; you can redistribute it and/or | ||
5 | # modify it under the terms of the GNU General Public License as | ||
6 | # published by the Free Software Foundation; either version 3, or (at | ||
7 | # your option) any later version. | ||
8 | # | ||
9 | # GNU Mailutils is distributed in the hope that it will be useful, but | ||
10 | # WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | # General Public License for more details. | ||
13 | # | ||
14 | # You should have received a copy of the GNU General Public License | ||
15 | # along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. | ||
16 | |||
17 | AT_SETUP([encoded-character]) | ||
18 | AT_KEYWORDS([encoded-character enc-char]) | ||
19 | |||
20 | AT_CHECK([ | ||
21 | AT_DATA([prog],[[require ["reject", "encoded-character"]; | ||
22 | |||
23 | reject "$${hex:40}"; | ||
24 | reject "${hex: 40 }"; | ||
25 | reject "${HEX: 40}"; | ||
26 | reject "${hex:40"; | ||
27 | reject "${hex:400}"; | ||
28 | reject "${hex:4${hex:30}}"; | ||
29 | reject "${unicode:40}"; | ||
30 | reject "${ unicode:40}"; | ||
31 | reject "${UNICODE:40}"; | ||
32 | reject "${UnICoDE:0000040}"; | ||
33 | reject "${Unicode:40}"; | ||
34 | reject "${Unicode:Cool}"; | ||
35 | reject "Now ${hex: 69 73 20}the${unicode:20 74}${hex:69 6d}e"; | ||
36 | reject "Unbalanced ${hex: 73 65 71 uence"; | ||
37 | reject "Nested ${hex: 73 65 71 ${hex: 75 65 6E}}ce"; | ||
38 | reject "Invalid ${hex: 73 RE}"; | ||
39 | ]]) | ||
40 | |||
41 | sieve MUT_SIEVE_CMDLINE MUT_SIEVE_OPTIONS -D prog | grep ACTION | ||
42 | ], | ||
43 | [0], | ||
44 | [ 9: ACTION: reject "$@" | ||
45 | 16: ACTION: reject "@" | ||
46 | 23: ACTION: reject "@" | ||
47 | 30: ACTION: reject "${hex:40" | ||
48 | 37: ACTION: reject "${hex:400}" | ||
49 | 44: ACTION: reject "${hex:40}" | ||
50 | 51: ACTION: reject "@" | ||
51 | 58: ACTION: reject "${ unicode:40}" | ||
52 | 65: ACTION: reject "@" | ||
53 | 72: ACTION: reject "@" | ||
54 | 79: ACTION: reject "@" | ||
55 | 86: ACTION: reject "${Unicode:Cool}" | ||
56 | 93: ACTION: reject "Now is the time" | ||
57 | 100: ACTION: reject "Unbalanced ${hex: 73 65 71 uence" | ||
58 | 107: ACTION: reject "Nested ${hex: 73 65 71 uen}ce" | ||
59 | 114: ACTION: reject "Invalid ${hex: 73 RE}" | ||
60 | ]) | ||
61 | |||
62 | AT_CLEANUP |
... | @@ -113,6 +113,7 @@ m4_include([version.at]) | ... | @@ -113,6 +113,7 @@ m4_include([version.at]) |
113 | 113 | ||
114 | AT_BANNER(Compilation) | 114 | AT_BANNER(Compilation) |
115 | m4_include([compile.at]) | 115 | m4_include([compile.at]) |
116 | m4_include([enc-char.at]) | ||
116 | 117 | ||
117 | AT_BANNER(Actions) | 118 | AT_BANNER(Actions) |
118 | m4_include([false.at]) | 119 | m4_include([false.at]) | ... | ... |
-
Please register or sign in to post a comment