[SCM] GNU Mailutils branch, stream-cleanup, updated. rel-2_1-112-ga783f8c

"Sergey Poznyakoff" <[email protected]>
Newsgroups gmane.comp.gnu.mailutils.cvs
Message-ID <[email protected]>
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 <[email protected]>
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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.