summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2017-04-22 12:50:41 +0300
committerSergey Poznyakoff <gray@gnu.org.ua>2017-04-22 20:14:02 +0300
commiteaf6c0f065f0b1b09203dcd543acafcbcf414a61 (patch)
treeada72b08fe1bee1957b0c427f42a69bf774234a5
parent5aea5b2d9b0c87fe81ee566dba830a568398679c (diff)
downloadmailutils-eaf6c0f065f0b1b09203dcd543acafcbcf414a61.tar.gz
mailutils-eaf6c0f065f0b1b09203dcd543acafcbcf414a61.tar.bz2
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.
-rw-r--r--include/mailutils/assoc.h4
-rw-r--r--include/mailutils/cctype.h28
-rw-r--r--include/mailutils/filter.h4
-rw-r--r--include/mailutils/mime.h7
-rw-r--r--include/mailutils/stream.h6
-rw-r--r--include/mailutils/sys/filter.h8
-rw-r--r--libmailutils/base/assoc.c31
-rw-r--r--libmailutils/filter/Makefile.am2
-rw-r--r--libmailutils/filter/dq.c143
-rw-r--r--libmailutils/filter/filter.c2
-rw-r--r--libmailutils/filter/percent.c186
-rw-r--r--libmailutils/mime/Makefile.am3
-rw-r--r--libmailutils/mime/mime.c36
-rw-r--r--libmailutils/mime/mimehdrset.c314
-rw-r--r--libmailutils/stream/fltstream.c242
-rw-r--r--libmailutils/string/muctype.c30
-rw-r--r--libmailutils/tests/mimehdr.at121
-rw-r--r--libmailutils/tests/mimehdr.c27
-rw-r--r--mail/send.c4
19 files changed, 1069 insertions, 129 deletions
diff --git a/include/mailutils/assoc.h b/include/mailutils/assoc.h
index 23ae7cda4..a8f9845e1 100644
--- a/include/mailutils/assoc.h
+++ b/include/mailutils/assoc.h
@@ -53,6 +53,10 @@ typedef int (*mu_assoc_comparator_t) (const char *, const void *,
int mu_assoc_sort_r (mu_assoc_t assoc, mu_assoc_comparator_t cmp, void *data);
+int mu_assoc_mark (mu_assoc_t asc, int (*cond) (char const *, void *, void *),
+ void *data);
+int mu_assoc_sweep (mu_assoc_t asc);
+
#ifdef __cplusplus
}
diff --git a/include/mailutils/cctype.h b/include/mailutils/cctype.h
index ecd9c4007..bed749b96 100644
--- a/include/mailutils/cctype.h
+++ b/include/mailutils/cctype.h
@@ -24,18 +24,19 @@
extern "C" {
#endif
-#define MU_CTYPE_ALPHA 0x001
-#define MU_CTYPE_DIGIT 0x002
-#define MU_CTYPE_BLANK 0x004
-#define MU_CTYPE_CNTRL 0x008
-#define MU_CTYPE_GRAPH 0x010
-#define MU_CTYPE_LOWER 0x020
-#define MU_CTYPE_UPPER 0x040
-#define MU_CTYPE_PRINT 0x080
-#define MU_CTYPE_PUNCT 0x100
-#define MU_CTYPE_SPACE 0x200
-#define MU_CTYPE_XLETR 0x400
-#define MU_CTYPE_ENDLN 0x800
+#define MU_CTYPE_ALPHA 0x0001
+#define MU_CTYPE_DIGIT 0x0002
+#define MU_CTYPE_BLANK 0x0004
+#define MU_CTYPE_CNTRL 0x0008
+#define MU_CTYPE_GRAPH 0x0010
+#define MU_CTYPE_LOWER 0x0020
+#define MU_CTYPE_UPPER 0x0040
+#define MU_CTYPE_PRINT 0x0080
+#define MU_CTYPE_PUNCT 0x0100
+#define MU_CTYPE_SPACE 0x0200
+#define MU_CTYPE_XLETR 0x0400
+#define MU_CTYPE_ENDLN 0x0800
+#define MU_CTYPE_TSPEC 0x1000 /* tspecials: RFC 2045, section 5.1. */
#define MU_C_TAB_MAX 128
@@ -58,7 +59,8 @@ extern int mu_c_tab[MU_C_TAB_MAX];
#define mu_isascii(c) (((unsigned)c) < MU_C_TAB_MAX)
#define mu_isblank(c) mu_c_is_class (c, MU_CTYPE_BLANK)
#define mu_isendln(c) mu_c_is_class (c, MU_CTYPE_ENDLN)
-
+#define mu_istspec(c) mu_c_is_class (c, MU_CTYPE_TSPEC)
+
#define mu_tolower(c) \
({ int __c = (c); \
(__c >= 'A' && __c <= 'Z' ? __c - 'A' + 'a' : __c); \
diff --git a/include/mailutils/filter.h b/include/mailutils/filter.h
index 8bd107100..c8bddd40b 100644
--- a/include/mailutils/filter.h
+++ b/include/mailutils/filter.h
@@ -126,7 +126,9 @@ extern mu_filter_record_t mu_iconv_filter;
extern mu_filter_record_t mu_c_escape_filter;
extern mu_filter_record_t mu_htmlent_filter;
extern mu_filter_record_t mu_xml_filter;
-
+extern mu_filter_record_t mu_percent_filter;
+extern mu_filter_record_t mu_dq_filter;
+
enum mu_iconv_fallback_mode
{
mu_fallback_none,
diff --git a/include/mailutils/mime.h b/include/mailutils/mime.h
index 786f96f2b..503ebe399 100644
--- a/include/mailutils/mime.h
+++ b/include/mailutils/mime.h
@@ -75,6 +75,13 @@ int mu_mime_header_parse (const char *text, const char *charset, char **pvalue,
int mu_mime_header_parse_subset (const char *text, const char *charset,
char **pvalue,
mu_assoc_t assoc);
+
+int mu_mime_header_set_w (mu_header_t hdr, const char *name,
+ const char *value, mu_assoc_t params,
+ size_t line_width);
+int mu_mime_header_set (mu_header_t hdr, const char *name,
+ const char *value, mu_assoc_t params);
+
#ifdef __cplusplus
}
diff --git a/include/mailutils/stream.h b/include/mailutils/stream.h
index 2e7b86cb5..f7f58ba8a 100644
--- a/include/mailutils/stream.h
+++ b/include/mailutils/stream.h
@@ -195,6 +195,12 @@ enum mu_buffer_type
#define MU_IOCTL_FILTER_GET_DISABLED 0
#define MU_IOCTL_FILTER_SET_DISABLED 1
+ /* Set transcoder output buffer size.
+ Arg: size_t*
+ Has effect only if the stream is unbuffered
+ */
+#define MU_IOCTL_FILTER_SET_OUTBUF_SIZE 2
+
/* TLS transport streams */
/* Get cipher info.
Arg: mu_property_t *
diff --git a/include/mailutils/sys/filter.h b/include/mailutils/sys/filter.h
index 1ee0b1942..23b5affcd 100644
--- a/include/mailutils/sys/filter.h
+++ b/include/mailutils/sys/filter.h
@@ -36,16 +36,14 @@ struct _mu_filter_buffer
size_t pos;
};
-#define _MU_FILTER_DISABLED 0x01
-#define _MU_FILTER_EOF 0x02
-
struct _mu_filter_stream
{
struct _mu_stream stream;
mu_stream_t transport;
int mode;
- int fltflag;
-
+ unsigned flag_disabled:1;
+ unsigned flag_eof:1;
+ size_t outbuf_size;
struct _mu_filter_buffer inbuf, outbuf;
mu_filter_xcode_t xcode;
void *xdata;
diff --git a/libmailutils/base/assoc.c b/libmailutils/base/assoc.c
index 4e31b499a..b0e353d32 100644
--- a/libmailutils/base/assoc.c
+++ b/libmailutils/base/assoc.c
@@ -47,6 +47,7 @@ struct _mu_assoc_elem
{
char *name;
struct _mu_assoc_elem *next, *prev;
+ int mark:1;
char *data;
};
@@ -793,4 +794,34 @@ mu_assoc_sort_r (mu_assoc_t assoc, mu_assoc_comparator_t cmp, void *data)
return 0;
}
+
+int
+mu_assoc_mark (mu_assoc_t asc, int (*cond) (char const *, void *, void *),
+ void *data)
+{
+ struct _mu_assoc_elem *elt;
+
+ if (!asc)
+ return EINVAL;
+ for (elt = asc->head; elt; elt = elt->next)
+ elt->mark = !!cond (elt->name, elt->data, data);
+ return 0;
+}
+
+int
+mu_assoc_sweep (mu_assoc_t asc)
+{
+ unsigned i;
+
+ if (!asc)
+ return EINVAL;
+
+ for (i = hash_size[asc->hash_num]; i > 0; i--)
+ {
+ if (asc->tab[i-1] && asc->tab[i-1]->mark)
+ assoc_remove (asc, i-1);
+ }
+ return 0;
+}
+
diff --git a/libmailutils/filter/Makefile.am b/libmailutils/filter/Makefile.am
index b735bf772..5daedacae 100644
--- a/libmailutils/filter/Makefile.am
+++ b/libmailutils/filter/Makefile.am
@@ -25,6 +25,7 @@ libfilter_la_SOURCES =\
crlfflt.c\
decode.c\
dot.c\
+ dq.c\
filter.c\
fltchain.c\
fromflt.c\
@@ -34,6 +35,7 @@ libfilter_la_SOURCES =\
inline-comment.c\
linecon.c\
linelenflt.c\
+ percent.c\
qpflt.c\
xml.c
diff --git a/libmailutils/filter/dq.c b/libmailutils/filter/dq.c
new file mode 100644
index 000000000..d3bb18523
--- /dev/null
+++ b/libmailutils/filter/dq.c
@@ -0,0 +1,143 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+ Copyright (C) 2011-2012, 2014-2017 Free Software Foundation, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General
+ Public License along with this library. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* Doble-quote escaping filter.
+ In encode mode, escapes each occurrence of double-quote and backslash
+ by prefixing it with backslash.
+ In decode mode, removes backslash prefixes.
+*/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <mailutils/errno.h>
+#include <mailutils/filter.h>
+#include <mailutils/wordsplit.h>
+#include <mailutils/cctype.h>
+
+/* Move min(isize,osize) bytes from iptr to optr, replacing each
+ escapable control character with its escape sequence. */
+static enum mu_filter_result
+_dq_encoder (void *xd MU_ARG_UNUSED,
+ enum mu_filter_command cmd,
+ struct mu_filter_io *iobuf)
+{
+ size_t i, j;
+ const unsigned char *iptr;
+ size_t isize;
+ char *optr;
+ size_t osize;
+
+ switch (cmd)
+ {
+ case mu_filter_init:
+ case mu_filter_done:
+ return mu_filter_ok;
+ default:
+ break;
+ }
+
+ iptr = (const unsigned char *) iobuf->input;
+ isize = iobuf->isize;
+ optr = iobuf->output;
+ osize = iobuf->osize;
+
+ for (i = j = 0; i < isize && j < osize; i++)
+ {
+ unsigned char c = *iptr++;
+
+ if (strchr ("\\\"", c))
+ {
+ if (j + 1 == osize)
+ {
+ if (i == 0)
+ {
+ iobuf->osize = 2;
+ return mu_filter_moreoutput;
+ }
+ break;
+ }
+ else
+ {
+ optr[j++] = '\\';
+ optr[j++] = c;
+ }
+ }
+ else
+ optr[j++] = c;
+ }
+ iobuf->isize = i;
+ iobuf->osize = j;
+ return mu_filter_ok;
+}
+
+/* Move min(isize,osize) bytes from iptr to optr, replacing each escape
+ sequence with its ASCII code. */
+static enum mu_filter_result
+_dq_decoder (void *xd MU_ARG_UNUSED,
+ enum mu_filter_command cmd,
+ struct mu_filter_io *iobuf)
+{
+ size_t i, j;
+ const unsigned char *iptr;
+ size_t isize;
+ char *optr;
+ size_t osize;
+
+ switch (cmd)
+ {
+ case mu_filter_init:
+ case mu_filter_done:
+ return mu_filter_ok;
+ default:
+ break;
+ }
+
+ iptr = (const unsigned char *) iobuf->input;
+ isize = iobuf->isize;
+ optr = iobuf->output;
+ osize = iobuf->osize;
+
+ for (i = j = 0; i < isize && j < osize; i++)
+ {
+ unsigned char c = *iptr++;
+ if (c == '\\')
+ {
+ if (i + 1 == isize)
+ break;
+ optr[j++] = *iptr++;
+ }
+ else
+ optr[j++] = c;
+ }
+
+ iobuf->isize = i;
+ iobuf->osize = j;
+ return mu_filter_ok;
+}
+
+static struct _mu_filter_record _dq_filter = {
+ "dq",
+ NULL,
+ _dq_encoder,
+ _dq_decoder,
+};
+
+mu_filter_record_t mu_dq_filter = &_dq_filter;
+
diff --git a/libmailutils/filter/filter.c b/libmailutils/filter/filter.c
index 0717425fc..00bc50fa2 100644
--- a/libmailutils/filter/filter.c
+++ b/libmailutils/filter/filter.c
@@ -86,6 +86,8 @@ mu_filter_get_list (mu_list_t *plist)
mu_list_append (filter_list, mu_c_escape_filter);
mu_list_append (filter_list, mu_htmlent_filter);
mu_list_append (filter_list, mu_xml_filter);
+ mu_list_append (filter_list, mu_percent_filter);
+ mu_list_append (filter_list, mu_dq_filter);
/* FIXME: add the default encodings? */
}
*plist = filter_list;
diff --git a/libmailutils/filter/percent.c b/libmailutils/filter/percent.c
new file mode 100644
index 000000000..62d248d88
--- /dev/null
+++ b/libmailutils/filter/percent.c
@@ -0,0 +1,186 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+ Copyright (C) 2011-2012, 2014-2017 Free Software Foundation, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General
+ Public License along with this library. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <mailutils/errno.h>
+#include <mailutils/filter.h>
+#include <mailutils/cctype.h>
+
+static char xchar[] = "0123456789ABCDEF";
+
+static enum mu_filter_result
+percent_encoder (void *xd,
+ enum mu_filter_command cmd,
+ struct mu_filter_io *iobuf)
+{
+ size_t i, j;
+ const unsigned char *iptr;
+ size_t isize;
+ char *optr;
+ size_t osize;
+ char *escape_chars = xd;
+
+ switch (cmd)
+ {
+ case mu_filter_init:
+ case mu_filter_done:
+ return mu_filter_ok;
+ default:
+ break;
+ }
+
+ iptr = (const unsigned char *) iobuf->input;
+ isize = iobuf->isize;
+ optr = iobuf->output;
+ osize = iobuf->osize;
+
+ for (i = j = 0; i < isize && j < osize; i++)
+ {
+ unsigned char c = iptr[i];
+
+ if (c == 0 || strchr (escape_chars, c))
+ {
+ if (j + 3 >= osize)
+ {
+ if (i == 0)
+ {
+ iobuf->osize = 3;
+ return mu_filter_moreoutput;
+ }
+ break;
+ }
+ optr[j++] = '%';
+ optr[j++] = xchar[((c >> 4) & 0xf)];
+ optr[j++] = xchar[c & 0xf];
+ }
+ else
+ optr[j++] = c;
+ }
+ iobuf->isize = i;
+ iobuf->osize = j;
+ return mu_filter_ok;
+}
+
+static enum mu_filter_result
+percent_decoder (void *xd MU_ARG_UNUSED,
+ enum mu_filter_command cmd,
+ struct mu_filter_io *iobuf)
+{
+ size_t i, j;
+ const unsigned char *iptr;
+ size_t isize;
+ char *optr;
+ size_t osize;
+
+ switch (cmd)
+ {
+ case mu_filter_init:
+ case mu_filter_done:
+ return mu_filter_ok;
+ default:
+ break;
+ }
+
+ iptr = (const unsigned char *) iobuf->input;
+ isize = iobuf->isize;
+ optr = iobuf->output;
+ osize = iobuf->osize;
+
+ for (i = j = 0; i < isize && j < osize; j++)
+ {
+ unsigned char c = iptr[i++];
+ if (c == '%')
+ {
+ char *phi, *plo;
+
+ if (i + 2 >= isize)
+ break;
+ phi = strchr (xchar, mu_toupper (iptr[i]));
+ plo = strchr (xchar, mu_toupper (iptr[i+1]));
+ if (phi && plo)
+ {
+ optr[j] = ((phi - xchar) << 4) + (plo - xchar);
+ i += 2;
+ }
+ else
+ optr[j] = c;
+ }
+ else
+ optr[j] = c;
+ }
+ iobuf->isize = i;
+ iobuf->osize = j;
+ return mu_filter_ok;
+}
+
+static int
+percent_alloc (void **pret, int mode, int argc, const char **argv)
+{
+ if (mode == MU_FILTER_ENCODE)
+ {
+ char *s;
+ if (argc > 1)
+ {
+ int i;
+ size_t len = 0;
+
+ for (i = 1; i < argc; i++)
+ len += strlen (argv[i]);
+ s = malloc (len + 1);
+ if (!s)
+ return ENOMEM;
+ *pret = s;
+ *s = 0;
+ for (i = 1; i < argc; i++)
+ strcat (s, argv[i]);
+ }
+ else
+ {
+ int i;
+
+ s = malloc (UCHAR_MAX);
+ if (!s)
+ return ENOMEM;
+ *pret = s;
+ for (i = 1; i <= UCHAR_MAX; i++)
+ {
+ if (i == '%' || i == '"' || !mu_isgraph (i))
+ *s++ = i;
+ }
+ *s = 0;
+ }
+ }
+ else
+ *pret = NULL;
+ return 0;
+}
+
+static struct _mu_filter_record _percent_filter = {
+ "percent",
+ percent_alloc,
+ percent_encoder,
+ percent_decoder
+};
+
+mu_filter_record_t mu_percent_filter = &_percent_filter;
+
+
diff --git a/libmailutils/mime/Makefile.am b/libmailutils/mime/Makefile.am
index 98895cfd7..3edb9fdfa 100644
--- a/libmailutils/mime/Makefile.am
+++ b/libmailutils/mime/Makefile.am
@@ -20,6 +20,7 @@ noinst_LTLIBRARIES = libmime.la
libmime_la_SOURCES = \
attachment.c\
mime.c\
- mimehdr.c
+ mimehdr.c\
+ mimehdrset.c
AM_CPPFLAGS = @MU_LIB_COMMON_INCLUDES@ -I/libmailutils
diff --git a/libmailutils/mime/mime.c b/libmailutils/mime/mime.c
index 9c3879769..e4463d307 100644
--- a/libmailutils/mime/mime.c
+++ b/libmailutils/mime/mime.c
@@ -38,6 +38,8 @@
#include <mailutils/header.h>
#include <mailutils/errno.h>
#include <mailutils/util.h>
+#include <mailutils/assoc.h>
+#include <mailutils/io.h>
#include <mailutils/sys/mime.h>
#include <mailutils/sys/message.h>
@@ -445,6 +447,13 @@ _mimepart_body_lines (mu_body_t body, size_t *plines)
/*------ Mime message/header functions for CREATING multipart message -----*/
static int
+retain_charset (char const *name, void *value MU_ARG_UNUSED,
+ void *data MU_ARG_UNUSED)
+{
+ return strcmp (name, "charset") != 0;
+}
+
+static int
_mime_set_content_type (mu_mime_t mime)
{
const char *content_type;
@@ -473,9 +482,36 @@ _mime_set_content_type (mu_mime_t mime)
for (i = 0; i < mime->nmtp_parts; i++)
{
mu_header_t hdr;
+ char *val;
+ int rc;
mu_message_get_header (mime->mtp_parts[i]->msg, &hdr);
mu_header_remove (hdr, MU_HEADER_CONTENT_DISPOSITION, 1);
+
+ rc = mu_header_aget_value_unfold (hdr, MU_HEADER_CONTENT_TYPE,
+ &val);
+ if (rc == 0)
+ {
+ mu_content_type_t ct;
+ rc = mu_content_type_parse (val, NULL, &ct);
+ if (rc == 0)
+ {
+ char *type;
+
+ mu_assoc_mark (ct->param, retain_charset, NULL);
+ mu_assoc_sweep (ct->param);
+
+ rc = mu_asprintf (&type, "%s/%s", ct->type, ct->subtype);
+ if (rc == 0)
+ {
+ mu_mime_header_set (hdr,
+ MU_HEADER_CONTENT_TYPE, type,
+ ct->param);
+ free (type);
+ }
+ mu_content_type_destroy (&ct);
+ }
+ }
}
content_type = "multipart/alternative; boundary=";
diff --git a/libmailutils/mime/mimehdrset.c b/libmailutils/mime/mimehdrset.c
new file mode 100644
index 000000000..7c127caee
--- /dev/null
+++ b/libmailutils/mime/mimehdrset.c
@@ -0,0 +1,314 @@
+/* Functions for formatting RFC-2231-compliant mail headers fields.
+ GNU Mailutils -- a suite of utilities for electronic mail
+ Copyright (C) 1999-2001, 2004-2005, 2007, 2009-2012, 2014-2017 Free
+ Software Foundation, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General
+ Public License along with this library. If not,
+ see <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <mailutils/mime.h>
+#include <mailutils/cctype.h>
+#include <mailutils/cstr.h>
+#include <mailutils/header.h>
+#include <mailutils/stream.h>
+#include <mailutils/filter.h>
+#include <mailutils/assoc.h>
+#include <mailutils/errno.h>
+
+struct header_buffer
+{
+ mu_stream_t str; /* Output stream */
+ size_t line_len; /* Length of current line */
+ size_t line_max; /* Max. line length */
+};
+
+static int
+mime_store_parameter (char const *name, void *value, void *data)
+{
+ struct mu_mime_param *p = value;
+ struct header_buffer *hbuf = data;
+ size_t nlen; /* Length of parameter name
+ (eq. sign, eventual seqence no. and language info mark
+ included) */
+ size_t vlen; /* Length of lang'charset' part */
+ int langinfo; /* True if language info is available */
+ int quote = 0; /* 2 if the value should be quoted, 0 otherwise */
+ int segment = -1; /* Segment sequence number */
+ mu_stream_t valstr; /* Value stream (properly encoded) */
+ mu_off_t valsize; /* Number of octets left in valstr */
+ char const *filter_name = NULL; /* Name of the filter for the value */
+ int rc;
+
+ rc = mu_static_memory_stream_create (&valstr, p->value, strlen (p->value));
+ if (rc)
+ return rc;
+
+ nlen = strlen (name);
+ if (p->lang || p->cset)
+ {
+ vlen = 2;
+ if (p->lang)
+ vlen += strlen (p->lang);
+ if (p->cset)
+ vlen += strlen (p->cset);
+ langinfo = 1;
+ filter_name = "percent";
+ }
+ else
+ {
+ if (*mu_str_skip_class_comp (p->value, MU_CTYPE_TSPEC|MU_CTYPE_BLANK))
+ {
+ /* Must be in quoted-string, to use within parameter values */
+ quote = 2;
+ filter_name = "dq";
+ }
+ else
+ quote = 0;
+ vlen = 0;
+ langinfo = 0;
+ }
+
+ if (filter_name)
+ {
+ mu_stream_t tmp;
+
+ rc = mu_filter_create (&tmp, valstr, filter_name, MU_FILTER_ENCODE,
+ MU_STREAM_READ | MU_STREAM_SEEK);
+ if (rc)
+ goto err;
+ mu_stream_unref (valstr);
+ valstr = tmp;
+ rc = mu_memory_stream_create (&tmp, MU_STREAM_RDWR);
+ if (rc == 0)
+ {
+ rc = mu_stream_copy (tmp, valstr, 0, &valsize);
+ mu_stream_destroy (&tmp);
+ }
+ }
+ else
+ rc = mu_stream_size (valstr, &valsize);
+
+ if (rc)
+ goto err;
+
+ nlen += langinfo;
+
+ rc = mu_stream_seek (valstr, 0, MU_SEEK_SET, NULL);
+
+ if (hbuf->line_max == 0)
+ {
+ /* No line wrapping requested. Store the value as it is */
+ mu_stream_printf (hbuf->str, "%s", name);
+ if (langinfo)
+ mu_stream_write (hbuf->str, "*", 1, NULL);
+ mu_stream_write (hbuf->str, "=", 1, NULL);
+ if (vlen)
+ {
+ mu_stream_printf (hbuf->str, "%s'%s'",
+ p->lang ? p->lang : "",
+ p->cset ? p->cset : "");
+ vlen = 0;
+ }
+ else if (quote)
+ mu_stream_write (hbuf->str, "\"", 1, NULL);
+ mu_stream_copy (hbuf->str, valstr, 0, NULL);
+ if (quote)
+ mu_stream_write (hbuf->str, "\"", 1, NULL);
+ if (mu_stream_err (hbuf->str))
+ rc = mu_stream_last_error (hbuf->str);
+ }
+ else
+ {
+ /* Split the value into sequentially indexed segments, each one no
+ wider than the requested line width.
+
+ Without special precautions, an encoded character occurring at
+ the end of a segment can be split between this and the following
+ segment to satisfy line width requirements. To avoid this, the
+ following approach is used:
+
+ 1. The value stream is put to unbuffered mode.
+ 2. Before each write, the size of the transcoder output buffer
+ in valstr is set to the number of bytes left in the current
+ line.
+
+ This way the transcoder will write as many bytes as possible
+ without breaking the encoded constructs while the unbuffered mode
+ will ensure that it will not be called again to fill up the stream
+ buffer.
+
+ If the line width is insufficient, MU_ERR_BUFSPACE will be returned.
+ */
+ char *iobuf;
+
+ iobuf = malloc (hbuf->line_max + 1);
+ if (!iobuf)
+ {
+ rc = errno;
+ goto err;
+ }
+
+ mu_stream_set_buffer (valstr, mu_buffer_none, 0);
+
+ while (rc == 0 && valsize)
+ {
+ mu_off_t start, nr; /* Start and end positions in stream */
+ size_t sz, n;
+
+ mu_stream_write (hbuf->str, ";", 1, NULL);
+ mu_stream_seek (hbuf->str, 0, MU_SEEK_CUR, &start);
+
+ if (segment >= 0)
+ {
+ mu_stream_write (hbuf->str, "\n", 1, NULL);
+ hbuf->line_len = 0;
+ segment++;
+ }
+ else if (hbuf->line_len + valsize + quote + vlen + nlen + 1 >
+ hbuf->line_max)
+ {
+ mu_stream_write (hbuf->str, "\n", 1, NULL);
+ hbuf->line_len = 0;
+ if (hbuf->line_len + valsize + quote + vlen + nlen + 1 >
+ hbuf->line_max)
+ segment++;
+ }
+
+ mu_stream_write (hbuf->str, " ", 1, NULL);
+
+ if (segment >= 0)
+ mu_stream_printf (hbuf->str, "%s*%d", name, segment);
+ else
+ mu_stream_printf (hbuf->str, "%s", name);
+ if (langinfo)
+ mu_stream_write (hbuf->str, "*", 1, NULL);
+ mu_stream_write (hbuf->str, "=", 1, NULL);
+ mu_stream_seek (hbuf->str, 0, MU_SEEK_CUR, &nr);
+ nlen = nr - start;
+ hbuf->line_len += nlen;
+ start = nr;
+
+ /* Compute the number of octets to put into the current line.
+ If the requested line width is not enough to accomodate
+ the line, signal the error */
+ if (hbuf->line_max <= (hbuf->line_len + quote + vlen))
+ {
+ rc = MU_ERR_BUFSPACE;
+ break;
+ }
+
+ sz = hbuf->line_max - (hbuf->line_len + quote + vlen);
+ mu_stream_ioctl (valstr, MU_IOCTL_FILTER,
+ MU_IOCTL_FILTER_SET_OUTBUF_SIZE, &sz);
+
+ rc = mu_stream_read (valstr, iobuf, sz, &n);
+ if (rc || n == 0)
+ break;
+
+ if (vlen)
+ {
+ mu_stream_printf (hbuf->str, "%s'%s'",
+ p->lang ? p->lang : "",
+ p->cset ? p->cset : "");
+ vlen = 0;
+ }
+ else if (quote)
+ mu_stream_write (hbuf->str, "\"", 1, NULL);
+
+ mu_stream_write (hbuf->str, iobuf, n, NULL);
+
+ if (quote)
+ mu_stream_write (hbuf->str, "\"", 1, NULL);
+ mu_stream_seek (hbuf->str, 0, MU_SEEK_CUR, &nr);
+ nr -= start;
+ hbuf->line_len += nr;
+ valsize -= n;
+
+ if (mu_stream_err (hbuf->str))
+ rc = mu_stream_last_error (hbuf->str);
+ }
+ free (iobuf);
+ }
+ err:
+ mu_stream_destroy (&valstr);
+
+ return rc;
+}
+
+static int
+mime_header_format (const char *value, mu_assoc_t params,
+ struct header_buffer *hbuf)
+{
+ size_t l = strlen (value);
+
+ mu_stream_write (hbuf->str, value, l, NULL);
+ hbuf->line_len += l;
+ return mu_assoc_foreach (params, mime_store_parameter, hbuf);
+}
+
+/* Store a header in accordance with RFC 2231, Section 3,
+ "Parameter Value Continuations"
+
+ HDR - Message header object
+ NAME - Header name
+ VALUE - Header value part
+ PARAMS - Named parameters (assoc of struct mu_mime_param *)
+ LINE_WIDTH - Maximum line width.
+*/
+
+int
+mu_mime_header_set_w (mu_header_t hdr, const char *name,
+ const char *value, mu_assoc_t params, size_t line_width)
+{
+ struct header_buffer hbuf;
+ int rc;
+
+ rc = mu_memory_stream_create (&hbuf.str, MU_STREAM_RDWR);
+ if (rc)
+ return rc;
+ hbuf.line_len = strlen (name) + 2;
+ hbuf.line_max = line_width;
+ rc = mime_header_format (value, params, &hbuf);
+ if (rc == 0)
+ {
+ mu_off_t pos;
+ char *fmtval;
+
+ mu_stream_seek (hbuf.str, 0, MU_SEEK_CUR, &pos);
+ fmtval = malloc (pos + 1);
+ mu_stream_seek (hbuf.str, 0, MU_SEEK_SET, NULL);
+ mu_stream_read (hbuf.str, fmtval, pos, NULL);
+ fmtval[pos] = 0;
+ rc = mu_header_set_value (hdr, name, fmtval, 1);
+ free (fmtval);
+ }
+ mu_stream_destroy (&hbuf.str);
+ return rc;
+}
+
+int
+mu_mime_header_set (mu_header_t hdr, const char *name,
+ const char *value, mu_assoc_t params)
+{
+ return mu_mime_header_set_w (hdr, name, value, params, 76);
+}
+
+
+
diff --git a/libmailutils/stream/fltstream.c b/libmailutils/stream/fltstream.c
index 99b9241bf..3d2a6592d 100644
--- a/libmailutils/stream/fltstream.c
+++ b/libmailutils/stream/fltstream.c
@@ -27,63 +27,90 @@
#include <mailutils/stream.h>
#include <mailutils/sys/filter.h>
-#define MFB_BASE(buf) ((buf).base)
-#define MFB_CURPTR(buf) ((buf).base + (buf).pos)
-#define MFB_ENDPTR(buf) ((buf).base + (buf).level)
-
-#define MFB_SIZE(buf) ((buf).size)
-#define MFB_LEVEL(buf) ((buf).level)
-#define MFB_POS(buf) ((buf).pos)
-#define MFB_RDBYTES(buf) \
- (MFB_LEVEL (buf) - MFB_POS (buf))
-#define MFB_FREESIZE(buf) \
- (MFB_SIZE (buf) - MFB_LEVEL (buf))
-
-#define MBF_CLEAR(buf) ((buf).pos = (buf).level = 0)
-#define MBF_FREE(buf) free ((buf).base)
-
-static void
-init_iobuf (struct mu_filter_io *io, struct _mu_filter_stream *fs)
+static inline char *
+MFB_base_ptr (struct _mu_filter_buffer *buf)
{
- io->input = MFB_CURPTR (fs->inbuf);
- io->isize = MFB_RDBYTES (fs->inbuf);
- io->output = MFB_ENDPTR (fs->outbuf);
- io->osize = MFB_FREESIZE (fs->outbuf);
- io->errcode = MU_ERR_FAILURE;
- io->eof = 0;
+ return buf->base;
}
-static int
-filter_stream_init (struct _mu_filter_stream *fs)
+static inline char *
+MFB_cur_ptr (struct _mu_filter_buffer *buf)
{
- if (fs->xdata)
+ return buf->base + buf->pos;
+}
+
+static inline char *
+MFB_end_ptr (struct _mu_filter_buffer *buf)
+{
+ return buf->base + buf->level;
+}
+
+static inline size_t
+MFB_size (struct _mu_filter_buffer *buf)
+{
+ return buf->size;
+}
+
+static inline size_t
+MFB_level (struct _mu_filter_buffer *buf)
+{
+ return buf->level;
+}
+
+static inline size_t
+MFB_pos (struct _mu_filter_buffer *buf)
+{
+ return buf->pos;
+}
+
+static inline size_t
+MFB_rdbytes (struct _mu_filter_buffer *buf)
+{
+ return MFB_level (buf) - MFB_pos (buf);
+}
+
+static inline size_t
+MFB_freesize (struct _mu_filter_buffer *buf)
+{
+ return MFB_size (buf) - MFB_level (buf);
+}
+
+static inline void
+MFB_clear (struct _mu_filter_buffer *buf)
+{
+ buf->pos = buf->level = 0;
+}
+
+static inline void
+MFB_deallocate (struct _mu_filter_buffer *buf)
+{
+ free (buf->base);
+}
+
+/* Compact the buffer */
+static inline void
+MFB_compact (struct _mu_filter_buffer *buf)
+{
+ if (MFB_pos (buf))
{
- struct mu_filter_io iobuf;
- memset (&iobuf, 0, sizeof (iobuf));
- iobuf.errcode = MU_ERR_FAILURE;
- if (fs->xcode (fs->xdata, mu_filter_init, &iobuf) == mu_filter_failure)
- return iobuf.errcode;
+ memmove (MFB_base_ptr (buf), MFB_cur_ptr (buf), MFB_rdbytes (buf));
+ buf->level -= buf->pos;
+ buf->pos = 0;
}
- return 0;
}
static int
MFB_require (struct _mu_filter_buffer *buf, size_t size)
{
- if (size > MFB_FREESIZE (*buf))
+ if (size > MFB_freesize (buf))
{
- /* Compact the buffer */
- if (MFB_POS (*buf))
- {
- memmove (MFB_BASE (*buf), MFB_CURPTR (*buf), MFB_RDBYTES (*buf));
- buf->level -= buf->pos;
- buf->pos = 0;
- }
- if (size > MFB_FREESIZE (*buf))
+ MFB_compact (buf);
+
+ if (size > MFB_freesize (buf))
{
char *p;
- size += MFB_LEVEL (*buf);
+ size += MFB_level (buf);
p = realloc (buf->base, size);
if (!p)
return ENOMEM;
@@ -94,7 +121,7 @@ MFB_require (struct _mu_filter_buffer *buf, size_t size)
return 0;
}
-static void
+static inline void
MFB_advance_pos (struct _mu_filter_buffer *buf, size_t delta)
{
buf->pos += delta;
@@ -102,11 +129,45 @@ MFB_advance_pos (struct _mu_filter_buffer *buf, size_t delta)
buf->pos = buf->level = 0;
}
-static void
+static inline void
MFB_advance_level (struct _mu_filter_buffer *buf, size_t delta)
{
buf->level += delta;
}
+
+static void
+init_iobuf (struct mu_filter_io *io, struct _mu_filter_stream *fs)
+{
+ io->input = MFB_cur_ptr (&fs->inbuf);
+ io->isize = MFB_rdbytes (&fs->inbuf);
+
+ if (fs->outbuf_size)
+ {
+ if (MFB_freesize (&fs->outbuf) < fs->outbuf_size)
+ MFB_require (&fs->outbuf, fs->outbuf_size);
+ io->osize = fs->outbuf_size;
+ }
+ else
+ io->osize = MFB_freesize (&fs->outbuf);
+ io->output = MFB_end_ptr (&fs->outbuf);
+
+ io->errcode = MU_ERR_FAILURE;
+ io->eof = 0;
+}
+
+static int
+filter_stream_init (struct _mu_filter_stream *fs)
+{
+ if (fs->xdata)
+ {
+ struct mu_filter_io iobuf;
+ memset (&iobuf, 0, sizeof (iobuf));
+ iobuf.errcode = MU_ERR_FAILURE;
+ if (fs->xcode (fs->xdata, mu_filter_init, &iobuf) == mu_filter_failure)
+ return iobuf.errcode;
+ }
+ return 0;
+}
static int
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)
int stop = 0;
int again = 0;
- if (fs->fltflag & _MU_FILTER_DISABLED)
+ if (fs->flag_disabled)
return mu_stream_read (fs->transport, buf, size, pret);
do
{
size_t rdsize;
- if (MFB_RDBYTES (fs->outbuf) == 0)
+ if (MFB_rdbytes (&fs->outbuf) == 0)
{
enum mu_filter_result res;
int rc;
- if (fs->fltflag & _MU_FILTER_EOF)
+ if (fs->flag_eof)
break;
- if (MFB_RDBYTES (fs->inbuf) < min_input_level && !again)
+ if (MFB_rdbytes (&fs->inbuf) < min_input_level && !again)
{
rc = MFB_require (&fs->inbuf, min_input_level);
if (rc)
return rc;
rc = mu_stream_read (fs->transport,
- MFB_ENDPTR (fs->inbuf),
- MFB_FREESIZE (fs->inbuf),
+ MFB_end_ptr (&fs->inbuf),
+ MFB_freesize (&fs->inbuf),
&rdsize);
if (rc)
return rc;
if (rdsize == 0 &&
- MFB_RDBYTES (fs->outbuf) == 0 &&
- MFB_RDBYTES (fs->inbuf) == 0)
+ MFB_rdbytes (&fs->outbuf) == 0 &&
+ MFB_rdbytes (&fs->inbuf) == 0)
break;
MFB_advance_level (&fs->inbuf, rdsize);
}
- if (min_output_size < MFB_RDBYTES (fs->inbuf))
- min_output_size = MFB_RDBYTES (fs->inbuf);
+ if (min_output_size < MFB_rdbytes (&fs->inbuf))
+ min_output_size = MFB_rdbytes (&fs->inbuf);
rc = MFB_require (&fs->outbuf, min_output_size);
if (rc)
return rc;
@@ -195,8 +256,8 @@ filter_read (mu_stream_t stream, char *buf, size_t size, size_t *pret)
continue;
}
- if (iobuf.isize > MFB_RDBYTES (fs->inbuf)
- || iobuf.osize > MFB_FREESIZE (fs->outbuf))
+ if (iobuf.isize > MFB_rdbytes (&fs->inbuf)
+ || iobuf.osize > MFB_freesize (&fs->outbuf))
return MU_ERR_BUFSPACE;
/* 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)
{
if (iobuf.eof)
{
- fs->fltflag |= _MU_FILTER_EOF;
+ fs->flag_eof = 1;
+ stop = 1;
+ }
+ else if (fs->outbuf_size)
+ {
+ if (iobuf.osize == 0)
+ return MU_ERR_BUFSPACE;
stop = 1;
}
else if (cmd == mu_filter_lastbuf)
{
- if (MFB_RDBYTES (fs->inbuf))
+ if (MFB_rdbytes (&fs->inbuf))
{
/* If xcoder has not consumed all input, try again */
if (++again > MU_FILTER_MAX_AGAIN)
@@ -227,7 +294,7 @@ filter_read (mu_stream_t stream, char *buf, size_t size, size_t *pret)
}
else
{
- fs->fltflag |= _MU_FILTER_EOF;
+ fs->flag_eof = 1;
stop = 1;
}
}
@@ -237,9 +304,9 @@ filter_read (mu_stream_t stream, char *buf, size_t size, size_t *pret)
}
rdsize = size - total;
- if (rdsize > MFB_RDBYTES (fs->outbuf))
- rdsize = MFB_RDBYTES (fs->outbuf);
- memcpy (buf + total, MFB_CURPTR (fs->outbuf), rdsize);
+ if (rdsize > MFB_rdbytes (&fs->outbuf))
+ rdsize = MFB_rdbytes (&fs->outbuf);
+ memcpy (buf + total, MFB_cur_ptr (&fs->outbuf), rdsize);
MFB_advance_pos (&fs->outbuf, rdsize);
total += rdsize;
@@ -275,7 +342,7 @@ filter_write_internal (mu_stream_t stream, enum mu_filter_command cmd,
size_t rdsize;
enum mu_filter_result res;
- if (MFB_RDBYTES (fs->inbuf) < min_input_level)
+ if (MFB_rdbytes (&fs->inbuf) < min_input_level)
{
rdsize = size - total;
if (rdsize == 0)
@@ -283,15 +350,15 @@ filter_write_internal (mu_stream_t stream, enum mu_filter_command cmd,
rc = MFB_require (&fs->inbuf, min_input_level);
if (rc)
break;
- if (rdsize > MFB_FREESIZE (fs->inbuf))
- rdsize = MFB_FREESIZE (fs->inbuf);
- memcpy (MFB_ENDPTR (fs->inbuf), buf + total, rdsize);
+ if (rdsize > MFB_freesize (&fs->inbuf))
+ rdsize = MFB_freesize (&fs->inbuf);
+ memcpy (MFB_end_ptr (&fs->inbuf), buf + total, rdsize);
MFB_advance_level (&fs->inbuf, rdsize);
total += rdsize;
}
- if (min_output_size < MFB_RDBYTES (fs->inbuf))
- min_output_size = MFB_RDBYTES (fs->inbuf);
+ if (min_output_size < MFB_rdbytes (&fs->inbuf))
+ min_output_size = MFB_rdbytes (&fs->inbuf);
rc = MFB_require (&fs->outbuf, min_output_size);
if (rc)
return rc;
@@ -332,8 +399,8 @@ filter_write_internal (mu_stream_t stream, enum mu_filter_command cmd,
continue;
}
- if (iobuf.isize > MFB_RDBYTES (fs->inbuf)
- || iobuf.osize > MFB_FREESIZE (fs->outbuf))
+ if (iobuf.isize > MFB_rdbytes (&fs->inbuf)
+ || iobuf.osize > MFB_freesize (&fs->outbuf))
return MU_ERR_BUFSPACE;
/* 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,
MFB_advance_pos (&fs->inbuf, iobuf.isize);
rc = mu_stream_write (fs->transport,
- MFB_CURPTR (fs->outbuf),
- MFB_RDBYTES (fs->outbuf),
+ MFB_cur_ptr (&fs->outbuf),
+ MFB_rdbytes (&fs->outbuf),
&rdsize);
if (rc == 0)
MFB_advance_pos (&fs->outbuf, rdsize);
else
break;
}
- while (!stop && (MFB_RDBYTES (fs->outbuf) || again));
+ while (!stop && (MFB_rdbytes (&fs->outbuf) || again));
if (pret)
*pret = total;
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)
{
struct _mu_filter_stream *fs = (struct _mu_filter_stream *)stream;
- if (fs->fltflag & _MU_FILTER_DISABLED)
+ if (fs->flag_disabled)
return mu_stream_write (fs->transport, buf, size, pret);
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)
if (status)
return status;
if (ptr && *(int*)ptr)
- fs->fltflag |= _MU_FILTER_DISABLED;
+ fs->flag_disabled = 1;
else
- fs->fltflag &= ~_MU_FILTER_DISABLED;
+ fs->flag_disabled = 0;
break;
case MU_IOCTL_FILTER_GET_DISABLED:
if (!ptr)
return EINVAL;
- *(int*)ptr = fs->fltflag & _MU_FILTER_DISABLED;
+ *(int*)ptr = fs->flag_disabled;
break;
+ case MU_IOCTL_FILTER_SET_OUTBUF_SIZE:
+ if (!ptr)
+ return EINVAL;
+ fs->outbuf_size = *(size_t*)ptr;
+ break;
+
default:
return ENOSYS;
}
@@ -506,8 +579,8 @@ static void
filter_done (mu_stream_t stream)
{
struct _mu_filter_stream *fs = (struct _mu_filter_stream *)stream;
- MBF_FREE (fs->inbuf);
- MBF_FREE (fs->outbuf);
+ MFB_deallocate (&fs->inbuf);
+ MFB_deallocate (&fs->outbuf);
if (fs->xdata)
{
fs->xcode (fs->xdata, mu_filter_done, NULL);
@@ -520,7 +593,7 @@ static int
filter_wr_close (mu_stream_t stream)
{
struct _mu_filter_stream *fs = (struct _mu_filter_stream *)stream;
- if (!mu_stream_eof (stream) && !(fs->fltflag & _MU_FILTER_EOF))
+ if (!mu_stream_eof (stream) && !fs->flag_eof)
{
size_t dummy;
int rc = filter_write_internal (stream, mu_filter_lastbuf, NULL, 0,
@@ -528,8 +601,8 @@ filter_wr_close (mu_stream_t stream)
if (rc)
return rc;
}
- MBF_CLEAR (fs->inbuf);
- MBF_CLEAR (fs->outbuf);
+ MFB_clear (&fs->inbuf);
+ MFB_clear (&fs->outbuf);
return mu_stream_close (fs->transport);
}
@@ -537,8 +610,8 @@ static int
filter_rd_close (mu_stream_t stream)
{
struct _mu_filter_stream *fs = (struct _mu_filter_stream *)stream;
- MBF_CLEAR (fs->inbuf);
- MBF_CLEAR (fs->outbuf);
+ MFB_clear (&fs->inbuf);
+ MFB_clear (&fs->outbuf);
return mu_stream_close (fs->transport);
}
@@ -633,7 +706,6 @@ mu_filter_stream_create (mu_stream_t *pflt,
fs->xcode = xcode;
fs->xdata = xdata;
fs->mode = mode;
- fs->fltflag = 0;
mu_stream_set_buffer ((mu_stream_t) fs, mu_buffer_full,
MU_FILTER_BUF_SIZE);
diff --git a/libmailutils/string/muctype.c b/libmailutils/string/muctype.c
index 1cc76443a..ffa050d6e 100644
--- a/libmailutils/string/muctype.c
+++ b/libmailutils/string/muctype.c
@@ -55,20 +55,20 @@ int mu_c_tab[MU_C_TAB_MAX] = {
MU_CTYPE_CNTRL,
MU_CTYPE_PRINT|MU_CTYPE_SPACE|MU_CTYPE_BLANK,
MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT,
+ MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT|MU_CTYPE_TSPEC,
MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT,
MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT,
MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT,
MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT,
MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT,
+ MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT|MU_CTYPE_TSPEC,
+ MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT|MU_CTYPE_TSPEC,
MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT,
MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT,
+ MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT|MU_CTYPE_TSPEC,
MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT,
MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT,
- MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT,
- MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT,
- MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT,
- MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT,
- MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT,
+ MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT|MU_CTYPE_TSPEC,
MU_CTYPE_DIGIT|MU_CTYPE_GRAPH|MU_CTYPE_PRINT,
MU_CTYPE_DIGIT|MU_CTYPE_GRAPH|MU_CTYPE_PRINT,
MU_CTYPE_DIGIT|MU_CTYPE_GRAPH|MU_CTYPE_PRINT,
@@ -79,13 +79,13 @@ int mu_c_tab[MU_C_TAB_MAX] = {
MU_CTYPE_DIGIT|MU_CTYPE_GRAPH|MU_CTYPE_PRINT,
MU_CTYPE_DIGIT|MU_CTYPE_GRAPH|MU_CTYPE_PRINT,
MU_CTYPE_DIGIT|MU_CTYPE_GRAPH|MU_CTYPE_PRINT,
- MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT,
- MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT,
- MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT,
- MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT,
- MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT,
- MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT,
- MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT,
+ MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT|MU_CTYPE_TSPEC,
+ MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT|MU_CTYPE_TSPEC,
+ MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT|MU_CTYPE_TSPEC,
+ MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT|MU_CTYPE_TSPEC,
+ MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT|MU_CTYPE_TSPEC,
+ MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT|MU_CTYPE_TSPEC,
+ MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT|MU_CTYPE_TSPEC,
MU_CTYPE_ALPHA|MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_UPPER|MU_CTYPE_XLETR,
MU_CTYPE_ALPHA|MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_UPPER|MU_CTYPE_XLETR,
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] = {
MU_CTYPE_ALPHA|MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_UPPER,
MU_CTYPE_ALPHA|MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_UPPER,
MU_CTYPE_ALPHA|MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_UPPER,
- MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT,
- MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT,
- MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT,
+ MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT|MU_CTYPE_TSPEC,
+ MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT|MU_CTYPE_TSPEC,
+ MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT|MU_CTYPE_TSPEC,
MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT,
MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT,
MU_CTYPE_GRAPH|MU_CTYPE_PRINT|MU_CTYPE_PUNCT,
diff --git a/libmailutils/tests/mimehdr.at b/libmailutils/tests/mimehdr.at
index a39a81059..88d5534f9 100644
--- a/libmailutils/tests/mimehdr.at
+++ b/libmailutils/tests/mimehdr.at
@@ -119,13 +119,128 @@ filename(lang:el_GR/UTF-8)=αρχείο για την δοκιμασία
MIMEHDR([combined charset, lang and cset],[mimehdr08 mimehdr-comb mimehdr-charset-rfc2231],
[],
-[application/x-stuff
- title*0*=us-ascii'en'This%20is%20even%20more%20
- title*1*=%2A%2A%2Afun%2A%2A%2A%20
+[application/x-stuff;
+ title*0*=us-ascii'en'This%20is%20even%20more%20;
+ title*1*=%2A%2A%2Afun%2A%2A%2A%20;
title*2="isn't it!"
],
[application/x-stuff
title(lang:en/us-ascii)=This is even more ***fun*** isn't it!
])
+MIMEHDR([format: simple],[mimehdr09],
+[-header=X-MIME-Test-Header -width=26],
+[application/x-stuff; charset=ascii; title=foobar],
+[X-MIME-Test-Header: application/x-stuff;
+ charset=ascii;
+ title=foobar
+
+])
+
+MIMEHDR([format: split],[mimehdr10],
+[-header=X-MIME-Test-Header -width=76],
+[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"],
+[X-MIME-Test-Header: attachment;
+ title*0="unusually long filename created by gray expressly for testing pu";
+ title*1="rposes and not meant for any other purpose but testing the forma";
+ title*2="tting of very long MIME headers"
+
+])
+
+MIMEHDR([format: split 2],[mimehdr11],
+[-header=X-MIME-Test-Header -width=26],
+[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"],
+[X-MIME-Test-Header: attachment;
+ title*0="unusually long";
+ title*1=" filename crea";
+ title*2="ted by gray ex";
+ title*3="pressly for te";
+ title*4="sting purposes";
+ title*5=" and not meant";
+ title*6=" for any other";
+ title*7=" purpose but t";
+ title*8="esting the for";
+ title*9="matting of ver";
+ title*10="y long MIME h";
+ title*11="eaders"
+
+])
+
+# This test is split into 5 subtests to make sure encoded character
+# representation is not split between subsequent numbered parameters.
+MIMEHDR([format: language info 1],[mimehdr12 mimehdr12a],
+[-header=X-MIME-Test-Header -width=27],
+[application/x-stuff;
+ title*0*=us-ascii'en'This%20is%20even%20more%20;
+ title*1*=%2A%2A%2Afun%2A%2A%2A%20;
+ title*2="isn't it!"
+],
+[X-MIME-Test-Header: application/x-stuff;
+ title*0*=en'us-ascii'This;
+ title*1*=%20is%20even%20m;
+ title*2*=ore%20***fun***;
+ title*3*=%20isn't%20it!
+
+])
+
+MIMEHDR([format: language info 2],[mimehdr12 mimehdr12b],
+[-header=X-MIME-Test-Header -width=28],
+[application/x-stuff;
+ title*0*=us-ascii'en'This%20is%20even%20more%20;
+ title*1*=%2A%2A%2Afun%2A%2A%2A%20;
+ title*2="isn't it!"
+],
+[X-MIME-Test-Header: application/x-stuff;
+ title*0*=en'us-ascii'This;
+ title*1*=%20is%20even%20mo;
+ title*2*=re%20***fun***;
+ title*3*=%20isn't%20it!
+
+])
+
+MIMEHDR([format: language info 3],[mimehdr12 mimehdr12c],
+[-header=X-MIME-Test-Header -width=29],
+[application/x-stuff;
+ title*0*=us-ascii'en'This%20is%20even%20more%20;
+ title*1*=%2A%2A%2Afun%2A%2A%2A%20;
+ title*2="isn't it!"
+],
+[X-MIME-Test-Header: application/x-stuff;
+ title*0*=en'us-ascii'This;
+ title*1*=%20is%20even%20mor;
+ title*2*=e%20***fun***%20is;
+ title*3*=n't%20it!
+
+])
+
+MIMEHDR([format: language info 4],[mimehdr12 mimehdr12d],
+[-header=X-MIME-Test-Header -width=30],
+[application/x-stuff;
+ title*0*=us-ascii'en'This%20is%20even%20more%20;
+ title*1*=%2A%2A%2Afun%2A%2A%2A%20;
+ title*2="isn't it!"
+],
+[X-MIME-Test-Header: application/x-stuff;
+ title*0*=en'us-ascii'This;
+ title*1*=%20is%20even%20more;
+ title*2*=%20***fun***%20isn';
+ title*3*=t%20it!
+
+])
+
+MIMEHDR([format: language info 5],[mimehdr12 mimehdr12e],
+[-header=X-MIME-Test-Header -width=31],
+[application/x-stuff;
+ title*0*=us-ascii'en'This%20is%20even%20more%20;
+ title*1*=%2A%2A%2Afun%2A%2A%2A%20;
+ title*2="isn't it!"
+],
+[X-MIME-Test-Header: application/x-stuff;
+ title*0*=en'us-ascii'This%20i;
+ title*1*=s%20even%20more%20**;
+ title*2*=*fun***%20isn't%20it;
+ title*3*=!
+
+])
+
m4_popdef([MIMEHDR])
diff --git a/libmailutils/tests/mimehdr.c b/libmailutils/tests/mimehdr.c
index a2ad75998..ac2d9493d 100644
--- a/libmailutils/tests/mimehdr.c
+++ b/libmailutils/tests/mimehdr.c
@@ -61,6 +61,8 @@ main (int argc, char **argv)
char *value;
mu_assoc_t assoc;
char *charset = NULL;
+ char *header_name = NULL;
+ unsigned long width = 76;
mu_set_program_name (argv[0]);
for (i = 1; i < argc; i++)
@@ -73,9 +75,13 @@ main (int argc, char **argv)
charset = opt + 9;
else if (strcmp (opt, "-h") == 0 || strcmp (opt, "-help") == 0)
{
- mu_printf ("usage: %s [-charset=cs] [-debug=SPEC]", mu_program_name);
+ mu_printf ("usage: %s [-charset=cs] [-debug=SPEC] [-header=NAME] [-width=N]", mu_program_name);
return 0;
}
+ else if (strncmp (opt, "-header=", 8) == 0)
+ header_name = opt + 8;
+ else if (strncmp (opt, "-width=", 7) == 0)
+ width = strtoul (opt + 7, NULL, 10);
else
{
mu_error ("unknown option %s", opt);
@@ -97,9 +103,22 @@ main (int argc, char **argv)
MU_ASSERT (mu_mime_header_parse ((char*)trans[0], charset, &value, &assoc));
- mu_printf ("%s\n", value);
- mu_assoc_sort_r (assoc, sort_names, NULL);
- mu_assoc_foreach (assoc, print_param, NULL);
+ if (header_name)
+ {
+ mu_header_t hdr;
+ mu_stream_t hstr;
+
+ MU_ASSERT (mu_header_create (&hdr, NULL, 0));
+ MU_ASSERT (mu_mime_header_set_w (hdr, header_name, value, assoc, width));
+ MU_ASSERT (mu_header_get_streamref (hdr, &hstr));
+ MU_ASSERT (mu_stream_copy (mu_strout, hstr, 0, NULL));
+ }
+ else
+ {
+ mu_printf ("%s\n", value);
+ mu_assoc_sort_r (assoc, sort_names, NULL);
+ mu_assoc_foreach (assoc, print_param, NULL);
+ }
return 0;
}
diff --git a/mail/send.c b/mail/send.c
index 7075794da..cec3990c9 100644
--- a/mail/send.c
+++ b/mail/send.c
@@ -464,8 +464,8 @@ saveatt (void *item, void *data)
char *p;
rc = mu_attachment_create (&part, aptr->content_type, aptr->encoding,
- env->alt ? NULL : aptr->name,
- env->alt ? NULL : aptr->filename);
+ aptr->name,
+ aptr->filename);
if (rc)
{
mu_error (_("can't create attachment %s: %s"),

Return to:

Send suggestions and report system problems to the System administrator.