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
907 additions
and
39 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,6 +59,7 @@ extern int mu_c_tab[MU_C_TAB_MAX]; | ... | @@ -58,6 +59,7 @@ 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) |
62 | #define mu_istspec(c) mu_c_is_class (c, MU_CTYPE_TSPEC) | ||
61 | 63 | ||
62 | #define mu_tolower(c) \ | 64 | #define mu_tolower(c) \ |
63 | ({ int __c = (c); \ | 65 | ({ int __c = (c); \ | ... | ... |
... | @@ -126,6 +126,8 @@ extern mu_filter_record_t mu_iconv_filter; | ... | @@ -126,6 +126,8 @@ 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 | extern mu_filter_record_t mu_percent_filter; | ||
130 | extern mu_filter_record_t mu_dq_filter; | ||
129 | 131 | ||
130 | enum mu_iconv_fallback_mode | 132 | enum mu_iconv_fallback_mode |
131 | { | 133 | { | ... | ... |
... | @@ -76,6 +76,13 @@ int mu_mime_header_parse_subset (const char *text, const char *charset, | ... | @@ -76,6 +76,13 @@ 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 | 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 | |||
85 | |||
79 | #ifdef __cplusplus | 86 | #ifdef __cplusplus |
80 | } | 87 | } |
81 | #endif | 88 | #endif | ... | ... |
... | @@ -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 | ||
... | @@ -794,3 +795,33 @@ mu_assoc_sort_r (mu_assoc_t assoc, mu_assoc_comparator_t cmp, void *data) | ... | @@ -794,3 +795,33 @@ mu_assoc_sort_r (mu_assoc_t assoc, mu_assoc_comparator_t cmp, void *data) |
794 | return 0; | 795 | return 0; |
795 | } | 796 | } |
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 | } | ||
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 |
This diff is collapsed.
Click to expand it.
... | @@ -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 | ||
106 | if (header_name) | ||
107 | { | ||
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 | { | ||
100 | mu_printf ("%s\n", value); | 118 | mu_printf ("%s\n", value); |
101 | mu_assoc_sort_r (assoc, sort_names, NULL); | 119 | mu_assoc_sort_r (assoc, sort_names, NULL); |
102 | mu_assoc_foreach (assoc, print_param, 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