This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GNU Mailutils".
http://git.savannah.gnu.org/cgit/mailutils.git/commit/?id=a783f8c35ed0fc9a7a18dc82f43bbe34a37aae37 The branch, stream-cleanup has been updated via a783f8c35ed0fc9a7a18dc82f43bbe34a37aae37 (commit) from 286657e78705d061fc68c000cd3823608c522c04 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit a783f8c35ed0fc9a7a18dc82f43bbe34a37aae37 Author: Sergey Poznyakoff <g...@gnu.org.ua> Date: Mon Aug 30 10:48:54 2010 +0300 Add a framework for printing I/O transcripts; modify pop3d to use it. * include/mailutils/stream.h (MU_STREAM_RDTHRU) (MU_STREAM_WRTHRU,MU_IOCTL_SET_TRANSPORT): New flags. (mu_xscript_stream_create, mu_iostream_create) (mu_dbgstream_create): New prototypes. * include/mailutils/sys/dbgstream.h: New header. * include/mailutils/sys/iostream.h: New header. * include/mailutils/sys/xscript-stream.h: New header. * include/mailutils/sys/Makefile.am (sysinclude_HEADERS): Add dbgstream.h, iostream.h and xscript-stream.h * mailbox/dbgstream.c: New file. * mailbox/iostream.c: New file. * mailbox/xscript-stream.c: New file. * mailbox/Makefile.am (libmailutils_la_SOURCES): Add dbgstream.c, iostream.c and xscript-stream.c * mailbox/filter_iconv.c (_icvt_ioctl): Simplify the declaration of ptrans. * mailbox/mapfile_stream.c (_mapfile_ioctl): Likewise. * mailbox/memory_stream.c (_memory_ioctl): Likewise. * mailbox/prog_stream.c (_prog_ioctl): Likewise. * mailbox/tcp.c (_tcp_ioctl): Likewise. * mailbox/fltstream.c (filter_ctl): Likewise. (filter_read_through, filter_write_through): New methods. (mu_filter_stream_create): Allow for use of MU_STREAM_RDTHRU and MU_STREAM_WRTHRU to create two-way filters (writing triggers filtering while reading is transparent or vice versa). * pop3d/extra.c (istream, ostream): Remove globals. (iostream): New variable. (real_istream, real_ostream): New variables. (pop3d_setio): Set transcript stream on top of the I/O one, if required. (pop3d_init_tls_server): Rewrite. Revert the meaning of the return code to match the usual convention (0 - success). (transcript): Removed. (pop3d_outf): Remove calls to transcript. * pop3d/pop3d.h (istream, ostream): Remove externs. (iostream): New extern. * pop3d/retr.c: Use iostream, instear of ostream. * pop3d/top.c: Likewise. * pop3d/stls.c: Update the call to pop3d_init_tls_server. * mailbox/stream_vprintf.c (mu_stream_vprintf): Fix return value to match the usual convention. ----------------------------------------------------------------------- Summary of changes: include/mailutils/stream.h | 12 + include/mailutils/sys/Makefile.am | 5 +- .../mailutils/sys/{streamtrans.h => dbgstream.h} | 18 +- .../mailutils/sys/{streamtrans.h => iostream.h} | 21 +- .../sys/{streamtrans.h => xscript-stream.h} | 20 +- mailbox/Makefile.am | 5 +- mailbox/dbgstream.c | 86 ++++++ mailbox/file_stream.c | 6 +- mailbox/filter_iconv.c | 6 +- mailbox/fltstream.c | 45 +++- mailbox/iostream.c | 249 ++++++++++++++++ mailbox/mapfile_stream.c | 6 +- mailbox/memory_stream.c | 6 +- mailbox/prog_stream.c | 6 +- mailbox/stream_vprintf.c | 2 +- mailbox/tcp.c | 6 +- mailbox/xscript-stream.c | 300 ++++++++++++++++++++ pop3d/extra.c | 111 ++++---- pop3d/pop3d.h | 2 +- pop3d/retr.c | 2 +- pop3d/stls.c | 2 +- pop3d/top.c | 2 +- 22 files changed, 816 insertions(+), 102 deletions(-) copy include/mailutils/sys/{streamtrans.h => dbgstream.h} (74%) copy include/mailutils/sys/{streamtrans.h => iostream.h} (70%) copy include/mailutils/sys/{streamtrans.h => xscript-stream.h} (70%) create mode 100644 mailbox/dbgstream.c create mode 100644 mailbox/iostream.c create mode 100644 mailbox/xscript-stream.c diff --git a/include/mailutils/stream.h b/include/mailutils/stream.h index 1aee884..1b74651 100644 --- a/include/mailutils/stream.h +++ b/include/mailutils/stream.h @@ -47,6 +47,9 @@ enum mu_buffer_type /* FIXME: This one affects only mailboxes */ #define MU_STREAM_QACCESS 0x00000200 +#define MU_STREAM_RDTHRU 0x00000400 +#define MU_STREAM_WRTHRU 0x00000800 + #define MU_STREAM_IRGRP 0x00001000 #define MU_STREAM_IWGRP 0x00002000 #define MU_STREAM_IROTH 0x00004000 @@ -59,6 +62,7 @@ enum mu_buffer_type #define MU_IOCTL_SET_SEEK_LIMITS 4 #define MU_IOCTL_ABRIDGE_SEEK MU_IOCTL_SET_SEEK_LIMITS #define MU_IOCTL_GET_SEEK_LIMITS 5 +#define MU_IOCTL_SET_TRANSPORT 6 void mu_stream_ref (mu_stream_t stream); void mu_stream_unref (mu_stream_t stream); @@ -145,4 +149,12 @@ int mu_tcp_stream_create_with_source_host (mu_stream_t *stream, int mu_tcp_stream_create (mu_stream_t *stream, const char *host, int port, int flags); +int mu_xscript_stream_create(mu_stream_t *pref, mu_stream_t transport, + mu_stream_t logstr, + const char *prefix[]); +int mu_iostream_create (mu_stream_t *pref, mu_stream_t in, mu_stream_t out, + int flags); +int mu_dbgstream_create(mu_stream_t *pref, mu_debug_t debug, + mu_log_level_t level, int flags); + #endif diff --git a/include/mailutils/sys/Makefile.am b/include/mailutils/sys/Makefile.am index 34f995b..ce37112 100644 --- a/include/mailutils/sys/Makefile.am +++ b/include/mailutils/sys/Makefile.am @@ -19,10 +19,12 @@ sysincludedir=$(pkgincludedir)/sys sysinclude_HEADERS = \ + dbgstream.h\ file_stream.h\ filter.h\ header_stream.h\ header.h\ + iostream.h\ mapfile_stream.h\ memory_stream.h\ message_stream.h\ @@ -36,4 +38,5 @@ sysinclude_HEADERS = \ stream.h\ tls-stream.h\ pop3.h\ - nntp.h + nntp.h\ + xscript-stream.h diff --git a/include/mailutils/sys/streamtrans.h b/include/mailutils/sys/dbgstream.h similarity index 74% copy from include/mailutils/sys/streamtrans.h copy to include/mailutils/sys/dbgstream.h index 25bc0d9..6934372 100644 --- a/include/mailutils/sys/streamtrans.h +++ b/include/mailutils/sys/dbgstream.h @@ -14,14 +14,18 @@ You should have received a copy of the GNU Lesser General Public License along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef _MAILUTILS_SYS_STREAMTRANS_H -#define _MAILUTILS_SYS_STREAMTRANS_H +#ifndef _MAILUTILS_SYS_DBGSTREAM_H +# define _MAILUTILS_SYS_DBGSTREAM_H -#include <mailutils/types.h> -#include <mailutils/sys/stream.h> +# include <mailutils/types.h> +# include <mailutils/stream.h> +# include <mailutils/sys/stream.h> -struct _mu_streamtrans +struct _mu_dbgstream { - struct _mu_stream base; /* Superclass */ - mu_stream_t transport; /* Transport stream */ + struct _mu_stream stream; + mu_debug_t debug; + mu_log_level_t level; }; + +#endif diff --git a/include/mailutils/sys/streamtrans.h b/include/mailutils/sys/iostream.h similarity index 70% copy from include/mailutils/sys/streamtrans.h copy to include/mailutils/sys/iostream.h index 25bc0d9..d8922f6 100644 --- a/include/mailutils/sys/streamtrans.h +++ b/include/mailutils/sys/iostream.h @@ -14,14 +14,21 @@ You should have received a copy of the GNU Lesser General Public License along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef _MAILUTILS_SYS_STREAMTRANS_H -#define _MAILUTILS_SYS_STREAMTRANS_H +#ifndef _MAILUTILS_SYS_IOSTREAM_H +# define _MAILUTILS_SYS_IOSTREAM_H -#include <mailutils/types.h> -#include <mailutils/sys/stream.h> +# include <mailutils/types.h> +# include <mailutils/stream.h> +# include <mailutils/sys/stream.h> -struct _mu_streamtrans +# define _MU_STREAM_INPUT 0 +# define _MU_STREAM_OUTPUT 1 + +struct _mu_iostream { - struct _mu_stream base; /* Superclass */ - mu_stream_t transport; /* Transport stream */ + struct _mu_stream stream; + mu_stream_t transport[2]; + int last_err_str; }; + +#endif diff --git a/include/mailutils/sys/streamtrans.h b/include/mailutils/sys/xscript-stream.h similarity index 70% copy from include/mailutils/sys/streamtrans.h copy to include/mailutils/sys/xscript-stream.h index 25bc0d9..c6b4538 100644 --- a/include/mailutils/sys/streamtrans.h +++ b/include/mailutils/sys/xscript-stream.h @@ -14,14 +14,20 @@ You should have received a copy of the GNU Lesser General Public License along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef _MAILUTILS_SYS_STREAMTRANS_H -#define _MAILUTILS_SYS_STREAMTRANS_H +#ifndef _MAILUTILS_SYS_XSCRIPT_STREAM_H +# define _MAILUTILS_SYS_XSCRIPT_STREAM_H -#include <mailutils/types.h> -#include <mailutils/sys/stream.h> +# include <mailutils/types.h> +# include <mailutils/stream.h> +# include <mailutils/sys/stream.h> -struct _mu_streamtrans +struct _mu_xscript_stream { - struct _mu_stream base; /* Superclass */ - mu_stream_t transport; /* Transport stream */ + struct _mu_stream stream; + mu_stream_t transport; + mu_stream_t logstr; + int flags; + char *prefix[2]; }; + +#endif diff --git a/mailbox/Makefile.am b/mailbox/Makefile.am index 0d04930..1fd892d 100644 --- a/mailbox/Makefile.am +++ b/mailbox/Makefile.am @@ -69,6 +69,7 @@ libmailutils_la_SOURCES = \ daemon.c\ date.c\ dbgstderr.c\ + dbgstream.c\ dbgsyslog.c\ debug.c\ diag.c\ @@ -84,6 +85,7 @@ libmailutils_la_SOURCES = \ gocs.c\ hdritr.c\ header.c\ + iostream.c\ iterator.c\ ipsrv.c\ kwd.c\ @@ -150,7 +152,8 @@ libmailutils_la_SOURCES = \ vartab.c\ vasnprintf.c\ version.c\ - wicket.c + wicket.c\ + xscript-stream.c BUILT_SOURCES = parsedate.c muerrno.c cfg_parser.c cfg_parser.h cfg_lexer.c MOSTLYCLEANFILES= diff --git a/mailbox/dbgstream.c b/mailbox/dbgstream.c new file mode 100644 index 0000000..19c137d --- /dev/null +++ b/mailbox/dbgstream.c @@ -0,0 +1,86 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 1999, 2000, 2001, 2002, 2004, + 2005, 2006, 2007, 2008, 2009, 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, 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 GNU Mailutils. 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/types.h> +#include <mailutils/alloc.h> +#include <mailutils/errno.h> + +#include <mailutils/nls.h> +#include <mailutils/stream.h> +#include <mailutils/sys/stream.h> +#include <mailutils/sys/dbgstream.h> +#include <mailutils/debug.h> + +static int +_dbg_write (struct _mu_stream *str, const char *buf, size_t size, + size_t *pnwrite) +{ + struct _mu_dbgstream *sp = (struct _mu_dbgstream *)str; + if (pnwrite) + *pnwrite = size; + while (size > 0 && (buf[size-1] == '\n' || buf[size-1] == '\r')) + size--; + if (size) + mu_debug_printf (sp->debug, sp->level, "%.*s\n", size, buf); + return 0; +} + +static int +_dbg_flush (struct _mu_stream *str) +{ + struct _mu_dbgstream *sp = (struct _mu_dbgstream *)str; + mu_debug_printf (sp->debug, sp->level, "\n"); + return 0; +} + +static void +_dbg_done (struct _mu_stream *str) +{ + struct _mu_dbgstream *sp = (struct _mu_dbgstream *)str; + if (!(str->flags & MU_STREAM_NO_CLOSE)) + mu_debug_destroy (&sp->debug, NULL); +} + +int +mu_dbgstream_create(mu_stream_t *pref, mu_debug_t debug, mu_log_level_t level, + int flags) +{ + struct _mu_dbgstream *sp; + + sp = (struct _mu_dbgstream *) + _mu_stream_create (sizeof (*sp), MU_STREAM_WRITE | + (flags & MU_STREAM_NO_CLOSE)); + if (!sp) + return ENOMEM; + sp->stream.write = _dbg_write; + sp->stream.flush = _dbg_flush; + sp->stream.done = _dbg_done; + + sp->debug = debug; + sp->level = level; + mu_stream_set_buffer ((mu_stream_t) sp, mu_buffer_line, 1024); + *pref = (mu_stream_t) sp; + return 0; +} + diff --git a/mailbox/file_stream.c b/mailbox/file_stream.c index c97075f..7dc8c90 100644 --- a/mailbox/file_stream.c +++ b/mailbox/file_stream.c @@ -192,7 +192,7 @@ static int fd_ioctl (struct _mu_stream *str, int code, void *ptr) { struct _mu_file_stream *fstr = (struct _mu_file_stream *) str; - mu_transport_t (*ptrans)[2]; + mu_transport_t *ptrans; switch (code) { @@ -200,8 +200,8 @@ fd_ioctl (struct _mu_stream *str, int code, void *ptr) if (!ptr) return EINVAL; ptrans = ptr; - (*ptrans)[0] = (mu_transport_t) fstr->fd; - (*ptrans)[1] = NULL; + ptrans[0] = (mu_transport_t) fstr->fd; + ptrans[1] = NULL; break; default: diff --git a/mailbox/filter_iconv.c b/mailbox/filter_iconv.c index 6674ba4..c948df4 100644 --- a/mailbox/filter_iconv.c +++ b/mailbox/filter_iconv.c @@ -390,7 +390,7 @@ static int _icvt_ioctl (mu_stream_t stream, int code, void *ptr) { struct icvt_stream *s = (struct icvt_stream *)stream; - mu_transport_t (*ptrans)[2]; + mu_transport_t *ptrans; switch (code) { @@ -398,8 +398,8 @@ _icvt_ioctl (mu_stream_t stream, int code, void *ptr) if (!ptr) return EINVAL; ptrans = ptr; - (*ptrans)[0] = (mu_transport_t) s->transport; - (*ptrans)[1] = NULL; + ptrans[0] = (mu_transport_t) s->transport; + ptrans[1] = NULL; break; default: diff --git a/mailbox/fltstream.c b/mailbox/fltstream.c index 8f6260a..c759134 100644 --- a/mailbox/fltstream.c +++ b/mailbox/fltstream.c @@ -335,7 +335,7 @@ static int filter_ctl (struct _mu_stream *stream, int op, void *ptr) { struct _mu_filter_stream *fs = (struct _mu_filter_stream *)stream; - mu_transport_t (*ptrans)[2]; + mu_transport_t *ptrans; switch (op) { @@ -343,8 +343,8 @@ filter_ctl (struct _mu_stream *stream, int op, void *ptr) if (!ptr) return EINVAL; ptrans = ptr; - (*ptrans)[0] = (mu_transport_t) fs->transport; - (*ptrans)[1] = NULL; + ptrans[0] = (mu_transport_t) fs->transport; + ptrans[1] = NULL; break; default: @@ -390,6 +390,26 @@ filter_close (mu_stream_t stream) return mu_stream_close (fs->transport); } + +static int +filter_read_through (struct _mu_stream *stream, + char *buf, size_t bufsize, + size_t *pnread) +{ + struct _mu_filter_stream *fs = (struct _mu_filter_stream *)stream; + return mu_stream_read (fs->transport, buf, bufsize, pnread); +} + +static int +filter_write_through (struct _mu_stream *stream, + const char *buf, size_t bufsize, + size_t *pnwrite) +{ + struct _mu_filter_stream *fs = (struct _mu_filter_stream *)stream; + return mu_stream_write (fs->transport, buf, bufsize, pnwrite); +} + + int mu_filter_stream_create (mu_stream_t *pflt, mu_stream_t str, @@ -402,7 +422,14 @@ mu_filter_stream_create (mu_stream_t *pflt, if ((flags & MU_STREAM_RDWR) == MU_STREAM_RDWR || !(flags & MU_STREAM_RDWR) - || (flags & (MU_STREAM_WRITE|MU_STREAM_SEEK)) == (MU_STREAM_WRITE|MU_STREAM_SEEK)) + || (flags & (MU_STREAM_WRITE|MU_STREAM_SEEK)) == + (MU_STREAM_WRITE|MU_STREAM_SEEK) + || (flags & (MU_STREAM_RDTHRU|MU_STREAM_WRTHRU)) == + (MU_STREAM_RDTHRU|MU_STREAM_WRTHRU) + || (flags & (MU_STREAM_READ|MU_STREAM_RDTHRU)) == + (MU_STREAM_READ|MU_STREAM_RDTHRU) + || (flags & (MU_STREAM_WRITE|MU_STREAM_WRTHRU)) == + (MU_STREAM_WRITE|MU_STREAM_WRTHRU)) return EINVAL; fs = (struct _mu_filter_stream *) _mu_stream_create (sizeof (*fs), flags); @@ -413,11 +440,21 @@ mu_filter_stream_create (mu_stream_t *pflt, { fs->stream.read = filter_read; fs->stream.flush = filter_rd_flush; + if (flags & MU_STREAM_WRTHRU) + { + flags |= MU_STREAM_WRITE; + fs->stream.write = filter_write_through; + } } else { fs->stream.write = filter_write; fs->stream.flush = filter_wr_flush; + if (flags & MU_STREAM_RDTHRU) + { + flags |= MU_STREAM_READ; + fs->stream.read = filter_read_through; + } } fs->stream.done = filter_done; fs->stream.close = filter_close; diff --git a/mailbox/iostream.c b/mailbox/iostream.c new file mode 100644 index 0000000..4b76d3a --- /dev/null +++ b/mailbox/iostream.c @@ -0,0 +1,249 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 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, 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 GNU Mailutils. 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/types.h> +#include <mailutils/alloc.h> +#include <mailutils/errno.h> + +#include <mailutils/nls.h> +#include <mailutils/stream.h> +#include <mailutils/sys/stream.h> +#include <mailutils/sys/iostream.h> + +static int +_iostream_read (struct _mu_stream *str, char *buf, size_t bufsize, + size_t *pnread) +{ + struct _mu_iostream *sp = (struct _mu_iostream *)str; + int rc = mu_stream_read (sp->transport[_MU_STREAM_INPUT], buf, bufsize, + pnread); + if (rc) + sp->last_err_str = _MU_STREAM_INPUT; + return rc; +} + +static int +_iostream_readdelim (struct _mu_stream *str, char *buf, size_t bufsize, + int delim, size_t *pnread) +{ + struct _mu_iostream *sp = (struct _mu_iostream *)str; + int rc = mu_stream_readdelim (sp->transport[_MU_STREAM_INPUT], buf, + bufsize, delim, pnread); + if (rc) + sp->last_err_str = _MU_STREAM_INPUT; + return rc; +} + +static int +_iostream_write (struct _mu_stream *str, const char *buf, size_t bufsize, + size_t *pnwrite) +{ + struct _mu_iostream *sp = (struct _mu_iostream *)str; + int rc = mu_stream_write (sp->transport[_MU_STREAM_OUTPUT], buf, bufsize, + pnwrite); + if (rc) + sp->last_err_str = _MU_STREAM_OUTPUT; + return rc; +} + +static int +_iostream_flush (struct _mu_stream *str) +{ + struct _mu_iostream *sp = (struct _mu_iostream *)str; + int rc = mu_stream_flush (sp->transport[_MU_STREAM_INPUT]); + if (rc) + { + sp->last_err_str = _MU_STREAM_INPUT; + return rc; + } + if (sp->transport[_MU_STREAM_INPUT] != sp->transport[_MU_STREAM_OUTPUT]) + { + rc = mu_stream_flush (sp->transport[_MU_STREAM_OUTPUT]); + if (rc) + sp->last_err_str = _MU_STREAM_OUTPUT; + } + return rc; +} + +static int +_iostream_open (struct _mu_stream *str) +{ + struct _mu_iostream *sp = (struct _mu_iostream *)str; + int rc; + rc = mu_stream_open (sp->transport[_MU_STREAM_INPUT]); + if (rc) + { + sp->last_err_str = _MU_STREAM_INPUT; + return rc; + } + if (sp->transport[_MU_STREAM_INPUT] != sp->transport[_MU_STREAM_OUTPUT]) + { + rc = mu_stream_open (sp->transport[_MU_STREAM_OUTPUT]); + if (rc) + { + sp->last_err_str = _MU_STREAM_OUTPUT; + mu_stream_close (sp->transport[_MU_STREAM_INPUT]); + } + } + return rc; +} + +static int +_iostream_close (struct _mu_stream *str) +{ + struct _mu_iostream *sp = (struct _mu_iostream *)str; + if (sp->stream.flags & MU_STREAM_NO_CLOSE) + return 0; + mu_stream_close (sp->transport[_MU_STREAM_INPUT]); + if (sp->transport[_MU_STREAM_INPUT] != sp->transport[_MU_STREAM_OUTPUT]) + mu_stream_close (sp->transport[_MU_STREAM_OUTPUT]); + return 0; +} + +static void +_iostream_done (struct _mu_stream *str) +{ + struct _mu_iostream *sp = (struct _mu_iostream *)str; + mu_stream_unref (sp->transport[_MU_STREAM_INPUT]); + if (sp->transport[_MU_STREAM_INPUT] != sp->transport[_MU_STREAM_OUTPUT]) + mu_stream_unref (sp->transport[_MU_STREAM_OUTPUT]); +} + +static int +_iostream_ctl (struct _mu_stream *str, int op, void *arg) +{ + struct _mu_iostream *sp = (struct _mu_iostream *)str; + mu_transport_t *ptrans; + + switch (op) + { + case MU_IOCTL_GET_TRANSPORT: + if (!arg) + return EINVAL; + ptrans = arg; + ptrans[0] = (mu_transport_t) sp->transport[_MU_STREAM_INPUT]; + ptrans[1] = (mu_transport_t) sp->transport[_MU_STREAM_OUTPUT]; + break; + + case MU_IOCTL_SET_TRANSPORT: + if (!arg) + return EINVAL; + ptrans = arg; + sp->transport[_MU_STREAM_INPUT] = (mu_stream_t) ptrans[0]; + sp->transport[_MU_STREAM_OUTPUT] = (mu_stream_t) ptrans[1]; + break; + + default: + return EINVAL; + } + return 0; +} + +static int +_iostream_wait (struct _mu_stream *str, int *pflags, struct timeval *tvp) +{ + struct _mu_iostream *sp = (struct _mu_iostream *)str; + int rc = EINVAL; + + if (*pflags == MU_STREAM_READY_RD) + { + rc = mu_stream_wait (sp->transport[_MU_STREAM_INPUT], pflags, tvp); + if (rc) + sp->last_err_str = _MU_STREAM_INPUT; + } + else if (*pflags == MU_STREAM_READY_WR) + { + rc = mu_stream_wait (sp->transport[_MU_STREAM_OUTPUT], pflags, tvp); + if (rc) + sp->last_err_str = _MU_STREAM_OUTPUT; + } + return rc; +} + +static int +_iostream_shutdown (struct _mu_stream *str, int how) +{ + struct _mu_iostream *sp = (struct _mu_iostream *)str; + int rc = EINVAL; + switch (how) + { + case MU_STREAM_READ: + rc = mu_stream_shutdown (sp->transport[_MU_STREAM_INPUT], how); + if (rc) + sp->last_err_str = _MU_STREAM_INPUT; + break; + + case MU_STREAM_WRITE: + rc = mu_stream_shutdown (sp->transport[_MU_STREAM_OUTPUT], how); + if (rc) + sp->last_err_str = _MU_STREAM_OUTPUT; + } + return rc; +} + +static const char * +_iostream_error_string (struct _mu_stream *str, int rc) +{ + struct _mu_iostream *sp = (struct _mu_iostream *)str; + mu_stream_t transport = sp->transport[sp->last_err_str]; + if (transport) + return mu_stream_strerror (transport, rc); + return mu_strerror (rc); +} + +int +mu_iostream_create (mu_stream_t *pref, mu_stream_t in, mu_stream_t out, + int flags) +{ + struct _mu_iostream *sp; + + sp = (struct _mu_iostream *) + _mu_stream_create (sizeof (*sp), + MU_STREAM_READ | MU_STREAM_WRITE | + (flags & MU_STREAM_NO_CLOSE)); + if (!sp) + return ENOMEM; + + sp->stream.read = _iostream_read; + sp->stream.readdelim = _iostream_readdelim; + sp->stream.write = _iostream_write; + sp->stream.flush = _iostream_flush; + sp->stream.open = _iostream_open; + sp->stream.close = _iostream_close; + sp->stream.done = _iostream_done; + sp->stream.ctl = _iostream_ctl; + sp->stream.wait = _iostream_wait; + sp->stream.shutdown = _iostream_shutdown; + sp->stream.error_string = _iostream_error_string; + + mu_stream_ref (in); + sp->transport[_MU_STREAM_INPUT] = in; + mu_stream_ref (out); + sp->transport[_MU_STREAM_OUTPUT] = out; + + mu_stream_set_buffer ((mu_stream_t) sp, mu_buffer_line, 1024); + *pref = (mu_stream_t) sp; + return 0; +} + + diff --git a/mailbox/mapfile_stream.c b/mailbox/mapfile_stream.c index 89b3e47..aeb85e5 100644 --- a/mailbox/mapfile_stream.c +++ b/mailbox/mapfile_stream.c @@ -209,13 +209,13 @@ static int _mapfile_ioctl (struct _mu_stream *str, int code, void *ptr) { struct _mu_mapfile_stream *mfs = (struct _mu_mapfile_stream *) str; - mu_transport_t (*ptrans)[2]; + mu_transport_t ptrans[2]; switch (code) { case MU_IOCTL_GET_TRANSPORT: - (*ptrans)[0] = (mu_transport_t) mfs->fd; - (*ptrans)[1] = NULL; + ptrans[0] = (mu_transport_t) mfs->fd; + ptrans[1] = NULL; break; default: diff --git a/mailbox/memory_stream.c b/mailbox/memory_stream.c index ecb091f..19d4590 100644 --- a/mailbox/memory_stream.c +++ b/mailbox/memory_stream.c @@ -147,7 +147,7 @@ static int _memory_ioctl (struct _mu_stream *stream, int code, void *ptr) { struct _mu_memory_stream *mfs = (struct _mu_memory_stream *) stream; - mu_transport_t (*ptrans)[2]; + mu_transport_t *ptrans; switch (code) { @@ -155,8 +155,8 @@ _memory_ioctl (struct _mu_stream *stream, int code, void *ptr) if (!ptr) return EINVAL; ptrans = ptr; - (*ptrans)[0] = (mu_transport_t) mfs->ptr; - (*ptrans)[1] = NULL; + ptrans[0] = (mu_transport_t) mfs->ptr; + ptrans[1] = NULL; break; default: diff --git a/mailbox/prog_stream.c b/mailbox/prog_stream.c index 7c65940..4c0bb8e 100644 --- a/mailbox/prog_stream.c +++ b/mailbox/prog_stream.c @@ -367,7 +367,7 @@ _prog_ioctl (struct _mu_stream *str, int code, void *ptr) { struct _mu_prog_stream *fstr = (struct _mu_prog_stream *) str; mu_transport_t t[2]; - mu_transport_t (*ptrans)[2]; + mu_transport_t *ptrans; switch (code) { @@ -375,9 +375,9 @@ _prog_ioctl (struct _mu_stream *str, int code, void *ptr) if (!ptr) return EINVAL; mu_stream_ioctl (fstr->in, MU_IOCTL_GET_TRANSPORT, t); - (*ptrans)[0] = t[0]; + ptrans[0] = t[0]; mu_stream_ioctl (fstr->out, MU_IOCTL_GET_TRANSPORT, t); - (*ptrans)[1] = t[1]; + ptrans[1] = t[1]; break; case MU_IOCTL_GET_STATUS: diff --git a/mailbox/stream_vprintf.c b/mailbox/stream_vprintf.c index db0bff3..5bd9c09 100644 --- a/mailbox/stream_vprintf.c +++ b/mailbox/stream_vprintf.c @@ -37,6 +37,6 @@ mu_stream_vprintf (mu_stream_t str, const char *fmt, va_list ap) n = strlen (buf); rc = mu_stream_write (str, buf, n, NULL); free (buf); - return rc == 0 ? n : -1; + return rc; } diff --git a/mailbox/tcp.c b/mailbox/tcp.c index a03eedb..0810728 100644 --- a/mailbox/tcp.c +++ b/mailbox/tcp.c @@ -196,7 +196,7 @@ static int _tcp_ioctl (mu_stream_t stream, int code, void *ptr) { struct _tcp_instance *tcp = (struct _tcp_instance *)stream; - mu_transport_t (*ptrans)[2]; + mu_transport_t *ptrans; switch (code) { @@ -204,8 +204,8 @@ _tcp_ioctl (mu_stream_t stream, int code, void *ptr) if (!ptr) return EINVAL; ptrans = ptr; - (*ptrans)[0] = (mu_transport_t) tcp->fd; - (*ptrans)[1] = NULL; + ptrans[0] = (mu_transport_t) tcp->fd; + ptrans[1] = NULL; break; default: diff --git a/mailbox/xscript-stream.c b/mailbox/xscript-stream.c new file mode 100644 index 0000000..c3a5c40 --- /dev/null +++ b/mailbox/xscript-stream.c @@ -0,0 +1,300 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 1999, 2000, 2001, 2002, 2004, + 2005, 2006, 2007, 2008, 2009, 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, 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 GNU Mailutils. 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/types.h> +#include <mailutils/alloc.h> +#include <mailutils/errno.h> + +#include <mailutils/nls.h> +#include <mailutils/stream.h> +#include <mailutils/sys/stream.h> +#include <mailutils/sys/xscript-stream.h> + +/* A "transcript stream" transparently writes data to and reads data from + an underlying transport stream, writing each lineful of data to a "log + stream". Writes to log stream are prefixed with a string indicating + direction of the data (read/write). Default prefixes are those used in + RFCs -- "S: ", for data written ("Server"), and "C: ", for data read + ("Client"). */ + +#define TRANS_READ 0x1 +#define TRANS_WRITE 0x2 +#define FLAG_TO_PFX(c) ((c) - 1) + +static void +print_transcript (struct _mu_xscript_stream *str, int flag, + const char *buf, size_t size) +{ + while (size) + { + const char *p; + size_t len; + + if (str->flags & flag) + { + mu_stream_write (str->logstr, + str->prefix[FLAG_TO_PFX(flag)], + strlen (str->prefix[FLAG_TO_PFX (flag)]), + NULL); + str->flags &= ~flag; + } + p = memchr (buf, '\n', size); + if (p) + { + len = p - buf; + if (p > buf && p[-1] == '\r') + len--; + mu_stream_write (str->logstr, buf, len, NULL); + mu_stream_write (str->logstr, "\n", 1, NULL); + str->flags |= flag; + + len = p - buf + 1; + buf = p + 1; + size -= len; + } + else + { + mu_stream_write (str->logstr, buf, size, NULL); + break; + } + } +} + +static int +_xscript_read (struct _mu_stream *str, char *buf, size_t bufsize, + size_t *pnread) +{ + struct _mu_xscript_stream *sp = (struct _mu_xscript_stream *)str; + size_t nbytes; + int rc = mu_stream_read (sp->transport, buf, bufsize, &nbytes); + + if (rc == 0) + { + print_transcript (sp, TRANS_READ, buf, nbytes); + if (pnread) + *pnread = nbytes; + } + return rc; +} + +static int +_xscript_readdelim (struct _mu_stream *str, char *buf, size_t bufsize, + int delim, size_t *pnread) +{ + struct _mu_xscript_stream *sp = (struct _mu_xscript_stream *)str; + size_t nread; + int rc = mu_stream_readdelim (sp->transport, buf, bufsize, delim, &nread); + if (rc == 0) + { + print_transcript (sp, TRANS_READ, buf, nread); + if (pnread) + *pnread = nread; + } + return rc; +} + +static int +_xscript_write (struct _mu_stream *str, const char *buf, size_t bufsize, + size_t *pnwrite) +{ + struct _mu_xscript_stream *sp = (struct _mu_xscript_stream *)str; + int rc = mu_stream_write (sp->transport, buf, bufsize, pnwrite); + + if (rc == 0) + print_transcript (sp, TRANS_WRITE, buf, pnwrite ? *pnwrite : bufsize); + return rc; +} + +static int +_xscript_flush (struct _mu_stream *str) +{ + struct _mu_xscript_stream *sp = (struct _mu_xscript_stream *)str; + return mu_stream_flush (sp->transport); +} + +static int +_xscript_open (struct _mu_stream *str) +{ + struct _mu_xscript_stream *sp = (struct _mu_xscript_stream *)str; + return mu_stream_open (sp->transport); +} + +static int +_xscript_close (struct _mu_stream *str) +{ + struct _mu_xscript_stream *sp = (struct _mu_xscript_stream *)str; + if (sp->stream.flags & MU_STREAM_NO_CLOSE) + return 0; + return mu_stream_close (sp->transport); +} + +static void +_xscript_done (struct _mu_stream *str) +{ + struct _mu_xscript_stream *sp = (struct _mu_xscript_stream *)str; + free (sp->prefix[0]); + free (sp->prefix[1]); + mu_stream_unref (sp->transport); + mu_stream_unref (sp->logstr); +} + +static int +_xscript_seek (struct _mu_stream *str, mu_off_t off, mu_off_t *ppos) +{ + struct _mu_xscript_stream *sp = (struct _mu_xscript_stream *)str; + return mu_stream_seek (sp->transport, off, MU_SEEK_SET, ppos); +} + +static int +_xscript_size (struct _mu_stream *str, mu_off_t *psize) +{ + struct _mu_xscript_stream *sp = (struct _mu_xscript_stream *)str; + return mu_stream_size (sp->transport, psize); +} + +static int +_xscript_ctl (struct _mu_stream *str, int op, void *arg) +{ + struct _mu_xscript_stream *sp = (struct _mu_xscript_stream *)str; + mu_transport_t *ptrans; + + switch (op) + { + case MU_IOCTL_GET_TRANSPORT: + if (!arg) + return EINVAL; + ptrans = arg; + ptrans[0] = (mu_transport_t) sp->transport; + ptrans[1] = (mu_transport_t) sp->logstr; + break; + + case MU_IOCTL_SET_TRANSPORT: + if (!arg) + return EINVAL; + ptrans = arg; + if (ptrans[0]) + sp->transport = (mu_stream_t) ptrans[0]; + if (ptrans[1]) + sp->logstr = (mu_stream_t) ptrans[1]; + break; + + default: + return mu_stream_ioctl (sp->transport, op, arg); + } + return 0; +} + +static int +_xscript_wait (struct _mu_stream *str, int *pflags, struct timeval *tvp) +{ + struct _mu_xscript_stream *sp = (struct _mu_xscript_stream *)str; + return mu_stream_wait (sp->transport, pflags, tvp); +} + +static int +_xscript_truncate (struct _mu_stream *str, mu_off_t size) +{ + struct _mu_xscript_stream *sp = (struct _mu_xscript_stream *)str; + return mu_stream_truncate (sp->transport, size); +} + +static int +_xscript_shutdown (struct _mu_stream *str, int how) +{ + struct _mu_xscript_stream *sp = (struct _mu_xscript_stream *)str; + return mu_stream_shutdown (sp->transport, how); +} + +static const char * +_xscript_error_string (struct _mu_stream *str, int rc) +{ + struct _mu_xscript_stream *sp = (struct _mu_xscript_stream *)str; + const char *p = mu_stream_strerror (sp->transport, rc); + if (!p) + p = mu_strerror (rc); + return p; +} + +const char *default_prefix[2] = { + "C: ", "S: " +}; + +int +mu_xscript_stream_create(mu_stream_t *pref, mu_stream_t transport, + mu_stream_t logstr, + const char *prefix[]) +{ + int flags; + struct _mu_xscript_stream *sp; + + mu_stream_get_flags (transport, &flags); + sp = (struct _mu_xscript_stream *) _mu_stream_create (sizeof (*sp), flags); + if (!sp) + return ENOMEM; + + sp->stream.read = _xscript_read; + sp->stream.readdelim = _xscript_readdelim; + sp->stream.write = _xscript_write; + sp->stream.flush = _xscript_flush; + sp->stream.open = _xscript_open; + sp->stream.close = _xscript_close; + sp->stream.done = _xscript_done; + sp->stream.seek = _xscript_seek; + sp->stream.size = _xscript_size; + sp->stream.ctl = _xscript_ctl; + sp->stream.wait = _xscript_wait; + sp->stream.truncate = _xscript_truncate; + sp->stream.shutdown = _xscript_shutdown; + sp->stream.error_string = _xscript_error_string; + + mu_stream_ref (transport); + sp->transport = transport; + mu_stream_ref (logstr); + sp->logstr = logstr; + + sp->flags = TRANS_READ | TRANS_WRITE; + if (prefix) + { + sp->prefix[0] = strdup(prefix[0] ? prefix[0] : default_prefix[0]); + sp->prefix[1] = strdup(prefix[1] ? prefix[1] : default_prefix[1]); + } + else + { + sp->prefix[0] = strdup(default_prefix[0]); + sp->prefix[1] = strdup(default_prefix[1]); + } + + if (sp->prefix[0] == NULL || sp->prefix[1] == 0) + { + free (sp->prefix[0]); + free (sp->prefix[1]); + free (sp); + return ENOMEM; + } + mu_stream_set_buffer ((mu_stream_t) sp, mu_buffer_line, 1024); + *pref = (mu_stream_t) sp; + return 0; +} + + diff --git a/pop3d/extra.c b/pop3d/extra.c index 2ab0f8a..ea0929f 100644 --- a/pop3d/extra.c +++ b/pop3d/extra.c @@ -20,7 +20,7 @@ #include "pop3d.h" #include "mailutils/libargp.h" -mu_stream_t istream, ostream; +mu_stream_t iostream; void pop3d_parse_command (char *cmd, char **pcmd, char **parg) @@ -132,12 +132,12 @@ pop3d_abquit (int reason) FIXME: This is sorta kludge: we could use MU_IOCTL_GET_TRANSPORT call to retrieve the bottom-level stream, if filter streams supported it. */ -static mu_stream_t real_ostream; +static mu_stream_t real_istream, real_ostream; void pop3d_setio (FILE *in, FILE *out) { - mu_stream_t str; + mu_stream_t str, istream, ostream; if (!in) pop3d_abquit (ERR_NO_IFILE); @@ -147,6 +147,7 @@ pop3d_setio (FILE *in, FILE *out) if (mu_stdio_stream_create (&istream, fileno (in), MU_STREAM_READ | MU_STREAM_NO_CLOSE)) pop3d_abquit (ERR_NO_IFILE); + real_istream = istream; mu_stream_set_buffer (istream, mu_buffer_line, 1024); if (mu_stdio_stream_create (&str, fileno (out), @@ -157,6 +158,32 @@ pop3d_setio (FILE *in, FILE *out) MU_STREAM_WRITE | MU_STREAM_NO_CLOSE)) pop3d_abquit (ERR_NO_IFILE); mu_stream_set_buffer (ostream, mu_buffer_line, 1024); + + if (mu_iostream_create (&iostream, istream, ostream, 0)) + pop3d_abquit (ERR_FILE); + if (pop3d_transcript) + { + int rc; + mu_debug_t debug; + mu_stream_t dstr, xstr; + + mu_diag_get_debug (&debug); + + rc = mu_dbgstream_create (&dstr, debug, MU_DIAG_DEBUG, + MU_STREAM_NO_CLOSE); + if (rc) + mu_error (_("cannot create debug stream; transcript disabled: %s"), + mu_strerror (rc)); + else + { + rc = mu_xscript_stream_create (&xstr, iostream, dstr, NULL); + if (rc) + mu_error (_("cannot create transcript stream: %s"), + mu_strerror (rc)); + else + iostream = xstr; + } + } } #ifdef WITH_TLS @@ -166,37 +193,44 @@ pop3d_init_tls_server () mu_stream_t stream; int rc; - rc = mu_tls_server_stream_create (&stream, istream, real_ostream, 0); + rc = mu_tls_server_stream_create (&stream, real_istream, real_ostream, + MU_STREAM_NO_CLOSE); if (rc) - return 0; + return 1; rc = mu_stream_open (stream); if (rc) { mu_diag_output (MU_DIAG_ERROR, _("cannot open TLS stream: %s"), mu_stream_strerror (stream, rc)); - return 0; + mu_stream_destroy (&stream); + return 1; } - - istream = stream; - mu_stream_destroy (&ostream); - if (mu_filter_create (&ostream, stream, "rfc822", MU_FILTER_ENCODE, - MU_STREAM_WRITE | MU_STREAM_NO_CLOSE)) + + if (mu_filter_create (&stream, stream, "rfc822", MU_FILTER_ENCODE, + MU_STREAM_WRITE | MU_STREAM_RDTHRU | + MU_STREAM_NO_CLOSE)) pop3d_abquit (ERR_NO_IFILE); - mu_stream_set_buffer (ostream, mu_buffer_line, 1024); - return 1; + + if (pop3d_transcript) + { + mu_transport_t trans[2]; + + trans[0] = (mu_transport_t) stream; + trans[1] = NULL; + mu_stream_ioctl (iostream, MU_IOCTL_SET_TRANSPORT, trans); + } + else + iostream = stream; + return 0; } #endif void pop3d_bye () { - if (istream == ostream) - { - mu_stream_close (istream); - mu_stream_destroy (&istream); - } - /* There's no reason closing in/out streams otherwise */ + mu_stream_close (iostream); + mu_stream_destroy (&iostream); #ifdef WITH_TLS if (tls_available) mu_deinit_tls_libs (); @@ -206,53 +240,28 @@ pop3d_bye () void pop3d_flush_output () { - mu_stream_flush (ostream); + mu_stream_flush (iostream); } int pop3d_is_master () { - return ostream == NULL; -} - -static void -transcript (const char *pfx, const char *buf) -{ - if (pop3d_transcript) - { - int len = strlen (buf); - if (len > 0 && buf[len-1] == '\n') - { - len--; - if (len > 0 && buf[len-1] == '\r') - len--; - } - mu_diag_output (MU_DIAG_DEBUG, "%s: %-.*s", pfx, len, buf); - } + return iostream == NULL; } void pop3d_outf (const char *fmt, ...) { va_list ap; - char *buf; int rc; va_start (ap, fmt); - vasprintf (&buf, fmt, ap); + rc = mu_stream_vprintf (iostream, fmt, ap); va_end (ap); - - if (!buf) - pop3d_abquit (ERR_NO_MEM); - - transcript ("sent", buf); - - rc = mu_stream_write (ostream, buf, strlen (buf), NULL); - free (buf); if (rc) { mu_diag_output (MU_DIAG_ERROR, _("Write failed: %s"), - mu_stream_strerror (ostream, rc)); + mu_stream_strerror (iostream, rc)); pop3d_abquit (ERR_IO); } } @@ -265,13 +274,13 @@ pop3d_readline (char *buffer, size_t size) size_t nbytes; alarm (idle_timeout); - rc = mu_stream_readline (istream, buffer, size, &nbytes); + rc = mu_stream_readline (iostream, buffer, size, &nbytes); alarm (0); if (rc) { mu_diag_output (MU_DIAG_ERROR, _("Read failed: %s"), - mu_stream_strerror (ostream, rc)); + mu_stream_strerror (iostream, rc)); pop3d_abquit (ERR_IO); } else if (nbytes == 0) @@ -285,8 +294,6 @@ pop3d_readline (char *buffer, size_t size) pop3d_abquit (ERR_PROTO); } - transcript ("recv", buffer); - return buffer; } diff --git a/pop3d/pop3d.h b/pop3d/pop3d.h index b7e593b..f77652f 100644 --- a/pop3d/pop3d.h +++ b/pop3d/pop3d.h @@ -189,7 +189,7 @@ struct pop3d_command pop3d_command_handler_t handler; }; -extern mu_stream_t istream, ostream; +extern mu_stream_t iostream; extern mu_pop_server_t pop3srv; extern mu_mailbox_t mbox; extern int state; diff --git a/pop3d/retr.c b/pop3d/retr.c index 53b25c0..5c30643 100644 --- a/pop3d/retr.c +++ b/pop3d/retr.c @@ -46,7 +46,7 @@ pop3d_retr (char *arg) return ERR_UNKNOWN; pop3d_outf ("+OK\n"); - mu_stream_copy (ostream, stream, 0); + mu_stream_copy (iostream, stream, 0); mu_stream_destroy (&stream); if (!mu_attribute_is_read (attr)) diff --git a/pop3d/stls.c b/pop3d/stls.c index 189bc7c..6a8bbf6 100644 --- a/pop3d/stls.c +++ b/pop3d/stls.c @@ -35,7 +35,7 @@ pop3d_stls (char *arg) pop3d_outf ("+OK Begin TLS negotiation\n"); pop3d_flush_output (); - tls_done = pop3d_init_tls_server (); + tls_done = pop3d_init_tls_server () == 0; if (!tls_done) { diff --git a/pop3d/top.c b/pop3d/top.c index 73d6a27..3716875 100644 --- a/pop3d/top.c +++ b/pop3d/top.c @@ -62,7 +62,7 @@ pop3d_top (char *arg) return ERR_UNKNOWN; pop3d_outf ("+OK\n"); - mu_stream_copy (ostream, stream, 0); + mu_stream_copy (iostream, stream, 0); pop3d_outf ("\n"); mu_stream_destroy (&stream); hooks/post-receive -- GNU Mailutils _______________________________________________ Commit-mailutils mailing list Commit-mailutils@gnu.org http://lists.gnu.org/mailman/listinfo/commit-mailutils