Commit dd8d091b dd8d091ba3cae58fd437c664478de8bcbdf25ac6 by Sergey Poznyakoff

Implement a filter for quoting ^From. Use it for appending to UNIX mailboxes.

* libmailutils/fromflt.c: New file.
* libmailutils/Makefile.am (libmailutils_la_SOURCES): Add fromflt.c
* libmailutils/tests/testsuite.at: Include fromflt.at.
* include/mailutils/filter.h (mu_from_filter): New filter type.
* libmailutils/filter.c (mu_filter_get_list): Register mu_from_filter.

* libmailutils/fromflt.at: New file.
* libmailutils/tests/Makefile.am (TESTSUITE_AT): Add fromflt.at.
* libmailutils/tests/base64d.at: Mention `filter' in the keywords.
* libmailutils/tests/base64e.at: Likewise.
* libmailutils/tests/fltst.c (main): Fix argc check.

* libproto/mbox/mbox.c (append_message_to_stream): Use "FROM" filter.
1 parent f24df125
......@@ -103,7 +103,8 @@ 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,
......
......@@ -83,6 +83,7 @@ libmailutils_la_SOURCES = \
fltstream.c\
folder.c\
freeitem.c\
fromflt.c\
gdebug.c\
getpass.c\
gocs.c\
......
......@@ -78,6 +78,7 @@ mu_filter_get_list (mu_list_t *plist)
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;
......
/* 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;
......@@ -64,6 +64,7 @@ TESTSUITE_AT = \
base64e.at\
decode2047.at\
encode2047.at\
fromflt.at\
list.at\
mailcap.at\
testsuite.at\
......
......@@ -16,7 +16,7 @@
# 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
......@@ -28,7 +28,7 @@ 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
......
......@@ -16,7 +16,7 @@
# 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
......@@ -28,7 +28,7 @@ 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
......
......@@ -114,7 +114,7 @@ main (int argc, char * argv [])
if (argc == 1)
usage (NULL);
if (argc < 3)
if (argc < 4)
usage ("not enough arguments");
fltname = argv[1];
......
# 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
......@@ -63,4 +63,5 @@ m4_include([base64e.at])
m4_include([base64d.at])
m4_include([decode2047.at])
m4_include([encode2047.at])
m4_include([fromflt.at])
......
......@@ -28,6 +28,7 @@
#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)
......@@ -1033,7 +1034,7 @@ 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)
......@@ -1084,10 +1085,18 @@ append_message_to_stream (mu_stream_t ostr, mu_message_t msg,
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;
}
......