Commit 1e6dc073 1e6dc073c8b89d740c7eeba747965dfb76be5f2a by Sergey Poznyakoff

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.
1 parent 05df35d0
...@@ -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@
......
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 }
......
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
...@@ -47,6 +47,7 @@ TESTSUITE_AT = \ ...@@ -47,6 +47,7 @@ TESTSUITE_AT = \
47 anyof.at\ 47 anyof.at\
48 delheader.at\ 48 delheader.at\
49 compile.at\ 49 compile.at\
50 enc-char.at\
50 envelope.at\ 51 envelope.at\
51 exists.at\ 52 exists.at\
52 ext.at\ 53 ext.at\
......
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])
......