diff options
-rw-r--r-- | include/mailutils/filter.h | 3 | ||||
-rw-r--r-- | libmailutils/Makefile.am | 1 | ||||
-rw-r--r-- | libmailutils/filter.c | 1 | ||||
-rw-r--r-- | libmailutils/fromflt.c | 283 | ||||
-rw-r--r-- | libmailutils/tests/Makefile.am | 1 | ||||
-rw-r--r-- | libmailutils/tests/base64d.at | 4 | ||||
-rw-r--r-- | libmailutils/tests/base64e.at | 4 | ||||
-rw-r--r-- | libmailutils/tests/fltst.c | 2 | ||||
-rw-r--r-- | libmailutils/tests/fromflt.at | 96 | ||||
-rw-r--r-- | libmailutils/tests/testsuite.at | 1 | ||||
-rw-r--r-- | libproto/mbox/mbox.c | 17 |
11 files changed, 403 insertions, 10 deletions
diff --git a/include/mailutils/filter.h b/include/mailutils/filter.h index 120318d57..d9c53ca7f 100644 --- a/include/mailutils/filter.h +++ b/include/mailutils/filter.h @@ -100,13 +100,14 @@ extern mu_filter_record_t mu_qp_filter; /* quoted-printable. */ extern mu_filter_record_t mu_base64_filter; extern mu_filter_record_t mu_binary_filter; extern mu_filter_record_t mu_bit8_filter; extern mu_filter_record_t mu_bit7_filter; extern mu_filter_record_t mu_rfc_2047_Q_filter; extern mu_filter_record_t mu_rfc_2047_B_filter; - +extern mu_filter_record_t mu_from_filter; + enum mu_iconv_fallback_mode { mu_fallback_none, mu_fallback_copy_pass, mu_fallback_copy_octal }; diff --git a/libmailutils/Makefile.am b/libmailutils/Makefile.am index 3f083e01d..07a0a4e54 100644 --- a/libmailutils/Makefile.am +++ b/libmailutils/Makefile.am @@ -80,12 +80,13 @@ libmailutils_la_SOURCES = \ file_stream.c\ filter.c\ filter_iconv.c\ fltstream.c\ folder.c\ freeitem.c\ + fromflt.c\ gdebug.c\ getpass.c\ gocs.c\ hdritr.c\ header.c\ iostream.c\ diff --git a/libmailutils/filter.c b/libmailutils/filter.c index 8fdc25f90..0008ba0f1 100644 --- a/libmailutils/filter.c +++ b/libmailutils/filter.c @@ -75,12 +75,13 @@ mu_filter_get_list (mu_list_t *plist) mu_list_append (filter_list, mu_rfc822_filter); mu_list_append (filter_list, mu_crlf_filter); mu_list_append (filter_list, mu_crlfdot_filter); mu_list_append (filter_list, mu_dot_filter); mu_list_append (filter_list, mu_rfc_2047_Q_filter); mu_list_append (filter_list, mu_rfc_2047_B_filter); + mu_list_append (filter_list, mu_from_filter); /* FIXME: add the default encodings? */ } *plist = filter_list; mu_monitor_unlock (&filter_monitor); return 0; } diff --git a/libmailutils/fromflt.c b/libmailutils/fromflt.c new file mode 100644 index 000000000..d96d46d85 --- /dev/null +++ b/libmailutils/fromflt.c @@ -0,0 +1,283 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2003, 2007, 2010 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, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301 USA */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdlib.h> +#include <string.h> +#include <mailutils/errno.h> +#include <mailutils/filter.h> +#include <mailutils/stream.h> + +enum from_decode_state + { + from_decode_init, + from_decode_nl, + from_decode_char + }; + +#define GT_FROM_MARK_STR ">From " +#define GT_FROM_MARK_LEN (sizeof (GT_FROM_MARK_STR) - 1) + +/* Move min(isize,osize) bytes from iptr to optr, replacing each '>From ' + at the beginning of line with 'From '. */ +static enum mu_filter_result +_from_decoder (void *xd, + enum mu_filter_command cmd, + struct mu_filter_io *iobuf) +{ + int *pstate = xd; + const unsigned char *iptr; + size_t isize; + char *optr; + size_t osize; + enum from_decode_state state; + size_t i, j; + + switch (cmd) + { + case mu_filter_init: + *pstate = from_decode_init; + return mu_filter_ok; + + case mu_filter_done: + return mu_filter_ok; + + default: + state = *pstate; + 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 == '\n') + state = from_decode_nl; + else if (state == from_decode_init || state == from_decode_nl) + { + size_t len = isize - i; + + if (len < GT_FROM_MARK_LEN) + { + if (memcmp (iptr - 1, GT_FROM_MARK_STR, len) == 0) + { + if (i == 0) + { + iobuf->isize = GT_FROM_MARK_LEN - len; + return mu_filter_moreinput; + } + break; + } + else + state = from_decode_char; + } + else if (memcmp (iptr - 1, GT_FROM_MARK_STR, GT_FROM_MARK_LEN) == 0) + { + /* Skip > */ + state = from_decode_char; + continue; + } + } + optr[j++] = c; + } + + *pstate = state; + iobuf->isize = i; + iobuf->osize = j; + return mu_filter_ok; +} + +#define FROM_MARK_STR "From " +#define FROM_MARK_LEN (sizeof (FROM_MARK_STR) - 1) + +enum from_encode_state + { + from_encode_init, + from_encode_nl, + from_encode_char, + from_encode_gt, + from_encode_f, + from_encode_r, + from_encode_o, + from_encode_m, + from_encode_sp + }; + +static int length_to_state_tab[] = { + from_encode_gt, + from_encode_f, + from_encode_r, + from_encode_o, + from_encode_m, + from_encode_sp +}; + +static int state_to_length_tab[] = { + 0, 0, 0, + GT_FROM_MARK_LEN, + GT_FROM_MARK_LEN-1, + GT_FROM_MARK_LEN-2, + GT_FROM_MARK_LEN-3, + GT_FROM_MARK_LEN-4, + GT_FROM_MARK_LEN-5 +}; + +/* Move min(isize,osize) bytes from iptr to optr, replacing each 'From ' + at the beginning of line with '>From '. */ + +static enum mu_filter_result +_from_encoder (void *xd, + enum mu_filter_command cmd, + struct mu_filter_io *iobuf) +{ + int *pstate = xd; + const unsigned char *iptr; + size_t isize; + char *optr; + size_t osize; + enum from_encode_state state; + size_t i, j; + + switch (cmd) + { + case mu_filter_init: + *pstate = from_encode_init; + return mu_filter_ok; + + case mu_filter_done: + return mu_filter_ok; + + default: + state = *pstate; + switch (state) + { + case from_encode_init: + case from_encode_nl: + case from_encode_char: + break; + + default: + osize = state_to_length_tab[state]; + if (iobuf->osize < osize) + { + iobuf->osize = osize; + return mu_filter_moreoutput; + } + memcpy (iobuf->output, GT_FROM_MARK_STR + GT_FROM_MARK_LEN - osize, + osize); + iobuf->osize = osize; + iobuf->isize = osize; + *pstate = from_encode_init; + return mu_filter_ok; + } + 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 == '\n') + state = from_encode_nl; + else if (state == from_encode_init || state == from_encode_nl) + { + size_t len = isize - i; + + if (len < FROM_MARK_LEN) + { + if (memcmp (iptr - 1, FROM_MARK_STR, len) == 0) + { + if (i == 0) + { + iobuf->isize = FROM_MARK_LEN; + return mu_filter_moreinput; + } + break; + } + else + state = from_encode_char; + } + else if (memcmp (iptr - 1, FROM_MARK_STR, FROM_MARK_LEN) == 0) + { + size_t rest = osize - j; + + if (rest > GT_FROM_MARK_LEN) + rest = GT_FROM_MARK_LEN; + else if (rest < 2) + { + if (i == 0) + { + iobuf->osize = GT_FROM_MARK_LEN; + return mu_filter_moreoutput; + } + break; + } + + memcpy (optr + j, GT_FROM_MARK_STR, rest); + i += rest - 2; + iptr += rest - 2; + j += rest; + if (rest < GT_FROM_MARK_LEN) + state = length_to_state_tab[rest]; + else + state = from_encode_char; + continue; + } + else + state = from_encode_char; + } + optr[j++] = c; + } + *pstate = state; + iobuf->isize = i; + iobuf->osize = j; + return mu_filter_ok; +} + +static int +_from_alloc_state (void **pret, int mode, void *data MU_ARG_UNUSED) +{ + *pret = malloc (sizeof (int)); + if (!*pret) + return ENOMEM; + return 0; +} + +static struct _mu_filter_record _from_filter = { + "FROM", + 0, + _from_alloc_state, + _from_encoder, + _from_decoder +}; + +mu_filter_record_t mu_from_filter = &_from_filter; + diff --git a/libmailutils/tests/Makefile.am b/libmailutils/tests/Makefile.am index 7324e88e4..a8215fb5f 100644 --- a/libmailutils/tests/Makefile.am +++ b/libmailutils/tests/Makefile.am @@ -61,12 +61,13 @@ TESTSUITE_AT = \ address.at\ argcv.at\ base64d.at\ base64e.at\ decode2047.at\ encode2047.at\ + fromflt.at\ list.at\ mailcap.at\ testsuite.at\ url.at TESTSUITE = $(srcdir)/testsuite diff --git a/libmailutils/tests/base64d.at b/libmailutils/tests/base64d.at index b26c41591..df1efd31d 100644 --- a/libmailutils/tests/base64d.at +++ b/libmailutils/tests/base64d.at @@ -13,25 +13,25 @@ # # You should have received a copy of the GNU General Public License # along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. # This file is part of Mailfromd testsuite. AT_SETUP([base64 decoding (read)]) -AT_KEYWORDS([base64 base64d base64dr decode]) +AT_KEYWORDS([base64 base64d base64dr decode filter]) AT_CHECK([ cp $abs_top_srcdir/libmailutils/tests/Encode expout fltst base64 decode read linelen=0 < $abs_top_srcdir/libmailutils/tests/Decode], [0], [expout]) AT_CLEANUP AT_SETUP([base64 decoding (write)]) -AT_KEYWORDS([base64 base64d base64dw decode]) +AT_KEYWORDS([base64 base64d base64dw decode filter]) AT_CHECK([ cp $abs_top_srcdir/libmailutils/tests/Encode expout fltst base64 decode write linelen=0 < $abs_top_srcdir/libmailutils/tests/Decode], [0], [expout]) diff --git a/libmailutils/tests/base64e.at b/libmailutils/tests/base64e.at index c753471a1..b94522e41 100644 --- a/libmailutils/tests/base64e.at +++ b/libmailutils/tests/base64e.at @@ -13,25 +13,25 @@ # # You should have received a copy of the GNU General Public License # along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. # This file is part of Mailfromd testsuite. AT_SETUP([base64 encoding (read)]) -AT_KEYWORDS([base64 base64e base64er encode]) +AT_KEYWORDS([base64 base64e base64er encode filter]) AT_CHECK([ cp $abs_top_srcdir/libmailutils/tests/Decode expout fltst base64 encode read nl < $abs_top_srcdir/libmailutils/tests/Encode], [0], [expout]) AT_CLEANUP AT_SETUP([base64 encoding (write)]) -AT_KEYWORDS([base64 base64e base64ew encode]) +AT_KEYWORDS([base64 base64e base64ew encode filter]) AT_CHECK([ cp $abs_top_srcdir/libmailutils/tests/Decode expout fltst base64 encode write nl < $abs_top_srcdir/libmailutils/tests/Encode], [0], [expout]) diff --git a/libmailutils/tests/fltst.c b/libmailutils/tests/fltst.c index 8597dd5a0..d62a02b2e 100644 --- a/libmailutils/tests/fltst.c +++ b/libmailutils/tests/fltst.c @@ -111,13 +111,13 @@ main (int argc, char * argv []) size_t line_length; int line_length_option = 0; int newline_option = 0; if (argc == 1) usage (NULL); - if (argc < 3) + if (argc < 4) usage ("not enough arguments"); fltname = argv[1]; if (strcmp (argv[2], "encode") == 0) mode = MU_FILTER_ENCODE; diff --git a/libmailutils/tests/fromflt.at b/libmailutils/tests/fromflt.at new file mode 100644 index 000000000..a5b331375 --- /dev/null +++ b/libmailutils/tests/fromflt.at @@ -0,0 +1,96 @@ +# This file is part of GNU Mailutils. -*- Autotest -*- +# Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc. +# +# GNU Mailutils is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 3, or (at +# your option) any later version. +# +# This program 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 +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. +# This file is part of Mailfromd testsuite. + +# ------------------------------------------- +# Data for 'From' filter tests. +# ------------------------------------------- + +m4_define([from_plain_text],[From this time on +from that source + From stdin +and +From them +]) + +m4_define([from_encoded_text],[>From this time on +from that source + From stdin +and +>From them +]) + +# ------------------------------------------- +# Test 'From' encoding +# ------------------------------------------- + +# Test read mode + +AT_SETUP([from filter encoding (read)]) +AT_KEYWORDS([from frome fromer encode]) + +AT_CHECK([ +AT_DATA([input],from_plain_text) +fltst from encode read < input +], +[0], +[from_encoded_text]) + +AT_CLEANUP + +# The same, in write mode + +AT_SETUP([from filter encoding (write)]) +AT_KEYWORDS([from frome fromew encode]) + +AT_CHECK([ +AT_DATA([input],from_plain_text) +fltst from encode write < input +], +[0], +[from_encoded_text]) + +AT_CLEANUP + +# ------------------------------------------- +# Test '>From' decoding +# ------------------------------------------- + +AT_SETUP([from filter decoding (read)]) +AT_KEYWORDS([from fromd fromdr decode]) + +AT_CHECK([ +AT_DATA([input],from_encoded_text) +fltst from decode read < input +], +[0], +[from_plain_text]) + +AT_CLEANUP + +# The same, in write mode + +AT_SETUP([from filter decoding (write)]) +AT_KEYWORDS([from fromd fromdw decode]) + +AT_CHECK([ +AT_DATA([input],from_encoded_text) +fltst from decode write < input +], +[0], +[from_plain_text]) + +AT_CLEANUP diff --git a/libmailutils/tests/testsuite.at b/libmailutils/tests/testsuite.at index 1de64b66b..fbdc7c99b 100644 --- a/libmailutils/tests/testsuite.at +++ b/libmailutils/tests/testsuite.at @@ -60,7 +60,8 @@ m4_include([argcv.at]) m4_include([url.at]) m4_include([mailcap.at]) m4_include([base64e.at]) m4_include([base64d.at]) m4_include([decode2047.at]) m4_include([encode2047.at]) +m4_include([fromflt.at]) diff --git a/libproto/mbox/mbox.c b/libproto/mbox/mbox.c index 62507657e..cc412ff37 100644 --- a/libproto/mbox/mbox.c +++ b/libproto/mbox/mbox.c @@ -25,12 +25,13 @@ # include <config.h> #endif #include <mbox0.h> #include <mailutils/cstr.h> #include <mailutils/io.h> +#include <mailutils/filter.h> #define ATTRIBUTE_IS_DELETED(flag) (flag & MU_ATTRIBUTE_DELETED) #define ATTRIBUTE_IS_EQUAL(flag1, flag2) (flag1 == flag2) static int mbox_is_updated (mu_mailbox_t mailbox); static int mbox_expunge0 (mu_mailbox_t mailbox, int remove_deleted); @@ -1030,13 +1031,13 @@ uid_to_stream (mu_stream_t ostr, mu_message_t msg, mbox_data_t mud, int flags) /* Append MSG to stream OSTR in its current position */ static int append_message_to_stream (mu_stream_t ostr, mu_message_t msg, mbox_data_t mud, int flags) { int status; - mu_stream_t istr; + mu_stream_t istr, flt; status = msg_envelope_to_stream (ostr, msg); if (status) return status; if (flags & MBOX_EXPUNGE) @@ -1081,16 +1082,24 @@ append_message_to_stream (mu_stream_t ostr, mu_message_t msg, else { status = mu_message_get_streamref (msg, &istr); if (status) return status; } - status = mu_stream_copy (ostr, istr, 0, NULL); - mu_stream_destroy (&istr); + + status = mu_filter_create (&flt, istr, "FROM", + MU_FILTER_ENCODE, MU_STREAM_READ); + mu_stream_unref (istr); if (status == 0) - status = mu_stream_write (ostr, "\n", 1, NULL); + { + status = mu_stream_copy (ostr, flt, 0, NULL); + mu_stream_destroy (&flt); + if (status == 0) + status = mu_stream_write (ostr, "\n", 1, NULL); + } + return status; } static int mbox_append_message (mu_mailbox_t mailbox, mu_message_t msg) { |