Commit eaf6c0f0 eaf6c0f065f0b1b09203dcd543acafcbcf414a61 by Sergey Poznyakoff

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.
1 parent 5aea5b2d
...@@ -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
......
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;
......
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=";
......
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"),
......