diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2018-08-26 00:21:08 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2018-08-26 00:34:08 +0300 |
commit | ce5b13e92b6e2f7af243654fe0673646f00dc3a6 (patch) | |
tree | 9822a86f6eeadf5c9bf6b9ec1ce7e9db6ec99f99 | |
parent | 4a9746cc2ff998a5c52a5fb24c9aea3a851b1ea1 (diff) | |
download | mailutils-ce5b13e92b6e2f7af243654fe0673646f00dc3a6.tar.gz mailutils-ce5b13e92b6e2f7af243654fe0673646f00dc3a6.tar.bz2 |
Implement SCM interface to mailutils filters
* include/mailutils/guile.h (mu_port_make_from_stream): Remove
unused msg argument. All uses updated.
* libmu_scm/mu_filter.c: New file.
* libmu_scm/Makefile.am: Add mu_filter.c
* libmu_scm/mu_message.c (mu-message-get-port): Add missing anchor to
the docstring.
* libmu_scm/mu_port.c (mu_port): Remove msg.
* libmu_scm/mu_scm.c (mu_scm_init): Call mu_scm_filter_init.
* NEWS: Updated.
-rw-r--r-- | NEWS | 38 | ||||
-rw-r--r-- | include/mailutils/guile.h | 2 | ||||
-rw-r--r-- | libmu_scm/Makefile.am | 5 | ||||
-rw-r--r-- | libmu_scm/mu_filter.c | 248 | ||||
-rw-r--r-- | libmu_scm/mu_message.c | 3 | ||||
-rw-r--r-- | libmu_scm/mu_port.c | 6 | ||||
-rw-r--r-- | libmu_scm/mu_scm.c | 1 |
7 files changed, 295 insertions, 8 deletions
@@ -1,4 +1,4 @@ -GNU mailutils NEWS -- history of user-visible changes. 2018-07-30 +GNU mailutils NEWS -- history of user-visible changes. 2018-08-26 Copyright (C) 2002-2018 Free Software Foundation, Inc. See the end of file for copying conditions. @@ -8,6 +8,42 @@ Version 3.4.91 (Git) * Dropped support for Guile version prior to 2.2.0 +* New scheme functions + +** mu-encoder-port port name . args + +Create encoding port using Mailutils filter <name> with optional arguments +<args>. The <port> argument must be a port opened either for writing +or for reading, but not both. The returned port will have the same +mode as <port>. + +If <port> is open for reading, data will be read from it, passed through the +filter and returned. If it is open for writing, data written to the returned +port will be passed through filter and its output will be written to <port>. + +** mu-decoder-port port name . args + +Create decoding port using Mailutils filter <name> with optional arguments +<args>. The <port> argument must be a port opened either for writing +or for reading, but not both. The returned port will have the same +mode as <port>. + +If <port> is open for reading, data will be read from it, passed through the +filter and returned. If it is open for writing, data written to the returned +port will be passed through filter and its output will be written to <port>. + +** mu-header-decode hdr [charset] + +Decode the header value hdr, encoded as per RFC 2047. +Optional charset defaults to "utf-8". + +** mu-header-encode hdr [encoding [charset]] + +Encode the string hdr as per RFC 2047. +Allowed values for encoding are "base64 and "quoted-printable". +Default is selected depending on number of printable characters in "hdr". +Optional charset defaults to "utf-8". + * Introduced support for Python 3.x * Support for Berkeley DB versions 5 and 6 diff --git a/include/mailutils/guile.h b/include/mailutils/guile.h index 1803ec03c..ee06628c8 100644 --- a/include/mailutils/guile.h +++ b/include/mailutils/guile.h @@ -62,7 +62,7 @@ extern void mu_scm_address_init (void); extern void mu_scm_logger_init (void); extern void mu_scm_port_init (void); -extern SCM mu_port_make_from_stream (SCM msg, mu_stream_t stream, long mode); +extern SCM mu_port_make_from_stream (mu_stream_t stream, long mode); extern void mu_scm_mime_init (void); extern void mu_scm_message_add_owner (SCM MESG, SCM owner); diff --git a/libmu_scm/Makefile.am b/libmu_scm/Makefile.am index 20cd6e2d7..a3fc0d776 100644 --- a/libmu_scm/Makefile.am +++ b/libmu_scm/Makefile.am @@ -26,6 +26,7 @@ C_SRCS=\ mu_body.c\ mu_debug.c\ mu_dbgport.c\ + mu_filter.c\ mu_guile.c\ mu_mailbox.c\ mu_message.c\ @@ -56,6 +57,7 @@ DOT_X_FILES=\ mu_address.x\ mu_body.x\ mu_debug.x\ + mu_filter.x\ mu_mailbox.x\ mu_message.x\ mu_mime.x\ @@ -68,13 +70,14 @@ DOT_DOC_FILES=\ mu_address.doc\ mu_body.doc\ mu_debug.doc\ + mu_filter.doc\ mu_mailbox.doc\ mu_message.doc\ mu_mime.doc\ mu_logger.doc\ mu_port.doc\ mu_scm.doc\ - mu_util.doc + mu_util.doc EXTRA_DIST= CLEANFILES= diff --git a/libmu_scm/mu_filter.c b/libmu_scm/mu_filter.c new file mode 100644 index 000000000..933c9ef1a --- /dev/null +++ b/libmu_scm/mu_filter.c @@ -0,0 +1,248 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2018 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/>. */ + +#include "mu_scm.h" +#include <mailutils/filter.h> +#include <mailutils/argcv.h> + +static void +argv_free (void *p) +{ + mu_argv_free ((char**)p); +} + +static SCM +make_filter_port (SCM port, SCM name, SCM args, + int filter_mode, char const *func_name) +/* The FUNC_NAME macro is used by SCM_VALIDATE_REST_ARGUMENT */ +#define FUNC_NAME func_name +{ + char *fltname; + mu_stream_t filter; + mu_stream_t instr; + size_t argc = 0; + char **argv = NULL; + int rc; + int flags = 0; + char *port_mode; + + SCM_ASSERT (scm_port_p (port), port, SCM_ARG1, FUNC_NAME); + SCM_ASSERT (scm_is_string (name), name, SCM_ARG2, FUNC_NAME); + SCM_VALIDATE_REST_ARGUMENT (args); + + port_mode = scm_to_locale_string (scm_port_mode (port)); + if (strchr (port_mode, 'r')) + flags |= MU_STREAM_READ; + if (strchr (port_mode, 'w')) + flags |= MU_STREAM_WRITE; + free (port_mode); + if (!flags + || ((flags & (MU_STREAM_READ|MU_STREAM_WRITE)) + == (MU_STREAM_READ|MU_STREAM_WRITE))) + scm_out_of_range (FUNC_NAME, port); //FIXME + + scm_dynwind_begin (0); + + fltname = scm_to_locale_string (name); + scm_dynwind_free (fltname); + + rc = mu_scm_port_stream_create (&instr, port); + if (rc) + { + mu_scm_error (FUNC_NAME, rc, + "Failed to convert transport port ~A", + scm_list_1 (port)); + } + + if (!scm_is_null (args)) + { + size_t n; + + argc = scm_to_size_t (scm_length (args)) + 1; + argv = calloc (argc + 1, sizeof (argv[0])); + if (!argv) + mu_scm_error (FUNC_NAME, ENOMEM, "Cannot allocate memory", SCM_BOOL_F); + + argv[0] = strdup (fltname); + n = 1; + for (; !scm_is_null (args); args = SCM_CDR (args)) + { + SCM arg = SCM_CAR (args); + SCM_ASSERT (scm_is_string (arg), arg, SCM_ARGn, FUNC_NAME); + argv[n] = scm_to_locale_string (arg); + n++; + } + argv[n] = NULL; + scm_dynwind_unwind_handler (argv_free, argv, SCM_F_WIND_EXPLICITLY); + } + + rc = mu_filter_create_args (&filter, instr, + fltname, argc, (const char**) argv, + filter_mode, flags); + if (rc) + { + mu_scm_error (FUNC_NAME, rc, + "Failed to create filter ~A", + scm_list_1 (name)); + } + + scm_dynwind_end (); + return mu_port_make_from_stream (filter, + flags == MU_STREAM_READ + ? SCM_RDNG + : SCM_WRTNG); +} +#undef FUNC_NAME + +SCM_DEFINE_PUBLIC (scm_mu_encoder_port, "mu-encoder-port", 2, 0, 1, + (SCM port, SCM name, SCM args), +"Create encoding port using Mailutils filter @var{name} with optional arguments\n" +"@var{args}. The @var{port} argument must be a port opened either for\n" +"writing or for reading, but not both. The returned port will have the same\n" +"mode as @var{port}." +"\n\n" +"If @var{port} is open for reading, data will be read from it, passed through the\n" +"filter and returned. If it is open for writing, data written to the returned\n" +"port will be passed through filter and its output will be written to @var{port}.\n") +#define FUNC_NAME s_scm_mu_encoder_port +{ + return make_filter_port (port, name, args, MU_FILTER_ENCODE, FUNC_NAME); +} +#undef FUNC_NAME + +SCM_DEFINE_PUBLIC (scm_mu_decoder_port, "mu-decoder-port", 2, 0, 1, + (SCM port, SCM name, SCM args), +"Create a decoding port using Mailutils filter @var{name} with optional arguments\n" +"@var{args}. The @var{port} argument must be a port opened either for\n" +"writing or for reading, but not both. The returned port will have the same\n" +"mode as @var{port}." +"\n\n" +"If @var{port} is open for reading, data will be read from it, passed through the\n" +"filter and returned. If it is open for writing, data written to the returned\n" +"port will be passed through filter and its output will be written to @var{port}.\n") +#define FUNC_NAME s_scm_mu_decoder_port +{ + return make_filter_port (port, name, args, MU_FILTER_DECODE, FUNC_NAME); +} +#undef FUNC_NAME + +SCM_DEFINE_PUBLIC (scm_mu_header_decode, "mu-header-decode", 1, 1, 0, + (SCM hdr, SCM charset), +"Decode the header value @var{hdr}, encoded as per RFC 2047.\n" +"Optional @var{charset} defaults to @samp{utf-8}.\n") +#define FUNC_NAME s_scm_mu_header_decode +{ + char *c_hdr, *c_charset, *c_res; + int rc; + SCM res; + + SCM_ASSERT (scm_is_string (hdr), hdr, SCM_ARG1, FUNC_NAME); + + scm_dynwind_begin (0); + if (SCM_UNBNDP (charset)) + c_charset = "utf-8"; + else + { + SCM_ASSERT (scm_is_string (charset), charset, SCM_ARG2, FUNC_NAME); + c_charset = scm_to_locale_string (charset); + scm_dynwind_free (c_charset); + } + c_hdr = scm_to_locale_string (hdr); + scm_dynwind_free (c_hdr); + + rc = mu_rfc2047_decode (c_charset, c_hdr, &c_res); + if (rc) + mu_scm_error (FUNC_NAME, rc, + "Can't convert header value", SCM_BOOL_F); + + scm_dynwind_end (); + + res = scm_from_locale_string (c_res); + free (c_res); + + return res; +} +#undef FUNC_NAME + +SCM_DEFINE_PUBLIC (scm_mu_header_encode, "mu-header-encode", 1, 2, 0, + (SCM hdr, SCM encoding, SCM charset), +"Encode the string @var{hdr} as per RFC 2047.\n" +"Both @var{encoding} and @var{charset} are optional.\n" +"Allowed values for @var{encoding} are @samp{base64} and @samp{quoted-printable}.\n" +"Default is selected depending on number of printable characters in @var{hdr}.\n" +"Optional @var{charset} defaults to @samp{utf-8}.\n") +#define FUNC_NAME s_scm_mu_header_encode +{ + char *c_hdr, *c_charset, *c_encoding, *c_res; + int rc; + SCM res; + + SCM_ASSERT (scm_is_string (hdr), hdr, SCM_ARG1, FUNC_NAME); + + scm_dynwind_begin (0); + + if (SCM_UNBNDP (encoding)) + c_encoding = NULL; + else + { + SCM_ASSERT (scm_is_string (encoding), encoding, SCM_ARG2, FUNC_NAME); + c_encoding = scm_to_locale_string (encoding); + scm_dynwind_free (c_encoding); + } + + if (SCM_UNBNDP (charset)) + c_charset = "utf-8"; + else + { + SCM_ASSERT (scm_is_string (charset), charset, SCM_ARG3, FUNC_NAME); + c_charset = scm_to_locale_string (charset); + scm_dynwind_free (c_charset); + } + c_hdr = scm_to_locale_string (hdr); + scm_dynwind_free (c_hdr); + + if (!c_encoding) + { + size_t len = strlen (c_hdr); + size_t i, enc; + + enc = 0; + for (i = 0; i < len; i++) + if (!mu_isprint (c_hdr[i])) + enc++; + c_encoding = (enc > len / 2) ? "base64" : "quoted-printable"; + } + + rc = mu_rfc2047_encode (c_charset, c_encoding, c_hdr, &c_res); + if (rc) + mu_scm_error (FUNC_NAME, rc, + "Can't encode header value", SCM_BOOL_F); + + scm_dynwind_end (); + + res = scm_from_locale_string (c_res); + free (c_res); + + return res; +} +#undef FUNC_NAME + +void +mu_scm_filter_init (void) +{ +#include "mu_filter.x" +} diff --git a/libmu_scm/mu_message.c b/libmu_scm/mu_message.c index 8eda9d3f2..3e868d94d 100644 --- a/libmu_scm/mu_message.c +++ b/libmu_scm/mu_message.c @@ -897,6 +897,7 @@ SCM_DEFINE_PUBLIC (scm_mu_message_set_user_flag, "mu-message-set-user-flag", 2, SCM_DEFINE_PUBLIC (scm_mu_message_get_port, "mu-message-get-port", 2, 1, 0, (SCM mesg, SCM mode, SCM full), +"@anchor{mu-message-get-port}\n" "Returns a port associated with the message @var{mesg}. The @var{mode} is a\n" "string defining operation mode of the stream. It may contain any of the\n" "two characters: @samp{r} for reading, @samp{w} for writing.\n" @@ -943,7 +944,7 @@ SCM_DEFINE_PUBLIC (scm_mu_message_get_port, "mu-message-get-port", 2, 1, 0, } str = scm_to_locale_string (mode); - ret = mu_port_make_from_stream (mesg, stream, scm_mode_bits (str)); + ret = mu_port_make_from_stream (stream, scm_mode_bits (str)); free (str); return ret; } diff --git a/libmu_scm/mu_port.c b/libmu_scm/mu_port.c index 1b6834dcd..93b815cbf 100644 --- a/libmu_scm/mu_port.c +++ b/libmu_scm/mu_port.c @@ -22,7 +22,6 @@ struct mu_port { mu_stream_t stream; /* Associated stream */ - SCM msg; /* Message the port belongs to */ }; #define MU_PORT(x) ((struct mu_port *) SCM_STREAM (x)) @@ -30,12 +29,11 @@ struct mu_port static scm_t_port_type *scm_mu_port_type; SCM -mu_port_make_from_stream (SCM msg, mu_stream_t stream, long mode) +mu_port_make_from_stream (mu_stream_t stream, long mode) { struct mu_port *mp; mp = scm_gc_typed_calloc (struct mu_port); - mp->msg = msg; mp->stream = stream; return scm_c_make_port (scm_mu_port_type, mode | SCM_BUF0, (scm_t_bits) mp); } @@ -53,7 +51,7 @@ mu_port_read (SCM port, SCM dst, size_t start, size_t count) struct mu_port *mp = MU_PORT (port); int status; size_t nread; - + status = mu_stream_read (mp->stream, SCM_BYTEVECTOR_CONTENTS (dst) + start, count, diff --git a/libmu_scm/mu_scm.c b/libmu_scm/mu_scm.c index 59e30cc44..0ab69ec3d 100644 --- a/libmu_scm/mu_scm.c +++ b/libmu_scm/mu_scm.c @@ -214,6 +214,7 @@ mu_scm_init () mu_scm_mime_init (); mu_scm_debug_port_init (); mu_scm_debug_init (); + mu_scm_filter_init (); #include "mu_scm.x" |