summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2018-08-26 00:21:08 +0300
committerSergey Poznyakoff <gray@gnu.org>2018-08-26 00:34:08 +0300
commitce5b13e92b6e2f7af243654fe0673646f00dc3a6 (patch)
tree9822a86f6eeadf5c9bf6b9ec1ce7e9db6ec99f99
parent4a9746cc2ff998a5c52a5fb24c9aea3a851b1ea1 (diff)
downloadmailutils-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--NEWS38
-rw-r--r--include/mailutils/guile.h2
-rw-r--r--libmu_scm/Makefile.am5
-rw-r--r--libmu_scm/mu_filter.c248
-rw-r--r--libmu_scm/mu_message.c3
-rw-r--r--libmu_scm/mu_port.c6
-rw-r--r--libmu_scm/mu_scm.c1
7 files changed, 295 insertions, 8 deletions
diff --git a/NEWS b/NEWS
index c99c1b63b..04c9f0ff1 100644
--- a/NEWS
+++ b/NEWS
@@ -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"

Return to:

Send suggestions and report system problems to the System administrator.