Functions for formatting RFC-2231-compliant mail headers fields.
* include/mailutils/cctype.h (MU_CTYPE_TSPEC): New class. Represents tspecials as per RFC 2045, section 5.1. (mu_istspec): New define. * libmailutils/string/muctype.c (mu_c_tab): Mark tspecials * include/mailutils/assoc.h (mu_assoc_mark) (mu_assoc_sweep): New protos. * libmailutils/base/assoc.c (_mu_assoc_elem): New field: mark (mu_assoc_mark,mu_assoc_sweep): New functions. * libmailutils/filter/Makefile.am (libfilter_la_SOURCES): Add dq.c and percent.c. * libmailutils/filter/dq.c: New file. * libmailutils/filter/percent.c: New file. * include/mailutils/filter.h (mu_percent_filter) (mu_dq_filter): New externs. * libmailutils/filter/filter.c (mu_filter_get_list): Register mu_percent_filter and mu_dq_filter. * include/mailutils/mime.h (mu_mime_header_set) (mu_mime_header_set_w): New protos. * libmailutils/mime/Makefile.am (libmime_la_SOURCES): Add mimehdrset.c * libmailutils/mime/mimehdrset.c: New file. * libmailutils/mime/mime.c (_mime_set_content_type): For multipart/alternative, remove also all parameters except charset from the Content-Type header. * mail/send.c (saveatt): Remove the now unneeded conditionals. * libmailutils/tests/mimehdr.at: Test formatting functions. * include/mailutils/stream.h (MU_IOCTL_FILTER_SET_OUTBUF_SIZE): New ioctl. * include/mailutils/sys/filter.h (_MU_FILTER_DISABLED) (_MU_FILTER_EOF): Remove. Use bitfields instead. (_mu_filter_stream): Remove fltflag. New fields: flag_disabled, flag_eof, outbuf_size. * libmailutils/stream/fltstream.c (MFB_BASE) (MFB_CURPTR, MFB_ENDPTR, MFB_SIZE, MFB_LEVEL) (MFB_POS, MFB_RDBYTES, MFB_FREESIZE) (MBF_CLEAR, MBF_FREE): Replace with inline functions. (init_iobuf): Use the outbuf_size field (unless 0) to set the output buffer size. (filter_read): Stop if on success if outbuf_size is set, without trying to fill the entire buffer. (filter_ctl): Handle MU_IOCTL_FILTER_SET_OUTBUF_SIZE. * libmailutils/tests/mimehdr.c: New option -width: format and print the value assuming given line width.
Showing
19 changed files
with
1069 additions
and
129 deletions
... | @@ -53,6 +53,10 @@ typedef int (*mu_assoc_comparator_t) (const char *, const void *, | ... | @@ -53,6 +53,10 @@ typedef int (*mu_assoc_comparator_t) (const char *, const void *, |
53 | 53 | ||
54 | int mu_assoc_sort_r (mu_assoc_t assoc, mu_assoc_comparator_t cmp, void *data); | 54 | int mu_assoc_sort_r (mu_assoc_t assoc, mu_assoc_comparator_t cmp, void *data); |
55 | 55 | ||
56 | int mu_assoc_mark (mu_assoc_t asc, int (*cond) (char const *, void *, void *), | ||
57 | void *data); | ||
58 | int mu_assoc_sweep (mu_assoc_t asc); | ||
59 | |||
56 | 60 | ||
57 | #ifdef __cplusplus | 61 | #ifdef __cplusplus |
58 | } | 62 | } | ... | ... |
... | @@ -24,18 +24,19 @@ | ... | @@ -24,18 +24,19 @@ |
24 | extern "C" { | 24 | extern "C" { |
25 | #endif | 25 | #endif |
26 | 26 | ||
27 | #define MU_CTYPE_ALPHA 0x001 | 27 | #define MU_CTYPE_ALPHA 0x0001 |
28 | #define MU_CTYPE_DIGIT 0x002 | 28 | #define MU_CTYPE_DIGIT 0x0002 |
29 | #define MU_CTYPE_BLANK 0x004 | 29 | #define MU_CTYPE_BLANK 0x0004 |
30 | #define MU_CTYPE_CNTRL 0x008 | 30 | #define MU_CTYPE_CNTRL 0x0008 |
31 | #define MU_CTYPE_GRAPH 0x010 | 31 | #define MU_CTYPE_GRAPH 0x0010 |
32 | #define MU_CTYPE_LOWER 0x020 | 32 | #define MU_CTYPE_LOWER 0x0020 |
33 | #define MU_CTYPE_UPPER 0x040 | 33 | #define MU_CTYPE_UPPER 0x0040 |
34 | #define MU_CTYPE_PRINT 0x080 | 34 | #define MU_CTYPE_PRINT 0x0080 |
35 | #define MU_CTYPE_PUNCT 0x100 | 35 | #define MU_CTYPE_PUNCT 0x0100 |
36 | #define MU_CTYPE_SPACE 0x200 | 36 | #define MU_CTYPE_SPACE 0x0200 |
37 | #define MU_CTYPE_XLETR 0x400 | 37 | #define MU_CTYPE_XLETR 0x0400 |
38 | #define MU_CTYPE_ENDLN 0x800 | 38 | #define MU_CTYPE_ENDLN 0x0800 |
39 | #define MU_CTYPE_TSPEC 0x1000 /* tspecials: RFC 2045, section 5.1. */ | ||
39 | 40 | ||
40 | #define MU_C_TAB_MAX 128 | 41 | #define MU_C_TAB_MAX 128 |
41 | 42 | ||
... | @@ -58,7 +59,8 @@ extern int mu_c_tab[MU_C_TAB_MAX]; | ... | @@ -58,7 +59,8 @@ extern int mu_c_tab[MU_C_TAB_MAX]; |
58 | #define mu_isascii(c) (((unsigned)c) < MU_C_TAB_MAX) | 59 | #define mu_isascii(c) (((unsigned)c) < MU_C_TAB_MAX) |
59 | #define mu_isblank(c) mu_c_is_class (c, MU_CTYPE_BLANK) | 60 | #define mu_isblank(c) mu_c_is_class (c, MU_CTYPE_BLANK) |
60 | #define mu_isendln(c) mu_c_is_class (c, MU_CTYPE_ENDLN) | 61 | #define mu_isendln(c) mu_c_is_class (c, MU_CTYPE_ENDLN) |
61 | 62 | #define mu_istspec(c) mu_c_is_class (c, MU_CTYPE_TSPEC) | |
63 | |||
62 | #define mu_tolower(c) \ | 64 | #define mu_tolower(c) \ |
63 | ({ int __c = (c); \ | 65 | ({ int __c = (c); \ |
64 | (__c >= 'A' && __c <= 'Z' ? __c - 'A' + 'a' : __c); \ | 66 | (__c >= 'A' && __c <= 'Z' ? __c - 'A' + 'a' : __c); \ | ... | ... |
... | @@ -126,7 +126,9 @@ extern mu_filter_record_t mu_iconv_filter; | ... | @@ -126,7 +126,9 @@ extern mu_filter_record_t mu_iconv_filter; |
126 | extern mu_filter_record_t mu_c_escape_filter; | 126 | extern mu_filter_record_t mu_c_escape_filter; |
127 | extern mu_filter_record_t mu_htmlent_filter; | 127 | extern mu_filter_record_t mu_htmlent_filter; |
128 | extern mu_filter_record_t mu_xml_filter; | 128 | extern mu_filter_record_t mu_xml_filter; |
129 | 129 | extern mu_filter_record_t mu_percent_filter; | |
130 | extern mu_filter_record_t mu_dq_filter; | ||
131 | |||
130 | enum mu_iconv_fallback_mode | 132 | enum mu_iconv_fallback_mode |
131 | { | 133 | { |
132 | mu_fallback_none, | 134 | mu_fallback_none, | ... | ... |
... | @@ -75,6 +75,13 @@ int mu_mime_header_parse (const char *text, const char *charset, char **pvalue, | ... | @@ -75,6 +75,13 @@ int mu_mime_header_parse (const char *text, const char *charset, char **pvalue, |
75 | int mu_mime_header_parse_subset (const char *text, const char *charset, | 75 | int mu_mime_header_parse_subset (const char *text, const char *charset, |
76 | char **pvalue, | 76 | char **pvalue, |
77 | mu_assoc_t assoc); | 77 | mu_assoc_t assoc); |
78 | |||
79 | int mu_mime_header_set_w (mu_header_t hdr, const char *name, | ||
80 | const char *value, mu_assoc_t params, | ||
81 | size_t line_width); | ||
82 | int mu_mime_header_set (mu_header_t hdr, const char *name, | ||
83 | const char *value, mu_assoc_t params); | ||
84 | |||
78 | 85 | ||
79 | #ifdef __cplusplus | 86 | #ifdef __cplusplus |
80 | } | 87 | } | ... | ... |
... | @@ -195,6 +195,12 @@ enum mu_buffer_type | ... | @@ -195,6 +195,12 @@ enum mu_buffer_type |
195 | #define MU_IOCTL_FILTER_GET_DISABLED 0 | 195 | #define MU_IOCTL_FILTER_GET_DISABLED 0 |
196 | #define MU_IOCTL_FILTER_SET_DISABLED 1 | 196 | #define MU_IOCTL_FILTER_SET_DISABLED 1 |
197 | 197 | ||
198 | /* Set transcoder output buffer size. | ||
199 | Arg: size_t* | ||
200 | Has effect only if the stream is unbuffered | ||
201 | */ | ||
202 | #define MU_IOCTL_FILTER_SET_OUTBUF_SIZE 2 | ||
203 | |||
198 | /* TLS transport streams */ | 204 | /* TLS transport streams */ |
199 | /* Get cipher info. | 205 | /* Get cipher info. |
200 | Arg: mu_property_t * | 206 | Arg: mu_property_t * | ... | ... |
... | @@ -36,16 +36,14 @@ struct _mu_filter_buffer | ... | @@ -36,16 +36,14 @@ struct _mu_filter_buffer |
36 | size_t pos; | 36 | size_t pos; |
37 | }; | 37 | }; |
38 | 38 | ||
39 | #define _MU_FILTER_DISABLED 0x01 | ||
40 | #define _MU_FILTER_EOF 0x02 | ||
41 | |||
42 | struct _mu_filter_stream | 39 | struct _mu_filter_stream |
43 | { | 40 | { |
44 | struct _mu_stream stream; | 41 | struct _mu_stream stream; |
45 | mu_stream_t transport; | 42 | mu_stream_t transport; |
46 | int mode; | 43 | int mode; |
47 | int fltflag; | 44 | unsigned flag_disabled:1; |
48 | 45 | unsigned flag_eof:1; | |
46 | size_t outbuf_size; | ||
49 | struct _mu_filter_buffer inbuf, outbuf; | 47 | struct _mu_filter_buffer inbuf, outbuf; |
50 | mu_filter_xcode_t xcode; | 48 | mu_filter_xcode_t xcode; |
51 | void *xdata; | 49 | void *xdata; | ... | ... |
... | @@ -47,6 +47,7 @@ struct _mu_assoc_elem | ... | @@ -47,6 +47,7 @@ struct _mu_assoc_elem |
47 | { | 47 | { |
48 | char *name; | 48 | char *name; |
49 | struct _mu_assoc_elem *next, *prev; | 49 | struct _mu_assoc_elem *next, *prev; |
50 | int mark:1; | ||
50 | char *data; | 51 | char *data; |
51 | }; | 52 | }; |
52 | 53 | ||
... | @@ -793,4 +794,34 @@ mu_assoc_sort_r (mu_assoc_t assoc, mu_assoc_comparator_t cmp, void *data) | ... | @@ -793,4 +794,34 @@ mu_assoc_sort_r (mu_assoc_t assoc, mu_assoc_comparator_t cmp, void *data) |
793 | 794 | ||
794 | return 0; | 795 | return 0; |
795 | } | 796 | } |
797 | |||
798 | int | ||
799 | mu_assoc_mark (mu_assoc_t asc, int (*cond) (char const *, void *, void *), | ||
800 | void *data) | ||
801 | { | ||
802 | struct _mu_assoc_elem *elt; | ||
803 | |||
804 | if (!asc) | ||
805 | return EINVAL; | ||
806 | for (elt = asc->head; elt; elt = elt->next) | ||
807 | elt->mark = !!cond (elt->name, elt->data, data); | ||
808 | return 0; | ||
809 | } | ||
810 | |||
811 | int | ||
812 | mu_assoc_sweep (mu_assoc_t asc) | ||
813 | { | ||
814 | unsigned i; | ||
815 | |||
816 | if (!asc) | ||
817 | return EINVAL; | ||
818 | |||
819 | for (i = hash_size[asc->hash_num]; i > 0; i--) | ||
820 | { | ||
821 | if (asc->tab[i-1] && asc->tab[i-1]->mark) | ||
822 | assoc_remove (asc, i-1); | ||
823 | } | ||
796 | 824 | ||
825 | return 0; | ||
826 | } | ||
827 | ... | ... |
... | @@ -25,6 +25,7 @@ libfilter_la_SOURCES =\ | ... | @@ -25,6 +25,7 @@ libfilter_la_SOURCES =\ |
25 | crlfflt.c\ | 25 | crlfflt.c\ |
26 | decode.c\ | 26 | decode.c\ |
27 | dot.c\ | 27 | dot.c\ |
28 | dq.c\ | ||
28 | filter.c\ | 29 | filter.c\ |
29 | fltchain.c\ | 30 | fltchain.c\ |
30 | fromflt.c\ | 31 | fromflt.c\ |
... | @@ -34,6 +35,7 @@ libfilter_la_SOURCES =\ | ... | @@ -34,6 +35,7 @@ libfilter_la_SOURCES =\ |
34 | inline-comment.c\ | 35 | inline-comment.c\ |
35 | linecon.c\ | 36 | linecon.c\ |
36 | linelenflt.c\ | 37 | linelenflt.c\ |
38 | percent.c\ | ||
37 | qpflt.c\ | 39 | qpflt.c\ |
38 | xml.c | 40 | xml.c |
39 | 41 | ... | ... |
libmailutils/filter/dq.c
0 → 100644
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 2011-2012, 2014-2017 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 | /* Doble-quote escaping filter. | ||
19 | In encode mode, escapes each occurrence of double-quote and backslash | ||
20 | by prefixing it with backslash. | ||
21 | In decode mode, removes backslash prefixes. | ||
22 | */ | ||
23 | |||
24 | #ifdef HAVE_CONFIG_H | ||
25 | # include <config.h> | ||
26 | #endif | ||
27 | #include <stdlib.h> | ||
28 | #include <string.h> | ||
29 | #include <mailutils/errno.h> | ||
30 | #include <mailutils/filter.h> | ||
31 | #include <mailutils/wordsplit.h> | ||
32 | #include <mailutils/cctype.h> | ||
33 | |||
34 | /* Move min(isize,osize) bytes from iptr to optr, replacing each | ||
35 | escapable control character with its escape sequence. */ | ||
36 | static enum mu_filter_result | ||
37 | _dq_encoder (void *xd MU_ARG_UNUSED, | ||
38 | enum mu_filter_command cmd, | ||
39 | struct mu_filter_io *iobuf) | ||
40 | { | ||
41 | size_t i, j; | ||
42 | const unsigned char *iptr; | ||
43 | size_t isize; | ||
44 | char *optr; | ||
45 | size_t osize; | ||
46 | |||
47 | switch (cmd) | ||
48 | { | ||
49 | case mu_filter_init: | ||
50 | case mu_filter_done: | ||
51 | return mu_filter_ok; | ||
52 | default: | ||
53 | break; | ||
54 | } | ||
55 | |||
56 | iptr = (const unsigned char *) iobuf->input; | ||
57 | isize = iobuf->isize; | ||
58 | optr = iobuf->output; | ||
59 | osize = iobuf->osize; | ||
60 | |||
61 | for (i = j = 0; i < isize && j < osize; i++) | ||
62 | { | ||
63 | unsigned char c = *iptr++; | ||
64 | |||
65 | if (strchr ("\\\"", c)) | ||
66 | { | ||
67 | if (j + 1 == osize) | ||
68 | { | ||
69 | if (i == 0) | ||
70 | { | ||
71 | iobuf->osize = 2; | ||
72 | return mu_filter_moreoutput; | ||
73 | } | ||
74 | break; | ||
75 | } | ||
76 | else | ||
77 | { | ||
78 | optr[j++] = '\\'; | ||
79 | optr[j++] = c; | ||
80 | } | ||
81 | } | ||
82 | else | ||
83 | optr[j++] = c; | ||
84 | } | ||
85 | iobuf->isize = i; | ||
86 | iobuf->osize = j; | ||
87 | return mu_filter_ok; | ||
88 | } | ||
89 | |||
90 | /* Move min(isize,osize) bytes from iptr to optr, replacing each escape | ||
91 | sequence with its ASCII code. */ | ||
92 | static enum mu_filter_result | ||
93 | _dq_decoder (void *xd MU_ARG_UNUSED, | ||
94 | enum mu_filter_command cmd, | ||
95 | struct mu_filter_io *iobuf) | ||
96 | { | ||
97 | size_t i, j; | ||
98 | const unsigned char *iptr; | ||
99 | size_t isize; | ||
100 | char *optr; | ||
101 | size_t osize; | ||
102 | |||
103 | switch (cmd) | ||
104 | { | ||
105 | case mu_filter_init: | ||
106 | case mu_filter_done: | ||
107 | return mu_filter_ok; | ||
108 | default: | ||
109 | break; | ||
110 | } | ||
111 | |||
112 | iptr = (const unsigned char *) iobuf->input; | ||
113 | isize = iobuf->isize; | ||
114 | optr = iobuf->output; | ||
115 | osize = iobuf->osize; | ||
116 | |||
117 | for (i = j = 0; i < isize && j < osize; i++) | ||
118 | { | ||
119 | unsigned char c = *iptr++; | ||
120 | if (c == '\\') | ||
121 | { | ||
122 | if (i + 1 == isize) | ||
123 | break; | ||
124 | optr[j++] = *iptr++; | ||
125 | } | ||
126 | else | ||
127 | optr[j++] = c; | ||
128 | } | ||
129 | |||
130 | iobuf->isize = i; | ||
131 | iobuf->osize = j; | ||
132 | return mu_filter_ok; | ||
133 | } | ||
134 | |||
135 | static struct _mu_filter_record _dq_filter = { | ||
136 | "dq", | ||
137 | NULL, | ||
138 | _dq_encoder, | ||
139 | _dq_decoder, | ||
140 | }; | ||
141 | |||
142 | mu_filter_record_t mu_dq_filter = &_dq_filter; | ||
143 |
... | @@ -86,6 +86,8 @@ mu_filter_get_list (mu_list_t *plist) | ... | @@ -86,6 +86,8 @@ mu_filter_get_list (mu_list_t *plist) |
86 | mu_list_append (filter_list, mu_c_escape_filter); | 86 | mu_list_append (filter_list, mu_c_escape_filter); |
87 | mu_list_append (filter_list, mu_htmlent_filter); | 87 | mu_list_append (filter_list, mu_htmlent_filter); |
88 | mu_list_append (filter_list, mu_xml_filter); | 88 | mu_list_append (filter_list, mu_xml_filter); |
89 | mu_list_append (filter_list, mu_percent_filter); | ||
90 | mu_list_append (filter_list, mu_dq_filter); | ||
89 | /* FIXME: add the default encodings? */ | 91 | /* FIXME: add the default encodings? */ |
90 | } | 92 | } |
91 | *plist = filter_list; | 93 | *plist = filter_list; | ... | ... |
libmailutils/filter/percent.c
0 → 100644
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 2011-2012, 2014-2017 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 | #include <stdlib.h> | ||
22 | #include <string.h> | ||
23 | #include <limits.h> | ||
24 | #include <mailutils/errno.h> | ||
25 | #include <mailutils/filter.h> | ||
26 | #include <mailutils/cctype.h> | ||
27 | |||
28 | static char xchar[] = "0123456789ABCDEF"; | ||
29 | |||
30 | static enum mu_filter_result | ||
31 | percent_encoder (void *xd, | ||
32 | enum mu_filter_command cmd, | ||
33 | struct mu_filter_io *iobuf) | ||
34 | { | ||
35 | size_t i, j; | ||
36 | const unsigned char *iptr; | ||
37 | size_t isize; | ||
38 | char *optr; | ||
39 | size_t osize; | ||
40 | char *escape_chars = xd; | ||
41 | |||
42 | switch (cmd) | ||
43 | { | ||
44 | case mu_filter_init: | ||
45 | case mu_filter_done: | ||
46 | return mu_filter_ok; | ||
47 | default: | ||
48 | break; | ||
49 | } | ||
50 | |||
51 | iptr = (const unsigned char *) iobuf->input; | ||
52 | isize = iobuf->isize; | ||
53 | optr = iobuf->output; | ||
54 | osize = iobuf->osize; | ||
55 | |||
56 | for (i = j = 0; i < isize && j < osize; i++) | ||
57 | { | ||
58 | unsigned char c = iptr[i]; | ||
59 | |||
60 | if (c == 0 || strchr (escape_chars, c)) | ||
61 | { | ||
62 | if (j + 3 >= osize) | ||
63 | { | ||
64 | if (i == 0) | ||
65 | { | ||
66 | iobuf->osize = 3; | ||
67 | return mu_filter_moreoutput; | ||
68 | } | ||
69 | break; | ||
70 | } | ||
71 | optr[j++] = '%'; | ||
72 | optr[j++] = xchar[((c >> 4) & 0xf)]; | ||
73 | optr[j++] = xchar[c & 0xf]; | ||
74 | } | ||
75 | else | ||
76 | optr[j++] = c; | ||
77 | } | ||
78 | iobuf->isize = i; | ||
79 | iobuf->osize = j; | ||
80 | return mu_filter_ok; | ||
81 | } | ||
82 | |||
83 | static enum mu_filter_result | ||
84 | percent_decoder (void *xd MU_ARG_UNUSED, | ||
85 | enum mu_filter_command cmd, | ||
86 | struct mu_filter_io *iobuf) | ||
87 | { | ||
88 | size_t i, j; | ||
89 | const unsigned char *iptr; | ||
90 | size_t isize; | ||
91 | char *optr; | ||
92 | size_t osize; | ||
93 | |||
94 | switch (cmd) | ||
95 | { | ||
96 | case mu_filter_init: | ||
97 | case mu_filter_done: | ||
98 | return mu_filter_ok; | ||
99 | default: | ||
100 | break; | ||
101 | } | ||
102 | |||
103 | iptr = (const unsigned char *) iobuf->input; | ||
104 | isize = iobuf->isize; | ||
105 | optr = iobuf->output; | ||
106 | osize = iobuf->osize; | ||
107 | |||
108 | for (i = j = 0; i < isize && j < osize; j++) | ||
109 | { | ||
110 | unsigned char c = iptr[i++]; | ||
111 | if (c == '%') | ||
112 | { | ||
113 | char *phi, *plo; | ||
114 | |||
115 | if (i + 2 >= isize) | ||
116 | break; | ||
117 | phi = strchr (xchar, mu_toupper (iptr[i])); | ||
118 | plo = strchr (xchar, mu_toupper (iptr[i+1])); | ||
119 | if (phi && plo) | ||
120 | { | ||
121 | optr[j] = ((phi - xchar) << 4) + (plo - xchar); | ||
122 | i += 2; | ||
123 | } | ||
124 | else | ||
125 | optr[j] = c; | ||
126 | } | ||
127 | else | ||
128 | optr[j] = c; | ||
129 | } | ||
130 | iobuf->isize = i; | ||
131 | iobuf->osize = j; | ||
132 | return mu_filter_ok; | ||
133 | } | ||
134 | |||
135 | static int | ||
136 | percent_alloc (void **pret, int mode, int argc, const char **argv) | ||
137 | { | ||
138 | if (mode == MU_FILTER_ENCODE) | ||
139 | { | ||
140 | char *s; | ||
141 | if (argc > 1) | ||
142 | { | ||
143 | int i; | ||
144 | size_t len = 0; | ||
145 | |||
146 | for (i = 1; i < argc; i++) | ||
147 | len += strlen (argv[i]); | ||
148 | s = malloc (len + 1); | ||
149 | if (!s) | ||
150 | return ENOMEM; | ||
151 | *pret = s; | ||
152 | *s = 0; | ||
153 | for (i = 1; i < argc; i++) | ||
154 | strcat (s, argv[i]); | ||
155 | } | ||
156 | else | ||
157 | { | ||
158 | int i; | ||
159 | |||
160 | s = malloc (UCHAR_MAX); | ||
161 | if (!s) | ||
162 | return ENOMEM; | ||
163 | *pret = s; | ||
164 | for (i = 1; i <= UCHAR_MAX; i++) | ||
165 | { | ||
166 | if (i == '%' || i == '"' || !mu_isgraph (i)) | ||
167 | *s++ = i; | ||
168 | } | ||
169 | *s = 0; | ||
170 | } | ||
171 | } | ||
172 | else | ||
173 | *pret = NULL; | ||
174 | return 0; | ||
175 | } | ||
176 | |||
177 | static struct _mu_filter_record _percent_filter = { | ||
178 | "percent", | ||
179 | percent_alloc, | ||
180 | percent_encoder, | ||
181 | percent_decoder | ||
182 | }; | ||
183 | |||
184 | mu_filter_record_t mu_percent_filter = &_percent_filter; | ||
185 | |||
186 |
... | @@ -20,6 +20,7 @@ noinst_LTLIBRARIES = libmime.la | ... | @@ -20,6 +20,7 @@ noinst_LTLIBRARIES = libmime.la |
20 | libmime_la_SOURCES = \ | 20 | libmime_la_SOURCES = \ |
21 | attachment.c\ | 21 | attachment.c\ |
22 | mime.c\ | 22 | mime.c\ |
23 | mimehdr.c | 23 | mimehdr.c\ |
24 | mimehdrset.c | ||
24 | 25 | ||
25 | AM_CPPFLAGS = @MU_LIB_COMMON_INCLUDES@ -I/libmailutils | 26 | AM_CPPFLAGS = @MU_LIB_COMMON_INCLUDES@ -I/libmailutils | ... | ... |
... | @@ -38,6 +38,8 @@ | ... | @@ -38,6 +38,8 @@ |
38 | #include <mailutils/header.h> | 38 | #include <mailutils/header.h> |
39 | #include <mailutils/errno.h> | 39 | #include <mailutils/errno.h> |
40 | #include <mailutils/util.h> | 40 | #include <mailutils/util.h> |
41 | #include <mailutils/assoc.h> | ||
42 | #include <mailutils/io.h> | ||
41 | 43 | ||
42 | #include <mailutils/sys/mime.h> | 44 | #include <mailutils/sys/mime.h> |
43 | #include <mailutils/sys/message.h> | 45 | #include <mailutils/sys/message.h> |
... | @@ -445,6 +447,13 @@ _mimepart_body_lines (mu_body_t body, size_t *plines) | ... | @@ -445,6 +447,13 @@ _mimepart_body_lines (mu_body_t body, size_t *plines) |
445 | 447 | ||
446 | /*------ Mime message/header functions for CREATING multipart message -----*/ | 448 | /*------ Mime message/header functions for CREATING multipart message -----*/ |
447 | static int | 449 | static int |
450 | retain_charset (char const *name, void *value MU_ARG_UNUSED, | ||
451 | void *data MU_ARG_UNUSED) | ||
452 | { | ||
453 | return strcmp (name, "charset") != 0; | ||
454 | } | ||
455 | |||
456 | static int | ||
448 | _mime_set_content_type (mu_mime_t mime) | 457 | _mime_set_content_type (mu_mime_t mime) |
449 | { | 458 | { |
450 | const char *content_type; | 459 | const char *content_type; |
... | @@ -473,9 +482,36 @@ _mime_set_content_type (mu_mime_t mime) | ... | @@ -473,9 +482,36 @@ _mime_set_content_type (mu_mime_t mime) |
473 | for (i = 0; i < mime->nmtp_parts; i++) | 482 | for (i = 0; i < mime->nmtp_parts; i++) |
474 | { | 483 | { |
475 | mu_header_t hdr; | 484 | mu_header_t hdr; |
485 | char *val; | ||
486 | int rc; | ||
476 | 487 | ||
477 | mu_message_get_header (mime->mtp_parts[i]->msg, &hdr); | 488 | mu_message_get_header (mime->mtp_parts[i]->msg, &hdr); |
478 | mu_header_remove (hdr, MU_HEADER_CONTENT_DISPOSITION, 1); | 489 | mu_header_remove (hdr, MU_HEADER_CONTENT_DISPOSITION, 1); |
490 | |||
491 | rc = mu_header_aget_value_unfold (hdr, MU_HEADER_CONTENT_TYPE, | ||
492 | &val); | ||
493 | if (rc == 0) | ||
494 | { | ||
495 | mu_content_type_t ct; | ||
496 | rc = mu_content_type_parse (val, NULL, &ct); | ||
497 | if (rc == 0) | ||
498 | { | ||
499 | char *type; | ||
500 | |||
501 | mu_assoc_mark (ct->param, retain_charset, NULL); | ||
502 | mu_assoc_sweep (ct->param); | ||
503 | |||
504 | rc = mu_asprintf (&type, "%s/%s", ct->type, ct->subtype); | ||
505 | if (rc == 0) | ||
506 | { | ||
507 | mu_mime_header_set (hdr, | ||
508 | MU_HEADER_CONTENT_TYPE, type, | ||
509 | ct->param); | ||
510 | free (type); | ||
511 | } | ||
512 | mu_content_type_destroy (&ct); | ||
513 | } | ||
514 | } | ||
479 | } | 515 | } |
480 | 516 | ||
481 | content_type = "multipart/alternative; boundary="; | 517 | content_type = "multipart/alternative; boundary="; | ... | ... |
libmailutils/mime/mimehdrset.c
0 → 100644
1 | /* Functions for formatting RFC-2231-compliant mail headers fields. | ||
2 | GNU Mailutils -- a suite of utilities for electronic mail | ||
3 | Copyright (C) 1999-2001, 2004-2005, 2007, 2009-2012, 2014-2017 Free | ||
4 | Software Foundation, Inc. | ||
5 | |||
6 | This library is free software; you can redistribute it and/or | ||
7 | modify it under the terms of the GNU Lesser General Public | ||
8 | License as published by the Free Software Foundation; either | ||
9 | version 3 of the License, or (at your option) any later version. | ||
10 | |||
11 | This library is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | Lesser General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU Lesser General | ||
17 | Public License along with this library. If not, | ||
18 | see <http://www.gnu.org/licenses/>. */ | ||
19 | |||
20 | #ifdef HAVE_CONFIG_H | ||
21 | #include <config.h> | ||
22 | #endif | ||
23 | #include <stdlib.h> | ||
24 | #include <string.h> | ||
25 | #include <errno.h> | ||
26 | #include <mailutils/mime.h> | ||
27 | #include <mailutils/cctype.h> | ||
28 | #include <mailutils/cstr.h> | ||
29 | #include <mailutils/header.h> | ||
30 | #include <mailutils/stream.h> | ||
31 | #include <mailutils/filter.h> | ||
32 | #include <mailutils/assoc.h> | ||
33 | #include <mailutils/errno.h> | ||
34 | |||
35 | struct header_buffer | ||
36 | { | ||
37 | mu_stream_t str; /* Output stream */ | ||
38 | size_t line_len; /* Length of current line */ | ||
39 | size_t line_max; /* Max. line length */ | ||
40 | }; | ||
41 | |||
42 | static int | ||
43 | mime_store_parameter (char const *name, void *value, void *data) | ||
44 | { | ||
45 | struct mu_mime_param *p = value; | ||
46 | struct header_buffer *hbuf = data; | ||
47 | size_t nlen; /* Length of parameter name | ||
48 | (eq. sign, eventual seqence no. and language info mark | ||
49 | included) */ | ||
50 | size_t vlen; /* Length of lang'charset' part */ | ||
51 | int langinfo; /* True if language info is available */ | ||
52 | int quote = 0; /* 2 if the value should be quoted, 0 otherwise */ | ||
53 | int segment = -1; /* Segment sequence number */ | ||
54 | mu_stream_t valstr; /* Value stream (properly encoded) */ | ||
55 | mu_off_t valsize; /* Number of octets left in valstr */ | ||
56 | char const *filter_name = NULL; /* Name of the filter for the value */ | ||
57 | int rc; | ||
58 | |||
59 | rc = mu_static_memory_stream_create (&valstr, p->value, strlen (p->value)); | ||
60 | if (rc) | ||
61 | return rc; | ||
62 | |||
63 | nlen = strlen (name); | ||
64 | if (p->lang || p->cset) | ||
65 | { | ||
66 | vlen = 2; | ||
67 | if (p->lang) | ||
68 | vlen += strlen (p->lang); | ||
69 | if (p->cset) | ||
70 | vlen += strlen (p->cset); | ||
71 | langinfo = 1; | ||
72 | filter_name = "percent"; | ||
73 | } | ||
74 | else | ||
75 | { | ||
76 | if (*mu_str_skip_class_comp (p->value, MU_CTYPE_TSPEC|MU_CTYPE_BLANK)) | ||
77 | { | ||
78 | /* Must be in quoted-string, to use within parameter values */ | ||
79 | quote = 2; | ||
80 | filter_name = "dq"; | ||
81 | } | ||
82 | else | ||
83 | quote = 0; | ||
84 | vlen = 0; | ||
85 | langinfo = 0; | ||
86 | } | ||
87 | |||
88 | if (filter_name) | ||
89 | { | ||
90 | mu_stream_t tmp; | ||
91 | |||
92 | rc = mu_filter_create (&tmp, valstr, filter_name, MU_FILTER_ENCODE, | ||
93 | MU_STREAM_READ | MU_STREAM_SEEK); | ||
94 | if (rc) | ||
95 | goto err; | ||
96 | mu_stream_unref (valstr); | ||
97 | valstr = tmp; | ||
98 | rc = mu_memory_stream_create (&tmp, MU_STREAM_RDWR); | ||
99 | if (rc == 0) | ||
100 | { | ||
101 | rc = mu_stream_copy (tmp, valstr, 0, &valsize); | ||
102 | mu_stream_destroy (&tmp); | ||
103 | } | ||
104 | } | ||
105 | else | ||
106 | rc = mu_stream_size (valstr, &valsize); | ||
107 | |||
108 | if (rc) | ||
109 | goto err; | ||
110 | |||
111 | nlen += langinfo; | ||
112 | |||
113 | rc = mu_stream_seek (valstr, 0, MU_SEEK_SET, NULL); | ||
114 | |||
115 | if (hbuf->line_max == 0) | ||
116 | { | ||
117 | /* No line wrapping requested. Store the value as it is */ | ||
118 | mu_stream_printf (hbuf->str, "%s", name); | ||
119 | if (langinfo) | ||
120 | mu_stream_write (hbuf->str, "*", 1, NULL); | ||
121 | mu_stream_write (hbuf->str, "=", 1, NULL); | ||
122 | if (vlen) | ||
123 | { | ||
124 | mu_stream_printf (hbuf->str, "%s'%s'", | ||
125 | p->lang ? p->lang : "", | ||
126 | p->cset ? p->cset : ""); | ||
127 | vlen = 0; | ||
128 | } | ||
129 | else if (quote) | ||
130 | mu_stream_write (hbuf->str, "\"", 1, NULL); | ||
131 | mu_stream_copy (hbuf->str, valstr, 0, NULL); | ||
132 | if (quote) | ||
133 | mu_stream_write (hbuf->str, "\"", 1, NULL); | ||
134 | if (mu_stream_err (hbuf->str)) | ||
135 | rc = mu_stream_last_error (hbuf->str); | ||
136 | } | ||
137 | else | ||
138 | { | ||
139 | /* Split the value into sequentially indexed segments, each one no | ||
140 | wider than the requested line width. | ||
141 | |||
142 | Without special precautions, an encoded character occurring at | ||
143 | the end of a segment can be split between this and the following | ||
144 | segment to satisfy line width requirements. To avoid this, the | ||
145 | following approach is used: | ||
146 | |||
147 | 1. The value stream is put to unbuffered mode. | ||
148 | 2. Before each write, the size of the transcoder output buffer | ||
149 | in valstr is set to the number of bytes left in the current | ||
150 | line. | ||
151 | |||
152 | This way the transcoder will write as many bytes as possible | ||
153 | without breaking the encoded constructs while the unbuffered mode | ||
154 | will ensure that it will not be called again to fill up the stream | ||
155 | buffer. | ||
156 | |||
157 | If the line width is insufficient, MU_ERR_BUFSPACE will be returned. | ||
158 | */ | ||
159 | char *iobuf; | ||
160 | |||
161 | iobuf = malloc (hbuf->line_max + 1); | ||
162 | if (!iobuf) | ||
163 | { | ||
164 | rc = errno; | ||
165 | goto err; | ||
166 | } | ||
167 | |||
168 | mu_stream_set_buffer (valstr, mu_buffer_none, 0); | ||
169 | |||
170 | while (rc == 0 && valsize) | ||
171 | { | ||
172 | mu_off_t start, nr; /* Start and end positions in stream */ | ||
173 | size_t sz, n; | ||
174 | |||
175 | mu_stream_write (hbuf->str, ";", 1, NULL); | ||
176 | mu_stream_seek (hbuf->str, 0, MU_SEEK_CUR, &start); | ||
177 | |||
178 | if (segment >= 0) | ||
179 | { | ||
180 | mu_stream_write (hbuf->str, "\n", 1, NULL); | ||
181 | hbuf->line_len = 0; | ||
182 | segment++; | ||
183 | } | ||
184 | else if (hbuf->line_len + valsize + quote + vlen + nlen + 1 > | ||
185 | hbuf->line_max) | ||
186 | { | ||
187 | mu_stream_write (hbuf->str, "\n", 1, NULL); | ||
188 | hbuf->line_len = 0; | ||
189 | if (hbuf->line_len + valsize + quote + vlen + nlen + 1 > | ||
190 | hbuf->line_max) | ||
191 | segment++; | ||
192 | } | ||
193 | |||
194 | mu_stream_write (hbuf->str, " ", 1, NULL); | ||
195 | |||
196 | if (segment >= 0) | ||
197 | mu_stream_printf (hbuf->str, "%s*%d", name, segment); | ||
198 | else | ||
199 | mu_stream_printf (hbuf->str, "%s", name); | ||
200 | if (langinfo) | ||
201 | mu_stream_write (hbuf->str, "*", 1, NULL); | ||
202 | mu_stream_write (hbuf->str, "=", 1, NULL); | ||
203 | mu_stream_seek (hbuf->str, 0, MU_SEEK_CUR, &nr); | ||
204 | nlen = nr - start; | ||
205 | hbuf->line_len += nlen; | ||
206 | start = nr; | ||
207 | |||
208 | /* Compute the number of octets to put into the current line. | ||
209 | If the requested line width is not enough to accomodate | ||
210 | the line, signal the error */ | ||
211 | if (hbuf->line_max <= (hbuf->line_len + quote + vlen)) | ||
212 | { | ||
213 | rc = MU_ERR_BUFSPACE; | ||
214 | break; | ||
215 | } | ||
216 | |||
217 | sz = hbuf->line_max - (hbuf->line_len + quote + vlen); | ||
218 | mu_stream_ioctl (valstr, MU_IOCTL_FILTER, | ||
219 | MU_IOCTL_FILTER_SET_OUTBUF_SIZE, &sz); | ||
220 | |||
221 | rc = mu_stream_read (valstr, iobuf, sz, &n); | ||
222 | if (rc || n == 0) | ||
223 | break; | ||
224 | |||
225 | if (vlen) | ||
226 | { | ||
227 | mu_stream_printf (hbuf->str, "%s'%s'", | ||
228 | p->lang ? p->lang : "", | ||
229 | p->cset ? p->cset : ""); | ||
230 | vlen = 0; | ||
231 | } | ||
232 | else if (quote) | ||
233 | mu_stream_write (hbuf->str, "\"", 1, NULL); | ||
234 | |||
235 | mu_stream_write (hbuf->str, iobuf, n, NULL); | ||
236 | |||
237 | if (quote) | ||
238 | mu_stream_write (hbuf->str, "\"", 1, NULL); | ||
239 | mu_stream_seek (hbuf->str, 0, MU_SEEK_CUR, &nr); | ||
240 | nr -= start; | ||
241 | hbuf->line_len += nr; | ||
242 | valsize -= n; | ||
243 | |||
244 | if (mu_stream_err (hbuf->str)) | ||
245 | rc = mu_stream_last_error (hbuf->str); | ||
246 | } | ||
247 | free (iobuf); | ||
248 | } | ||
249 | err: | ||
250 | mu_stream_destroy (&valstr); | ||
251 | |||
252 | return rc; | ||
253 | } | ||
254 | |||
255 | static int | ||
256 | mime_header_format (const char *value, mu_assoc_t params, | ||
257 | struct header_buffer *hbuf) | ||
258 | { | ||
259 | size_t l = strlen (value); | ||
260 | |||
261 | mu_stream_write (hbuf->str, value, l, NULL); | ||
262 | hbuf->line_len += l; | ||
263 | return mu_assoc_foreach (params, mime_store_parameter, hbuf); | ||
264 | } | ||
265 | |||
266 | /* Store a header in accordance with RFC 2231, Section 3, | ||
267 | "Parameter Value Continuations" | ||
268 | |||
269 | HDR - Message header object | ||
270 | NAME - Header name | ||
271 | VALUE - Header value part | ||
272 | PARAMS - Named parameters (assoc of struct mu_mime_param *) | ||
273 | LINE_WIDTH - Maximum line width. | ||
274 | */ | ||
275 | |||
276 | int | ||
277 | mu_mime_header_set_w (mu_header_t hdr, const char *name, | ||
278 | const char *value, mu_assoc_t params, size_t line_width) | ||
279 | { | ||
280 | struct header_buffer hbuf; | ||
281 | int rc; | ||
282 | |||
283 | rc = mu_memory_stream_create (&hbuf.str, MU_STREAM_RDWR); | ||
284 | if (rc) | ||
285 | return rc; | ||
286 | hbuf.line_len = strlen (name) + 2; | ||
287 | hbuf.line_max = line_width; | ||
288 | rc = mime_header_format (value, params, &hbuf); | ||
289 | if (rc == 0) | ||
290 | { | ||
291 | mu_off_t pos; | ||
292 | char *fmtval; | ||
293 | |||
294 | mu_stream_seek (hbuf.str, 0, MU_SEEK_CUR, &pos); | ||
295 | fmtval = malloc (pos + 1); | ||
296 | mu_stream_seek (hbuf.str, 0, MU_SEEK_SET, NULL); | ||
297 | mu_stream_read (hbuf.str, fmtval, pos, NULL); | ||
298 | fmtval[pos] = 0; | ||
299 | rc = mu_header_set_value (hdr, name, fmtval, 1); | ||
300 | free (fmtval); | ||
301 | } | ||
302 | mu_stream_destroy (&hbuf.str); | ||
303 | return rc; | ||
304 | } | ||
305 | |||
306 | int | ||
307 | mu_mime_header_set (mu_header_t hdr, const char *name, | ||
308 | const char *value, mu_assoc_t params) | ||
309 | { | ||
310 | return mu_mime_header_set_w (hdr, name, value, params, 76); | ||
311 | } | ||
312 | |||
313 | |||
314 |
... | @@ -27,63 +27,90 @@ | ... | @@ -27,63 +27,90 @@ |
27 | #include <mailutils/stream.h> | 27 | #include <mailutils/stream.h> |
28 | #include <mailutils/sys/filter.h> | 28 | #include <mailutils/sys/filter.h> |
29 | 29 | ||
30 | #define MFB_BASE(buf) ((buf).base) | 30 | static inline char * |
31 | #define MFB_CURPTR(buf) ((buf).base + (buf).pos) | 31 | MFB_base_ptr (struct _mu_filter_buffer *buf) |
32 | #define MFB_ENDPTR(buf) ((buf).base + (buf).level) | ||
33 | |||
34 | #define MFB_SIZE(buf) ((buf).size) | ||
35 | #define MFB_LEVEL(buf) ((buf).level) | ||
36 | #define MFB_POS(buf) ((buf).pos) | ||
37 | #define MFB_RDBYTES(buf) \ | ||
38 | (MFB_LEVEL (buf) - MFB_POS (buf)) | ||
39 | #define MFB_FREESIZE(buf) \ | ||
40 | (MFB_SIZE (buf) - MFB_LEVEL (buf)) | ||
41 | |||
42 | #define MBF_CLEAR(buf) ((buf).pos = (buf).level = 0) | ||
43 | #define MBF_FREE(buf) free ((buf).base) | ||
44 | |||
45 | static void | ||
46 | init_iobuf (struct mu_filter_io *io, struct _mu_filter_stream *fs) | ||
47 | { | 32 | { |
48 | io->input = MFB_CURPTR (fs->inbuf); | 33 | return buf->base; |
49 | io->isize = MFB_RDBYTES (fs->inbuf); | ||
50 | io->output = MFB_ENDPTR (fs->outbuf); | ||
51 | io->osize = MFB_FREESIZE (fs->outbuf); | ||
52 | io->errcode = MU_ERR_FAILURE; | ||
53 | io->eof = 0; | ||
54 | } | 34 | } |
55 | 35 | ||
56 | static int | 36 | static inline char * |
57 | filter_stream_init (struct _mu_filter_stream *fs) | 37 | MFB_cur_ptr (struct _mu_filter_buffer *buf) |
58 | { | 38 | { |
59 | if (fs->xdata) | 39 | return buf->base + buf->pos; |
40 | } | ||
41 | |||
42 | static inline char * | ||
43 | MFB_end_ptr (struct _mu_filter_buffer *buf) | ||
44 | { | ||
45 | return buf->base + buf->level; | ||
46 | } | ||
47 | |||
48 | static inline size_t | ||
49 | MFB_size (struct _mu_filter_buffer *buf) | ||
50 | { | ||
51 | return buf->size; | ||
52 | } | ||
53 | |||
54 | static inline size_t | ||
55 | MFB_level (struct _mu_filter_buffer *buf) | ||
56 | { | ||
57 | return buf->level; | ||
58 | } | ||
59 | |||
60 | static inline size_t | ||
61 | MFB_pos (struct _mu_filter_buffer *buf) | ||
62 | { | ||
63 | return buf->pos; | ||
64 | } | ||
65 | |||
66 | static inline size_t | ||
67 | MFB_rdbytes (struct _mu_filter_buffer *buf) | ||
68 | { | ||
69 | return MFB_level (buf) - MFB_pos (buf); | ||
70 | } | ||
71 | |||
72 | static inline size_t | ||
73 | MFB_freesize (struct _mu_filter_buffer *buf) | ||
74 | { | ||
75 | return MFB_size (buf) - MFB_level (buf); | ||
76 | } | ||
77 | |||
78 | static inline void | ||
79 | MFB_clear (struct _mu_filter_buffer *buf) | ||
80 | { | ||
81 | buf->pos = buf->level = 0; | ||
82 | } | ||
83 | |||
84 | static inline void | ||
85 | MFB_deallocate (struct _mu_filter_buffer *buf) | ||
86 | { | ||
87 | free (buf->base); | ||
88 | } | ||
89 | |||
90 | /* Compact the buffer */ | ||
91 | static inline void | ||
92 | MFB_compact (struct _mu_filter_buffer *buf) | ||
93 | { | ||
94 | if (MFB_pos (buf)) | ||
60 | { | 95 | { |
61 | struct mu_filter_io iobuf; | 96 | memmove (MFB_base_ptr (buf), MFB_cur_ptr (buf), MFB_rdbytes (buf)); |
62 | memset (&iobuf, 0, sizeof (iobuf)); | 97 | buf->level -= buf->pos; |
63 | iobuf.errcode = MU_ERR_FAILURE; | 98 | buf->pos = 0; |
64 | if (fs->xcode (fs->xdata, mu_filter_init, &iobuf) == mu_filter_failure) | ||
65 | return iobuf.errcode; | ||
66 | } | 99 | } |
67 | return 0; | ||
68 | } | 100 | } |
69 | 101 | ||
70 | static int | 102 | static int |
71 | MFB_require (struct _mu_filter_buffer *buf, size_t size) | 103 | MFB_require (struct _mu_filter_buffer *buf, size_t size) |
72 | { | 104 | { |
73 | if (size > MFB_FREESIZE (*buf)) | 105 | if (size > MFB_freesize (buf)) |
74 | { | 106 | { |
75 | /* Compact the buffer */ | 107 | MFB_compact (buf); |
76 | if (MFB_POS (*buf)) | 108 | |
77 | { | 109 | if (size > MFB_freesize (buf)) |
78 | memmove (MFB_BASE (*buf), MFB_CURPTR (*buf), MFB_RDBYTES (*buf)); | ||
79 | buf->level -= buf->pos; | ||
80 | buf->pos = 0; | ||
81 | } | ||
82 | if (size > MFB_FREESIZE (*buf)) | ||
83 | { | 110 | { |
84 | char *p; | 111 | char *p; |
85 | 112 | ||
86 | size += MFB_LEVEL (*buf); | 113 | size += MFB_level (buf); |
87 | p = realloc (buf->base, size); | 114 | p = realloc (buf->base, size); |
88 | if (!p) | 115 | if (!p) |
89 | return ENOMEM; | 116 | return ENOMEM; |
... | @@ -94,7 +121,7 @@ MFB_require (struct _mu_filter_buffer *buf, size_t size) | ... | @@ -94,7 +121,7 @@ MFB_require (struct _mu_filter_buffer *buf, size_t size) |
94 | return 0; | 121 | return 0; |
95 | } | 122 | } |
96 | 123 | ||
97 | static void | 124 | static inline void |
98 | MFB_advance_pos (struct _mu_filter_buffer *buf, size_t delta) | 125 | MFB_advance_pos (struct _mu_filter_buffer *buf, size_t delta) |
99 | { | 126 | { |
100 | buf->pos += delta; | 127 | buf->pos += delta; |
... | @@ -102,11 +129,45 @@ MFB_advance_pos (struct _mu_filter_buffer *buf, size_t delta) | ... | @@ -102,11 +129,45 @@ MFB_advance_pos (struct _mu_filter_buffer *buf, size_t delta) |
102 | buf->pos = buf->level = 0; | 129 | buf->pos = buf->level = 0; |
103 | } | 130 | } |
104 | 131 | ||
105 | static void | 132 | static inline void |
106 | MFB_advance_level (struct _mu_filter_buffer *buf, size_t delta) | 133 | MFB_advance_level (struct _mu_filter_buffer *buf, size_t delta) |
107 | { | 134 | { |
108 | buf->level += delta; | 135 | buf->level += delta; |
109 | } | 136 | } |
137 | |||
138 | static void | ||
139 | init_iobuf (struct mu_filter_io *io, struct _mu_filter_stream *fs) | ||
140 | { | ||
141 | io->input = MFB_cur_ptr (&fs->inbuf); | ||
142 | io->isize = MFB_rdbytes (&fs->inbuf); | ||
143 | |||
144 | if (fs->outbuf_size) | ||
145 | { | ||
146 | if (MFB_freesize (&fs->outbuf) < fs->outbuf_size) | ||
147 | MFB_require (&fs->outbuf, fs->outbuf_size); | ||
148 | io->osize = fs->outbuf_size; | ||
149 | } | ||
150 | else | ||
151 | io->osize = MFB_freesize (&fs->outbuf); | ||
152 | io->output = MFB_end_ptr (&fs->outbuf); | ||
153 | |||
154 | io->errcode = MU_ERR_FAILURE; | ||
155 | io->eof = 0; | ||
156 | } | ||
157 | |||
158 | static int | ||
159 | filter_stream_init (struct _mu_filter_stream *fs) | ||
160 | { | ||
161 | if (fs->xdata) | ||
162 | { | ||
163 | struct mu_filter_io iobuf; | ||
164 | memset (&iobuf, 0, sizeof (iobuf)); | ||
165 | iobuf.errcode = MU_ERR_FAILURE; | ||
166 | if (fs->xcode (fs->xdata, mu_filter_init, &iobuf) == mu_filter_failure) | ||
167 | return iobuf.errcode; | ||
168 | } | ||
169 | return 0; | ||
170 | } | ||
110 | 171 | ||
111 | static int | 172 | static int |
112 | filter_read (mu_stream_t stream, char *buf, size_t size, size_t *pret) | 173 | filter_read (mu_stream_t stream, char *buf, size_t size, size_t *pret) |
... | @@ -120,42 +181,42 @@ filter_read (mu_stream_t stream, char *buf, size_t size, size_t *pret) | ... | @@ -120,42 +181,42 @@ filter_read (mu_stream_t stream, char *buf, size_t size, size_t *pret) |
120 | int stop = 0; | 181 | int stop = 0; |
121 | int again = 0; | 182 | int again = 0; |
122 | 183 | ||
123 | if (fs->fltflag & _MU_FILTER_DISABLED) | 184 | if (fs->flag_disabled) |
124 | return mu_stream_read (fs->transport, buf, size, pret); | 185 | return mu_stream_read (fs->transport, buf, size, pret); |
125 | 186 | ||
126 | do | 187 | do |
127 | { | 188 | { |
128 | size_t rdsize; | 189 | size_t rdsize; |
129 | 190 | ||
130 | if (MFB_RDBYTES (fs->outbuf) == 0) | 191 | if (MFB_rdbytes (&fs->outbuf) == 0) |
131 | { | 192 | { |
132 | enum mu_filter_result res; | 193 | enum mu_filter_result res; |
133 | int rc; | 194 | int rc; |
134 | 195 | ||
135 | if (fs->fltflag & _MU_FILTER_EOF) | 196 | if (fs->flag_eof) |
136 | break; | 197 | break; |
137 | 198 | ||
138 | if (MFB_RDBYTES (fs->inbuf) < min_input_level && !again) | 199 | if (MFB_rdbytes (&fs->inbuf) < min_input_level && !again) |
139 | { | 200 | { |
140 | rc = MFB_require (&fs->inbuf, min_input_level); | 201 | rc = MFB_require (&fs->inbuf, min_input_level); |
141 | if (rc) | 202 | if (rc) |
142 | return rc; | 203 | return rc; |
143 | rc = mu_stream_read (fs->transport, | 204 | rc = mu_stream_read (fs->transport, |
144 | MFB_ENDPTR (fs->inbuf), | 205 | MFB_end_ptr (&fs->inbuf), |
145 | MFB_FREESIZE (fs->inbuf), | 206 | MFB_freesize (&fs->inbuf), |
146 | &rdsize); | 207 | &rdsize); |
147 | if (rc) | 208 | if (rc) |
148 | return rc; | 209 | return rc; |
149 | if (rdsize == 0 && | 210 | if (rdsize == 0 && |
150 | MFB_RDBYTES (fs->outbuf) == 0 && | 211 | MFB_rdbytes (&fs->outbuf) == 0 && |
151 | MFB_RDBYTES (fs->inbuf) == 0) | 212 | MFB_rdbytes (&fs->inbuf) == 0) |
152 | break; | 213 | break; |
153 | 214 | ||
154 | MFB_advance_level (&fs->inbuf, rdsize); | 215 | MFB_advance_level (&fs->inbuf, rdsize); |
155 | } | 216 | } |
156 | 217 | ||
157 | if (min_output_size < MFB_RDBYTES (fs->inbuf)) | 218 | if (min_output_size < MFB_rdbytes (&fs->inbuf)) |
158 | min_output_size = MFB_RDBYTES (fs->inbuf); | 219 | min_output_size = MFB_rdbytes (&fs->inbuf); |
159 | rc = MFB_require (&fs->outbuf, min_output_size); | 220 | rc = MFB_require (&fs->outbuf, min_output_size); |
160 | if (rc) | 221 | if (rc) |
161 | return rc; | 222 | return rc; |
... | @@ -195,8 +256,8 @@ filter_read (mu_stream_t stream, char *buf, size_t size, size_t *pret) | ... | @@ -195,8 +256,8 @@ filter_read (mu_stream_t stream, char *buf, size_t size, size_t *pret) |
195 | continue; | 256 | continue; |
196 | } | 257 | } |
197 | 258 | ||
198 | if (iobuf.isize > MFB_RDBYTES (fs->inbuf) | 259 | if (iobuf.isize > MFB_rdbytes (&fs->inbuf) |
199 | || iobuf.osize > MFB_FREESIZE (fs->outbuf)) | 260 | || iobuf.osize > MFB_freesize (&fs->outbuf)) |
200 | return MU_ERR_BUFSPACE; | 261 | return MU_ERR_BUFSPACE; |
201 | 262 | ||
202 | /* iobuf.osize contains number of bytes written to output */ | 263 | /* iobuf.osize contains number of bytes written to output */ |
... | @@ -209,12 +270,18 @@ filter_read (mu_stream_t stream, char *buf, size_t size, size_t *pret) | ... | @@ -209,12 +270,18 @@ filter_read (mu_stream_t stream, char *buf, size_t size, size_t *pret) |
209 | { | 270 | { |
210 | if (iobuf.eof) | 271 | if (iobuf.eof) |
211 | { | 272 | { |
212 | fs->fltflag |= _MU_FILTER_EOF; | 273 | fs->flag_eof = 1; |
274 | stop = 1; | ||
275 | } | ||
276 | else if (fs->outbuf_size) | ||
277 | { | ||
278 | if (iobuf.osize == 0) | ||
279 | return MU_ERR_BUFSPACE; | ||
213 | stop = 1; | 280 | stop = 1; |
214 | } | 281 | } |
215 | else if (cmd == mu_filter_lastbuf) | 282 | else if (cmd == mu_filter_lastbuf) |
216 | { | 283 | { |
217 | if (MFB_RDBYTES (fs->inbuf)) | 284 | if (MFB_rdbytes (&fs->inbuf)) |
218 | { | 285 | { |
219 | /* If xcoder has not consumed all input, try again */ | 286 | /* If xcoder has not consumed all input, try again */ |
220 | if (++again > MU_FILTER_MAX_AGAIN) | 287 | if (++again > MU_FILTER_MAX_AGAIN) |
... | @@ -227,7 +294,7 @@ filter_read (mu_stream_t stream, char *buf, size_t size, size_t *pret) | ... | @@ -227,7 +294,7 @@ filter_read (mu_stream_t stream, char *buf, size_t size, size_t *pret) |
227 | } | 294 | } |
228 | else | 295 | else |
229 | { | 296 | { |
230 | fs->fltflag |= _MU_FILTER_EOF; | 297 | fs->flag_eof = 1; |
231 | stop = 1; | 298 | stop = 1; |
232 | } | 299 | } |
233 | } | 300 | } |
... | @@ -237,9 +304,9 @@ filter_read (mu_stream_t stream, char *buf, size_t size, size_t *pret) | ... | @@ -237,9 +304,9 @@ filter_read (mu_stream_t stream, char *buf, size_t size, size_t *pret) |
237 | } | 304 | } |
238 | 305 | ||
239 | rdsize = size - total; | 306 | rdsize = size - total; |
240 | if (rdsize > MFB_RDBYTES (fs->outbuf)) | 307 | if (rdsize > MFB_rdbytes (&fs->outbuf)) |
241 | rdsize = MFB_RDBYTES (fs->outbuf); | 308 | rdsize = MFB_rdbytes (&fs->outbuf); |
242 | memcpy (buf + total, MFB_CURPTR (fs->outbuf), rdsize); | 309 | memcpy (buf + total, MFB_cur_ptr (&fs->outbuf), rdsize); |
243 | MFB_advance_pos (&fs->outbuf, rdsize); | 310 | MFB_advance_pos (&fs->outbuf, rdsize); |
244 | total += rdsize; | 311 | total += rdsize; |
245 | 312 | ||
... | @@ -275,7 +342,7 @@ filter_write_internal (mu_stream_t stream, enum mu_filter_command cmd, | ... | @@ -275,7 +342,7 @@ filter_write_internal (mu_stream_t stream, enum mu_filter_command cmd, |
275 | size_t rdsize; | 342 | size_t rdsize; |
276 | enum mu_filter_result res; | 343 | enum mu_filter_result res; |
277 | 344 | ||
278 | if (MFB_RDBYTES (fs->inbuf) < min_input_level) | 345 | if (MFB_rdbytes (&fs->inbuf) < min_input_level) |
279 | { | 346 | { |
280 | rdsize = size - total; | 347 | rdsize = size - total; |
281 | if (rdsize == 0) | 348 | if (rdsize == 0) |
... | @@ -283,15 +350,15 @@ filter_write_internal (mu_stream_t stream, enum mu_filter_command cmd, | ... | @@ -283,15 +350,15 @@ filter_write_internal (mu_stream_t stream, enum mu_filter_command cmd, |
283 | rc = MFB_require (&fs->inbuf, min_input_level); | 350 | rc = MFB_require (&fs->inbuf, min_input_level); |
284 | if (rc) | 351 | if (rc) |
285 | break; | 352 | break; |
286 | if (rdsize > MFB_FREESIZE (fs->inbuf)) | 353 | if (rdsize > MFB_freesize (&fs->inbuf)) |
287 | rdsize = MFB_FREESIZE (fs->inbuf); | 354 | rdsize = MFB_freesize (&fs->inbuf); |
288 | memcpy (MFB_ENDPTR (fs->inbuf), buf + total, rdsize); | 355 | memcpy (MFB_end_ptr (&fs->inbuf), buf + total, rdsize); |
289 | MFB_advance_level (&fs->inbuf, rdsize); | 356 | MFB_advance_level (&fs->inbuf, rdsize); |
290 | total += rdsize; | 357 | total += rdsize; |
291 | } | 358 | } |
292 | 359 | ||
293 | if (min_output_size < MFB_RDBYTES (fs->inbuf)) | 360 | if (min_output_size < MFB_rdbytes (&fs->inbuf)) |
294 | min_output_size = MFB_RDBYTES (fs->inbuf); | 361 | min_output_size = MFB_rdbytes (&fs->inbuf); |
295 | rc = MFB_require (&fs->outbuf, min_output_size); | 362 | rc = MFB_require (&fs->outbuf, min_output_size); |
296 | if (rc) | 363 | if (rc) |
297 | return rc; | 364 | return rc; |
... | @@ -332,8 +399,8 @@ filter_write_internal (mu_stream_t stream, enum mu_filter_command cmd, | ... | @@ -332,8 +399,8 @@ filter_write_internal (mu_stream_t stream, enum mu_filter_command cmd, |
332 | continue; | 399 | continue; |
333 | } | 400 | } |
334 | 401 | ||
335 | if (iobuf.isize > MFB_RDBYTES (fs->inbuf) | 402 | if (iobuf.isize > MFB_rdbytes (&fs->inbuf) |
336 | || iobuf.osize > MFB_FREESIZE (fs->outbuf)) | 403 | || iobuf.osize > MFB_freesize (&fs->outbuf)) |
337 | return MU_ERR_BUFSPACE; | 404 | return MU_ERR_BUFSPACE; |
338 | 405 | ||
339 | /* iobuf.osize contains number of bytes written to output */ | 406 | /* iobuf.osize contains number of bytes written to output */ |
... | @@ -343,15 +410,15 @@ filter_write_internal (mu_stream_t stream, enum mu_filter_command cmd, | ... | @@ -343,15 +410,15 @@ filter_write_internal (mu_stream_t stream, enum mu_filter_command cmd, |
343 | MFB_advance_pos (&fs->inbuf, iobuf.isize); | 410 | MFB_advance_pos (&fs->inbuf, iobuf.isize); |
344 | 411 | ||
345 | rc = mu_stream_write (fs->transport, | 412 | rc = mu_stream_write (fs->transport, |
346 | MFB_CURPTR (fs->outbuf), | 413 | MFB_cur_ptr (&fs->outbuf), |
347 | MFB_RDBYTES (fs->outbuf), | 414 | MFB_rdbytes (&fs->outbuf), |
348 | &rdsize); | 415 | &rdsize); |
349 | if (rc == 0) | 416 | if (rc == 0) |
350 | MFB_advance_pos (&fs->outbuf, rdsize); | 417 | MFB_advance_pos (&fs->outbuf, rdsize); |
351 | else | 418 | else |
352 | break; | 419 | break; |
353 | } | 420 | } |
354 | while (!stop && (MFB_RDBYTES (fs->outbuf) || again)); | 421 | while (!stop && (MFB_rdbytes (&fs->outbuf) || again)); |
355 | if (pret) | 422 | if (pret) |
356 | *pret = total; | 423 | *pret = total; |
357 | else if (total < size && rc == 0) | 424 | else if (total < size && rc == 0) |
... | @@ -364,7 +431,7 @@ filter_write (mu_stream_t stream, const char *buf, size_t size, size_t *pret) | ... | @@ -364,7 +431,7 @@ filter_write (mu_stream_t stream, const char *buf, size_t size, size_t *pret) |
364 | { | 431 | { |
365 | struct _mu_filter_stream *fs = (struct _mu_filter_stream *)stream; | 432 | struct _mu_filter_stream *fs = (struct _mu_filter_stream *)stream; |
366 | 433 | ||
367 | if (fs->fltflag & _MU_FILTER_DISABLED) | 434 | if (fs->flag_disabled) |
368 | return mu_stream_write (fs->transport, buf, size, pret); | 435 | return mu_stream_write (fs->transport, buf, size, pret); |
369 | 436 | ||
370 | return filter_write_internal (stream, mu_filter_xcode, buf, size, pret); | 437 | return filter_write_internal (stream, mu_filter_xcode, buf, size, pret); |
... | @@ -412,17 +479,23 @@ filter_ctl (struct _mu_stream *stream, int code, int opcode, void *ptr) | ... | @@ -412,17 +479,23 @@ filter_ctl (struct _mu_stream *stream, int code, int opcode, void *ptr) |
412 | if (status) | 479 | if (status) |
413 | return status; | 480 | return status; |
414 | if (ptr && *(int*)ptr) | 481 | if (ptr && *(int*)ptr) |
415 | fs->fltflag |= _MU_FILTER_DISABLED; | 482 | fs->flag_disabled = 1; |
416 | else | 483 | else |
417 | fs->fltflag &= ~_MU_FILTER_DISABLED; | 484 | fs->flag_disabled = 0; |
418 | break; | 485 | break; |
419 | 486 | ||
420 | case MU_IOCTL_FILTER_GET_DISABLED: | 487 | case MU_IOCTL_FILTER_GET_DISABLED: |
421 | if (!ptr) | 488 | if (!ptr) |
422 | return EINVAL; | 489 | return EINVAL; |
423 | *(int*)ptr = fs->fltflag & _MU_FILTER_DISABLED; | 490 | *(int*)ptr = fs->flag_disabled; |
424 | break; | 491 | break; |
425 | 492 | ||
493 | case MU_IOCTL_FILTER_SET_OUTBUF_SIZE: | ||
494 | if (!ptr) | ||
495 | return EINVAL; | ||
496 | fs->outbuf_size = *(size_t*)ptr; | ||
497 | break; | ||
498 | |||
426 | default: | 499 | default: |
427 | return ENOSYS; | 500 | return ENOSYS; |
428 | } | 501 | } |
... | @@ -506,8 +579,8 @@ static void | ... | @@ -506,8 +579,8 @@ static void |
506 | filter_done (mu_stream_t stream) | 579 | filter_done (mu_stream_t stream) |
507 | { | 580 | { |
508 | struct _mu_filter_stream *fs = (struct _mu_filter_stream *)stream; | 581 | struct _mu_filter_stream *fs = (struct _mu_filter_stream *)stream; |
509 | MBF_FREE (fs->inbuf); | 582 | MFB_deallocate (&fs->inbuf); |
510 | MBF_FREE (fs->outbuf); | 583 | MFB_deallocate (&fs->outbuf); |
511 | if (fs->xdata) | 584 | if (fs->xdata) |
512 | { | 585 | { |
513 | fs->xcode (fs->xdata, mu_filter_done, NULL); | 586 | fs->xcode (fs->xdata, mu_filter_done, NULL); |
... | @@ -520,7 +593,7 @@ static int | ... | @@ -520,7 +593,7 @@ static int |
520 | filter_wr_close (mu_stream_t stream) | 593 | filter_wr_close (mu_stream_t stream) |
521 | { | 594 | { |
522 | struct _mu_filter_stream *fs = (struct _mu_filter_stream *)stream; | 595 | struct _mu_filter_stream *fs = (struct _mu_filter_stream *)stream; |
523 | if (!mu_stream_eof (stream) && !(fs->fltflag & _MU_FILTER_EOF)) | 596 | if (!mu_stream_eof (stream) && !fs->flag_eof) |
524 | { | 597 | { |
525 | size_t dummy; | 598 | size_t dummy; |
526 | int rc = filter_write_internal (stream, mu_filter_lastbuf, NULL, 0, | 599 | int rc = filter_write_internal (stream, mu_filter_lastbuf, NULL, 0, |
... | @@ -528,8 +601,8 @@ filter_wr_close (mu_stream_t stream) | ... | @@ -528,8 +601,8 @@ filter_wr_close (mu_stream_t stream) |
528 | if (rc) | 601 | if (rc) |
529 | return rc; | 602 | return rc; |
530 | } | 603 | } |
531 | MBF_CLEAR (fs->inbuf); | 604 | MFB_clear (&fs->inbuf); |
532 | MBF_CLEAR (fs->outbuf); | 605 | MFB_clear (&fs->outbuf); |
533 | return mu_stream_close (fs->transport); | 606 | return mu_stream_close (fs->transport); |
534 | } | 607 | } |
535 | 608 | ||
... | @@ -537,8 +610,8 @@ static int | ... | @@ -537,8 +610,8 @@ static int |
537 | filter_rd_close (mu_stream_t stream) | 610 | filter_rd_close (mu_stream_t stream) |
538 | { | 611 | { |
539 | struct _mu_filter_stream *fs = (struct _mu_filter_stream *)stream; | 612 | struct _mu_filter_stream *fs = (struct _mu_filter_stream *)stream; |
540 | MBF_CLEAR (fs->inbuf); | 613 | MFB_clear (&fs->inbuf); |
541 | MBF_CLEAR (fs->outbuf); | 614 | MFB_clear (&fs->outbuf); |
542 | return mu_stream_close (fs->transport); | 615 | return mu_stream_close (fs->transport); |
543 | } | 616 | } |
544 | 617 | ||
... | @@ -633,7 +706,6 @@ mu_filter_stream_create (mu_stream_t *pflt, | ... | @@ -633,7 +706,6 @@ mu_filter_stream_create (mu_stream_t *pflt, |
633 | fs->xcode = xcode; | 706 | fs->xcode = xcode; |
634 | fs->xdata = xdata; | 707 | fs->xdata = xdata; |
635 | fs->mode = mode; | 708 | fs->mode = mode; |
636 | fs->fltflag = 0; | ||
637 | 709 | ||
638 | mu_stream_set_buffer ((mu_stream_t) fs, mu_buffer_full, | 710 | mu_stream_set_buffer ((mu_stream_t) fs, mu_buffer_full, |
639 | MU_FILTER_BUF_SIZE); | 711 | MU_FILTER_BUF_SIZE); | ... | ... |
... | @@ -55,20 +55,20 @@ int mu_c_tab[MU_C_TAB_MAX] = { | ... | @@ -55,20 +55,20 @@ int mu_c_tab[MU_C_TAB_MAX] = { |
55 | MU_CTYPE_CNTRL, | 55 | MU_CTYPE_CNTRL, |
56 | MU_CTYPE_PRINT|MU_CTYPE_SPACE|MU_CTYPE_BLANK, | 56 | MU_CTYPE_PRINT|MU_CTYPE_SPACE|MU_CTYPE_BLANK, |
57 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT, | 57 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT, |
58 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT|MU_CTYPE_TSPEC, | ||
58 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT, | 59 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT, |
59 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT, | 60 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT, |
60 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT, | 61 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT, |
61 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT, | 62 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT, |
62 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT, | 63 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT, |
64 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT|MU_CTYPE_TSPEC, | ||
65 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT|MU_CTYPE_TSPEC, | ||
63 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT, | 66 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT, |
64 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT, | 67 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT, |
68 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT|MU_CTYPE_TSPEC, | ||
65 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT, | 69 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT, |
66 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT, | 70 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT, |
67 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT, | 71 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT|MU_CTYPE_TSPEC, |
68 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT, | ||
69 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT, | ||
70 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT, | ||
71 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT, | ||
72 | MU_CTYPE_DIGIT|MU_CTYPE_GRAPH|MU_CTYPE_PRINT, | 72 | MU_CTYPE_DIGIT|MU_CTYPE_GRAPH|MU_CTYPE_PRINT, |
73 | MU_CTYPE_DIGIT|MU_CTYPE_GRAPH|MU_CTYPE_PRINT, | 73 | MU_CTYPE_DIGIT|MU_CTYPE_GRAPH|MU_CTYPE_PRINT, |
74 | MU_CTYPE_DIGIT|MU_CTYPE_GRAPH|MU_CTYPE_PRINT, | 74 | MU_CTYPE_DIGIT|MU_CTYPE_GRAPH|MU_CTYPE_PRINT, |
... | @@ -79,13 +79,13 @@ int mu_c_tab[MU_C_TAB_MAX] = { | ... | @@ -79,13 +79,13 @@ int mu_c_tab[MU_C_TAB_MAX] = { |
79 | MU_CTYPE_DIGIT|MU_CTYPE_GRAPH|MU_CTYPE_PRINT, | 79 | MU_CTYPE_DIGIT|MU_CTYPE_GRAPH|MU_CTYPE_PRINT, |
80 | MU_CTYPE_DIGIT|MU_CTYPE_GRAPH|MU_CTYPE_PRINT, | 80 | MU_CTYPE_DIGIT|MU_CTYPE_GRAPH|MU_CTYPE_PRINT, |
81 | MU_CTYPE_DIGIT|MU_CTYPE_GRAPH|MU_CTYPE_PRINT, | 81 | MU_CTYPE_DIGIT|MU_CTYPE_GRAPH|MU_CTYPE_PRINT, |
82 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT, | 82 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT|MU_CTYPE_TSPEC, |
83 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT, | 83 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT|MU_CTYPE_TSPEC, |
84 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT, | 84 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT|MU_CTYPE_TSPEC, |
85 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT, | 85 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT|MU_CTYPE_TSPEC, |
86 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT, | 86 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT|MU_CTYPE_TSPEC, |
87 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT, | 87 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT|MU_CTYPE_TSPEC, |
88 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT, | 88 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT|MU_CTYPE_TSPEC, |
89 | MU_CTYPE_ALPHA|MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_UPPER|MU_CTYPE_XLETR, | 89 | MU_CTYPE_ALPHA|MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_UPPER|MU_CTYPE_XLETR, |
90 | MU_CTYPE_ALPHA|MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_UPPER|MU_CTYPE_XLETR, | 90 | MU_CTYPE_ALPHA|MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_UPPER|MU_CTYPE_XLETR, |
91 | MU_CTYPE_ALPHA|MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_UPPER|MU_CTYPE_XLETR, | 91 | MU_CTYPE_ALPHA|MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_UPPER|MU_CTYPE_XLETR, |
... | @@ -112,9 +112,9 @@ int mu_c_tab[MU_C_TAB_MAX] = { | ... | @@ -112,9 +112,9 @@ int mu_c_tab[MU_C_TAB_MAX] = { |
112 | MU_CTYPE_ALPHA|MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_UPPER, | 112 | MU_CTYPE_ALPHA|MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_UPPER, |
113 | MU_CTYPE_ALPHA|MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_UPPER, | 113 | MU_CTYPE_ALPHA|MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_UPPER, |
114 | MU_CTYPE_ALPHA|MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_UPPER, | 114 | MU_CTYPE_ALPHA|MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_UPPER, |
115 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT, | 115 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT|MU_CTYPE_TSPEC, |
116 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT, | 116 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT|MU_CTYPE_TSPEC, |
117 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT, | 117 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT|MU_CTYPE_TSPEC, |
118 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT, | 118 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT, |
119 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT, | 119 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT, |
120 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT, | 120 | MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT, | ... | ... |
... | @@ -119,13 +119,128 @@ filename(lang:el_GR/UTF-8)=αρχείο για την δοκιμασία | ... | @@ -119,13 +119,128 @@ filename(lang:el_GR/UTF-8)=αρχείο για την δοκιμασία |
119 | 119 | ||
120 | MIMEHDR([combined charset, lang and cset],[mimehdr08 mimehdr-comb mimehdr-charset-rfc2231], | 120 | MIMEHDR([combined charset, lang and cset],[mimehdr08 mimehdr-comb mimehdr-charset-rfc2231], |
121 | [], | 121 | [], |
122 | [application/x-stuff | 122 | [application/x-stuff; |
123 | title*0*=us-ascii'en'This%20is%20even%20more%20 | 123 | title*0*=us-ascii'en'This%20is%20even%20more%20; |
124 | title*1*=%2A%2A%2Afun%2A%2A%2A%20 | 124 | title*1*=%2A%2A%2Afun%2A%2A%2A%20; |
125 | title*2="isn't it!" | 125 | title*2="isn't it!" |
126 | ], | 126 | ], |
127 | [application/x-stuff | 127 | [application/x-stuff |
128 | title(lang:en/us-ascii)=This is even more ***fun*** isn't it! | 128 | title(lang:en/us-ascii)=This is even more ***fun*** isn't it! |
129 | ]) | 129 | ]) |
130 | 130 | ||
131 | MIMEHDR([format: simple],[mimehdr09], | ||
132 | [-header=X-MIME-Test-Header -width=26], | ||
133 | [application/x-stuff; charset=ascii; title=foobar], | ||
134 | [X-MIME-Test-Header: application/x-stuff; | ||
135 | charset=ascii; | ||
136 | title=foobar | ||
137 | |||
138 | ]) | ||
139 | |||
140 | MIMEHDR([format: split],[mimehdr10], | ||
141 | [-header=X-MIME-Test-Header -width=76], | ||
142 | [attachment; title="unusually long filename created by gray expressly for testing purposes and not meant for any other purpose but testing the formatting of very long MIME headers"], | ||
143 | [X-MIME-Test-Header: attachment; | ||
144 | title*0="unusually long filename created by gray expressly for testing pu"; | ||
145 | title*1="rposes and not meant for any other purpose but testing the forma"; | ||
146 | title*2="tting of very long MIME headers" | ||
147 | |||
148 | ]) | ||
149 | |||
150 | MIMEHDR([format: split 2],[mimehdr11], | ||
151 | [-header=X-MIME-Test-Header -width=26], | ||
152 | [attachment; title="unusually long filename created by gray expressly for testing purposes and not meant for any other purpose but testing the formatting of very long MIME headers"], | ||
153 | [X-MIME-Test-Header: attachment; | ||
154 | title*0="unusually long"; | ||
155 | title*1=" filename crea"; | ||
156 | title*2="ted by gray ex"; | ||
157 | title*3="pressly for te"; | ||
158 | title*4="sting purposes"; | ||
159 | title*5=" and not meant"; | ||
160 | title*6=" for any other"; | ||
161 | title*7=" purpose but t"; | ||
162 | title*8="esting the for"; | ||
163 | title*9="matting of ver"; | ||
164 | title*10="y long MIME h"; | ||
165 | title*11="eaders" | ||
166 | |||
167 | ]) | ||
168 | |||
169 | # This test is split into 5 subtests to make sure encoded character | ||
170 | # representation is not split between subsequent numbered parameters. | ||
171 | MIMEHDR([format: language info 1],[mimehdr12 mimehdr12a], | ||
172 | [-header=X-MIME-Test-Header -width=27], | ||
173 | [application/x-stuff; | ||
174 | title*0*=us-ascii'en'This%20is%20even%20more%20; | ||
175 | title*1*=%2A%2A%2Afun%2A%2A%2A%20; | ||
176 | title*2="isn't it!" | ||
177 | ], | ||
178 | [X-MIME-Test-Header: application/x-stuff; | ||
179 | title*0*=en'us-ascii'This; | ||
180 | title*1*=%20is%20even%20m; | ||
181 | title*2*=ore%20***fun***; | ||
182 | title*3*=%20isn't%20it! | ||
183 | |||
184 | ]) | ||
185 | |||
186 | MIMEHDR([format: language info 2],[mimehdr12 mimehdr12b], | ||
187 | [-header=X-MIME-Test-Header -width=28], | ||
188 | [application/x-stuff; | ||
189 | title*0*=us-ascii'en'This%20is%20even%20more%20; | ||
190 | title*1*=%2A%2A%2Afun%2A%2A%2A%20; | ||
191 | title*2="isn't it!" | ||
192 | ], | ||
193 | [X-MIME-Test-Header: application/x-stuff; | ||
194 | title*0*=en'us-ascii'This; | ||
195 | title*1*=%20is%20even%20mo; | ||
196 | title*2*=re%20***fun***; | ||
197 | title*3*=%20isn't%20it! | ||
198 | |||
199 | ]) | ||
200 | |||
201 | MIMEHDR([format: language info 3],[mimehdr12 mimehdr12c], | ||
202 | [-header=X-MIME-Test-Header -width=29], | ||
203 | [application/x-stuff; | ||
204 | title*0*=us-ascii'en'This%20is%20even%20more%20; | ||
205 | title*1*=%2A%2A%2Afun%2A%2A%2A%20; | ||
206 | title*2="isn't it!" | ||
207 | ], | ||
208 | [X-MIME-Test-Header: application/x-stuff; | ||
209 | title*0*=en'us-ascii'This; | ||
210 | title*1*=%20is%20even%20mor; | ||
211 | title*2*=e%20***fun***%20is; | ||
212 | title*3*=n't%20it! | ||
213 | |||
214 | ]) | ||
215 | |||
216 | MIMEHDR([format: language info 4],[mimehdr12 mimehdr12d], | ||
217 | [-header=X-MIME-Test-Header -width=30], | ||
218 | [application/x-stuff; | ||
219 | title*0*=us-ascii'en'This%20is%20even%20more%20; | ||
220 | title*1*=%2A%2A%2Afun%2A%2A%2A%20; | ||
221 | title*2="isn't it!" | ||
222 | ], | ||
223 | [X-MIME-Test-Header: application/x-stuff; | ||
224 | title*0*=en'us-ascii'This; | ||
225 | title*1*=%20is%20even%20more; | ||
226 | title*2*=%20***fun***%20isn'; | ||
227 | title*3*=t%20it! | ||
228 | |||
229 | ]) | ||
230 | |||
231 | MIMEHDR([format: language info 5],[mimehdr12 mimehdr12e], | ||
232 | [-header=X-MIME-Test-Header -width=31], | ||
233 | [application/x-stuff; | ||
234 | title*0*=us-ascii'en'This%20is%20even%20more%20; | ||
235 | title*1*=%2A%2A%2Afun%2A%2A%2A%20; | ||
236 | title*2="isn't it!" | ||
237 | ], | ||
238 | [X-MIME-Test-Header: application/x-stuff; | ||
239 | title*0*=en'us-ascii'This%20i; | ||
240 | title*1*=s%20even%20more%20**; | ||
241 | title*2*=*fun***%20isn't%20it; | ||
242 | title*3*=! | ||
243 | |||
244 | ]) | ||
245 | |||
131 | m4_popdef([MIMEHDR]) | 246 | m4_popdef([MIMEHDR]) | ... | ... |
... | @@ -61,6 +61,8 @@ main (int argc, char **argv) | ... | @@ -61,6 +61,8 @@ main (int argc, char **argv) |
61 | char *value; | 61 | char *value; |
62 | mu_assoc_t assoc; | 62 | mu_assoc_t assoc; |
63 | char *charset = NULL; | 63 | char *charset = NULL; |
64 | char *header_name = NULL; | ||
65 | unsigned long width = 76; | ||
64 | 66 | ||
65 | mu_set_program_name (argv[0]); | 67 | mu_set_program_name (argv[0]); |
66 | for (i = 1; i < argc; i++) | 68 | for (i = 1; i < argc; i++) |
... | @@ -73,9 +75,13 @@ main (int argc, char **argv) | ... | @@ -73,9 +75,13 @@ main (int argc, char **argv) |
73 | charset = opt + 9; | 75 | charset = opt + 9; |
74 | else if (strcmp (opt, "-h") == 0 || strcmp (opt, "-help") == 0) | 76 | else if (strcmp (opt, "-h") == 0 || strcmp (opt, "-help") == 0) |
75 | { | 77 | { |
76 | mu_printf ("usage: %s [-charset=cs] [-debug=SPEC]", mu_program_name); | 78 | mu_printf ("usage: %s [-charset=cs] [-debug=SPEC] [-header=NAME] [-width=N]", mu_program_name); |
77 | return 0; | 79 | return 0; |
78 | } | 80 | } |
81 | else if (strncmp (opt, "-header=", 8) == 0) | ||
82 | header_name = opt + 8; | ||
83 | else if (strncmp (opt, "-width=", 7) == 0) | ||
84 | width = strtoul (opt + 7, NULL, 10); | ||
79 | else | 85 | else |
80 | { | 86 | { |
81 | mu_error ("unknown option %s", opt); | 87 | mu_error ("unknown option %s", opt); |
... | @@ -97,9 +103,22 @@ main (int argc, char **argv) | ... | @@ -97,9 +103,22 @@ main (int argc, char **argv) |
97 | 103 | ||
98 | MU_ASSERT (mu_mime_header_parse ((char*)trans[0], charset, &value, &assoc)); | 104 | MU_ASSERT (mu_mime_header_parse ((char*)trans[0], charset, &value, &assoc)); |
99 | 105 | ||
100 | mu_printf ("%s\n", value); | 106 | if (header_name) |
101 | mu_assoc_sort_r (assoc, sort_names, NULL); | 107 | { |
102 | mu_assoc_foreach (assoc, print_param, NULL); | 108 | mu_header_t hdr; |
109 | mu_stream_t hstr; | ||
110 | |||
111 | MU_ASSERT (mu_header_create (&hdr, NULL, 0)); | ||
112 | MU_ASSERT (mu_mime_header_set_w (hdr, header_name, value, assoc, width)); | ||
113 | MU_ASSERT (mu_header_get_streamref (hdr, &hstr)); | ||
114 | MU_ASSERT (mu_stream_copy (mu_strout, hstr, 0, NULL)); | ||
115 | } | ||
116 | else | ||
117 | { | ||
118 | mu_printf ("%s\n", value); | ||
119 | mu_assoc_sort_r (assoc, sort_names, NULL); | ||
120 | mu_assoc_foreach (assoc, print_param, NULL); | ||
121 | } | ||
103 | 122 | ||
104 | return 0; | 123 | return 0; |
105 | } | 124 | } | ... | ... |
... | @@ -464,8 +464,8 @@ saveatt (void *item, void *data) | ... | @@ -464,8 +464,8 @@ saveatt (void *item, void *data) |
464 | char *p; | 464 | char *p; |
465 | 465 | ||
466 | rc = mu_attachment_create (&part, aptr->content_type, aptr->encoding, | 466 | rc = mu_attachment_create (&part, aptr->content_type, aptr->encoding, |
467 | env->alt ? NULL : aptr->name, | 467 | aptr->name, |
468 | env->alt ? NULL : aptr->filename); | 468 | aptr->filename); |
469 | if (rc) | 469 | if (rc) |
470 | { | 470 | { |
471 | mu_error (_("can't create attachment %s: %s"), | 471 | mu_error (_("can't create attachment %s: %s"), | ... | ... |
-
Please register or sign in to post a comment