commit-mailutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[SCM] GNU Mailutils branch, master, updated. release-2.2-59-g6cf8cbb


From: Sergey Poznyakoff
Subject: [SCM] GNU Mailutils branch, master, updated. release-2.2-59-g6cf8cbb
Date: Thu, 09 Sep 2010 08:32:37 +0000

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=6cf8cbbb057216f37008287a83d1c61908e21737

The branch, master has been updated
       via  6cf8cbbb057216f37008287a83d1c61908e21737 (commit)
       via  ab4d428ed68026a722481de0b8e44cab50224fa2 (commit)
       via  08dbbe2a422ee12fc9b80f2b7bd5d209b0812272 (commit)
       via  7bfe0ed907c5300d68fea2f2d4e53bac6dc78b60 (commit)
       via  62c5c62a7e8fd3524227cd241986d6ce4711b239 (commit)
       via  69f7dcae5a906acc9126ca25e33881cba944f85d (commit)
       via  b93556087280eab726c507486415385f996ebf54 (commit)
       via  d22b2199ab813bf994afc2dbe8e033ffcc01d045 (commit)
       via  b94a6d3cd2112e9b06f069e6ef9789cf6bc0d4e2 (commit)
       via  d01da801a3543c80e172992ffb7d26a8d128556b (commit)
       via  46e3b517d99ae4c24c000d893095168017129eb5 (commit)
       via  c97b96ae673278d60906314001aec978bdcf4485 (commit)
       via  81166ab69da9bb6cb5a2911107405a2362e200ee (commit)
       via  6c60ab472d3ded91bd212b9f140c5294dec59c9f (commit)
       via  1d6e52af3261347bb5bc3be8ef35f519ec99c412 (commit)
       via  02abfc4419cc651df0005a065f0db781dc884594 (commit)
       via  b5986a2df68af1d7217907f3c655f1ef59ebde5f (commit)
       via  d6153b1307bf9ab9242d4f9f76592d346ebc6ec1 (commit)
       via  29d2e3904c897c01191072db85985b93f9ea1704 (commit)
       via  baea3184ad1cf5c6124ac1697a52d782ed7bebab (commit)
       via  814b97914c8ac0177af4688e934511912733c314 (commit)
       via  cab810601ec85691494b1d3424b171b06b0c2348 (commit)
       via  400fdaaca90616a996f9a6fd230eb084aebb1bb8 (commit)
       via  c1d1ab07c72070d2ca92f729ab2454ad0b06f0ae (commit)
       via  3ffda3e10d5db2d26d739e37653cae22971e1741 (commit)
       via  cbc008712897959c17cde4b9afcb18925da267a7 (commit)
       via  dca7b761362545f359968be344267c3fd93cb935 (commit)
       via  66c992c3780eb1191c5644c4f3068da5abaae2ec (commit)
       via  c7491f228d5fce68e50192d26a98ecf8115f5283 (commit)
       via  e7b40d4ec935750c3a395d5f9853d6011883a135 (commit)
       via  2e58dde3af88615b3af67dcbae69aaaf5b120783 (commit)
       via  8355901b63008385294d0c4b79539d70cb8f5c90 (commit)
       via  5f0b1ed3c5d5276df98b20cb4bb020915b6a064c (commit)
       via  8f8e01b920d0601df5e60cd8060eba5909a10178 (commit)
       via  85b56e79be1935ba99df3574cf47cf19179cc3fe (commit)
       via  11c14a014892507f7fa1dca4610840a4e4668d43 (commit)
       via  1270a9f683827885e91a39e4088d2297af4b5987 (commit)
       via  012b6c7facbd39596a7bf9e8ac61c732c87a236a (commit)
       via  352c5e92e6d26701fccced669c40409d6010ff10 (commit)
       via  2203753f72c89a194889baa199a513e3ed02e5b3 (commit)
       via  0f2fc18ab5ef3bc518e9d37d422db0484b4cc8d3 (commit)
       via  c8abc2b1adfcddccf0e85caf44f3376aad11552c (commit)
       via  fa54cb19078773382fb1db24bbf450a9962e186d (commit)
       via  dfea400b082c5eff4f31c4fd0ac9e57756a04866 (commit)
       via  9b4deb97eec3c3efdb7b416bc6e357c33a632158 (commit)
       via  3fefeaa458075ca20381284950b32f6afdccfffe (commit)
       via  f96ce94e2ad041c0f6011eafb74e1799e1f90eb0 (commit)
       via  03aa45f1aafdfb3eaea8a56fb092ec091694c432 (commit)
       via  3f4567b725d10dba3f179c7220ce275c8ffe8085 (commit)
       via  e71e1073a09547a195a1cc070ed825e651b8c415 (commit)
       via  b5ddabd7415663a140bdb9daf97577db26116c4e (commit)
       via  d17ec29ca42139df7588ee4f85bbeb8bd20c93e8 (commit)
       via  3437509ff40a5e7cc86f8b26fb182592cab43b74 (commit)
       via  7220d9ddf7abd7ec0cb499194b3272467b4bf91c (commit)
       via  1f4deff1e92e2c23020dcf93f3836895d6b6ac5d (commit)
       via  0c013ac57ef780d2d6f2a9b389b1c754b5c29033 (commit)
       via  f900b3b06e7748b04fd31a4bfc3c3c82272f019e (commit)
       via  d976d8a10c7930658054733e3173d4b45355f61e (commit)
       via  d7a596df78be3863fd7a71977e99332eac38bda5 (commit)
      from  5124a1e140db914eec9bc1dbe52eb02409ec4acd (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 6cf8cbbb057216f37008287a83d1c61908e21737
Author: Sergey Poznyakoff <address@hidden>
Date:   Thu Sep 9 11:31:41 2010 +0300

    Remove leftovers of ARG_LICENSE option from MH.

commit ab4d428ed68026a722481de0b8e44cab50224fa2
Author: Sergey Poznyakoff <address@hidden>
Date:   Tue Sep 7 22:54:40 2010 +0300

    Rename XSCRIPT_ macros to MU_XSCRIPT.

commit 08dbbe2a422ee12fc9b80f2b7bd5d209b0812272
Author: Sergey Poznyakoff <address@hidden>
Date:   Tue Sep 7 18:06:11 2010 +0300

    Improve transcript stream.
    
    * include/mailutils/stream.h (MU_IOCTL_LEVEL): New ioctl op.
    (XSCRIPT_NORMAL, XSCRIPT_SECURE, XSCRIPT_PAYLOAD): New constants.
    * include/mailutils/sys/xscript-stream.h (_mu_xscript_stream)
    <level>: New member.
    * mailbox/xscript-stream.c (TRANS_DISABLED): New flag.
    (print_transcript): Amount of output varies depending on the
    current output level.  For secure data, try to recognize passwords
    and to replace them with *** on output.
    (_xscript_ctl): Support MU_IOCTL_LEVEL.
    * pop3d/extra.c (set_xscript_level): New function.
    * pop3d/pop3d.h (set_xscript_level): New proto.
    * pop3d/retr.c (pop3d_retr): Set XSCRIPT_PAYLOAD level before
    sending actual data and reset it to XSCRIPT_NORMAL afterwards.
    * pop3d/top.c (pop3d_top): Likewise.
    * pop3d/user.c: Set XSCRIPT_SECURE level while expecting the
    PASS command.
    
    * imap4d/fetch.c (imap4d_fetch): Run imap4d_fetch0 in XSCRIPT_PAYLOAD
    level.
    * imap4d/uid.c (imap4d_uid): Likewise.
    * imap4d/imap4d.c (imap4d_mainloop): Unless started in preauth mode,
    select XSCRIPT_SECURE mode until authentication has been passed.
    * imap4d/imap4d.h (set_xscript_level): New proto.
    * imap4d/io.c (io_format_completion_response): Switch to XSCRIPT_NORMAL
    level when changing to the authenticated state.
    (imap4d_readline): Read literals in XSCRIPT_PAYLOAD level.
    * imap4d/util.c (set_xscript_level): New function.
    
    * include/mailutils/pop3.h (mu_pop3_trace_mask): New prototype.
    (MU_POP3_XSCRIPT_MASK): New macro.
    (_mu_pop3_xscript_level): New proto.
    * libproto/pop/pop3_pass.c (mu_pop3_pass): Set XSCRIPT_SECURE
    while sending the password.
    * libproto/pop/pop3_retr.c (mu_pop3_retr): Set XSCRIPT_PAYLOAD before
    going to MU_POP3_RETR_RX state.
    * libproto/pop/pop3_stream.c (_pop3_event_cb): Set XSCRIPT_NORMAL.
    * libproto/pop/pop3_top.c (mu_pop3_top): Set XSCRIPT_PAYLOAD before
    going to MU_POP3_TOP_RX state.
    * libproto/pop/pop3_trace.c (mu_pop3_trace_mask)
    (_mu_pop3_xscript_level): New functions.
    * libproto/pop/mbox.c (pop_open): Set trace masks depending on the
    trace6 and trace7 debug levels.
    
    * examples/pop3client.c (com_verbose): Allow to mask/unmask transcript
    levels.

commit 7bfe0ed907c5300d68fea2f2d4e53bac6dc78b60
Author: Sergey Poznyakoff <address@hidden>
Date:   Tue Sep 7 13:57:30 2010 +0300

    Finish pop3 mailbox implementation.
    
    * mailbox/msgscan.c: New file.
    * mailbox/Makefile.am (libmailutils_la_SOURCES): Add it.
    
    * include/mailutils/body.h (mu_body_set_get_stream): New prototype.
    * include/mailutils/message.h (MU_SCAN_SEEK, MU_SCAN_SIZE): New
    defines.
    (mu_message_scan): New structure.
    (mu_stream_scan_message): New prototype.
    (mu_message_set_get_stream): New prototype.
    * include/mailutils/stream.h (mu_stream_copy): Change signature: takes
    4 arguments now.
    * include/mailutils/sys/body.h (_mu_body) <_get_stream>: New method.
    * include/mailutils/sys/message.h (_mu_message) <_get_stream>: New method.
    * mailbox/body.c (_body_get_stream): Call _get_stream, if provided.
    * mailbox/message.c (_message_get_stream): Call _get_stream, if provided.
    
    * mailbox/stream.c (_stream_flush_buffer): Avoid infinite recursion:
    call stream->seek directly.
    * mailbox/streamcpy.c (mu_stream_copy): Return the number of bytes
    actually copied in the fourth argument. All uses updated.
    * mailbox/streamref.c (streamref_return): Do not propagate internal
    flags.
    (_streamref_readdelim): Ensure there is enough buffer space for the
    mu_stream_readdelim call.
    
    * libproto/pop/mbox.c: Finish client implementation.
    
    * mail/print.c (mail_print_msg): Close pager before returning on
    error.

commit 62c5c62a7e8fd3524227cd241986d6ce4711b239
Author: Sergey Poznyakoff <address@hidden>
Date:   Mon Sep 6 19:18:32 2010 +0300

    Implement "read cache" streams. Rewrite stdio and socket streams.
    
    * include/mailutils/sys/stdio_stream.h: Remove.
    * include/mailutils/sys/socket_stream.h: Remove.
    * include/mailutils/sys/rdcache_stream.h: New file.
    * include/mailutils/sys/Makefile.am: Update.
    * mailbox/rdcache_stream.c: New file.
    * mailbox/Makefile.am: Update.
    
    * examples/mucat.c: New example.
    * examples/musocio.c: New example.
    * examples/Makefile.am (noinst_PROGRAMS): Build new examples.
    
    * include/mailutils/stream.h (mu_fd_stream_create): New proto.
    (mu_rdcache_stream_create): New proto.
    * include/mailutils/sys/file_stream.h (_mu_file_stream_create): Change
    prototype.
    * mailbox/file_stream.c (fd_open): Raise the MU_STREAM_AUTOCLOSE bit.
    (fd_ioctl): Support MU_IOCTL_SET_TRANSPORT.
    (_mu_file_stream_create): Change signature. All uses updated.
    Allocate a copy of the filename argument, unless it is NULL.
    (mu_fd_stream_create): New function.
    
    * mailbox/socket_stream.c: Rewrite using file_stream directly.
    * mailbox/stdio_stream.c: Rewrite. Use rdcache_stream if
    the seek capability is required on an input stream.
    * mailbox/streamcpy.c (mu_stream_copy): Handle eventual
    EACCES return from mu_stream_seek as equivalent to ENOSYS.

commit 69f7dcae5a906acc9126ca25e33881cba944f85d
Author: Sergey Poznyakoff <address@hidden>
Date:   Mon Sep 6 02:00:20 2010 +0300

    Further improvements in pop3client: readline & history.

commit b93556087280eab726c507486415385f996ebf54
Author: Sergey Poznyakoff <address@hidden>
Date:   Sun Sep 5 23:49:54 2010 +0300

    Begin rewriting pop3 mailbox support. Several bugfixes.
    
    * examples/pop3client.c (com_capa): Call mu_pop3_capa_test.
    (com_stat): Count is size_t.
    
    * include/mailutils/opool.h (mu_opool_copy): New proto.
    * mailbox/opool.c (mu_opool_copy): New function.
    * mailbox/xscript-stream.c (_xscript_ctl)
    <MU_IOCTL_SWAP_STREAM>: Avoid coredumping if sp->transport
    is NULL.
    
    * include/mailutils/pop3.h (pop3_capa_test): Rename to
    mu_pop3_capa_test.
    (mu_pop3_stat): Third argument is a pointer to mu_off_t.
    * libproto/pop/pop3_capatst.c (pop3_capa_test): Rename to
    mu_pop3_capa_test.
    * libproto/pop/pop3_stat.c (mu_pop3_stat): Third argument is
    a pointer to mu_off_t.
    
    * libproto/pop/Makefile.am (libmu_pop_la_SOURCES): Put back
    folder.c, url.c and mbox.c.
    * libproto/pop/mbox.c: Begin rewriting.

commit d22b2199ab813bf994afc2dbe8e033ffcc01d045
Author: Sergey Poznyakoff <address@hidden>
Date:   Sun Sep 5 20:14:53 2010 +0300

    Minor change in stream API.  Improve POP3 client interface.
    
    * include/mailutils/sys/stream.h (_MU_STR_EVENT_SET)
    (_MU_STR_EVENT_CLR): New defines.
    (_mu_stream) <event_cb, event_mask>: New members.
    * mailbox/stream.c (_stream_setflag, _stream_clrflag): New static
    functions.
    All functions use these instead of setting/clearing flags directly.
    (_mu_stream_cleareof, _mu_stream_seteof): New extern functions.
    (_stream_cleareof): Remove define, use _mu_stream_cleareof instead.
    (_stream_fill_buffer): Set EOF marker when end of stream is reached.
    
    * mailbox/fltstream.c (filter_read): Call _mu_stream_seteof to set
    EOF flag.
    
    * include/mailutils/pop3.h: Get rid of the superfluous "extern" in
    front of function prototypes.
    Add new prototypes.
    Remove extra whitespace.
    
    * libproto/pop/pop3_capatst.c: New file.
    * libproto/pop/pop3_list_cmd.c: New file.
    * libproto/pop/pop3_listas.c: New file.
    * libproto/pop/pop3_rdlist.c: New file.
    * libproto/pop/pop3_uidl_cmd.c: New file.
    * libproto/pop/pop3_uidlas.c: New file.
    * libproto/pop/Makefile.am: Add new files.
    * libproto/pop/pop3_capa.c (_mu_pop3_fill_list): Remove.
    Use mu_pop3_read_list instead.
    (capa_comp): New comparator for capa lists.
    * libproto/pop/pop3_list.c (mu_pop3_list): Fix format specifier.
    * libproto/pop/pop3_lista.c (mu_pop3_list_all): Rewrite.
    * libproto/pop/pop3_retr.c (mu_pop3_retr) <MU_POP3_RETR_RX>: do not
    reset state, this is done by the EOF event callback.
    * libproto/pop/pop3_top.c (mu_pop3_top) <MU_POP3_TOP_RX>: Likewise.
    * libproto/pop/pop3_stream.c (pop3_decode_state): New state pds_char.
    Change semantics of pds_init.
    (newstate, _pop3_decoder): Handle .\r\n in the initial state.
    (_pop3_event_cb): New event callback.
    (mu_pop3_filter_create): Set event callback on the filter stream.
    * libproto/pop/pop3_uidla.c (mu_pop3_uidl_all): Rewrite.
    
    * examples/Makefile.am (pop3client_CPPFLAGS): Add MU_APP_COMMON_INCLUDES.
    * examples/pop3client.c: Rewrite command parser.

commit b94a6d3cd2112e9b06f069e6ef9789cf6bc0d4e2
Author: Sergey Poznyakoff <address@hidden>
Date:   Sun Sep 5 12:38:39 2010 +0300

    Further fixes in pop3.
    
    * libproto/pop/pop3_create.c (_mu_pop3_init): Fix return value.
    * libproto/pop/pop3_destroy.c: Add missing includes.
    * libproto/pop/pop3_stream.c (_pop3_decoder): Remove the final
    .\r\n altogether.
    * mailbox/fltstream.c (filter_read): Remove the hack for supporting
    buggy filters.

commit d01da801a3543c80e172992ffb7d26a8d128556b
Author: Sergey Poznyakoff <address@hidden>
Date:   Sun Sep 5 12:38:20 2010 +0300

    Fix TLS support in smtp.
    
    * include/mailutils/tls.h (mu_tls_readline_fn)
    (mu_tls_writeline_fn, mu_tls_stream_ctl_fn): Remove typedefs.
    (mu_tls_begin): Remove prototype.
    * libmu_auth/tls.c (mu_tls_begin): Remove function.
    * libproto/mailer/smtp.c: Revamp STARTTLS support.

commit 46e3b517d99ae4c24c000d893095168017129eb5
Author: Sergey Poznyakoff <address@hidden>
Date:   Sun Sep 5 02:26:51 2010 +0300

    Re-implement pop3 client functions.
    
    * include/mailutils/filter.h (mu_filter_io) <eof>: New member.
    * mailbox/fltstream.c (init_iobuf): Initialize eof to 0.
    (filter_read): Break the loop if the decoder has set eof.
    * mailbox/xscript-stream.c (_xscript_ctl) <MU_IOCTL_SWAP_STREAM>: Handle
    a special case when the transport does not support stream swapping.
    
    * include/mailutils/pop3.h (mu_pop3_set_debug): Remove.
    (MU_POP3_TRACE_CLR, MU_POP3_TRACE_SET, MU_POP3_TRACE_QRY): New macros.
    (mu_pop3_trace): New proto.
    (mu_pop3_readline): Remove.
    (mu_pop3_getline): New proto.
    (mu_pop3_capa): Change signature.
    * include/mailutils/sys/pop3.h (mu_pop3_state): Remove the *_ACK states.
    (mu_pop3_work_buf): Remove.
    (MU_POP3_ACK, MU_POP3_TRACE): New defines.
    (_mu_pop3): Rewrite the structure.
    (mu_pop3_debug_cmd, mu_pop3_debug_ack): Remove functions.
    (MU_POP3_FISSET, MU_POP3_FSET, MU_POP3_FCLR): New macros.
    (_mu_pop3_trace_enable, _mu_pop3_trace_disable)
    (_mu_pop3_init): New protos.
    
    * include/mailutils/tls.h (mu_tls_stream_ctl_fn)
    (mu_tls_writeline_fn): Change typedefs.
    * libmu_auth/tls.c (mu_tls_begin): Update function calls
    accordingly.
    
    * libproto/pop/pop3_debug.c: Remove.
    * libproto/pop/pop3_trace.c: New function.
    * libproto/pop/Makefile.am (libmu_pop_la_SOURCES): Temporarly
    comment out folder.c, mbox.c and url.c.
    Remove pop3_debug.c.
    Add pop3_trace.c.
    * libproto/pop/pop3_capa.c: Rewrite.
    * libproto/pop/pop3_create.c: Rewrite.
    * libproto/pop/pop3_iterator.c: Rewrite.
    * libproto/pop/pop3_response.c: Rewrite.
    * libproto/pop/pop3_sendline.c: Rewrite.
    * libproto/pop/pop3_stls.c: Rewrite.
    * libproto/pop/pop3_stream.c: Rewrite.
    * libproto/pop/pop3_apop.c: Reflect changes to the pop3 framework.
    * libproto/pop/pop3_carrier.c: Likewise.
    * libproto/pop/pop3_connect.c: Likewise.
    * libproto/pop/pop3_dele.c: Likewise.
    * libproto/pop/pop3_destroy.c: Likewise.
    * libproto/pop/pop3_disconnect.c: Likewise.
    * libproto/pop/pop3_list.c: Likewise.
    * libproto/pop/pop3_lista.c: Likewise.
    * libproto/pop/pop3_noop.c: Likewise.
    * libproto/pop/pop3_pass.c: Likewise.
    * libproto/pop/pop3_quit.c: Likewise.
    * libproto/pop/pop3_retr.c: Likewise.
    * libproto/pop/pop3_readline.c: Likewise.
    * libproto/pop/pop3_rset.c: Likewise.
    * libproto/pop/pop3_stat.c: Likewise.
    * libproto/pop/pop3_top.c: Likewise.
    * libproto/pop/pop3_uidl.c: Likewise.
    * libproto/pop/pop3_uidla.c: Likewise.
    * libproto/pop/pop3_user.c: Likewise.
    
    * examples/pop3client.c: Implement the stls comand.
    (main) [WITH_TLS]: Call mu_init_tls_libs.
    (com_verbose): Redo verbose support.
    (com_capa): Implement "reread" option.

commit c97b96ae673278d60906314001aec978bdcf4485
Author: Sergey Poznyakoff <address@hidden>
Date:   Sat Sep 4 12:31:37 2010 +0300

    Reorganize directory tree.
    
    Move libproto/include/(*)0.h to include/mailutils/sys/\1.h
    Remove libproto/include.

commit 81166ab69da9bb6cb5a2911107405a2362e200ee
Author: Sergey Poznyakoff <address@hidden>
Date:   Sat Sep 4 00:00:09 2010 +0300

    Remove unused constants.
    
    * pop3d/pop3d.h (POP_MAXCMDLEN, BUFFERSIZE): Remove constants.
    (_QNX_SOURCE): Remove define.

commit 6c60ab472d3ded91bd212b9f140c5294dec59c9f
Author: Sergey Poznyakoff <address@hidden>
Date:   Fri Sep 3 16:59:56 2010 +0300

    pop3d: bugfixes.
    
    * pop3d/apop.c (pop3d_apopuser, pop3d_apopuser): Remove statically
    allocated buffers.
    * pop3d/pop3d.c (pop3d_mainloop): Likewise.
    * pop3d/user.c (pop3d_begin_session): Likewise.

commit 1d6e52af3261347bb5bc3be8ef35f519ec99c412
Author: Sergey Poznyakoff <address@hidden>
Date:   Fri Sep 3 16:08:12 2010 +0300

    pop3d: optimize apop support.
    
    * pop3d/apop.c (pop3d_apopuser): Fix highly ineffective resource
    usage in both branches.
    * pop3d/pop3d.c: Remove misleading comment.

commit 02abfc4419cc651df0005a065f0db781dc884594
Author: Sergey Poznyakoff <address@hidden>
Date:   Fri Sep 3 12:49:33 2010 +0300

    Re-implement GSASL support.
    
    * libmu_auth/lbuf.c: Removed.
    * libmu_auth/lbuf.h: Removed.
    * libmu_auth/Makefile.am : Remove lbuf stuff.
    
    * include/mailutils/sys/gsasl-stream.h: New file.
    * include/mailutils/sys/Makefile.am: Add gsasl-stream.h.
    * include/mailutils/gsasl.h (mu_gsasl_stream_create): Remove.
    (gsasl_encoder_stream, gsasl_decoder_stream): New prototypes.
    
    * libmu_auth/gsasl.c: Rewrite.
    
    * imap4d/authenticate.c (auth_data): Remove.
    Use struct imap4d_auth instead.
    (_auth_try): Use new authentication API.
    (imap4d_authenticate): Likewise.
    * imap4d/imap4d.h (util_register_event, util_event_remove)
    (util_run_events): Remove.
    (imap4d_auth_handler_fp): Change prototype.
    (imap4d_auth): New struct.
    (imap4d_auth_result): New enum.
    * imap4d/io.c (io_format_completion_response)
    (io_stream_completion_response): New functions.
    (io_completion_response): Rewrite using io_format_completion_response.
    * imap4d/util.c (sc2string): Remove leftover prototype.
    (util_register_event, util_event_remove)
    (util_run_events): Remove.
    * imap4d/auth_gsasl.c: Revamp using new streams and the new
    authentication interface.
    * imap4d/auth_gss.c: Likewise (though yet untested).
    
    * mailbox/xscript-stream.c (_xscript_ctl): Remove unused variables.

commit b5986a2df68af1d7217907f3c655f1ef59ebde5f
Author: Sergey Poznyakoff <address@hidden>
Date:   Fri Sep 3 09:39:13 2010 +0300

    Port the new I/O scheme from pop3d to imap4d.
    
    * mailbox/fltstream.c (filter_wr_flush): Fix erroneous conditional.
    (filter_wait): New method.
    (mu_filter_stream_create): Set wait method.
    
    * imap4d/io.c: New source.
    * imap4d/Makefile.am: Add io.c
    * imap4d/*: Update I/O function calls.

commit d6153b1307bf9ab9242d4f9f76592d346ebc6ec1
Author: Sergey Poznyakoff <address@hidden>
Date:   Fri Sep 3 01:15:00 2010 +0300

    Minor change.
    
    * pop3d/extra.c (pop3d_setio): Use the canonic name of the CRLF
    filter, instead of the legacy "rfc822".
    * imap4d/fetch.c: Likewise.
    * imap4d/util.c: Likewise.

commit 29d2e3904c897c01191072db85985b93f9ea1704
Author: Sergey Poznyakoff <address@hidden>
Date:   Thu Sep 2 10:04:45 2010 +0300

    Implement an ioctl for replace bottom-level transport layers in a stream 
chain.
    
    * include/mailutils/stream.h (MU_IOCTL_SWAP_STREAM): New ioctl op.
    (mu_stream_seterr): New function.
    * include/mailutils/sys/stream.h (_MU_SWAP_FIRST_ONLY)
    (_MU_SWAP_IOCTL_MUST_SUCCEED): New defines.
    (_mu_stream_swap_streams): New proto.
    * mailbox/amd.c (amd_body_stream_read): Always update *pnread.
    * mailbox/errors (MU_ERR_NO_TRANSPORT): New error code.
    
    * mailbox/stream.c (_stream_seterror): Rename to mu_stream_seterr,
    remove static qualifier. All uses updated.
    (_mu_stream_swap_streams): New function.
    
    * mailbox/filter_iconv.c (_icvt_ioctl): Implement MU_IOCTL_SWAP_STREAM.
    * mailbox/iostream.c (_iostream_ctl): Likewise.
    * mailbox/xscript-stream.c (_xscript_ctl): Likewise.
    
    * pop3d/extra.c (real_istream, real_ostream): Remove statics.
    (pop3d_init_tls_server): Use MU_IOCTL_SWAP_STREAM to replace
    bottom-level transport layers without recreating the entire stream
    chain.

commit baea3184ad1cf5c6124ac1697a52d782ed7bebab
Author: Sergey Poznyakoff <address@hidden>
Date:   Mon Aug 30 22:19:53 2010 +0300

    Redo the support for transport-based streams.
    
    If a stream takes another stream(s) as a transport, it
    always increases its reference count.  This means that
    when that stream is destroyed the underlying stream is
    not destroyed by default (its refcount is decreased, that's
    all). To force destruction of the underlying stream,
    the caller must explicitly unreference it after creating
    the stream that uses it (or give its creation function
    the MU_STREAM_AUTOCLOSE flag, if it supports flags).
    
    Similarly, if a stream uses a non-stream object (e.g. a file
    descriptor) as the transport, it will not destroy it, unless
    it has been created with the MU_STREAM_AUTOCLOSE flag. This
    differs from the previous behavior.
    
    The MU_STREAM_NO_CHECK and MU_STREAM_NO_CLOSE flags are removed.
    
    * examples/base64.c (main): Call mu_filter_create with the
    MU_STREAM_AUTOCLOSE flag.
    * examples/mimetest.c (message_display_parts): Likewise.
    * examples/murun.c (main): Unref the input stream after
    passing it to mu_filter_prog_stream_create.
    * imap4d/fetch.c (fetch_io): Update arguments to mu_filter_create
    and mu_memory_stream_create.
    * imap4d/preauth.c (decode64_buf)
    (do_preauth_ident): Update arguments to mu_memory_stream_create and
    mu_tcp_stream_create.
    * imap4d/util.c (util_setio): Update arguments to mu_filter_create and
    mu_stdio_stream_create.
    * include/mailutils/stream.h (MU_STREAM_NO_CLOSE)
    (MU_STREAM_NO_CHECK): Remove.
    (MU_STREAM_AUTOCLOSE): New flag.
    (mu_iostream_create): Remove the `flags' argument.
    * libmu_argp/muinit.c (mu_app_init): Update arguments to
    mu_stdio_stream_create.
    * libmu_auth/ldap.c: Update arguments to
    mu_memory_stream_create and mu_filter_create.
    * libmu_auth/tls.c (_tls_io_close, _tls_close): Always try to close the
    transport stream. Rely on refcount to protect it.
    (_tls_io_done, _tls_done): Likewise, always unreference it.
    (_mu_tls_io_stream_create): Increase reference counter on the
    transport stream, unless MU_STREAM_AUTOCLOSE is requested.
    (_mu_tls_stream_create): Rewrite using the new MU_STREAM_AUTOCLOSE
    logic.
    * libmu_sieve/extensions/spamd.c (spamd_connect_tcp): Update arguments to
    mu_tcp_stream_create.
    (spamd_connect_tcp): Update arguments to mu_socket_stream_create and
    mu_filter_create.
    * libmu_sieve/extensions/vacation.c (build_mime): Update arguments to
    mu_filter_create.
    * mail/decode.c (display_submessage): Update arguments to
    mu_filter_create.
    * mailbox/attachment.c (mu_message_save_attachment): Update arguments to
    mu_filter_create.
    * mailbox/cfg_driver.c (mu_cfg_tree_reduce): Update arguments to
    mu_stdio_stream_create.
    * mailbox/dbgstream.c (_dbg_done): Use MU_STREAM_AUTOCLOSE bit to
    decide whether to destroy the debug object.
    (mu_dbgstream_create): Use MU_STREAM_AUTOCLOSE instead of
    MU_STREAM_NO_CLOSE.
    * mailbox/file_stream.c (fd_close): Use MU_STREAM_AUTOCLOSE bit to
    decide whether to close the descriptor.
    (mu_file_stream_create): Force MU_STREAM_AUTOCLOSE bit.
    * mailbox/filter.c (filter_create_rd, filter_create_wr): Change
    substream creation logic.
    * mailbox/filter_iconv.c (_icvt_close): Always try to close the
    transport stream. Rely on refcount to protect it.
    (_icvt_done): Ditto for destroying it.
    (mu_filter_iconv_create): Increase refcount on the transport stream,
    unless MU_STREAM_AUTOCLOSE is requested.
    * mailbox/fltstream.c (filter_done): Always dereference the
    transport stream. Rely on refcount to protect it.
    (filter_close): Ditto for closing it.
    (mu_filter_stream_create): Increase refcount on the transport stream,
    unless MU_STREAM_AUTOCLOSE is requested.
    * mailbox/iostream.c (_iostream_close) : Always try to close the
    transport stream. Rely on refcount to protect it.
    (_iostream_done): Ditto for closing it.
    (mu_iostream_create): Remove the use of MU_STREAM_NO_CLOSE.
    * mailbox/mimehdr.c (mu_mimehdr_decode_param): Remove the use of
    MU_STREAM_NO_CLOSE.
    * mailbox/mutil.c (mu_decode_filter) Change substream creation logic.
    * mailbox/prog_stream.c (_prog_open): Use MU_STREAM_AUTOCLOSE bit
    in arguments to mu_stdio_stream_create.
    (mu_filter_prog_stream_create): Increase refcount on the transport
    (input) stream.
    * mailbox/rfc2047.c (mu_rfc2047_decode): Dereference in_stream after
    passing it to mu_decode_filter.
    Pass MU_STREAM_AUTOCLOSE in flags to mu_filter_create.
    * mailbox/socket_stream.c (mu_socket_stream_create): Force
    MU_STREAM_AUTOCLOSE bit.
    * mailbox/streamref.c (_streamref_close): Always close the
    transport stream (refcount will protect it, if necessary).
    (mu_streamref_create_abridged): Mask out the MU_STREAM_AUTOCLOSE bit.
    * mailbox/temp_file_stream.c (mu_temp_file_stream_create: Force
    MU_STREAM_AUTOCLOSE bit.
    * mailbox/xscript-stream.c (_xscript_close): Always close the
    transport stream (refcount will protect it, if necessary).
    (mu_xscript_stream_create): Increase refcounts on both underlying streams,
    unless MU_STREAM_AUTOCLOSE is set.
    * pop3d/extra.c (pop3d_setio): Remove uses of MU_STREAM_NO_CLOSE.
    
    * examples/nntpclient.c: Remove uses of 
MU_STREAM_NO_CHECK/MU_STREAM_NO_CLOSE.
    * examples/pop3client.c: Likewise.
    * libmu_auth/gsasl.c: Likewise.
    * libproto/nntp/nntp_stream.c: Likewise.
    * libproto/pop/pop3_stream.c: Likewise.
    * mailbox/tcp.c: Likewise.
    * mailbox/vartab.c: Likewise.
    * mh/mh_list.c: Likewise.
    * mimeview/mimeview.c: Likewise.
    * mh/mhn.c: Likewise.
    (edit_mime): Use MU_STREAM_AUTOCLOSE.
    
    Bugfixes:
    
    * mailbox/fltstream.c (init_iobuf): Fix input initialization.
    (filter_write_internal): Bugfix.
    * mailbox/stream.c (_stream_buffer_freespace): New macro.
    (_stream_buffer_is_full): New macro.
    (BUFFER_FULL_P): Remove, use _stream_buffer_is_full instead. All callers
    updated.
    (_stream_flush_buffer): Operation for full buffered streams does not
    depend on the `all' flag.
    (mu_stream_write): Fix calculation of the bytes available in the
    buffer.

commit 814b97914c8ac0177af4688e934511912733c314
Author: Sergey Poznyakoff <address@hidden>
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.

commit cab810601ec85691494b1d3424b171b06b0c2348
Author: Sergey Poznyakoff <address@hidden>
Date:   Mon Aug 30 00:08:31 2010 +0300

    Re-implement server TLS support.
    
    STLS in pop3d is already working.
    
    * include/mailutils/sys/tls-stream.h: New header.
    * include/mailutils/tls.h (mu_tls_stream_create)
    (mu_tls_stream_create_client)
    (mu_tls_stream_create_client_from_tcp): Remove.
    (mu_tls_server_stream_create, mu_tls_client_stream_create): New
    protos.
    * libmu_auth/tls.c: Rewrite.
    
    * imap4d/util.c: Use mu_tls_server_stream_create.
    * libproto/pop/mbox.c: Use mu_tls_server_stream_create/
    mu_tls_client_stream_create.
    * libproto/pop/pop3_stls.c: Use mu_tls_client_stream_create.
    * libproto/imap/folder.c: Use mu_tls_client_stream_create.
    
    * pop3d/capa.c (pop3d_capa): CAPA is allowed in both states.
    * pop3d/extra.c (pop3d_setio): Rewrite.

commit 400fdaaca90616a996f9a6fd230eb084aebb1bb8
Author: Sergey Poznyakoff <address@hidden>
Date:   Sun Aug 29 18:01:27 2010 +0300

    amd, pop3d: bugfixes.
    
    * mailbox/amd.c (amd_body_stream_readdelim): Fix the logic.
    * mailbox/message.c (_message_stream_seek): Fix seeks in
    backward direction.
    * pop3d/top.c: Fix output of the body.

commit c1d1ab07c72070d2ca92f729ab2454ad0b06f0ae
Author: Sergey Poznyakoff <address@hidden>
Date:   Sun Aug 29 14:30:58 2010 +0300

    Bugfix.
    
    * imap4d/append.c: Add a comment.
    * imap4d/imap4d.h (imap4d_child_signal_setup): New proto.
    * libmu_sieve/extensions/pipe.c (sieve_action_pipe): Use
    mu_stream_copy, rewrite error handling.
    * libmu_sieve/extensions/spamd.c (spamd_send_message): se
    mu_stream_copy.
    (spamd_test): Honor dry-run mode.
    * libmu_sieve/extensions/vacation.c (build_mime): Remove
    misleading FIXME. Use mu_stream_copy.
    * libmu_sieve/extensions/moderator.c (moderator_message_get_part): Use
    mu_body_get_streamref.
    * examples/header.c (hstream): New global.
    (cmd_load, cmd_free, cmd_remove, cmd_insert): Discard hstream.
    (cmd_readline): Use hstream. Obtain it using mu_stream_readline.
    * libproto/mbox/mbox.c (mbox_envelope_date): Remove trailing
    newline from the obtained envelope line.
    * mailbox/amd.c (amd_body_stream_seek): Allow for off == size
    (imprtant for empty bodies).

commit 3ffda3e10d5db2d26d739e37653cae22971e1741
Author: Sergey Poznyakoff <address@hidden>
Date:   Sun Aug 29 10:06:59 2010 +0300

    libmu_sieve: cleanup
    
    * libmu_sieve/actions.c (mime_create_quote): Use mu_stream_copy.

commit cbc008712897959c17cde4b9afcb18925da267a7
Author: Sergey Poznyakoff <address@hidden>
Date:   Sun Aug 29 10:04:38 2010 +0300

    pop3d: cleanup
    
    * pop3d/pop3d.h: Include filter.h.
    (istream, ostream): New externs.
    * pop3d/extra.c (pop3d_setio): Set a crlf filter on the
    output stream. This allows to forget about \r in the rest of
    the code.
    * pop3d/retr.c (pop3d_retr): Use mu_stream_copy instead of
    copying streams manually.
    * pop3d/top.c (pop3d_top): Rewrite using streamrefs and
    mu_stream_copy.
    * all sources: Use \n instead of \r\n in output strings.

commit dca7b761362545f359968be344267c3fd93cb935
Author: Sergey Poznyakoff <address@hidden>
Date:   Sun Aug 29 02:36:03 2010 +0300

    Fix mime creation and Sieve reject/redirect actions.
    
    * examples/mta.c (finalize_option): New variable.
    (message_finalize): Don't modify the message if finalize_option
    is 0.
    * include/mailutils/sys/message.h (_mu_message)
    <orig_header_size>: New member.
    * include/mailutils/sys/mime.h (_mu_mime) <part_stream>: New member.
    * libmu_sieve/actions.c (mime_create_reason)
    (mime_create_ds): Use mu_body_get_streamref.
    (mime_create_quote): Use mu_body_get_streamref/mu_message_get_streamref.
    (sieve_action_reject): Set the To: header.
    * mailbox/message.c (mu_message_get_header): Set orig_header_size.
    (mu_message_get_body): Use orig_header_size instead of relying
    on mu_header_size.
    * mailbox/mime.c (_mime_part_size): New static.
    (_mime_body_stream_size): New method.
    (_mime_body_seek): Rename to _mime_body_stream_seek.
    (_mime_body_read): Rewrite and rename to _mime_body_stream_read.
    (_mime_body_ioctl): Rename to _mime_body_stream_ioctl.
    (create_mime_body_stream): Take mu_mime_t as the 2nd parameter.
    Initialize sp->stream.size and sp->mime.
    (_mime_body_size): Rewrite using _mime_part_size.
    (mu_mime_destroy): Destroy part_stream.
    * sieve/testsuite/Redirect: Reflect new mta behavior.
    * sieve/testsuite/Reject: Likewise.

commit 66c992c3780eb1191c5644c4f3068da5abaae2ec
Author: Sergey Poznyakoff <address@hidden>
Date:   Sat Aug 28 23:10:40 2010 +0300

    Further bugfixes.
    
    * libproto/mbox/mbox.c (_msg_stream_setup): Fix abridgement limits.
    (mbox_expunge_unlocked): Don't write extra newline after each
    message.
    * mailbox/stream.c (mu_stream_seek): ESPIPE does not constitute
    a permanent error.

commit c7491f228d5fce68e50192d26a98ecf8115f5283
Author: Sergey Poznyakoff <address@hidden>
Date:   Sat Aug 28 22:42:04 2010 +0300

    Fix mime test.
    
    * mailbox/mime.c (mu_mime_get_part): Fix the end limit for the
    part's abridgement.
    * mailbox/streamref.c (_streamref_seek): Fix ESPIPE condition.

commit e7b40d4ec935750c3a395d5f9853d6011883a135
Author: Sergey Poznyakoff <address@hidden>
Date:   Sat Aug 28 18:39:43 2010 +0300

    pop3d: bugfixes.
    
    * include/mailutils/message.h (mu_message_set_stream): Mark as deprecated.
    * pop3d/retr.c (pop3d_retr): Rewind the stream obtained from
    mu_message_get_stream.
    * pop3d/top.c (pop3d_top): Rewind the streams obtained from
    mu_body_get_stream and mu_header_get_stream.

commit 2e58dde3af88615b3af67dcbae69aaaf5b120783
Author: Sergey Poznyakoff <address@hidden>
Date:   Sat Aug 28 16:58:08 2010 +0300

    Fix encode2047 test.
    
    * mailbox/base64.c (_base64_encoder): Fix the use
    of uninitialized variable.
    * mailbox/rfc2047.c (mu_rfc2047_encode): Rewind the
    input stream before reading from it.

commit 8355901b63008385294d0c4b79539d70cb8f5c90
Author: Sergey Poznyakoff <address@hidden>
Date:   Sat Aug 28 16:36:14 2010 +0300

    Fix decode2047 test.
    
    * mailbox/filter_iconv.c (mu_filter_iconv_create): Set filter flags.
    * mailbox/fltstream.c (mu_filter_stream_create): Likewise.
    * mailbox/qpflt.c (_qp_decoder): Handle '_'.

commit 5f0b1ed3c5d5276df98b20cb4bb020915b6a064c
Author: Sergey Poznyakoff <address@hidden>
Date:   Sat Aug 28 16:08:07 2010 +0300

    Fix base64 test.
    
    * examples/base64.c (c_copy): Handle printable mode (-p).
    (reset_line_length): New function.
    (main): New option -lN sets the maximum length for output
    lines to N (0 means unlimited).
    * mailbox/testsuite/mailbox/base64.exp: Use -l0 in the
    Decode test.

commit 8f8e01b920d0601df5e60cd8060eba5909a10178
Author: Sergey Poznyakoff <address@hidden>
Date:   Sat Aug 28 17:22:40 2010 +0300

    Bugfixes
    
    * include/mailutils/header.h (mu_header_invalidate): New proto.
    * mailbox/header.c (mu_header_invalidate): New function.
    
    * libmu_argp/muinit.c (get_canonical_name): Avoid coredumping
    if argp_program_version is NULL.
    * mailbox/base64.c (mu_base64_decode): Fix inconsistent return
    code.
    * mailbox/debug.c (mu_debug_destroy): Allow for debug->stream == NULL.
    
    * mailbox/mapfile_stream.c (_mapfile_truncate): Incorrect size
    was used when unmapping.
    * mailbox/message.c (mu_message_create_copy): Use a temporary
    memory stream.
    (mu_message_get_body): Comment out the check for MESSAGE_INTERNAL_STREAM.
    (_message_get_stream): Initialize message header and body.
    
    * mailbox/progmailer.c (mu_progmailer_send): Check  return
    from the mu_header_get_streamref.
    
    * mailbox/stream.c (_stream_scandelim, _stream_readdelim): If
    size is 0, return MU_ERR_BUFSPACE.

commit 85b56e79be1935ba99df3574cf47cf19179cc3fe
Author: Sergey Poznyakoff <address@hidden>
Date:   Sun May 2 23:21:01 2010 +0300

    Fix readmsg.
    
    Readmsg passes all tests successfully.
    
    * readmsg/msglist.c (msglist): Check return from mu_message_get_streamref.
    * readmsg/readmsg.c (print_header, print_body): Check return values.

commit 11c14a014892507f7fa1dca4610840a4e4668d43
Author: Sergey Poznyakoff <address@hidden>
Date:   Sun May 2 23:20:39 2010 +0300

    Bugfixes
    
    * mailbox/header.c (header_seek): Do not dereference
    hstr->hdr->size directly, because it may not be initialized yet.
    Use mu_header_size instead.
    * mailbox/message.c (_message_stream_readdelim): Break the loop
    if mu_stream_readdelim returned error or EOF.

commit 1270a9f683827885e91a39e4088d2297af4b5987
Author: Sergey Poznyakoff <address@hidden>
Date:   Sun May 2 22:38:06 2010 +0300

    Various fixes in imap4d.
    
    Imap4d successfully passes all tests.
    
    * imap4d/close.c (imap4d_close0): Fix improper use of MU_STREAM_READ
    (flags changed their semantics since then).
    * imap4d/fetch.c: Send \n terminated lines, rely on filters to recode
    line terminators to \r\n.
    (fetch_io): Rewrite using CRLF encoder and util_copy_out.
    (_frt_header_fields): Rewind memory stream before reading from it.
    
    * imap4d/auth_gsasl.c: Send \n terminated lines, rely on filters
    to recode line terminators to \r\n.
    * imap4d/auth_gss.c: Likewise.
    * imap4d/capability.c: Likewise.
    * imap4d/copy.c: Likewise.
    * imap4d/id.c: Likewise.
    * imap4d/idle.c: Likewise.
    * imap4d/list.c: Likewise.
    * imap4d/namespace.c: Likewise.
    * imap4d/preauth.c: Likewise.
    * imap4d/search.c: Likewise.
    * imap4d/status.c: Likewise.
    * imap4d/store.c: Likewise.
    * imap4d/select.c: Likewise.
    (imap4d_select_status): Fix improper use of MU_STREAM_READ.
    
    * imap4d/util.c: Send \n terminated lines, rely on filters
    to recode line terminators to \r\n.
    (util_setio): Apply CRLF filters to both input and output streams
    (in opposite directions).
    (util_copy_out): New function.
    (remove_cr): Remove.
    * imap4d/imap4d.h (util_copy_out): New prototype.

commit 012b6c7facbd39596a7bf9e8ac61c732c87a236a
Author: Sergey Poznyakoff <address@hidden>
Date:   Sun May 2 22:33:08 2010 +0300

    Fix for mbox read/write consistency.
    
    * libproto/mbox/mbox.c (append_message_to_stream): Add \n after each
    message (scanner relies on this to determine message sizes).

commit 352c5e92e6d26701fccced669c40409d6010ff10
Author: Sergey Poznyakoff <address@hidden>
Date:   Sun May 2 22:32:11 2010 +0300

    Bugfixes in stream-related code.
    
    * mailbox/fltstream.c (filter_read): Do not try to get more input until
    the output buffer is drained.
    * mailbox/mapfile_stream.c (_mapfile_seek): Fix conditional.
    * mailbox/stream.c (_stream_fill_buffer): Fix increment.
    (mu_stream_skip_input_bytes): Bugfixes.

commit 2203753f72c89a194889baa199a513e3ed02e5b3
Author: Sergey Poznyakoff <address@hidden>
Date:   Sun May 2 17:58:01 2010 +0300

    Implement seek on filters in read-only mode.
    
    * include/mailutils/stream.h (mu_stream_skip_input_bytes): New proto.
    * mailbox/stream.c (mu_stream_skip_input_bytes): New function.
    * mailbox/fltstream.c (filter_seek): Re-implement on top of
    mu_stream_skip_input_bytes.
    (mu_filter_stream_create): Fix flag validity checking.
    
    * examples/base64.c: Add new option (-s) for testing seek operations
    on filters.

commit 0f2fc18ab5ef3bc518e9d37d422db0484b4cc8d3
Author: Sergey Poznyakoff <address@hidden>
Date:   Sun May 2 17:00:23 2010 +0300

    Make version output of the MH utilities more informative.
    
    * mh/mh_argp.c [MU_ALPHA_RELEASE}: Include git-describe.h
    (mh_program_version_hook): New function.
    (mh_argp_init): Take no arguments. Set argp_program_version_hook.
    * mh/mh_getopt.h (ARG_LICENSE): Remove.
    (mh_argp_init): Change proto.
    
    All sources: Fix calls to mh_argp_init, remove --license option.

commit c8abc2b1adfcddccf0e85caf44f3376aad11552c
Author: Sergey Poznyakoff <address@hidden>
Date:   Sun May 2 16:16:44 2010 +0300

    For alpha version, include git tag info in the version output.
    
    * include/mailutils/libargp.h (mu_program_version_hook): New proto.
    * libmu_argp/Makefile.am (libmu_argp_a_SOURCES): Remove mu_argp.h.
    * libmu_argp/mu_argp.h: Remove.
    * libmu_argp/muinit.c [MU_ALPHA_RELEASE]: Include git-describe.h
    (mu_program_version_hook): New function.
    (mu_argp_init): Set mu_program_version_hook, unless vers is given.
    
    * comsat/comsat.c (main): Call mu_argp_init with NULL arguments.
    * config/mailutils-config.c: Likewise.
    * dotlock/dotlock.c: Likewise.
    * examples/muauth.c: Likewise.
    * frm/frm.c: Likewise.
    * frm/from.c: Likewise.
    * guimb/main.c: Likewise.
    * imap4d/imap4d.c: Likewise.
    * maidag/maidag.c: Likewise.
    * mail/mail.c: Likewise.
    * messages/messages.c: Likewise.
    * mimeview/mimeview.c: Likewise.
    * movemail/movemail.c: Likewise.
    * pop3d/pop3d.c: Likewise.
    * pop3d/popauth.c: Likewise.
    * readmsg/readmsg.c: Likewise.
    * sieve/sieve.c: Likewise.

commit fa54cb19078773382fb1db24bbf450a9962e186d
Author: Sergey Poznyakoff <address@hidden>
Date:   Sun May 2 15:40:02 2010 +0300

    Fix conditional compilation.
    
    * .gitignore: Add git-describe and git-describe.h.
    * Makefile.am (MU_COND_LIBMU_CPP): Replaced with MU_COND_SUPPORT_CXX
    (SUBDIRS): Begin with .
    (EXTRA_DIST, BUILT_SOURCES): Add git-describe and git-describe.h.
    (git-describe, git-describe.h): New rules.
    (alpha, alphacheck): Use git-describe to produce additional suffix.
    * enable.m4 (MU_ENABLE_SUPPORT): Create an Automake condition.
    * configure.ac: Fix MU_ENABLE_SUPPORT calls.
    (--without-python): Replace with --disable-python.
    * examples/Makefile.am: Disable components based on MU_COND conditions.
    * libproto/Makefile.am: Likewise.
    * include/mailutils/Makefile.am (MU_COND_LIBMU_CPP): Replace with
    MU_COND_SUPPORT_CXX.
    
    * mailbox/nullrec.c: New file.
    * mailbox/Makefile.am (libmailutils_la_SOURCES): Add nullrec.c.
    
    * mail/decode.c: Remove unused variable.
    * mailbox/streamref.c: Likewise.

commit dfea400b082c5eff4f31c4fd0ac9e57756a04866
Author: Sergey Poznyakoff <address@hidden>
Date:   Sun May 2 14:20:32 2010 +0300

    Simplify stream->seek.
    
    * include/mailutils/sys/stream.h (_mu_stream) <seek>: Remove the
    `whence' parameter.
    * mailbox/stream.c (mu_stream_seek): Update the seek method call.
    
    * mailbox/streamref.c (_streamref_seek): Fix the signature. Remove
    unnecessary code.
    * mailbox/amd.c (amd_body_stream_seek): Likewise.
    * mailbox/body.c (_body_seek): Likewise.
    * mailbox/file_stream.c (fd_seek): Likewise.
    * mailbox/filter_iconv.c (_icvt_seek): Likewise.
    * mailbox/fltstream.c (filter_seek): Likewise.
    * mailbox/header.c (header_seek): Likewise.
    * mailbox/mapfile_stream.c (_mapfile_seek): Likewise.
    * mailbox/memory_stream.c (_memory_seek): Likewise.
    * mailbox/message.c (_message_stream_seek): Likewise.
    * mailbox/message_stream.c (_message_stream_seek): Likewise.
    * mailbox/mime.c (_mime_body_seek): Likewise.
    * mailbox/stdio_stream.c (stdio_seek): Likewise.

commit 9b4deb97eec3c3efdb7b416bc6e357c33a632158
Author: Sergey Poznyakoff <address@hidden>
Date:   Sun May 2 13:57:06 2010 +0300

    Improve CRLF filter.
    
    * include/mailutils/filter.h (mu_filter_new_data_t): Change prototype.
    * mailbox/filter.c (mu_filter_create): Reflect the above.
    * mailbox/crlfflt.c (crlf_state): New enum.
    (_crlf_encoder): Keep state info in xd. Do not modify eventual input
    CRLFs.
    (alloc_state): New function.
    (_rfc822_filter,_crlf_filter): Provide the `newdata' method.

commit 3fefeaa458075ca20381284950b32f6afdccfffe
Author: Sergey Poznyakoff <address@hidden>
Date:   Sat May 1 20:51:57 2010 +0300

    Bugfixes.
    
    * mailbox/rfc2047.c (mu_rfc2047_decode): Rewind in_stream.
    * mailbox/stream.c (_stream_scandelim): Break the loop when
    the delimiter is found.
    * mailbox/streamref.c (_streamref_readdelim): Take into account
    the abridgement.

commit f96ce94e2ad041c0f6011eafb74e1799e1f90eb0
Author: Sergey Poznyakoff <address@hidden>
Date:   Sat May 1 19:58:33 2010 +0300

    Optimize readline/readdelim/getdelim calls.
    
    This speeds up common reading operations by factor of 4-6.
    
    * include/mailutils/stream.h (mu_stream_readdelim): New proto.
    * include/mailutils/sys/stream.h (_mu_stream) <readdelim>: New method.
    * mailbox/stream.c (_stream_scandelim, _stream_readdelim): New functions.
    (mu_stream_readdelim): New function.
    (mu_stream_readline): Rewrite using mu_stream_readdelim.
    (mu_stream_getdelim): Optimize.
    
    * mailbox/amd.c (amd_body_stream_readdelim): New function.
    (_amd_attach_message): Set the readdelim method.
    * mailbox/header.c: Add a placeholder for readdelim method.
    * mailbox/message.c (_message_stream_readdelim): New function.
    (_message_stream_create): Set the readdelim method.
    * mailbox/streamref.c (_streamref_readdelim): New function.
    (mu_streamref_create_abridged): Set the readdelim method.

commit 03aa45f1aafdfb3eaea8a56fb092ec091694c432
Author: Sergey Poznyakoff <address@hidden>
Date:   Sat May 1 17:44:07 2010 +0300

    Fix amd
    
    * mailbox/amd.c (_amd_attach_message): Store body.
    (amd_scan_message): Scan the message only if it has been modified
    after the last scan.
    Fix loop condition.
    Store mhm->mtime on success.
    (amd_message_stream_open): Enforce full buffering.
    (amd_body_stream_read): Fix.
    (amd_body_stream_seek): Don't call mu_stream_seek on mhm->stream.

commit 3f4567b725d10dba3f179c7220ce275c8ffe8085
Author: Sergey Poznyakoff <address@hidden>
Date:   Sat May 1 17:43:48 2010 +0300

    Bugfixes
    
    * mailbox/message.c (_check_stream_state): Bugfix.
    (_message_stream_seek): Bugfix.
    (_message_stream_read): Always try to fill out the buffer.
    (_message_stream_create): Set MU_STREAM_SEEK flag bit.

commit e71e1073a09547a195a1cc070ed825e651b8c415
Author: Sergey Poznyakoff <address@hidden>
Date:   Sat May 1 17:42:52 2010 +0300

    Bugfix in filter_iconv.
    
    * mailbox/filter_iconv.c (mu_filter_iconv_create): Return
    the created stream in *s.

commit b5ddabd7415663a140bdb9daf97577db26116c4e
Author: Sergey Poznyakoff <address@hidden>
Date:   Sat May 1 17:42:13 2010 +0300

    Keep track of the current offset in the _mu_stream structure.
    
    * include/mailutils/sys/stream.h (_mu_stream)<offset>: New member.
    * mailbox/stream.c (_stream_fill_buffer): Propagate return value
    from mu_stream_read_unbuffered.
    (_stream_flush_buffer): Use stream->offset. Honor the `all' argument.
    (mu_stream_seek): Rewrite using the `offset' member.
    (mu_stream_read_unbuffered)
    (mu_stream_write_unbuffered): Update offset.
    (mu_stream_readline): Return EINVAL if size is 0.

commit d17ec29ca42139df7588ee4f85bbeb8bd20c93e8
Author: Sergey Poznyakoff <address@hidden>
Date:   Sat May 1 01:39:49 2010 +0300

    Use stringrefs, add some guidelines for further editing.
    
    * comsat/action.c
    * imap4d/fetch.c
    * imap4d/search.c
    * mh/burst.c
    * mh/comp.c
    * mh/forw.c
    * mh/mh_ctx.c
    * mh/mh_format.c
    * mh/mh_list.c
    * mh/mhn.c
    * mh/pick.y
    * pop3d/retr.c
    * pop3d/top.c
    * readmsg/msglist.c
    * readmsg/readmsg.c

commit 3437509ff40a5e7cc86f8b26fb182592cab43b74
Author: Sergey Poznyakoff <address@hidden>
Date:   Sat May 1 01:33:49 2010 +0300

    Fix compilation of libmu_scm.
    
    * libmu_scm/mu_body.c (mu_scm_body_free): Unref the stream.
    Return 0.
    (mu-body-read-line, mu-body-write): Use stringrefs.
    * libmu_scm/mu_mailbox.c (mu-mailbox-get-port): Use stringrefs.
    * libmu_scm/mu_message.c (mu-message-copy): Use stringrefs.
    Use mu_stream_copy instead of manually copying stream contents.
    (mu-message-get-port): Use stringrefs.
    * libmu_scm/mu_port.c (mu_port_free): Unref the stream.

commit 7220d9ddf7abd7ec0cb499194b3272467b4bf91c
Author: Sergey Poznyakoff <address@hidden>
Date:   Sat May 1 01:31:16 2010 +0300

    Fix compilation of several example programs.
    
    * examples/header.c: Use streamrefs.
    * examples/mimetest.c: Likewise.
    * examples/mta.c: Likewise.
    * examples/nntpclient.c: Remove an unused variable.

commit 1f4deff1e92e2c23020dcf93f3836895d6b6ac5d
Author: Sergey Poznyakoff <address@hidden>
Date:   Sat May 1 01:29:39 2010 +0300

    Fix compilation of mimeview.
    
    * mimeview/mimeview.c (mimeview_fp): Restore the variable.

commit 0c013ac57ef780d2d6f2a9b389b1c754b5c29033
Author: Sergey Poznyakoff <address@hidden>
Date:   Sat May 1 01:28:47 2010 +0300

    Fix UNIX mbox driver and mail utility.
    
    The `mail' and `frm' utilities pass tests.
    
    * include/mailutils/stream.h (mu_stream_err): New proto.
    * libproto/mbox/mbox.c (_msg_stream_setup)
    (_msg_body_setup): Fix stream abridgement.
    (mbox_envelope_date, mbox_envelope_sender): Fix seek position.
    (uid_to_stream): Fix invocation of mu_stream_printf.
    (append_message_to_stream): Likewise.
    (mbox_expunge_unlocked): Rewind tempstr before copying its
    contents back to the mailbox.
    (mbox_expunge0): Open tempstr.
    * libproto/mbox/mbox0.h (_mbox_message)<header_from>: Rename to
    envel_from.
    <header_from_end>: Rename to envel_from_end. All uses changed.
    * libproto/mbox/mboxscan.c: Minor changes.
    
    * mail/decode.c: Use streamrefs.
    * mail/escape.c: Likewise.
    * mail/msgset.y: Likewise.
    * mail/pipe.c: Likewise.
    * mail/print.c: Likewise.
    * mail/top.c: Likewise.
    * mail/write.c: Likewise.
    
    * mail/send.c: Use streamrefs.
    (mail_send0): Reset env->header after assigning it to
    the message.
    
    * mailbox/body.c (_body_seek): Fix a typo which produced
    a recursive call.
    * mailbox/file_stream.c (fd_truncate): New function.
    (_mu_file_stream_create): Initialize str->stream.truncate.
    
    * mailbox/header.c (header_parse): Fix parsing of blurbs lacking
    terminating empty line.
    (header_seek): Fix boundary checks.
    Return new position in presult.
    * mailbox/message.c (string_find_eoh): Rewrite to handle \n\n
    split between two successive invocations.
    (_header_fill): Update the invocation of string_find_eoh.
    
    * mailbox/stream.c (mu_stream_destroy): Call mu_stream_close.
    (mu_stream_get_flags, mu_stream_set_flags)
    (mu_stream_clr_flags): Ignore internal
    bits.
    (mu_stream_err): New function.
    (mu_stream_close): Close the stream only if it is not used by anyone else.
    * mailbox/streamref.c (_streamref_read): Clear transport error if
    ESPIPE is returned.
    (_streamref_size): Take into account sp->end and sp->start.
    (mu_streamref_create_abridged): Set pointer to 0.

commit f900b3b06e7748b04fd31a4bfc3c3c82272f019e
Author: Sergey Poznyakoff <address@hidden>
Date:   Fri Apr 30 02:59:59 2010 +0300

    Bugfixes in stream code.
    
    * mailbox/amd.c (amd_body_stream_seek): Fix boundary checking.
    Return ESPIPE on boundary error.
    * mailbox/header.c (header_seek): Likewise.
    * mailbox/memory_stream.c (_memory_seek): Likewise.
    * mailbox/message.c (_message_stream_seek): Likewise.
    * mailbox/message_stream.c (_message_seek): Likewise.
    * mailbox/stdio_stream.c (stdio_seek): Likewise.
    
    * mailbox/file_stream.c (fd_open): Invert error condition.
    Fix computation of open flags.
    Return immediately if open returns -1.
    (fd_seek): Fix boundary checking.
    Return ESPIPE on boundary error.
    * mailbox/mapfile_stream.c (_mapfile_open): Fix flags calculation.
    (_mapfile_seek): Fix boundary checking.
    Return ESPIPE on boundary error.
    
    * mailbox/streamref.c (_streamref_read): Fix calculation of the
    top size boundary.
    Return 0 bytes if seek returns ESPIPE.
    (_streamref_seek): Return ESPIPE on boundary error.
    
    * mailbox/base64.c (_base64_decoder, _base64_encoder): Do
    not dereference iobuf if cmd is mu_filter_init or mu_filter_done.
    * mailbox/binflt.c (_copy_codec, _bit7_coder): Likewise.
    * mailbox/crlfflt.c (_crlf_encoder, _crlf_decoder): Likewise.
    * mailbox/linelenflt.c (_ll_encoder): Likewise.
    * mailbox/qpflt.c (_qp_decoder, _qp_encoder): Likewise.
    
    * mailbox/mailcap.c (mu_mailcap_parse): Fix loop condition.

commit d976d8a10c7930658054733e3173d4b45355f61e
Author: Sergey Poznyakoff <address@hidden>
Date:   Thu Apr 29 23:24:12 2010 +0300

    Bugfixes.
    
    * examples/sfrom.c (main): Check return from mu_mailbox_messages_count.
    * include/mailutils/sys/stream.h (_MU_STR_WRT): New constant.
    * libproto/mbox/mbox.c (_msg_stream_setup): Fix 3rd argument to
    mu_streamref_create_abridged.
    * libproto/mbox/mboxscan.c (mbox_scan_internal): Don't use mailbox->stream
    directly, because its offsets may get shifted by observers. Use streamref
    instead.
    * mailbox/argcv.c (argcv_get): Do nothing if argc <= 0.
    * mailbox/mapfile_stream.c (_mapfile_seek): Fill the *presult.
    * mailbox/memory_stream.c (_memory_done): Remove leftover free.
    * mailbox/stream.c: Reorder functions.
    (_mu_stream_create): Increase reference count (i.e. set it to 1)
    before returning.
    (mu_stream_seek): Call _stream_flush_buffer instead of
    mu_stream_flush.
    (mu_stream_read_unbuffered): Return 0 on EOF.
    (mu_stream_write_unbuffered): Set _MU_STR_WRT bit.
    (mu_stream_readline, mu_stream_getdelim): Check the actual
    number of bytes read.
    (mu_stream_flush): Call flush method only if _MU_STR_WRT is set.
    Clear it.
    * mailbox/streamref.c (_streamref_seek): Optimization for off==0 and
    whence == MU_SEEK_CUR.
    (_streamref_seek): Return new offset in ppos.
    (mu_streamref_create_abridged): Set MU_STREAM_NO_CLOSE.
    * mailbox/memory_stream.c (_memory_seek) : Return new offset in presult.
    * mailbox/message_stream.c (_message_seek): Likewise.
    * mailbox/stdio_stream.c (stdio_seek): Fix prototype.

commit d7a596df78be3863fd7a71977e99332eac38bda5
Author: Sergey Poznyakoff <address@hidden>
Date:   Fri Apr 23 23:33:49 2010 +0300

    Stream support rewritten from scratch.
    
    Does not compile yet.
    
    New files:
    * mailbox/streamref.c
    * include/mailutils/sys/streamref.h
    * include/mailutils/sys/file_stream.h
    * include/mailutils/sys/header_stream.h
    * include/mailutils/sys/mapfile_stream.h
    * include/mailutils/sys/memory_stream.h
    * include/mailutils/sys/message_stream.h
    * include/mailutils/sys/prog_stream.h
    * include/mailutils/sys/socket_stream.h
    * include/mailutils/sys/stdio_stream.h
    * include/mailutils/sys/stream.h
    * include/mailutils/sys/streamtrans.h
    * mailbox/prog_stream.c
    * mailbox/stdio_stream.c
    * mailbox/stream_printf.c
    * mailbox/stream_vprintf.c
    * mailbox/temp_file_stream.c
    * mailbox/streamcpy.c
    * mailbox/binflt.c
    * mailbox/crlfflt.c
    * mailbox/fltstream.c
    * mailbox/qpflt.c
    * mailbox/linelenflt.c
    
    Removed files:
    * mailbox/filter_rfc822.c
    * mailbox/filter_trans.c
    
    Moved files (with edits):
    * libproto/include/filter0.h -> include/mailutils/sys/filter.h
    * libproto/include/header0.h -> include/mailutils/sys/header.h
    * libproto/include/message0.h -> include/mailutils/sys/message.h
    * libproto/include/mime0.h -> include/mailutils/sys/mime.h
    
    Modified files:
    * comsat/action.c
    * config/mailutils-config.c
    * examples/base64.c
    * examples/cpp/msg-send.cc
    * examples/header.c
    * examples/http.c
    * examples/iconv.c
    * examples/mimetest.c
    * examples/msg-send.c
    * examples/mta.c
    * examples/murun.c
    * examples/nntpclient.c
    * examples/pop3client.c
    * imap4d/append.c
    * imap4d/auth_gsasl.c
    * imap4d/fetch.c
    * imap4d/preauth.c
    * imap4d/search.c
    * imap4d/util.c
    * include/mailutils/body.h
    * include/mailutils/folder.h
    * include/mailutils/header.h
    * include/mailutils/mailbox.h
    * include/mailutils/mailer.h
    * include/mailutils/mailutils.h
    * include/mailutils/message.h
    * include/mailutils/stream.h
    * include/mailutils/sys/Makefile.am
    * include/mailutils/sys/filter.h
    * include/mailutils/sys/header.h
    * include/mailutils/sys/message.h
    * include/mailutils/sys/mime.h
    * include/mailutils/sys/nntp.h
    * include/mailutils/sys/pop3.h
    * include/mailutils/sys/stream.h
    * include/mailutils/types.hin
    * lib/mailcap.c
    * lib/mu_dbm.h
    * libmu_argp/muinit.c
    * libmu_auth/ldap.c
    * libmu_auth/tls.c
    * libmu_scm/Makefile.am
    * libmu_scm/mu_body.c
    * libmu_scm/mu_message.c
    * libmu_scm/mu_port.c
    * libmu_sieve/actions.c
    * libmu_sieve/extensions/pipe.c
    * libmu_sieve/extensions/spamd.c
    * libmu_sieve/extensions/vacation.c
    * libproto/mailer/smtp.c
    * libproto/mbox/mboxscan.c
    * libproto/mbox/mbox.c
    * libproto/mbox/mbox0.h
    * libproto/nntp/nntp_article.c
    * libproto/nntp/nntp_carrier.c
    * libproto/nntp/nntp_destroy.c
    * libproto/nntp/nntp_ihave.c
    * libproto/nntp/nntp_post.c
    * libproto/nntp/nntp_readline.c
    * libproto/nntp/nntp_sendline.c
    * libproto/pop/pop3_carrier.c
    * libproto/pop/pop3_destroy.c
    * libproto/pop/pop3_readline.c
    * libproto/pop/pop3_sendline.c
    * libproto/pop/pop3_stat.c
    * maidag/mailtmp.c
    * mail/decode.c
    * mail/escape.c
    * mail/msgset.y
    * mail/pipe.c
    * mail/print.c
    * mail/send.c
    * mail/top.c
    * mail/util.c
    * mail/write.c
    * mailbox/Makefile.am
    * mailbox/amd.c
    * mailbox/attachment.c
    * mailbox/body.c
    * mailbox/cfg_driver.c
    * mailbox/cfg_format.c
    * mailbox/debug.c
    * mailbox/file_stream.c
    * mailbox/folder.c
    * mailbox/hdritr.c
    * mailbox/header.c
    * mailbox/mailbox.c
    * mailbox/mailcap.c
    * mailbox/mailer.c
    * mailbox/mapfile_stream.c
    * mailbox/memory_stream.c
    * mailbox/message.c
    * mailbox/message_stream.c
    * mailbox/mime.c
    * mailbox/mimehdr.c
    * mailbox/mutil.c
    * mailbox/prog_stream.c
    * mailbox/progmailer.c
    * mailbox/rfc2047.c
    * mailbox/socket_stream.c
    * mailbox/stream.c
    * mailbox/stream_vprintf.c
    * mailbox/tcp.c
    * mailbox/vartab.c
    * mailbox/wicket.c
    * mh/burst.c
    * mh/comp.c
    * mh/compcommon.c
    * mh/forw.c
    * mh/mh_ctx.c
    * mh/mh_format.c
    * mh/mh_init.c
    * mh/mh_list.c
    * mh/mh_whatnow.c
    * mh/mhl.c
    * mh/mhn.c
    * mh/pick.y
    * mh/repl.c
    * mimeview/mimeview.c
    * mu-aux/generr.awk
    * pop3d/extra.c
    * pop3d/pop3d.h
    * pop3d/retr.c
    * pop3d/top.c
    * readmsg/msglist.c
    * readmsg/readmsg.c
    * sieve/sieve.c

-----------------------------------------------------------------------

Summary of changes:
 .gitignore                             |    2 +
 Makefile.am                            |   53 +-
 am/enable.m4                           |    6 +-
 comsat/action.c                        |    5 +-
 comsat/comsat.c                        |    2 +-
 config/mailutils-config.c              |    5 +-
 configure.ac                           |   53 +-
 dotlock/dotlock.c                      |    3 +-
 examples/Makefile.am                   |   23 +-
 examples/base64.c                      |  125 ++-
 examples/cpp/msg-send.cc               |    2 +-
 examples/header.c                      |   40 +-
 examples/http.c                        |   47 +-
 examples/iconv.c                       |   17 +-
 examples/mimetest.c                    |   15 +-
 examples/msg-send.c                    |    2 +-
 examples/mta.c                         |   29 +-
 examples/muauth.c                      |    3 +-
 examples/mucat.c                       |   87 +
 examples/murun.c                       |   16 +-
 examples/musocio.c                     |  124 ++
 examples/nntpclient.c                  |   13 +-
 examples/pop3client.c                  |  876 +++++++----
 examples/sfrom.c                       |    7 +-
 frm/frm.c                              |    3 +-
 frm/from.c                             |    3 +-
 guimb/main.c                           |    3 +-
 imap4d/Makefile.am                     |    1 +
 imap4d/append.c                        |   21 +-
 imap4d/auth_gsasl.c                    |  150 +-
 imap4d/auth_gss.c                      |   74 +-
 imap4d/authenticate.c                  |   72 +-
 imap4d/bye.c                           |   17 +-
 imap4d/capability.c                    |   10 +-
 imap4d/check.c                         |    4 +-
 imap4d/close.c                         |    8 +-
 imap4d/copy.c                          |    6 +-
 imap4d/create.c                        |   10 +-
 imap4d/delete.c                        |   10 +-
 imap4d/examine.c                       |    2 +-
 imap4d/expunge.c                       |    4 +-
 imap4d/fetch.c                         |  323 ++--
 imap4d/id.c                            |   12 +-
 imap4d/idle.c                          |   19 +-
 imap4d/imap4d.c                        |   18 +-
 imap4d/imap4d.h                        |   77 +-
 imap4d/io.c                            |  622 ++++++++
 imap4d/list.c                          |   35 +-
 imap4d/login.c                         |   15 +-
 imap4d/logout.c                        |    2 +-
 imap4d/lsub.c                          |   15 +-
 imap4d/namespace.c                     |   22 +-
 imap4d/noop.c                          |    4 +-
 imap4d/preauth.c                       |   23 +-
 imap4d/rename.c                        |   19 +-
 imap4d/search.c                        |   17 +-
 imap4d/select.c                        |   32 +-
 imap4d/starttls.c                      |   10 +-
 imap4d/status.c                        |   32 +-
 imap4d/store.c                         |   10 +-
 imap4d/subscribe.c                     |    6 +-
 imap4d/sync.c                          |   16 +-
 imap4d/uid.c                           |   10 +-
 imap4d/unsubscribe.c                   |    6 +-
 imap4d/util.c                          |  743 +---------
 include/mailutils/Makefile.am          |    2 +-
 include/mailutils/body.h               |    9 +-
 include/mailutils/filter.h             |   79 +-
 include/mailutils/folder.h             |    5 +-
 include/mailutils/gsasl.h              |    6 +-
 include/mailutils/header.h             |   14 +-
 include/mailutils/libargp.h            |    1 +
 include/mailutils/mailbox.h            |    4 +-
 include/mailutils/mailer.h             |    4 +-
 include/mailutils/mailutils.h          |    9 +-
 include/mailutils/message.h            |   32 +-
 include/mailutils/opool.h              |    4 +
 include/mailutils/pop3.h               |  125 +-
 include/mailutils/stream.h             |  323 ++--
 include/mailutils/sys/Makefile.am      |   42 +-
 include/mailutils/sys/amd.h            |  116 ++
 include/mailutils/sys/attribute.h      |   45 +
 include/mailutils/sys/auth.h           |   66 +
 include/mailutils/sys/body.h           |   50 +
 include/mailutils/sys/dbgstream.h      |   31 +
 include/mailutils/sys/debug.h          |   46 +
 include/mailutils/sys/envelope.h       |   43 +
 include/mailutils/sys/file_stream.h    |   37 +
 include/mailutils/sys/filter.h         |   55 +
 include/mailutils/sys/folder.h         |   73 +
 include/mailutils/sys/gsasl-stream.h   |   38 +
 include/mailutils/sys/header.h         |   80 +
 include/mailutils/sys/header_stream.h  |   30 +
 include/mailutils/sys/imap.h           |  236 +++
 include/mailutils/sys/iostream.h       |   34 +
 include/mailutils/sys/iterator.h       |   49 +
 include/mailutils/sys/list.h           |   62 +
 include/mailutils/sys/mailbox.h        |   83 +
 include/mailutils/sys/mailer.h         |   67 +
 include/mailutils/sys/mapfile_stream.h |   33 +
 include/mailutils/sys/memory_stream.h  |   33 +
 include/mailutils/sys/message.h        |   70 +
 include/mailutils/sys/message_stream.h |   48 +
 include/mailutils/sys/mime.h           |   97 ++
 include/mailutils/sys/monitor.h        |   37 +
 include/mailutils/sys/nntp.h           |    2 +-
 include/mailutils/sys/observer.h       |   56 +
 include/mailutils/sys/pop3.h           |  173 +-
 include/mailutils/sys/prog_stream.h    |   35 +
 include/mailutils/sys/property.h       |   51 +
 include/mailutils/sys/rdcache_stream.h |   33 +
 include/mailutils/sys/registrar.h      |   98 ++
 include/mailutils/sys/stream.h         |   84 +
 include/mailutils/sys/streamref.h      |   34 +
 include/mailutils/sys/streamtrans.h    |   27 +
 include/mailutils/sys/tls-stream.h     |   57 +
 include/mailutils/sys/url.h            |   66 +
 include/mailutils/sys/xscript-stream.h |   34 +
 include/mailutils/tls.h                |   21 +-
 include/mailutils/types.hin            |    5 +-
 lib/allocsa.valgrind                   |    7 -
 lib/mailcap.c                          |    8 +-
 lib/mu_dbm.c                           |    1 +
 lib/mu_dbm.h                           |    2 -
 libmu_argp/Makefile.am                 |    1 -
 libmu_argp/mu_argp.h                   |   46 -
 libmu_argp/muinit.c                    |   50 +-
 libmu_auth/Makefile.am                 |    2 -
 libmu_auth/gsasl.c                     |  316 ++---
 libmu_auth/lbuf.c                      |  167 --
 libmu_auth/lbuf.h                      |   37 -
 libmu_auth/ldap.c                      |   45 +-
 libmu_auth/tls.c                       |  616 ++++----
 libmu_scm/Makefile.am                  |    2 +-
 libmu_scm/mu_body.c                    |   56 +-
 libmu_scm/mu_mailbox.c                 |    2 +-
 libmu_scm/mu_message.c                 |   38 +-
 libmu_scm/mu_port.c                    |   49 +-
 libmu_sieve/actions.c                  |   66 +-
 libmu_sieve/extensions/moderator.c     |    3 +-
 libmu_sieve/extensions/pipe.c          |  149 +-
 libmu_sieve/extensions/spamd.c         |   55 +-
 libmu_sieve/extensions/vacation.c      |   59 +-
 libproto/Makefile.am                   |   22 +-
 libproto/imap/Makefile.am              |    2 +-
 libproto/imap/folder.c                 |   12 +-
 libproto/imap/mbox.c                   |    8 +-
 libproto/imap/url.c                    |    4 +-
 libproto/include/.gitignore            |    2 -
 libproto/include/Makefile.am           |   43 -
 libproto/include/amd.h                 |  112 --
 libproto/include/attribute0.h          |   49 -
 libproto/include/auth0.h               |   70 -
 libproto/include/body0.h               |   53 -
 libproto/include/debug0.h              |   50 -
 libproto/include/envelope0.h           |   47 -
 libproto/include/filter0.h             |   50 -
 libproto/include/folder0.h             |   77 -
 libproto/include/header0.h             |   84 -
 libproto/include/imap0.h               |  241 ---
 libproto/include/iterator0.h           |   53 -
 libproto/include/list0.h               |   66 -
 libproto/include/mailbox0.h            |   87 -
 libproto/include/mailer0.h             |   71 -
 libproto/include/message0.h            |   76 -
 libproto/include/mime0.h               |  100 --
 libproto/include/monitor0.h            |   41 -
 libproto/include/observer0.h           |   62 -
 libproto/include/property0.h           |   55 -
 libproto/include/registrar0.h          |   98 --
 libproto/include/stream0.h             |   76 -
 libproto/include/url0.h                |   71 -
 libproto/maildir/Makefile.am           |    2 +-
 libproto/maildir/folder.c              |    8 +-
 libproto/maildir/mbox.c                |    6 +-
 libproto/mailer/Makefile.am            |    2 +-
 libproto/mailer/mbox.c                 |    4 +-
 libproto/mailer/prog.c                 |    8 +-
 libproto/mailer/remote.c               |    6 +-
 libproto/mailer/sendmail.c             |    8 +-
 libproto/mailer/smtp.c                 |  251 ++--
 libproto/mbox/Makefile.am              |    2 +-
 libproto/mbox/folder.c                 |    4 +-
 libproto/mbox/mbox.c                   | 2178 +++++++++++---------------
 libproto/mbox/mbox0.h                  |   61 +-
 libproto/mbox/mboxscan.c               |   32 +-
 libproto/mh/Makefile.am                |    2 +-
 libproto/mh/folder.c                   |   10 +-
 libproto/mh/mbox.c                     |    6 +-
 libproto/nntp/Makefile.am              |    2 +-
 libproto/nntp/folder.c                 |    6 +-
 libproto/nntp/mbox.c                   |    6 +-
 libproto/nntp/nntp_article.c           |    1 +
 libproto/nntp/nntp_carrier.c           |    2 +-
 libproto/nntp/nntp_destroy.c           |    2 +-
 libproto/nntp/nntp_ihave.c             |    4 +-
 libproto/nntp/nntp_post.c              |    3 +-
 libproto/nntp/nntp_readline.c          |    4 +-
 libproto/nntp/nntp_sendline.c          |    2 +-
 libproto/nntp/nntp_stream.c            |    2 +-
 libproto/nntp/url.c                    |    2 +-
 libproto/pop/Makefile.am               |   14 +-
 libproto/pop/folder.c                  |    8 +-
 libproto/pop/mbox.c                    | 2734 ++++++++------------------------
 libproto/pop/pop3_apop.c               |   28 +-
 libproto/pop/pop3_capa.c               |   62 +-
 libproto/pop/pop3_capatst.c            |   37 +
 libproto/pop/pop3_carrier.c            |    6 +-
 libproto/pop/pop3_connect.c            |   30 +-
 libproto/pop/pop3_create.c             |   42 +-
 libproto/pop/pop3_debug.c              |   51 -
 libproto/pop/pop3_dele.c               |   11 +-
 libproto/pop/pop3_destroy.c            |   16 +-
 libproto/pop/pop3_disconnect.c         |    9 +-
 libproto/pop/pop3_iterator.c           |   71 +-
 libproto/pop/pop3_list.c               |   16 +-
 libproto/pop/pop3_list_cmd.c           |   64 +
 libproto/pop/pop3_lista.c              |   50 +-
 libproto/pop/pop3_listas.c             |   39 +
 libproto/pop/pop3_noop.c               |   11 +-
 libproto/pop/pop3_pass.c               |   19 +-
 libproto/pop/pop3_quit.c               |   12 +-
 libproto/pop/pop3_rdlist.c             |   65 +
 libproto/pop/pop3_readline.c           |  147 +--
 libproto/pop/pop3_response.c           |   47 +-
 libproto/pop/pop3_retr.c               |   17 +-
 libproto/pop/pop3_rset.c               |   11 +-
 libproto/pop/pop3_sendline.c           |   80 +-
 libproto/pop/pop3_stat.c               |   20 +-
 libproto/pop/pop3_stls.c               |   71 +-
 libproto/pop/pop3_stream.c             |  314 +++-
 libproto/pop/pop3_top.c                |   20 +-
 libproto/pop/pop3_trace.c              |  150 ++
 libproto/pop/pop3_uidl.c               |   69 +-
 libproto/pop/pop3_uidl_cmd.c           |   61 +
 libproto/pop/pop3_uidla.c              |   51 +-
 libproto/pop/pop3_uidlas.c             |   36 +
 libproto/pop/pop3_user.c               |   11 +-
 libproto/pop/url.c                     |    4 +-
 maidag/maidag.c                        |    2 +-
 maidag/mailtmp.c                       |   24 +-
 mail/decode.c                          |   41 +-
 mail/escape.c                          |   39 +-
 mail/mail.c                            |    2 +-
 mail/msgset.y                          |    9 +-
 mail/pipe.c                            |   11 +-
 mail/print.c                           |   21 +-
 mail/send.c                            |   34 +-
 mail/top.c                             |    9 +-
 mail/util.c                            |    6 +-
 mail/write.c                           |   10 +-
 mailbox/Makefile.am                    |   22 +-
 mailbox/alloc.c                        |   22 +-
 mailbox/amd.c                          |  387 +++--
 mailbox/argcv.c                        |    2 +
 mailbox/assoc.c                        |    2 +-
 mailbox/attachment.c                   |  158 +--
 mailbox/attribute.c                    |    2 +-
 mailbox/auth.c                         |    2 +-
 mailbox/base64.c                       |  198 +++-
 mailbox/binflt.c                       |  113 ++
 mailbox/body.c                         |  182 ++-
 mailbox/cfg_driver.c                   |    5 +-
 mailbox/cfg_format.c                   |   83 +-
 mailbox/crlfflt.c                      |  182 +++
 mailbox/dbgstream.c                    |   86 +
 mailbox/debug.c                        |   43 +-
 mailbox/envelope.c                     |    2 +-
 mailbox/errors                         |    2 +
 mailbox/file_stream.c                  | 1187 ++------------
 mailbox/filter.c                       |  297 ++---
 mailbox/filter_iconv.c                 |  181 ++-
 mailbox/filter_rfc822.c                |  203 ---
 mailbox/filter_trans.c                 |  796 ----------
 mailbox/fltstream.c                    |  491 ++++++
 mailbox/folder.c                       |   29 +-
 mailbox/hdritr.c                       |    2 +-
 mailbox/header.c                       |  287 ++--
 mailbox/iostream.c                     |  248 +++
 mailbox/iterator.c                     |    4 +-
 mailbox/linelenflt.c                   |  110 ++
 mailbox/list.c                         |    4 +-
 mailbox/listlist.c                     |    4 +-
 mailbox/mailbox.c                      |   28 +-
 mailbox/mailcap.c                      |   20 +-
 mailbox/mailer.c                       |   62 +-
 mailbox/mapfile_stream.c               |  246 ++--
 mailbox/mbx_default.c                  |    2 +-
 mailbox/mbxitr.c                       |    2 +-
 mailbox/memory_stream.c                |  266 ++--
 mailbox/message.c                      | 1001 +++++++-----
 mailbox/message_stream.c               |  512 +++----
 mailbox/mime.c                         |  368 +++--
 mailbox/mimehdr.c                      |   26 +-
 mailbox/monitor.c                      |    2 +-
 mailbox/msgscan.c                      |  106 ++
 mailbox/mutil.c                        |   14 +-
 mailbox/nullrec.c                      |   49 +
 mailbox/observer.c                     |    2 +-
 mailbox/opool.c                        |   19 +
 mailbox/prog_stream.c                  |  462 ++++++
 mailbox/progmailer.c                   |   34 +-
 mailbox/property.c                     |    2 +-
 mailbox/qpflt.c                        |  262 +++
 mailbox/rdcache_stream.c               |  201 +++
 mailbox/registrar.c                    |    2 +-
 mailbox/rfc2047.c                      |   31 +-
 mailbox/socket_stream.c                |  233 +---
 mailbox/stdio_stream.c                 |   83 +
 mailbox/stream.c                       | 1609 ++++++++++---------
 mailbox/stream_printf.c                |   32 +
 mailbox/stream_vprintf.c               |   42 +
 mailbox/streamcpy.c                    |  128 ++
 mailbox/streamref.c                    |  311 ++++
 mailbox/tcp.c                          |  142 +-
 mailbox/temp_file_stream.c             |   65 +
 mailbox/testsuite/mailbox/base64.exp   |    4 +-
 mailbox/ticket.c                       |    2 +-
 mailbox/url.c                          |    2 +-
 mailbox/vartab.c                       |   36 +-
 mailbox/wicket.c                       |    9 +-
 mailbox/xscript-stream.c               |  431 +++++
 messages/messages.c                    |    3 +-
 mh/ali.c                               |    9 +-
 mh/anno.c                              |    9 +-
 mh/burst.c                             |   52 +-
 mh/comp.c                              |   51 +-
 mh/compcommon.c                        |    8 +-
 mh/fmtcheck.c                          |    9 +-
 mh/folder.c                            |   10 +-
 mh/forw.c                              |   44 +-
 mh/inc.c                               |    9 +-
 mh/install-mh.c                        |    9 +-
 mh/mark.c                              |    9 +-
 mh/mh_argp.c                           |   45 +-
 mh/mh_ctx.c                            |   17 +-
 mh/mh_format.c                         |   13 +-
 mh/mh_getopt.h                         |    3 +-
 mh/mh_init.c                           |   12 +-
 mh/mh_list.c                           |   32 +-
 mh/mh_whatnow.c                        |    9 +-
 mh/mhl.c                               |   17 +-
 mh/mhn.c                               |  201 +--
 mh/mhparam.c                           |    9 +-
 mh/mhpath.c                            |    9 +-
 mh/pick.c                              |    9 +-
 mh/pick.y                              |    6 +-
 mh/refile.c                            |    9 +-
 mh/repl.c                              |   15 +-
 mh/rmf.c                               |    9 +-
 mh/rmm.c                               |    9 +-
 mh/scan.c                              |   10 +-
 mh/send.c                              |    9 +-
 mh/sortm.c                             |   10 +-
 mh/whatnow.c                           |   10 +-
 mh/whom.c                              |   10 +-
 mimeview/mimeview.c                    |   16 +-
 movemail/movemail.c                    |    3 +-
 mu-aux/generr.awk                      |    1 +
 pop3d/apop.c                           |   92 +-
 pop3d/capa.c                           |   27 +-
 pop3d/dele.c                           |    2 +-
 pop3d/extra.c                          |  180 ++-
 pop3d/list.c                           |    8 +-
 pop3d/logindelay.c                     |    2 +-
 pop3d/noop.c                           |    2 +-
 pop3d/pop3d.c                          |   17 +-
 pop3d/pop3d.h                          |   13 +-
 pop3d/popauth.c                        |    8 +-
 pop3d/quit.c                           |    2 +-
 pop3d/retr.c                           |   47 +-
 pop3d/rset.c                           |    2 +-
 pop3d/stat.c                           |    2 +-
 pop3d/stls.c                           |    4 +-
 pop3d/top.c                            |   88 +-
 pop3d/uidl.c                           |    8 +-
 pop3d/user.c                           |   25 +-
 readmsg/msglist.c                      |   25 +-
 readmsg/readmsg.c                      |   37 +-
 sieve/sieve.c                          |    6 +-
 sieve/testsuite/Redirect               |   94 +-
 sieve/testsuite/Reject                 |  328 ++--
 382 files changed, 16448 insertions(+), 15402 deletions(-)
 create mode 100644 examples/mucat.c
 create mode 100644 examples/musocio.c
 create mode 100644 imap4d/io.c
 create mode 100644 include/mailutils/sys/amd.h
 create mode 100644 include/mailutils/sys/attribute.h
 create mode 100644 include/mailutils/sys/auth.h
 create mode 100644 include/mailutils/sys/body.h
 create mode 100644 include/mailutils/sys/dbgstream.h
 create mode 100644 include/mailutils/sys/debug.h
 create mode 100644 include/mailutils/sys/envelope.h
 create mode 100644 include/mailutils/sys/file_stream.h
 create mode 100644 include/mailutils/sys/filter.h
 create mode 100644 include/mailutils/sys/folder.h
 create mode 100644 include/mailutils/sys/gsasl-stream.h
 create mode 100644 include/mailutils/sys/header.h
 create mode 100644 include/mailutils/sys/header_stream.h
 create mode 100644 include/mailutils/sys/imap.h
 create mode 100644 include/mailutils/sys/iostream.h
 create mode 100644 include/mailutils/sys/iterator.h
 create mode 100644 include/mailutils/sys/list.h
 create mode 100644 include/mailutils/sys/mailbox.h
 create mode 100644 include/mailutils/sys/mailer.h
 create mode 100644 include/mailutils/sys/mapfile_stream.h
 create mode 100644 include/mailutils/sys/memory_stream.h
 create mode 100644 include/mailutils/sys/message.h
 create mode 100644 include/mailutils/sys/message_stream.h
 create mode 100644 include/mailutils/sys/mime.h
 create mode 100644 include/mailutils/sys/monitor.h
 create mode 100644 include/mailutils/sys/observer.h
 create mode 100644 include/mailutils/sys/prog_stream.h
 create mode 100644 include/mailutils/sys/property.h
 create mode 100644 include/mailutils/sys/rdcache_stream.h
 create mode 100644 include/mailutils/sys/registrar.h
 create mode 100644 include/mailutils/sys/stream.h
 create mode 100644 include/mailutils/sys/streamref.h
 create mode 100644 include/mailutils/sys/streamtrans.h
 create mode 100644 include/mailutils/sys/tls-stream.h
 create mode 100644 include/mailutils/sys/url.h
 create mode 100644 include/mailutils/sys/xscript-stream.h
 delete mode 100644 lib/allocsa.valgrind
 delete mode 100644 libmu_argp/mu_argp.h
 delete mode 100644 libmu_auth/lbuf.c
 delete mode 100644 libmu_auth/lbuf.h
 delete mode 100644 libproto/include/.gitignore
 delete mode 100644 libproto/include/Makefile.am
 delete mode 100644 libproto/include/amd.h
 delete mode 100644 libproto/include/attribute0.h
 delete mode 100644 libproto/include/auth0.h
 delete mode 100644 libproto/include/body0.h
 delete mode 100644 libproto/include/debug0.h
 delete mode 100644 libproto/include/envelope0.h
 delete mode 100644 libproto/include/filter0.h
 delete mode 100644 libproto/include/folder0.h
 delete mode 100644 libproto/include/header0.h
 delete mode 100644 libproto/include/imap0.h
 delete mode 100644 libproto/include/iterator0.h
 delete mode 100644 libproto/include/list0.h
 delete mode 100644 libproto/include/mailbox0.h
 delete mode 100644 libproto/include/mailer0.h
 delete mode 100644 libproto/include/message0.h
 delete mode 100644 libproto/include/mime0.h
 delete mode 100644 libproto/include/monitor0.h
 delete mode 100644 libproto/include/observer0.h
 delete mode 100644 libproto/include/property0.h
 delete mode 100644 libproto/include/registrar0.h
 delete mode 100644 libproto/include/stream0.h
 delete mode 100644 libproto/include/url0.h
 create mode 100644 libproto/pop/pop3_capatst.c
 delete mode 100644 libproto/pop/pop3_debug.c
 create mode 100644 libproto/pop/pop3_list_cmd.c
 create mode 100644 libproto/pop/pop3_listas.c
 create mode 100644 libproto/pop/pop3_rdlist.c
 create mode 100644 libproto/pop/pop3_trace.c
 create mode 100644 libproto/pop/pop3_uidl_cmd.c
 create mode 100644 libproto/pop/pop3_uidlas.c
 create mode 100644 mailbox/binflt.c
 create mode 100644 mailbox/crlfflt.c
 create mode 100644 mailbox/dbgstream.c
 delete mode 100644 mailbox/filter_rfc822.c
 delete mode 100644 mailbox/filter_trans.c
 create mode 100644 mailbox/fltstream.c
 create mode 100644 mailbox/iostream.c
 create mode 100644 mailbox/linelenflt.c
 create mode 100644 mailbox/msgscan.c
 create mode 100644 mailbox/nullrec.c
 create mode 100644 mailbox/prog_stream.c
 create mode 100644 mailbox/qpflt.c
 create mode 100644 mailbox/rdcache_stream.c
 create mode 100644 mailbox/stdio_stream.c
 create mode 100644 mailbox/stream_printf.c
 create mode 100644 mailbox/stream_vprintf.c
 create mode 100644 mailbox/streamcpy.c
 create mode 100644 mailbox/streamref.c
 create mode 100644 mailbox/temp_file_stream.c
 create mode 100644 mailbox/xscript-stream.c

diff --git a/.gitignore b/.gitignore
index 3f3f74e..a142bc9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,6 +22,8 @@ config.h.in
 config.log
 config.status
 configure
+git-describe
+git-describe.h
 libtool
 m4
 pathdefs.h
diff --git a/Makefile.am b/Makefile.am
index f6f53a9..81aefd2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -85,11 +85,11 @@ if MU_COND_LIBMU_SCM
   LIBMU_SCM_DIR = libmu_scm
 endif
 
-if MU_COND_LIBMU_CPP
+if MU_COND_SUPPORT_CXX
   LIBMU_CPP_DIR = libmu_cpp
 endif
 
-SUBDIRS = \
+SUBDIRS = . \
  mu-aux\
  include\
  po\
@@ -124,8 +124,8 @@ SUBDIRS = \
  $(MOVEMAIL_DIR)\
  $(MIMEVIEW_DIR)
 
-EXTRA_DIST = COPYING.LESSER paths
-
+EXTRA_DIST = COPYING.LESSER paths git-describe git-describe.h
+BUILT_SOURCES = git-describe git-describe.h
 DISTCLEANFILES = pathdefs.h
 
 gen_start_date = "2008-12-08"
@@ -155,12 +155,45 @@ ChangeLog:
          mv cl-t ChangeLog;                                               \
        fi
 
-alpha:
-       $(MAKE) dist distdir=$(PACKAGE)-$(VERSION)-`date +"%Y%m%d"`
+.PHONY: git-describe
+git-describe:
+       $(AM_V_GEN)if test -d .git; then \
+               dirty=`git diff-index --name-only HEAD 2>/dev/null` || dirty=;\
+               test -n "$$dirty" && dirty="-dirty"; \
+               descr=`git describe`; \
+               echo $${descr}$$dirty > git-describe; \
+       fi
 
-alphacheck:
-       $(MAKE) distcheck distdir=$(PACKAGE)-$(VERSION)-`date +"%Y%m%d"`
+dist-hook: ChangeLog git-describe
+       @PATCHLEV=`echo "$(PACKAGE_VERSION)" | \
+                   sed -r "s/[0-9]+\.[0-9]+\.?//"`; \
+       if test $${PATCHLEV:-0} -lt 50; then \
+               if grep -q FIXME NEWS; then \
+                       echo >&2 "NEWS file contains FIXMEs"; \
+                       exit 1; \
+               fi; \
+       fi
+
+git-describe.h: git-describe
+       $(AM_V_GEN)if test -f $(srcdir)/git-describe; then \
+         sed '1s/.*/#define GIT_DESCRIBE "&"/' $(srcdir)/git-describe; \
+       else \
+          echo "/* No git tag */"; \
+       fi > git-describe.h
+
+alpha: git-describe
+       $(AM_V_GEN)if test -f $(srcdir)/git-describe; then \
+         tag=`head -n 1 $(srcdir)/git-describe`; \
+       else \
+         tag=`date +"%Y%m%d"`; \
+       fi; \
+       $(MAKE) dist distdir=$(PACKAGE)-$(VERSION)-$$tag
 
-rpm: dist
-       rpm -ta --clean mailutils-$(VERSION).tar.gz
+alphacheck:
+       $(AM_V_GEN)if test -f $(srcdir)/git-describe; then \
+         tag=`head -n 1 $(srcdir)/git-describe`; \
+       else \
+         tag=`date +"%Y%m%d"`; \
+       fi; \
+       $(MAKE) distcheck distdir=$(PACKAGE)-$(VERSION)-$$tag
 
diff --git a/am/enable.m4 b/am/enable.m4
index faf3a31..e531c98 100644
--- a/am/enable.m4
+++ b/am/enable.m4
@@ -23,6 +23,7 @@ dnl                   [default-value])
 AC_DEFUN([MU_ENABLE_SUPPORT], [
        pushdef([mu_upcase],translit($1,[a-z+-],[A-ZX_]))
        pushdef([mu_cache_var],[mu_cv_enable_]translit($1,[+-],[x_]))
+       pushdef([mu_cond],[MU_COND_SUPPORT_]mu_upcase)
 
        AC_ARG_ENABLE($1, 
                      AC_HELP_STRING([--disable-]$1,
@@ -43,8 +44,11 @@ AC_DEFUN([MU_ENABLE_SUPPORT], [
        if test x"[$]mu_cache_var" = x"yes"; then
                AC_DEFINE([ENABLE_]mu_upcase,1,[Define this if you enable $1 
support])
         fi
-       popdef([mu_upcase])
+       AM_CONDITIONAL(mu_cond,
+                      [test x"[$]mu_cache_var" = x"yes" ifelse($4,,,[&& $4])])
+       popdef([mu_cond])
        popdef([mu_cache_var])
+       popdef([mu_upcase])
 ])
 
 dnl MU_ENABLE_BUILD(feature, [action-if-true], [action-if-false],
diff --git a/comsat/action.c b/comsat/action.c
index 738079b..738521c 100644
--- a/comsat/action.c
+++ b/comsat/action.c
@@ -155,14 +155,14 @@ expand_escape (char **pp, mu_message_t msg, struct 
obstack *stk)
       if (lncount == 0)
        lncount = maxlines;
       if (mu_message_get_body (msg, &body) == 0
-         && mu_body_get_stream (body, &stream) == 0)
+         && mu_body_get_streamref (body, &stream) == 0)
        {
          size_t nread;
          char *buf = malloc (size+1);
 
          if (!buf)
            break;
-         if (mu_stream_read (stream, buf, size, 0, &nread) == 0)
+         if (mu_stream_read (stream, buf, size, &nread) == 0)
            {
              char *q;
 
@@ -179,6 +179,7 @@ expand_escape (char **pp, mu_message_t msg, struct obstack 
*stk)
                }
              obstack_grow (stk, buf, size);
            }
+         mu_stream_destroy (&stream);
          free (buf);
        }
       *pp = p;
diff --git a/comsat/comsat.c b/comsat/comsat.c
index 82e8056..ca11efe 100644
--- a/comsat/comsat.c
+++ b/comsat/comsat.c
@@ -570,7 +570,7 @@ main (int argc, char **argv)
   /* Native Language Support */
   MU_APP_INIT_NLS ();
 
-  mu_argp_init (program_version, NULL);
+  mu_argp_init (NULL, NULL);
   comsat_init ();
   mu_acl_cfg_init ();
   mu_m_server_cfg_init ();
diff --git a/config/mailutils-config.c b/config/mailutils-config.c
index c246d10..ccf55ab 100644
--- a/config/mailutils-config.c
+++ b/config/mailutils-config.c
@@ -25,7 +25,6 @@
 #include <mu_asprintf.h>
 #include "mailutils/libargp.h"
 
-const char *program_version = "mailutils-config (" PACKAGE_STRING ")";
 static char doc[] = N_("GNU mailutils-config -- display compiler and loader 
options needed for building a program with mailutils.");
 static char args_doc[] = N_("[arg...]");
 
@@ -188,7 +187,7 @@ main (int argc, char **argv)
   mu_stream_t stream;
   int fmtflags = 0;
   
-  mu_argp_init (program_version, NULL);
+  mu_argp_init (NULL, NULL);
 
   mu_set_program_name (argv[0]);
   mu_libargp_init ();
@@ -343,7 +342,7 @@ main (int argc, char **argv)
        exit (1);
       if (!tree)
        exit (0);
-      rc = mu_stdio_stream_create (&stream, stdout, 0);
+      rc = mu_stdio_stream_create (&stream, MU_STDOUT_FD, 0);
       if (rc)
        {
          mu_error ("mu_stdio_stream_create: %s", mu_strerror (rc));
diff --git a/configure.ac b/configure.ac
index 275d50f..eb11d20 100644
--- a/configure.ac
+++ b/configure.ac
@@ -40,16 +40,16 @@ dnl Library paths
 AC_SUBST(MU_LIB_AUTH,'${top_builddir}/libmu_auth/libmu_auth.la')
 AC_SUBST(MU_LIB_MAILUTILS,'${top_builddir}/mailbox/libmailutils.la')
 AC_SUBST(MU_LIB_SQL,'${top_builddir}/sql/libsql.la')
-AC_SUBST(MU_LIB_IMAP,'${top_builddir}/libproto/imap/libmu_imap.la')
-AC_SUBST(MU_LIB_MAILDIR,'${top_builddir}/libproto/maildir/libmu_maildir.la')
+AC_SUBST(MU_LIB_IMAP)
+AC_SUBST(MU_LIB_MAILDIR)
 AC_SUBST(MU_LIB_MAILER,'${top_builddir}/libproto/mailer/libmu_mailer.la')
 AC_SUBST(MU_LIB_MBOX,'${top_builddir}/libproto/mbox/libmu_mbox.la')
-AC_SUBST(MU_LIB_MH,'${top_builddir}/libproto/mh/libmu_mh.la')
-AC_SUBST(MU_LIB_NNTP,'${top_builddir}/libproto/nntp/libmu_nntp.la')
-AC_SUBST(MU_LIB_POP,'${top_builddir}/libproto/pop/libmu_pop.la')
+AC_SUBST(MU_LIB_MH)
+AC_SUBST(MU_LIB_NNTP)
+AC_SUBST(MU_LIB_POP)
 AC_SUBST(MU_LIB_SIEVE,'${top_builddir}/libmu_sieve/libmu_sieve.la')
-AC_SUBST(MU_LIB_SCM,'${top_builddir}/libmu_scm/libmu_scm.la')
-AC_SUBST(MU_LIB_CPP,'${top_builddir}/libmu_cpp/libmu_cpp.la')
+AC_SUBST(MU_LIB_SCM)
+AC_SUBST(MU_LIB_CPP)
 AC_SUBST(MU_LIB_ARGP,'${top_builddir}/libmu_argp/libmu_argp.la')
 AC_SUBST(MU_LIB_PY)
 
@@ -69,7 +69,7 @@ AC_SUBST(MU_APP_LIBRARIES,'../libmu_argp/libmu_argp.a 
../libmu_cfg/libmu_cfg.la
 # header files. There are two exceptions, though. See NOTE before the
 # AC_CONFIG_LINKS statements, below.
 
-AC_SUBST(MU_LIB_COMMON_INCLUDES,'-I${top_builddir} -I${top_srcdir}/include  
-I${top_builddir}/include -I${top_srcdir}/mailbox 
-I${top_srcdir}/libproto/include')
+AC_SUBST(MU_LIB_COMMON_INCLUDES,'-I${top_builddir} -I${top_srcdir}/include  
-I${top_builddir}/include -I${top_srcdir}/mailbox')
 
 AC_SUBST(MU_APP_COMMON_INCLUDES,'-I${srcdir} -I${top_srcdir}/include 
-I${top_srcdir}/lib -I${top_builddir}/lib -I${top_builddir} 
-I${top_builddir}/include -I${top_srcdir}/mailbox -I${top_srcdir}/libmu_argp 
-I${top_srcdir}/libmu_cfg')
 
@@ -805,9 +805,17 @@ AC_ARG_WITH([virtual-pwddir],
                *)  SITE_VIRTUAL_PWDDIR="\$(sysconfdir)/${withval}";;
             esac],
              [SITE_VIRTUAL_PWDDIR="\$(sysconfdir)/domain"])
-MU_ENABLE_SUPPORT(imap)
-MU_ENABLE_SUPPORT(pop)
-MU_ENABLE_SUPPORT(nntp)
+            
+MU_ENABLE_SUPPORT([imap],
+         [MU_LIB_IMAP='${top_builddir}/libproto/imap/libmu_imap.la'])
+MU_ENABLE_SUPPORT([pop],
+         [MU_LIB_POP='${top_builddir}/libproto/pop/libmu_pop.la'])
+MU_ENABLE_SUPPORT([nntp],
+         [MU_LIB_NNTP='${top_builddir}/libproto/nntp/libmu_nntp.la'])
+MU_ENABLE_SUPPORT([mh],
+         [MU_LIB_MH='${top_builddir}/libproto/mh/libmu_mh.la'])
+MU_ENABLE_SUPPORT([maildir],
+         [MU_LIB_MAILDIR='${top_builddir}/libproto/maildir/libmu_maildir.la'])
 
 AC_SUBST(MU_SMTP_PROGRAMS_BUILD)
 AC_SUBST(MU_SMTP_DEJATOOL)
@@ -819,9 +827,6 @@ MU_ENABLE_SUPPORT(sendmail)
 
 MU_ENABLE_SUPPORT(prog)
 
-MU_ENABLE_SUPPORT(mh)
-
-MU_ENABLE_SUPPORT(maildir)
 
 # FIXME: Should be --with-radius 
 MU_ENABLE_SUPPORT(radius,
@@ -1091,14 +1096,14 @@ fi
 AC_SUBST(lisp_LISP)
 
 # Check for Python
-AC_ARG_WITH([python],
-            AC_HELP_STRING([--without-python],
-                           [do not build Python interface]),
-            [
-case "${withval}" in
+AC_ARG_ENABLE([python],
+              AC_HELP_STRING([--disable-python],
+                             [do not build Python interface]),
+              [
+case "${enableval}" in
   yes) status_python=yes ;;
   no)  status_python=no ;;
-  *)   AC_MSG_ERROR(bad value ${withval} for --without-python) ;;
+  *)   AC_MSG_ERROR(bad value ${enableval} for --enable-python) ;;
 esac],[status_python=yes])
 
 AC_SUBST(PYTHON_LIBS)
@@ -1138,8 +1143,8 @@ AM_CONDITIONAL([MU_COND_PYTHON], [test "$status_python" = 
yes])
 
 AC_SUBST(MU_CXX_EXAMPLES_BUILD)
 MU_ENABLE_SUPPORT(cxx,
-                 [MU_CXX_EXAMPLES_BUILD='$(MU_CXX_EXAMPLES_LIST)'])
-AM_CONDITIONAL([MU_COND_LIBMU_CPP], [test "$mu_cv_enable_cxx" = yes])
+                 [MU_CXX_EXAMPLES_BUILD='$(MU_CXX_EXAMPLES_LIST)'
+                   MU_LIB_CPP='${top_builddir}/libmu_cpp/libmu_cpp.la'])
 
 # Default mailbox record
 # Note: 1. Support for mbox type is always enabled.
@@ -1224,12 +1229,13 @@ case `echo $VERSION|sed  's/[[^.]]//g'` in
 "..")  if test `echo $VERSION | sed  's/.*\.//'` -lt 50; then
         RENDITION=DISTRIB
        else
+         AC_DEFINE_UNQUOTED([MU_ALPHA_RELEASE], 1,
+                           [Define if this is an alpha release])
          RENDITION=PROOF
        fi;;
 *)     RENDITION=PROOF;;
 esac
 
-
 AC_CONFIG_COMMANDS([status],[
 cat <<EOF
 
@@ -1344,7 +1350,6 @@ AC_CONFIG_FILES([
  libproto/pop/Makefile
  libproto/nntp/Makefile
  libproto/imap/Makefile
- libproto/include/Makefile
  maidag/Makefile
  mail/Makefile
  mail/testsuite/Makefile
diff --git a/dotlock/dotlock.c b/dotlock/dotlock.c
index 6315b2d..d561d18 100644
--- a/dotlock/dotlock.c
+++ b/dotlock/dotlock.c
@@ -33,7 +33,6 @@
 
 #include "mailutils/libargp.h"
 
-const char *program_version = "GNU dotlock (" PACKAGE_STRING ")";
 static char doc[] =
 N_("GNU dotlock -- lock mail spool files.")
 "\v"
@@ -161,7 +160,7 @@ main (int argc, char *argv[])
 
   argp_err_exit_status = MU_DL_EX_ERROR;
   
-  mu_argp_init (program_version, NULL);
+  mu_argp_init (NULL, NULL);
   if (mu_app_init (&argp, dotlock_capa, dotlock_cfg_param, 
                   argc, argv, 0, NULL, NULL))
     exit (1);
diff --git a/examples/Makefile.am b/examples/Makefile.am
index cb2415b..7e858d7 100644
--- a/examples/Makefile.am
+++ b/examples/Makefile.am
@@ -18,7 +18,19 @@
 ##   Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA
 ##   02110-1301 USA
 
-SUBDIRS = config cpp python scheme
+if MU_COND_SUPPORT_POP
+  POP3CLIENT = pop3client
+endif
+
+if MU_COND_SUPPORT_NNTP
+  NNTPCLIENT = nntpclient
+endif
+
+if MU_COND_SUPPORT_CXX
+  CPP_DIR = cpp
+endif
+
+SUBDIRS = config $(CPP_DIR) python scheme
 
 noinst_PROGRAMS = \
  aclck\
@@ -37,14 +49,18 @@ noinst_PROGRAMS = \
  mimetest\
  msg-send\
  mta\
+ mucat\
  muauth\
  muemail\
  murun\
- nntpclient\
- pop3client \
+ musocio\
+ $(NNTPCLIENT)\
+ $(POP3CLIENT)\
  sfrom\
  url-parse
 
+EXTRA_PROGRAMS = pop3client nntpclient
+
 ## NOTE: Numaddr must be an installable target, otherwise libtool
 ## will not create a shared library and `make check' will fail in
 ## sieve. Pity.
@@ -97,6 +113,7 @@ sfrom_LDADD =\
  @address@hidden
  ${MU_LIB_MAILUTILS}
 
+pop3client_CPPFLAGS = @MU_APP_COMMON_INCLUDES@
 pop3client_LDADD = \
  ../lib/libmuaux.la\
  ${MU_LIB_POP}\
diff --git a/examples/base64.c b/examples/base64.c
index dc4fde5..aa6bdeb 100644
--- a/examples/base64.c
+++ b/examples/base64.c
@@ -29,19 +29,73 @@
 
 #define ISPRINT(c) ((c)>=' '&&(c)<127) 
 
+int verbose = 0;
+int printable = 0;
+
+static void
+c_copy (mu_stream_t out, mu_stream_t in)
+{
+  if (printable)
+    {
+      char c;
+      size_t size;
+      
+      while (mu_stream_read (in, &c, 1, &size) == 0 && size > 0)
+       {
+         int rc;
+         
+         if (printable && !ISPRINT (c))
+           {
+             char outbuf[24];
+             sprintf (outbuf, "\\%03o", (unsigned char) c);
+             rc = mu_stream_write (out, outbuf, strlen (outbuf), NULL);
+           }
+         else
+           rc = mu_stream_write (out, &c, 1, NULL);
+       }
+    }
+  else
+    MU_ASSERT (mu_stream_copy (out, in, 0, NULL));
+  mu_stream_write (out, "\n", 1, NULL);
+  mu_stream_close (out);
+  mu_stream_close (in);
+  if (verbose)
+    fprintf (stderr, "\ntotal: %lu/%lu bytes\n",
+            (unsigned long) mu_stream_bytes_in (in),
+            (unsigned long) mu_stream_bytes_out (out));
+}
+
+/* Set the maximum line length for the filter NAME to LENGTH.
+   FIXME: This is a kludge. Perhaps API should provide a function
+   for that. */
+static void
+reset_line_length (const char *name, size_t length)
+{
+  mu_list_t list;
+  int status;
+  mu_filter_record_t frec;
+  
+  mu_filter_get_list (&list);
+  status = mu_list_locate (list, (void*)name, (void**)&frec);
+  if (status == 0)
+    frec->max_line_length = length;
+  /* don't bail out, leave that to mu_filter_create */
+}
+
 int
 main (int argc, char * argv [])
 {
   mu_stream_t in, out, flt;
-  unsigned char buffer;
-  int c, verbose = 0;
-  int printable = 0;
-  size_t size, total = 0;
+  int c;
   int mode = MU_FILTER_ENCODE;
+  int flags = MU_STREAM_READ;
   char *input = NULL, *output = NULL;
   char *encoding = "base64";
-    
-  while ((c = getopt (argc, argv, "deE:hi:o:pv")) != EOF)
+  mu_off_t shift = 0;
+  size_t line_length;
+  int line_length_option = 0;
+  
+  while ((c = getopt (argc, argv, "deE:hi:l:o:ps:vw")) != EOF)
     switch (c)
       {
       case 'i':
@@ -64,9 +118,18 @@ main (int argc, char * argv [])
        mode = MU_FILTER_ENCODE;
        break;
 
+      case 'l':
+       line_length = strtoul (optarg, NULL, 10);
+       line_length_option = 1;
+       break;
+       
       case 'p':
        printable = 1;
        break;
+
+      case 's':
+       shift = strtoul (optarg, NULL, 0); 
+       break;
        
       case 'v':
        verbose = 1;
@@ -75,44 +138,48 @@ main (int argc, char * argv [])
       case 'h':
        printf ("usage: base64 [-vpde][-E encoding][-i infile][-o outfile]\n");
        exit (0);
-         
+
+      case 'w':
+       flags = MU_STREAM_WRITE;
+       break;
+       
       default:
        exit (1);
       }
 
   if (input)
-    MU_ASSERT (mu_file_stream_create (&in, input, MU_STREAM_READ));
+    MU_ASSERT (mu_file_stream_create (&in, input, 
MU_STREAM_READ|MU_STREAM_SEEK));
   else
-    MU_ASSERT (mu_stdio_stream_create (&in, stdin, 0));
-  MU_ASSERT (mu_filter_create (&flt, in, encoding, mode, MU_STREAM_READ));
+    MU_ASSERT (mu_stdio_stream_create (&in, MU_STDIN_FD, 0));
   MU_ASSERT (mu_stream_open (in));
 
   if (output)
     MU_ASSERT (mu_file_stream_create (&out, output, 
                                       MU_STREAM_WRITE|MU_STREAM_CREAT));
   else
-    MU_ASSERT (mu_stdio_stream_create (&out, stdout, 0));
+    MU_ASSERT (mu_stdio_stream_create (&out, MU_STDOUT_FD, 0));
   MU_ASSERT (mu_stream_open (out));
+
+  if (line_length_option)
+    reset_line_length (encoding, line_length);
   
-  while (mu_stream_read (flt, (char*) &buffer,
-                        sizeof (buffer), total, &size) == 0
-        && size > 0)
+  if (flags == MU_STREAM_READ)
     {
-      if (printable && !ISPRINT (buffer))
-       {
-         char outbuf[24];
-         sprintf (outbuf, "\\%03o", (unsigned int) buffer);
-         mu_stream_sequential_write (out, outbuf, strlen (outbuf));
-       } 
-      else
-       mu_stream_sequential_write (out, (char*) &buffer, size);
-      total += size;
+      MU_ASSERT (mu_filter_create (&flt, in, encoding, mode,
+                                  MU_STREAM_READ|MU_STREAM_SEEK|
+                                  MU_STREAM_AUTOCLOSE));
+      if (shift)
+       MU_ASSERT (mu_stream_seek (flt, shift, MU_SEEK_SET, NULL));
+      c_copy (out, flt);
     }
-
-  mu_stream_sequential_write (out, "\n", 1);
-  mu_stream_close (in);
-  mu_stream_close (out);
-  if (verbose)
-    fprintf (stderr, "total: %lu bytes\n", (unsigned long) total);
+  else
+    {
+      MU_ASSERT (mu_filter_create (&flt, out, encoding, mode,
+                                  MU_STREAM_WRITE|MU_STREAM_AUTOCLOSE));
+      if (shift)
+       MU_ASSERT (mu_stream_seek (in, shift, MU_SEEK_SET, NULL));
+      c_copy (flt, in);
+    }
+      
   return 0;
 }
diff --git a/examples/cpp/msg-send.cc b/examples/cpp/msg-send.cc
index 59179d2..1c5eac6 100644
--- a/examples/cpp/msg-send.cc
+++ b/examples/cpp/msg-send.cc
@@ -88,7 +88,7 @@ main (int argc, char *argv[])
     }
 
   try {
-    StdioStream in (stdin, MU_STREAM_SEEKABLE);
+    StdioStream in (stdin, MU_STREAM_SEEK);
     in.open ();
 
     Message msg;
diff --git a/examples/header.c b/examples/header.c
index f53368a..63733f8 100644
--- a/examples/header.c
+++ b/examples/header.c
@@ -28,6 +28,7 @@
 char *file;
 mu_header_t header;
 mu_iterator_t iterator;
+mu_stream_t hstream;
 
 char *ps[] = { "> ", ". " };
 int interactive;
@@ -83,7 +84,7 @@ load_file (const char *name)
 
   buf[st.st_size] = '\n';
   buf[st.st_size+1] = 0;
-  status = mu_header_create (&header, buf, st.st_size + 1, NULL);
+  status = mu_header_create (&header, buf, st.st_size + 1);
   free (buf);
   if (status)
     {
@@ -124,7 +125,8 @@ cmd_load (int argc, char **argv)
 {
   if (check_args (argv[0], argc, 2, 2))
     return;
-  mu_header_destroy (&header, NULL);
+  mu_stream_destroy (&hstream);
+  mu_header_destroy (&header);
   load_file (argv[1]);
 }
 
@@ -134,7 +136,8 @@ cmd_free (int argc, char **argv)
   if (check_args (argv[0], argc, 1, 1))
     return;
   mu_iterator_destroy (&iterator);
-  mu_header_destroy (&header, NULL);
+  mu_stream_destroy (&hstream);
+  mu_header_destroy (&header);
 }
 
 void
@@ -173,25 +176,27 @@ cmd_dump (int argc, char **argv)
   if (argc == 2)
     off = strtoul (argv[1], NULL, 0);
 
-  status = mu_header_get_stream (header, &stream);
+  status = mu_header_get_streamref (header, &stream);
   if (status)
     {
       mu_error ("%u: cannot get stream: %s", line_num, mu_strerror (status));
       return;
     }
 
-  status = mu_stream_seek (stream, off, SEEK_SET);
+  status = mu_stream_seek (stream, off, SEEK_SET, NULL);
   if (status)
     {
+      mu_stream_destroy (&stream);
       mu_error ("%u: cannot seek: %s", line_num, mu_strerror (status));
       return;
     }
 
-  while (mu_stream_sequential_read (stream, buf, sizeof buf, &n) == 0
+  while (mu_stream_read (stream, buf, sizeof buf, &n) == 0
         && n > 0)
     {
       fwrite (buf, 1, n, stdout);
     }
+  mu_stream_destroy (&stream);
 }  
 
 void
@@ -209,6 +214,7 @@ cmd_remove (int argc, char **argv)
   status = mu_header_remove (header, fn, num);
   if (status)
     mu_error ("%u: %s: %s", line_num, argv[0], mu_strerror (status));
+  mu_stream_destroy (&hstream);
 }
 
 /* insert header value [ref [num] [before|after] [replace]] */
@@ -258,6 +264,7 @@ cmd_insert (int argc, char **argv)
     }
   status = mu_header_insert (header, argv[1], argv[2],
                             ref, num, flags);
+  mu_stream_destroy (&hstream);
   if (status)
     mu_error ("%u: %s: %s", line_num, argv[0], mu_strerror (status));
 }
@@ -272,20 +279,22 @@ cmd_write (int argc, char **argv)
   if (check_args (argv[0], argc, 1, 1))
     return;
 
-  status = mu_header_get_stream (header, &str);
+  status = mu_header_get_streamref (header, &str);
   if (status)
     {
       mu_error ("%u: cannot get stream: %s", line_num, mu_strerror (status));
       return;
     }
   printf("[reading headers; end with an empty line]\n");
-  mu_stream_seek (str, 0, SEEK_SET);
+  mu_stream_seek (str, 0, SEEK_SET, NULL);
   while (prompt (1), fgets(buf, sizeof buf, stdin))
     {
-      mu_stream_sequential_write (str, buf, strlen (buf));
+      mu_stream_write (str, buf, strlen (buf), NULL);
       if (buf[0] == '\n')
        break;
     }
+  mu_stream_destroy (&str);
+  mu_stream_destroy (&hstream);
 }
 
 void
@@ -338,18 +347,19 @@ void
 cmd_readline (int argc, char **argv)
 {
   char *buf;
-  size_t size;
-  mu_stream_t stream;
+  size_t size = 128;
   size_t nbytes;
   
   if (check_args (argv[0], argc, 1, 2))
     return;
-  size = atoi (argv[1]);
+  if (argc == 2)
+    size = atoi (argv[1]);
   buf = malloc (size);
   if (!buf)
     abort ();
-  mu_header_get_stream (header, &stream);
-  mu_stream_readline (stream, buf, size, 0, &nbytes);
+  if (!hstream)
+    mu_header_get_streamref (header, &hstream);
+  mu_stream_readline (hstream, buf, size, &nbytes);
   printf ("\"%*.*s\"", (int) nbytes, (int) nbytes, buf);
   free (buf);
 }
@@ -509,7 +519,7 @@ main (int argc, char **argv)
     }
   else
     {
-      int status = mu_header_create (&header, NULL, 0, NULL);
+      int status = mu_header_create (&header, NULL, 0);
       if (status)
        {
          mu_error ("cannot create header: %s", mu_strerror (status));
diff --git a/examples/http.c b/examples/http.c
index b62208b..a2bb6b7 100644
--- a/examples/http.c
+++ b/examples/http.c
@@ -51,19 +51,20 @@ http_stream_wait (mu_stream_t stream, int flags, size_t 
*attempt)
       tv.tv_sec = io_timeout;
       tv.tv_usec = 0;
       rc = mu_stream_wait (stream, &oflags, &tv);
-      switch (rc) {
-      case 0:
-       if (flags & oflags)
-         return 0;
-       /* FALLTHROUGH */
-      case EAGAIN:
-      case EINPROGRESS:
-       ++*attempt;
-       continue;
-       
-      default:
-       return rc;
-      }
+      switch (rc)
+       {
+       case 0:
+         if (flags & oflags)
+           return 0;
+         /* FALLTHROUGH */
+       case EAGAIN:
+       case EINPROGRESS:
+         ++*attempt;
+         continue;
+         
+       default:
+         return rc;
+       }
     }
   return ETIMEDOUT;
 }
@@ -71,7 +72,7 @@ http_stream_wait (mu_stream_t stream, int flags, size_t 
*attempt)
 int
 main (int argc, char **argv)
 {
-  int ret, off = 0;
+  int ret;
   mu_stream_t stream;
   size_t nb, size;
   size_t attempt;
@@ -108,19 +109,11 @@ main (int argc, char **argv)
       exit (EXIT_FAILURE);
     }
 
-  for (attempt = 0, size = strlen (wbuf); size > 0; )
+  for (attempt = 0, size = strlen (wbuf);; )
     {
-      ret = mu_stream_write (stream, wbuf + off, strlen (wbuf), 0, &nb);
+      ret = mu_stream_write (stream, wbuf, strlen (wbuf), NULL);
       if (ret == 0)
-       {
-         if (nb == 0)
-           {
-             mu_error("mu_stream_write: wrote 0 bytes");
-             exit (EXIT_FAILURE);
-           }
-         off += nb;
-         size -= nb;
-       }
+       break;
       else if (ret == EAGAIN)
         {
          if (attempt < io_attempts)
@@ -149,7 +142,7 @@ main (int argc, char **argv)
   attempt = 0;
   for (;;)
     {
-      ret = mu_stream_read (stream, rbuf, sizeof (rbuf), 0, &nb);
+      ret = mu_stream_read (stream, rbuf, sizeof (rbuf), &nb);
       if (ret == 0)
        {
          if (nb == 0)
@@ -182,6 +175,6 @@ main (int argc, char **argv)
       exit (EXIT_FAILURE);
     }
 
-  mu_stream_destroy (&stream, NULL);
+  mu_stream_destroy (&stream);
   exit (EXIT_SUCCESS);
 }
diff --git a/examples/iconv.c b/examples/iconv.c
index 9aacfef..fd293bf 100644
--- a/examples/iconv.c
+++ b/examples/iconv.c
@@ -33,7 +33,7 @@ main (int argc, char **argv)
   int rc;
   mu_stream_t in, out;
   mu_stream_t cvt;
-  size_t total = 0, size;
+  size_t  size;
   char buffer[80];
   
   if (argc != 3)
@@ -42,27 +42,26 @@ main (int argc, char **argv)
       return 1;
     }
 
-  MU_ASSERT (mu_stdio_stream_create (&in, stdin, 0));
+  MU_ASSERT (mu_stdio_stream_create (&in, MU_STDIN_FD, 0));
   MU_ASSERT (mu_stream_open (in));
   MU_ASSERT (mu_filter_iconv_create (&cvt, in, argv[1], argv[2], 
                                      0, mu_fallback_none));
   MU_ASSERT (mu_stream_open (cvt));
   
-  MU_ASSERT (mu_stdio_stream_create (&out, stdout, 0));
+  MU_ASSERT (mu_stdio_stream_create (&out, MU_STDOUT_FD, 0));
   MU_ASSERT (mu_stream_open (out));
 
-  while ((rc = mu_stream_read (cvt, buffer, sizeof (buffer), total, &size)) == 0
+  while ((rc = mu_stream_read (cvt, buffer, sizeof (buffer), &size)) == 0
         && size > 0)
     {
-      mu_stream_sequential_write (out, buffer, size);
-      total += size;
+      mu_stream_write (out, buffer, size, NULL);
     }
   mu_stream_flush (out);
   if (rc)
     {
-      const char *p;
-      mu_stream_strerror (cvt, &p);
-      fprintf (stderr, "error: %s / %s\n", mu_strerror (rc), p);
+      fprintf (stderr, "error: %s / %s\n",
+              mu_stream_strerror (cvt, rc),
+              mu_strerror (rc));
     }
   return 0;
 }
diff --git a/examples/mimetest.c b/examples/mimetest.c
index 9b1170c..0f4f119 100644
--- a/examples/mimetest.c
+++ b/examples/mimetest.c
@@ -182,7 +182,7 @@ message_display_parts (mu_message_t msg, int indent)
   mu_header_t hdr;
   mu_stream_t str;
   mu_body_t body;
-  int offset, ismulti;
+  int ismulti;
   size_t nbytes;
 
   /* How many parts does the message has? */
@@ -249,19 +249,18 @@ message_display_parts (mu_message_t msg, int indent)
          printf ("%*.*sText Message\n", indent, indent, "");
           printf ("%*.*sBegin\n", indent, indent, "");
           mu_message_get_body (part, &body);
-          mu_body_get_stream (body, &str);
+          mu_body_get_streamref (body, &str);
           /* Make sure the original body stream is not closed when
              str gets destroyed */
           mu_filter_create (&str, str, encoding, MU_FILTER_DECODE,
-                           MU_STREAM_READ | MU_STREAM_NO_CLOSE);
-          offset = 0;
-          while (mu_stream_readline (str, buf, sizeof (buf),
-                                    offset, &nbytes) == 0 && nbytes)
+                           MU_STREAM_READ);
+         
+         while (mu_stream_readline (str, buf, sizeof (buf), &nbytes) == 0
+                && nbytes)
             {
               printf ("%*.*s%s", indent, indent, "", buf);
-              offset += nbytes;
             }
-          mu_stream_destroy (&str, NULL);
+          mu_stream_destroy (&str);
         }
       else
         {
diff --git a/examples/msg-send.c b/examples/msg-send.c
index 4fdcf2c..5c4f70f 100644
--- a/examples/msg-send.c
+++ b/examples/msg-send.c
@@ -108,7 +108,7 @@ main (int argc, char *argv[])
       MU_ASSERT (mu_address_createv (&to, (const char **) av, -1));
     }
 
-  MU_ASSERT (mu_stdio_stream_create (&in, stdin, MU_STREAM_SEEKABLE));
+  MU_ASSERT (mu_stdio_stream_create (&in, MU_STDIN_FD, MU_STREAM_SEEK));
   MU_ASSERT (mu_stream_open (in));
   MU_ASSERT (mu_message_create (&msg, NULL));
   MU_ASSERT (mu_message_set_stream (msg, in, NULL));
diff --git a/examples/mta.c b/examples/mta.c
index 57b5daa..4d27774 100644
--- a/examples/mta.c
+++ b/examples/mta.c
@@ -19,7 +19,7 @@
 
 /* This is a "fake" mta designed for testing purposes. It imitates
    sendmail sending and daemon modes. It does not actually send anything,
-   instead it just outputs the transcript of what would have been done.
+   instead it just outputs a transcript of what would have been done.
 
    Invocation:
    
@@ -73,6 +73,18 @@ int dot = 1;             /* Message is terminated by a lone 
dot on a line */
 
 mu_address_t recipients = NULL;
 char *progname;
+/* FIXME: If finalize_option is set, mta should try to finalize
+   received messages the way sendmail does, i.e. to add To: or
+   Cc: headers, if they are missing, etc. The code to do so is
+   already included, but the modified message is not reproduced
+   on diagnostic output because mta_send reads it from the stream,
+   which does not reflect modifications to the header.
+
+   Ideally, the mu_message_get_streamref function should notice the
+   change in the header (and/or the body) and return a temporary
+   stream, which will read the modified values.  This is left as
+   as TODO for a later time.                  2010-09-29, Sergey */
+int finalize_option = 0; 
 
 int mta_stdin (int argc, char **argv);
 int mta_smtp (int argc, char **argv);
@@ -312,7 +324,7 @@ mta_send (mu_message_t msg)
   size_t n;
   char buffer[512];    
   mu_stream_t stream = NULL;
-  size_t off = 0, line;
+  size_t line;
   char *value;
 
   value = from_address ();
@@ -326,10 +338,10 @@ mta_send (mu_message_t msg)
   fprintf (diag, "ENVELOPE TO: %s\n", value);
   free (value);
 
-  mu_message_get_stream (msg, &stream);
+  mu_message_get_streamref (msg, &stream);
   line = 0;
   fprintf (diag, "%4lu: ", (unsigned long) line);
-  while (mu_stream_read (stream, buffer, sizeof buffer - 1, off, &n) == 0
+  while (mu_stream_read (stream, buffer, sizeof buffer - 1, &n) == 0
         && n != 0)
     {
       size_t i;
@@ -343,8 +355,8 @@ mta_send (mu_message_t msg)
              fprintf (diag, "%4lu: ", (unsigned long) line);
            }
        }
-      off += n;
     }
+  mu_stream_destroy (&stream);
   fprintf (diag, "\nEND OF MESSAGE\n");
   fflush (diag);
   return 0;
@@ -361,7 +373,7 @@ message_finalize (mu_message_t msg, int warn)
   
   mu_message_get_header (msg, &header);
 
-  if (warn && from_person)
+  if (finalize_option && warn && from_person)
     {
       struct passwd *pwd = getpwuid (getuid ());
       char *warn = malloc (strlen (pwd->pw_name) + 1 +
@@ -400,7 +412,8 @@ message_finalize (mu_message_t msg, int warn)
          free (value);
        }  
          
-      if (mu_header_aget_value (header, MU_HEADER_BCC, &value) == 0)
+      if (finalize_option &&
+         mu_header_aget_value (header, MU_HEADER_BCC, &value) == 0)
        {
          if (add_recipient (value))
            {
@@ -412,7 +425,7 @@ message_finalize (mu_message_t msg, int warn)
        }  
     }
 
-  if (!have_to)
+  if (finalize_option && !have_to)
     {
       size_t n;
       int c;
diff --git a/examples/muauth.c b/examples/muauth.c
index 23ba521..c771ebf 100644
--- a/examples/muauth.c
+++ b/examples/muauth.c
@@ -27,7 +27,6 @@
 #include <mailutils/mailutils.h>
 #include "mailutils/libargp.h"
 
-const char *program_version = "muauth (" PACKAGE_STRING ")";
 static char doc[] =
 "muauth -- test mailutils authentication and authorization schemes";
 static char args_doc[] = "key";
@@ -91,7 +90,7 @@ main (int argc, char * argv [])
   uid_t uid;
   
   MU_AUTH_REGISTER_ALL_MODULES ();
-  mu_argp_init (program_version, NULL);
+  mu_argp_init (NULL, NULL);
   if (mu_app_init (&argp, capa, NULL, argc, argv, 0, &index, NULL))
     exit (1);
 
diff --git a/examples/mucat.c b/examples/mucat.c
new file mode 100644
index 0000000..92f55eb
--- /dev/null
+++ b/examples/mucat.c
@@ -0,0 +1,87 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 1999, 2000, 2001, 2002, 2005, 2007, 2010 Free Software
+   Foundation, Inc.
+
+   GNU Mailutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GNU Mailutils is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GNU Mailutils; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+   MA 02110-1301 USA */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <unistd.h>
+#include <stdio.h>
+#include <assert.h>
+#include <ctype.h>
+#include <string.h>
+#include <mailutils/mailutils.h>
+
+int
+main (int argc, char * argv [])
+{
+  int c;
+  mu_stream_t in, out;
+  int reread_option = 0;
+  mu_off_t reread_off;
+  int skip_option = 0;
+  mu_off_t skip_off;
+  
+  while ((c = getopt (argc, argv, "hs:r:")) != EOF)
+    switch (c)
+      {
+      case 'r':
+       reread_option = 1;
+       reread_off = strtoul (optarg, NULL, 10);
+       break;
+
+      case 's':
+       skip_option = 1;
+       skip_off = strtoul (optarg, NULL, 10);
+       break;
+
+      case 'h':
+       printf ("usage: cat [-s off]\n");
+       exit (0);
+
+      default:
+       exit (1);
+      }
+       
+
+  MU_ASSERT (mu_stdio_stream_create (&in, MU_STDIN_FD, MU_STREAM_SEEK));
+  MU_ASSERT (mu_stdio_stream_create (&out, MU_STDOUT_FD, 0));
+
+  if (skip_option)
+    {
+      mu_stream_printf (out, "skipping to %lu:\n",
+                       (unsigned long) skip_off);
+      MU_ASSERT (mu_stream_seek (in, skip_off, MU_SEEK_SET, NULL));
+    }
+  
+  MU_ASSERT (mu_stream_copy (out, in, 0, NULL));
+
+  if (reread_option)
+    {
+      mu_stream_printf (out, "rereading from %lu:\n",
+                       (unsigned long) reread_off);
+      MU_ASSERT (mu_stream_seek (in, reread_off, MU_SEEK_SET, NULL));
+      MU_ASSERT (mu_stream_copy (out, in, 0, NULL));
+    }
+  
+  mu_stream_close (in);
+  mu_stream_destroy (&in);
+  mu_stream_close (out);
+  mu_stream_destroy (&out);
+  return 0;
+}
diff --git a/examples/murun.c b/examples/murun.c
index f9fbc4f..51b4710 100644
--- a/examples/murun.c
+++ b/examples/murun.c
@@ -34,10 +34,10 @@ read_and_print (mu_stream_t in, mu_stream_t out)
   size_t size;
   char buffer[128];
   
-  while (mu_stream_sequential_readline (in, buffer, sizeof (buffer), &size) == 0
+  while (mu_stream_readline (in, buffer, sizeof (buffer), &size) == 0
         && size > 0)
     {
-      mu_stream_sequential_write (out, buffer, size);
+      mu_stream_write (out, buffer, size, NULL);
     }
 }
 
@@ -68,9 +68,11 @@ main (int argc, char *argv[])
   if (read_stdin)
     {
       mu_stream_t in;
-      MU_ASSERT (mu_stdio_stream_create (&in, stdin, 0));
+      MU_ASSERT (mu_stdio_stream_create (&in, MU_STDIN_FD, 0));
       MU_ASSERT (mu_stream_open (in));
       rc = mu_filter_prog_stream_create (&stream, cmdline, in);
+      /* Make sure closing/destroying stream will close/destroy in */
+      mu_stream_unref (in);
     }
   else
     rc = mu_prog_stream_create (&stream, cmdline, flags);
@@ -80,7 +82,7 @@ main (int argc, char *argv[])
               argv[0], mu_strerror (rc));
       exit (1);
     }
-
+  
   rc = mu_stream_open (stream);
   if (rc)
     {
@@ -89,13 +91,13 @@ main (int argc, char *argv[])
       exit (1);
     }
 
-  MU_ASSERT (mu_stdio_stream_create (&out, stdout, 0));
+  MU_ASSERT (mu_stdio_stream_create (&out, MU_STDOUT_FD, 0));
   MU_ASSERT (mu_stream_open (out));
   
   read_and_print (stream, out);
   mu_stream_close (stream);
-  mu_stream_destroy (&stream, mu_stream_get_owner (stream));
+  mu_stream_destroy (&stream);
   mu_stream_close (out);
-  mu_stream_destroy (&out, mu_stream_get_owner (stream));
+  mu_stream_destroy (&out);
   return 0;
 }
diff --git a/examples/musocio.c b/examples/musocio.c
new file mode 100644
index 0000000..66bf346
--- /dev/null
+++ b/examples/musocio.c
@@ -0,0 +1,124 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 1999, 2000, 2001, 2002, 2005, 2007, 2010 Free Software
+   Foundation, Inc.
+
+   GNU Mailutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GNU Mailutils is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GNU Mailutils; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+   MA 02110-1301 USA */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <assert.h>
+#include <ctype.h>
+#include <string.h>
+#include <mailutils/mailutils.h>
+
+int verbose;
+
+void
+ioloop (char *id, mu_stream_t in, mu_stream_t out)
+{
+  char *buf = NULL;
+  size_t size = 0, n;
+  int rc;
+  
+  while ((rc = mu_stream_getline (in, &buf, &size, &n)) == 0 && n > 0)
+    {
+      if (rc)
+       {
+         mu_error("%s: read error: %s", id, mu_stream_strerror (in, rc));
+         exit (1);
+       }
+      MU_ASSERT (mu_stream_write (out, buf, n, NULL));
+    }
+  mu_stream_flush (out);
+  if (verbose)
+    fprintf (stderr, "%s exited\n", id);
+}
+
+int
+main (int argc, char * argv [])
+{
+  mu_stream_t in, out, sock;
+  pid_t pid;
+  int status, c;
+
+  while ((c = getopt (argc, argv, "v")) != EOF)
+    switch (c)
+      {
+      case 'v':
+       verbose++;
+       break;
+
+      case 'h':
+       printf ("usage: musocio file\n");
+       return 0;
+
+      default:
+       return 1;
+      }
+
+  argc -= optind;
+  argv += optind;
+  
+  if (argc != 2)
+    {
+      mu_error ("usage: musocio file");
+      return 1;
+    }
+
+  MU_ASSERT (mu_stdio_stream_create (&in, MU_STDIN_FD, 0));
+  mu_stream_set_buffer (in, mu_buffer_line, 1024);
+  MU_ASSERT (mu_stdio_stream_create (&out, MU_STDOUT_FD, 0));
+  mu_stream_set_buffer (out, mu_buffer_line, 1024);
+  MU_ASSERT (mu_socket_stream_create (&sock, argv[1], MU_STREAM_RDWR));
+  mu_stream_set_buffer (sock, mu_buffer_line, 1024);
+  MU_ASSERT (mu_stream_open (sock));
+  
+  pid = fork ();
+  if (pid == -1)
+    {
+      mu_error ("fork failed: %s", mu_strerror (errno));
+      return 1;
+    }
+
+  if (pid == 0)
+    {
+      mu_stream_close (in);
+      mu_stream_destroy (&in);
+      ioloop ("reader", sock, out);
+      exit (0);
+    }
+
+  ioloop ("writer", in, sock);
+
+  mu_stream_close (in);
+  mu_stream_destroy (&in);
+
+  mu_stream_shutdown (sock, MU_STREAM_WRITE);
+  waitpid (pid, &status, 0);
+
+  mu_stream_close (sock);
+  mu_stream_destroy (&sock);
+  
+  mu_stream_close (out);
+  mu_stream_destroy (&out);
+  return 0;
+}
diff --git a/examples/nntpclient.c b/examples/nntpclient.c
index 0e7e806..4c7722f 100644
--- a/examples/nntpclient.c
+++ b/examples/nntpclient.c
@@ -395,9 +395,10 @@ com_head (char *arg)
     {
       size_t n = 0;
       char buf[128];
-      while ((mu_stream_readline (stream, buf, sizeof buf, 0, &n) == 0) && n)
+      /* FIXME: mu_stream_seek (stream, 0, MU_SEEK_SET); ? */
+      while ((mu_stream_readline (stream, buf, sizeof buf, &n) == 0) && n)
         printf ("%s", buf);
-      mu_stream_destroy (&stream, NULL);
+      mu_stream_destroy (&stream);
     }
    return status;
 }
@@ -422,11 +423,10 @@ com_body (char *arg)
 
    if (status == 0 && stream != NULL)
     {
-      size_t n = 0;
       char buf[128];
-      while ((mu_stream_readline (stream, buf, sizeof buf, 0, &n) == 0) && n)
+      while (mu_stream_readline (stream, buf, sizeof buf, 0) == 0)
         printf ("%s", buf);
-      mu_stream_destroy (&stream, NULL);
+      mu_stream_destroy (&stream);
     }
    return status;
 }
@@ -1004,8 +1004,7 @@ com_connect (char *arg)
       if (verbose)
        com_verbose ("on");
       status =
-       mu_tcp_stream_create (&tcp, host, port,
-                          MU_STREAM_READ | MU_STREAM_NO_CHECK);
+       mu_tcp_stream_create (&tcp, host, port, MU_STREAM_READ);
       if (status == 0)
        {
          mu_nntp_set_carrier (nntp, tcp);
diff --git a/examples/pop3client.c b/examples/pop3client.c
index 6912920..c924638 100644
--- a/examples/pop3client.c
+++ b/examples/pop3client.c
@@ -34,6 +34,7 @@
 #include <stdlib.h>
 #include <termios.h>
 #include <signal.h>
+#include <xalloc.h>
 
 #ifdef WITH_READLINE
 # include <readline/readline.h>
@@ -48,6 +49,8 @@
 #include <mailutils/argcv.h>
 #include <mailutils/cctype.h>
 #include <mailutils/cstr.h>
+#include <mailutils/tls.h>
+#include <mailutils/mutil.h>
 
 /* A structure which contains information on the commands this program
    can understand. */
@@ -55,62 +58,86 @@
 typedef struct
 {
   const char *name;            /* User printable name of the function. */
-  int (*func) (char *);                /* Function to call to do the job. */
+  int argmin;
+  int argmax;
+  int (*func) (int, char **);  /* Function to call to do the job. */
   const char *doc;             /* Documentation for this function.  */
 }
 COMMAND;
 
 /* The names of functions that actually do the manipulation. */
-int com_apop (char *);
-int com_capa (char *);
-int com_disconnect (char *);
-int com_dele (char *);
-int com_exit (char *);
-int com_help (char *);
-int com_list (char *);
-int com_noop (char *);
-int com_connect (char *);
-int com_pass (char *);
-int com_quit (char *);
-int com_retr (char *);
-int com_rset (char *);
-int com_stat (char *);
-int com_top (char *);
-int com_uidl (char *);
-int com_user (char *);
-int com_verbose (char *);
-int com_prompt (char *);
-
-void initialize_readline (void);
-COMMAND *find_command (char *);
-char *dupstr (const char *);
-int execute_line (char *);
-int valid_argument (const char *, char *);
+int com_apop (int, char **);
+int com_capa (int, char **);
+int com_disconnect (int, char **);
+int com_dele (int, char **);
+int com_exit (int, char **);
+int com_help (int, char **);
+int com_list (int, char **);
+int com_noop (int, char **);
+int com_connect (int, char **);
+int com_pass (int, char **);
+int com_quit (int, char **);
+int com_retr (int, char **);
+int com_rset (int, char **);
+int com_stat (int, char **);
+int com_top (int, char **);
+int com_uidl (int, char **);
+int com_user (int, char **);
+int com_verbose (int, char **);
+int com_prompt (int, char **);
+int com_stls (int, char **);
+int com_history (int, char **);
 
-void sig_int (int);
+COMMAND *find_command (char *);
 
 COMMAND commands[] = {
-  { "apop", com_apop, "Authenticate with APOP: APOP user secret" },
-  { "capa", com_capa, "List capabilities: capa" },
-  { "disconnect", com_disconnect, "Close connection: disconnect" },
-  { "dele", com_dele, "Mark message: DELE msgno" },
-  { "exit", com_exit, "exit program" },
-  { "help", com_help, "Display this text" },
-  { "?", com_help, "Synonym for `help'" },
-  { "list", com_list, "List messages: LIST [msgno]" },
-  { "noop", com_noop, "Send no operation: NOOP" },
-  { "pass", com_pass, "Send passwd: PASS [passwd]" },
-  { "prompt", com_prompt, "Set command prompt" },
-  { "connect", com_connect, "Open connection: connect hostname [port]" },
-  { "quit", com_quit, "Go to Update state : QUIT" },
-  { "retr", com_retr, "Dowload message: RETR msgno" },
-  { "rset", com_rset, "Unmark all messages: RSET" },
-  { "stat", com_stat, "Get the size and count of mailbox : STAT [msgno]" },
-  { "top", com_top, "Get the header of message: TOP msgno [lines]" },
-  { "uidl", com_uidl, "Get the unique id of message: UIDL [msgno]" },
-  { "user", com_user, "send login: USER user" },
-  { "verbose", com_verbose, "Enable Protocol tracing: verbose [on|off]" },
-  { NULL, NULL, NULL }
+  { "apop",       3,  3, com_apop,
+    "Authenticate with APOP: APOP user secret" },
+  { "capa",       1, -1, com_capa,
+    "List capabilities: capa [-reread] [names...]" },
+  { "disconnect", 1, 1,
+    com_disconnect, "Close connection: disconnect" },
+  { "dele",       2, 2, com_dele,
+    "Mark message: DELE msgno" },
+  { "exit",       1, 1, com_exit,
+    "exit program" },
+  { "help",       1, 1, com_help,
+    "Display this text" },
+  { "?",          1, 1, com_help,
+    "Synonym for `help'" },
+  { "list",       1, 2, com_list,
+    "List messages: LIST [msgno]" },
+  { "noop",       1, 1, com_noop,
+    "Send no operation: NOOP" },
+  { "pass",       1, 2, com_pass,
+    "Send passwd: PASS [passwd]" },
+  { "prompt",     -1, -1, com_prompt,
+    "Set command prompt" },
+  { "connect",    1, 4, com_connect,
+    "Open connection: connect [-tls] hostname port" },
+  { "quit",       1, 1, com_quit,
+    "Go to Update state : QUIT" },
+  { "retr",       2, 2, com_retr,
+    "Dowload message: RETR msgno" },
+  { "rset",       1, 1, com_rset,
+    "Unmark all messages: RSET" },
+  { "stat",       1, 1, com_stat,
+    "Get the size and count of mailbox : STAT" },
+  { "stls",       1, 1, com_stls,
+    "Start TLS negotiation" },
+  { "top",        2, 3, com_top,
+    "Get the header of message: TOP msgno [lines]" },
+  { "uidl",       1, 2, com_uidl,
+    "Get the unique id of message: UIDL [msgno]" },
+  { "user",       2, 2, com_user,
+    "send login: USER user" },
+  { "verbose",    1, 4, com_verbose,
+    "Enable Protocol tracing: verbose [on|off|mask|unmask] [x1 [x2]]" },
+#ifdef WITH_READLINE
+  { "history",    1, 1, com_history,
+    "Show command history" },
+#endif
+  { NULL }
 };
 
 /* Global handle for pop3.  */
@@ -118,6 +145,14 @@ mu_pop3_t pop3;
 
 /* Flag if verbosity is needed.  */
 int verbose;
+#define VERBOSE_MASK(n) (1<<((n)+1))
+#define SET_VERBOSE_MASK(n) (verbose |= VERBOSE_MASK (n))
+#define CLR_VERBOSE_MASK(n) (verbose &= VERBOSE_MASK (n))
+#define QRY_VERBOSE_MASK(n) (verbose & VERBOSE_MASK (n))
+#define HAS_VERBOSE_MASK(n) (verbose & ~1)
+#define SET_VERBOSE() (verbose |= 1)
+#define CLR_VERBOSE() (verbose &= ~1)
+#define QRY_VERBOSE() (verbose & 1)
 
 /* When non-zero, this global means the user is done using this program. */
 int done;
@@ -186,23 +221,30 @@ expand_prompt ()
   return str;
 }
 
-char *
-dupstr (const char *s)
+
+
+#ifdef WITH_READLINE
+#define HISTFILE_SUFFIX "_history"
+
+static char *
+get_history_file_name ()
 {
-  char *r;
+  static char *filename = NULL;
 
-  r = malloc (strlen (s) + 1);
-  if (!r)
+  if (!filename)
     {
-      mu_error ("Memory exhausted");
-      exit (1);
+      char *hname;
+      
+      hname = xmalloc(3 + strlen (rl_readline_name) + sizeof HISTFILE_SUFFIX);
+      strcpy (hname, "~/.");
+      strcat (hname, rl_readline_name);
+      strcat (hname, HISTFILE_SUFFIX);
+      filename = mu_tilde_expansion (hname, "/", NULL);
+      free(hname);
     }
-  strcpy (r, s);
-  return r;
+  return filename;
 }
-
 
-#ifdef WITH_READLINE
 /* Interface to Readline Completion */
 
 char *command_generator (const char *, int);
@@ -215,10 +257,18 @@ void
 initialize_readline ()
 {
   /* Allow conditional parsing of the ~/.inputrc file. */
-  rl_readline_name = (char *) "pop3";
+  rl_readline_name = (char *) "pop3client";
 
   /* Tell the completer that we want a crack first. */
   rl_attempted_completion_function = (CPPFunction *) pop_completion;
+
+  read_history (get_history_file_name ());
+}
+
+void
+finish_readline ()
+{
+  write_history (get_history_file_name());
 }
 
 /* Attempt to complete on the contents of TEXT.  START and END bound the
@@ -266,19 +316,72 @@ command_generator (const char *text, int state)
       list_index++;
 
       if (strncmp (name, text, len) == 0)
-       return (dupstr (name));
+       return xstrdup (name);
     }
 
   /* If no names matched, then return NULL. */
   return NULL;
 }
 
-#else
-void
-initialize_readline ()
+static char *pre_input_line;
+
+static int
+pre_input (void)
 {
+  rl_insert_text (pre_input_line);
+  free (pre_input_line);
+  rl_pre_input_hook = NULL;
+  rl_redisplay ();
+  return 0;
+}
+
+static int
+retrieve_history (char *str)
+{
+  char *out;
+  int rc;
+
+  rc = history_expand (str, &out);
+  switch (rc)
+    {
+    case -1:
+      mu_error ("%s", out);
+      free (out);
+      return 1;
+
+    case 0:
+      break;
+
+    case 1:
+      pre_input_line = out;
+      rl_pre_input_hook = pre_input;
+      return 1;
+
+    case 2:
+      printf ("%s\n", out);
+      free (out);
+      return 1;
+    }
+  return 0;
 }
 
+int
+com_history (int argc, char **argv)
+{
+  int i;
+  HIST_ENTRY **hlist;
+
+  hlist = history_list ();
+  for (i = 0; i < history_length; i++)
+    printf ("%4d) %s\n", i + 1, hlist[i]->line);
+
+  return 0;
+}
+
+#else
+# define initialize_readline()
+# define finish_readline()
+
 char *
 readline (char *prompt)
 {
@@ -292,7 +395,7 @@ readline (char *prompt)
 
   if (!fgets (buf, sizeof (buf), stdin))
     return NULL;
-  return strdup (buf);
+  return xstrdup (buf);
 }
 
 void
@@ -301,71 +404,101 @@ add_history (const char *s MU_ARG_UNUSED)
 }
 #endif
 
-
 int
-main (int argc MU_ARG_UNUSED, char **argv)
+get_bool (const char *str, int *pb)
 {
-  char *line, *s;
+  if (mu_c_strcasecmp (str, "yes") == 0
+      || mu_c_strcasecmp (str, "on") == 0
+      || mu_c_strcasecmp (str, "true") == 0)
+    *pb = 1;
+  else if (mu_c_strcasecmp (str, "no") == 0
+      || mu_c_strcasecmp (str, "off") == 0
+      || mu_c_strcasecmp (str, "false") == 0)
+    *pb = 0;
+  else
+    return 1;
 
-  mu_set_program_name (argv[0]);
-  prompt = strdup (DEFAULT_PROMPT);
-  initialize_readline ();      /* Bind our completer. */
+  return 0;
+}
 
-  /* Loop reading and executing lines until the user quits. */
-  while (!done)
+int
+get_port (const char *port_str, int *pn)
+{
+  short port_num;
+  long num;
+  char *p;
+  
+  num = port_num = strtol (port_str, &p, 0);
+  if (*p == 0)
     {
-      char *p = expand_prompt ();
-      line = readline (p);
-      free (p);
-      
-      if (!line)
-       break;
-
-      /* Remove leading and trailing whitespace from the line.
-         Then, if there is anything left, add it to the history list
-         and execute it. */
-      s = mu_str_stripws (line);
-
-      if (*s)
+      if (num != port_num)
        {
-         int status;
-         add_history (s);
-         status = execute_line (s);
-         if (status != 0)
-           mu_error ("Error: %s", mu_strerror (status));
+         mu_error ("bad port number: %s", port_str);
+         return 1;
        }
-
-      free (line);
     }
-  exit (0);
+  else
+    {
+      struct servent *sp = getservbyname (port_str, "tcp");
+      if (!sp)
+       {
+         mu_error ("unknown port name");
+         return 1;
+       }
+      port_num = ntohs (sp->s_port);
+    }
+  *pn = port_num;
+  return 0;
 }
-
+
 /* Parse and execute a command line. */
 int
 execute_line (char *line)
 {
-  COMMAND *command;
-  char *word, *arg;
+  int argc;
+  char **argv;
+  int status = 0;
 
-  /* Isolate the command word. */
-  word = mu_str_skip_class (line, MU_CTYPE_SPACE);
-  arg = mu_str_skip_class_comp (word, MU_CTYPE_SPACE);
-  if (*arg)
+  if (mu_argcv_get (line, NULL, "#", &argc, &argv))
     {
-      *arg++ = 0;
-      arg = mu_str_skip_class (arg, MU_CTYPE_SPACE);
+      mu_error("cannot parse input line");
+      return 0;
     }
-      
-  command = find_command (word);
 
-  if (!command)
+  if (argc >= 0)
     {
-      mu_error ("%s: No such command.", word);
-      return 0;
+      COMMAND *command = find_command (argv[0]);
+      
+      if (!command)
+       mu_error ("%s: no such command.", argv[0]);
+      else if (command->argmin > 0 && argc < command->argmin)
+       mu_error ("%s: too few arguments", argv[0]);
+      else if (command->argmax > 0 && argc > command->argmax)
+       mu_error ("%s: too many arguments", argv[0]);
+      else
+       {
+         if (command->argmin <= 0 && argc != 2)
+           {
+             char *word = mu_str_skip_class (line, MU_CTYPE_SPACE);
+             char *arg = mu_str_skip_class_comp (word, MU_CTYPE_SPACE);
+             if (*arg)
+               {
+                 *arg++ = 0;
+                 arg = mu_str_skip_class (arg, MU_CTYPE_SPACE);
+               }
+             
+             mu_argcv_free (argc, argv);
+             argc = 2;
+             argv = xcalloc (argc + 1, sizeof (argv[0]));
+             argv[0] = xstrdup (word);
+             argv[1] = xstrdup (arg);
+             argv[2] = NULL;
+           }
+         status = command->func (argc, argv);
+       }
     }
-
-  /* Call the function. */
-  return ((*(command->func)) (arg));
+  mu_argcv_free (argc, argv);
+  return status;
 }
 
 /* Look up NAME as the name of a command, and return a pointer to that
@@ -373,99 +506,221 @@ execute_line (char *line)
 COMMAND *
 find_command (char *name)
 {
-  register int i;
+  COMMAND *cp;
 
-  for (i = 0; commands[i].name; i++)
-    if (strcmp (name, commands[i].name) == 0)
-      return (&commands[i]);
+  for (cp = commands; cp->name; cp++)
+    if (strcmp (cp->name, name) == 0)
+      return cp;
 
-  return ((COMMAND *) NULL);
+  return NULL;
 }
 
-int
-com_verbose (char *arg)
+static int
+string_to_xlev (const char *name, int *pv)
 {
-  int status = 0;
-  if (!valid_argument ("verbose", arg))
-    return EINVAL;
+  if (strcmp (name, "secure") == 0)
+    *pv = MU_XSCRIPT_SECURE;
+  else if (strcmp (name, "payload") == 0)
+    *pv = MU_XSCRIPT_PAYLOAD;
+  else
+    return 1;
+  return 0;
+}
 
-  verbose = (strcmp (arg, "on") == 0);
-  if (pop3 != NULL)
+static int
+change_verbose_mask (int set, int argc, char **argv)
+{
+  int i;
+  
+  for (i = 0; i < argc; i++)
     {
-      if (verbose == 1)
+      int lev;
+      
+      if (string_to_xlev (argv[i], &lev))
        {
-         mu_debug_t debug;
-         mu_debug_create (&debug, NULL);
-         mu_debug_set_level (debug, MU_DEBUG_LEVEL_UPTO (MU_DEBUG_PROT));
-         status = mu_pop3_set_debug (pop3, debug);
+         mu_error ("unknown level: %s", argv[i]);
+         return 1;
        }
+      if (set)
+       SET_VERBOSE_MASK (lev);
       else
+       CLR_VERBOSE_MASK (lev);
+    }
+  return 0;
+}
+
+void
+set_verbose (mu_pop3_t p)
+{
+  if (p)
+    {
+      if (QRY_VERBOSE ())
        {
-         status = mu_pop3_set_debug (pop3, NULL);
+         mu_pop3_trace (p, MU_POP3_TRACE_SET);
        }
+      else
+       mu_pop3_trace (p, MU_POP3_TRACE_CLR);
+    }
+}
+
+void
+set_verbose_mask (mu_pop3_t p)
+{
+  if (p)
+    {
+      mu_pop3_trace_mask (p, QRY_VERBOSE_MASK (MU_XSCRIPT_SECURE)
+                                 ? MU_POP3_TRACE_SET : MU_POP3_TRACE_CLR,
+                             MU_XSCRIPT_SECURE);
+      mu_pop3_trace_mask (p, QRY_VERBOSE_MASK (MU_XSCRIPT_PAYLOAD)
+                                 ? MU_POP3_TRACE_SET : MU_POP3_TRACE_CLR,
+                             MU_XSCRIPT_PAYLOAD);
     }
-  return status;
 }
 
 int
-com_user (char *arg)
+com_verbose (int argc, char **argv)
+{
+  if (argc == 1)
+    {
+      if (QRY_VERBOSE ())
+       {
+         printf ("verbose is on");
+         if (HAS_VERBOSE_MASK ())
+           {
+             char *delim = " (";
+           
+             if (QRY_VERBOSE_MASK (MU_XSCRIPT_SECURE))
+               {
+                 printf("%ssecure", delim);
+                 delim = ", ";
+               }
+             if (QRY_VERBOSE_MASK (MU_XSCRIPT_PAYLOAD))
+               printf("%spayload", delim);
+             printf (")");
+           }
+         printf ("\n");
+       }
+      else
+       printf ("verbose is off\n");
+    }
+  else
+    {
+      int bv;
+
+      if (get_bool (argv[1], &bv) == 0)
+       {
+         verbose |= bv;
+         if (argc > 2)
+           change_verbose_mask (verbose, argc - 2, argv + 2);
+         set_verbose (pop3);
+       }
+      else if (strcmp (argv[1], "mask") == 0)
+       change_verbose_mask (1, argc - 2, argv + 2);
+      else if (strcmp (argv[1], "unmask") == 0)
+       change_verbose_mask (0, argc - 2, argv + 2);
+      else
+       mu_error ("unknown subcommand");
+      set_verbose_mask (pop3);
+    }
+
+  return 0;
+}
+
+int
+com_user (int argc, char **argv)
 {
   int status;
   
-  if (!valid_argument ("user", arg))
-    return EINVAL;
-  status = mu_pop3_user (pop3, arg);
+  status = mu_pop3_user (pop3, argv[1]);
   if (status == 0)
-    username = strdup (arg);
+    username = strdup (argv[1]);
   return status;
 }
 
 int
-com_apop (char *arg)
+com_apop (int argc, char **argv)
 {
   int status;
-  char *user, *digest;
-
-  if (!valid_argument ("apop", arg))
-    return EINVAL;
-  user = strtok (arg, " ");
-  digest = strtok (NULL, " ");
-  if (!valid_argument ("apop", user) || !valid_argument ("apop", digest))
-    return EINVAL;
-  status = mu_pop3_apop (pop3, user, digest);
+
+  status = mu_pop3_apop (pop3, argv[1], argv[2]);
   if (status == 0)
     {
-      username = strdup (user);
+      username = strdup (argv[1]);
       pop_session_status = pop_session_logged_in;
     }
   return status;
 }
 
 int
-com_capa (char *arg MU_ARG_UNUSED)
+com_capa (int argc, char **argv)
 {
   mu_iterator_t iterator = NULL;
-  int status = mu_pop3_capa (pop3, &iterator);
+  int status = 0;
+  int reread = 0;
+  int i = 1;
+  
+  for (i = 1; i < argc; i++)
+    {
+      if (strcmp (argv[i], "-reread") == 0)
+       reread = 1;
+      else
+       break;
+    }
 
-  if (status == 0)
+  if (i < argc)
+    {
+      if (reread)
+       {
+         status = mu_pop3_capa (pop3, 1, NULL);
+         if (status)
+           return status;
+       }
+      for (; i < argc; i++)
+       {
+         const char *elt;
+         int rc = mu_pop3_capa_test (pop3, argv[i], &elt);
+         switch (rc)
+           {
+           case 0:
+             if (*elt)
+               printf ("%s: %s\n", argv[i], elt);
+             else
+               printf ("%s is set\n", argv[i]);
+             break;
+
+           case MU_ERR_NOENT:
+             printf ("%s is not set\n", argv[i]);
+             break;
+
+           default:
+             return rc;
+           }
+       }
+    }
+  else
     {
-      for (mu_iterator_first (iterator);
-          !mu_iterator_is_done (iterator); mu_iterator_next (iterator))
+      status = mu_pop3_capa (pop3, reread, &iterator);
+
+      if (status == 0)
        {
-         char *capa = NULL;
-         mu_iterator_current (iterator, (void **) &capa);
-         printf ("Capa: %s\n", (capa) ? capa : "");
+         for (mu_iterator_first (iterator);
+              !mu_iterator_is_done (iterator); mu_iterator_next (iterator))
+           {
+             char *capa = NULL;
+             mu_iterator_current (iterator, (void **) &capa);
+             printf ("CAPA: %s\n", capa ? capa : "");
+           }
+         mu_iterator_destroy (&iterator);
        }
-      mu_iterator_destroy (&iterator);
     }
   return status;
 }
 
 int
-com_uidl (char *arg)
+com_uidl (int argc, char **argv)
 {
   int status = 0;
-  if (arg == NULL || *arg == '\0')
+  if (argc == 1)
     {
       mu_iterator_t uidl_iterator = NULL;
       status = mu_pop3_uidl_all (pop3, &uidl_iterator);
@@ -477,7 +732,7 @@ com_uidl (char *arg)
            {
              char *uidl = NULL;
              mu_iterator_current (uidl_iterator, (void **) &uidl);
-             printf ("UIDL: %s\n", (uidl) ? uidl : "");
+             printf ("UIDL: %s\n", uidl ? uidl : "");
            }
          mu_iterator_destroy (&uidl_iterator);
        }
@@ -485,20 +740,20 @@ com_uidl (char *arg)
   else
     {
       char *uidl = NULL;
-      unsigned int msgno = strtoul (arg, NULL, 10);
+      unsigned int msgno = strtoul (argv[1], NULL, 10);
       status = mu_pop3_uidl (pop3, msgno, &uidl);
       if (status == 0)
-       printf ("Msg: %d UIDL: %s\n", msgno, (uidl) ? uidl : "");
+       printf ("Msg: %d UIDL: %s\n", msgno, uidl ? uidl : "");
       free (uidl);
     }
   return status;
 }
 
 int
-com_list (char *arg)
+com_list (int argc, char **argv)
 {
   int status = 0;
-  if (arg == NULL || *arg == '\0')
+  if (argc == 1)
     {
       mu_iterator_t list_iterator;
       status = mu_pop3_list_all (pop3, &list_iterator);
@@ -518,7 +773,7 @@ com_list (char *arg)
   else
     {
       size_t size = 0;
-      unsigned int msgno = strtoul (arg, NULL, 10);
+      unsigned int msgno = strtoul (argv[1], NULL, 10);
       status = mu_pop3_list (pop3, msgno, &size);
       if (status == 0)
        printf ("Msg: %u Size: %lu\n", msgno, (unsigned long) size);
@@ -527,7 +782,7 @@ com_list (char *arg)
 }
 
 int
-com_noop (char *arg MU_ARG_UNUSED)
+com_noop (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED)
 {
   return mu_pop3_noop (pop3);
 }
@@ -549,33 +804,31 @@ echo_on (struct termios *stored_settings)
 }
 
 int
-com_prompt (char *arg)
+com_prompt (int argc, char **argv)
 {
   int quote;
   size_t size;
   
-  if (!valid_argument ("prompt", arg))
-    return EINVAL;
-
   free (prompt);
-  size = mu_argcv_quoted_length (arg, &quote);
+  size = mu_argcv_quoted_length (argv[1], &quote);
   prompt = malloc (size + 1);
   if (!prompt)
     {
       mu_error ("Memory exhausted");
       exit (1);
     }
-  mu_argcv_unquote_copy (prompt, arg, size);
+  mu_argcv_unquote_copy (prompt, argv[1], size);
   return 0;
 }
 
 int
-com_pass (char *arg)
+com_pass (int argc, char **argv)
 {
   int status;
   char pass[256];
+  char *pwd;
   
-  if (!arg || *arg == '\0')
+  if (argc == 1)
     {
       struct termios stored_settings;
 
@@ -587,19 +840,21 @@ com_pass (char *arg)
       putchar ('\n');
       fflush (stdout);
       pass[strlen (pass) - 1] = '\0';  /* nuke the trailing line.  */
-      arg = pass;
+      pwd = pass;
     }
-  status = mu_pop3_pass (pop3, arg);
+  else
+    pwd = argv[1];
+  status = mu_pop3_pass (pop3, pwd);
   if (status == 0)
     pop_session_status = pop_session_logged_in;
   return status;
 }
 
 int
-com_stat (char *arg MU_ARG_UNUSED)
+com_stat (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED)
 {
-  unsigned count = 0;
-  size_t size = 0;
+  size_t count = 0;
+  mu_off_t size = 0;
   int status = 0;
 
   status = mu_pop3_stat (pop3, &count, &size);
@@ -609,26 +864,31 @@ com_stat (char *arg MU_ARG_UNUSED)
 }
 
 int
-com_dele (char *arg)
+com_stls (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED)
+{
+  return mu_pop3_stls (pop3);
+}
+
+int
+com_dele (int argc, char **argv)
 {
   unsigned msgno;
-  if (!valid_argument ("dele", arg))
-    return EINVAL;
-  msgno = strtoul (arg, NULL, 10);
+  msgno = strtoul (argv[1], NULL, 10);
   return mu_pop3_dele (pop3, msgno);
 }
 
 /* Print out help for ARG, or for all of the commands if ARG is
    not present. */
 int
-com_help (char *arg)
+com_help (int argc, char **argv)
 {
   int i;
   int printed = 0;
-
+  char *name = argv[1];
+  
   for (i = 0; commands[i].name; i++)
     {
-      if (!*arg || (strcmp (arg, commands[i].name) == 0))
+      if (!name || (strcmp (name, commands[i].name) == 0))
        {
          printf ("%s\t\t%s.\n", commands[i].name, commands[i].doc);
          printed++;
@@ -637,7 +897,7 @@ com_help (char *arg)
 
   if (!printed)
     {
-      printf ("No commands match `%s'.  Possibilties are:\n", arg);
+      printf ("No commands match `%s'.  Possibilties are:\n", name);
 
       for (i = 0; commands[i].name; i++)
        {
@@ -659,32 +919,24 @@ com_help (char *arg)
 }
 
 int
-com_rset (char *arg MU_ARG_UNUSED)
+com_rset (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED)
 {
   return mu_pop3_rset (pop3);
 }
 
 int
-com_top (char *arg)
+com_top (int argc, char **argv)
 {
   mu_stream_t stream;
   unsigned int msgno;
   unsigned int lines;
-  char *space;
   int status;
 
-  if (!valid_argument ("top", arg))
-    return EINVAL;
-
-  space = strchr (arg, ' ');
-  if (space)
-    {
-      *space++ = '\0';
-      lines = strtoul (space, NULL, 10);
-    }
+  msgno = strtoul (argv[1], NULL, 10);
+  if (argc == 3)
+    lines = strtoul (argv[2], NULL, 10);
   else
-    lines = 0;
-  msgno = strtoul (arg, NULL, 10);
+    lines = 5;
 
   status = mu_pop3_top (pop3, msgno, lines, &stream);
 
@@ -692,118 +944,112 @@ com_top (char *arg)
     {
       size_t n = 0;
       char buf[128];
-      while ((mu_stream_readline (stream, buf, sizeof buf, 0, &n) == 0) && n)
+      while ((mu_stream_readline (stream, buf, sizeof buf, &n) == 0) && n)
        printf ("%s", buf);
-      mu_stream_destroy (&stream, NULL);
+      mu_stream_destroy (&stream);
     }
   return status;
 }
 
 int
-com_retr (char *arg)
+com_retr (int argc, char **argv)
 {
   mu_stream_t stream;
   unsigned int msgno;
   int status;
 
-  if (!valid_argument ("retr", arg))
-    return EINVAL;
-
-  msgno = strtoul (arg, NULL, 10);
+  msgno = strtoul (argv[1], NULL, 10);
   status = mu_pop3_retr (pop3, msgno, &stream);
 
   if (status == 0)
     {
       size_t n = 0;
       char buf[128];
-      while ((mu_stream_readline (stream, buf, sizeof buf, 0, &n) == 0) && n)
+      while ((mu_stream_readline (stream, buf, sizeof buf, &n) == 0) && n)
        printf ("%s", buf);
-      mu_stream_destroy (&stream, NULL);
+      mu_stream_destroy (&stream);
     }
   return status;
 }
 
 int
-get_port (const char *port_str, int *pn)
+com_connect (int argc, char **argv)
 {
-  short port_num;
-  long num;
-  char *p;
+  int status;
+  int n = 0;
+  int tls = 0;
+  int i = 1;
   
-  num = port_num = strtol (port_str, &p, 0);
-  if (*p == 0)
-    {
-      if (num != port_num)
-       {
-         mu_error ("bad port number: %s", port_str);
-         return 1;
-       }
-    }
-  else
+  for (i = 1; i < argc; i++)
     {
-      struct servent *sp = getservbyname (port_str, "tcp");
-      if (!sp)
+      if (strcmp (argv[i], "-tls") == 0)
        {
-         mu_error ("unknown port name");
-         return 1;
+         if (WITH_TLS)
+           tls = 1;
+         else
+           {
+             mu_error ("TLS not supported");
+             return 0;
+           }
        }
-      port_num = ntohs (sp->s_port);
+      else
+       break;
     }
-  *pn = port_num;
-  return 0;
-}
 
-int
-com_connect (char *arg)
-{
-  int status;
-  int n = 110;
-  int argc;
-  char **argv;
-  
-  if (!valid_argument ("connect", arg))
-    return 1;
-  
-  if (mu_argcv_get (arg, NULL, NULL, &argc, &argv))
-    {
-      mu_error ("Cannot parse arguments");
-      return 0;
-    }
+  argc -= i;
+  argv += i;
   
-  if (!valid_argument ("connect", argv[0]))
-    {
-      mu_argcv_free (argc, argv);
-      return EINVAL;
-    }
-  
-  if (argc > 2)
-    {
-      mu_error ("Too many arguments");
-      mu_argcv_free (argc, argv);
-      return 0;
-    }
-
-  if (argc == 2 && get_port (argv[1], &n))
+  if (argc >= 2)
     {
-      mu_argcv_free (argc, argv);
-      return 0;
+      if (get_port (argv[1], &n))
+       return 0;
     }
+  else if (tls)
+    n = MU_POP3_DEFAULT_SSL_PORT;
+  else
+    n = MU_POP3_DEFAULT_PORT;
   
   if (pop_session_status != pop_session_disconnected)
-    com_disconnect (NULL);
+    com_disconnect (0, NULL);
   
   status = mu_pop3_create (&pop3);
   if (status == 0)
     {
       mu_stream_t tcp;
 
-      if (verbose)
-       com_verbose ("on");
-      status =
-       mu_tcp_stream_create (&tcp, argv[0], n,
-                             MU_STREAM_READ | MU_STREAM_NO_CHECK);
+      if (QRY_VERBOSE ())
+       {
+         set_verbose (pop3);
+         set_verbose_mask (pop3);
+       }
+      status = mu_tcp_stream_create (&tcp, argv[0], n, MU_STREAM_READ);
       if (status == 0)
        {
+#ifdef WITH_TLS
+         if (tls)
+           {
+             mu_stream_t tlsstream;
+             
+             status = mu_stream_open (tcp);
+             if (status)
+               {
+                 mu_error ("cannot open connection: %s",
+                           mu_stream_strerror (tcp, status));
+                 mu_stream_destroy (&tcp);
+                 return 0;
+               }
+
+             status = mu_tls_client_stream_create (&tlsstream, tcp, tcp, 0);
+             mu_stream_unref (tcp);
+             if (status)
+               {
+                 mu_error ("cannot create TLS stream: %s",
+                           mu_strerror (status));
+                 return 0;
+               }
+             tcp = tlsstream;
+           }
+#endif
          mu_pop3_set_carrier (pop3, tcp);
          status = mu_pop3_connect (pop3);
        }
@@ -815,14 +1061,14 @@ com_connect (char *arg)
     }
 
   if (status)
-    {
-      mu_error ("Failed to create pop3: %s", mu_strerror (status));
-      mu_argcv_free (argc, argv);
-    }
+    mu_error ("Failed to create pop3: %s", mu_strerror (status));
   else
     {
       connect_argc = argc;
-      connect_argv = argv;
+      connect_argv = xcalloc (argc, sizeof (*connect_argv));
+      for (i = 0; i < argc; i++)
+       connect_argv[i] = xstrdup (argv[i]);
+      connect_argv[i] = NULL;
       port = n;
       pop_session_status = pop_session_connected;
     }
@@ -831,7 +1077,7 @@ com_connect (char *arg)
 }
 
 int
-com_disconnect (char *arg MU_ARG_UNUSED)
+com_disconnect (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED)
 {
   if (pop3)
     {
@@ -848,14 +1094,14 @@ com_disconnect (char *arg MU_ARG_UNUSED)
 }
 
 int
-com_quit (char *arg MU_ARG_UNUSED)
+com_quit (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED)
 {
   int status = 0;
   if (pop3)
     {
       if (mu_pop3_quit (pop3) == 0)
        {
-         status = com_disconnect (arg);
+         status = com_disconnect (0, NULL);
        }
       else
        {
@@ -868,7 +1114,7 @@ com_quit (char *arg MU_ARG_UNUSED)
 }
 
 int
-com_exit (char *arg MU_ARG_UNUSED)
+com_exit (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED)
 {
   if (pop3)
     {
@@ -879,16 +1125,76 @@ com_exit (char *arg MU_ARG_UNUSED)
   return 0;
 }
 
-/* Return non-zero if ARG is a valid argument for CALLER, else print
-   an error message and return zero. */
+
+static char *
+input_line_interactive ()
+{
+  char *p = expand_prompt ();
+  char *line = readline (p);
+  free (p);
+  return line;
+}
+
+static char *
+input_line_script ()
+{
+  size_t size = 0;
+  char *buf = NULL;
+  if (getline (&buf, &size, stdin) <= 0)
+    return NULL;
+  return buf;
+}
+
 int
-valid_argument (const char *caller, char *arg)
+main (int argc MU_ARG_UNUSED, char **argv)
 {
-  if (!arg || !*arg)
+  char *line, *s;
+  int interactive = isatty (0);
+  char *(*input_line) () = interactive ?
+                             input_line_interactive : input_line_script;
+
+  mu_set_program_name (argv[0]);
+  prompt = strdup (DEFAULT_PROMPT);
+  if (interactive)
+    initialize_readline ();    /* Bind our completer. */
+
+#ifdef WITH_TLS
+  mu_init_tls_libs ();
+#endif  
+  /* Loop reading and executing lines until the user quits. */
+  while (!done)
     {
-      mu_error ("%s: Argument required", caller);
-      return 0;
-    }
+      line = input_line ();
+      if (!line)
+       break;
+
+      /* Remove leading and trailing whitespace from the line.
+         Then, if there is anything left, add it to the history list
+         and execute it. */
+      s = mu_str_stripws (line);
 
-  return 1;
+      if (*s)
+       {
+         int status;
+
+#ifdef WITH_READLINE
+         if (interactive)
+           {
+             if (retrieve_history (s))
+               continue;
+             add_history (s);
+           }
+#endif
+
+         status = execute_line (s);
+         if (status != 0)
+           mu_error ("Error: %s", mu_strerror (status));
+       }
+
+      free (line);
+    }
+  if (interactive)
+    finish_readline ();
+  exit (0);
 }
+
diff --git a/examples/sfrom.c b/examples/sfrom.c
index 3a79cef..8e6384c 100644
--- a/examples/sfrom.c
+++ b/examples/sfrom.c
@@ -53,7 +53,12 @@ main (int argc, const char **argv)
       exit (EXIT_FAILURE);
     }
 
-  mu_mailbox_messages_count (mbox, &total);
+  status = mu_mailbox_messages_count (mbox, &total);
+  if (status != 0)
+    {
+      mu_error ("mu_mailbox_messages_count: %s", mu_strerror (status));
+      exit (EXIT_FAILURE);
+    }
 
   for (msgno = 1; msgno <= total; msgno++)
     {
diff --git a/frm/frm.c b/frm/frm.c
index b56bff2..f978560 100644
--- a/frm/frm.c
+++ b/frm/frm.c
@@ -31,7 +31,6 @@ static int align = 0;      /* Tidy mode. -t option. */
 #define IS_NEW  0x100
 static int select_attribute;
 
-const char *program_version = "frm (" PACKAGE_STRING ")";
 static char doc[] = N_("GNU frm -- display From: lines.");
 
 static struct attr_tab {
@@ -358,7 +357,7 @@ main (int argc, char **argv)
   mu_gocs_register ("tls", mu_tls_module_init);
 #endif
   
-  mu_argp_init (program_version, NULL);
+  mu_argp_init (NULL, NULL);
   if (mu_app_init (&argp, frm_argp_capa, NULL, argc, argv, 0, &c, NULL))
     exit (1);
 
diff --git a/frm/from.c b/frm/from.c
index 080b548..6b9fdf8 100644
--- a/frm/from.c
+++ b/frm/from.c
@@ -23,7 +23,6 @@ int count_only;
 char *sender_option;
 char *mailbox_name;
 
-const char *program_version = "from (" PACKAGE_STRING ")";
 static char doc[] = N_("GNU from -- display from and subject.");
 
 static struct argp_option options[] = {
@@ -120,7 +119,7 @@ main (int argc, char **argv)
   mu_gocs_register ("tls", mu_tls_module_init);
 #endif
 
-  mu_argp_init (program_version, NULL);
+  mu_argp_init (NULL, NULL);
   if (mu_app_init (&argp, capa, NULL, argc, argv, 0, &c, NULL))
     exit (1);
 
diff --git a/guimb/main.c b/guimb/main.c
index 460c6bd..f08d450 100644
--- a/guimb/main.c
+++ b/guimb/main.c
@@ -122,7 +122,6 @@ parse_opt (int key, char *arg, struct argp_state *state)
   return 0;
 }
 
-const char *program_version = "guimb (" PACKAGE_STRING ")";
 static char doc[] =
 N_("GNU guimb -- process contents of the specified mailboxes "
 "using a Scheme program or expression.");
@@ -161,7 +160,7 @@ main (int argc, char *argv[])
   /* Register the desired formats. */
   mu_register_all_formats ();
 
-  mu_argp_init (program_version, NULL);
+  mu_argp_init (NULL, NULL);
   if (mu_app_init (&argp, guimb_argp_capa, NULL, argc, argv, 0, &index, &c))
     exit (1);
 
diff --git a/imap4d/Makefile.am b/imap4d/Makefile.am
index 65a5b8c..bb0c19b 100644
--- a/imap4d/Makefile.am
+++ b/imap4d/Makefile.am
@@ -41,6 +41,7 @@ imap4d_SOURCES = \
  idle.c\
  imap4d.c\
  imap4d.h\
+ io.c\
  list.c\
  logout.c\
  login.c\
diff --git a/imap4d/append.c b/imap4d/append.c
index f6662aa..3a5c6cc 100644
--- a/imap4d/append.c
+++ b/imap4d/append.c
@@ -45,6 +45,7 @@ _append_sender (mu_envelope_t envelope, char *buf, size_t 
len, size_t *pnwrite)
   return 0;
 }
 
+/* FIXME: Why not use mu_message_size instead? */
 static int
 _append_size (mu_message_t msg, size_t *psize)
 {
@@ -66,7 +67,6 @@ imap4d_append0 (mu_mailbox_t mbox, int flags, char 
*date_time, char *text,
 {
   mu_stream_t stream;
   int rc = 0;
-  size_t len = 0;
   mu_message_t msg = 0;
   struct tm *tm;
   time_t t;
@@ -75,7 +75,7 @@ imap4d_append0 (mu_mailbox_t mbox, int flags, char 
*date_time, char *text,
   if (mu_message_create (&msg, &tm))
     return 1;
   
-  if (mu_memory_stream_create (&stream, 0, MU_STREAM_RDWR)
+  if (mu_memory_stream_create (&stream, MU_STREAM_RDWR)
       || mu_stream_open (stream))
     {
       mu_message_destroy (&msg, &tm);
@@ -101,7 +101,7 @@ imap4d_append0 (mu_mailbox_t mbox, int flags, char 
*date_time, char *text,
   while (*text && mu_isblank (*text))
     text++;
 
-  mu_stream_write (stream, text, strlen (text), len, &len);
+  mu_stream_write (stream, text, strlen (text), NULL);
   mu_message_set_stream (msg, stream, &tm);
   mu_message_set_size (msg, _append_size, &tm);
 
@@ -140,11 +140,11 @@ imap4d_append (struct imap4d_command *command, 
imap4d_tokbuf_t tok)
   char *err_text = "[TRYCREATE] failed";
   
   if (argc < 4)
-    return util_finish (command, RESP_BAD, "Too few arguments");
+    return io_completion_response (command, RESP_BAD, "Too few arguments");
       
   mboxname = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1);
   if (!mboxname)
-    return util_finish (command, RESP_BAD, "Too few arguments");
+    return io_completion_response (command, RESP_BAD, "Too few arguments");
 
   i = IMAP4_ARG_2;
   if (imap4d_tokbuf_getarg (tok, i)[0] == '(')
@@ -160,7 +160,8 @@ imap4d_append (struct imap4d_command *command, 
imap4d_tokbuf_t tok)
            break;
        }
       if (i == argc)
-       return util_finish (command, RESP_BAD, "Missing closing parenthesis");
+       return io_completion_response (command, RESP_BAD, 
+                                      "Missing closing parenthesis");
       i++;
     }
 
@@ -177,14 +178,14 @@ imap4d_append (struct imap4d_command *command, 
imap4d_tokbuf_t tok)
       break;
 
     default:
-      return util_finish (command, RESP_BAD, "Too many arguments");
+      return io_completion_response (command, RESP_BAD, "Too many arguments");
     }
 
   msg_text = imap4d_tokbuf_getarg (tok, i);
   
   mboxname = namespace_getfullpath (mboxname, "/", NULL);
   if (!mboxname)
-    return util_finish (command, RESP_NO, "Couldn't open mailbox"); 
+    return io_completion_response (command, RESP_NO, "Couldn't open mailbox"); 
 
   status = mu_mailbox_create_default (&dest_mbox, mboxname);
   if (status == 0)
@@ -202,9 +203,9 @@ imap4d_append (struct imap4d_command *command, 
imap4d_tokbuf_t tok)
   
   free (mboxname);
   if (status == 0)
-    return util_finish (command, RESP_OK, "Completed");
+    return io_completion_response (command, RESP_OK, "Completed");
 
-  return util_finish (command, RESP_NO, err_text);
+  return io_completion_response (command, RESP_NO, err_text);
 }
 
 
diff --git a/imap4d/auth_gsasl.c b/imap4d/auth_gsasl.c
index cf3e201..b16cd38 100644
--- a/imap4d/auth_gsasl.c
+++ b/imap4d/auth_gsasl.c
@@ -29,44 +29,6 @@ static Gsasl_session *sess_ctx;
 
 static void auth_gsasl_capa_init (int disable);
 
-static int
-create_gsasl_stream (mu_stream_t *newstr, mu_stream_t transport, int flags)
-{
-  int rc;
-  
-  rc = mu_gsasl_stream_create (newstr, transport, sess_ctx, flags);
-  if (rc)
-    {
-      mu_diag_output (MU_DIAG_ERROR, _("cannot create SASL stream: %s"),
-             mu_strerror (rc));
-      return RESP_NO;
-    }
-
-  if ((rc = mu_stream_open (*newstr)) != 0)
-    {
-      const char *p;
-      if (mu_stream_strerror (*newstr, &p))
-       p = mu_strerror (rc);
-      mu_diag_output (MU_DIAG_ERROR, _("cannot open SASL input stream: %s"), 
p);
-      return RESP_NO;
-    }
-
-  return RESP_OK;
-}
-
-int
-gsasl_replace_streams (void *self, void *data)
-{
-  mu_stream_t *s = data;
-
-  util_set_input (s[0]);
-  util_set_output (s[1]);
-  free (s);
-  util_event_remove (self);
-  free (self);
-  return 0;
-}
-
 static void
 finish_session (void)
 {
@@ -74,7 +36,21 @@ finish_session (void)
 }
 
 static int
-auth_gsasl (struct imap4d_command *command, char *auth_type, char **username)
+restore_and_return (struct imap4d_auth *ap, mu_stream_t *str, int resp)
+{
+  int rc = mu_stream_ioctl (iostream, MU_IOCTL_SWAP_STREAM, str);
+  if (rc)
+    {
+      mu_error (_("%s failed when it should not: %s"), "MU_IOCTL_SWAP_STREAM",
+               mu_stream_strerror (iostream, rc));
+      abort ();
+    }
+  ap->response = resp;
+  return imap4d_auth_resp;
+}
+
+static enum imap4d_auth_result
+auth_gsasl (struct imap4d_auth *ap)
 {
   char *input_str = NULL;
   size_t input_size = 0;
@@ -82,22 +58,22 @@ auth_gsasl (struct imap4d_command *command, char 
*auth_type, char **username)
   char *output;
   int rc;
   
-  rc = gsasl_server_start (ctx, auth_type, &sess_ctx);
+  rc = gsasl_server_start (ctx, ap->auth_type, &sess_ctx);
   if (rc != GSASL_OK)
     {
       mu_diag_output (MU_DIAG_NOTICE, _("SASL gsasl_server_start: %s"),
                      gsasl_strerror (rc));
-      return 0;
+      return imap4d_auth_fail;
     }
 
-  gsasl_callback_hook_set (ctx, username);
+  gsasl_callback_hook_set (ctx, &ap->username);
 
   output = NULL;
   while ((rc = gsasl_step64 (sess_ctx, input_str, &output))
           == GSASL_NEEDS_MORE)
     {
-      util_send ("+ %s\r\n", output);
-      imap4d_getline (&input_str, &input_size, &input_len);
+      io_sendf ("+ %s\n", output);
+      io_getline (&input_str, &input_size, &input_len);
     }
   
   if (rc != GSASL_OK)
@@ -106,58 +82,96 @@ auth_gsasl (struct imap4d_command *command, char 
*auth_type, char **username)
                      gsasl_strerror (rc));
       free (input_str);
       free (output);
-      return RESP_NO;
+      ap->response = RESP_NO;
+      return imap4d_auth_resp;
     }
 
   /* Some SASL mechanisms output additional data when GSASL_OK is
      returned, and clients must respond with an empty response. */
   if (output[0])
     {
-      util_send ("+ %s\r\n", output);
-      imap4d_getline (&input_str, &input_size, &input_len);
+      io_sendf ("+ %s\n", output);
+      io_getline (&input_str, &input_size, &input_len);
       if (input_len != 0)
        {
          mu_diag_output (MU_DIAG_NOTICE, _("non-empty client response"));
           free (input_str);
           free (output);
-         return RESP_NO;
+         ap->response = RESP_NO;
+         return imap4d_auth_resp;
        }
     }
 
   free (input_str);
   free (output);
 
-  if (*username == NULL)
+  if (ap->username == NULL)
     {
-      mu_diag_output (MU_DIAG_NOTICE, _("GSASL %s: cannot get username"), 
auth_type);
-      return RESP_NO;
+      mu_diag_output (MU_DIAG_NOTICE, _("GSASL %s: cannot get username"),
+                     ap->auth_type);
+      ap->response = RESP_NO;
+      return imap4d_auth_resp;
     }
 
+  auth_gsasl_capa_init (1);
   if (sess_ctx)
     {
-      mu_stream_t tmp, new_in, new_out;
-      mu_stream_t *s;
-
-      util_get_input (&tmp);
-      if (create_gsasl_stream (&new_in, tmp, MU_STREAM_READ))
-       return RESP_NO;
-      util_get_output (&tmp);
-      if (create_gsasl_stream (&new_out, tmp, MU_STREAM_WRITE))
+      mu_stream_t stream[2], newstream[2];
+
+      stream[0] = stream[1] = NULL;
+      rc = mu_stream_ioctl (iostream, MU_IOCTL_SWAP_STREAM, stream);
+      if (rc)
+       {
+         mu_error (_("%s failed: %s"), "MU_IOCTL_SWAP_STREAM",
+                   mu_stream_strerror (iostream, rc));
+         ap->response = RESP_NO;
+         return imap4d_auth_resp;
+       }
+      rc = gsasl_encoder_stream (&newstream[0], stream[0], sess_ctx,
+                                MU_STREAM_READ);
+      if (rc)
+       {
+         mu_error (_("%s failed: %s"), "gsasl_encoder_stream",
+                   mu_strerror (rc));
+         return restore_and_return (ap, stream, RESP_NO);
+       }
+
+      rc = gsasl_decoder_stream (&newstream[1], stream[1], sess_ctx,
+                                MU_STREAM_WRITE);
+      if (rc)
+       {
+         mu_error (_("%s failed: %s"), "gsasl_decoder_stream",
+                   mu_strerror (rc));
+         mu_stream_destroy (&newstream[0]);
+         return restore_and_return (ap, stream, RESP_NO);
+       }
+      
+      if (ap->username)
        {
-         mu_stream_destroy (&new_in, mu_stream_get_owner (new_in));
-         return RESP_NO;
+         if (imap4d_session_setup (ap->username))
+           return restore_and_return (ap, stream, RESP_NO);
        }
 
-      s = calloc (2, sizeof (mu_stream_t));
-      s[0] = new_in;
-      s[1] = new_out;
-      util_register_event (STATE_NONAUTH, STATE_AUTH,
-                          gsasl_replace_streams, s);
+      /* FIXME: This is not reflected in the transcript. */
+      io_stream_completion_response (stream[1], ap->command, RESP_OK,
+                                    "%s authentication successful",
+                                    ap->auth_type);
+      mu_stream_flush (stream[1]);
+      
+      rc = mu_stream_ioctl (iostream, MU_IOCTL_SWAP_STREAM, newstream);
+      if (rc)
+       {
+         mu_error (_("%s failed when it should not: %s"),
+                   "MU_IOCTL_SWAP_STREAM",
+                   mu_stream_strerror (iostream, rc));
+         abort ();
+       }
       util_atexit (finish_session);
+      return imap4d_auth_ok;
     }
   
-  auth_gsasl_capa_init (1);
-  return RESP_OK;
+  ap->response = RESP_OK;
+  return imap4d_auth_resp;
 }
 
 static void
diff --git a/imap4d/auth_gss.c b/imap4d/auth_gss.c
index e85c258..28ce74a 100644
--- a/imap4d/auth_gss.c
+++ b/imap4d/auth_gss.c
@@ -108,9 +108,8 @@ imap4d_gss_userok (gss_buffer_t client_name, char *name)
 }
 #endif
 
-static int
-auth_gssapi (struct imap4d_command *command,
-            char *auth_type_unused, char **username)
+static enum imap4d_auth_result
+auth_gssapi (struct imap4d_auth *ap)
 {
   gss_buffer_desc tokbuf, outbuf;
   OM_uint32 maj_stat, min_stat, min_stat2;
@@ -147,7 +146,8 @@ auth_gssapi (struct imap4d_command *command,
   if (maj_stat != GSS_S_COMPLETE)
     {
       display_status ("import name", maj_stat, min_stat);
-      return RESP_NO;
+      ap->response = RESP_NO;
+      return imap4d_auth_resp;
     }
 
   maj_stat = gss_acquire_cred (&min_stat, server_name, 0,
@@ -158,13 +158,14 @@ auth_gssapi (struct imap4d_command *command,
   if (maj_stat != GSS_S_COMPLETE)
     {
       display_status ("acquire credentials", maj_stat, min_stat);
-      return RESP_NO;
+      ap->response = RESP_NO;
+      return imap4d_auth_resp;
     }
 
   /* Start the dialogue */
 
-  util_send ("+ \r\n");
-  util_flush_output ();
+  io_sendf ("+ \n");
+  io_flush ();
   
   context = GSS_C_NO_CONTEXT;
 
@@ -172,7 +173,7 @@ auth_gssapi (struct imap4d_command *command,
     {
       OM_uint32 ret_flags;
       
-      imap4d_getline (&token_str, &token_size, &token_len);
+      io_getline (&token_str, &token_size, &token_len);
       mu_base64_decode ((unsigned char*) token_str, token_len, &tmp, &size);
       tokbuf.value = tmp;
       tokbuf.length = size;
@@ -192,7 +193,7 @@ auth_gssapi (struct imap4d_command *command,
          if (outbuf.length)
            {
              mu_base64_encode (outbuf.value, outbuf.length, &tmp, &size);
-             util_send ("+ %s\r\n", tmp);
+             io_sendf ("+ %s\n", tmp);
              free (tmp);
              gss_release_buffer (&min_stat, &outbuf);
            }
@@ -206,16 +207,17 @@ auth_gssapi (struct imap4d_command *command,
       maj_stat = gss_delete_sec_context (&min_stat, &context, &outbuf);
       gss_release_buffer (&min_stat, &outbuf);
       free (token_str);
-      return RESP_NO;
+      ap->response = RESP_NO;
+      return imap4d_auth_resp;
     }
 
   if (outbuf.length)
     {
       mu_base64_encode (outbuf.value, outbuf.length, &tmp, &size);
-      util_send ("+ %s\r\n", tmp);
+      io_sendf ("+ %s\n", tmp);
       free (tmp);
       gss_release_buffer (&min_stat, &outbuf);
-      imap4d_getline (&token_str, &token_size, &token_len);
+      io_getline (&token_str, &token_size, &token_len);
     }
 
   /* Construct security-level data */
@@ -228,14 +230,15 @@ auth_gssapi (struct imap4d_command *command,
     {
       display_status ("wrap", maj_stat, min_stat);
       free (token_str);
-      return RESP_NO;
+      ap->response = RESP_NO;
+      return imap4d_auth_resp;
     }
   
   mu_base64_encode (outbuf.value, outbuf.length, &tmp, &size);
-  util_send ("+ %s\r\n", tmp);
+  io_sendf ("+ %s\n", tmp);
   free (tmp);
 
-  imap4d_getline (&token_str, &token_size, &token_len);
+  io_getline (&token_str, &token_size, &token_len);
   mu_base64_decode ((unsigned char *) token_str, token_len,
                    (unsigned char **) &tokbuf.value, &tokbuf.length);
   free (token_str);
@@ -246,7 +249,8 @@ auth_gssapi (struct imap4d_command *command,
   if (maj_stat != GSS_S_COMPLETE)
     {
       display_status ("unwrap", maj_stat, min_stat);
-      return RESP_NO;
+      ap->response = RESP_NO;
+      return imap4d_auth_resp;
     }
   
   sec_level = ntohl (*(OM_uint32 *) outbuf.value);
@@ -261,23 +265,25 @@ auth_gssapi (struct imap4d_command *command,
       gss_release_buffer (&min_stat, &outbuf);
       maj_stat = gss_delete_sec_context (&min_stat, &context, &outbuf);
       gss_release_buffer (&min_stat, &outbuf);
-      return RESP_NO;
+      ap->response = RESP_NO;
+      return imap4d_auth_resp;
     }
   protection_mech = mech;
   client_buffer_size = sec_level & 0x00ffffffff;
 
-  *username = malloc (outbuf.length - 4 + 1);
-  if (!*username)
+  ap->username = malloc (outbuf.length - 4 + 1);
+  if (!ap->username)
     {
       mu_diag_output (MU_DIAG_NOTICE, _("not enough memory"));
       gss_release_buffer (&min_stat, &outbuf);
       maj_stat = gss_delete_sec_context (&min_stat, &context, &outbuf);
       gss_release_buffer (&min_stat, &outbuf);
-      return RESP_NO;
+      ap->response = RESP_NO;
+      return imap4d_auth_resp;
     }
        
-  memcpy (*username, (char *) outbuf.value + 4, outbuf.length - 4);
-  (*username)[outbuf.length - 4] = '\0';
+  memcpy (ap->username, (char *) outbuf.value + 4, outbuf.length - 4);
+  ap->username[outbuf.length - 4] = '\0';
   gss_release_buffer (&min_stat, &outbuf);
 
   maj_stat = gss_display_name (&min_stat, client, &client_name, &mech_type);
@@ -286,36 +292,40 @@ auth_gssapi (struct imap4d_command *command,
       display_status ("get client name", maj_stat, min_stat);
       maj_stat = gss_delete_sec_context (&min_stat, &context, &outbuf);
       gss_release_buffer (&min_stat, &outbuf);
-      free (*username);
-      return RESP_NO;
+      free (ap->username);
+      ap->response = RESP_NO;
+      return imap4d_auth_resp;
     }
 
 #ifdef WITH_GSS
-  baduser = !gss_userok (client, *username);
+  baduser = !gss_userok (client, ap->username);
 #else
-  baduser = imap4d_gss_userok (&client_name, *username);
+  baduser = imap4d_gss_userok (&client_name, ap->username);
 #endif
 
   if (baduser)
     {
-      mu_diag_output (MU_DIAG_NOTICE, _("GSSAPI user %s is NOT authorized as 
%s"),
-             (char *) client_name.value, *username);
+      mu_diag_output (MU_DIAG_NOTICE,
+                     _("GSSAPI user %s is NOT authorized as %s"),
+                     (char *) client_name.value, ap->username);
       maj_stat = gss_delete_sec_context (&min_stat, &context, &outbuf);
       gss_release_buffer (&min_stat, &outbuf);
       gss_release_buffer (&min_stat, &client_name);
-      free (*username);
-      return RESP_NO;
+      free (ap->username);
+      ap->response = RESP_NO;
+      return imap4d_auth_resp;
     }
   else
     {
       mu_diag_output (MU_DIAG_NOTICE, _("GSSAPI user %s is authorized as %s"),
-             (char *) client_name.value, *username);
+             (char *) client_name.value, ap->username);
     }
 
   gss_release_buffer (&min_stat, &client_name);
   maj_stat = gss_delete_sec_context (&min_stat, &context, &outbuf);
   gss_release_buffer (&min_stat, &outbuf);
-  return RESP_OK;
+  ap->response = RESP_OK;
+  return imap4d_auth_resp;
 }
 
 void
diff --git a/imap4d/authenticate.c b/imap4d/authenticate.c
index 1354203..166294c 100644
--- a/imap4d/authenticate.c
+++ b/imap4d/authenticate.c
@@ -19,7 +19,8 @@
 
 #include "imap4d.h"
 
-struct imap_auth {
+struct imap_auth
+{
   char *name;
   imap4d_auth_handler_fp handler;
 };
@@ -62,28 +63,21 @@ static int
 _auth_capa (void *item, void *usused)
 {
   struct imap_auth *p = item;
-  util_send(" AUTH=%s", p->name);
+  io_sendf (" AUTH=%s", p->name);
   return 0;
 }
 
-struct auth_data {
-  struct imap4d_command *command;
-  char *auth_type;
-  char *arg;
-  char *username;
-  int result;
-};
-
 static int
 _auth_try (void *item, void *data)
 {
   struct imap_auth *p = item;
-  struct auth_data *ap = data;
+  struct imap4d_auth *ap = data;
 
   if (strcmp (p->name, ap->auth_type) == 0)
     {
-      ap->result = p->handler (ap->command, ap->auth_type, &ap->username);
-      return 1;
+      int res = p->handler (ap);
+      if (res)
+       return res;
     }
   return 0;
 }
@@ -104,37 +98,49 @@ int
 imap4d_authenticate (struct imap4d_command *command, imap4d_tokbuf_t tok)
 {
   char *auth_type;
-  struct auth_data adata;
-
+  struct imap4d_auth adata;
+  enum imap4d_auth_result res;
+  
   if (imap4d_tokbuf_argc (tok) != 3)
-    return util_finish (command, RESP_BAD, "Invalid arguments");
+    return io_completion_response (command, RESP_BAD, "Invalid arguments");
   
   auth_type = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1);
 
   if (tls_required)
-    return util_finish (command, RESP_NO,
-                       "Command disabled: Use STARTTLS first");
+    return io_completion_response (command, RESP_NO,
+                                  "Command disabled: Use STARTTLS first");
   
   adata.command = command;
   adata.auth_type = auth_type;
-  adata.arg = NULL;
   adata.username = NULL;
 
-  if (mu_list_do (imap_auth_list, _auth_try, &adata) == 0)
-    return util_finish (command, RESP_NO,
-                       "Authentication mechanism not supported");
-  
-  if (adata.result == RESP_OK && adata.username)
+  res = mu_list_do (imap_auth_list, _auth_try, &adata);
+
+  switch (res)
     {
-      if (imap4d_session_setup (adata.username))
-       return util_finish (command, RESP_NO,
-                           "User name or passwd rejected");
-      else
-       return util_finish (command, RESP_OK,
-                           "%s authentication successful", auth_type);
+    case imap4d_auth_nosup:
+      return io_completion_response (command, RESP_NO,
+                                    "Authentication mechanism not supported");
+    case imap4d_auth_ok:
+      return 0;
+
+    case imap4d_auth_resp:
+      if (adata.response == RESP_OK && adata.username)
+       {
+         if (imap4d_session_setup (adata.username))
+           return io_completion_response (command, RESP_NO,
+                                          "User name or passwd rejected");
+         else
+           return io_completion_response (command, RESP_OK,
+                                          "%s authentication successful",
+                                          auth_type);
+       }
+      /* fall through */
+    case imap4d_auth_fail:
+      adata.response = RESP_NO;
+      break;
     }
-      
-  return util_finish (command, adata.result,
-                     "%s authentication failed", auth_type);
+  return io_completion_response (command, adata.response,
+                                "%s authentication failed", auth_type);
 }
 
diff --git a/imap4d/bye.c b/imap4d/bye.c
index 832fc7c..16b67df 100644
--- a/imap4d/bye.c
+++ b/imap4d/bye.c
@@ -40,13 +40,13 @@ imap4d_bye0 (int reason, struct imap4d_command *command)
   switch (reason)
     {
     case ERR_NO_MEM:
-      util_out (RESP_BYE, "Server terminating: no more resources.");
+      io_untagged_response (RESP_BYE, "Server terminating: no more 
resources.");
       mu_diag_output (MU_DIAG_ERROR, _("not enough memory"));
       break;
 
     case ERR_TERMINATE:
       status = EX_OK;
-      util_out (RESP_BYE, "Server terminating on request.");
+      io_untagged_response (RESP_BYE, "Server terminating on request.");
       mu_diag_output (MU_DIAG_NOTICE, _("terminating on request"));
       break;
 
@@ -56,7 +56,7 @@ imap4d_bye0 (int reason, struct imap4d_command *command)
 
     case ERR_TIMEOUT:
       status = EX_TEMPFAIL;
-      util_out (RESP_BYE, "Session timed out");
+      io_untagged_response (RESP_BYE, "Session timed out");
       if (state == STATE_NONAUTH)
         mu_diag_output (MU_DIAG_INFO, _("session timed out for no user"));
       else
@@ -77,10 +77,15 @@ imap4d_bye0 (int reason, struct imap4d_command *command)
       status = EX_OSERR;
       mu_diag_output (MU_DIAG_ERROR, _("mailbox modified by third party"));
       break;
+
+    case ERR_STREAM_CREATE:
+      status = EX_UNAVAILABLE;
+      mu_diag_output (MU_DIAG_ERROR, _("cannot create transport stream"));
+      break;
       
     case OK:
       status = EX_OK;
-      util_out (RESP_BYE, "Session terminating.");
+      io_untagged_response (RESP_BYE, "Session terminating.");
       if (state == STATE_NONAUTH)
        mu_diag_output (MU_DIAG_INFO, _("session terminating"));
       else
@@ -88,13 +93,13 @@ imap4d_bye0 (int reason, struct imap4d_command *command)
       break;
 
     default:
-      util_out (RESP_BYE, "Quitting (reason unknown)");
+      io_untagged_response (RESP_BYE, "Quitting (reason unknown)");
       mu_diag_output (MU_DIAG_ERROR, _("quitting (numeric reason %d)"), 
reason);
       break;
     }
 
   if (status == EX_OK && command)
-     util_finish (command, RESP_OK, "Completed");
+     io_completion_response (command, RESP_OK, "Completed");
 
   util_bye ();
 
diff --git a/imap4d/capability.c b/imap4d/capability.c
index c88bc60..02b5664 100644
--- a/imap4d/capability.c
+++ b/imap4d/capability.c
@@ -65,7 +65,7 @@ imap4d_capability_init ()
 static int
 print_capa (void *item, void *data)
 {
-  util_send (" %s", (char *)item);
+  io_sendf (" %s", (char *)item);
   return 0;
 }
 
@@ -73,14 +73,14 @@ int
 imap4d_capability (struct imap4d_command *command, imap4d_tokbuf_t tok)
 {
   if (imap4d_tokbuf_argc (tok) != 2)
-    return util_finish (command, RESP_BAD, "Invalid arguments");
+    return io_completion_response (command, RESP_BAD, "Invalid arguments");
   
-  util_send ("* CAPABILITY");
+  io_sendf ("* CAPABILITY");
 
   mu_list_do (capa_list, print_capa, NULL);
   
   imap4d_auth_capability ();
-  util_send ("\r\n");
+  io_sendf ("\n");
 
-  return util_finish (command, RESP_OK, "Completed");
+  return io_completion_response (command, RESP_OK, "Completed");
 }
diff --git a/imap4d/check.c b/imap4d/check.c
index ee1897d..4713a94 100644
--- a/imap4d/check.c
+++ b/imap4d/check.c
@@ -34,6 +34,6 @@ int
 imap4d_check (struct imap4d_command *command, imap4d_tokbuf_t tok)
 {
   if (imap4d_tokbuf_argc (tok) != 2)
-    return util_finish (command, RESP_BAD, "Invalid arguments");
-  return util_finish (command, RESP_OK, "Completed");
+    return io_completion_response (command, RESP_BAD, "Invalid arguments");
+  return io_completion_response (command, RESP_OK, "Completed");
 }
diff --git a/imap4d/close.c b/imap4d/close.c
index 732e849..49ede1c 100644
--- a/imap4d/close.c
+++ b/imap4d/close.c
@@ -27,10 +27,10 @@ imap4d_close0 (struct imap4d_command *command, 
imap4d_tokbuf_t tok,
   int status, flags;
 
   if (imap4d_tokbuf_argc (tok) != 2)
-    return util_finish (command, RESP_BAD, "Invalid arguments");
+    return io_completion_response (command, RESP_BAD, "Invalid arguments");
   
   mu_mailbox_get_flags (mbox, &flags);
-  if ((flags & MU_STREAM_READ) == 0)
+  if (flags & MU_STREAM_WRITE)
     {
       status = mu_mailbox_flush (mbox, expunge);
       if (status)
@@ -51,8 +51,8 @@ imap4d_close0 (struct imap4d_command *command, 
imap4d_tokbuf_t tok,
   mu_mailbox_destroy (&mbox);
 
   if (msg)
-    return util_finish (command, RESP_NO, msg);
-  return util_finish (command, RESP_OK, "Completed");
+    return io_completion_response (command, RESP_NO, msg);
+  return io_completion_response (command, RESP_OK, "Completed");
 }
 
 /*
diff --git a/imap4d/copy.c b/imap4d/copy.c
index b25e1ee..ef7aea0 100644
--- a/imap4d/copy.c
+++ b/imap4d/copy.c
@@ -42,7 +42,7 @@ imap4d_copy (struct imap4d_command *command, imap4d_tokbuf_t 
tok)
   char *text;
 
   if (imap4d_tokbuf_argc (tok) != 4)
-    return util_finish (command, RESP_BAD, "Invalid arguments");
+    return io_completion_response (command, RESP_BAD, "Invalid arguments");
   
   rc = imap4d_copy0 (tok, 0, &text);
   
@@ -52,9 +52,9 @@ imap4d_copy (struct imap4d_command *command, imap4d_tokbuf_t 
tok)
       int new_state = (rc == RESP_OK) ? command->success : command->failure;
       if (new_state != STATE_NONE)
        state = new_state;
-      return util_send ("%s %s\r\n", command->tag, text);
+      return io_sendf ("%s %s\n", command->tag, text);
     }
-  return util_finish (command, rc, "%s", text);
+  return io_completion_response (command, rc, "%s", text);
 }
 
 int
diff --git a/imap4d/create.c b/imap4d/create.c
index 0768d9f..918926a 100644
--- a/imap4d/create.c
+++ b/imap4d/create.c
@@ -91,16 +91,16 @@ imap4d_create (struct imap4d_command *command, 
imap4d_tokbuf_t tok)
   const char *msg = "Completed";
 
   if (imap4d_tokbuf_argc (tok) != 3)
-    return util_finish (command, RESP_BAD, "Invalid arguments");
+    return io_completion_response (command, RESP_BAD, "Invalid arguments");
 
   name = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1);
 
   if (*name == '\0')
-    return util_finish (command, RESP_BAD, "Too few arguments");
+    return io_completion_response (command, RESP_BAD, "Too few arguments");
 
   /* Creating, "Inbox" should always fail.  */
   if (mu_c_strcasecmp (name, "INBOX") == 0)
-    return util_finish (command, RESP_BAD, "Already exist");
+    return io_completion_response (command, RESP_BAD, "Already exist");
 
   /* RFC 3501:
          If the mailbox name is suffixed with the server's hierarchy
@@ -117,7 +117,7 @@ imap4d_create (struct imap4d_command *command, 
imap4d_tokbuf_t tok)
   name = namespace_getfullpath (name, delim, &ns);
 
   if (!name)
-    return util_finish (command, RESP_NO, "Cannot create mailbox");
+    return io_completion_response (command, RESP_NO, "Cannot create mailbox");
 
   /* It will fail if the mailbox already exists.  */
   if (access (name, F_OK) != 0)
@@ -165,5 +165,5 @@ imap4d_create (struct imap4d_command *command, 
imap4d_tokbuf_t tok)
       msg = "already exists";
     }
 
-  return util_finish (command, rc, msg);
+  return io_completion_response (command, rc, msg);
 }
diff --git a/imap4d/delete.c b/imap4d/delete.c
index b6f4f90..b7d30ae 100644
--- a/imap4d/delete.c
+++ b/imap4d/delete.c
@@ -39,25 +39,25 @@ imap4d_delete (struct imap4d_command *command, 
imap4d_tokbuf_t tok)
   char *name;
 
   if (imap4d_tokbuf_argc (tok) != 3)
-    return util_finish (command, RESP_BAD, "Invalid arguments");
+    return io_completion_response (command, RESP_BAD, "Invalid arguments");
   name = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1);
   if (!name || *name == '\0')
-    return util_finish (command, RESP_BAD, "Too few arguments");
+    return io_completion_response (command, RESP_BAD, "Too few arguments");
 
   /* It is an error to attempt to delele "INBOX or a mailbox
      name that dos not exists.  */
   if (mu_c_strcasecmp (name, "INBOX") == 0)
-    return util_finish (command, RESP_NO, "Already exist");
+    return io_completion_response (command, RESP_NO, "Already exist");
 
  /* Allocates memory.  */
   name = namespace_getfullpath (name, delim, NULL);
   if (!name)
-    return util_finish (command, RESP_NO, "Cannot remove");
+    return io_completion_response (command, RESP_NO, "Cannot remove");
 
   if (remove (name) != 0)
     {
       rc = RESP_NO;
       msg = "Cannot remove";
     }
-  return util_finish (command, rc, msg);
+  return io_completion_response (command, rc, msg);
 }
diff --git a/imap4d/examine.c b/imap4d/examine.c
index 6f5ed6a..cd4d669 100644
--- a/imap4d/examine.c
+++ b/imap4d/examine.c
@@ -36,7 +36,7 @@ int
 imap4d_examine (struct imap4d_command *command, imap4d_tokbuf_t tok)
 {
   if (imap4d_tokbuf_argc (tok) != 3)
-    return util_finish (command, RESP_BAD, "Invalid arguments");
+    return io_completion_response (command, RESP_BAD, "Invalid arguments");
   return imap4d_select0 (command, imap4d_tokbuf_getarg (tok, IMAP4_ARG_1),
                         MU_STREAM_READ);
 }
diff --git a/imap4d/expunge.c b/imap4d/expunge.c
index efea04f..46df985 100644
--- a/imap4d/expunge.c
+++ b/imap4d/expunge.c
@@ -36,11 +36,11 @@ int
 imap4d_expunge (struct imap4d_command *command, imap4d_tokbuf_t tok)
 {
   if (imap4d_tokbuf_argc (tok) != 2)
-    return util_finish (command, RESP_BAD, "Invalid arguments");
+    return io_completion_response (command, RESP_BAD, "Invalid arguments");
 
   /* FIXME: check for errors.  */
   mu_mailbox_expunge (mbox);
 
   imap4d_sync ();
-  return util_finish (command, RESP_OK, "Completed");
+  return io_completion_response (command, RESP_OK, "Completed");
 }
diff --git a/imap4d/fetch.c b/imap4d/fetch.c
index ef7d6ce..34860ff 100644
--- a/imap4d/fetch.c
+++ b/imap4d/fetch.c
@@ -77,7 +77,7 @@ fetch_send_address (const char *addr)
   /* Short circuit.  */
   if (addr == NULL || *addr == '\0')
     {
-      util_send ("NIL");
+      io_sendf ("NIL");
       return RESP_OK;
     }
 
@@ -87,26 +87,26 @@ fetch_send_address (const char *addr)
   /* We failed: can't parse.  */
   if (count == 0)
     {
-      util_send ("NIL");
+      io_sendf ("NIL");
       return RESP_OK;
     }
 
-  util_send ("(");
+  io_sendf ("(");
   for (i = 1; i <= count; i++)
     {
       const char *str;
       int is_group = 0;
 
-      util_send ("(");
+      io_sendf ("(");
 
       mu_address_sget_personal (address, i, &str);
-      util_send_qstring (str);
-      util_send (" ");
+      io_send_qstring (str);
+      io_sendf (" ");
 
       mu_address_sget_route (address, i, &str);
-      util_send_qstring (str);
+      io_send_qstring (str);
 
-      util_send (" ");
+      io_sendf (" ");
 
       mu_address_is_group (address, i, &is_group);
       str = NULL;
@@ -115,16 +115,16 @@ fetch_send_address (const char *addr)
       else
        mu_address_sget_local_part (address, i, &str);
 
-      util_send_qstring (str);
+      io_send_qstring (str);
 
-      util_send (" ");
+      io_sendf (" ");
 
       mu_address_sget_domain (address, i, &str);
-      util_send_qstring (str);
+      io_send_qstring (str);
 
-      util_send (")");
+      io_sendf (")");
     }
-  util_send (")");
+  io_sendf (")");
   return RESP_OK;
 }
 
@@ -135,16 +135,16 @@ fetch_send_header_value (mu_header_t header, const char 
*name,
   char *buffer;
   
   if (space)
-    util_send (" ");
+    io_sendf (" ");
   if (mu_header_aget_value (header, name, &buffer) == 0)
     {
-      util_send_qstring (buffer);
+      io_send_qstring (buffer);
       free (buffer);
     }
   else if (defval)
-    util_send_qstring (defval);
+    io_send_qstring (defval);
   else
-    util_send ("NIL");
+    io_sendf ("NIL");
 }
 
 static void
@@ -154,7 +154,7 @@ fetch_send_header_address (mu_header_t header, const char 
*name,
   char *buffer;
   
   if (space)
-    util_send (" ");
+    io_sendf (" ");
   if (mu_header_aget_value (header, name, &buffer) == 0)
     {
       fetch_send_address (buffer);
@@ -173,36 +173,36 @@ send_parameter_list (const char *buffer)
   
   if (!buffer)
     {
-      util_send ("NIL");
+      io_sendf ("NIL");
       return;
     }
 
   mu_argcv_get (buffer, " \t\r\n;=", NULL, &argc, &argv);
   
   if (argc == 0)
-    util_send ("NIL");
+    io_sendf ("NIL");
   else
     {
       char *p;
       
-      util_send ("(");
+      io_sendf ("(");
         
       p = argv[0];
-      util_send_qstring (p);
+      io_send_qstring (p);
 
       if (argc > 1)
        {
          int i, space = 0;
          char *lvalue = NULL;
 
-         util_send ("(");
+         io_sendf ("(");
          for (i = 1; i < argc; i++)
            {
              if (lvalue)
                {
                  if (space)
-                   util_send (" ");
-                 util_send_qstring (lvalue);
+                   io_sendf (" ");
+                 io_send_qstring (lvalue);
                  lvalue = NULL;
                  space = 1;
                }
@@ -216,8 +216,8 @@ send_parameter_list (const char *buffer)
                  if (++i < argc)
                    {
                      char *p = argv[i];
-                     util_send (" ");
-                     util_send_qstring (p);
+                     io_sendf (" ");
+                     io_send_qstring (p);
                    }
                  break;
                  
@@ -228,14 +228,14 @@ send_parameter_list (const char *buffer)
          if (lvalue)
            {
              if (space)
-               util_send (" ");
-             util_send_qstring (lvalue);
+               io_sendf (" ");
+             io_send_qstring (lvalue);
            }
-         util_send (")");
+         io_sendf (")");
        }
       else
-       util_send (" NIL");
-      util_send (")");
+       io_sendf (" NIL");
+      io_sendf (")");
     }
   mu_argcv_free (argc, argv);
 }
@@ -247,7 +247,7 @@ fetch_send_header_list (mu_header_t header, const char 
*name,
   char *buffer;
   
   if (space)
-    util_send (" ");
+    io_sendf (" ");
   if (mu_header_aget_value (header, name, &buffer) == 0)
     {
       send_parameter_list (buffer);
@@ -256,7 +256,7 @@ fetch_send_header_list (mu_header_t header, const char 
*name,
   else if (defval)
     send_parameter_list (defval);
   else
-    util_send ("NIL");
+    io_sendf ("NIL");
 }
 
 /* ENVELOPE:
@@ -282,7 +282,7 @@ fetch_envelope0 (mu_message_t msg)
 
   /* From:  */
   mu_header_aget_value (header, "From", &from);
-  util_send (" ");
+  io_sendf (" ");
   fetch_send_address (from);
 
   fetch_send_header_address (header, "Sender", from, 1);
@@ -369,9 +369,9 @@ bodystructure (mu_message_t msg, int extension)
       if (s)
        *s++ = 0;
       p = argv[0];
-      util_send_qstring (p);
-      util_send (" ");
-      util_send_qstring (s);
+      io_send_qstring (p);
+      io_sendf (" ");
+      io_send_qstring (s);
 
       /* body parameter parenthesized list: Content-type attributes */
       if (argc > 1 || text_plain)
@@ -381,7 +381,7 @@ bodystructure (mu_message_t msg, int extension)
          int have_charset = 0;
          int i;
          
-         util_send (" (");
+         io_sendf (" (");
          for (i = 1; i < argc; i++)
            {
              /* body parameter parenthesized list:
@@ -389,8 +389,8 @@ bodystructure (mu_message_t msg, int extension)
              if (lvalue)
                {
                  if (space)
-                   util_send (" ");
-                 util_send_qstring (lvalue);
+                   io_sendf (" ");
+                 io_send_qstring (lvalue);
                  lvalue = NULL;
                  space = 1;
                }
@@ -404,8 +404,8 @@ bodystructure (mu_message_t msg, int extension)
                  if (++i < argc)
                    {
                      char *p = argv[i];
-                     util_send (" ");
-                     util_send_qstring (p);
+                     io_sendf (" ");
+                     io_send_qstring (p);
                    }
                  break;
                  
@@ -420,27 +420,27 @@ bodystructure (mu_message_t msg, int extension)
          if (lvalue)
            {
              if (space)
-               util_send (" ");
-             util_send_qstring (lvalue);
+               io_sendf (" ");
+             io_send_qstring (lvalue);
            }
          
          if (!have_charset && text_plain)
            {
              if (space)
-               util_send (" ");
-             util_send ("\"CHARSET\" \"US-ASCII\"");
+               io_sendf (" ");
+             io_sendf ("\"CHARSET\" \"US-ASCII\"");
            }
-         util_send (")");
+         io_sendf (")");
        }
       else
-       util_send (" NIL");
+       io_sendf (" NIL");
       mu_argcv_free (argc, argv);
       free (buffer);
     }
   else
     {
       /* Default? If Content-Type is not present consider as text/plain.  */
-      util_send ("\"TEXT\" \"PLAIN\" (\"CHARSET\" \"US-ASCII\")");
+      io_sendf ("\"TEXT\" \"PLAIN\" (\"CHARSET\" \"US-ASCII\")");
       text_plain = 1;
     }
   
@@ -460,14 +460,14 @@ bodystructure (mu_message_t msg, int extension)
     mu_message_get_body (msg, &body);
     mu_body_size (body, &size);
     mu_body_lines (body, &blines);
-    util_send (" %s", mu_umaxtostr (0, size + blines));
+    io_sendf (" %s", mu_umaxtostr (0, size + blines));
   }
 
   /* If the mime type was text.  */
   if (text_plain)
     {
       /* Add the line number of the body.  */
-      util_send (" %s", mu_umaxtostr (0, blines));
+      io_sendf (" %s", mu_umaxtostr (0, blines));
     }
   else if (message_rfc822)
     {
@@ -475,16 +475,16 @@ bodystructure (mu_message_t msg, int extension)
       mu_message_t emsg = NULL;
       mu_message_unencapsulate  (msg, &emsg, NULL);
       /* Add envelope structure of the encapsulated message.  */
-      util_send (" (");
+      io_sendf (" (");
       fetch_envelope0 (emsg);
-      util_send (")");
+      io_sendf (")");
       /* Add body structure of the encapsulated message.  */
-      util_send ("(");
+      io_sendf ("(");
       bodystructure (emsg, extension);
-      util_send (")");
+      io_sendf (")");
       /* Size in text lines of the encapsulated message.  */
       mu_message_lines (emsg, &lines);
-      util_send (" %s", mu_umaxtostr (0, lines));
+      io_sendf (" %s", mu_umaxtostr (0, lines));
       mu_message_destroy (&emsg, NULL);
     }
 
@@ -544,9 +544,9 @@ fetch_bodystructure0 (mu_message_t message, int extension)
         {
           mu_message_t msg = NULL;
           mu_message_get_part (message, i, &msg);
-          util_send ("(");
+          io_sendf ("(");
           fetch_bodystructure0 (msg, extension);
-          util_send (")");
+          io_sendf (")");
         } /* for () */
 
       mu_message_get_header (message, &header);
@@ -564,8 +564,8 @@ fetch_bodystructure0 (mu_message_t message, int extension)
          s = strchr (argv[0], '/');
          if (s)
            s++;
-         util_send (" ");
-         util_send_qstring (s);
+         io_sendf (" ");
+         io_send_qstring (s);
 
          /* The extension data for multipart. */
          if (extension)
@@ -573,7 +573,7 @@ fetch_bodystructure0 (mu_message_t message, int extension)
              int space = 0;
              char *lvalue = NULL;
              
-             util_send (" (");
+             io_sendf (" (");
              for (i = 1; i < argc; i++)
                {
                  /* body parameter parenthesized list:
@@ -581,8 +581,8 @@ fetch_bodystructure0 (mu_message_t message, int extension)
                  if (lvalue)
                    {
                      if (space)
-                       util_send (" ");
-                     util_send_qstring (lvalue);
+                       io_sendf (" ");
+                     io_send_qstring (lvalue);
                      lvalue = NULL;
                      space = 1;
                    }
@@ -596,8 +596,8 @@ fetch_bodystructure0 (mu_message_t message, int extension)
                      if (++i < argc)
                        {
                          char *p = argv[i];
-                         util_send (" ");
-                         util_send_qstring (p);
+                         io_sendf (" ");
+                         io_send_qstring (p);
                        }
                      break;
                      
@@ -608,19 +608,19 @@ fetch_bodystructure0 (mu_message_t message, int extension)
              if (lvalue)
                {
                  if (space)
-                   util_send (" ");
-                 util_send_qstring (lvalue);
+                   io_sendf (" ");
+                 io_send_qstring (lvalue);
                }
-             util_send (")");
+             io_sendf (")");
            }
          else
-           util_send (" NIL");
+           io_sendf (" NIL");
          mu_argcv_free (argc, argv);
           free (buffer);
        }
       else
        /* No content-type header */
-       util_send (" NIL");
+       io_sendf (" NIL");
 
       /* body disposition: Content-Disposition.  */
       fetch_send_header_list (header, MU_HEADER_CONTENT_DISPOSITION,
@@ -644,7 +644,7 @@ set_seen (struct fetch_function_closure *ffc,
       mu_message_get_attribute (frt->msg, &attr);
       if (!mu_attribute_is_read (attr))
        {
-         util_send ("FLAGS (\\Seen) ");
+         io_sendf ("FLAGS (\\Seen) ");
          mu_attribute_set_read (attr);
        }
     }
@@ -669,92 +669,100 @@ fetch_send_section_part (struct fetch_function_closure 
*ffc,
 {
   int i;
   
-  util_send ("BODY[");
+  io_sendf ("BODY[");
   for (i = 0; i < ffc->nset; i++)
     {
       if (i)
-       util_send (".");
-      util_send ("%lu",  (unsigned long) ffc->section_part[i]);
+       io_sendf (".");
+      io_sendf ("%lu",  (unsigned long) ffc->section_part[i]);
     }
   if (suffix)
     {
       if (i)
-       util_send (".");
-      util_send ("%s", suffix);
+       io_sendf (".");
+      io_sendf ("%s", suffix);
     }
   if (close_bracket)
-    util_send ("]");
+    io_sendf ("]");
 }
 
 static int
 fetch_io (mu_stream_t stream, size_t start, size_t size, size_t max)
 {
   mu_stream_t rfc = NULL;
+  
   size_t n = 0;
-  mu_off_t offset;
-
-  mu_filter_create (&rfc, stream, "rfc822", MU_FILTER_ENCODE,
-                   MU_STREAM_READ|MU_STREAM_NO_CHECK|MU_STREAM_NO_CLOSE);
 
+  mu_filter_create (&rfc, stream, "CRLF", MU_FILTER_ENCODE,
+                   MU_STREAM_READ|MU_STREAM_SEEK);
+  
   if (start == 0 && size == (size_t) -1)
     {
-      char *buffer;
-      size_t bufsize;
-
-      for (bufsize = max; (buffer = malloc (bufsize)) == NULL; bufsize /= 2)
-       if (bufsize < 512)
-         imap4d_bye (ERR_NO_MEM);
-
-      offset = 0;
+      int rc;
+      
+      rc = mu_stream_seek (rfc, 0, MU_SEEK_SET, NULL);
+      if (rc)
+       {
+         mu_error ("seek error: %s", mu_stream_strerror (stream, rc));
+         return RESP_BAD;
+       }
       if (max)
        {
-         util_send (" {%lu}\r\n", (unsigned long) max);
-         while (mu_stream_read (rfc, buffer, bufsize, offset,
-                                &n) == 0 && n > 0)
-           {
-             util_send_bytes (buffer, n);
-             offset += n;
-           }
+         io_sendf (" {%lu}\n", (unsigned long) max);
+         io_copy_out (rfc, max);
          /* FIXME: Make sure exactly max bytes were sent */
-          free (buffer); 
        }
       else
-       util_send (" \"\"");
+       io_sendf (" \"\"");
+    }
+  else if (start > max)
+    {
+      io_sendf ("<%lu>", (unsigned long) start);
+      io_sendf (" \"\"");
     }
   else if (size + 2 < size) /* Check for integer overflow */
     {
-      mu_stream_destroy (&rfc, NULL);
+      mu_stream_destroy (&rfc);
       return RESP_BAD;
     }
   else
     {
+      int rc;
       char *buffer, *p;
       size_t total = 0;
-      offset = start;
+
       p = buffer = malloc (size + 1);
       if (!p)
        imap4d_bye (ERR_NO_MEM);
-      
+
+      rc = mu_stream_seek (rfc, start, MU_SEEK_SET, NULL);
+      if (rc)
+       {
+         mu_error ("seek error: %s", mu_stream_strerror (rfc, rc));
+         free (buffer);
+         mu_stream_destroy (&rfc);
+         return RESP_BAD;
+       }
+
       while (total < size
-            && mu_stream_read (rfc, p, size - total + 1, offset, &n) == 0
+            && mu_stream_read (rfc, p, size - total, &n) == 0
             && n > 0)
        {
-         offset += n;
          total += n;
          p += n;
        }
       *p = 0;
-      util_send ("<%lu>", (unsigned long) start);
+      io_sendf ("<%lu>", (unsigned long) start);
       if (total)
        {
-         util_send (" {%lu}\r\n", (unsigned long) total);
-         util_send_bytes (buffer, total);
+         io_sendf (" {%lu}\n", (unsigned long) total);
+         io_send_bytes (buffer, total);
        }
       else
-       util_send (" \"\"");
+       io_sendf (" \"\"");
       free (buffer);
     }
-  mu_stream_destroy (&rfc, NULL);
+  mu_stream_destroy (&rfc);
   return RESP_OK;
 }
 
@@ -767,7 +775,7 @@ _frt_uid (struct fetch_function_closure *ffc,
   size_t uid = 0;
 
   mu_message_get_uid (frt->msg, &uid);
-  util_send ("%s %s", ffc->name, mu_umaxtostr (0, uid));
+  io_sendf ("%s %s", ffc->name, mu_umaxtostr (0, uid));
   return RESP_OK;
 }
 
@@ -775,9 +783,9 @@ static int
 _frt_envelope (struct fetch_function_closure *ffc,
               struct fetch_runtime_closure *frt)
 {
-  util_send ("%s (", ffc->name);
+  io_sendf ("%s (", ffc->name);
   fetch_envelope0 (frt->msg);
-  util_send (")");
+  io_sendf (")");
   return RESP_OK;
 }
 
@@ -788,9 +796,9 @@ _frt_flags (struct fetch_function_closure *ffc,
   mu_attribute_t attr = NULL;
 
   mu_message_get_attribute (frt->msg, &attr);
-  util_send ("%s (", ffc->name);
+  io_sendf ("%s (", ffc->name);
   util_print_flags (attr);
-  util_send (")");
+  io_sendf (")");
   return 0;
 }
 
@@ -843,8 +851,8 @@ _frt_internaldate (struct fetch_function_closure *ffc,
       tmp = localtime (&t);
     }
   mu_strftime (datebuf, sizeof (datebuf), "%d-%b-%Y %H:%M:%S", tmp);
-  util_send ("%s", ffc->name);
-  util_send (" \"%s +0000\"", datebuf);
+  io_sendf ("%s", ffc->name);
+  io_sendf (" \"%s +0000\"", datebuf);
   return 0;
 }
 
@@ -852,9 +860,9 @@ static int
 _frt_bodystructure (struct fetch_function_closure *ffc,
                    struct fetch_runtime_closure *frt)
 {
-  util_send ("%s (", ffc->name);
+  io_sendf ("%s (", ffc->name);
   fetch_bodystructure0 (frt->msg, 1); /* 1 means with extension data.  */
-  util_send (")");
+  io_sendf (")");
   return RESP_OK;
 }
 
@@ -862,9 +870,9 @@ static int
 _frt_bodystructure0 (struct fetch_function_closure *ffc,
                     struct fetch_runtime_closure *frt)
 {
-  util_send ("%s (", ffc->name);
+  io_sendf ("%s (", ffc->name);
   fetch_bodystructure0 (frt->msg, 0);
-  util_send (")");
+  io_sendf (")");
   return RESP_OK;
 }
 
@@ -876,22 +884,25 @@ _frt_body (struct fetch_function_closure *ffc,
   mu_message_t msg;
   mu_stream_t stream = NULL;
   size_t size = 0, lines = 0;
-
+  int rc;
+  
   set_seen (ffc, frt);
   if (ffc->name)
-    util_send ("%s", ffc->name);
+    io_sendf ("%s", ffc->name);
   else
     fetch_send_section_part (ffc, NULL, 1);
   msg = fetch_get_part (ffc, frt);
   if (!msg)
     {
-      util_send (" \"\"");
+      io_sendf (" \"\"");
       return RESP_OK;
     }
-  mu_message_get_stream (msg, &stream);
+  mu_message_get_streamref (msg, &stream);
   mu_message_size (msg, &size);
   mu_message_lines (msg, &lines);
-  return fetch_io (stream, ffc->start, ffc->size, size + lines);
+  rc = fetch_io (stream, ffc->start, ffc->size, size + lines);
+  mu_stream_destroy (&stream);
+  return rc;
 }
 
 static int
@@ -902,24 +913,27 @@ _frt_body_text (struct fetch_function_closure *ffc,
   mu_body_t body = NULL;
   mu_stream_t stream = NULL;
   size_t size = 0, lines = 0;
-
+  int rc;
+  
   set_seen (ffc, frt);
   if (ffc->name)
-    util_send ("%s",  ffc->name);
+    io_sendf ("%s",  ffc->name);
   else
     fetch_send_section_part (ffc, ffc->section_tag, 1);
   msg = fetch_get_part (ffc, frt);
   if (!msg)
     {
-      util_send (" \"\"");
+      io_sendf (" \"\"");
       return RESP_OK;
     }
 
   mu_message_get_body (msg, &body);
   mu_body_size (body, &size);
   mu_body_lines (body, &lines);
-  mu_body_get_stream (body, &stream);
-  return fetch_io (stream, ffc->start, ffc->size, size + lines);
+  mu_body_get_streamref (body, &stream);
+  rc = fetch_io (stream, ffc->start, ffc->size, size + lines);
+  mu_stream_destroy (&stream);
+  return rc;
 }
 
 static int
@@ -931,7 +945,7 @@ _frt_size (struct fetch_function_closure *ffc,
   
   mu_message_size (frt->msg, &size);
   mu_message_lines (frt->msg, &lines);
-  util_send ("%s %lu", ffc->name, (unsigned long) (size + lines));
+  io_sendf ("%s %lu", ffc->name, (unsigned long) (size + lines));
   return RESP_OK;
 }
 
@@ -943,24 +957,27 @@ _frt_header (struct fetch_function_closure *ffc,
   mu_header_t header = NULL;
   mu_stream_t stream = NULL;
   size_t size = 0, lines = 0;
+  int rc;
   
   set_seen (ffc, frt);
   if (ffc->name)
-    util_send ("%s", ffc->name);
+    io_sendf ("%s",  ffc->name);
   else
     fetch_send_section_part (ffc, ffc->section_tag, 1);
 
   msg = fetch_get_part (ffc, frt);
   if (!msg)
     {
-      util_send (" \"\"");
+      io_sendf (" \"\"");
       return RESP_OK;
     }
   mu_message_get_header (msg, &header);
   mu_header_size (header, &size);
   mu_header_lines (header, &lines);
-  mu_header_get_stream (header, &stream);
-  return fetch_io (stream, ffc->start, ffc->size, size + lines);
+  mu_header_get_streamref (header, &stream);
+  rc = fetch_io (stream, ffc->start, ffc->size, size + lines);
+  mu_stream_destroy (&stream);
+  return rc;
 }
 
 static int
@@ -968,10 +985,10 @@ _send_header_name (void *item, void *data)
 {
   int *pf = data;
   if (*pf)
-    util_send (" ");
+    io_sendf (" ");
   else
     *pf = 1;
-  util_send ("%s", (char*) item);
+  io_sendf ("%s", (char*) item);
   return 0;
 }
 
@@ -1000,16 +1017,16 @@ _frt_header_fields (struct fetch_function_closure *ffc,
 
   fetch_send_section_part (ffc, "HEADER.FIELDS", 0);
   if (ffc->not)
-    util_send (".NOT");
-  util_send (" (");
+    io_sendf (".NOT");
+  io_sendf (" (");
   status = 0;
   mu_list_do (ffc->headers, _send_header_name, &status);
-  util_send (")]");
+  io_sendf (")]");
   
   msg = fetch_get_part (ffc, frt);
   if (!msg)
     {
-      util_send (" \"\"");
+      io_sendf (" \"\"");
       return RESP_OK;
     }
 
@@ -1017,11 +1034,11 @@ _frt_header_fields (struct fetch_function_closure *ffc,
   if (mu_message_get_header (msg, &header)
       || mu_header_get_iterator (header, &itr))
     {
-      util_send (" \"\"");
+      io_sendf (" \"\"");
       return RESP_OK;
     }
 
-  status = mu_memory_stream_create (&stream, NULL, MU_STREAM_NO_CHECK);
+  status = mu_memory_stream_create (&stream, 0);
   if (status != 0)
     imap4d_bye (ERR_NO_MEM);
 
@@ -1042,17 +1059,19 @@ _frt_header_fields (struct fetch_function_closure *ffc,
       
       if (status)
        {
-         mu_stream_sequential_printf (stream, "%s: %s\n", item, hv);
+         mu_stream_printf (stream, "%s: %s\n", item, hv);
          lines += 1 + count_nl (hv);
        }
     }
-  mu_stream_sequential_write (stream, "\n", 1);
+  mu_iterator_destroy (&itr);
+  mu_stream_write (stream, "\n", 1, NULL);
   lines++;
   
   /* Output collected data */
   mu_stream_size (stream, &size);
+  mu_stream_seek (stream, 0, MU_SEEK_SET, NULL);
   status = fetch_io (stream, ffc->start, ffc->size, size + lines);
-  mu_stream_destroy (&stream, NULL);
+  mu_stream_destroy (&stream);
   
   return status;
 }
@@ -1080,7 +1099,7 @@ _do_fetch (void *item, void *data)
   struct fetch_function_closure *ffc = item;
   struct fetch_runtime_closure *frt = data;
   if (frt->eltno++)
-    util_send (" ");
+    io_sendf (" ");
   return ffc->fun (ffc, frt);
 }
 
@@ -1625,10 +1644,10 @@ imap4d_fetch0 (imap4d_tokbuf_t tok, int isuid, char 
**err_text)
          if (frc.msgno &&
              mu_mailbox_get_message (mbox, frc.msgno, &frc.msg) == 0)
            {
-             util_send ("* %lu FETCH (", (unsigned long) frc.msgno);
+             io_sendf ("* %lu FETCH (", (unsigned long) frc.msgno);
              frc.eltno = 0;
              rc = mu_list_do (pclos.fnlist, _do_fetch, &frc);
-             util_send (")\r\n");
+             io_sendf (")\n");
            }
        }
       }
@@ -1660,8 +1679,8 @@ imap4d_fetch (struct imap4d_command *command, 
imap4d_tokbuf_t tok)
 {
   int rc;
   char *err_text = "Completed";
-
+  int xlev = set_xscript_level (MU_XSCRIPT_PAYLOAD);
   rc = imap4d_fetch0 (tok, 0, &err_text);
-  return util_finish (command, rc, "%s", err_text);
+  set_xscript_level (xlev);
+  return io_completion_response (command, rc, "%s", err_text);
 }
-
diff --git a/imap4d/id.c b/imap4d/id.c
index f8c261c..2561a1a 100644
--- a/imap4d/id.c
+++ b/imap4d/id.c
@@ -169,7 +169,7 @@ imap4d_id (struct imap4d_command *command, imap4d_tokbuf_t 
tok)
 {
   int rc = eat_args (tok);
   if (rc != RESP_OK)
-    return util_finish (command, rc, "Syntax error");
+    return io_completion_response (command, rc, "Syntax error");
   if (imap4d_id_list)
     {
       mu_iterator_t itr;
@@ -194,15 +194,15 @@ imap4d_id (struct imap4d_command *command, 
imap4d_tokbuf_t tok)
          if (q)
            {
              if (outcnt++ == 0)
-               util_send ("* ID (");
+               io_sendf ("* ID (");
              else
-               util_send (" ");
-             util_send ("\"%*.*s\" \"%s\"", (int) len, (int) len, p, q);
+               io_sendf (" ");
+             io_sendf ("\"%*.*s\" \"%s\"", (int) len, (int) len, p, q);
            }
        }
       mu_iterator_destroy (&itr);
       if (outcnt)
-       util_send (")\r\n");
+       io_sendf (")\n");
     }
-  return util_finish (command, RESP_OK, "Completed");
+  return io_completion_response (command, RESP_OK, "Completed");
 }
diff --git a/imap4d/idle.c b/imap4d/idle.c
index e3ddd6c..fde91ab 100644
--- a/imap4d/idle.c
+++ b/imap4d/idle.c
@@ -27,21 +27,20 @@ imap4d_idle (struct imap4d_command *command, 
imap4d_tokbuf_t tok)
   size_t token_size = 0, token_len;
   
   if (imap4d_tokbuf_argc (tok) != 2)
-    return util_finish (command, RESP_BAD, "Invalid arguments");
+    return io_completion_response (command, RESP_BAD, "Invalid arguments");
 
-  if (util_wait_input (0) == -1)
-    return util_finish (command, RESP_NO, "Cannot idle");
+  if (io_wait_input (0) == -1)
+    return io_completion_response (command, RESP_NO, "Cannot idle");
 
-  util_send ("+ idling\r\n");
-  util_flush_output ();
+  io_sendf ("+ idling\n");
+  io_flush ();
 
   start = time (NULL);
   while (1)
     {
-      if (util_wait_input (5))
+      if (io_wait_input (5))
        {
-          imap4d_getline (&token_str, &token_size, &token_len);          
-         token_len = util_trim_nl (token_str, token_len);
+          io_getline (&token_str, &token_size, &token_len);      
          if (token_len == 4 && mu_c_strcasecmp (token_str, "done") == 0)
            break;
        }
@@ -49,9 +48,9 @@ imap4d_idle (struct imap4d_command *command, imap4d_tokbuf_t 
tok)
        imap4d_bye (ERR_TIMEOUT);
 
       imap4d_sync ();
-      util_flush_output ();
+      io_flush ();
     }
   free (token_str);
-  return util_finish (command, RESP_OK, "terminated");
+  return io_completion_response (command, RESP_OK, "terminated");
 }
 
diff --git a/imap4d/imap4d.c b/imap4d/imap4d.c
index 0b36a00..a5b29e0 100644
--- a/imap4d/imap4d.c
+++ b/imap4d/imap4d.c
@@ -399,7 +399,7 @@ imap4d_mainloop (int fd, FILE *infile, FILE *outfile)
   int debug_mode = isatty (fd);
 
   imap4d_child_signal_setup (imap4d_child_signal);
-  util_setio (infile, outfile);
+  io_setio (infile, outfile);
 
   if (imap4d_preauth_setup (fd) == 0)
     {
@@ -413,14 +413,18 @@ imap4d_mainloop (int fd, FILE *infile, FILE *outfile)
     }
   else
     {
-      util_flush_output ();
+      io_flush ();
       return 0;
     }
 
-  /* Greetings.  */
-  util_out ((state == STATE_AUTH) ? RESP_PREAUTH : RESP_OK, "%s", text);
-  util_flush_output ();
+  /* Greetings. */
+  io_untagged_response ((state == STATE_AUTH) ? 
+                        RESP_PREAUTH : RESP_OK, "%s", text);
+  io_flush ();
 
+  set_xscript_level ((state == STATE_AUTH) ?
+                      MU_XSCRIPT_NORMAL : MU_XSCRIPT_SECURE);
+  
   tokp = imap4d_tokbuf_init ();
   while (1)
     {
@@ -429,7 +433,7 @@ imap4d_mainloop (int fd, FILE *infile, FILE *outfile)
       imap4d_sync ();
       util_do_command (tokp);
       imap4d_sync ();
-      util_flush_output ();
+      io_flush ();
     }
 
   return 0;
@@ -507,7 +511,7 @@ main (int argc, char **argv)
   mu_acl_cfg_init ();
   mu_m_server_cfg_init ();
   
-  mu_argp_init (program_version, NULL);
+  mu_argp_init (NULL, NULL);
 
   mu_m_server_create (&server, program_version);
   mu_m_server_set_conn (server, imap4d_connection);
diff --git a/imap4d/imap4d.h b/imap4d/imap4d.h
index 1d9378d..7618107 100644
--- a/imap4d/imap4d.h
+++ b/imap4d/imap4d.h
@@ -154,7 +154,8 @@ struct imap4d_command
 #define ERR_TLS               6
 #define ERR_MAILBOX_CORRUPTED 7
 #define ERR_TERMINATE         8
-  
+#define ERR_STREAM_CREATE     9
+
 /* Namespace numbers */
 #define NS_PRIVATE 0
 #define NS_OTHER   1
@@ -202,20 +203,39 @@ extern int imap4d_transcript;
 extern mu_list_t imap4d_id_list;
 extern int imap4d_argc;                 
 extern char **imap4d_argv;
-  
+
 #ifndef HAVE_STRTOK_R
 extern char *strtok_r (char *s, const char *delim, char **save_ptr);
 #endif
 
 /* Input functions */
+extern mu_stream_t iostream;
+extern int  io_untagged_response (int, const char *, ...) MU_PRINTFLIKE(2,3);
+extern int  io_sendf (const char *, ...) MU_PRINTFLIKE(1,2);
+extern int  io_send_bytes (const char *buf, size_t size);
+extern int  io_send_qstring (const char *);
+extern int  io_send_literal (const char *);
+extern int  io_copy_out (mu_stream_t str, size_t size);
+extern int  io_completion_response (struct imap4d_command *, int,
+                                    const char *, ...) MU_PRINTFLIKE(3,4);
+extern int io_stream_completion_response (mu_stream_t str,
+                                         struct imap4d_command *command,
+                                         int rc, 
+                                         const char *format, ...)
+                                    MU_PRINTFLIKE(4,5);
+int io_getline (char **pbuf, size_t *psize, size_t *pnbytes);
+void io_setio (FILE*, FILE*);
+void io_flush (void);
+int io_wait_input (int);
+  
 imap4d_tokbuf_t imap4d_tokbuf_init (void);
 void imap4d_tokbuf_destroy (imap4d_tokbuf_t *tok);
 int imap4d_tokbuf_argc (imap4d_tokbuf_t tok);
 char *imap4d_tokbuf_getarg (imap4d_tokbuf_t tok, int n);
 void imap4d_readline (imap4d_tokbuf_t tok);
-struct imap4d_tokbuf *imap4d_tokbuf_from_string (char *str);
-int imap4d_getline (char **pbuf, size_t *psize, size_t *pnbytes);
+imap4d_tokbuf_t imap4d_tokbuf_from_string (char *str);
 
+  
 #define IMAP4_ARG_TAG     0
 #define IMAP4_ARG_COMMAND 1
 #define IMAP4_ARG_1       2
@@ -322,21 +342,16 @@ extern char *namespace_checkfullpath (const char *name, 
const char *pattern,
                                       const char *delim, int *pns);
 int imap4d_session_setup (char *username);
 int imap4d_session_setup0 (void);
+void imap4d_child_signal_setup (RETSIGTYPE (*handler) (int signo));
   
 /* Capability functions */
 extern void imap4d_capability_add (const char *str);
 extern void imap4d_capability_remove (const char *str);
 extern void imap4d_capability_init (void);
-  
+
 /* Helper functions.  */
-extern int  util_out (int, const char *, ...) MU_PRINTFLIKE(2,3);
-extern int  util_send (const char *, ...) MU_PRINTFLIKE(1,2);
-extern int  util_send_bytes (const char *buf, size_t size);
-extern int  util_send_qstring (const char *);
-extern int  util_send_literal (const char *);
+
 extern int  util_start (char *);
-extern int  util_finish (struct imap4d_command *, int, const char *, ...) 
-                         MU_PRINTFLIKE(3,4);
 extern int  util_getstate (void);
 extern int  util_do_command (imap4d_tokbuf_t);
 extern char *util_tilde_expansion (const char *, const char *);
@@ -358,18 +373,6 @@ int util_type_to_attribute (int type, char **attr_str);
 int util_attribute_matches_flag (mu_attribute_t attr, const char *item);
 int util_uidvalidity (mu_mailbox_t smbox, unsigned long *uidvp);
 
-void util_setio (FILE*, FILE*);
-void util_flush_output (void);
-void util_get_input (mu_stream_t *pstr);
-void util_get_output (mu_stream_t *pstr);
-void util_set_input (mu_stream_t str);
-void util_set_output (mu_stream_t str);
-int util_wait_input (int);
-  
-void util_register_event (int old_state, int new_state,
-                         mu_list_action_t *action, void *data);
-void util_event_remove (void *id);
-void util_run_events (int old_state, int new_state);
   
 int util_is_master (void);
 void util_bye (void);  
@@ -378,13 +381,33 @@ void util_chdir (const char *homedir);
 int is_atom (const char *s);
 int util_isdelim (const char *str);
 int util_trim_nl (char *s, size_t len);
-  
+
+int set_xscript_level (int xlev);
+
 #ifdef WITH_TLS
 int imap4d_init_tls_server (void);
 #endif /* WITH_TLS */
 
-typedef int (*imap4d_auth_handler_fp) (struct imap4d_command *,
-                                      char *, char **);
+struct imap4d_auth
+{
+  /* input */
+  struct imap4d_command *command;
+  char *auth_type;
+  /* output */
+  char *username;
+  int response;
+};
+
+enum imap4d_auth_result
+  {
+    imap4d_auth_nosup,
+    imap4d_auth_ok,
+    imap4d_auth_resp,
+    imap4d_auth_fail
+  };
+  
+typedef enum imap4d_auth_result
+          (*imap4d_auth_handler_fp) (struct imap4d_auth *);
   
 extern void auth_add (char *name, imap4d_auth_handler_fp handler);
 extern void auth_remove (char *name);
diff --git a/imap4d/io.c b/imap4d/io.c
new file mode 100644
index 0000000..726cfaa
--- /dev/null
+++ b/imap4d/io.c
@@ -0,0 +1,622 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 1999, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+   2009, 2010 Free Software Foundation, Inc.
+
+   GNU Mailutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GNU Mailutils is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GNU Mailutils; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+   MA 02110-1301 USA */
+
+#include "imap4d.h"
+
+mu_stream_t iostream;
+
+void
+io_setio (FILE *in, FILE *out)
+{
+  mu_stream_t str, istream, ostream;
+  
+  if (!in)
+    imap4d_bye (ERR_NO_IFILE);
+  if (!out)
+    imap4d_bye (ERR_NO_OFILE);
+
+  if (mu_stdio_stream_create (&istream, fileno (in), 
+                              MU_STREAM_READ | MU_STREAM_AUTOCLOSE))
+    imap4d_bye (ERR_STREAM_CREATE);
+  mu_stream_set_buffer (istream, mu_buffer_line, 1024);
+  
+  if (mu_stdio_stream_create (&ostream, fileno (out), 
+                              MU_STREAM_WRITE | MU_STREAM_AUTOCLOSE))
+    imap4d_bye (ERR_STREAM_CREATE);
+
+  /* Combine the two streams into an I/O one. */
+  if (mu_iostream_create (&str, istream, ostream))
+    imap4d_bye (ERR_STREAM_CREATE);
+
+  /* Convert all writes to CRLF form.
+     There is no need to convert reads, as the code ignores extra \r anyway.
+  */
+  if (mu_filter_create (&iostream, str, "CRLF", MU_FILTER_ENCODE,
+                       MU_STREAM_WRITE | MU_STREAM_RDTHRU))
+    imap4d_bye (ERR_STREAM_CREATE);
+  /* Change buffering scheme: filter streams are fully buffered by default. */
+  mu_stream_set_buffer (iostream, mu_buffer_line, 1024);
+  
+  if (imap4d_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, 0);
+      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
+           {
+             mu_stream_unref (iostream);
+             iostream = xstr;
+           }
+       }
+    }
+}
+
+#ifdef WITH_TLS
+int
+imap4d_init_tls_server ()
+{
+  mu_stream_t tlsstream, stream[2];
+  int rc;
+
+  stream[0] = stream[1] = NULL;
+  rc = mu_stream_ioctl (iostream, MU_IOCTL_SWAP_STREAM, stream);
+  if (rc)
+    {
+      mu_error (_("%s failed: %s"), "MU_IOCTL_SWAP_STREAM",
+               mu_stream_strerror (iostream, rc));
+      return 1;
+    }
+  
+  rc = mu_tls_server_stream_create (&tlsstream, stream[0], stream[1], 0);
+  if (rc)
+    return 1;
+
+  rc = mu_stream_open (tlsstream);
+  if (rc)
+    {
+      mu_diag_output (MU_DIAG_ERROR, _("cannot open TLS stream: %s"),
+                     mu_stream_strerror (tlsstream, rc));
+      mu_stream_destroy (&tlsstream);
+      return 1;
+    }
+  else
+    stream[0] = stream[1] = tlsstream;
+
+  rc = mu_stream_ioctl (iostream, MU_IOCTL_SWAP_STREAM, stream);
+  if (rc)
+    {
+      mu_error (_("%s failed: %s"), "MU_IOCTL_SWAP_STREAM",
+               mu_stream_strerror (iostream, rc));
+      imap4d_bye (ERR_STREAM_CREATE);
+    }
+  return 0;
+}
+#endif
+
+
+/* Status Code to String.  */
+static const char *
+sc2string (int rc)
+{
+  switch (rc)
+    {
+    case RESP_OK:
+      return "OK ";
+
+    case RESP_BAD:
+      return "BAD ";
+
+    case RESP_NO:
+      return "NO ";
+
+    case RESP_BYE:
+      return "BYE ";
+
+    case RESP_PREAUTH:
+      return "PREAUTH ";
+    }
+  return "";
+}
+
+/* FIXME: Check return values from the output functions */
+
+int
+io_copy_out (mu_stream_t str, size_t size)
+{
+  return mu_stream_copy (iostream, str, size, NULL);
+}
+
+int
+io_send_bytes (const char *buf, size_t size)
+{
+  return mu_stream_write (iostream, buf, size, NULL);
+}
+
+int
+io_sendf (const char *format, ...)
+{
+  int status;
+  va_list ap;
+
+  va_start (ap, format);
+  status = mu_stream_vprintf (iostream, format, ap);
+  va_end (ap);
+  return status;
+}
+
+/* Send NIL if empty string, change the quoted string to a literal if the
+   string contains: double quotes, CR, LF, and '/'.  CR, LF will be change
+   to spaces.  */
+int
+io_send_qstring (const char *buffer)
+{
+  if (buffer == NULL || *buffer == '\0')
+    return io_sendf ("NIL");
+  if (strchr (buffer, '"') || strchr (buffer, '\r') || strchr (buffer, '\n')
+      || strchr (buffer, '\\'))
+    {
+      char *s;
+      int ret;
+      char *b = strdup (buffer);
+      while ((s = strchr (b, '\n')) || (s = strchr (b, '\r')))
+       *s = ' ';
+      ret = io_send_literal (b);
+      free (b);
+      return ret;
+    }
+  return io_sendf ("\"%s\"", buffer);
+}
+
+int
+io_send_literal (const char *buffer)
+{
+  return io_sendf ("{%lu}\n%s", (unsigned long) strlen (buffer), buffer);
+}
+
+/* Send an untagged response.  */
+int
+io_untagged_response (int rc, const char *format, ...)
+{
+  int status;
+  va_list ap;
+
+  mu_stream_printf (iostream, "* %s", sc2string (rc));
+  va_start (ap, format);
+  status = mu_stream_vprintf (iostream, format, ap);
+  va_end (ap);
+  mu_stream_write (iostream, "\n", 1, NULL);
+  return status;
+}
+
+/* Send the completion response and reset the state.  */
+int
+io_format_completion_response (mu_stream_t str,
+                              struct imap4d_command *command, int rc, 
+                              const char *format, va_list ap)
+{
+  int new_state;
+  int status = 0;
+  const char *sc = sc2string (rc);
+
+  mu_stream_printf (str, "%s %s%s ",
+                   command->tag, sc, command->name);
+  mu_stream_vprintf (str, format, ap);
+  mu_stream_write (str, "\n", 1, NULL);
+
+  /* Reset the state.  */
+  if (rc == RESP_OK)
+    new_state = command->success;
+  else if (command->failure <= state)
+    new_state = command->failure;
+  else
+    new_state = STATE_NONE;
+
+  if (new_state != STATE_NONE)
+    {
+      if (new_state == STATE_AUTH)
+       set_xscript_level (MU_XSCRIPT_NORMAL);
+      state = new_state;
+    }
+  
+  return status;
+}
+
+int
+io_completion_response (struct imap4d_command *command, int rc, 
+                        const char *format, ...)
+{
+  va_list ap;
+  int status;
+
+  va_start (ap, format);
+  status = io_format_completion_response (iostream, command, rc, format, ap);
+  va_end (ap);
+  return status;
+}
+
+int
+io_stream_completion_response (mu_stream_t str,
+                              struct imap4d_command *command, int rc, 
+                              const char *format, ...)
+{
+  va_list ap;
+  int status;
+  
+  va_start (ap, format);
+  status = io_format_completion_response (str, command, rc, format, ap);
+  va_end (ap);
+  return status;
+}
+
+/* Wait TIMEOUT seconds for data on the input stream.
+   Returns 0   if no data available
+           1   if some data is available
+          -1  an error occurred */
+int
+io_wait_input (int timeout)
+{
+  int wflags = MU_STREAM_READY_RD;
+  struct timeval tv;
+  int status;
+  
+  tv.tv_sec = timeout;
+  tv.tv_usec = 0;
+  status = mu_stream_wait (iostream, &wflags, &tv);
+  if (status)
+    {
+      mu_diag_output (MU_DIAG_ERROR, _("cannot poll input stream: %s"),
+                     mu_strerror(status));
+      return -1;
+    }
+  return wflags & MU_STREAM_READY_RD;
+}
+
+void
+io_flush ()
+{
+  mu_stream_flush (iostream);
+}
+
+int
+util_is_master ()
+{
+  return iostream == NULL;
+}
+
+int
+io_getline (char **pbuf, size_t *psize, size_t *pnbytes)
+{
+  size_t len;
+  int rc = mu_stream_getline (iostream, pbuf, psize, &len);
+  if (rc == 0)
+    {
+      char *s = *pbuf;
+
+      if (len == 0)
+        {
+          imap4d_bye (ERR_NO_IFILE);
+          /*FIXME rc = ECONNABORTED;*/
+        }
+      len = mu_rtrim_cset (s, "\r\n");
+      if (pnbytes)
+       *pnbytes = len;
+    }
+  return rc;
+}
+
+
+static size_t
+unquote (char *line, size_t len)
+{
+  char *prev = NULL;
+  size_t rlen = len;
+  char *p;
+  int off = 0;
+  while ((p = memchr (line + off, '\\', len - off)))
+    {
+      if (p[1] == '\\' || p[1] == '"')
+       {
+         if (prev)
+           {
+             memmove (prev, line, p - line);
+             prev += p - line;
+           }
+         else
+           prev = p;
+         off = p[1] == '\\';
+         rlen--;
+         len -= p - line + 1;
+         line = p + 1;
+       }
+    }
+  if (prev)
+    memmove (prev, line, len);
+  return rlen;
+}
+
+struct imap4d_tokbuf
+{
+  char *buffer;
+  size_t size;
+  size_t level;
+  int argc;
+  int argmax;
+  size_t *argp;
+};
+
+struct imap4d_tokbuf *
+imap4d_tokbuf_init ()
+{
+  struct imap4d_tokbuf *tok = malloc (sizeof (tok[0]));
+  if (!tok)
+    imap4d_bye (ERR_NO_MEM);
+  memset (tok, 0, sizeof (*tok));
+  return tok;
+}
+
+void
+imap4d_tokbuf_destroy (struct imap4d_tokbuf **ptok)
+{
+  struct imap4d_tokbuf *tok = *ptok;
+  free (tok->buffer);
+  free (tok->argp);
+  free (tok);
+  *ptok = NULL;
+}
+
+int
+imap4d_tokbuf_argc (struct imap4d_tokbuf *tok)
+{
+  return tok->argc;
+}
+
+char *
+imap4d_tokbuf_getarg (struct imap4d_tokbuf *tok, int n)
+{
+  if (n < tok->argc)
+    return tok->buffer + tok->argp[n];
+  return NULL;
+}
+
+static void
+imap4d_tokbuf_unquote (struct imap4d_tokbuf *tok, size_t *poff, size_t *plen)
+{
+  char *buf = tok->buffer + *poff;
+  if (buf[0] == '"' && buf[*plen - 1] == '"')
+    {
+      ++*poff;
+      *plen = unquote (buf + 1, *plen - 1);
+    }
+}
+
+static void
+imap4d_tokbuf_expand (struct imap4d_tokbuf *tok, size_t size)
+{
+  if (tok->size - tok->level < size)          
+    {                                          
+      tok->size = tok->level + size;
+      tok->buffer = realloc (tok->buffer, tok->size);
+      if (!tok->buffer)                                
+       imap4d_bye (ERR_NO_MEM);
+    }
+}
+
+#define ISDELIM(c) (strchr ("()", (c)) != NULL)
+
+static size_t
+insert_nul (struct imap4d_tokbuf *tok, size_t off)
+{
+  imap4d_tokbuf_expand (tok, 1);
+  if (off < tok->level)
+    {
+      memmove (tok->buffer + off + 1, tok->buffer + off, tok->level - off);
+      tok->level++;
+    }
+  tok->buffer[off] = 0;
+  return off + 1;
+}
+
+static size_t
+gettok (struct imap4d_tokbuf *tok, size_t off)
+{
+  char *buf = tok->buffer;
+  
+  while (off < tok->level && mu_isblank (buf[off]))
+    off++;
+
+  if (tok->argc == tok->argmax)
+    {
+      if (tok->argmax == 0)
+       tok->argmax = 16;
+      else
+       tok->argmax *= 2;
+      tok->argp = realloc (tok->argp, tok->argmax * sizeof (tok->argp[0]));
+      if (!tok->argp)
+       imap4d_bye (ERR_NO_MEM);
+    }
+  
+  if (buf[off] == '"')
+    {
+      char *start = buf + off + 1;
+      char *p = NULL;
+      
+      while (*start && (p = strchr (start, '"')))
+       {
+         if (p == start || p[-1] != '\\')
+           break;
+         start = p + 1;
+       }
+
+      if (p)
+       {
+         size_t len;
+         off++;
+         len  = unquote (buf + off, p - (buf + off));
+         buf[off + len] = 0;
+         tok->argp[tok->argc++] = off;
+         return p - buf + 1;
+       }
+    }
+
+  tok->argp[tok->argc++] = off;
+  if (ISDELIM (buf[off]))
+    return insert_nul (tok, off + 1);
+
+  while (off < tok->level && !mu_isblank (buf[off]))
+    {
+      if (ISDELIM (buf[off]))
+       return insert_nul (tok, off);
+      off++;
+    }
+  buf[off++] = 0;
+  
+  return off;
+}
+
+static void
+imap4d_tokbuf_tokenize (struct imap4d_tokbuf *tok, size_t off)
+{
+  while (off < tok->level)
+    off = gettok (tok, off);
+}
+
+static void
+check_input_err (int rc, size_t sz)
+{
+  if (rc)
+    {
+      const char *p = mu_stream_strerror (iostream, rc);
+      if (!p)
+       p = mu_strerror (rc);
+      
+      mu_diag_output (MU_DIAG_INFO,
+                     _("error reading from input file: %s"), p);
+      imap4d_bye (ERR_NO_IFILE);
+    }
+  else if (sz == 0)
+    {
+      mu_diag_output (MU_DIAG_INFO, _("unexpected eof on input"));
+      imap4d_bye (ERR_NO_IFILE);
+    }
+}
+
+static size_t
+imap4d_tokbuf_getline (struct imap4d_tokbuf *tok)
+{
+  char buffer[512];
+  size_t level = tok->level;
+  
+  do
+    {
+      size_t len;
+      int rc;
+      
+      rc = mu_stream_readline (iostream, buffer, sizeof (buffer), &len);
+      check_input_err (rc, len);
+      imap4d_tokbuf_expand (tok, len);
+      
+      memcpy (tok->buffer + tok->level, buffer, len);
+      tok->level += len;
+    }
+  while (tok->level && tok->buffer[tok->level - 1] != '\n');
+  tok->buffer[--tok->level] = 0;
+  if (tok->buffer[tok->level - 1] == '\r')
+    tok->buffer[--tok->level] = 0;
+  return level;
+}
+
+void
+imap4d_readline (struct imap4d_tokbuf *tok)
+{
+  tok->argc = 0;
+  tok->level = 0;
+  for (;;)
+    {
+      char *last_arg;
+      size_t off = imap4d_tokbuf_getline (tok);
+      imap4d_tokbuf_tokenize (tok, off);
+      if (tok->argc == 0)
+        break;  
+      last_arg = tok->buffer + tok->argp[tok->argc - 1];
+      if (last_arg[0] == '{' && last_arg[strlen(last_arg)-1] == '}')
+       {
+         int rc;
+         unsigned long number;
+         char *sp = NULL;
+         char *buf;
+         size_t len;
+         int xlev = set_xscript_level (MU_XSCRIPT_PAYLOAD);
+         
+         number = strtoul (last_arg + 1, &sp, 10);
+         /* Client can ask for non-synchronised literal,
+            if a '+' is appended to the octet count. */
+         if (*sp == '}')
+           io_sendf ("+ GO AHEAD\n");
+         else if (*sp != '+')
+           break;
+         imap4d_tokbuf_expand (tok, number + 1);
+         off = tok->level;
+         buf = tok->buffer + off;
+          len = 0;
+          while (len < number)
+            {
+               size_t sz;
+              rc = mu_stream_read (iostream, buf + len, number - len, &sz);
+               if (rc || sz == 0)
+                 break;
+               len += sz;
+            }
+         check_input_err (rc, len);
+         imap4d_tokbuf_unquote (tok, &off, &len);
+         tok->level += len;
+         tok->buffer[tok->level++] = 0;
+         tok->argp[tok->argc - 1] = off;
+         set_xscript_level (xlev);
+       }
+      else
+       break;
+    }
+}  
+
+struct imap4d_tokbuf *
+imap4d_tokbuf_from_string (char *str)
+{
+  struct imap4d_tokbuf *tok = imap4d_tokbuf_init ();
+  tok->buffer = strdup (str);
+  if (!tok->buffer)
+    imap4d_bye (ERR_NO_MEM);
+  tok->level = strlen (str);
+  tok->size = tok->level + 1;
+  imap4d_tokbuf_tokenize (tok, 0);
+  return tok;
+}
+
diff --git a/imap4d/list.c b/imap4d/list.c
index 7ee42be..8f1dc6d 100644
--- a/imap4d/list.c
+++ b/imap4d/list.c
@@ -51,16 +51,16 @@ list_fun (mu_folder_t folder, struct mu_list_response 
*resp, void *data)
       && memcmp (name + refinfo->homelen + 1, "INBOX", 5) == 0)
     return 0;
      
-  util_send ("* %s", "LIST (");
+  io_sendf ("* %s", "LIST (");
   if ((resp->type & (MU_FOLDER_ATTRIBUTE_FILE|MU_FOLDER_ATTRIBUTE_DIRECTORY))
        == (MU_FOLDER_ATTRIBUTE_FILE|MU_FOLDER_ATTRIBUTE_DIRECTORY))
     /* nothing */;
   else if (resp->type & MU_FOLDER_ATTRIBUTE_FILE)
-    util_send ("\\NoInferiors");
+    io_sendf ("\\NoInferiors");
   else if (resp->type & MU_FOLDER_ATTRIBUTE_DIRECTORY)
-    util_send ("\\NoSelect");
+    io_sendf ("\\NoSelect");
   
-  util_send (") \"%c\" ", resp->separator);
+  io_sendf (") \"%c\" ", resp->separator);
 
   name = resp->name + refinfo->pfxlen;
   size = strlen (name) + refinfo->reflen + 1;
@@ -97,11 +97,11 @@ list_fun (mu_folder_t folder, struct mu_list_response 
*resp, void *data)
   name = refinfo->buf;
   
   if (strpbrk (name, "\"{}"))
-    util_send ("{%lu}\r\n%s\r\n", (unsigned long) strlen (name), name);
+    io_sendf ("{%lu}\n%s\n", (unsigned long) strlen (name), name);
   else if (is_atom (name))
-    util_send ("%s\r\n", name);
+    io_sendf ("%s\n", name);
   else
-    util_send ("\"%s\"\r\n", name);
+    io_sendf ("\"%s\"\n", name);
   return 0;
 }
 
@@ -146,7 +146,7 @@ imap4d_list (struct imap4d_command *command, 
imap4d_tokbuf_t tok)
   const char *delim = "/";
 
   if (imap4d_tokbuf_argc (tok) != 4)
-    return util_finish (command, RESP_BAD, "Invalid arguments");
+    return io_completion_response (command, RESP_BAD, "Invalid arguments");
   
   ref = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1);
   wcard = imap4d_tokbuf_getarg (tok, IMAP4_ARG_2);
@@ -155,14 +155,15 @@ imap4d_list (struct imap4d_command *command, 
imap4d_tokbuf_t tok)
      return the hierarchy.  */
   if (*wcard == '\0')
     {
-      util_out (RESP_NONE, "LIST (\\NoSelect) \"%s\" \"%s\"", delim,
-               (*ref) ? delim : "");
+      io_untagged_response (RESP_NONE,
+                               "LIST (\\NoSelect) \"%s\" \"%s\"", delim,
+                              (*ref) ? delim : "");
     }
   /* There is only one mailbox in the "INBOX" hierarchy ... INBOX.  */
   else if (mu_c_strcasecmp (ref, "INBOX") == 0
           || (ref[0] == 0 && mu_c_strcasecmp (wcard, "INBOX") == 0))
     {
-      util_out (RESP_NONE, "LIST (\\NoInferiors) NIL INBOX");
+      io_untagged_response (RESP_NONE, "LIST (\\NoInferiors) NIL INBOX");
     }
   else
     {
@@ -233,16 +234,16 @@ imap4d_list (struct imap4d_command *command, 
imap4d_tokbuf_t tok)
       if (!cwd)
        {
          free (ref);
-         return util_finish (command, RESP_NO,
-                             "The requested item could not be found.");
+         return io_completion_response (command, RESP_NO,
+                                     "The requested item could not be found.");
        }
       status = mu_folder_create (&folder, cwd);
       if (status)
        {
          free (ref);
          free (cwd);
-         return util_finish (command, RESP_NO,
-                             "The requested item could not be found.");
+         return io_completion_response (command, RESP_NO,
+                                     "The requested item could not be found.");
        }
       mu_folder_set_match (folder, imap4d_match);
 
@@ -263,7 +264,7 @@ imap4d_list (struct imap4d_command *command, 
imap4d_tokbuf_t tok)
 
       if (!*ref && (imap4d_match ("INBOX", wcard, 0) == 0
                    || imap4d_match ("inbox", wcard, 0) == 0))
-       util_out (RESP_NONE, "LIST (\\NoInferiors) NIL INBOX");
+       io_untagged_response (RESP_NONE, "LIST (\\NoInferiors) NIL INBOX");
 
       mu_folder_enumerate (folder, NULL, wcard, 0, 0, NULL,
                           list_fun, &refinfo);
@@ -273,6 +274,6 @@ imap4d_list (struct imap4d_command *command, 
imap4d_tokbuf_t tok)
       free (ref);
     }
 
-  return util_finish (command, RESP_OK, "Completed");
+  return io_completion_response (command, RESP_OK, "Completed");
 }
 
diff --git a/imap4d/login.c b/imap4d/login.c
index 5a313d7..e14649c 100644
--- a/imap4d/login.c
+++ b/imap4d/login.c
@@ -38,10 +38,10 @@ imap4d_login (struct imap4d_command *command, 
imap4d_tokbuf_t tok)
   int rc;
 
   if (login_disabled || tls_required)    
-    return util_finish (command, RESP_NO, "Command disabled");
+    return io_completion_response (command, RESP_NO, "Command disabled");
 
   if (imap4d_tokbuf_argc (tok) != 4)
-    return util_finish (command, RESP_BAD, "Invalid arguments");
+    return io_completion_response (command, RESP_BAD, "Invalid arguments");
   
   username = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1);
   pass = imap4d_tokbuf_getarg (tok, IMAP4_ARG_2);
@@ -51,7 +51,8 @@ imap4d_login (struct imap4d_command *command, imap4d_tokbuf_t 
tok)
   if (auth_data == NULL)
     {
       mu_diag_output (MU_DIAG_INFO, _("user `%s' nonexistent"), username);
-      return util_finish (command, RESP_NO, "User name or passwd rejected");
+      return io_completion_response (command, RESP_NO, 
+                                     "User name or passwd rejected");
     }
 
   rc = mu_authenticate (auth_data, pass);
@@ -59,11 +60,13 @@ imap4d_login (struct imap4d_command *command, 
imap4d_tokbuf_t tok)
   if (rc)
     {
       mu_diag_output (MU_DIAG_INFO, _("login failed: %s"), username);
-      return util_finish (command, RESP_NO, "User name or passwd rejected");
+      return io_completion_response (command, RESP_NO, 
+                                     "User name or passwd rejected");
     }
 
   if (imap4d_session_setup0 ())
-    return util_finish (command, RESP_NO, "User name or passwd rejected");
-  return util_finish (command, RESP_OK, "Completed");
+    return io_completion_response (command, RESP_NO, 
+                                   "User name or passwd rejected");
+  return io_completion_response (command, RESP_OK, "Completed");
 }
 
diff --git a/imap4d/logout.c b/imap4d/logout.c
index d6ca0e0..4ce2d52 100644
--- a/imap4d/logout.c
+++ b/imap4d/logout.c
@@ -34,7 +34,7 @@ int
 imap4d_logout (struct imap4d_command *command, imap4d_tokbuf_t tok)
 {
   if (imap4d_tokbuf_argc (tok) != 2)
-    return util_finish (command, RESP_BAD, "Invalid arguments");
+    return io_completion_response (command, RESP_BAD, "Invalid arguments");
   imap4d_bye0 (OK, command);
   return 0;
 }
diff --git a/imap4d/lsub.c b/imap4d/lsub.c
index 5b748ae..6ae650e 100644
--- a/imap4d/lsub.c
+++ b/imap4d/lsub.c
@@ -42,20 +42,20 @@ imap4d_lsub (struct imap4d_command *command, 
imap4d_tokbuf_t tok)
   FILE *fp;
   
   if (imap4d_tokbuf_argc (tok) != 4)
-    return util_finish (command, RESP_BAD, "Invalid arguments");
+    return io_completion_response (command, RESP_BAD, "Invalid arguments");
   
   ref = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1);
   wcard = imap4d_tokbuf_getarg (tok, IMAP4_ARG_2);
 
   asprintf (&pattern, "%s%s", ref, wcard);
   if (!pattern)
-    return util_finish (command, RESP_NO, "Not enough memory");
+    return io_completion_response (command, RESP_NO, "Not enough memory");
   
   asprintf (&file, "%s/.mailboxlist", real_homedir);
   if (!file)
     {
       free (pattern);
-      return util_finish (command, RESP_NO, "Not enough memory");
+      return io_completion_response (command, RESP_NO, "Not enough memory");
     }
   
   fp = fopen (file, "r");
@@ -71,13 +71,14 @@ imap4d_lsub (struct imap4d_command *command, 
imap4d_tokbuf_t tok)
          if (buf[len - 1] == '\n')
            buf[len - 1] = '\0';
          if (util_wcard_match (buf, pattern, delim) == 0)
-           util_out (RESP_NONE, "LIST () \"%s\" %s", delim, buf);
+           io_untagged_response (RESP_NONE, "LIST () \"%s\" %s", 
+                                    delim, buf);
        }
       fclose (fp);
       free (buf);
-      return util_finish (command, RESP_OK, "Completed");
+      return io_completion_response (command, RESP_OK, "Completed");
     }
   else if (errno == ENOENT)
-    return util_finish (command, RESP_OK, "Completed");
-  return util_finish (command, RESP_NO, "Cannot list subscriber");
+    return io_completion_response (command, RESP_OK, "Completed");
+  return io_completion_response (command, RESP_NO, "Cannot list subscriber");
 }
diff --git a/imap4d/namespace.c b/imap4d/namespace.c
index abe21cd..335a909 100644
--- a/imap4d/namespace.c
+++ b/imap4d/namespace.c
@@ -42,8 +42,8 @@ print_namespace_fun (void *item, void *data)
   const char *dir = printable_pathname (item);
   char *suf = (dir[0] && dir[strlen (dir) - 1] != '/') ? "/" : "";
   if ((*pcount)++)
-    util_send (" ");
-  util_send ("(\"%s%s\" \"/\")", dir, suf);
+    io_sendf (" ");
+  io_sendf ("(\"%s%s\" \"/\")", dir, suf);
   return 0;
 }
 
@@ -52,14 +52,14 @@ print_namespace (int nsid)
 {
   mu_list_t list = namespace[nsid];
   if (!list)
-    util_send ("NIL");
+    io_sendf ("NIL");
   else
     {
       int count;
       count = 0;
-      util_send ("(");
+      io_sendf ("(");
       mu_list_do (list, print_namespace_fun, &count);
-      util_send (")");
+      io_sendf (")");
     }
 }
 
@@ -117,18 +117,18 @@ int
 imap4d_namespace (struct imap4d_command *command, imap4d_tokbuf_t tok)
 {
   if (imap4d_tokbuf_argc (tok) != 2)
-    return util_finish (command, RESP_BAD, "Invalid arguments");
+    return io_completion_response (command, RESP_BAD, "Invalid arguments");
 
-  util_send ("* NAMESPACE ");
+  io_sendf ("* NAMESPACE ");
 
   print_namespace (NS_PRIVATE);
-  util_send (" ");
+  io_sendf (" ");
   print_namespace (NS_OTHER);
-  util_send (" ");
+  io_sendf (" ");
   print_namespace (NS_SHARED);
-  util_send ("\r\n");
+  io_sendf ("\n");
 
-  return util_finish (command, RESP_OK, "Completed");
+  return io_completion_response (command, RESP_OK, "Completed");
 }
 
 
diff --git a/imap4d/noop.c b/imap4d/noop.c
index d09d50a..cfbafd5 100644
--- a/imap4d/noop.c
+++ b/imap4d/noop.c
@@ -23,7 +23,7 @@ int
 imap4d_noop (struct imap4d_command *command, imap4d_tokbuf_t tok)
 {
   if (imap4d_tokbuf_argc (tok) != 2)
-    return util_finish (command, RESP_BAD, "Invalid arguments");
+    return io_completion_response (command, RESP_BAD, "Invalid arguments");
   imap4d_sync ();
-  return util_finish (command, RESP_OK, "Completed");
+  return io_completion_response (command, RESP_OK, "Completed");
 }
diff --git a/imap4d/preauth.c b/imap4d/preauth.c
index 203cb29..4c505b3 100644
--- a/imap4d/preauth.c
+++ b/imap4d/preauth.c
@@ -210,13 +210,13 @@ decode64_buf (const char *name, unsigned char **pbuf, 
size_t *psize)
   
   name++;
   namelen = strlen (name) - 1;
-  mu_memory_stream_create (&str, NULL, MU_STREAM_NO_CHECK);
+  mu_memory_stream_create (&str, 0);
   mu_filter_create (&flt, str, "base64", MU_FILTER_DECODE,
-                   MU_STREAM_READ | MU_STREAM_NO_CHECK);
+                   MU_STREAM_READ | MU_STREAM_AUTOCLOSE);
   mu_stream_open (str);
-  mu_stream_sequential_write (str, name, namelen);
-  mu_stream_read (flt, (char*) buf, sizeof buf, 0, &size);
-  mu_stream_destroy (&flt, NULL);
+  mu_stream_write (str, name, namelen, NULL);
+  mu_stream_read (flt, buf, sizeof buf, &size);
+  mu_stream_destroy (&flt);
   *pbuf = malloc (size);
   if (!*pbuf)
     return 1;
@@ -349,8 +349,7 @@ do_preauth_ident (struct sockaddr *clt_sa, struct sockaddr 
*srv_sa)
   
   memcpy (hostaddr, p, 15);
   hostaddr[15] = 0;
-  rc = mu_tcp_stream_create (&stream, hostaddr, ident_port, 
-                            MU_STREAM_RDWR | MU_STREAM_NO_CHECK);
+  rc = mu_tcp_stream_create (&stream, hostaddr, ident_port, MU_STREAM_RDWR);
   if (rc)
     {
       mu_diag_output (MU_DIAG_INFO, _("cannot create TCP stream: %s"),
@@ -366,14 +365,14 @@ do_preauth_ident (struct sockaddr *clt_sa, struct 
sockaddr *srv_sa)
       return NULL;
     }
 
-  mu_stream_sequential_printf (stream, "%u , %u\r\n",
-                              ntohs (clt_addr->sin_port),
-                              ntohs (srv_addr->sin_port));
+  mu_stream_printf (stream, "%u , %u\n",
+                   ntohs (clt_addr->sin_port),
+                   ntohs (srv_addr->sin_port));
   mu_stream_shutdown (stream, MU_STREAM_WRITE);
 
-  rc = mu_stream_sequential_getline (stream, &buf, &size, NULL);
+  rc = mu_stream_getline (stream, &buf, &size, NULL);
   mu_stream_close (stream);
-  mu_stream_destroy (&stream, NULL);
+  mu_stream_destroy (&stream);
   if (rc)
     {
       mu_diag_output (MU_DIAG_INFO, _("cannot read answer from %s:%d: %s"),
diff --git a/imap4d/rename.c b/imap4d/rename.c
index 97cfa41..a7a65cb 100644
--- a/imap4d/rename.c
+++ b/imap4d/rename.c
@@ -48,18 +48,18 @@ imap4d_rename (struct imap4d_command *command, 
imap4d_tokbuf_t tok)
   int ns;
   
   if (imap4d_tokbuf_argc (tok) != 4)
-    return util_finish (command, RESP_BAD, "Invalid arguments");
+    return io_completion_response (command, RESP_BAD, "Invalid arguments");
   
   oldname = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1);
   newname = imap4d_tokbuf_getarg (tok, IMAP4_ARG_2);
 
   if (mu_c_strcasecmp (newname, "INBOX") == 0)
-    return util_finish (command, RESP_NO, "Name Inbox is reservered");
+    return io_completion_response (command, RESP_NO, "Name Inbox is 
reservered");
 
   /* Allocates memory.  */
   newname = namespace_getfullpath (newname, delim, &ns);
   if (!newname)
-    return util_finish (command, RESP_NO, "Permission denied");
+    return io_completion_response (command, RESP_NO, "Permission denied");
 
   /* It is an error to attempt to rename from a mailbox name that already
      exist.  */
@@ -68,7 +68,8 @@ imap4d_rename (struct imap4d_command *command, 
imap4d_tokbuf_t tok)
       if (!S_ISDIR(newst.st_mode))
        {
          free (newname);
-         return util_finish (command, RESP_NO, "Already exist, delete first");
+         return io_completion_response (command, RESP_NO,
+                                        "Already exist, delete first");
        }
     }
 
@@ -83,7 +84,8 @@ imap4d_rename (struct imap4d_command *command, 
imap4d_tokbuf_t tok)
       if (S_ISDIR (newst.st_mode))
        {
          free (newname);
-         return util_finish (command, RESP_NO, "Cannot be a directory");
+         return io_completion_response (command, RESP_NO, 
+                                        "Cannot be a directory");
        }
       if (mu_mailbox_create (&newmbox, newname) != 0
          || mu_mailbox_open (newmbox,
@@ -91,7 +93,8 @@ imap4d_rename (struct imap4d_command *command, 
imap4d_tokbuf_t tok)
                                | mailbox_mode[ns]) != 0)
        {
          free (newname);
-         return util_finish (command, RESP_NO, "Cannot create new mailbox");
+         return io_completion_response (command, RESP_NO,
+                                        "Cannot create new mailbox");
        }
       free (newname);
 
@@ -118,7 +121,7 @@ imap4d_rename (struct imap4d_command *command, 
imap4d_tokbuf_t tok)
        }
       mu_mailbox_close (newmbox);
       mu_mailbox_destroy (&newmbox);
-      return util_finish (command, RESP_OK, "Already exist");
+      return io_completion_response (command, RESP_OK, "Already exist");
     }
 
   oldname = namespace_getfullpath (oldname, delim, NULL);
@@ -135,5 +138,5 @@ imap4d_rename (struct imap4d_command *command, 
imap4d_tokbuf_t tok)
   if (oldname)
     free (oldname);
   free (newname);
-  return util_finish (command, rc, msg);
+  return io_completion_response (command, rc, msg);
 }
diff --git a/imap4d/search.c b/imap4d/search.c
index a753cb7..9e4a904 100644
--- a/imap4d/search.c
+++ b/imap4d/search.c
@@ -269,7 +269,7 @@ imap4d_search (struct imap4d_command *command, 
imap4d_tokbuf_t tok)
   char *err_text= "";
   
   rc = imap4d_search0 (tok, 0, &err_text);
-  return util_finish (command, rc, "%s", err_text);
+  return io_completion_response (command, rc, "%s", err_text);
 }
   
 int
@@ -347,7 +347,7 @@ do_search (struct parsebuf *pb)
   
   mu_mailbox_messages_count (mbox, &count);
 
-  util_send ("* SEARCH");
+  io_sendf ("* SEARCH");
   for (pb->msgno = 1; pb->msgno <= count; pb->msgno++)
     {
       if (mu_mailbox_get_message (mbox, pb->msgno, &pb->msg) == 0
@@ -357,13 +357,13 @@ do_search (struct parsebuf *pb)
            {
              size_t uid;
              mu_message_get_uid (pb->msg, &uid);
-             util_send (" %s", mu_umaxtostr (0, uid));
+             io_sendf (" %s", mu_umaxtostr (0, uid));
            }
          else
-           util_send (" %s", mu_umaxtostr (0, pb->msgno));
+           io_sendf (" %s", mu_umaxtostr (0, pb->msgno));
        }
     }
-  util_send ("\r\n");
+  io_sendf ("\n");
 }
 
 /* Parse buffer functions */
@@ -837,22 +837,21 @@ _scan_body (struct parsebuf *pb, char *text)
   size_t size = 0, lines = 0;
   char buffer[128];
   size_t n = 0;
-  off_t offset = 0;
   int rc;
   
   mu_message_get_body (pb->msg, &body);
   mu_body_size (body, &size);
   mu_body_lines (body, &lines);
-  mu_body_get_stream (body, &stream);
+  mu_body_get_streamref (body, &stream);
   rc = 0;
   while (rc == 0
-        && mu_stream_read (stream, buffer, sizeof(buffer)-1, offset, &n) == 0
+        && mu_stream_read (stream, buffer, sizeof(buffer)-1, &n) == 0
         && n > 0)
     {
       buffer[n] = 0;
-      offset += n;
       rc = util_strcasestr (buffer, text) != NULL;
     }
+  mu_stream_destroy (&stream);
   return rc;
 }
 
diff --git a/imap4d/select.c b/imap4d/select.c
index dcf3fe0..2897870 100644
--- a/imap4d/select.c
+++ b/imap4d/select.c
@@ -27,7 +27,7 @@ int
 imap4d_select (struct imap4d_command *command, imap4d_tokbuf_t tok)
 {
   if (imap4d_tokbuf_argc (tok) != 3)
-    return util_finish (command, RESP_BAD, "Invalid arguments");
+    return io_completion_response (command, RESP_BAD, "Invalid arguments");
   return imap4d_select0 (command, imap4d_tokbuf_getarg (tok, IMAP4_ARG_1),
                         MU_STREAM_RDWR);
 }
@@ -60,7 +60,7 @@ imap4d_select0 (struct imap4d_command *command, const char 
*mboxname,
   mailbox_name = namespace_getfullpath (mboxname, "/", NULL);
 
   if (!mailbox_name)
-    return util_finish (command, RESP_NO, "Couldn't open mailbox");
+    return io_completion_response (command, RESP_NO, "Couldn't open mailbox");
 
   if ((status = mu_mailbox_create_default (&mbox, mailbox_name)) == 0
       && (status = mu_mailbox_open (mbox, flags)) == 0)
@@ -74,14 +74,14 @@ imap4d_select0 (struct imap4d_command *command, const char 
*mboxname,
        {
          free (mailbox_name);
          /* Need to set the state explicitely for select.  */
-         return util_send ("%s OK [%s] %s Completed\r\n", command->tag,
-                           (flags & MU_STREAM_READ)  ?
-                           "READ-ONLY" : "READ-WRITE", command->name);
+         return io_sendf ("%s OK [%s] %s Completed\n", command->tag,
+                          ((flags & MU_STREAM_RDWR) == MU_STREAM_RDWR) ?
+                          "READ-WRITE" : "READ-ONLY", command->name);
        }
     }
   
   mu_mailbox_destroy (&mbox);
-  status = util_finish (command, RESP_NO, "Could not open %s: %s",
+  status = io_completion_response (command, RESP_NO, "Could not open %s: %s",
                        mboxname, mu_strerror (status));
   free (mailbox_name);
   return status;
@@ -109,20 +109,22 @@ imap4d_select_status ()
 
   /* This outputs EXISTS and RECENT responses */
   imap4d_sync();
-  util_out (RESP_OK, "[UIDVALIDITY %lu] UID valididy status", uidvalidity);
-  util_out (RESP_OK, "[UIDNEXT %lu] Predicted next uid",
-           (unsigned long) uidnext);
+  io_untagged_response (RESP_OK, "[UIDVALIDITY %lu] UID valididy status", 
+                           uidvalidity);
+  io_untagged_response (RESP_OK, "[UIDNEXT %lu] Predicted next uid",
+                          (unsigned long) uidnext);
   if (unseen)
-    util_out (RESP_OK, "[UNSEEN %lu] first unseen messsage ",
-             (unsigned long) unseen);
-  util_out (RESP_NONE, "FLAGS (%s)", mflags);
+    io_untagged_response (RESP_OK, "[UNSEEN %lu] first unseen messsage ",
+                            (unsigned long) unseen);
+  io_untagged_response (RESP_NONE, "FLAGS (%s)", mflags);
   /* FIXME:
      - '\*' can be supported if we use the attribute_set userflag()
      - Answered is still not set in the mailbox code.  */
-  if (select_flags & MU_STREAM_READ)
-    util_out (RESP_OK, "[PERMANENTFLAGS ()] No Permanent flags");
+  if (!(select_flags & MU_STREAM_WRITE))
+    io_untagged_response (RESP_OK, "[PERMANENTFLAGS ()] No Permanent flags");
   else
-    util_out (RESP_OK, "[PERMANENTFLAGS (%s)] Permanent flags", pflags);
+    io_untagged_response (RESP_OK, "[PERMANENTFLAGS (%s)] Permanent flags",
+                          pflags);
 
   return 0;
 }
diff --git a/imap4d/starttls.c b/imap4d/starttls.c
index fbb1e4d..f71d135 100644
--- a/imap4d/starttls.c
+++ b/imap4d/starttls.c
@@ -40,16 +40,16 @@ imap4d_starttls (struct imap4d_command *command, 
imap4d_tokbuf_t tok)
   int status;
 
   if (!tls_available || tls_done)
-    return util_finish (command, RESP_BAD, "Invalid command");
+    return io_completion_response (command, RESP_BAD, "Invalid command");
 
   if (imap4d_tokbuf_argc (tok) != 2)
-    return util_finish (command, RESP_BAD, "Invalid arguments");
+    return io_completion_response (command, RESP_BAD, "Invalid arguments");
 
   util_atexit (mu_deinit_tls_libs);
 
-  status = util_finish (command, RESP_OK, "Begin TLS negotiation");
-  util_flush_output ();
-  tls_done = imap4d_init_tls_server ();
+  status = io_completion_response (command, RESP_OK, "Begin TLS negotiation");
+  io_flush ();
+  tls_done = imap4d_init_tls_server () == 0;
 
   if (tls_done)
     {
diff --git a/imap4d/status.c b/imap4d/status.c
index 3933a79..a462829 100644
--- a/imap4d/status.c
+++ b/imap4d/status.c
@@ -79,14 +79,14 @@ imap4d_status (struct imap4d_command *command, 
imap4d_tokbuf_t tok)
   int argc = imap4d_tokbuf_argc (tok);
 
   if (argc < 4)
-    return util_finish (command, RESP_BAD, "Invalid arguments");
+    return io_completion_response (command, RESP_BAD, "Invalid arguments");
   
   name = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1);
 
   mailbox_name = namespace_getfullpath (name, delim, NULL);
 
   if (!mailbox_name)
-    return util_finish (command, RESP_NO, "Error opening mailbox");
+    return io_completion_response (command, RESP_NO, "Error opening mailbox");
 
   /* We may be opening the current mailbox, so make sure the attributes are
      preserved */
@@ -105,7 +105,8 @@ imap4d_status (struct imap4d_command *command, 
imap4d_tokbuf_t tok)
          if (item[0] == '(')
            {
              if (imap4d_tokbuf_getarg (tok, argc - 1)[0] != ')')
-               return util_finish (command, RESP_BAD, "Invalid arguments");
+               return io_completion_response (command, RESP_BAD, 
+                                              "Invalid arguments");
              argc--;
              i++;
            }
@@ -123,11 +124,11 @@ imap4d_status (struct imap4d_command *command, 
imap4d_tokbuf_t tok)
                }
                  
              if (count++ == 0)
-               util_send ("* STATUS %s (", name);
+               io_sendf ("* STATUS %s (", name);
              else if (!space_sent)
                 {
                   space_sent = 1;
-                 util_send (" ");
+                 io_sendf (" ");
                 }     
 
              if (!fun (smbox))
@@ -136,7 +137,7 @@ imap4d_status (struct imap4d_command *command, 
imap4d_tokbuf_t tok)
 
          
          if (count > 0)
-           util_send (")\r\n");
+           io_sendf (")\n");
          mu_mailbox_close (smbox);
        }
       mu_mailbox_destroy (&smbox);
@@ -146,13 +147,14 @@ imap4d_status (struct imap4d_command *command, 
imap4d_tokbuf_t tok)
   if (status == 0)
     {
       if (count == 0)
-       return util_finish (command, RESP_BAD, "Too few args (empty list)");
+       return io_completion_response (command, RESP_BAD, 
+                                      "Too few args (empty list)");
       else if (err_msg)
-       return util_finish (command, RESP_BAD, err_msg);
-      return util_finish (command, RESP_OK, "Completed");
+       return io_completion_response (command, RESP_BAD, err_msg);
+      return io_completion_response (command, RESP_OK, "Completed");
     }
   
-  return util_finish (command, RESP_NO, "Error opening mailbox");
+  return io_completion_response (command, RESP_NO, "Error opening mailbox");
 }
 
 static int
@@ -160,7 +162,7 @@ status_messages (mu_mailbox_t smbox)
 {
   size_t total = 0;
   mu_mailbox_messages_count (smbox, &total);
-  util_send ("MESSAGES %lu", (unsigned long) total);
+  io_sendf ("MESSAGES %lu", (unsigned long) total);
   return 0;
 }
 
@@ -169,7 +171,7 @@ status_recent (mu_mailbox_t smbox)
 {
   size_t recent = 0;
   mu_mailbox_messages_recent (smbox, &recent);
-  util_send ("RECENT %lu", (unsigned long) recent);
+  io_sendf ("RECENT %lu", (unsigned long) recent);
   return 0;
 }
 
@@ -178,7 +180,7 @@ status_uidnext (mu_mailbox_t smbox)
 {
   size_t uidnext = 1;
   mu_mailbox_uidnext (smbox, &uidnext);
-  util_send ("UIDNEXT %lu", (unsigned long) uidnext);
+  io_sendf ("UIDNEXT %lu", (unsigned long) uidnext);
   return 0;
 }
 
@@ -187,7 +189,7 @@ status_uidvalidity (mu_mailbox_t smbox)
 {
   unsigned long uidvalidity = 0;
   util_uidvalidity (smbox, &uidvalidity);
-  util_send ("UIDVALIDITY %lu", uidvalidity);
+  io_sendf ("UIDVALIDITY %lu", uidvalidity);
   return 0;
 }
 
@@ -214,6 +216,6 @@ status_unseen (mu_mailbox_t smbox)
       if (!mu_attribute_is_read (attr))
        unseen++;
     }
-  util_send ("UNSEEN %lu", (unsigned long) unseen);
+  io_sendf ("UNSEEN %lu", (unsigned long) unseen);
   return 0;
 }
diff --git a/imap4d/store.c b/imap4d/store.c
index ac06bdc..e8d592d 100644
--- a/imap4d/store.c
+++ b/imap4d/store.c
@@ -151,13 +151,13 @@ imap4d_store0 (imap4d_tokbuf_t tok, int isuid, char 
**ptext)
          
          if (pclos.ack)
            {
-             util_send ("* %lu FETCH (", (unsigned long) msgno);
+             io_sendf ("* %lu FETCH (", (unsigned long) msgno);
              
              if (isuid)
-               util_send ("UID %lu ", (unsigned long) msgno);
-             util_send ("FLAGS (");
+               io_sendf ("UID %lu ", (unsigned long) msgno);
+             io_sendf ("FLAGS (");
              util_print_flags (attr);
-             util_send ("))\r\n");
+             io_sendf ("))\n");
            }
          /* Update the flags of uid table.  */
          imap4d_sync_flags (pclos.set[i]);
@@ -178,6 +178,6 @@ imap4d_store (struct imap4d_command *command, 
imap4d_tokbuf_t tok)
   char *err_text;
   
   rc = imap4d_store0 (tok, 0, &err_text);
-  return util_finish (command, rc, "%s", err_text);
+  return io_completion_response (command, rc, "%s", err_text);
 }
 
diff --git a/imap4d/subscribe.c b/imap4d/subscribe.c
index b604d04..e694636 100644
--- a/imap4d/subscribe.c
+++ b/imap4d/subscribe.c
@@ -38,7 +38,7 @@ imap4d_subscribe (struct imap4d_command *command, 
imap4d_tokbuf_t tok)
   FILE *fp;
 
   if (imap4d_tokbuf_argc (tok) != 3)
-    return util_finish (command, RESP_BAD, "Invalid arguments");
+    return io_completion_response (command, RESP_BAD, "Invalid arguments");
 
   name = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1);
 
@@ -50,7 +50,7 @@ imap4d_subscribe (struct imap4d_command *command, 
imap4d_tokbuf_t tok)
       fputs (name, fp);
       fputs ("\n", fp);
       fclose (fp);
-      return util_finish (command, RESP_OK, "Completed");
+      return io_completion_response (command, RESP_OK, "Completed");
     }
-  return util_finish (command, RESP_NO, "Cannot subscribe");
+  return io_completion_response (command, RESP_NO, "Cannot subscribe");
 }
diff --git a/imap4d/sync.c b/imap4d/sync.c
index 3877a93..c4a5268 100644
--- a/imap4d/sync.c
+++ b/imap4d/sync.c
@@ -102,8 +102,8 @@ notify_flag (size_t msgno, mu_attribute_t oattr)
            add_flag (&abuf, "\\Recent");
          }
       if (*abuf)
-       util_out (RESP_NONE, "%lu FETCH FLAGS (%s)",
-                 (unsigned long) msgno, abuf);
+       io_untagged_response (RESP_NONE, "%lu FETCH FLAGS (%s)",
+                                (unsigned long) msgno, abuf);
       free (abuf);
     }
 }
@@ -125,8 +125,8 @@ notify_deleted (void)
        {
          if (!(uid_table[i].notify))
            {
-             util_out (RESP_NONE, "%lu EXPUNGED",
-                       (unsigned long) uid_table[i].msgno-decr);
+             io_untagged_response (RESP_NONE, "%lu EXPUNGED",
+                                      (unsigned long) uid_table[i].msgno-decr);
              uid_table[i].notify = 1;
              decr++;
            }
@@ -240,8 +240,8 @@ notify (void)
       mu_mailbox_messages_recent (mbox, &recent);
     }
 
-  util_out (RESP_NONE, "%lu EXISTS", (unsigned long) total);
-  util_out (RESP_NONE, "%lu RECENT", (unsigned long) recent);
+  io_untagged_response (RESP_NONE, "%lu EXISTS", (unsigned long) total);
+  io_untagged_response (RESP_NONE, "%lu RECENT", (unsigned long) recent);
 
   if (!reset)
     reset_uids ();
@@ -331,8 +331,8 @@ imap4d_sync (void)
          imap4d_set_observer (mbox);
          free_uids ();
          mailbox_corrupt = 0;
-         util_out (RESP_NONE,
-                   "OK [ALERT] Mailbox modified by another program");
+         io_untagged_response (RESP_NONE,
+                            "OK [ALERT] Mailbox modified by another program");
        }
       notify ();
     }
diff --git a/imap4d/uid.c b/imap4d/uid.c
index 6c9e132..e4e5859 100644
--- a/imap4d/uid.c
+++ b/imap4d/uid.c
@@ -32,12 +32,16 @@ imap4d_uid (struct imap4d_command *command, imap4d_tokbuf_t 
tok)
   char *err_text = "Completed";
 
   if (imap4d_tokbuf_argc (tok) < 3)
-    return util_finish (command, RESP_BAD, "Invalid arguments");
+    return io_completion_response (command, RESP_BAD, "Invalid arguments");
 
   cmd = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1);
   
   if (mu_c_strcasecmp (cmd, "FETCH") == 0)
-    rc = imap4d_fetch0 (tok, 1, &err_text);
+    {
+      int xlev = set_xscript_level (MU_XSCRIPT_PAYLOAD);
+      rc = imap4d_fetch0 (tok, 1, &err_text);
+      set_xscript_level (xlev);
+    }
   else if (mu_c_strcasecmp (cmd, "COPY") == 0)
     rc = imap4d_copy0 (tok, 1, &err_text);
   else if (mu_c_strcasecmp (cmd, "STORE") == 0)
@@ -49,5 +53,5 @@ imap4d_uid (struct imap4d_command *command, imap4d_tokbuf_t 
tok)
       err_text = "Uknown uid command";
       rc = RESP_BAD;
     }
-  return util_finish (command, rc, "%s %s", cmd, err_text);
+  return io_completion_response (command, rc, "%s %s", cmd, err_text);
 }
diff --git a/imap4d/unsubscribe.c b/imap4d/unsubscribe.c
index 3ef2ac2..9132095 100644
--- a/imap4d/unsubscribe.c
+++ b/imap4d/unsubscribe.c
@@ -97,7 +97,7 @@ imap4d_unsubscribe (struct imap4d_command *command, 
imap4d_tokbuf_t tok)
   int rc;
   
   if (imap4d_tokbuf_argc (tok) != 3)
-    return util_finish (command, RESP_BAD, "Invalid arguments");
+    return io_completion_response (command, RESP_BAD, "Invalid arguments");
 
   name = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1);
 
@@ -128,7 +128,7 @@ imap4d_unsubscribe (struct imap4d_command *command, 
imap4d_tokbuf_t tok)
 
   free (file);
   if (rc)
-    return util_finish (command, RESP_NO, "Cannot unsubscribe");
+    return io_completion_response (command, RESP_NO, "Cannot unsubscribe");
 
-  return util_finish (command, RESP_OK, "Completed");
+  return io_completion_response (command, RESP_OK, "Completed");
 }
diff --git a/imap4d/util.c b/imap4d/util.c
index d697a33..73d4031 100644
--- a/imap4d/util.c
+++ b/imap4d/util.c
@@ -19,11 +19,7 @@
 
 #include "imap4d.h"
 
-static mu_stream_t istream;
-static mu_stream_t ostream;
-
 static int add2set (size_t **, int *, unsigned long);
-static const char *sc2string (int);
 
 /* NOTE: Allocates Memory.  */
 /* Expand: ~ --> /home/user and to ~guest --> /home/guest.  */
@@ -270,149 +266,6 @@ util_msgset (char *s, size_t ** set, int *n, int isuid)
 }
 
 int
-util_send_bytes (const char *buf, size_t size)
-{
-  return mu_stream_sequential_write (ostream, buf, size);
-}
-
-int
-util_send (const char *format, ...)
-{
-  char *buf = NULL;
-  int status = 0;
-  va_list ap;
-
-  va_start (ap, format);
-  vasprintf (&buf, format, ap);
-  va_end (ap);
-  if (!buf)
-      imap4d_bye (ERR_NO_MEM);
-
-#if 0
-  if (imap4d_transcript)
-    mu_diag_output (MU_DIAG_DEBUG, "sent: %s", buf);
-#endif
-
-  status = mu_stream_sequential_write (ostream, buf, strlen (buf));
-  free (buf);
-
-  return status;
-}
-
-/* Send NIL if empty string, change the quoted string to a literal if the
-   string contains: double quotes, CR, LF, and '/'.  CR, LF will be change
-   to spaces.  */
-int
-util_send_qstring (const char *buffer)
-{
-  if (buffer == NULL || *buffer == '\0')
-    return util_send ("NIL");
-  if (strchr (buffer, '"') || strchr (buffer, '\r') || strchr (buffer, '\n')
-      || strchr (buffer, '\\'))
-    {
-      char *s;
-      int ret;
-      char *b = strdup (buffer);
-      while ((s = strchr (b, '\n')) || (s = strchr (b, '\r')))
-       *s = ' ';
-      ret = util_send_literal (b);
-      free (b);
-      return ret;
-    }
-  return util_send ("\"%s\"", buffer);
-}
-
-int
-util_send_literal (const char *buffer)
-{
-  return util_send ("{%lu}\r\n%s", (unsigned long) strlen (buffer), buffer);
-}
-
-/* Send an unsolicited response.  */
-int
-util_out (int rc, const char *format, ...)
-{
-  char *tempbuf = NULL;
-  char *buf = NULL;
-  int status = 0;
-  va_list ap;
-
-  asprintf (&tempbuf, "* %s%s\r\n", sc2string (rc), format);
-  va_start (ap, format);
-  vasprintf (&buf, tempbuf, ap);
-  va_end (ap);
-  if (!buf)
-    imap4d_bye (ERR_NO_MEM);
-
-  if (imap4d_transcript)
-    {
-      int len = strcspn (buf, "\r\n");
-      mu_diag_output (MU_DIAG_DEBUG, "sent: %*.*s", len, len, buf);
-    }
-
-  status = mu_stream_sequential_write (ostream, buf, strlen (buf));
-  free (buf);
-  free (tempbuf);
-  return status;
-}
-
-/* Send the tag response and reset the state.  */
-int
-util_finish (struct imap4d_command *command, int rc, const char *format, ...)
-{
-  size_t size;
-  char *buf = NULL;
-  char *tempbuf = NULL;
-  int new_state;
-  int status = 0;
-  va_list ap;
-  const char *sc = sc2string (rc);
-  
-  va_start (ap, format);
-  vasprintf (&tempbuf, format, ap);
-  va_end (ap);
-  if (!tempbuf)
-    imap4d_bye (ERR_NO_MEM);
-  
-  size = strlen (command->tag) + 1 +
-         strlen (sc) + strlen (command->name) + 1 +
-         strlen (tempbuf) + 1;
-  buf = malloc (size);
-  if (!buf)
-    imap4d_bye (ERR_NO_MEM);
-  strcpy (buf, command->tag);
-  strcat (buf, " ");
-  strcat (buf, sc);
-  strcat (buf, command->name);
-  strcat (buf, " ");
-  strcat (buf, tempbuf);
-  free (tempbuf);
-
-  if (imap4d_transcript)
-    mu_diag_output (MU_DIAG_DEBUG, "sent: %s", buf);
-
-  mu_stream_sequential_write (ostream, buf, strlen (buf));
-  free (buf);
-  mu_stream_sequential_write (ostream, "\r\n", 2);
-
-  /* Reset the state.  */
-  if (rc == RESP_OK)
-    new_state = command->success;
-  else if (command->failure <= state)
-    new_state = command->failure;
-  else
-    new_state = STATE_NONE;
-
-  if (new_state != STATE_NONE)
-    {
-      util_run_events (state, new_state);
-      state = new_state;
-    }
-  
-  return status;
-}
-
-int
 util_do_command (imap4d_tokbuf_t tok)
 {
   char *tag, *cmd;
@@ -424,13 +277,13 @@ util_do_command (imap4d_tokbuf_t tok)
     {
       nullcommand.name = "";
       nullcommand.tag = (char *) "*";
-      return util_finish (&nullcommand, RESP_BAD, "Null command");
+      return io_completion_response (&nullcommand, RESP_BAD, "Null command");
     }
   else if (argc == 1)
     {
       nullcommand.name = "";
       nullcommand.tag = imap4d_tokbuf_getarg (tok, 0);
-      return util_finish (&nullcommand, RESP_BAD, "Missing command");
+      return io_completion_response (&nullcommand, RESP_BAD, "Missing 
command");
     }
 
   tag = imap4d_tokbuf_getarg (tok, 0);
@@ -441,13 +294,13 @@ util_do_command (imap4d_tokbuf_t tok)
     {
       nullcommand.name = "";
       nullcommand.tag = tag;
-      return util_finish (&nullcommand, RESP_BAD, "Invalid command");
+      return io_completion_response (&nullcommand, RESP_BAD, "Invalid 
command");
     }
 
   command->tag = tag;
 
   if (command->states && (command->states & state) == 0)
-    return util_finish (command, RESP_BAD, "Wrong state");
+    return io_completion_response (command, RESP_BAD, "Wrong state");
 
   return command->func (command, tok);
 }
@@ -466,30 +319,6 @@ util_getcommand (char *cmd, struct imap4d_command 
command_table[])
   return NULL;
 }
 
-/* Status Code to String.  */
-static const char *
-sc2string (int rc)
-{
-  switch (rc)
-    {
-    case RESP_OK:
-      return "OK ";
-
-    case RESP_BAD:
-      return "BAD ";
-
-    case RESP_NO:
-      return "NO ";
-
-    case RESP_BYE:
-      return "BYE ";
-
-    case RESP_PREAUTH:
-      return "PREAUTH ";
-    }
-  return "";
-}
-
 static int
 add2set (size_t ** set, int *n, unsigned long val)
 {
@@ -646,17 +475,17 @@ util_print_flags (mu_attribute_t attr)
     if (flags & _imap4d_attrlist[i].flag)
       {
        if (space)
-         util_send (" ");
+         io_sendf (" ");
        else
          space = 1;
-       util_send (_imap4d_attrlist[i].name);
+       io_sendf (_imap4d_attrlist[i].name);
       }
 
   if (MU_ATTRIBUTE_IS_UNSEEN (flags))
     {
       if (space)
-       util_send (" ");
-      util_send ("\\Recent");
+       io_sendf (" ");
+      io_sendf ("\\Recent");
     }
 }
 
@@ -796,106 +625,6 @@ util_uidvalidity (mu_mailbox_t smbox, unsigned long 
*uidvp)
   return mu_mailbox_uidvalidity (smbox, uidvp);
 }
 
-
-void
-util_setio (FILE *in, FILE *out)
-{
-  if (!in)
-    imap4d_bye (ERR_NO_IFILE);
-  if (!out)
-    imap4d_bye (ERR_NO_OFILE);
-
-  setvbuf (in, NULL, _IOLBF, 0);
-  setvbuf (out, NULL, _IOLBF, 0);
-  if (mu_stdio_stream_create (&istream, in, MU_STREAM_NO_CLOSE))
-    imap4d_bye (ERR_NO_IFILE);
-  if (mu_stdio_stream_create (&ostream, out, MU_STREAM_NO_CLOSE))
-    imap4d_bye (ERR_NO_OFILE);
-}
-
-void
-util_get_input (mu_stream_t *pstr)
-{
-  *pstr = istream;
-}
-
-void
-util_get_output (mu_stream_t *pstr)
-{
-  *pstr = ostream;
-}
-
-void
-util_set_input (mu_stream_t str)
-{
-  istream = str;
-}
-
-void
-util_set_output (mu_stream_t str)
-{
-  ostream = str;
-}
-
-/* Wait TIMEOUT seconds for data on the input stream.
-   Returns 0   if no data available
-           1   if some data is available
-          -1  an error occurred */
-int
-util_wait_input (int timeout)
-{
-  int wflags = MU_STREAM_READY_RD;
-  struct timeval tv;
-  int status;
-  
-  tv.tv_sec = timeout;
-  tv.tv_usec = 0;
-  status = mu_stream_wait (istream, &wflags, &tv);
-  if (status)
-    {
-      mu_diag_output (MU_DIAG_ERROR, _("cannot poll input stream: %s"),
-                     mu_strerror(status));
-      return -1;
-    }
-  return wflags & MU_STREAM_READY_RD;
-}
-
-void
-util_flush_output ()
-{
-  mu_stream_flush (ostream);
-}
-
-int
-util_is_master ()
-{
-  return ostream == NULL;
-}
-
-#ifdef WITH_TLS
-int
-imap4d_init_tls_server ()
-{
-  mu_stream_t stream;
-  int rc;
- 
-  rc = mu_tls_stream_create (&stream, istream, ostream, 0);
-  if (rc)
-    return 0;
-
-  if (mu_stream_open (stream))
-    {
-      const char *p;
-      mu_stream_strerror (stream, &p);
-      mu_diag_output (MU_DIAG_ERROR, _("cannot open TLS stream: %s"), p);
-      return 0;
-    }
-
-  istream = ostream = stream;
-  return 1;
-}
-#endif /* WITH_TLS */
-
 static mu_list_t atexit_list;
 
 void
@@ -916,87 +645,11 @@ atexit_run (void *item, void *data)
 void
 util_bye ()
 {
-  int rc = istream != ostream;
-  
-  mu_stream_close (istream);
-  mu_stream_destroy (&istream, mu_stream_get_owner (istream));
-
-  if (rc)
-    {
-      mu_stream_close (ostream);
-      mu_stream_destroy (&ostream, mu_stream_get_owner (ostream));
-    }
-      
+  mu_stream_close (iostream);
+  mu_stream_destroy (&iostream);
   mu_list_do (atexit_list, atexit_run, 0);
 }
 
-struct state_event {
-  int old_state;
-  int new_state;
-  mu_list_action_t *action;
-  void *data;
-};
-
-static mu_list_t event_list;
-
-void
-util_register_event (int old_state, int new_state,
-                    mu_list_action_t *action, void *data)
-{
-  struct state_event *evp = malloc (sizeof (*evp));
-  if (!evp)
-    imap4d_bye (ERR_NO_MEM);
-  evp->old_state = old_state;
-  evp->new_state = new_state;
-  evp->action = action;
-  evp->data = data;
-  if (!event_list)
-    {
-      mu_list_create (&event_list);
-      mu_list_set_destroy_item (event_list, mu_list_free_item);
-    }
-  mu_list_append (event_list, (void*)evp);
-}
-
-void
-util_event_remove (void *id)
-{
-  mu_list_remove (event_list, id);
-}
-
-static int
-event_exec (void *item, void *data)
-{
-  struct state_event *ev = data, *elem = item;
-
-  if (ev->old_state == elem->old_state && ev->new_state == elem->new_state)
-    return elem->action (item, elem->data);
-  return 0;
-}
-
-void
-util_run_events (int old_state, int new_state)
-{
-  if (event_list)
-    {
-      struct state_event ev;
-      mu_iterator_t itr;
-      ev.old_state = old_state;
-      ev.new_state = new_state;
-
-      mu_list_get_iterator (event_list, &itr);
-      for (mu_iterator_first (itr);
-          !mu_iterator_is_done (itr); mu_iterator_next (itr))
-       {
-         struct state_event *p;
-         mu_iterator_current (itr, (void **)&p);
-         if (event_exec (p, &ev))
-           break;
-       }
-      mu_iterator_destroy (&itr);
-    }
-}
-  
 void
 util_chdir (const char *dir)
 {
@@ -1019,378 +672,22 @@ is_atom (const char *s)
   return 1;
 }
      
-
-static size_t
-remove_cr (char *line, size_t len)
-{
-  char *prev = NULL;
-  size_t rlen = len;
-  char *p;
-  while ((p = memchr (line, '\r', len)))
-    {
-      if (prev)
-       {
-         memmove (prev, line, p - line);
-         prev += p - line;
-       }
-      else
-       prev = p;
-      rlen--;
-      len -= p - line + 1;
-      line = p + 1;
-    }
-  if (prev)
-    memmove (prev, line, len);
-  return rlen;
-}
-
-static size_t
-unquote (char *line, size_t len)
-{
-  char *prev = NULL;
-  size_t rlen = len;
-  char *p;
-  int off = 0;
-  while ((p = memchr (line + off, '\\', len - off)))
-    {
-      if (p[1] == '\\' || p[1] == '"')
-       {
-         if (prev)
-           {
-             memmove (prev, line, p - line);
-             prev += p - line;
-           }
-         else
-           prev = p;
-         off = p[1] == '\\';
-         rlen--;
-         len -= p - line + 1;
-         line = p + 1;
-       }
-    }
-  if (prev)
-    memmove (prev, line, len);
-  return rlen;
-}
-
-struct imap4d_tokbuf {
-  char *buffer;
-  size_t size;
-  size_t level;
-  int argc;
-  int argmax;
-  size_t *argp;
-};
-
-struct imap4d_tokbuf *
-imap4d_tokbuf_init ()
-{
-  struct imap4d_tokbuf *tok = malloc (sizeof (tok[0]));
-  if (!tok)
-    imap4d_bye (ERR_NO_MEM);
-  memset (tok, 0, sizeof (*tok));
-  return tok;
-}
-
-void
-imap4d_tokbuf_destroy (struct imap4d_tokbuf **ptok)
-{
-  struct imap4d_tokbuf *tok = *ptok;
-  free (tok->buffer);
-  free (tok->argp);
-  free (tok);
-  *ptok = NULL;
-}
-
-int
-imap4d_tokbuf_argc (struct imap4d_tokbuf *tok)
-{
-  return tok->argc;
-}
-
-char *
-imap4d_tokbuf_getarg (struct imap4d_tokbuf *tok, int n)
-{
-  if (n < tok->argc)
-    return tok->buffer + tok->argp[n];
-  return NULL;
-}
-
-static void
-imap4d_tokbuf_unquote (struct imap4d_tokbuf *tok, size_t *poff, size_t *plen)
-{
-  char *buf = tok->buffer + *poff;
-  if (buf[0] == '"' && buf[*plen - 1] == '"')
-    {
-      ++*poff;
-      *plen = unquote (buf + 1, *plen - 1);
-    }
-}
-
-static void
-imap4d_tokbuf_expand (struct imap4d_tokbuf *tok, size_t size)
-{
-  if (tok->size - tok->level < size)          
-    {                                          
-      tok->size = tok->level + size;
-      tok->buffer = realloc (tok->buffer, tok->size);
-      if (!tok->buffer)                                
-       imap4d_bye (ERR_NO_MEM);
-    }
-}
-
-#define ISDELIM(c) (strchr ("()", (c)) != NULL)
-
 int
-util_isdelim (const char *str)
+set_xscript_level (int xlev)
 {
-  return str[1] == 0 && ISDELIM (str[0]);
-}
-
-static size_t
-insert_nul (struct imap4d_tokbuf *tok, size_t off)
-{
-  imap4d_tokbuf_expand (tok, 1);
-  if (off < tok->level)
-    {
-      memmove (tok->buffer + off + 1, tok->buffer + off, tok->level - off);
-      tok->level++;
-    }
-  tok->buffer[off] = 0;
-  return off + 1;
-}
-
-static size_t
-gettok (struct imap4d_tokbuf *tok, size_t off)
-{
-  char *buf = tok->buffer;
-  
-  while (off < tok->level && mu_isblank (buf[off]))
-    off++;
-
-  if (tok->argc == tok->argmax)
-    {
-      if (tok->argmax == 0)
-       tok->argmax = 16;
-      else
-       tok->argmax *= 2;
-      tok->argp = realloc (tok->argp, tok->argmax * sizeof (tok->argp[0]));
-      if (!tok->argp)
-       imap4d_bye (ERR_NO_MEM);
-    }
-  
-  if (buf[off] == '"')
-    {
-      char *start = buf + off + 1;
-      char *p = NULL;
-      
-      while (*start && (p = strchr (start, '"')))
-       {
-         if (p == start || p[-1] != '\\')
-           break;
-         start = p + 1;
-       }
-
-      if (p)
-       {
-         size_t len;
-         off++;
-         len  = unquote (buf + off, p - (buf + off));
-         buf[off + len] = 0;
-         tok->argp[tok->argc++] = off;
-         return p - buf + 1;
-       }
-    }
-
-  tok->argp[tok->argc++] = off;
-  if (ISDELIM (buf[off]))
-    return insert_nul (tok, off + 1);
-
-  while (off < tok->level && !mu_isblank (buf[off]))
-    {
-      if (ISDELIM (buf[off]))
-       return insert_nul (tok, off);
-      off++;
-    }
-  buf[off++] = 0;
-  
-  return off;
-}
-
-static void
-imap4d_tokbuf_tokenize (struct imap4d_tokbuf *tok, size_t off)
-{
-  while (off < tok->level)
-    off = gettok (tok, off);
-}
-
-static void
-check_input_err (int rc, size_t sz)
-{
-  if (rc)
-    {
-      const char *p;
-      if (mu_stream_strerror (istream, &p))
-       p = mu_strerror (rc);
-      
-      mu_diag_output (MU_DIAG_INFO,
-                     _("error reading from input file: %s"), p);
-      imap4d_bye (ERR_NO_IFILE);
-    }
-  else if (sz == 0)
-    {
-      mu_diag_output (MU_DIAG_INFO, _("unexpected eof on input"));
-      imap4d_bye (ERR_NO_IFILE);
-    }
-}
-
-static size_t
-imap4d_tokbuf_getline (struct imap4d_tokbuf *tok)
-{
-  char buffer[512];
-  size_t level = tok->level;
-  
-  do
-    {
-      size_t len;
-      int rc;
-      
-      rc = mu_stream_sequential_readline (istream,
-                                         buffer, sizeof (buffer), &len);
-      check_input_err (rc, len);
-      imap4d_tokbuf_expand (tok, len);
-      
-      memcpy (tok->buffer + tok->level, buffer, len);
-      tok->level += len;
-    }
-  while (tok->level && tok->buffer[tok->level - 1] != '\n');
-  tok->buffer[--tok->level] = 0;
-  if (tok->buffer[tok->level - 1] == '\r')
-    tok->buffer[--tok->level] = 0;
-  return level;
-}
-
-void
-imap4d_readline (struct imap4d_tokbuf *tok)
-{
-  int transcript = imap4d_transcript;
-  tok->argc = 0;
-  tok->level = 0;
-  for (;;)
+  if (imap4d_transcript)
     {
-      char *last_arg;
-      size_t off = imap4d_tokbuf_getline (tok);
-      if (transcript)
-        {
-          int len;
-          char *p = mu_strcasestr (tok->buffer, "LOGIN");
-          if (p && p > tok->buffer && mu_isblank (p[-1]))
-            {
-             char *q = mu_str_skip_class (p + 5, MU_CTYPE_SPACE);
-             q = mu_str_skip_class_comp (q, MU_CTYPE_SPACE);
-              len = q - tok->buffer; 
-              mu_diag_output (MU_DIAG_DEBUG,
-                             "recv: %*.*s {censored}", len, len,
-                              tok->buffer);
-             }
-           else
-             {
-               len = strcspn (tok->buffer, "\r\n");
-               mu_diag_output (MU_DIAG_DEBUG, "recv: %*.*s", 
-                               len, len, tok->buffer);
-             }
-        }
-      imap4d_tokbuf_tokenize (tok, off);
-      if (tok->argc == 0)
-        break;  
-      last_arg = tok->buffer + tok->argp[tok->argc - 1];
-      if (last_arg[0] == '{' && last_arg[strlen(last_arg)-1] == '}')
+      if (xlev != MU_XSCRIPT_NORMAL)
        {
-         int rc;
-         unsigned long number;
-         char *sp = NULL;
-         char *buf;
-         size_t len;
+         mu_log_level_t n = xlev == MU_XSCRIPT_SECURE ?
+                             MU_DEBUG_TRACE6 : MU_DEBUG_TRACE7;
          
-          if (transcript)
-            mu_diag_output (MU_DIAG_DEBUG, "(literal follows)");
-          transcript = 0;
-         number = strtoul (last_arg + 1, &sp, 10);
-         /* Client can ask for non-synchronised literal,
-            if a '+' is appended to the octet count. */
-         if (*sp == '}')
-           util_send ("+ GO AHEAD\r\n");
-         else if (*sp != '+')
-           break;
-         imap4d_tokbuf_expand (tok, number + 1);
-         off = tok->level;
-         buf = tok->buffer + off;
-          len = 0;
-          while (len < number)
-            {
-               size_t sz;
-              rc = mu_stream_sequential_read (istream, 
-                                               buf + len, number - len, &sz);
-               if (rc || sz == 0)
-                 break;
-               len += sz;
-            }
-         check_input_err (rc, len);
-         len = remove_cr (buf, len);
-         imap4d_tokbuf_unquote (tok, &off, &len);
-         tok->level += len;
-         tok->buffer[tok->level++] = 0;
-         tok->argp[tok->argc - 1] = off;
+         if (mu_global_debug_level ("imap4") & MU_DEBUG_LEVEL_MASK (n))
+           return MU_XSCRIPT_NORMAL;
        }
-      else
-       break;
-    }
-}  
-
-struct imap4d_tokbuf *
-imap4d_tokbuf_from_string (char *str)
-{
-  struct imap4d_tokbuf *tok = imap4d_tokbuf_init ();
-  tok->buffer = strdup (str);
-  if (!tok->buffer)
-    imap4d_bye (ERR_NO_MEM);
-  tok->level = strlen (str);
-  tok->size = tok->level + 1;
-  imap4d_tokbuf_tokenize (tok, 0);
-  return tok;
-}
 
-int
-util_trim_nl (char *s, size_t len)
-{
-  if (s && len > 0 && s[len - 1] == '\n')
-    s[--len] = 0;
-  if (s && len > 0 && s[len - 1] == '\r')
-    s[--len] = 0;
-  return len;
-}
-
-int
-imap4d_getline (char **pbuf, size_t *psize, size_t *pnbytes)
-{
-  size_t len;
-  int rc = mu_stream_sequential_getline (istream, pbuf, psize, &len);
-  if (rc == 0)
-    {
-      char *s = *pbuf;
-
-      if (len == 0)
-        {
-         if (imap4d_transcript)
-            mu_diag_output (MU_DIAG_DEBUG, "got EOF");
-          imap4d_bye (ERR_NO_IFILE);
-          /*FIXME rc = ECONNABORTED;*/
-        }
-      len = util_trim_nl (s, len);
-      if (imap4d_transcript)
-       mu_diag_output (MU_DIAG_DEBUG, "recv: %s", s);
-      if (pnbytes)
-       *pnbytes = len;
+      if (mu_stream_ioctl (iostream, MU_IOCTL_LEVEL, &xlev) == 0)
+       return xlev;
     }
-  return rc;
+  return 0;
 }
diff --git a/include/mailutils/Makefile.am b/include/mailutils/Makefile.am
index d1261d2..098a9fa 100644
--- a/include/mailutils/Makefile.am
+++ b/include/mailutils/Makefile.am
@@ -98,7 +98,7 @@ pkginclude_HEADERS = \
  vartab.h\
  version.h
 
-if MU_COND_LIBMU_CPP
+if MU_COND_SUPPORT_CXX
   CPP_DIR = cpp
 endif
 
diff --git a/include/mailutils/body.h b/include/mailutils/body.h
index d6552db..d935d00 100644
--- a/include/mailutils/body.h
+++ b/include/mailutils/body.h
@@ -32,9 +32,14 @@ extern void * mu_body_get_owner   (mu_body_t);
 extern int mu_body_is_modified    (mu_body_t);
 extern int mu_body_clear_modified (mu_body_t);
 
-extern int mu_body_get_stream     (mu_body_t, mu_stream_t *);
+extern int mu_body_get_stream     (mu_body_t, mu_stream_t *)
+                                      __attribute__ ((deprecated));
+extern int mu_body_get_streamref  (mu_body_t body, mu_stream_t *pstream);
 extern int mu_body_set_stream     (mu_body_t, mu_stream_t, void *owner);
-
+extern int mu_body_set_get_stream (mu_body_t,
+                                  int (*) (mu_body_t, mu_stream_t *),
+                                  void *owner);
+  
 extern int mu_body_get_filename   (mu_body_t, char *, size_t, size_t *);
 
 extern int mu_body_size           (mu_body_t, size_t *);
diff --git a/include/mailutils/filter.h b/include/mailutils/filter.h
index 779abbd..2490f8b 100644
--- a/include/mailutils/filter.h
+++ b/include/mailutils/filter.h
@@ -26,7 +26,7 @@
 extern "C" {
 #endif
 
-/* Type.  */
+/* Mode */
 #define MU_FILTER_DECODE 0
 #define MU_FILTER_ENCODE 1
 
@@ -35,22 +35,60 @@ extern "C" {
 #define MU_FILTER_WRITE MU_STREAM_WRITE
 #define MU_FILTER_RDWR  MU_STREAM_RDWR
 
-struct _mu_filter_record
+struct mu_filter_io
 {
-  const char *name;
-  int  (*_mu_filter)     (mu_filter_t);
-  void *data;
-
-  /* Stub function return the fields.  */
-  int (*_is_filter)  (mu_filter_record_t, const char *);
-  int (*_get_filter) (mu_filter_record_t, int (*(*_mu_filter)) (mu_filter_t));
+  const char *input;
+  size_t isize;
+  char *output;
+  size_t osize;
+  int errcode;
+  int eof;
 };
 
+enum mu_filter_command
+  {
+    mu_filter_init,
+    mu_filter_done,
+    mu_filter_xcode,
+    mu_filter_lastbuf
+  };
+  
+enum mu_filter_result
+  {
+    mu_filter_ok,
+    mu_filter_falure,
+    mu_filter_moreinput,
+    mu_filter_moreoutput
+  };
+  
+typedef int (*mu_filter_new_data_t) (void **, int, void *);
+typedef enum mu_filter_result (*mu_filter_xcode_t) (void *data,
+                                                   enum mu_filter_command cmd,
+                                                   struct mu_filter_io *iobuf);
+
+int mu_filter_stream_create (mu_stream_t *pflt,
+                            mu_stream_t str,
+                            int mode, 
+                            mu_filter_xcode_t xcode,
+                            void *xdata, 
+                            int flags);
 
-extern int mu_filter_create   (mu_stream_t *, mu_stream_t, const char*, int, 
int);
+
+struct _mu_filter_record
+{
+  const char *name;
+  size_t max_line_length;
+  mu_filter_new_data_t newdata;
+  mu_filter_xcode_t encoder;
+  mu_filter_xcode_t decoder;
+};
+  
+extern int mu_filter_create (mu_stream_t *, mu_stream_t, const char*,
+                            int, int);
 extern int mu_filter_get_list (mu_list_t *);
 
 /* List of defaults.  */
+extern mu_filter_record_t mu_crlf_filter;
 extern mu_filter_record_t mu_rfc822_filter;
 extern mu_filter_record_t mu_qp_filter; /* quoted-printable.  */
 extern mu_filter_record_t mu_base64_filter;
@@ -60,16 +98,21 @@ extern mu_filter_record_t mu_bit7_filter;
 extern mu_filter_record_t mu_rfc_2047_Q_filter;
 extern mu_filter_record_t mu_rfc_2047_B_filter;
   
-enum mu_iconv_fallback_mode {
-  mu_fallback_none,
-  mu_fallback_copy_pass,
-  mu_fallback_copy_octal
-};
+enum mu_iconv_fallback_mode
+  {
+    mu_fallback_none,
+    mu_fallback_copy_pass,
+    mu_fallback_copy_octal
+  };
 
 extern int mu_filter_iconv_create (mu_stream_t *s, mu_stream_t transport,
-                               const char *fromcode, const char *tocode,
-                               int flags,
-                               enum mu_iconv_fallback_mode fallback_mode);
+                                  const char *fromcode, const char *tocode,
+                                  int flags,
+                                  enum mu_iconv_fallback_mode fallback_mode);
+
+
+extern int mu_linelen_filter_create (mu_stream_t *pstream, mu_stream_t stream,
+                                    size_t limit, int flags);
 
   
 #ifdef __cplusplus
diff --git a/include/mailutils/folder.h b/include/mailutils/folder.h
index 03390dc..279c80f 100644
--- a/include/mailutils/folder.h
+++ b/include/mailutils/folder.h
@@ -62,7 +62,10 @@ extern int  mu_folder_lsub           (mu_folder_t, const 
char *, const char *,
                                      mu_list_t *);
 
 /* Stream settings.  */
-extern int  mu_folder_get_stream     (mu_folder_t, mu_stream_t *);
+extern int  mu_folder_get_stream     (mu_folder_t, mu_stream_t *)
+                                       __attribute__ ((deprecated));
+extern int  mu_folder_get_streamref  (mu_folder_t, mu_stream_t *);
+  
 extern int  mu_folder_set_stream     (mu_folder_t, mu_stream_t);
 
   /* Match function */
diff --git a/include/mailutils/gsasl.h b/include/mailutils/gsasl.h
index 583b356..be5f2bb 100644
--- a/include/mailutils/gsasl.h
+++ b/include/mailutils/gsasl.h
@@ -36,8 +36,10 @@ extern struct mu_gsasl_module_data mu_gsasl_module_data;
 #ifdef WITH_GSASL
 #include <gsasl.h>
 
-int mu_gsasl_stream_create (mu_stream_t *stream, mu_stream_t transport,
-                           Gsasl_session *ctx, int flags);
+int gsasl_encoder_stream (mu_stream_t *pstr, mu_stream_t transport,
+                         Gsasl_session *ctx, int flags);
+int gsasl_decoder_stream (mu_stream_t *pstr, mu_stream_t transport,
+                         Gsasl_session *ctx, int flags);
 
 #endif
 
diff --git a/include/mailutils/header.h b/include/mailutils/header.h
index b994415..57a1107 100644
--- a/include/mailutils/header.h
+++ b/include/mailutils/header.h
@@ -76,9 +76,9 @@ extern "C" {
 #define MU_HEADER_REPLACE 0x01
 #define MU_HEADER_BEFORE  0x02
 
-extern int mu_header_create (mu_header_t *, const char *, size_t, void *);
-extern void mu_header_destroy (mu_header_t *, void *);
-extern void *mu_header_get_owner (mu_header_t);
+extern int mu_header_create (mu_header_t *, const char *, size_t);
+extern void mu_header_destroy (mu_header_t *);
+extern int mu_header_invalidate (mu_header_t);
 
 extern int mu_header_is_modified (mu_header_t);
 extern int mu_header_clear_modified (mu_header_t);
@@ -149,7 +149,10 @@ extern int mu_header_get_field_value_unfold (mu_header_t 
header, size_t num,
 extern int mu_header_aget_field_value_unfold (mu_header_t header, size_t num,
                                              char **pvalue);
 
-extern int mu_header_get_stream (mu_header_t, mu_stream_t *);
+extern int mu_header_get_stream (mu_header_t, mu_stream_t *)
+                                  __attribute__ ((deprecated));
+extern int mu_header_get_streamref (mu_header_t, mu_stream_t *);
+  
 /* FIXME: This function does not exist:
    extern int mu_header_set_stream (mu_header_t, mu_stream_t, void *);
 */
@@ -160,7 +163,8 @@ extern int mu_header_get_iterator (mu_header_t, 
mu_iterator_t *);
   
 
 extern int mu_header_set_fill (mu_header_t,
-      int (*_fill) (mu_header_t, char *, size_t, mu_off_t, size_t *), void 
*owner);
+                              int (*_fill) (void *data, char **, size_t *),
+                              void *data);
 
   
 #ifdef __cplusplus
diff --git a/include/mailutils/libargp.h b/include/mailutils/libargp.h
index e96df3a..c0317be 100644
--- a/include/mailutils/libargp.h
+++ b/include/mailutils/libargp.h
@@ -75,6 +75,7 @@ void mu_argp_init (const char *vers, const char *bugaddr);
 int mu_app_init (struct argp *myargp, const char **capa,
                 struct mu_cfg_param *cfg_param, 
                 int argc, char **argv, int flags, int *pindex, void *data);
+extern void mu_program_version_hook (FILE *stream, struct argp_state *state);
 
 error_t mu_argp_parse (const struct argp *myargp, 
                       int *pargc, char **pargv[],  
diff --git a/include/mailutils/mailbox.h b/include/mailutils/mailbox.h
index d3aa895..bec4498 100644
--- a/include/mailutils/mailbox.h
+++ b/include/mailutils/mailbox.h
@@ -83,7 +83,9 @@ extern int  mu_mailbox_scan            (mu_mailbox_t, size_t 
no, size_t *count);
 
 /* Mailbox Stream.  */
 extern int  mu_mailbox_set_stream      (mu_mailbox_t, mu_stream_t);
-extern int  mu_mailbox_get_stream      (mu_mailbox_t, mu_stream_t *);
+extern int  mu_mailbox_get_stream      (mu_mailbox_t, mu_stream_t *)
+                                         __attribute__ ((deprecated));
+extern int  mu_mailbox_get_streamref   (mu_mailbox_t, mu_stream_t *);
 
 /* Lock settings.  */
 extern int  mu_mailbox_get_locker      (mu_mailbox_t, mu_locker_t *);
diff --git a/include/mailutils/mailer.h b/include/mailutils/mailer.h
index 56f6615..5463d30 100644
--- a/include/mailutils/mailer.h
+++ b/include/mailutils/mailer.h
@@ -51,7 +51,9 @@ extern int mu_mailer_get_url_default       (const char** url);
 
 /* Accessor functions. */
 extern int mu_mailer_get_property   (mu_mailer_t, mu_property_t *);
-extern int mu_mailer_get_stream     (mu_mailer_t, mu_stream_t *);
+extern int mu_mailer_get_stream     (mu_mailer_t, mu_stream_t *)
+                                      __attribute__ ((deprecated));
+extern int mu_mailer_get_streamref  (mu_mailer_t, mu_stream_t *);
 extern int mu_mailer_set_stream     (mu_mailer_t, mu_stream_t);
 extern int mu_mailer_get_debug      (mu_mailer_t, mu_debug_t *);
 extern int mu_mailer_set_debug      (mu_mailer_t, mu_debug_t);
diff --git a/include/mailutils/mailutils.h b/include/mailutils/mailutils.h
index ad0f961..18aa097 100644
--- a/include/mailutils/mailutils.h
+++ b/include/mailutils/mailutils.h
@@ -12,10 +12,10 @@
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.
 
-   You should have received a copy of the GNU Lesser General
-   Public License along with this library; if not, write to the
-   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301 USA */
+   You should have received a copy of the GNU General Public License
+   along with GNU Mailutils.  If not, see <http://www.gnu.org/licenses/>. */
+
+#include <mailutils/types.h>
 
 #include <mailutils/acl.h>
 #include <mailutils/address.h>
@@ -56,7 +56,6 @@
 #include <mailutils/registrar.h>
 #include <mailutils/stream.h>
 #include <mailutils/tls.h>
-#include <mailutils/types.h>
 #include <mailutils/url.h>
 #include <mailutils/gocs.h>
 #include <mailutils/version.h>
diff --git a/include/mailutils/message.h b/include/mailutils/message.h
index 9ca5703..14df6f6 100644
--- a/include/mailutils/message.h
+++ b/include/mailutils/message.h
@@ -26,6 +26,25 @@
 extern "C" {
 #endif
 
+#define MU_SCAN_SEEK  0x01
+#define MU_SCAN_SIZE  0x02
+
+struct mu_message_scan
+{
+  int flags;
+  mu_off_t message_start;
+  mu_off_t message_size;
+
+  mu_off_t body_start;
+  mu_off_t body_end;
+  size_t header_lines;
+  size_t body_lines;
+  int attr_flags;
+  unsigned long uidvalidity;
+};
+
+int mu_stream_scan_message (mu_stream_t stream, struct mu_message_scan *sp);
+  
 /* A message is considered to be a container for:
   mu_header_t, mu_body_t, and its mu_attribute_t.  */
 
@@ -34,7 +53,7 @@ extern void mu_message_destroy (mu_message_t *, void *owner);
 
 extern int mu_message_create_copy (mu_message_t *to, mu_message_t from);
 
-extern void * mu_message_get_owner (mu_message_t);
+extern void *mu_message_get_owner (mu_message_t);
 extern int mu_message_is_modified (mu_message_t);
 extern int mu_message_clear_modified (mu_message_t);
 extern int mu_message_get_mailbox (mu_message_t, mu_mailbox_t *);
@@ -52,14 +71,21 @@ extern int mu_message_set_header (mu_message_t, 
mu_header_t, void *);
 extern int mu_message_get_body (mu_message_t, mu_body_t *);
 extern int mu_message_set_body (mu_message_t, mu_body_t, void *);
 
-extern int mu_message_get_stream (mu_message_t, mu_stream_t *);
-extern int mu_message_set_stream (mu_message_t, mu_stream_t, void *);
+extern int mu_message_get_stream (mu_message_t, mu_stream_t *)
+                                   __attribute__((deprecated));
+extern int mu_message_get_streamref (mu_message_t, mu_stream_t *);
+
+extern int mu_message_set_stream (mu_message_t, mu_stream_t, void *)
+  __attribute__((deprecated));
 
 extern int mu_message_get_attribute (mu_message_t, mu_attribute_t *);
 extern int mu_message_set_attribute (mu_message_t, mu_attribute_t, void *);
 
 extern int mu_message_get_observable (mu_message_t, mu_observable_t *);
 
+extern int mu_message_set_get_stream (mu_message_t,
+                                     int (*) (mu_message_t, mu_stream_t *),
+                                     void *);
 extern int mu_message_is_multipart (mu_message_t, int *);
 extern int mu_message_set_is_multipart (mu_message_t, 
                                        int (*_is_multipart) (mu_message_t,
diff --git a/include/mailutils/opool.h b/include/mailutils/opool.h
index 78b66a7..49b1b02 100644
--- a/include/mailutils/opool.h
+++ b/include/mailutils/opool.h
@@ -62,6 +62,10 @@ size_t mu_opool_size (mu_opool_t opool);
    mu_opool_create, above). */
 int mu_opool_coalesce (mu_opool_t opool, size_t *psize);
 
+/* Copy at most SIZE bytes of collected data into BUF.  Return the
+   actual number of bytes copied. */
+size_t mu_opool_copy (mu_opool_t opool, void *buf, size_t size);
+
 /* Return the pointer to the current object head chunk.  If mu_opool_coalesce 
    was called before, the returned value points to the entire object.
    If PSIZE is not NULL, store the size of the head chunk to *PSIZE. */     
diff --git a/include/mailutils/pop3.h b/include/mailutils/pop3.h
index d1c7db5..53d6c16 100644
--- a/include/mailutils/pop3.h
+++ b/include/mailutils/pop3.h
@@ -29,90 +29,103 @@ extern "C" {
 #endif
 
 struct _mu_pop3;
-typedef struct _mu_pop3* mu_pop3_t;
+typedef struct _mu_pop3 *mu_pop3_t;
 
 #define MU_POP3_DEFAULT_PORT 110
+#define MU_POP3_DEFAULT_SSL_PORT 995
 
-extern int  mu_pop3_create       (mu_pop3_t *pop3);
-extern void mu_pop3_destroy      (mu_pop3_t *pop3);
+int  mu_pop3_create (mu_pop3_t *pop3);
+void mu_pop3_destroy (mu_pop3_t *pop3);
 
-extern int  mu_pop3_set_carrier  (mu_pop3_t pop3, mu_stream_t carrier);
-extern int  mu_pop3_get_carrier  (mu_pop3_t pop3, mu_stream_t *pcarrier);
+int  mu_pop3_set_carrier (mu_pop3_t pop3, mu_stream_t carrier);
+int  mu_pop3_get_carrier (mu_pop3_t pop3, mu_stream_t *pcarrier);
 
-extern int  mu_pop3_connect      (mu_pop3_t pop3);
-extern int  mu_pop3_disconnect   (mu_pop3_t pop3);
+int  mu_pop3_connect (mu_pop3_t pop3);
+int  mu_pop3_disconnect (mu_pop3_t pop3);
 
-extern int  mu_pop3_set_timeout  (mu_pop3_t pop3, int timeout);
-extern int  mu_pop3_get_timeout  (mu_pop3_t pop3, int *timeout);
+int  mu_pop3_set_timeout (mu_pop3_t pop3, int timeout);
+int  mu_pop3_get_timeout (mu_pop3_t pop3, int *timeout);
 
-extern int  mu_pop3_set_debug    (mu_pop3_t pop3, mu_debug_t debug);
+#define MU_POP3_TRACE_CLR 0
+#define MU_POP3_TRACE_SET 1
+#define MU_POP3_TRACE_QRY 2
+int mu_pop3_trace (mu_pop3_t pop3, int op);
+int mu_pop3_trace_mask (mu_pop3_t pop3, int op, int lev);
 
-extern int  mu_pop3_apop         (mu_pop3_t pop3, const char *name, const char 
*digest);
+int  mu_pop3_apop (mu_pop3_t pop3, const char *name, const char *digest);
 
-extern int  mu_pop3_stls         (mu_pop3_t pop3);
+int  mu_pop3_stls (mu_pop3_t pop3);
 
-/* It is the responsability of the caller to call mu_iterator_destroy() when 
done
-   with the iterator.  The items return by the iterator are of type "const 
char *",
-   no processing is done on the item except the removal of the trailing 
newline.  */
-extern int  mu_pop3_capa         (mu_pop3_t pop3, mu_iterator_t *iterator);
+/* It is the responsability of the caller to call mu_iterator_destroy() when
+   done with the iterator.  The items returned by the iterator are of type
+   "const char *", no processing is done on the item except the removal of
+   the trailing newline.  */
+int mu_pop3_capa (mu_pop3_t pop3, int reread, mu_iterator_t *piter);
+int mu_pop3_capa_test (mu_pop3_t pop3, const char *name, const char **pret);
 
-extern int  mu_pop3_dele         (mu_pop3_t pop3, unsigned int mesgno);
+int  mu_pop3_dele (mu_pop3_t pop3, unsigned int mesgno);
 
-extern int  mu_pop3_list         (mu_pop3_t pop3, unsigned int mesgno, size_t 
*mesg_octet);
+int  mu_pop3_list (mu_pop3_t pop3, unsigned int mesgno, size_t *mesg_octet);
 
-/* An iterator is return with the multi-line answer.  It is the responsability 
of
-   the caller to call mu_iterator_destroy() to dispose of the iterator.  */
-extern int  mu_pop3_list_all     (mu_pop3_t pop3, mu_iterator_t *piterator);
+/* Send the LIST command and prepare pop3 for receiving a multiline answer.
+   The caller is expected to obtain a stream via mu_pop3_stream_create,
+   or an iterator via mu_pop3_iterator_create and read data from them.
 
-extern int  mu_pop3_noop         (mu_pop3_t pop3);
+   This function is not intended for use by a casual user, better use
+   mu_pop3_list_all or mu_pop3_list_all_stream. */
+int mu_pop3_list_cmd (mu_pop3_t pop3);
+int mu_pop3_list_all (mu_pop3_t pop3, mu_iterator_t *pitr);
+int mu_pop3_list_all_stream (mu_pop3_t pop3, mu_stream_t *pstream);
 
-extern int  mu_pop3_pass         (mu_pop3_t pop3, const char *pass);
+int  mu_pop3_noop (mu_pop3_t pop3);
 
-extern int  mu_pop3_quit         (mu_pop3_t pop3);
+int  mu_pop3_pass (mu_pop3_t pop3, const char *pass);
 
-/* A stream is return with the multi-line answer.  It is the responsability of
-   the caller to call mu_stream_destroy() to dipose of the stream.  */
-extern int  mu_pop3_retr         (mu_pop3_t pop3, unsigned int mesgno, 
mu_stream_t *pstream);
+int  mu_pop3_quit (mu_pop3_t pop3);
 
-extern int  mu_pop3_rset         (mu_pop3_t pop3);
+/* A stream is returned with the multi-line answer.  It is the responsability
+   of the caller to call mu_stream_destroy() to dipose of the stream.  */
+int  mu_pop3_retr (mu_pop3_t pop3, unsigned int mesgno,
+                  mu_stream_t *pstream);
 
-extern int  mu_pop3_stat         (mu_pop3_t pop3, unsigned int *count, size_t 
*octets);
+int  mu_pop3_rset (mu_pop3_t pop3);
 
-/* A stream is return with the multi-line answer.  It is the responsability of
-   the caller to call mu_stream_destroy() to dipose of the stream.  */
-extern int  mu_pop3_top          (mu_pop3_t pop3, unsigned int mesgno, 
unsigned int lines, mu_stream_t *pstream);
+int  mu_pop3_stat (mu_pop3_t pop3, size_t *count, mu_off_t *octets);
 
-/* The uidl is malloc and return in puidl, it is the responsability of caller
-   to free() the uild when done.  */
-extern int  mu_pop3_uidl         (mu_pop3_t pop3, unsigned int mesgno, char 
**puidl);
-/* An iterator is return with the multi-line answer.  It is the responsability 
of
-   the caller to call mu_iterator_destroy() to dispose of the iterator.  */
-extern int  mu_pop3_uidl_all     (mu_pop3_t pop3, mu_iterator_t *piterator);
+/* A stream is returned with the multi-line answer.  It is the responsability
+   of the caller to call mu_stream_destroy() to dipose of the stream.  */
+int  mu_pop3_top (mu_pop3_t pop3, unsigned int mesgno,
+                 unsigned int lines, mu_stream_t *pstream);
 
-extern int  mu_pop3_user         (mu_pop3_t pop3, const char *user);
+/* The uidl is malloc'ed and returned in puidl; it is the responsability of
+   the caller to free() the uild when done.  */
+int  mu_pop3_uidl (mu_pop3_t pop3, unsigned int mesgno, char **puidl);
 
+/* Send the UIDL command and prepare pop3 for receiving a multiline answer.
+   The caller is expected to obtain a stream via mu_pop3_stream_create,
+   or an iterator via mu_pop3_iterator_create and read data from them.
 
-/* Reads the multi-line response of the server, nread will be 0 when the 
termination octets
-   are detected.  Clients should not use this function unless they are sending 
direct command.  */
-extern int  mu_pop3_readline     (mu_pop3_t pop3, char *buffer, size_t buflen, 
size_t *nread);
+   This function is not intended for use by a casual user, better use
+   mu_pop3_uidl_all or mu_pop3_uidl_all_stream. */
+int mu_pop3_uidl_all_cmd (mu_pop3_t pop3);
+int mu_pop3_uidl_all (mu_pop3_t pop3, mu_iterator_t *piterator);
+int mu_pop3_uidl_all_stream (mu_pop3_t pop3, mu_stream_t *pstream);
 
-/* Returns the last command acknowledge.  If the server supports RESP-CODE, 
the message
-   could be retrieve, but it is up the caller to do the parsing.  */
-extern int  mu_pop3_response     (mu_pop3_t pop3, char *buffer, size_t buflen, 
size_t *nread);
+int mu_pop3_user (mu_pop3_t pop3, const char *user);
 
-/* pop3_writeline copies the line in the internal buffer, a mu_pop3_send() is
-   needed to do the actual transmission.  */
-extern int  mu_pop3_writeline    (mu_pop3_t pop3, const char *format, ...)
-                                  MU_PRINTFLIKE(2,3);
+/* Returns the last command acknowledge.  If the server supports RESP-CODE,
+   the message could be retrieved, but it is up to the caller to do the
+   parsing.  */
+int  mu_pop3_response (mu_pop3_t pop3, size_t *nread);
 
-/* mu_pop3_sendline() is equivalent to:
-       mu_pop3_writeline (pop3, line);
-       mu_pop3_send (pop3);
- */
-extern int  mu_pop3_sendline     (mu_pop3_t pop3, const char *line);
+int  mu_pop3_writeline (mu_pop3_t pop3, const char *format, ...)
+                                  MU_PRINTFLIKE(2,3);
 
-/* Transmit via the carrier the internal buffer data.  */
-extern int  mu_pop3_send         (mu_pop3_t pop3);
+int  mu_pop3_sendline (mu_pop3_t pop3, const char *line);
+int mu_pop3_getline (mu_pop3_t pop3);
+int mu_pop3_read_list (mu_pop3_t pop3, mu_list_t list);
+int mu_pop3_stream_to_list (mu_pop3_t pop3, mu_stream_t stream,
+                           mu_list_t list);
 
 #ifdef __cplusplus
 }
diff --git a/include/mailutils/stream.h b/include/mailutils/stream.h
index 9625dae..0d50602 100644
--- a/include/mailutils/stream.h
+++ b/include/mailutils/stream.h
@@ -1,206 +1,175 @@
 /* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 1999, 2000, 2001, 2005, 2007, 2010 Free Software
-   Foundation, Inc.
+   Copyright (C) 2009 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.
+   GNU Mailutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
 
-   This library is distributed in the hope that it will be useful,
+   GNU Mailutils 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.
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
 
-   You should have received a copy of the GNU Lesser General
-   Public License along with this library; if not, write to the
-   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301 USA */
+   You should have received a copy of the GNU General Public License
+   along with GNU Mailutils.  If not, see <http://www.gnu.org/licenses/>. */
 
 #ifndef _MAILUTILS_STREAM_H
-# define _MAILUTILS_STREAM_H
+#define _MAILUTILS_STREAM_H
 
-#include <stdio.h>
-#include <stdarg.h>
 #include <mailutils/types.h>
+#include <stdarg.h>
+
+enum mu_buffer_type
+  {
+    mu_buffer_none,
+    mu_buffer_line,
+    mu_buffer_full
+  };
 
-#ifdef __cplusplus
-extern "C" { /*}*/
-#endif
+
+#define MU_SEEK_SET      0
+#define MU_SEEK_CUR      1
+#define MU_SEEK_END      2
 
 #define MU_STREAM_READ       0x00000001
 #define MU_STREAM_WRITE              0x00000002
-#define MU_STREAM_RDWR        0x00000004
+#define MU_STREAM_RDWR        (MU_STREAM_READ|MU_STREAM_WRITE)
+#define MU_STREAM_SEEK        0x00000004
 #define MU_STREAM_APPEND      0x00000008
 #define MU_STREAM_CREAT              0x00000010
 #define MU_STREAM_NONBLOCK    0x00000020
-/* Stream will be destroyed on mu_stream_destroy without checking the owner. */
-#define MU_STREAM_NO_CHECK    0x00000040
-#define MU_STREAM_SEEKABLE    0x00000080
-#define MU_STREAM_NO_CLOSE    0x00000100
-#define MU_STREAM_ALLOW_LINKS 0x00000200
-#define MU_STREAM_NONLOCK     0x00000400
-/* This one affects only mailboxes */  
-#define MU_STREAM_QACCESS     0x00000800
-  
+#define MU_STREAM_AUTOCLOSE   0x00000040
+#define MU_STREAM_NONLOCK     0x00000080
+#define MU_STREAM_ALLOW_LINKS 0x00000100
+/* 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
 #define MU_STREAM_IWOTH       0x00008000
 #define MU_STREAM_IMASK       0x0000F000
-  
-/* Functions useful to users of the pre-defined stream types. */
-
-extern int mu_file_stream_create    (mu_stream_t *stream, const char* filename,
-                                    int flags);
-extern int mu_temp_file_stream_create (mu_stream_t *stream, const char *dir);
-  
-extern int mu_tcp_stream_create     (mu_stream_t *stream, const char* host,
-                                    int port, int flags);
-extern int mu_tcp_stream_create_with_source_ip (mu_stream_t *stream,
-                                               const char *host, int port,
-                                               unsigned long source_ip,
-                                               int flags);
-extern int mu_tcp_stream_create_with_source_host (mu_stream_t *stream,
-                                                 const char *host, int port,
-                                                 const char *source_host,
-                                                 int flags);
-extern int mu_socket_stream_create (mu_stream_t *stream, const char *filename,
-                                   int flags);
-  
-extern int mu_mapfile_stream_create (mu_stream_t *stream, const char* filename,
-                                    int flags);
-extern int mu_memory_stream_create  (mu_stream_t *stream, const char* filename,
-                                    int flags);
-extern int mu_encoder_stream_create (mu_stream_t *stream, mu_stream_t iostream,
-                                    const char *encoding);
-extern int mu_decoder_stream_create (mu_stream_t *stream, mu_stream_t iostream,
-                                    const char *encoding);
-extern int mu_stdio_stream_create   (mu_stream_t *stream, FILE* stdio,
-                                    int flags);
-extern int mu_prog_stream_create    (mu_stream_t *stream, const char *progname,
-                                    int flags);
-int mu_filter_prog_stream_create    (mu_stream_t *stream, const char *progname,
-                                    mu_stream_t input);
-  
-extern void mu_stream_destroy    (mu_stream_t *, void *owner);
-
-extern int mu_stream_open        (mu_stream_t);
-extern int mu_stream_close       (mu_stream_t);
-extern int mu_stream_is_seekable (mu_stream_t);
-extern int mu_stream_get_transport2 (mu_stream_t stream, mu_transport_t *pt,
-                                    mu_transport_t *pt2);
-extern int mu_stream_get_transport (mu_stream_t stream, mu_transport_t *pt);
-
-extern int mu_stream_read        (mu_stream_t, char *, size_t, mu_off_t, 
size_t *);
-extern int mu_stream_readline    (mu_stream_t, char *, size_t, mu_off_t, 
size_t *);
-extern int mu_stream_getline     (mu_stream_t is, char **pbuf, size_t 
*pbufsize,
-                                 mu_off_t offset, size_t *pnread);
-extern int mu_stream_size        (mu_stream_t, mu_off_t *);
-extern int mu_stream_truncate    (mu_stream_t, mu_off_t);
-extern int mu_stream_write       (mu_stream_t, const char *, size_t, mu_off_t,
-                                 size_t *);
-extern int mu_stream_setbufsiz   (mu_stream_t stream, size_t size);
-extern int mu_stream_flush       (mu_stream_t);
-extern int mu_stream_shutdown    (mu_stream_t stream, int how);
-
-extern int mu_stream_vprintf     (mu_stream_t os, mu_off_t *poff, 
-                                  const char *fmt, va_list ap);
-extern int mu_stream_printf      (mu_stream_t stream, mu_off_t *off, 
-                                  const char *fmt, ...) MU_PRINTFLIKE(3,4);
-extern int mu_stream_sequential_vprintf (mu_stream_t stream, const char *fmt,
-                                         va_list ap);
-extern int mu_stream_sequential_printf (mu_stream_t stream, const char *fmt,
-                                        ...) MU_PRINTFLIKE(2,3);
+
+#define MU_IOCTL_GET_TRANSPORT   1
+#define MU_IOCTL_GET_STATUS      2
+#define MU_IOCTL_GET_PID         3
+#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
+#define MU_IOCTL_SWAP_STREAM     7
+
+#define MU_IOCTL_LEVEL           8
+
+
+void mu_stream_ref (mu_stream_t stream);
+void mu_stream_unref (mu_stream_t stream);
+void mu_stream_destroy (mu_stream_t *pstream);
+int mu_stream_open (mu_stream_t stream);
+const char *mu_stream_strerror (mu_stream_t stream, int rc);
+int mu_stream_err (mu_stream_t stream);
+int mu_stream_last_error (mu_stream_t stream);
+void mu_stream_clearerr (mu_stream_t stream);
+int mu_stream_seterr (struct _mu_stream *stream, int code, int perm);
+
+int mu_stream_eof (mu_stream_t stream);
+int mu_stream_seek (mu_stream_t stream, mu_off_t offset, int whence,
+                   mu_off_t *pres);
+int mu_stream_skip_input_bytes (mu_stream_t stream, mu_off_t count,
+                               mu_off_t *pres);
+
+int mu_stream_set_buffer (mu_stream_t stream, enum mu_buffer_type type,
+                         size_t size);
+int mu_stream_read (mu_stream_t stream, void *buf, size_t size, size_t *pread);
+int mu_stream_readdelim (mu_stream_t stream, char *buf, size_t size,
+                        int delim, size_t *pread);
+int mu_stream_readline (mu_stream_t stream, char *buf, size_t size, size_t 
*pread);
+int mu_stream_getdelim (mu_stream_t stream, char **pbuf, size_t *psize,
+                       int delim, size_t *pread);
+int mu_stream_getline (mu_stream_t stream, char **pbuf, size_t *psize,
+                      size_t *pread);
+int mu_stream_write (mu_stream_t stream, const void *buf, size_t size,
+                    size_t *pwrite);
+int mu_stream_writeline (mu_stream_t stream, const char *buf, size_t size);
+int mu_stream_flush (mu_stream_t stream);
+int mu_stream_close (mu_stream_t stream);
+int mu_stream_size (mu_stream_t stream, mu_off_t *psize);
+mu_off_t mu_stream_bytes_in (mu_stream_t stream);
+mu_off_t mu_stream_bytes_out (mu_stream_t stream);
+int mu_stream_ioctl (mu_stream_t stream, int code, void *ptr);
+int mu_stream_truncate (mu_stream_t stream, mu_off_t);
+int mu_stream_shutdown (mu_stream_t stream, int how);
 
 #define MU_STREAM_READY_RD 0x1
 #define MU_STREAM_READY_WR 0x2
 #define MU_STREAM_READY_EX 0x4  
 struct timeval;  /* Needed for the following declaration */ 
 
-extern int mu_stream_wait        (mu_stream_t stream, int *pflags, struct 
timeval *);
-
-/* Functions useful to implementors of new stream types. */
-
-extern int mu_stream_create       (mu_stream_t *stream, int flags, void 
*owner);
-
-extern void* mu_stream_get_owner  (mu_stream_t);
-extern void mu_stream_set_owner   (mu_stream_t, void* owner);
-
-extern int mu_stream_get_flags    (mu_stream_t, int *pflags);
-extern int mu_stream_set_flags    (mu_stream_t, int flags);
-extern int mu_stream_clr_flags    (mu_stream_t, int flags);
-
-extern int mu_stream_get_property (mu_stream_t, mu_property_t *);
-extern int mu_stream_set_property (mu_stream_t, mu_property_t, void *);
-
-#define MU_STREAM_STATE_OPEN  1
-#define MU_STREAM_STATE_READ  2
-#define MU_STREAM_STATE_WRITE 4
-#define MU_STREAM_STATE_CLOSE 8
-extern int mu_stream_get_state    (mu_stream_t, int *pstate);
-
-extern int mu_stream_set_destroy  (mu_stream_t,
-      void (*_destroy) (mu_stream_t), void *owner);
+int mu_stream_wait   (mu_stream_t stream, int *pflags, struct timeval *);
+
+void mu_stream_get_flags (mu_stream_t stream, int *pflags);
+int mu_stream_set_flags (mu_stream_t stream, int fl);
+int mu_stream_clr_flags (mu_stream_t stream, int fl);
+
+int mu_stream_vprintf (mu_stream_t str, const char *fmt, va_list ap);
+int mu_stream_printf (mu_stream_t stream, const char *fmt, ...);
+
+int mu_stream_copy (mu_stream_t dst, mu_stream_t src, mu_off_t size,
+                   mu_off_t *pcsz);
+
+
+int mu_file_stream_create (mu_stream_t *pstream, const char *filename, int 
flags);
+int mu_temp_file_stream_create (mu_stream_t *pstream, const char *dir);
+int mu_fd_stream_create (mu_stream_t *pstream, char *filename, int fd,
+                        int flags);
+
+#define MU_STDIN_FD  0
+#define MU_STDOUT_FD 1
+#define MU_STDERR_FD 2
+int mu_stdio_stream_create (mu_stream_t *pstream, int fd, int flags);
+
+int mu_prog_stream_create (mu_stream_t *pstream, const char *progname, int 
flags);
+int mu_filter_prog_stream_create (mu_stream_t *pstream, const char *progname,
+                                 mu_stream_t input);
+int mu_memory_stream_create (mu_stream_t *pstream, int flags);
+int mu_mapfile_stream_create (mu_stream_t *pstream, const char *filename,
+                             int flags);
+int mu_socket_stream_create (mu_stream_t *pstream, const char *filename,
+                            int flags);
+
+int mu_streamref_create_abridged (mu_stream_t *pref, mu_stream_t str,
+                                 mu_off_t start, mu_off_t end);
+int mu_streamref_create (mu_stream_t *pref, mu_stream_t str);
+
+int mu_tcp_stream_create_with_source_ip (mu_stream_t *stream,
+                                        const char *host, int port,
+                                        unsigned long source_ip,
+                                        int flags);
+int mu_tcp_stream_create_with_source_host (mu_stream_t *stream,
+                                          const char *host, int port,
+                                          const char *source_host,
+                                          int flags);
+int mu_tcp_stream_create (mu_stream_t *stream, const char *host, int port,
+                         int flags);
+
+/* Transcript output levels */
+#define MU_XSCRIPT_NORMAL  0  /* Normal transcript */
+#define MU_XSCRIPT_SECURE  1  /* Security-related data are being transmitted */
+#define MU_XSCRIPT_PAYLOAD 2  /* Actual payload (may be copious) */
+
+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 mu_dbgstream_create(mu_stream_t *pref, mu_debug_t debug,
+                       mu_log_level_t level, int flags);
+
+int mu_rdcache_stream_create (mu_stream_t *pstream, mu_stream_t transport,
+                             int flags);
 
-extern int mu_stream_set_open     (mu_stream_t,
-      int (*_open) (mu_stream_t), void *owner);
-
-extern int mu_stream_set_close    (mu_stream_t,
-      int (*_close) (mu_stream_t), void *owner);
-
-extern int mu_stream_set_get_transport2  (mu_stream_t,
-      int (*_get_fd) (mu_stream_t, mu_transport_t *, mu_transport_t *),
-      void *owner);
-
-extern int mu_stream_set_read     (mu_stream_t,
-      int (*_read) (mu_stream_t, char *, size_t, mu_off_t, size_t *),
-                                  void *owner);
-
-extern int mu_stream_set_readline (mu_stream_t, 
-      int (*_readline) (mu_stream_t, char *, size_t, mu_off_t, size_t *),
-                               void *owner);
-
-extern int mu_stream_set_size     (mu_stream_t,
-      int (*_size) (mu_stream_t, mu_off_t *), void *owner);
-
-extern int mu_stream_set_truncate (mu_stream_t,
-      int (*_truncate) (mu_stream_t, mu_off_t), void *owner);
-
-extern int mu_stream_set_write    (mu_stream_t,
-      int (*_write) (mu_stream_t, const char *, size_t, mu_off_t, size_t *),
-                           void *owner);
-
-extern int mu_stream_set_flush    (mu_stream_t,
-      int (*_flush) (mu_stream_t), void *owner);
-
-extern int mu_stream_set_strerror (mu_stream_t stream,
-      int (*fp) (mu_stream_t, const char **), void *owner);
-
-extern int mu_stream_set_wait (mu_stream_t stream,
-      int (*wait) (mu_stream_t, int *, struct timeval *), void *owner);
-
-extern int mu_stream_set_shutdown (mu_stream_t stream,
-      int (*_shutdown) (mu_stream_t, int how), void *owner);
-  
-extern int mu_stream_sequential_read (mu_stream_t stream,
-      char *buf, size_t size, size_t *nbytes);
-  
-extern int mu_stream_sequential_readline (mu_stream_t stream,
-      char *buf, size_t size, size_t *nbytes);
-
-extern int mu_stream_sequential_getline  (mu_stream_t is,
-      char **pbuf, size_t *pbufsize, size_t *pnread);
-  
-extern int mu_stream_sequential_write (mu_stream_t stream,
-                                   const char *buf, size_t size);
-extern int mu_stream_seek (mu_stream_t stream, mu_off_t off, int whence);
-  
-extern int mu_stream_strerror (mu_stream_t stream, const char **p);
-  
-#ifdef __cplusplus
-}
 #endif
-
-#endif /* _MAILUTILS_STREAM_H */
-
diff --git a/include/mailutils/sys/Makefile.am 
b/include/mailutils/sys/Makefile.am
index e220ad8..57a5dc0 100644
--- a/include/mailutils/sys/Makefile.am
+++ b/include/mailutils/sys/Makefile.am
@@ -1,6 +1,6 @@
 ## Process this file with GNU Automake to create Makefile.in
 
-##   Copyright (C) 2002, 2007, 2010 Free Software Foundation, Inc.
+##   Copyright (C) 2002, 2007, 2009, 2010 Free Software Foundation, Inc.
 ##
 ##   GNU Mailutils is free software; you can redistribute it and/or
 ##   modify it under the terms of the GNU General Public License as
@@ -19,5 +19,41 @@
 
 sysincludedir=$(pkgincludedir)/sys
 sysinclude_HEADERS = \
-  nntp.h\
-  pop3.h
+ amd.h\
+ attribute.h\
+ auth.h\
+ body.h\
+ dbgstream.h\
+ debug.h\
+ envelope.h\
+ file_stream.h\
+ filter.h\
+ folder.h\
+ gsasl-stream.h\
+ header_stream.h\
+ header.h\
+ imap.h\
+ iterator.h\
+ iostream.h\
+ list.h\
+ mailbox.h\
+ mailer.h\
+ mapfile_stream.h\
+ memory_stream.h\
+ message_stream.h\
+ message.h\
+ mime.h\
+ monitor.h\
+ nntp.h\
+ observer.h\
+ pop3.h\
+ prog_stream.h\
+ property.h\
+ rdcache_stream.h\
+ registrar.h\
+ streamref.h\
+ streamtrans.h\
+ stream.h\
+ tls-stream.h\
+ url.h\
+ xscript-stream.h
diff --git a/include/mailutils/sys/amd.h b/include/mailutils/sys/amd.h
new file mode 100644
index 0000000..b72c3c1
--- /dev/null
+++ b/include/mailutils/sys/amd.h
@@ -0,0 +1,116 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008,
+   2010 Free Software Foundation, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General
+   Public License along with this library; if not, write to the
+   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301 USA */
+
+#ifndef _MAILUTILS_SYS_AMD_H
+# define _MAILUTILS_SYS_AMD_H
+# define MAX_OPEN_STREAMS 16
+
+/* Notifications ADD_MESG. */
+# define DISPATCH_ADD_MSG(mbox,mhd,n)                                  \
+  do                                                                   \
+    {                                                                  \
+      int bailing = 0;                                                 \
+      mu_monitor_unlock (mbox->monitor);                               \
+      if (mbox->observable)                                            \
+       {                                                               \
+         size_t tmp = n;                                               \
+         bailing = mu_observable_notify (mbox->observable,             \
+                                         MU_EVT_MESSAGE_ADD,           \
+                                         &tmp);                        \
+       }                                                               \
+      if (bailing != 0)                                                        
\
+       {                                                               \
+         if (pcount)                                                   \
+           *pcount = (mhd)->msg_count;                                 \
+         mu_locker_unlock (mbox->locker);                              \
+         return EINTR;                                                 \
+       }                                                               \
+      mu_monitor_wrlock (mbox->monitor);                               \
+} while (0);
+
+# define MU_AMD_SIZE_FILE_NAME ".mu-size"
+
+struct _amd_data;
+struct _amd_message
+{
+  mu_stream_t stream;       /* Associated file stream */
+  mu_off_t body_start;      /* Offset of body start in the message file */
+  mu_off_t body_end;        /* Offset of body end (size of file, effectively)*/
+
+  int orig_flags;           /* Original attribute flags */
+  int attr_flags;           /* Current attribute flags */
+       
+
+  time_t mtime;             /* Time of last modification */
+  size_t header_lines;      /* Number of lines in the header part */
+  size_t body_lines;        /* Number of lines in the body */
+
+  mu_message_t message;     /* Corresponding mu_message_t */
+  struct _amd_data *amd;    /* Back pointer.  */
+};
+
+struct _amd_data
+{
+  size_t msg_size;               /* Size of struct _amd_message */
+  int (*create) (struct _amd_data *, int flags);       
+  int (*msg_init_delivery) (struct _amd_data *, struct _amd_message *);
+  int (*msg_finish_delivery) (struct _amd_data *, struct _amd_message *,
+                             const mu_message_t);
+  void (*msg_free) (struct _amd_message *);
+  int (*cur_msg_file_name) (struct _amd_message *, char **);   
+  int (*new_msg_file_name) (struct _amd_message *, int, int, char **);
+  int (*scan0)     (mu_mailbox_t mailbox, size_t msgno, size_t *pcount,
+                   int do_notify);
+  int (*mailbox_size) (mu_mailbox_t mailbox, mu_off_t *psize);
+  int (*qfetch)    (struct _amd_data *, mu_message_qid_t qid);
+  int (*msg_cmp) (struct _amd_message *, struct _amd_message *);
+  int (*message_uid) (mu_message_t msg, size_t *puid);
+  size_t (*next_uid) (struct _amd_data *mhd);
+  
+  /* List of messages: */
+  size_t msg_count; /* number of messages in the list */
+  size_t msg_max;   /* maximum message buffer capacity */
+  struct _amd_message **msg_array;
+
+  unsigned long uidvalidity;
+  int has_new_msg;  /* New messages have been appended */
+  char *name;                    /* Directory name */
+
+  /* Pool of open message streams */
+  struct _amd_message *msg_pool[MAX_OPEN_STREAMS];
+  int pool_first;    /* Index to the first used entry in msg_pool */
+  int pool_last;     /* Index to the first free entry in msg_pool */
+
+  time_t mtime;      /* Time of last modification */
+
+  mu_mailbox_t mailbox; /* Back pointer. */
+};
+
+
+int amd_init_mailbox (mu_mailbox_t mailbox, size_t mhd_size,
+                     struct _amd_data **pmhd);
+int _amd_message_insert (struct _amd_data *mhd, struct _amd_message *msg);
+int amd_message_stream_open (struct _amd_message *mhm);
+void amd_message_stream_close (struct _amd_message *mhm);
+void amd_cleanup (void *arg);
+struct _amd_message *_amd_get_message (struct _amd_data *amd, size_t msgno);
+int amd_msg_lookup (struct _amd_data *amd, struct _amd_message *msg,
+                   size_t *pret);
+
+#endif             
diff --git a/include/mailutils/sys/attribute.h 
b/include/mailutils/sys/attribute.h
new file mode 100644
index 0000000..83e1f11
--- /dev/null
+++ b/include/mailutils/sys/attribute.h
@@ -0,0 +1,45 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 1999, 2000, 2005, 2007, 2010 Free Software Foundation,
+   Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General
+   Public License along with this library; if not, write to the
+   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301 USA */
+
+#ifndef _MAILUTILS_SYS_ATTRIBUTE_H
+# define _MAILUTILS_SYS_ATTRIBUTE_H
+
+#include <mailutils/attribute.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _mu_attribute
+{
+  void *owner;
+
+  int flags;
+  int user_flags;
+
+  int (*_get_flags)   (mu_attribute_t, int *);
+  int (*_set_flags)   (mu_attribute_t, int);
+  int (*_unset_flags) (mu_attribute_t, int);
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _MAILUTILS_SYS_ATTRIBUTE_H */
diff --git a/include/mailutils/sys/auth.h b/include/mailutils/sys/auth.h
new file mode 100644
index 0000000..0a4308d
--- /dev/null
+++ b/include/mailutils/sys/auth.h
@@ -0,0 +1,66 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 1999, 2000, 2001, 2005, 2007, 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 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General
+   Public License along with this library; if not, write to the
+   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301 USA */
+
+#ifndef _MAILUTILS_SYS_AUTH_H
+# define _MAILUTILS_SYS_AUTH_H
+
+#include <sys/types.h>
+#include <mailutils/auth.h>
+#include <mailutils/list.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _mu_ticket
+{
+  void *owner;           /* Object owner.  Not actually needed, but retained
+                           for a while. */
+  unsigned int refcnt;   /* Reference counter */
+  char *plain;           /* Plaintext credential (if any) */
+  mu_secret_t secret;    /* Secret credential (if any) */
+  void (*_destroy)  (mu_ticket_t); /* Destroy function */
+  /* Function for obtaining credentials */
+  int  (*_get_cred) (mu_ticket_t, mu_url_t, const char *, char **,
+                    mu_secret_t *);
+  /* Additional data for _get_cred */
+  void *data;
+};
+
+struct _mu_authority
+{
+  void *owner;
+  mu_ticket_t ticket;
+  mu_list_t auth_methods; /* list of int (*_authenticate) (mu_authority_t)s; */
+};
+
+struct _mu_wicket
+{
+  unsigned int refcnt;   /* Reference counter */
+  void *data;
+  int (*_get_ticket) (mu_wicket_t, void *, const char *, mu_ticket_t *);
+  void (*_destroy) (mu_wicket_t);
+};
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _MAILUTILS_SYS_AUTH_H */
diff --git a/include/mailutils/sys/body.h b/include/mailutils/sys/body.h
new file mode 100644
index 0000000..7ec58e3
--- /dev/null
+++ b/include/mailutils/sys/body.h
@@ -0,0 +1,50 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 1999, 2000, 2001, 2007, 2010 Free Software Foundation,
+   Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General
+   Public License along with this library; if not, write to the
+   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301 USA */
+
+#ifndef _MAILUTILS_SYS_BODY_H
+# define _MAILUTILS_SYS_BODY_H
+
+#include <mailutils/stream.h>
+#include <mailutils/body.h>
+
+#include <stdio.h>
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _mu_body
+{
+  void *owner;
+  char *filename;
+  mu_stream_t stream;
+  mu_stream_t fstream;
+  int flags;
+
+  int (*_size)  (mu_body_t, size_t*);
+  int (*_lines) (mu_body_t, size_t*);
+  int (*_get_stream) (mu_body_t, mu_stream_t *);
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _MAILUTILS_SYS_BODY_H */
diff --git a/include/mailutils/sys/dbgstream.h 
b/include/mailutils/sys/dbgstream.h
new file mode 100644
index 0000000..6934372
--- /dev/null
+++ b/include/mailutils/sys/dbgstream.h
@@ -0,0 +1,31 @@
+/* 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/>. */
+
+#ifndef _MAILUTILS_SYS_DBGSTREAM_H
+# define _MAILUTILS_SYS_DBGSTREAM_H
+
+# include <mailutils/types.h>
+# include <mailutils/stream.h>
+# include <mailutils/sys/stream.h>
+
+struct _mu_dbgstream
+{
+  struct _mu_stream stream;
+  mu_debug_t debug;
+  mu_log_level_t level;
+};
+
+#endif
diff --git a/include/mailutils/sys/debug.h b/include/mailutils/sys/debug.h
new file mode 100644
index 0000000..30ac959
--- /dev/null
+++ b/include/mailutils/sys/debug.h
@@ -0,0 +1,46 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 1999, 2000, 2005, 2007, 2010 Free Software Foundation,
+   Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General
+   Public License along with this library; if not, write to the
+   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301 USA */
+
+#ifndef _MAILUTILS_SYS_DEBUG_H
+# define _MAILUTILS_SYS_DEBUG_H
+
+#include <mailutils/debug.h>
+#include <mailutils/stream.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _mu_debug
+{
+  size_t level;
+  mu_stream_t stream;
+  void *owner;
+  struct mu_debug_locus locus;
+  const char *function;
+  void *data;
+  mu_debug_printer_fp printer;
+  void (*destroy) (void *data);
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _MAILUTILS_SYS_DEBUG_H */
diff --git a/include/mailutils/sys/envelope.h b/include/mailutils/sys/envelope.h
new file mode 100644
index 0000000..fe4689a
--- /dev/null
+++ b/include/mailutils/sys/envelope.h
@@ -0,0 +1,43 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 1999, 2000, 2005, 2007, 2010 Free Software Foundation,
+   Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General
+   Public License along with this library; if not, write to the
+   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301 USA */
+
+#ifndef _MAILUTILS_SYS_ENVELOPE_H
+# define _MAILUTILS_SYS_ENVELOPE_H
+
+#include <mailutils/envelope.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _mu_envelope
+{
+  void *owner;
+  char *date;
+  char *sender;
+  int (*_destroy) (mu_envelope_t);
+  int (*_get_sender)  (mu_envelope_t, char *, size_t, size_t *);
+  int (*_get_date)    (mu_envelope_t, char *, size_t , size_t *);
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _MAILUTILS_SYS_ENVELOPE_H */
diff --git a/include/mailutils/sys/file_stream.h 
b/include/mailutils/sys/file_stream.h
new file mode 100644
index 0000000..70c576a
--- /dev/null
+++ b/include/mailutils/sys/file_stream.h
@@ -0,0 +1,37 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 2009 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/>. */
+
+#ifndef _MAILUTILS_SYS_FILE_STREAM_H
+#define _MAILUTILS_SYS_FILE_STREAM_H
+
+#include <mailutils/types.h>
+#include <mailutils/stream.h>
+#include <mailutils/sys/stream.h>
+
+#define _MU_FILE_STREAM_TEMP 0x01
+
+struct _mu_file_stream
+{
+  struct _mu_stream stream;
+  int fd;
+  int flags;
+  char *filename;
+};
+
+int _mu_file_stream_create (struct _mu_file_stream **pstream, size_t size,
+                           const char *filename, int fd, int flags);
+
+#endif
diff --git a/include/mailutils/sys/filter.h b/include/mailutils/sys/filter.h
new file mode 100644
index 0000000..ceceb78
--- /dev/null
+++ b/include/mailutils/sys/filter.h
@@ -0,0 +1,55 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 1999, 2000, 2001, 2005, 2007, 2010 Free Software
+   Foundation, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General
+   Public License along with this library; if not, write to the
+   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301 USA */
+
+#ifndef _MAILUTILS_SYS_FILTER_H
+#define _MAILUTILS_SYS_FILTER_H
+
+#include <mailutils/filter.h>
+#include <mailutils/sys/stream.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MU_FILTER_BUF_SIZE 2048
+
+struct _mu_filter_buffer
+{
+  char *base;
+  size_t size;
+  size_t level;
+  size_t pos;
+};
+
+struct _mu_filter_stream
+{
+  struct _mu_stream stream;
+  mu_stream_t transport;
+  int mode;
+  
+  struct _mu_filter_buffer inbuf, outbuf;
+  mu_filter_xcode_t xcode;
+  void *xdata;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _MAILUTILS_SYS_FILTER_H */
diff --git a/include/mailutils/sys/folder.h b/include/mailutils/sys/folder.h
new file mode 100644
index 0000000..912fb87
--- /dev/null
+++ b/include/mailutils/sys/folder.h
@@ -0,0 +1,73 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 1999, 2000, 2001, 2005, 2007, 2010 Free Software
+   Foundation, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General
+   Public License along with this library; if not, write to the
+   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301 USA */
+
+#ifndef _MAILUTILS_SYS_FOLDER_H
+# define _MAILUTILS_SYS_FOLDER_H
+
+# include <sys/types.h>
+# include <stdio.h>
+
+# include <mailutils/monitor.h>
+# include <mailutils/folder.h>
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+# define MU_FOLDER_LIST 0
+# define MU_FOLDER_ENUM 1
+  
+struct _mu_folder
+{
+  /* Data */
+  mu_authority_t authority;
+  mu_observable_t observable;
+  mu_debug_t debug;
+  mu_stream_t stream;
+  mu_monitor_t monitor;
+  mu_url_t url;
+  int flags;
+  int ref;
+  size_t uid;
+
+  /* Back pointer to the specific mailbox */
+  void *data;
+
+  /* Public methods */
+
+  void (*_destroy)     (mu_folder_t);
+
+  int  (*_open)        (mu_folder_t, int flag);
+  int  (*_close)       (mu_folder_t);
+  int  (*_list)        (mu_folder_t, const char *, void *, int, size_t,
+                       mu_list_t, mu_folder_enumerate_fp, void *);
+  int  (*_lsub)        (mu_folder_t, const char *, const char *,
+                       mu_list_t);
+  mu_folder_match_fp   _match;
+  int  (*_delete)      (mu_folder_t, const char *);
+  int  (*_rename)      (mu_folder_t, const char *, const char *);
+  int  (*_subscribe)   (mu_folder_t, const char *);
+  int  (*_unsubscribe) (mu_folder_t, const char *);
+};
+
+# ifdef __cplusplus
+}
+# endif
+
+#endif /* _MAILUTILS_SYS_FOLDER_H */
diff --git a/include/mailutils/sys/gsasl-stream.h 
b/include/mailutils/sys/gsasl-stream.h
new file mode 100644
index 0000000..c931767
--- /dev/null
+++ b/include/mailutils/sys/gsasl-stream.h
@@ -0,0 +1,38 @@
+/* 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/>. */
+
+#ifndef _MAILUTILS_SYS_TLS_STREAM_H
+# define _MAILUTILS_SYS_GSASL_STREAM_H
+
+# include <mailutils/types.h>
+# include <mailutils/stream.h>
+# include <mailutils/sys/stream.h>
+
+struct _mu_gsasl_filter
+{
+  Gsasl_session *sess_ctx; /* Context */
+  int gsasl_err;        /* Last Gsasl error code */
+  char *bufptr;
+  size_t bufsize;
+};
+
+struct _mu_gsasl_stream
+{
+  struct _mu_stream stream;
+  mu_stream_t transport;
+};
+
+#endif
diff --git a/include/mailutils/sys/header.h b/include/mailutils/sys/header.h
new file mode 100644
index 0000000..1898509
--- /dev/null
+++ b/include/mailutils/sys/header.h
@@ -0,0 +1,80 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 1999, 2000, 2001, 2005, 2007, 2010 Free Software
+   Foundation, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General
+   Public License along with this library; if not, write to the
+   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301 USA */
+
+#ifndef _HEADER0_H
+#define _HEADER0_H
+
+#ifdef DMALLOC
+# include <dmalloc.h>
+#endif
+
+#include <mailutils/header.h>
+#include <mailutils/assoc.h>
+#include <mailutils/iterator.h>
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* The structure members are offset that point to the begin/end of header
+   fields.  */
+struct mu_hdrent
+{
+  struct mu_hdrent *prev;
+  struct mu_hdrent *next;
+  size_t fn;
+  size_t nlen;
+  size_t fv;
+  size_t vlen;
+  size_t nlines;
+};
+
+struct _mu_header
+{
+  /* Data.  */
+  char *spool;
+  size_t spool_size;
+  size_t spool_used;
+  struct mu_hdrent *head, *tail;
+  int flags;
+
+  size_t numhdr;
+  size_t numlines;
+  size_t size;
+  
+  /* Temporary storage */
+  mu_stream_t mstream;
+  
+  /* Stream.  */
+  mu_stream_t stream;
+
+  /* Iterators */
+  mu_iterator_t itr;
+
+  /* Methods */
+  int (*_fill) (void *data, char **, size_t *);
+  void *data;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _HEADER0_H */
diff --git a/include/mailutils/sys/header_stream.h 
b/include/mailutils/sys/header_stream.h
new file mode 100644
index 0000000..d4fba99
--- /dev/null
+++ b/include/mailutils/sys/header_stream.h
@@ -0,0 +1,30 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 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/>. */
+
+#ifndef _MAILUTILS_SYS_HEADER_STREAM_H
+#define _MAILUTILS_SYS_HEADER_STREAM_H
+
+#include <mailutils/header.h>
+#include <mailutils/sys/stream.h>
+
+struct _mu_header_stream
+{
+  struct _mu_stream stream;
+  mu_header_t hdr;
+  mu_off_t off;
+};
+
+#endif
diff --git a/include/mailutils/sys/imap.h b/include/mailutils/sys/imap.h
new file mode 100644
index 0000000..bbad6e5
--- /dev/null
+++ b/include/mailutils/sys/imap.h
@@ -0,0 +1,236 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 1999, 2000, 2001, 2005, 2007, 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 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General
+   Public License along with this library; if not, write to the
+   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301 USA */
+
+#ifndef _MAILUTILS_SYS_IMAP_H
+# define _MAILUTILS_SYS_IMAP_H
+
+# include <mailutils/sys/folder.h>
+# include <mailutils/sys/mailbox.h>
+# include <mailutils/sys/registrar.h>
+# include <mailutils/sys/auth.h>
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+# define CLEAR_STATE(f_imap)                           \
+ f_imap->selected = NULL, f_imap->state = IMAP_NO_STATE
+
+/* Clear the state and close the stream.  */
+# define CHECK_ERROR_CLOSE(folder, f_imap, status)     \
+  do                                                   \
+    {                                                  \
+      if (status != 0)                                 \
+       {                                               \
+          mu_stream_close (folder->stream);            \
+          CLEAR_STATE (f_imap);                                \
+          return status;                               \
+       }                                               \
+    }                                                  \
+  while (0)
+
+/* Clear the state.  */
+# define CHECK_ERROR(f_imap, status)           \
+  do                                           \
+    {                                          \
+      if (status != 0)                         \
+       {                                       \
+          CLEAR_STATE (f_imap);                        \
+          return status;                       \
+       }                                       \
+    }                                          \
+while (0)
+
+/* Clear the state for non recoverable error.  */
+# define CHECK_EAGAIN(f_imap, status)          \
+  do                                           \
+    {                                          \
+      if (status != 0)                         \
+       {                                                               \
+         if (status != EAGAIN && status != EINPROGRESS && status != EINTR) \
+           {                                                           \
+             CLEAR_STATE (f_imap);                                     \
+           }                                                           \
+         return status;                                                \
+       }                                                               \
+    }                                                                  \
+  while (0)
+
+struct _f_imap;
+struct _m_imap;
+struct _msg_imap;
+typedef struct _f_imap *f_imap_t;
+typedef struct _m_imap *m_imap_t;
+typedef struct _msg_imap *msg_imap_t;
+
+enum imap_state
+{
+  IMAP_NO_STATE=0,
+  IMAP_AUTH, IMAP_AUTH_DONE,
+  IMAP_APPEND, IMAP_APPEND_CONT, IMAP_APPEND_SEND, IMAP_APPEND_ACK,
+  IMAP_BODY,
+  IMAP_CLOSE, IMAP_CLOSE_ACK,
+  IMAP_COPY, IMAP_COPY_ACK,
+  IMAP_CREATE, IMAP_CREATE_ACK,
+  IMAP_DELETE, IMAP_DELETE_ACK,
+  IMAP_EXPUNGE, IMAP_EXPUNGE_ACK,
+  IMAP_FETCH, IMAP_FETCH_ACK,
+  IMAP_GREETINGS,
+  IMAP_HEADER,
+  IMAP_HEADER_FIELD,
+  IMAP_LIST, IMAP_LIST_PARSE, IMAP_LIST_ACK,
+  IMAP_LOGIN, IMAP_LOGIN_ACK,
+  IMAP_LOGOUT, IMAP_LOGOUT_ACK,
+  IMAP_LSUB, IMAP_LSUB_ACK,
+  IMAP_MESSAGE,
+  IMAP_NOOP, IMAP_NOOP_ACK,
+  IMAP_OPEN_CONNECTION,
+  IMAP_RENAME, IMAP_RENAME_ACK,
+  IMAP_SCAN, IMAP_SCAN_ACK,
+  IMAP_SELECT, IMAP_SELECT_ACK,
+  IMAP_STORE, IMAP_STORE_ACK,
+  IMAP_SUBSCRIBE, IMAP_SUBSCRIBE_ACK,
+  IMAP_UNSUBSCRIBE, IMAP_UNSUBSCRIBE_ACK
+};
+
+enum imap_auth_state
+{
+  /* ANONYMOUS */
+  IMAP_AUTH_ANON_REQ_WRITE,
+  IMAP_AUTH_ANON_REQ_SEND,
+  IMAP_AUTH_ANON_WAIT_CONT,
+  IMAP_AUTH_ANON_MSG,
+  IMAP_AUTH_ANON_MSG_SEND,
+  IMAP_AUTH_ANON_WAIT_RESP
+};
+
+struct literal_string
+{
+  char *buffer;
+  size_t buflen;
+  size_t total;
+  msg_imap_t msg_imap;
+  enum imap_state type;
+  size_t nleft;  /* nleft to read in the literal. */
+};
+
+struct _f_imap
+{
+  /* Back pointer.  */
+  mu_folder_t folder;
+  m_imap_t selected;
+
+  enum imap_state state;
+  int imaps; /* IMAPS or IMAP? */
+
+  size_t seq; /* Sequence number to build a tag.  */
+  char **capav; /* Cabilities of the server.  */
+  int capac;    /* Number of capabilities in the above array */
+  int flags;
+
+  /* IO use to hold the literal and quoted strings send by
+     the IMAP server.  */
+  struct
+  {
+    mu_stream_t stream;
+    mu_off_t offset;
+    size_t nleft;  /* nleft to read in the literal. */
+    msg_imap_t msg_imap;
+    enum imap_state type;
+  } string;
+
+  /* Use for LIST and LSUB.  */
+  mu_list_t flist;
+  mu_folder_enumerate_fp enum_fun;
+  void *enum_data;
+  int enum_stop;
+  
+  int isopen;
+
+  /* Server channel buffer I/O  */
+  size_t buflen;
+  char *buffer;
+  char *ptr;
+  char *nl;
+  mu_off_t offset; /* Dummy, this is used because of the stream buffering.
+                   The mu_stream_t maintains and offset and the offset we
+                  use must be in sync.  */
+
+  /* Login  */
+  char *user;
+  mu_secret_t secret;
+
+  /* AUTHENTICATE states */
+  enum imap_auth_state auth_state;
+};
+
+struct _m_imap
+{
+  /* Back pointers.  */
+  mu_mailbox_t mailbox;
+  f_imap_t f_imap;
+  size_t messages_count;
+  size_t imessages_count;
+  msg_imap_t *imessages;
+  size_t recent;
+  size_t unseen;
+  unsigned long uidvalidity;
+  size_t uidnext;
+  char *name;
+  enum imap_state state;
+    /* mailbox operations can be sequences of folder operations, and
+       thus need to keep meta-state, mailbox_imap_open(), for example. */
+};
+
+struct _msg_imap
+{
+  /* Back pointers.  */
+  mu_message_t message;
+  m_imap_t m_imap;
+  size_t num;
+  size_t part;
+  size_t num_parts;
+  msg_imap_t *parts;
+  msg_imap_t parent;
+  int flags;
+  size_t uid;
+
+  mu_header_t fheader;
+  char *internal_date;
+
+  size_t mu_message_size;
+  size_t mu_message_lines;
+  size_t body_size;
+  size_t body_lines;
+  size_t header_size;
+  size_t header_lines;
+};
+
+int imap_writeline    (f_imap_t,  const char *format, ...) MU_PRINTFLIKE(2,3);
+int imap_write        (f_imap_t);
+int imap_send         (f_imap_t);
+int imap_parse        (f_imap_t);
+int imap_readline     (f_imap_t);
+char *section_name    (msg_imap_t);
+
+# ifdef __cplusplus
+}
+# endif
+
+#endif /* _MAILUTILS_SYS_IMAP_H */
diff --git a/include/mailutils/sys/iostream.h b/include/mailutils/sys/iostream.h
new file mode 100644
index 0000000..d8922f6
--- /dev/null
+++ b/include/mailutils/sys/iostream.h
@@ -0,0 +1,34 @@
+/* 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/>. */
+
+#ifndef _MAILUTILS_SYS_IOSTREAM_H
+# define _MAILUTILS_SYS_IOSTREAM_H
+
+# include <mailutils/types.h>
+# include <mailutils/stream.h>
+# include <mailutils/sys/stream.h>
+
+# define _MU_STREAM_INPUT 0
+# define _MU_STREAM_OUTPUT 1
+
+struct _mu_iostream
+{
+  struct _mu_stream stream;
+  mu_stream_t transport[2];
+  int last_err_str;
+};
+
+#endif
diff --git a/include/mailutils/sys/iterator.h b/include/mailutils/sys/iterator.h
new file mode 100644
index 0000000..5b5475f
--- /dev/null
+++ b/include/mailutils/sys/iterator.h
@@ -0,0 +1,49 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 1999, 2000, 2004, 2007, 2010 Free Software Foundation,
+   Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General
+   Public License along with this library; if not, write to the
+   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301 USA */
+
+#ifndef _MAILUTILS_SYS_ITERATOR_H
+# define _MAILUTILS_SYS_ITERATOR_H
+
+# include <mailutils/iterator.h>
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+struct _mu_iterator
+{
+  struct _mu_iterator *next_itr; /* Next iterator in the chain */
+  void *owner;                /* Object whose contents is being iterated */
+  int is_advanced;            /* Is the iterator already advanced */
+
+  int (*dup) (void **ptr, void *owner);
+  int (*destroy) (mu_iterator_t itr, void *owner);
+  int (*first) (void *owner);
+  int (*next) (void *owner);
+  int (*getitem) (void *owner, void **pret, const void **pkey);
+  int (*curitem_p) (void *owner, void *item);
+  int (*finished_p) (void *owner);
+  int (*itrctl) (void *owner, enum mu_itrctl_req req, void *arg);
+};
+
+# ifdef __cplusplus
+}
+# endif
+
+#endif /* _MAILUTILS_SYS_ITERATOR_H */
diff --git a/include/mailutils/sys/list.h b/include/mailutils/sys/list.h
new file mode 100644
index 0000000..2e9f83a
--- /dev/null
+++ b/include/mailutils/sys/list.h
@@ -0,0 +1,62 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 1999, 2000, 2005, 2007, 2010 Free Software Foundation,
+   Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General
+   Public License along with this library; if not, write to the
+   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301 USA */
+
+#ifndef _MAILUTILS_SYS_LIST_H
+# define _MAILUTILS_SYS_LIST_H
+
+# include <sys/types.h>
+
+# include <mailutils/list.h>
+# include <mailutils/monitor.h>
+# include <mailutils/iterator.h>
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+struct list_data
+{
+  void *item;
+  struct list_data *next;
+  struct list_data *prev;
+};
+
+struct _mu_list
+{
+  struct list_data head;
+  size_t count;
+  mu_monitor_t monitor;
+  mu_list_comparator_t comp;
+  void (*destroy_item) (void *item);
+  struct _mu_iterator *itr;
+};
+
+extern void _mu_list_clear (mu_list_t list);
+extern void _mu_list_insert_sublist (mu_list_t list,
+                                    struct list_data *current,
+                                    struct list_data *head,
+                                    struct list_data *tail,
+                                    size_t count,
+                                    int insert_before);
+
+# ifdef __cplusplus
+}
+# endif
+
+#endif /* _MAILUTILS_SYS_LIST_H */
diff --git a/include/mailutils/sys/mailbox.h b/include/mailutils/sys/mailbox.h
new file mode 100644
index 0000000..12af8fe
--- /dev/null
+++ b/include/mailutils/sys/mailbox.h
@@ -0,0 +1,83 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 1999, 2000, 2001, 2005, 2007, 2010 Free Software
+   Foundation, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General
+   Public License along with this library; if not, write to the
+   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301 USA */
+
+#ifndef _MAILUTILS_SYS_MAILBOX_H
+# define _MAILUTILS_SYS_MAILBOX_H
+
+# include <sys/types.h>
+# include <stdio.h>
+
+# include <mailutils/monitor.h>
+# include <mailutils/mailbox.h>
+# include <mailutils/iterator.h>
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+struct _mu_mailbox
+{
+  /* Data */
+  mu_observable_t observable;
+  mu_debug_t debug;
+  mu_property_t property;
+  mu_locker_t locker;
+  mu_stream_t stream;
+  mu_url_t url;
+  int flags;
+  mu_folder_t folder;
+  mu_monitor_t monitor;
+  mu_iterator_t iterator;
+  
+  /* Back pointer to the specific mailbox */
+  void *data;
+
+  /* Public methods */
+
+  void (*_destroy)         (mu_mailbox_t);
+
+  int  (*_open)            (mu_mailbox_t, int);
+  int  (*_close)           (mu_mailbox_t);
+  
+  /* messages */
+  int  (*_get_message)     (mu_mailbox_t, size_t, mu_message_t *);
+  int  (*_append_message)  (mu_mailbox_t, mu_message_t);
+  int  (*_messages_count)  (mu_mailbox_t, size_t *);
+  int  (*_messages_recent) (mu_mailbox_t, size_t *);
+  int  (*_message_unseen)  (mu_mailbox_t, size_t *);
+  int  (*_expunge)         (mu_mailbox_t);
+  int  (*_sync)            (mu_mailbox_t);
+  int  (*_uidvalidity)     (mu_mailbox_t, unsigned long *);
+  int  (*_uidnext)         (mu_mailbox_t, size_t *);
+  int  (*_get_property)    (mu_mailbox_t, mu_property_t *);
+
+  int  (*_scan)            (mu_mailbox_t, size_t, size_t *);
+  int  (*_is_updated)      (mu_mailbox_t);
+
+  int  (*_get_size)        (mu_mailbox_t, mu_off_t *);
+
+  int  (*_quick_get_message) (mu_mailbox_t, mu_message_qid_t, mu_message_t *);
+  int  (*_get_uidls) (mu_mailbox_t, mu_list_t);
+};
+
+# ifdef __cplusplus
+}
+# endif
+
+#endif /* _MAILUTILS_SYS_MAILBOX_H */
diff --git a/include/mailutils/sys/mailer.h b/include/mailutils/sys/mailer.h
new file mode 100644
index 0000000..b9413a3
--- /dev/null
+++ b/include/mailutils/sys/mailer.h
@@ -0,0 +1,67 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 1999, 2000, 2001, 2005, 2007, 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 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General
+   Public License along with this library; if not, write to the
+   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301 USA */
+
+#ifndef _MAILUTILS_SYS_MAILER_H
+# define _MAILUTILS_SYS_MAILER_H
+
+# include <sys/types.h>
+# include <mailutils/mailer.h>
+# include <mailutils/monitor.h>
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+/* Default mailer URL. */
+
+# define MAILER_URL_DEFAULT "sendmail:"
+
+# define MAILER_LINE_BUF_SIZE  1000
+
+struct _mu_mailer
+{
+  mu_stream_t stream;
+  mu_observable_t observable;
+  mu_debug_t debug;
+  mu_url_t url;
+  int flags;
+  mu_monitor_t monitor;
+  mu_property_t property;
+
+  /* Pointer to the specific mailer data.  */
+  void *data;
+
+  /* Public methods.  */
+  void (*_destroy)     (mu_mailer_t);
+  int (*_open)         (mu_mailer_t, int flags);
+  int (*_close)        (mu_mailer_t);
+  int (*_send_message) (mu_mailer_t, mu_message_t, mu_address_t, mu_address_t);
+};
+
+int _mu_mailer_mailbox_init (mu_mailbox_t mailbox);
+int _mu_mailer_folder_init (mu_folder_t folder MU_ARG_UNUSED);
+  
+# define MAILER_NOTIFY(mailer, type) \
+  if (mailer->observer) observer_notify (mailer->observer, type)
+
+# ifdef __cplusplus
+}
+# endif
+
+#endif /* _MAILUTILS_SYS_MAILER_H */
diff --git a/include/mailutils/sys/mapfile_stream.h 
b/include/mailutils/sys/mapfile_stream.h
new file mode 100644
index 0000000..010d4d5
--- /dev/null
+++ b/include/mailutils/sys/mapfile_stream.h
@@ -0,0 +1,33 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 2009 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/>. */
+
+#ifndef _MAILUTILS_SYS_MAPFILE_STREAM_H
+#define _MAILUTILS_SYS_MAPFILE_STREAM_H
+
+#include <mailutils/sys/stream.h>
+
+struct _mu_mapfile_stream
+{
+  struct _mu_stream stream;
+  int fd;
+  int flags;
+  char *ptr;
+  size_t offset;
+  size_t size;
+  char *filename;
+};
+
+#endif
diff --git a/include/mailutils/sys/memory_stream.h 
b/include/mailutils/sys/memory_stream.h
new file mode 100644
index 0000000..94b910c
--- /dev/null
+++ b/include/mailutils/sys/memory_stream.h
@@ -0,0 +1,33 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 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/>. */
+
+#ifndef _MAILUTILS_SYS_MEMORY_STREAM_H
+#define _MAILUTILS_SYS_MEMORY_STREAM_H
+
+#include <mailutils/sys/stream.h>
+
+#define MU_STREAM_MEMORY_BLOCKSIZE 1024
+
+struct _mu_memory_stream
+{
+  struct _mu_stream stream;
+  char *ptr;
+  size_t size;
+  mu_off_t offset;
+  size_t capacity;
+};
+
+#endif
diff --git a/include/mailutils/sys/message.h b/include/mailutils/sys/message.h
new file mode 100644
index 0000000..5e96d85
--- /dev/null
+++ b/include/mailutils/sys/message.h
@@ -0,0 +1,70 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 1999, 2000, 2001, 2005, 2007, 2010 Free Software
+   Foundation, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General
+   Public License along with this library; if not, write to the
+   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301 USA */
+
+#ifndef _MESSAGE0_H
+#define _MESSAGE0_H
+
+#include <mailutils/message.h>
+#include <mailutils/mime.h>
+#include <mailutils/monitor.h>
+
+#include <sys/types.h>
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _mu_message
+{
+  /* Who is the owner.  */
+  void *owner;
+
+  mu_envelope_t envelope;
+  mu_header_t header;
+  mu_body_t body;
+
+  int flags;
+  mu_stream_t stream;
+  mu_attribute_t attribute;
+  mu_monitor_t monitor;
+  mu_mime_t mime;
+  mu_observable_t observable;
+  mu_mailbox_t mailbox;
+  size_t orig_header_size;
+  
+  /* Reference count.  */
+  int ref;
+
+  int (*_get_stream)     (mu_message_t, mu_stream_t *);
+  int (*_get_uidl)       (mu_message_t, char *, size_t, size_t *);
+  int (*_get_uid)        (mu_message_t, size_t *);
+  int (*_get_qid)        (mu_message_t,        mu_message_qid_t *);
+  int (*_get_num_parts)  (mu_message_t, size_t *);
+  int (*_get_part)       (mu_message_t, size_t, mu_message_t *);
+  int (*_is_multipart)   (mu_message_t, int *);
+  int (*_lines)          (mu_message_t, size_t *);
+  int (*_size)           (mu_message_t, size_t *);
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _MESSAGE0_H */
diff --git a/include/mailutils/sys/message_stream.h 
b/include/mailutils/sys/message_stream.h
new file mode 100644
index 0000000..381e7c9
--- /dev/null
+++ b/include/mailutils/sys/message_stream.h
@@ -0,0 +1,48 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 2009 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/>. */
+
+#ifndef _MAILUTILS_SYS_MESSAGE_STREAM_H
+#define _MAILUTILS_SYS_MESSAGE_STREAM_H
+
+#include <mailutils/sys/stream.h>
+
+struct _mu_message_stream
+{
+  struct _mu_stream stream;
+  mu_stream_t transport;  /* Actual stream */
+  mu_off_t offset;
+
+  char *envelope;
+  size_t envelope_length; 
+  char *from;
+  char *date;
+  size_t mark_offset;  /* Offset of the header separator */
+  size_t mark_length;  /* Length of the header separator (not counting the
+                         newline) */
+  mu_off_t body_start;
+  mu_off_t body_end;
+};
+
+struct _mu_body_stream
+{
+  struct _mu_stream stream;
+  mu_off_t offset;
+  struct _mu_message_stream *message_stream;
+};
+
+#endif
+
+
diff --git a/include/mailutils/sys/mime.h b/include/mailutils/sys/mime.h
new file mode 100644
index 0000000..ce30042
--- /dev/null
+++ b/include/mailutils/sys/mime.h
@@ -0,0 +1,97 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 1999, 2000, 2005, 2007, 2010 Free Software Foundation,
+   Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General
+   Public License along with this library; if not, write to the
+   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301 USA */
+
+#ifndef _MAILUTILS_SYS_MIME_H
+#define _MAILUTILS_SYS_MIME_H
+
+#include <sys/types.h>
+#include <mailutils/mime.h>
+
+#ifdef __cplusplus
+extern "C" { 
+#endif
+
+#define MIME_MAX_HDR_LEN           256
+#define MIME_DFLT_BUF_SIZE         2048
+
+/* Parser states */
+#define MIME_STATE_BEGIN_LINE      1
+#define MIME_STATE_SCAN_BOUNDARY   2
+#define MIME_STATE_HEADERS         3
+
+#define MIME_FLAG_MASK             0x0000ffff
+
+/* private */
+#define MIME_PARSER_ACTIVE         0x80000000
+#define MIME_PARSER_HAVE_CR        0x40000000
+#define MIME_NEW_MESSAGE           0x20000000
+#define MIME_ADDED_CT              0x10000000
+#define MIME_ADDED_MULTIPART_CT    0x08000000
+#define MIME_INSERT_BOUNDARY       0x04000000
+#define MIME_ADDING_BOUNDARY       0x02000000
+
+struct _mu_mime
+{
+  mu_message_t       msg;
+  mu_header_t        hdrs;
+  mu_stream_t        stream;
+  int             flags;
+  char           *content_type;
+
+  size_t          tparts;
+  size_t          nmtp_parts;
+  struct _mime_part **mtp_parts;      /* list of parts in the msg */
+  char           *boundary;
+  size_t          cur_offset;
+  size_t          cur_part;
+  size_t          part_offset;
+  size_t          boundary_len;
+  size_t          preamble;
+  size_t          postamble;
+  mu_stream_t     part_stream;
+  /* parser state */
+  char           *cur_line;
+  ssize_t         line_ndx;
+  size_t          line_size;
+  char           *cur_buf;
+  size_t          buf_size;
+  char           *header_buf;
+  size_t          header_buf_size;
+  size_t          header_length;
+  size_t          body_offset;
+  size_t          body_length;
+  size_t          body_lines;
+  int             parser_state;
+};
+
+struct _mime_part
+{
+  mu_mime_t          mime;
+  mu_message_t       msg;
+  int                body_created;
+  size_t             offset;
+  size_t             len;
+  size_t             lines;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif                          /* MIME0_H */
diff --git a/include/mailutils/sys/monitor.h b/include/mailutils/sys/monitor.h
new file mode 100644
index 0000000..2d76265
--- /dev/null
+++ b/include/mailutils/sys/monitor.h
@@ -0,0 +1,37 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 1999, 2000, 2007, 2010 Free Software Foundation, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General
+   Public License along with this library; if not, write to the
+   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301 USA */
+
+#ifndef _MAILUTILS_SYS_MONITOR_H
+# define _MAILUTILS_SYS_MONITOR_H
+
+# ifdef HAVE_CONFIG_H
+#  include <config.h>
+# endif
+
+# include <sys/types.h>
+# include <mailutils/monitor.h>
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+/* FIXME: any protos? */
+# ifdef __cplusplus
+}
+# endif
+
+#endif /* _MONITOR0_H */
diff --git a/include/mailutils/sys/nntp.h b/include/mailutils/sys/nntp.h
index 8f86bec..5b28ad5 100644
--- a/include/mailutils/sys/nntp.h
+++ b/include/mailutils/sys/nntp.h
@@ -1,5 +1,5 @@
 /* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 2004, 2007, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2007 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
diff --git a/include/mailutils/sys/observer.h b/include/mailutils/sys/observer.h
new file mode 100644
index 0000000..7aede1c
--- /dev/null
+++ b/include/mailutils/sys/observer.h
@@ -0,0 +1,56 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 1999, 2000, 2005, 2007, 2010 Free Software Foundation,
+   Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General
+   Public License along with this library; if not, write to the
+   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301 USA */
+
+#ifndef _MAILUTILS_SYS_OBSERVER_H
+# define _MAILUTILS_SYS_OBSERVER_H
+
+# include <mailutils/observer.h>
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+struct _mu_observer
+{
+  int flags;
+  void *owner;
+  int (*_action)  (mu_observer_t, size_t, void *, void *);
+  void *_action_data;
+  int (*_destroy) (mu_observer_t, void *data);
+};
+
+struct _mu_observable
+{
+  void *owner;
+  mu_list_t list;
+};
+
+struct _event
+{
+  size_t type;
+  mu_observer_t observer;
+};
+
+typedef struct _event *event_t;
+
+# ifdef __cplusplus
+}
+# endif
+
+#endif /* _MAILUTILS_SYS_OBSERVER_H */
diff --git a/include/mailutils/sys/pop3.h b/include/mailutils/sys/pop3.h
index 419397b..55bedeb 100644
--- a/include/mailutils/sys/pop3.h
+++ b/include/mailutils/sys/pop3.h
@@ -1,6 +1,6 @@
 /* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 1999, 2000, 2001, 2003, 2004, 2007, 2009, 2010 Free
-   Software Foundation, Inc.
+   Copyright (C) 1999, 2000, 2001, 2003, 2004, 
+   2007, 2009 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
@@ -37,115 +37,114 @@ enum mu_pop3_state
   {
     MU_POP3_NO_STATE,
     MU_POP3_CONNECT, MU_POP3_GREETINGS,
-    MU_POP3_APOP,    MU_POP3_APOP_ACK,
-    MU_POP3_AUTH,    MU_POP3_AUTH_ACK,
-    MU_POP3_CAPA,    MU_POP3_CAPA_ACK, MU_POP3_CAPA_RX,
-    MU_POP3_DELE,    MU_POP3_DELE_ACK,
-    MU_POP3_LIST,    MU_POP3_LIST_ACK, MU_POP3_LIST_RX,
-    MU_POP3_NOOP,    MU_POP3_NOOP_ACK,
-    MU_POP3_PASS,    MU_POP3_PASS_ACK,
-    MU_POP3_QUIT,    MU_POP3_QUIT_ACK,
-    MU_POP3_RETR,    MU_POP3_RETR_ACK, MU_POP3_RETR_RX,
-    MU_POP3_RSET,    MU_POP3_RSET_ACK,
-    MU_POP3_STAT,    MU_POP3_STAT_ACK,
-    MU_POP3_STLS,    MU_POP3_STLS_ACK, MU_POP3_STLS_CONNECT,
-    MU_POP3_TOP,     MU_POP3_TOP_ACK,  MU_POP3_TOP_RX,
-    MU_POP3_UIDL,    MU_POP3_UIDL_ACK, MU_POP3_UIDL_RX,
-    MU_POP3_USER,    MU_POP3_USER_ACK,
-    MU_POP3_DONE,    MU_POP3_UNKNOWN,  MU_POP3_ERROR
-  };
-
-/* Structure holding the data necessary to do proper buffering.  */
-struct mu_pop3_work_buf
-  {
-    char *buf;
-    char *ptr;
-    char *nl;
-    size_t len;
+    MU_POP3_APOP,
+    MU_POP3_AUTH,
+    MU_POP3_CAPA, MU_POP3_CAPA_RX,
+    MU_POP3_DELE,
+    MU_POP3_LIST, MU_POP3_LIST_RX,
+    MU_POP3_NOOP,
+    MU_POP3_PASS,
+    MU_POP3_QUIT,
+    MU_POP3_RETR, MU_POP3_RETR_RX,
+    MU_POP3_RSET,
+    MU_POP3_STAT,
+    MU_POP3_STLS, MU_POP3_STLS_CONNECT,
+    MU_POP3_TOP,  MU_POP3_TOP_RX,
+    MU_POP3_UIDL, MU_POP3_UIDL_RX,
+    MU_POP3_USER,
+    MU_POP3_DONE,
+    MU_POP3_UNKNOWN,
+    MU_POP3_ERROR
   };
 
+#define MU_POP3_ACK   0x01
+#define MU_POP3_TRACE 0x02  
+#define MU_POP3_XSCRIPT_MASK(n) (1<<((n)+1))
+  
 /* Structure to hold things general to POP3 mailbox, like its state, etc ... */
 struct _mu_pop3
   {
-    /* Working I/O buffer.
-       io.buf: Working io buffer
-       io.ptr: Points to the end of the buffer, the non consumed chars
-       io.nl: Points to the '\n' char in the string
-       io.len: Len of io_buf.  */
-    struct mu_pop3_work_buf io;
-
-    /* Holds the first line response of the last command, i.e the ACK:
-       ack.buf: Buffer for the ack
-       ack.ptr: Working pointer, indicate the start of the non consumed chars
-       ack.len: Size 512 according to RFC2449.  */
-    struct mu_pop3_work_buf ack;
-    int acknowledge;
-
-    char *timestamp; /* For apop, if supported.  */
-    unsigned timeout;  /* Default is 10 minutes.  */
-
-    mu_debug_t debug; /* debugging trace.  */
-
-    enum mu_pop3_state state;  /* Indicate the state of the running command.  
*/
-
-    mu_stream_t carrier; /* TCP Connection.  */
+    int flags;
+    
+    /* Holds the first line response of the last command, i.e the ACK  */
+    char *ackbuf;
+    size_t acksize;
+
+    char *rdbuf;
+    size_t rdsize;
+    
+    char *timestamp;    /* For apop, if supported.  */
+    unsigned timeout;   /* Default is 10 minutes.  */
+
+    enum mu_pop3_state state;  /* Indicate the state of the running
+                                 command.  */
+    mu_list_t capa;            /* Capabilities. */ 
+    mu_stream_t carrier;       /* TCP Connection. */
   };
 
-extern int  mu_pop3_debug_cmd       (mu_pop3_t);
-extern int  mu_pop3_debug_ack       (mu_pop3_t);
+#define MU_POP3_FSET(p,f) ((p)->flags |= (f))
+#define MU_POP3_FISSET(p,f) ((p)->flags & (f))  
+#define MU_POP3_FCLR(p,f) ((p)->flags &= ~(f))
+  
 extern int  mu_pop3_iterator_create (mu_pop3_t pop3, mu_iterator_t *piterator);
 extern int  mu_pop3_stream_create (mu_pop3_t pop3, mu_stream_t *pstream);
-extern int  mu_pop3_carrier_is_ready (mu_stream_t carrier, int flag, int 
timeout);
+extern int  mu_pop3_carrier_is_ready (mu_stream_t carrier, int flag,
+                                     int timeout);
+
+int _mu_pop3_xscript_level (mu_pop3_t pop3, int xlev);
+
+int _mu_pop3_trace_enable (mu_pop3_t pop3);
+int _mu_pop3_trace_disable (mu_pop3_t pop3);  
 
+int _mu_pop3_init (mu_pop3_t pop3);
+  
 /* Check for non recoverable error.
    The error is consider not recoverable if not part of the signal set:
    EAGAIN, EINPROGRESS, EINTR.
    For unrecoverable error we reset, by moving the working ptr
    to the begining of the buffer and setting the state to error.
  */
-#define MU_POP3_CHECK_EAGAIN(pop3, status) \
-do \
-  { \
-    if (status != 0) \
-      { \
-         if (status != EAGAIN && status != EINPROGRESS && status != EINTR) \
-           { \
-             pop3->io.ptr = pop3->io.buf; \
-             pop3->state = MU_POP3_ERROR; \
-           } \
-         return status; \
-      } \
-   }  \
-while (0)
+#define MU_POP3_CHECK_EAGAIN(pop3, status)     \
+  do                                           \
+    {                                          \
+      if (status != 0)                         \
+       {                                                               \
+         if (status != EAGAIN && status != EINPROGRESS && status != EINTR) \
+           {                                                           \
+             pop3->state = MU_POP3_ERROR;                              \
+           }                                                           \
+         return status;                                                \
+       }                                                               \
+    }                                                                  \
+  while (0)
 
 /* If error return.
    Check status an reset(see MU_POP2_CHECK_EAGAIN) the buffer.
   */
-#define MU_POP3_CHECK_ERROR(pop3, status) \
-do \
-  { \
-     if (status != 0) \
-       { \
-          pop3->io.ptr = pop3->io.buf; \
-          pop3->state = MU_POP3_ERROR; \
-          return status; \
-       } \
-  } \
-while (0)
+#define MU_POP3_CHECK_ERROR(pop3, status)      \
+  do                                           \
+    {                                          \
+      if (status != 0)                         \
+       {                                       \
+          pop3->state = MU_POP3_ERROR;         \
+          return status;                       \
+       }                                       \
+    }                                          \
+  while (0)
 
 /* Check if we got "+OK".
    In POP3 protocol and ack of "+OK" means the command was successfull.
  */
-#define MU_POP3_CHECK_OK(pop3) \
-do \
-  { \
-     if (mu_c_strncasecmp (pop3->ack.buf, "+OK", 3) != 0) \
-       { \
-          pop3->state = MU_POP3_NO_STATE; \
-          return EACCES; \
-       } \
-  } \
-while (0)
+#define MU_POP3_CHECK_OK(pop3)                                 \
+  do                                                           \
+    {                                                          \
+      if (mu_c_strncasecmp (pop3->ackbuf, "+OK", 3) != 0)      \
+       {                                                       \
+          pop3->state = MU_POP3_NO_STATE;                      \
+          return EACCES;                                       \
+       }                                                       \
+    }                                                          \
+  while (0)
 
 #ifdef __cplusplus
 }
diff --git a/include/mailutils/sys/prog_stream.h 
b/include/mailutils/sys/prog_stream.h
new file mode 100644
index 0000000..fa042f2
--- /dev/null
+++ b/include/mailutils/sys/prog_stream.h
@@ -0,0 +1,35 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 2009 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/>. */
+
+#ifndef _MAILUTILS_SYS_PROG_STREAM_H
+#define _MAILUTILS_SYS_PROG_STREAM_H
+
+#include <mailutils/sys/stream.h>
+
+struct _mu_prog_stream
+{
+  struct _mu_stream stream;
+  pid_t pid;
+  int status;
+  pid_t writer_pid;
+  int argc;
+  char **argv;
+  mu_stream_t in, out;
+
+  mu_stream_t input;
+};
+
+#endif
diff --git a/include/mailutils/sys/property.h b/include/mailutils/sys/property.h
new file mode 100644
index 0000000..4faac9c
--- /dev/null
+++ b/include/mailutils/sys/property.h
@@ -0,0 +1,51 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 1999, 2000, 2001, 2007, 2008, 2010 Free Software
+   Foundation, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General
+   Public License along with this library; if not, write to the
+   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301 USA */
+
+#ifndef _MAILUTILS_SYS_PROPERTY_H
+# define _MAILUTILS_SYS_PROPERTY_H
+
+# include <errno.h>
+# include <stdlib.h>
+# include <string.h>
+
+# include <mailutils/property.h>
+# include <mailutils/monitor.h>
+# include <mailutils/assoc.h>
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+struct property_item
+{
+  char *value;
+};
+
+struct _mu_property
+{
+  mu_assoc_t assoc;
+  void *owner;
+  mu_monitor_t lock;
+};
+
+# ifdef __cplusplus
+}
+# endif
+
+#endif /* _MAILUTILS_SYS_PROPERTY_H */
diff --git a/include/mailutils/sys/rdcache_stream.h 
b/include/mailutils/sys/rdcache_stream.h
new file mode 100644
index 0000000..b6434be
--- /dev/null
+++ b/include/mailutils/sys/rdcache_stream.h
@@ -0,0 +1,33 @@
+/* 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/>. */
+
+#ifndef _MAILUTILS_SYS_RDCACHE_STREAM_H
+# define _MAILUTILS_SYS_RDCACHE_STREAM_H
+
+# include <mailutils/types.h>
+# include <mailutils/stream.h>
+# include <mailutils/sys/stream.h>
+
+struct _mu_rdcache_stream
+{
+  struct _mu_stream stream;
+  mu_stream_t transport;
+  mu_stream_t cache;
+  mu_off_t size;
+  mu_off_t offset;
+};
+
+#endif
diff --git a/include/mailutils/sys/registrar.h 
b/include/mailutils/sys/registrar.h
new file mode 100644
index 0000000..8b3d83d
--- /dev/null
+++ b/include/mailutils/sys/registrar.h
@@ -0,0 +1,98 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 1999, 2000, 2004, 2005, 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 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General
+   Public License along with this library; if not, write to the
+   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301 USA */
+
+#ifndef _MAILUTILS_SYS_REGISTRAR_H
+# define _MAILUTILS_SYS_REGISTRAR_H
+
+# include <mailutils/registrar.h>
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+/* The pop and imap defines are all wrong now, since they seem intertwined
+   with the old url parsing code. Also, "pop://" is not the POP scheme,
+   at least not as a scheme is described in the RFCs.
+
+   Perhaps they can be changed?
+*/
+# define MU_POP_PORT 110
+# define MU_POP_SCHEME "pop"
+# define MU_POP_SCHEME_LEN (sizeof (MU_POP_SCHEME) - 1)
+extern int _url_pop_init          (mu_url_t);
+extern int _mailbox_pop_init      (mu_mailbox_t);
+extern int _folder_pop_init       (mu_folder_t);
+
+# define MU_POPS_PORT 995
+# define MU_POPS_SCHEME "pops"
+# define MU_POPS_SCHEME_LEN (sizeof (MU_POPS_SCHEME) - 1)
+extern int _url_pops_init         (mu_url_t);
+extern int _mailbox_pops_init     (mu_mailbox_t);
+
+# define MU_IMAP_PORT 143
+# define MU_IMAP_SCHEME "imap"
+# define MU_IMAP_SCHEME_LEN (sizeof (MU_IMAP_SCHEME) - 1)
+extern int _url_imap_init         (mu_url_t);
+extern int _mailbox_imap_init     (mu_mailbox_t);
+extern int _folder_imap_init      (mu_folder_t);
+
+# define MU_IMAPS_PORT 993
+# define MU_IMAPS_SCHEME "imaps"
+# define MU_IMAPS_SCHEME_LEN (sizeof (MU_IMAPS_SCHEME) - 1)
+extern int _url_imaps_init        (mu_url_t);
+extern int _mailbox_imaps_init    (mu_mailbox_t);
+
+# define MU_MBOX_SCHEME "mbox"
+# define MU_MBOX_SCHEME_LEN (sizeof (MU_MBOX_SCHEME) - 1)
+extern int _mailbox_mbox_init     (mu_mailbox_t);
+extern int _folder_mbox_init      (mu_folder_t);
+
+# define MU_FILE_SCHEME "file"
+# define MU_FILE_SCHEME_LEN (sizeof (MU_FILE_SCHEME) - 1)
+
+# define MU_PATH_SCHEME "/"
+# define MU_PATH_SCHEME_LEN (sizeof (MU_PATH_SCHEME) - 1)
+extern int _mailbox_path_init     (mu_mailbox_t);
+extern int _folder_path_init      (mu_folder_t);
+
+# define MU_SMTP_SCHEME "smtp"
+# define MU_SMTP_SCHEME_LEN (sizeof (MU_SMTP_SCHEME) - 1)
+# define MU_SMTP_PORT 25
+
+# define MU_SENDMAIL_SCHEME "sendmail"
+# define MU_SENDMAIL_SCHEME_LEN (sizeof (MU_SENDMAIL_SCHEME) - 1)
+extern int _mu_mailer_sendmail_init (mu_mailer_t mailer);
+  
+# define MU_PROG_SCHEME "prog"
+# define MU_PROG_SCHEME_LEN (sizeof (MU_PROG_SCHEME) - 1)
+extern int _mu_mailer_prog_init  (mu_mailer_t);  
+  
+# define MU_MH_SCHEME "mh"
+# define MU_MH_SCHEME_LEN (sizeof (MU_MH_SCHEME) - 1)
+extern int _mailbox_mh_init (mu_mailbox_t mailbox);
+
+# define MU_MAILDIR_SCHEME "maildir"
+# define MU_MAILDIR_SCHEME_LEN (sizeof (MU_MAILDIR_SCHEME) - 1)
+extern int _mailbox_maildir_init (mu_mailbox_t mailbox);
+
+# ifdef __cplusplus
+}
+# endif
+
+#endif /* _MAILUTILS_SYS_REGISTRAR_H */
diff --git a/include/mailutils/sys/stream.h b/include/mailutils/sys/stream.h
new file mode 100644
index 0000000..3e114b5
--- /dev/null
+++ b/include/mailutils/sys/stream.h
@@ -0,0 +1,84 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 2009 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/>. */
+
+#ifndef _MAILUTILS_SYS_STREAM_H
+#define _MAILUTILS_SYS_STREAM_H
+
+#define _MU_STR_DIRTY         0x1000    /* Buffer dirty */
+#define _MU_STR_WRT           0x2000    /* Unflushed write pending */
+#define _MU_STR_ERR           0x4000    /* Permanent error state */
+#define _MU_STR_EOF           0x8000    /* EOF encountered */
+
+#define _MU_STR_INTERN_MASK   0xf000
+
+#define _MU_STR_EVENT_SET     1
+#define _MU_STR_EVENT_CLR     2
+
+struct _mu_stream
+{
+  int ref_count;
+  
+  enum mu_buffer_type buftype;
+  size_t bufsize;
+  char *buffer;
+  size_t level;
+  char *cur;
+
+  int flags;
+  mu_off_t offset;
+  mu_off_t bytes_in, bytes_out;
+  
+  int last_err;
+
+  int (*read) (struct _mu_stream *, char *, size_t, size_t *);
+  int (*readdelim) (struct _mu_stream *, char *, size_t, int, size_t *);
+  int (*write) (struct _mu_stream *, const char *, size_t, size_t *);
+  int (*flush) (struct _mu_stream *);
+  int (*open) (struct _mu_stream *);
+  int (*close) (struct _mu_stream *);
+  void (*done) (struct _mu_stream *);
+  int (*seek) (struct _mu_stream *, mu_off_t, mu_off_t *);
+  int (*size) (struct _mu_stream *, mu_off_t *);
+  int (*ctl) (struct _mu_stream *, int, void *);
+  int (*wait) (struct _mu_stream *, int *, struct timeval *);
+  int (*truncate) (struct _mu_stream *, mu_off_t);
+  int (*shutdown) (struct _mu_stream *, int);
+
+  void (*event_cb) (struct _mu_stream *, int, int);
+  int  event_mask;
+  
+  const char *(*error_string) (struct _mu_stream *, int);
+  
+};
+
+mu_stream_t _mu_stream_create (size_t size, int flags);
+int mu_stream_read_unbuffered (mu_stream_t stream, void *buf, size_t size,
+                              int full_read, size_t *pnread);
+int mu_stream_write_unbuffered (mu_stream_t stream,
+                               const void *buf, size_t size,
+                               int full_write, size_t *pnwritten);
+
+void _mu_stream_cleareof (mu_stream_t str);
+void _mu_stream_seteof (mu_stream_t str);
+
+#define _MU_SWAP_FIRST_ONLY         0x01
+#define _MU_SWAP_IOCTL_MUST_SUCCEED 0x02
+
+int _mu_stream_swap_streams (mu_stream_t stream, mu_stream_t *curtrans,
+                            mu_stream_t *newtrans, int flags);
+
+
+#endif
diff --git a/include/mailutils/sys/streamref.h 
b/include/mailutils/sys/streamref.h
new file mode 100644
index 0000000..35f035e
--- /dev/null
+++ b/include/mailutils/sys/streamref.h
@@ -0,0 +1,34 @@
+/* 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/>. */
+
+#ifndef _MAILUTILS_SYS_STREAMREF_H
+#define _MAILUTILS_SYS_STREAMREF_H
+
+#include <mailutils/types.h>
+#include <mailutils/sys/stream.h>
+
+struct _mu_streamref
+{
+  struct _mu_stream stream;      /* Superclass */
+  mu_stream_t transport;         /* Transport stream */
+  mu_off_t offset;               /* Offset in transport stream */
+                            /* For abridged stream references: */
+  mu_off_t start;                /* Start offset */
+  mu_off_t end;                  /* End offset */
+};
+
+#endif
+
diff --git a/include/mailutils/sys/streamtrans.h 
b/include/mailutils/sys/streamtrans.h
new file mode 100644
index 0000000..25bc0d9
--- /dev/null
+++ b/include/mailutils/sys/streamtrans.h
@@ -0,0 +1,27 @@
+/* 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/>. */
+
+#ifndef _MAILUTILS_SYS_STREAMTRANS_H
+#define _MAILUTILS_SYS_STREAMTRANS_H
+
+#include <mailutils/types.h>
+#include <mailutils/sys/stream.h>
+
+struct _mu_streamtrans
+{
+  struct _mu_stream base;      /* Superclass */
+  mu_stream_t transport;       /* Transport stream */
+};
diff --git a/include/mailutils/sys/tls-stream.h 
b/include/mailutils/sys/tls-stream.h
new file mode 100644
index 0000000..8a903b9
--- /dev/null
+++ b/include/mailutils/sys/tls-stream.h
@@ -0,0 +1,57 @@
+/* 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/>. */
+
+#ifndef _MAILUTILS_SYS_TLS_STREAM_H
+# define _MAILUTILS_SYS_TLS_STREAM_H
+
+# include <mailutils/types.h>
+# include <mailutils/stream.h>
+# include <mailutils/sys/stream.h>
+
+enum _mu_tls_stream_state
+  {
+    state_init,
+    state_open,
+    state_closed,
+    state_destroyed
+  };
+
+struct _mu_tls_io_stream
+{
+  struct _mu_stream stream;
+  mu_stream_t transport;
+  struct _mu_tls_stream *up;
+};
+
+struct _mu_tls_stream
+{
+  struct _mu_stream stream;
+  enum _mu_tls_stream_state state;
+  gnutls_session session;
+  int tls_err;
+  mu_stream_t transport[2];
+};
+
+struct _mu_tls_stream_s
+{
+  struct _mu_stream stream;
+  enum _mu_tls_stream_state state;
+  gnutls_session session;
+  int tls_err;
+  mu_stream_t transport;
+};
+
+#endif
diff --git a/include/mailutils/sys/url.h b/include/mailutils/sys/url.h
new file mode 100644
index 0000000..8e300ba
--- /dev/null
+++ b/include/mailutils/sys/url.h
@@ -0,0 +1,66 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 1999, 2000, 2005, 2007, 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 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General
+   Public License along with this library; if not, write to the
+   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301 USA */
+
+#ifndef _MAILUTILS_SYS_URL_H
+# define _MAILUTILS_SYS_URL_H
+
+# include <mailutils/url.h>
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+struct _mu_url
+{
+  /* Data */
+  char  *name;
+  char  *scheme;
+  char  *user;
+  mu_secret_t secret;
+  char  *auth;
+  char  *host;
+  long  port;
+  char  *path;
+  char  **fvpairs;
+  int   fvcount;
+
+  char  **qargv;
+  int   qargc;
+  
+  void  *data;
+
+  void  (*_destroy)    (mu_url_t url);
+
+  /* Methods */
+  int   (*_get_scheme) (const mu_url_t, char *, size_t, size_t *);
+  int   (*_get_user)   (const mu_url_t, char *, size_t, size_t *);
+  int   (*_get_secret) (const mu_url_t, mu_secret_t *);
+  int   (*_get_auth)   (const mu_url_t, char *, size_t, size_t *);
+  int   (*_get_host)   (const mu_url_t, char *, size_t, size_t *);
+  int   (*_get_port)   (const mu_url_t, long *);
+  int   (*_get_path)   (const mu_url_t, char *, size_t, size_t *);
+  int   (*_get_query)  (const mu_url_t, char *, size_t, size_t *);
+  int   (*_uplevel)    (const mu_url_t, mu_url_t *);
+};
+
+# ifdef __cplusplus
+}
+# endif
+
+#endif /* _MAILUTILS_SYS_URL_H */
diff --git a/include/mailutils/sys/xscript-stream.h 
b/include/mailutils/sys/xscript-stream.h
new file mode 100644
index 0000000..0f58bb9
--- /dev/null
+++ b/include/mailutils/sys/xscript-stream.h
@@ -0,0 +1,34 @@
+/* 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/>. */
+
+#ifndef _MAILUTILS_SYS_XSCRIPT_STREAM_H
+# define _MAILUTILS_SYS_XSCRIPT_STREAM_H
+
+# include <mailutils/types.h>
+# include <mailutils/stream.h>
+# include <mailutils/sys/stream.h>
+
+struct _mu_xscript_stream
+{
+  struct _mu_stream stream;
+  mu_stream_t transport;
+  mu_stream_t logstr;
+  int flags;
+  int level;
+  char *prefix[2];
+};
+
+#endif
diff --git a/include/mailutils/tls.h b/include/mailutils/tls.h
index 9848f82..dc630a2 100644
--- a/include/mailutils/tls.h
+++ b/include/mailutils/tls.h
@@ -36,30 +36,17 @@ struct mu_tls_module_config
 
 extern int mu_tls_module_init (enum mu_gocs_op, void *);
 
-extern int mu_tls_stream_create (mu_stream_t *stream, 
-                                mu_stream_t strin, mu_stream_t strout,
-                                int flags);
-extern int mu_tls_stream_create_client (mu_stream_t *stream,
+extern int mu_tls_server_stream_create (mu_stream_t *stream, 
+                                       mu_stream_t strin, mu_stream_t strout,
+                                       int flags);
+extern int mu_tls_client_stream_create (mu_stream_t *stream,
                                        mu_stream_t strin, mu_stream_t strout,
                                        int flags);
-extern int mu_tls_stream_create_client_from_tcp (mu_stream_t *stream,
-                                                mu_stream_t tcp_str,
-                                                int flags);
 
 extern int mu_check_tls_environment (void);
 extern int mu_init_tls_libs (void);
 extern void mu_deinit_tls_libs (void);
 
-typedef int (*mu_tls_readline_fn) (void *iodata);
-typedef int (*mu_tls_writeline_fn) (void *iodata, char *buf); 
-typedef void (*mu_tls_stream_ctl_fn) (void *iodata, mu_stream_t *pold,
-                                     mu_stream_t __new);
-
-extern int mu_tls_begin (void *iodata, mu_tls_readline_fn reader,
-                        mu_tls_writeline_fn writer,
-                        mu_tls_stream_ctl_fn stream_ctl,
-                        char *keywords[]);
-
 extern int mu_tls_enable;
   
 #ifdef __cplusplus
diff --git a/include/mailutils/types.hin b/include/mailutils/types.hin
index 019e66f..c492a5c 100644
--- a/include/mailutils/types.hin
+++ b/include/mailutils/types.hin
@@ -38,6 +38,9 @@
 extern "C" {
 #endif
 
+struct mu_core_class;  
+struct mu_core_object;
+  
 struct mu_address;
 struct _mu_attribute;
 struct _mu_authority;
@@ -72,7 +75,7 @@ struct _mu_server;
 struct _mu_tcp_server;
   
 typedef _MU_OFF_TYPE_ mu_off_t;
-  
+
 typedef struct mu_address *mu_address_t;
 typedef struct _mu_attribute *mu_attribute_t;
 typedef struct _mu_authority *mu_authority_t;
diff --git a/lib/allocsa.valgrind b/lib/allocsa.valgrind
deleted file mode 100644
index f4c77d6..0000000
--- a/lib/allocsa.valgrind
+++ /dev/null
@@ -1,7 +0,0 @@
-# Suppress a valgrind message about use of uninitialized memory in freesa().
-# This use is OK because it provides only a speedup.
-{
-    freesa
-    Memcheck:Cond
-    fun:freesa
-}
diff --git a/lib/mailcap.c b/lib/mailcap.c
index 88eab36..752a965 100644
--- a/lib/mailcap.c
+++ b/lib/mailcap.c
@@ -208,8 +208,10 @@ mime_context_write_input (struct mime_context *ctx, int fd)
   int status;
   
   mime_context_get_input (ctx, &input);
-  mu_stream_seek (input, 0, SEEK_SET);
-  while ((status = mu_stream_sequential_read (input, buf, sizeof buf, &n)) == 0
+  status = mu_stream_seek (input, 0, SEEK_SET, NULL);
+  if (status)
+    abort (); /* FIXME */
+  while ((status = mu_stream_read (input, buf, sizeof buf, &n)) == 0
         && n)
     write (fd, buf, n);
 }
@@ -603,7 +605,7 @@ find_entry (const char *file, struct mime_context *ctx)
   status = mu_stream_open (stream);
   if (status)
     {
-      mu_stream_destroy (&stream, mu_stream_get_owner (stream));
+      mu_stream_destroy (&stream);
       if (status != ENOENT)
        mu_error ("cannot open file stream %s: %s",
                  file, mu_strerror (status));
diff --git a/lib/mu_dbm.c b/lib/mu_dbm.c
index b62818a..f18cda8 100644
--- a/lib/mu_dbm.c
+++ b/lib/mu_dbm.c
@@ -32,6 +32,7 @@
 #endif
 #include <errno.h>
 #include <mailutils/errno.h>
+#include <mailutils/stream.h>
 #include <mu_dbm.h>
 #include <xalloc.h>
 
diff --git a/lib/mu_dbm.h b/lib/mu_dbm.h
index 87c3487..45b868c 100644
--- a/lib/mu_dbm.h
+++ b/lib/mu_dbm.h
@@ -17,8 +17,6 @@
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
    MA 02110-1301 USA */
 
-#include <mailutils/stream.h>
-
 #if defined(WITH_GDBM)
 
 #include <gdbm.h>
diff --git a/libmu_argp/Makefile.am b/libmu_argp/Makefile.am
index 3106f5c..87fd420 100644
--- a/libmu_argp/Makefile.am
+++ b/libmu_argp/Makefile.am
@@ -32,7 +32,6 @@ libmu_argp_a_SOURCES =\
  cmdline.h\
  common.c\
  compat.c\
- mu_argp.h\
  mu_argp.c\
  muinit.c\
  sieve.c\
diff --git a/libmu_argp/mu_argp.h b/libmu_argp/mu_argp.h
deleted file mode 100644
index 804f46c..0000000
--- a/libmu_argp/mu_argp.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 1999, 2000, 2001, 2004, 2005, 2007, 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 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General
-   Public License along with this library; if not, write to the
-   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301 USA */
-
-#ifndef _MAILUTILS_ARGP_H
-#define _MAILUTILS_ARGP_H
-
-#include <mailutils/types.h>
-#include <argp.h>
-#include <errno.h> /* May declare program_invocation_name */
-
-extern char *mu_license_text;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-extern void mu_argp_init (struct argp *argp, const char *vers,
-                         const char *bugaddr, const char *capa[]);
-extern void mu_argp_done (struct argp *argp);
-  
-extern int mu_register_argp_capa (const char *name, struct argp_child *child);
-
-extern void mu_print_options (void);
-  
-#ifdef __cplusplus
-}
-#endif
-
-#endif
-
diff --git a/libmu_argp/muinit.c b/libmu_argp/muinit.c
index 3853f0f..5471116 100644
--- a/libmu_argp/muinit.c
+++ b/libmu_argp/muinit.c
@@ -25,13 +25,48 @@
 #include <mailutils/stream.h>
 #include "xalloc.h"
 #include <string.h>
-
+#ifdef MU_ALPHA_RELEASE
+# include <git-describe.h>
+#endif
 struct mu_cfg_tree *mu_argp_tree;
 
+const char version_etc_copyright[] =
+  /* Do *not* mark this string for translation.  %s is a copyright
+     symbol suitable for this locale, and %d is the copyright
+     year.  */
+  "Copyright %s 2010 Free Software Foundation, inc.";
+
+void
+mu_program_version_hook (FILE *stream, struct argp_state *state)
+{
+#ifdef GIT_DESCRIBE
+  fprintf (stream, "%s (%s) %s [%s]\n",
+          mu_program_name, PACKAGE_NAME, PACKAGE_VERSION, GIT_DESCRIBE);
+#else
+  fprintf (stream, "%s (%s) %s\n", mu_program_name,
+          PACKAGE_NAME, PACKAGE_VERSION);
+#endif
+  /* TRANSLATORS: Translate "(C)" to the copyright symbol
+     (C-in-a-circle), if this symbol is available in the user's
+     locale.  Otherwise, do not translate "(C)"; leave it as-is.  */
+  fprintf (stream, version_etc_copyright, _("(C)"));
+
+  fputs (_("\
+\n\
+License GPLv3+: GNU GPL version 3 or later 
<http://gnu.org/licenses/gpl.html>\nThis is free software: you are free to 
change and redistribute it.\n\
+There is NO WARRANTY, to the extent permitted by law.\n\
+\n\
+"),
+        stream);
+}
+
 void
 mu_argp_init (const char *vers, const char *bugaddr)
 {
-  argp_program_version = vers ? vers : PACKAGE_STRING;
+  if (vers)
+    argp_program_version = vers;
+  else
+    argp_program_version_hook = mu_program_version_hook;
   argp_program_bug_address = bugaddr ? bugaddr : "<" PACKAGE_BUGREPORT ">";
 }
 
@@ -40,8 +75,10 @@ get_canonical_name ()
 {
   char *name;
   size_t len;
-  char *p = strchr (argp_program_version, ' ');
-  if (!p)
+  char *p;
+
+  if (!argp_program_version ||
+      !(p = strchr (argp_program_version, ' ')))
     return strdup (mu_program_name);
   len = p - argp_program_version;
   name = malloc (len + 1);
@@ -95,8 +132,7 @@ mu_app_init (struct argp *myargp, const char **capa,
       char *comment;
       char *canonical_name = get_canonical_name ();
       mu_stream_t stream;
-      mu_stdio_stream_create (&stream, stdout,
-                             MU_STREAM_NO_CHECK|MU_STREAM_NO_CLOSE);
+      mu_stdio_stream_create (&stream, MU_STDOUT_FD, 0);
       mu_stream_open (stream);
       asprintf (&comment,
                "Configuration file structure for %s utility.",
@@ -116,7 +152,7 @@ mu_app_init (struct argp *myargp, const char **capa,
       free (comment);
       
       mu_format_config_tree (stream, mu_program_name, cfg_param, 0);
-      mu_stream_destroy (&stream, NULL);
+      mu_stream_destroy (&stream);
       exit (0);
     }
 
diff --git a/libmu_auth/Makefile.am b/libmu_auth/Makefile.am
index 0f97e55..2533ffb 100644
--- a/libmu_auth/Makefile.am
+++ b/libmu_auth/Makefile.am
@@ -26,8 +26,6 @@ lib_LTLIBRARIES = libmu_auth.la
 
 libmu_auth_la_SOURCES = \
  gsasl.c\
- lbuf.c\
- lbuf.h\
  ldap.c\
  pam.c\
  radius.c\
diff --git a/libmu_auth/gsasl.c b/libmu_auth/gsasl.c
index 230a275..d03f3e2 100644
--- a/libmu_auth/gsasl.c
+++ b/libmu_auth/gsasl.c
@@ -33,9 +33,10 @@
 #include <mailutils/nls.h>
 #include <mailutils/stream.h>
 #include <mailutils/gsasl.h>
+#include <mailutils/sys/gsasl-stream.h>
+#include <mailutils/filter.h>
 
 #include <gsasl.h>
-#include <lbuf.h>
 
 struct mu_gsasl_module_data mu_gsasl_module_data = {
     SITE_CRAM_MD5_PWD
@@ -49,235 +50,172 @@ mu_gsasl_module_init (enum mu_gocs_op op, void *data)
   return 0;
 }
 
-struct _gsasl_stream {
-  Gsasl_session *sess_ctx; /* Context */
-  int last_err;        /* Last Gsasl error code */
-  
-  mu_stream_t stream;     /* I/O stream */
-  struct _line_buffer *lb; 
-};
-
-static void
-_gsasl_destroy (mu_stream_t stream)
-{
-  int flags;
-  struct _gsasl_stream *s = mu_stream_get_owner (stream);
-  mu_stream_get_flags (stream, &flags);
-  if (!(flags & MU_STREAM_NO_CLOSE))
-    mu_stream_destroy (&s->stream, mu_stream_get_owner (s->stream));
-  _auth_lb_destroy (&s->lb);
-}
-
-static int
-_gsasl_readline (mu_stream_t stream, char *optr, size_t osize,
-                off_t offset, size_t *nbytes)
+
+static enum mu_filter_result
+_gsasl_encoder (void *xdata,
+               enum mu_filter_command cmd,
+               struct mu_filter_io *iobuf)
 {
-  struct _gsasl_stream *s = mu_stream_get_owner (stream);
-  int rc;
-  size_t len, sz;
-  char *bufp = NULL;
+  struct _mu_gsasl_filter *flt = xdata;
   
-  if (_auth_lb_level (s->lb))
+  switch (cmd)
     {
-      len = _auth_lb_readline (s->lb, optr, osize-1);
-      optr[len] = 0;
-      if (nbytes)
-       *nbytes = len;
-      return 0;
+    case mu_filter_init:
+      flt->bufptr = NULL;
+      flt->bufsize = 0;
+      flt->gsasl_err = 0;
+      return mu_filter_ok;
+      
+    case mu_filter_done:
+      if (flt->bufptr)
+       free (flt->bufptr);
+      free (flt);
+      return mu_filter_ok;
+      
+    default:
+      break;
     }
 
-  do
+  if (flt->bufptr == NULL)
     {
-      char c;
-      size_t sz;
-      int status;
-      
-      status = mu_stream_sequential_read (s->stream, &c, 1, &sz);
-      if (status == EINTR)
-       continue;
-      else if (status)
+      int status = gsasl_encode (flt->sess_ctx, iobuf->input, iobuf->isize,
+                                &flt->bufptr, &flt->bufsize);
+      /* FIXME: Can it require more input? */
+      if (status)
        {
-         free (bufp);
-         return status;
+         flt->gsasl_err = status;
+         return mu_filter_falure;
        }
-      rc = _auth_lb_grow (s->lb, &c, sz);
-      if (rc)
-       return rc;
-      
-      rc = gsasl_decode (s->sess_ctx,
-                        _auth_lb_data (s->lb),
-                        _auth_lb_level (s->lb),
-                        &bufp, &len);
     }
-  while (rc == GSASL_NEEDS_MORE);
+    
+  iobuf->osize = flt->bufsize;
 
-  if (rc != GSASL_OK)
-    {
-      s->last_err = rc;
-      free (bufp);
-      return EIO;
-    }
-      
-  sz = len > osize ? osize : len;
-  
-  if (len > osize)
-    {
-      memcpy (optr, bufp, osize);
-      _auth_lb_drop (s->lb);
-      _auth_lb_grow (s->lb, bufp + osize, len - osize);
-      len = osize;
-    }
-  else
-    {
-      _auth_lb_drop (s->lb);
-      memcpy (optr, bufp, len);
-    }
+  if (flt->bufsize > iobuf->osize)
+    return mu_filter_moreoutput;
 
-  if (len < osize)
-    optr[len] = 0;
-  
-  if (nbytes)
-    *nbytes = len;
-  
-  free (bufp);
+  memcpy (iobuf->output, flt->bufptr, flt->bufsize);
 
-  return 0;
+  free (flt->bufptr);
+  flt->bufptr = NULL;
+  flt->bufsize = 0;
+  
+  return mu_filter_ok;
 }
-
-int
-write_chunk (void *data, char *start, char *end)
+       
+       
+static enum mu_filter_result
+_gsasl_decoder (void *xdata,
+               enum mu_filter_command cmd,
+               struct mu_filter_io *iobuf)
 {
-  struct _gsasl_stream *s = data;
-  size_t chunk_size = end - start + 1;
-  size_t len = 0;
-  char *buf = NULL;
+  struct _mu_gsasl_filter *flt = xdata;
   int status;
-    
-  gsasl_encode (s->sess_ctx, start, chunk_size, &buf, &len);
-
-  status = mu_stream_sequential_write (s->stream, buf, len);
   
-  free (buf);
+  switch (cmd)
+    {
+    case mu_filter_init:
+      flt->bufptr = NULL;
+      flt->bufsize = 0;
+      flt->gsasl_err = 0;
+      return mu_filter_ok;
+      
+    case mu_filter_done:
+      if (flt->bufptr)
+       free (flt->bufptr);
+      free (flt);
+      return mu_filter_ok;
+      
+    default:
+      break;
+    }
 
-  return status;
-}
+  if (flt->bufptr == NULL)
+    {
+      status = gsasl_decode (flt->sess_ctx, iobuf->input, iobuf->isize,
+                            &flt->bufptr, &flt->bufsize);
+      switch (status)
+       {
+       case GSASL_OK:
+         break;
+         
+       case GSASL_NEEDS_MORE:
+         iobuf->isize++;
+         return mu_filter_moreinput;
+         
+       default:
+         flt->gsasl_err = status;
+         return mu_filter_falure;
+       }
+    }
 
+  iobuf->osize = flt->bufsize;
 
-static int
-_gsasl_write (mu_stream_t stream, const char *iptr, size_t isize,
-             off_t offset, size_t *nbytes)
-{
-  int rc;
-  struct _gsasl_stream *s = mu_stream_get_owner (stream);
+  if (flt->bufsize > iobuf->osize)
+    return mu_filter_moreoutput;
   
-  rc = _auth_lb_grow (s->lb, iptr, isize);
-  if (rc)
-    return rc;
-
-  return _auth_lb_writelines (s->lb, iptr, isize, offset,
-                             write_chunk, s, nbytes);      
-}
-
-static int
-_gsasl_flush (mu_stream_t stream)
-{
-  struct _gsasl_stream *s = mu_stream_get_owner (stream);
-  return mu_stream_flush (s->stream);
-}
+  memcpy (iobuf->output, flt->bufptr, flt->bufsize);
 
-static int
-_gsasl_close (mu_stream_t stream)
-{
-  int flags;
-  struct _gsasl_stream *s = mu_stream_get_owner (stream);
-
-  mu_stream_get_flags (stream, &flags);
-  if (!(flags & MU_STREAM_NO_CLOSE))
-    mu_stream_close (s->stream);
-  return 0;
-}
-
-static int
-_gsasl_open (mu_stream_t stream)
-{
-  /* Nothing to do */
-  return 0;
-}
-
-int
-_gsasl_strerror (mu_stream_t stream, const char **pstr)
-{
-  struct _gsasl_stream *s = mu_stream_get_owner (stream);
-  *pstr = gsasl_strerror (s->last_err);
-  return 0;
+  free (flt->bufptr);
+  flt->bufptr = NULL;
+  flt->bufsize = 0;
+  
+  return mu_filter_ok;
 }
-
+  
 int
-_gsasl_get_transport2 (mu_stream_t stream, mu_transport_t *pt, mu_transport_t 
*pt2)
+gsasl_encoder_stream (mu_stream_t *pstr, mu_stream_t transport,
+                     Gsasl_session *ctx, int flags)
 {
-  struct _gsasl_stream *s = mu_stream_get_owner (stream);
-  *pt2 = NULL; /* FIXME 1 */
-  *pt = (mu_transport_t) s->stream;
-  return 0;
+  int rc;
+  struct _mu_gsasl_filter *flt = calloc (1, sizeof (*flt));
+  flt->sess_ctx = ctx;
+  rc = mu_filter_stream_create (pstr, transport, 
+                               MU_FILTER_ENCODE, 
+                               _gsasl_encoder,
+                               flt, flags);
+  if (rc == 0)
+    mu_stream_set_buffer (*pstr, mu_buffer_line, 1024);
+  return rc;
 }
 
 int
-_gsasl_wait (mu_stream_t stream, int *pflags, struct timeval *tvp)
+gsasl_decoder_stream (mu_stream_t *pstr, mu_stream_t transport,
+                     Gsasl_session *ctx, int flags)
 {
-  int flags;
-  struct _gsasl_stream *s = mu_stream_get_owner (stream);
-
-  mu_stream_get_flags (stream, &flags);
-  if (((*pflags & MU_STREAM_READY_RD) && !(flags & MU_STREAM_READ))
-      || ((*pflags & MU_STREAM_READY_WR) && !(flags & MU_STREAM_WRITE)))
-    return EINVAL; 
-  return mu_stream_wait (s->stream, pflags, tvp);
+  int rc;
+  struct _mu_gsasl_filter *flt = calloc (1, sizeof (*flt));
+  flt->sess_ctx = ctx;
+  rc = mu_filter_stream_create (pstr, transport, 
+                               MU_FILTER_DECODE, 
+                               _gsasl_decoder,
+                               flt, flags);
+  if (rc == 0)
+    mu_stream_set_buffer (*pstr, mu_buffer_line, 1024);
+  return rc;
 }
 
 int
 mu_gsasl_stream_create (mu_stream_t *stream, mu_stream_t transport,
                        Gsasl_session *ctx, int flags)
 {
-  struct _gsasl_stream *s;
   int rc;
-    
+  mu_stream_t in, out;
+  
   if (stream == NULL)
     return MU_ERR_OUT_PTR_NULL;
-
-  if ((flags & ~(MU_STREAM_READ|MU_STREAM_WRITE))
-      || (flags & (MU_STREAM_READ|MU_STREAM_WRITE)) ==
-          (MU_STREAM_READ|MU_STREAM_WRITE))
-    return EINVAL;
-  
-  s = calloc (1, sizeof (*s));
-  if (s == NULL)
-    return ENOMEM;
-
-  s->stream = transport;
-  s->sess_ctx = ctx;
-  
-  rc = mu_stream_create (stream, flags|MU_STREAM_NO_CHECK, s);
+  rc = gsasl_encoder_stream (&in, transport, ctx, MU_STREAM_READ);
+  if (rc)
+    return rc;
+  rc = gsasl_encoder_stream (&out, transport, ctx, MU_STREAM_WRITE);
   if (rc)
     {
-      free (s);
+      mu_stream_destroy (&in);
       return rc;
     }
-
-  mu_stream_set_open (*stream, _gsasl_open, s);
-  mu_stream_set_close (*stream, _gsasl_close, s);
-  mu_stream_set_flush (*stream, _gsasl_flush, s);
-  mu_stream_set_destroy (*stream, _gsasl_destroy, s);
-  mu_stream_set_strerror (*stream, _gsasl_strerror, s);
-  mu_stream_set_wait (*stream, _gsasl_wait, s);
-  mu_stream_set_get_transport2 (*stream, _gsasl_get_transport2, s);
-  if (flags & MU_STREAM_READ)
-    mu_stream_set_readline (*stream, _gsasl_readline, s);
-  else
-    mu_stream_set_write (*stream, _gsasl_write, s);
-
-  _auth_lb_create (&s->lb);
-  
-  return 0;
+  rc = mu_iostream_create (stream, in, out);
+  mu_stream_unref (in);
+  mu_stream_unref (out);
+  return rc;
 }
   
 #endif
diff --git a/libmu_auth/lbuf.c b/libmu_auth/lbuf.c
deleted file mode 100644
index ac80284..0000000
--- a/libmu_auth/lbuf.c
+++ /dev/null
@@ -1,167 +0,0 @@
-/* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 2003, 2007, 2010 Free Software Foundation, Inc.
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General
-   Public License along with this library; if not, write to the
-   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301 USA */
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <lbuf.h>
-
-struct _line_buffer {
-  char *buffer;        /* Line buffer */
-  size_t size;         /* Allocated size */
-  size_t level;        /* Current filling level */
-};
-
-int
-_auth_lb_create (struct _line_buffer **s)
-{
-  *s = malloc (sizeof (**s));
-  if (!*s)
-    return ENOMEM;
-  (*s)->buffer = NULL;
-  (*s)->size = 0;
-  (*s)->level = 0;
-  return 0;
-}
-
-void
-_auth_lb_destroy (struct _line_buffer **s)
-{
-  if (s && *s)
-    {
-      free ((*s)->buffer);
-      free (*s);
-      *s = NULL;
-    }
-}
-
-void
-_auth_lb_drop (struct _line_buffer *s)
-{
-  s->level = 0;
-}
-
-int
-_auth_lb_grow (struct _line_buffer *s, const char *ptr, size_t size)
-{
-  if (!s->buffer)
-    {
-      s->buffer = malloc (size);
-      s->size = size;
-      s->level = 0;
-    }
-  else if (s->size - s->level < size)
-    {
-      size_t newsize = s->size + size;
-      s->buffer = realloc (s->buffer, newsize);
-      if (s->buffer)
-       s->size = newsize;
-    }
-
-  if (!s->buffer)
-    return ENOMEM;
-  
-  memcpy (s->buffer + s->level, ptr, size);
-  s->level += size;
-  return 0;
-}
-
-int
-_auth_lb_read (struct _line_buffer *s, char *optr, size_t osize)
-{
-  int len;
-
-  len = s->level > osize ? osize : s->level;
-  memcpy (optr, s->buffer, len);
-  if (s->level > len)
-    {
-      memmove (s->buffer, s->buffer + len, s->level - len);
-      s->level -= len;
-    }
-  else if (s->level == len)
-    s->level = 0;
-    
-  return len;
-}
-
-int
-_auth_lb_readline (struct _line_buffer *s, char *ptr, size_t size)
-{
-  char *p = strchr (s->buffer, '\n');
-
-  if (p && p - s->buffer + 1 < size)
-    size = p - s->buffer + 1;
-  return _auth_lb_read (s, ptr, size);
-}
-
-int
-_auth_lb_writelines (struct _line_buffer *s, const char *iptr, size_t isize,
-                    off_t offset,
-                    int (*wr) (void *data, char *start, char *end),
-                    void *data,
-                    size_t *nbytes)
-{
-  if (s->level > 2)
-    {
-      char *start, *end;
-      
-      for (start = s->buffer,
-                  end = memchr (start, '\n', s->buffer + s->level - start);
-          end && end < s->buffer + s->level;
-          start = end + 1,
-                  end = memchr (start, '\n', s->buffer + s->level - start))
-       if (end[-1] == '\r')
-         {
-           int rc = wr (data, start, end);
-           if (rc)
-             return rc;
-         }
-
-      if (start > s->buffer)
-       {
-         if (start < s->buffer + s->level)
-           {
-             int rest = s->buffer + s->level - start;
-             memmove (s->buffer, start, rest);
-             s->level = rest;
-           }
-         else 
-           s->level = 0;
-       }
-    }
-
-  if (nbytes)
-    *nbytes = isize;
-  return 0;
-}
-
-int
-_auth_lb_level (struct _line_buffer *s)
-{
-  return s->level;
-}
-
-char *
-_auth_lb_data (struct _line_buffer *s)
-{
-  return s->buffer;
-}
diff --git a/libmu_auth/lbuf.h b/libmu_auth/lbuf.h
deleted file mode 100644
index 2b7c060..0000000
--- a/libmu_auth/lbuf.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 2003, 2005, 2007, 2010 Free Software Foundation, Inc.
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General
-   Public License along with this library; if not, write to the
-   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301 USA */
-
-#include <mailutils/types.h>
-
-struct _line_buffer;
-
-int _auth_lb_create (struct _line_buffer **s);
-void _auth_lb_destroy (struct _line_buffer **s);
-void _auth_lb_drop (struct _line_buffer *s);
-
-int _auth_lb_grow (struct _line_buffer *s, const char *ptr, size_t size);
-int _auth_lb_read (struct _line_buffer *s, char *ptr, size_t size);
-int _auth_lb_readline (struct _line_buffer *s, char *ptr, size_t size);
-int _auth_lb_writelines (struct _line_buffer *s, const char *iptr,
-                        size_t isize, off_t offset,
-                        int (*wr) (void *data, char *start, char *end),
-                        void *data, size_t *nbytes);
-int _auth_lb_level (struct _line_buffer *s);
-char *_auth_lb_data (struct _line_buffer *s);
-
-
diff --git a/libmu_auth/ldap.c b/libmu_auth/ldap.c
index 3fdedfb..5ced397 100644
--- a/libmu_auth/ldap.c
+++ b/libmu_auth/ldap.c
@@ -594,14 +594,14 @@ chk_md5 (const char *db_pass, const char *pass)
   mu_md5_process_bytes (pass, strlen (pass), &md5context);
   mu_md5_finish_ctx (&md5context, md5digest);
 
-  mu_memory_stream_create (&str, NULL, MU_STREAM_NO_CHECK);
+  mu_memory_stream_create (&str, 0);
   mu_filter_create (&flt, str, "base64", MU_FILTER_DECODE,
-                   MU_STREAM_READ | MU_STREAM_NO_CHECK);
+                   MU_STREAM_READ | MU_STREAM_AUTOCLOSE);
   mu_stream_open (str);
-  mu_stream_sequential_write (str, db_pass, strlen (db_pass));
+  mu_stream_write (str, db_pass, strlen (db_pass), NULL);
 
-  mu_stream_read (flt, (char*) d1, sizeof d1, 0, NULL);
-  mu_stream_destroy (&flt, NULL);
+  mu_stream_read (flt, (char*) d1, sizeof d1, NULL);
+  mu_stream_destroy (&flt);
   
   return memcmp (md5digest, d1, sizeof md5digest) == 0 ?
                   0 : MU_ERR_AUTH_FAILURE;
@@ -617,22 +617,22 @@ chk_smd5 (const char *db_pass, const char *pass)
   mu_stream_t str = NULL, flt = NULL;
   size_t size;
   
-  mu_memory_stream_create (&str, NULL, MU_STREAM_NO_CHECK);
+  mu_memory_stream_create (&str, 0);
   mu_filter_create (&flt, str, "base64", MU_FILTER_DECODE,
-                   MU_STREAM_READ | MU_STREAM_NO_CHECK);
+                   MU_STREAM_READ | MU_STREAM_AUTOCLOSE);
   mu_stream_open (str);
   size = strlen (db_pass);
-  mu_stream_sequential_write (str, db_pass, size);
+  mu_stream_write (str, db_pass, size, NULL);
 
   d1 = malloc (size);
   if (!d1)
     {
-      mu_stream_destroy (&flt, NULL);
+      mu_stream_destroy (&flt);
       return ENOMEM;
     }
   
-  mu_stream_read (flt, (char*) d1, size, 0, &size);
-  mu_stream_destroy (&flt, NULL);
+  mu_stream_read (flt, (char*) d1, size, &size);
+  mu_stream_destroy (&flt);
 
   if (size <= 16)
     {
@@ -663,14 +663,14 @@ chk_sha (const char *db_pass, const char *pass)
   mu_sha1_process_bytes (pass, strlen (pass), &sha1context);
   mu_sha1_finish_ctx (&sha1context, sha1digest);
 
-  mu_memory_stream_create (&str, NULL, MU_STREAM_NO_CHECK);
+  mu_memory_stream_create (&str, 0);
   mu_filter_create (&flt, str, "base64", MU_FILTER_DECODE,
-                   MU_STREAM_READ | MU_STREAM_NO_CHECK);
+                   MU_STREAM_READ | MU_STREAM_AUTOCLOSE);
   mu_stream_open (str);
-  mu_stream_sequential_write (str, db_pass, strlen (db_pass));
+  mu_stream_write (str, db_pass, strlen (db_pass), NULL);
 
-  mu_stream_read (flt, (char*) d1, sizeof d1, 0, NULL);
-  mu_stream_destroy (&flt, NULL);
+  mu_stream_read (flt, (char*) d1, sizeof d1, NULL);
+  mu_stream_destroy (&flt);
   
   return memcmp (sha1digest, d1, sizeof sha1digest) == 0 ?
                   0 : MU_ERR_AUTH_FAILURE;
@@ -686,23 +686,22 @@ chk_ssha (const char *db_pass, const char *pass)
   mu_stream_t str = NULL, flt = NULL;
   size_t size;
   
-  mu_memory_stream_create (&str, NULL, MU_STREAM_NO_CHECK);
+  mu_memory_stream_create (&str, 0);
   mu_filter_create (&flt, str, "base64", MU_FILTER_DECODE,
-                   MU_STREAM_READ | MU_STREAM_NO_CHECK);
+                   MU_STREAM_READ | MU_STREAM_AUTOCLOSE);
   mu_stream_open (str);
   size = strlen (db_pass);
-  mu_stream_sequential_write (str, db_pass, size);
+  mu_stream_write (str, db_pass, size, NULL);
 
   d1 = malloc (size);
   if (!d1)
     {
-      mu_stream_destroy (&flt, NULL);
+      mu_stream_destroy (&flt);
       return ENOMEM;
     }
   
-  mu_stream_read (flt, (char*) d1, size, 0, &size);
-  mu_stream_destroy (&flt, NULL);
-  mu_stream_destroy (&str, NULL);
+  mu_stream_read (flt, (char*) d1, size, &size);
+  mu_stream_destroy (&flt);
 
   if (size <= 16)
     {
diff --git a/libmu_auth/tls.c b/libmu_auth/tls.c
index 9d28f9e..2d3bd81 100644
--- a/libmu_auth/tls.c
+++ b/libmu_auth/tls.c
@@ -35,8 +35,6 @@
 #include <mailutils/stream.h>
 #include <mailutils/errno.h>
 
-#include <lbuf.h>
-
 struct mu_tls_module_config mu_tls_module_config = { 1, NULL, NULL, NULL };
   
 int
@@ -48,7 +46,7 @@ mu_tls_module_init (enum mu_gocs_op op, void *data)
       if (data)
        memcpy (&mu_tls_module_config, data, sizeof mu_tls_module_config);
       break;
-
+      
     case mu_gocs_op_flush:
 #ifdef WITH_TLS
       mu_init_tls_libs ();
@@ -61,6 +59,7 @@ mu_tls_module_init (enum mu_gocs_op op, void *data)
 #ifdef WITH_TLS
 
 #include <gnutls/gnutls.h>
+#include <mailutils/sys/tls-stream.h>
 
 #define DH_BITS 768
 
@@ -116,11 +115,23 @@ mu_check_tls_environment (void)
 
 int mu_tls_enable = 0;
 
+#if 0
+void
+_mu_gtls_logger(int level, const char *text)
+{
+  mu_diag_output (MU_DIAG_DEBUG, "GnuTLS(%d): %s", level, text);
+}
+#endif
+
 int
 mu_init_tls_libs (void)
 {
   if (mu_tls_module_config.enable && !mu_tls_enable)
     mu_tls_enable = !gnutls_global_init (); /* Returns 1 on success */
+#if 0
+  gnutls_global_set_log_function (_mu_gtls_logger);
+  gnutls_global_set_log_level (110);
+#endif
   return mu_tls_enable;
 }
 
@@ -153,199 +164,58 @@ initialize_tls_session (void)
   return session;
 }
 
-int
-mu_tls_begin (void *iodata,
-             mu_tls_readline_fn reader,
-             mu_tls_writeline_fn writer,
-             mu_tls_stream_ctl_fn stream_ctl,
-             char *keywords[])
+
+/* ************************* TLS Stream Support **************************** */
+
+static int
+_tls_io_close (mu_stream_t stream)
 {
-  int i = 0;
-  int status;
-  mu_stream_t oldstr, newstr;
+  struct _mu_tls_io_stream *sp = (struct _mu_tls_io_stream *) stream;
   
-  if (keywords == NULL)
-    return EINVAL;
-
-  for (i = 0; keywords[i]; i++)
-    {
-      switch (i)
-      {
-        case 0:
-          /*
-           *  Send STLS/STARTTLS
-           */
-          status = writer (iodata, keywords[i]);
-          if (status != 0)
-           {
-             mu_error ("mu_tls_begin: writer (0): %s", mu_strerror (status));
-             return status;
-           }
-          
-          status = reader (iodata);
-          if (status != 0)
-           {
-             mu_error ("mu_tls_begin: reader (0): %s", mu_strerror (status));
-             return status;
-           }
-
-          stream_ctl (iodata, &oldstr, NULL);
-          status = mu_tls_stream_create_client_from_tcp (&newstr, oldstr, 0);
-          if (status != 0)
-           {
-             mu_error ("mu_tls_begin: mu_tls_stream_create_client_from_tcp 
(0): %s",
-                       mu_strerror (status));
-             return status;
-           }
-
-          status = mu_stream_open (newstr);
-          if (status != 0)
-           {
-             mu_error ("mu_tls_begin: mu_stream_open (0): %s",
-                       mu_strerror (status));
-             return status;
-           }
-
-          stream_ctl (iodata, NULL, newstr);
-          break;
-
-        case 1:
-         /*
-          *  Send CAPABILITIES request
-          */
-          status = writer (iodata, keywords[i]);
-          if (status != 0)
-           {
-             mu_error ("mu_tls_begin: writer (1): %s", mu_strerror (status));
-             return status;
-           }
-
-          status = reader (iodata);
-          if (status != 0)
-           {
-             mu_error ("mu_tls_begin: reader (1): %s", mu_strerror (status));
-             return status;
-           }
-          break;
-          
-      default:
-       return 1;
-      }
-    }
-  return 0;
+  return mu_stream_close (sp->transport);
 }
 
-/* ************************* TLS Stream Support **************************** */
-
-enum tls_stream_state {
-  state_init,
-  state_open,
-  state_closed,
-  state_destroyed
-};
-
-struct _tls_stream {
-  mu_stream_t strin;  /* Input stream */
-  mu_stream_t strout; /* Output stream */ 
-  int last_err;
-  struct _line_buffer *lb;
-  enum tls_stream_state state;
-  gnutls_session session;
-};
-
-
 static void
-_tls_destroy (mu_stream_t stream)
+_tls_io_done (struct _mu_stream *stream)
 {
-  struct _tls_stream *s = mu_stream_get_owner (stream);
-  int flags;
-  
-  if (x509_cred)
-    gnutls_certificate_free_credentials (x509_cred);
-  if (s->session && s->state == state_closed)
-    {
-      gnutls_deinit (s->session);
-      s->state = state_destroyed;
-    }
-  _auth_lb_destroy (&s->lb);
-
-  mu_stream_get_flags (stream, &flags);
-  if (!(flags & MU_STREAM_NO_CLOSE))
-    {
-      int same_stream = s->strin == s->strout;
-      mu_stream_destroy (&s->strin, mu_stream_get_owner (s->strin));
-      if (!same_stream)
-       mu_stream_destroy (&s->strout, mu_stream_get_owner (s->strout));
-    }
-  free (s);
+  struct _mu_tls_io_stream *sp = (struct _mu_tls_io_stream *) stream;
+  mu_stream_unref (sp->transport);
 }
-    
+
 static int
-_tls_read (mu_stream_t stream, char *optr, size_t osize,
-          mu_off_t offset, size_t *nbytes)
+_tls_io_flush (struct _mu_stream *stream)
 {
-  struct _tls_stream *s = mu_stream_get_owner (stream);
-  int rc;
-  
-  if (!stream || s->state != state_open)
-    return EINVAL;
-  rc = gnutls_record_recv (s->session, optr, osize);
-  if (rc >= 0)
-    {
-      *nbytes = rc;
-      return 0;
-    }
-  s->last_err = rc;
-  return EIO;
+  struct _mu_tls_io_stream *sp = (struct _mu_tls_io_stream *) stream;
+  return mu_stream_flush (sp->transport);
 }
 
 static int
-_tls_readline (mu_stream_t stream, char *optr, size_t osize,
-               mu_off_t offset, size_t *nbytes)
+_tls_io_read (struct _mu_stream *stream, char *buf, size_t bufsize,
+             size_t *pnread)
 {
-  struct _tls_stream *s = mu_stream_get_owner (stream);
+  struct _mu_tls_io_stream *sp = (struct _mu_tls_io_stream *) stream;
   int rc;
-  char *ptr;
-  size_t rdsize;
   
-  if (!stream || s->state != state_open || osize < 2)
+  if (sp->up->state != state_open)
     return EINVAL;
-
-  if (_auth_lb_level (s->lb) == 0)
+  rc = gnutls_record_recv (sp->up->session, buf, bufsize);
+  if (rc >= 0)
     {
-      ptr = optr;
-      rdsize = 0;
-      do
-       {
-         rc = gnutls_record_recv (s->session, ptr + rdsize, osize - rdsize);
-         if (rc < 0)
-           {
-             s->last_err = rc;
-             return EIO;
-           }
-         rdsize += rc;
-       }
-      while (osize > rdsize && rc > 0 && ptr[rdsize-1] != '\n');
-      
-      _auth_lb_grow (s->lb, ptr, rdsize);
+      *pnread = rc;
+      return 0;
     }
-  
-  osize--; /* Allow for terminating zero */
-  rdsize = _auth_lb_readline (s->lb, optr, osize);
-  optr[rdsize] = 0;
-  if (nbytes)
-    *nbytes = rdsize;
-  return 0;
+  sp->up->tls_err = rc;
+  return EIO;
 }
 
 static int
-_tls_write (mu_stream_t stream, const char *iptr, size_t isize,
-           mu_off_t offset, size_t *nbytes)
+_tls_io_write (struct _mu_stream *stream, const char *buf, size_t bufsize,
+           size_t *pnwrite)
 {
-  struct _tls_stream *s = mu_stream_get_owner (stream);
+  struct _mu_tls_io_stream *sp = (struct _mu_tls_io_stream *) stream;
   int rc;
   
-  if (!stream || s->state != state_open)
+  if (sp->up->state != state_open)
     return EINVAL;
 
   /* gnutls_record_send() docs say:
@@ -356,53 +226,104 @@ _tls_write (mu_stream_t stream, const char *iptr, size_t 
isize,
        corrupted and the connection will be terminated. */
     
   do
-    rc = gnutls_record_send (s->session, iptr, isize);
+    rc = gnutls_record_send (sp->up->session, buf, bufsize);
   while (rc == GNUTLS_E_INTERRUPTED || rc == GNUTLS_E_AGAIN);
 
   if (rc < 0)
     {
-      s->last_err = rc;
+      sp->up->tls_err = rc;
       return EIO;
     }
 
-  if (nbytes)
-    *nbytes = rc;
+  *pnwrite = rc;
 
   return 0;
 }
 
 static int
-_tls_flush (mu_stream_t stream)
+_tls_rd_wait (struct _mu_stream *stream, int *pflags, struct timeval *tvp)
 {
-  struct _tls_stream *s = mu_stream_get_owner (stream);
-  return mu_stream_flush (s->strout);
+  struct _mu_tls_io_stream *sp = (struct _mu_tls_io_stream *) stream;
+  int rc = EINVAL;
+  
+  if (*pflags == MU_STREAM_READY_RD)
+    rc = mu_stream_wait (sp->transport, pflags, tvp);
+  return rc;
 }
 
 static int
-_tls_close (mu_stream_t stream)
+_tls_wr_wait (struct _mu_stream *stream, int *pflags, struct timeval *tvp)
 {
-  struct _tls_stream *s = mu_stream_get_owner (stream);
-  int flags;
+  struct _mu_tls_io_stream *sp = (struct _mu_tls_io_stream *) stream;
+  int rc = EINVAL;
   
-  if (s->session && s->state == state_open)
+  if (*pflags == MU_STREAM_READY_WR)
+    rc = mu_stream_wait (sp->transport, pflags, tvp);
+  return rc;
+}
+
+static int
+_tls_io_ioctl (struct _mu_stream *stream, int op, void *arg)
+{
+  struct _mu_tls_io_stream *sp = (struct _mu_tls_io_stream *) stream;
+  mu_transport_t *ptrans;
+
+  switch (op)
     {
-      gnutls_bye (s->session, GNUTLS_SHUT_RDWR);
-      s->state = state_closed;
+    case MU_IOCTL_GET_TRANSPORT:
+      if (!arg)
+       return EINVAL;
+      ptrans = arg;
+      ptrans[0] = (mu_transport_t) sp->transport;
+      ptrans[1] = NULL;
+      break;
+
+    default:
+      return EINVAL;
     }
-  
-  mu_stream_get_flags (stream, &flags);
-  if (!(flags & MU_STREAM_NO_CLOSE))
+  return 0;
+}
+
+static int
+_mu_tls_io_stream_create (mu_stream_t *pstream,
+                         mu_stream_t transport, int flags,
+                         struct _mu_tls_stream *master)
+{
+  struct _mu_tls_io_stream *sp;
+
+  sp = (struct _mu_tls_io_stream *)
+    _mu_stream_create (sizeof (*sp), flags & MU_STREAM_RDWR);
+  if (!sp)
+    return ENOMEM;
+
+  if (flags & MU_STREAM_READ)
+    {
+      sp->stream.read = _tls_io_read; 
+      sp->stream.wait = _tls_rd_wait;
+      mu_stream_set_buffer ((mu_stream_t) sp, mu_buffer_full, 1024);
+    }
+  else
     {
-      mu_stream_close (s->strin);
-      if (s->strin != s->strout)
-       mu_stream_close (s->strout);
+      sp->stream.write = _tls_io_write;
+      sp->stream.wait = _tls_wr_wait;
+      mu_stream_set_buffer ((mu_stream_t) sp, mu_buffer_line, 1024);
     }
+  sp->stream.flush = _tls_io_flush;
+  sp->stream.close = _tls_io_close;
+  sp->stream.done = _tls_io_done; 
+  sp->stream.ctl = _tls_io_ioctl;
+  /* FIXME:
+     sp->stream.error_string = _tls_error_string;*/
+
+  if (!(flags & MU_STREAM_AUTOCLOSE))
+    mu_stream_ref (transport);
+  sp->transport = transport;
+  sp->up = master;
+  *pstream = (mu_stream_t) sp;
   return 0;
 }
 
 
-/* Push & pull functions */
-
 static ssize_t
 _tls_stream_pull (gnutls_transport_ptr fd, void *buf, size_t size)
 {
@@ -410,9 +331,9 @@ _tls_stream_pull (gnutls_transport_ptr fd, void *buf, 
size_t size)
   int rc;
   size_t rdbytes;
        
-  while ((rc = mu_stream_sequential_read (stream, buf, size, &rdbytes)) == 
EAGAIN)
+  while ((rc = mu_stream_read (stream, buf, size, &rdbytes)) == EAGAIN)
     ;
-
+  
   if (rc)
     return -1;
   return rdbytes;
@@ -424,25 +345,26 @@ _tls_stream_push (gnutls_transport_ptr fd, const void 
*buf, size_t size)
   mu_stream_t stream = fd;
   int rc;
 
-  rc = mu_stream_sequential_write (stream, buf, size);
+  rc = mu_stream_write (stream, buf, size, &size);
   if (rc)
     {
       mu_error ("_tls_stream_push: %s", mu_strerror (rc)); /* FIXME */
       return -1;
     }
+
   mu_stream_flush (stream);
   return size;
 }
 
 
-
 static int
-_tls_open (mu_stream_t stream)
+_tls_server_open (mu_stream_t stream)
 {
-  struct _tls_stream *s = mu_stream_get_owner (stream);
+  struct _mu_tls_stream *sp = (struct _mu_tls_stream *) stream;
   int rc = 0;
+  mu_transport_t transport[2];
   
-  if (!stream || s->state != state_init)
+  if (!stream || sp->state != state_init)
     return EINVAL;
 
   gnutls_certificate_allocate_credentials (&x509_cred);
@@ -451,42 +373,45 @@ _tls_open (mu_stream_t stream)
     gnutls_certificate_set_x509_trust_file (x509_cred,
                                            mu_tls_module_config.ssl_cafile,
                                            GNUTLS_X509_FMT_PEM);
-
+  
   rc = gnutls_certificate_set_x509_key_file (x509_cred,
                                             mu_tls_module_config.ssl_cert, 
                                             mu_tls_module_config.ssl_key,
                                             GNUTLS_X509_FMT_PEM);
   if (rc < 0)
     {
-      s->last_err = rc;
+      sp->tls_err = rc;
       return EIO;
     }
   
   generate_dh_params ();
   gnutls_certificate_set_dh_params (x509_cred, dh_params);
 
-  s->session = initialize_tls_session ();
-  gnutls_transport_set_ptr2 (s->session,
-                            (gnutls_transport_ptr) s->strin,
-                            (gnutls_transport_ptr) s->strout);
-  gnutls_transport_set_pull_function (s->session, _tls_stream_pull);
-  gnutls_transport_set_push_function (s->session, _tls_stream_push);
+  sp->session = initialize_tls_session ();
+  mu_stream_ioctl (stream, MU_IOCTL_GET_TRANSPORT, transport);
+  gnutls_transport_set_ptr2 (sp->session,
+                            (gnutls_transport_ptr) transport[0],
+                            (gnutls_transport_ptr) transport[1]);
+  gnutls_transport_set_pull_function (sp->session, _tls_stream_pull);
+  gnutls_transport_set_push_function (sp->session, _tls_stream_push);
   
-  rc = gnutls_handshake (s->session);
+  rc = gnutls_handshake (sp->session);
   if (rc < 0)
     {
-      gnutls_deinit (s->session);
-      s->last_err = rc;
+      gnutls_deinit (sp->session);
+      sp->tls_err = rc;
       return EIO;
     }
-  s->state = state_open;
+  sp->state = state_open;
   return 0;
 }
 
 static int
-prepare_client_session (struct _tls_stream *s)
+prepare_client_session (mu_stream_t stream)
 {
+  struct _mu_tls_stream *sp = (struct _mu_tls_stream *) stream;
   int rc;
+  mu_transport_t transport[2];
   static int protocol_priority[] = {GNUTLS_TLS1, GNUTLS_SSL3, 0};
   static int kx_priority[] = {GNUTLS_KX_RSA, 0};
   static int cipher_priority[] = {GNUTLS_CIPHER_3DES_CBC,
@@ -495,12 +420,12 @@ prepare_client_session (struct _tls_stream *s)
   static int comp_priority[] = {GNUTLS_COMP_NULL, 0};
   static int mac_priority[] = {GNUTLS_MAC_SHA, GNUTLS_MAC_MD5, 0};
 
-  gnutls_init (&s->session, GNUTLS_CLIENT);
-  gnutls_protocol_set_priority (s->session, protocol_priority);
-  gnutls_cipher_set_priority (s->session, cipher_priority);
-  gnutls_compression_set_priority (s->session, comp_priority);
-  gnutls_kx_set_priority (s->session, kx_priority);
-  gnutls_mac_set_priority (s->session, mac_priority);
+  gnutls_init (&sp->session, GNUTLS_CLIENT);
+  gnutls_protocol_set_priority (sp->session, protocol_priority);
+  gnutls_cipher_set_priority (sp->session, cipher_priority);
+  gnutls_compression_set_priority (sp->session, comp_priority);
+  gnutls_kx_set_priority (sp->session, kx_priority);
+  gnutls_mac_set_priority (sp->session, mac_priority);
 
   gnutls_certificate_allocate_credentials (&x509_cred);
   if (mu_tls_module_config.ssl_cafile)
@@ -510,44 +435,45 @@ prepare_client_session (struct _tls_stream *s)
                                                   GNUTLS_X509_FMT_PEM);
       if (rc < 0)
        {
-         s->last_err = rc;
+         sp->tls_err = rc;
          return -1;
        }
     }
 
-  gnutls_credentials_set (s->session, GNUTLS_CRD_CERTIFICATE, x509_cred);
+  gnutls_credentials_set (sp->session, GNUTLS_CRD_CERTIFICATE, x509_cred);
 
-  gnutls_transport_set_ptr2 (s->session,
-                            (gnutls_transport_ptr) s->strin,
-                            (gnutls_transport_ptr) s->strout);
-  gnutls_transport_set_pull_function (s->session, _tls_stream_pull);
-  gnutls_transport_set_push_function (s->session, _tls_stream_push);
+  mu_stream_ioctl (stream, MU_IOCTL_GET_TRANSPORT, transport);
+  gnutls_transport_set_ptr2 (sp->session,
+                            (gnutls_transport_ptr) transport[0],
+                            (gnutls_transport_ptr) transport[1]);
+  gnutls_transport_set_pull_function (sp->session, _tls_stream_pull);
+  gnutls_transport_set_push_function (sp->session, _tls_stream_push);
       
   return 0;
 }
-  
+
 static int
-_tls_open_client (mu_stream_t stream)
+_tls_client_open (mu_stream_t stream)
 {
-  struct _tls_stream *s = mu_stream_get_owner (stream);
+  struct _mu_tls_stream *sp = (struct _mu_tls_stream *) stream;
   int rc = 0;
   
-  switch (s->state)
+  switch (sp->state)
     {
     case state_closed:
       gnutls_certificate_free_credentials (x509_cred);
-      if (s->session)
-       gnutls_deinit (s->session);
+      if (sp->session)
+       gnutls_deinit (sp->session);
       /* FALLTHROUGH */
       
     case state_init:
-      prepare_client_session (s);
-      rc = gnutls_handshake (s->session);
+      prepare_client_session (stream);
+      rc = gnutls_handshake (sp->session);
       if (rc < 0)
        {
-         s->last_err = rc;
-         gnutls_deinit (s->session);
-         s->state = state_init;
+         sp->tls_err = rc;
+         gnutls_deinit (sp->session);
+         sp->state = state_init;
          return MU_ERR_FAILURE;
        }
       break;
@@ -557,133 +483,171 @@ _tls_open_client (mu_stream_t stream)
     }
 
   /* FIXME: if (ssl_cafile) verify_certificate (s->session); */
-  s->state = state_open;
+  sp->state = state_open;
   return 0;
 }
 
-int
-_tls_strerror (mu_stream_t stream, const char **pstr)
+static int
+_tls_read (struct _mu_stream *str, char *buf, size_t bufsize,
+          size_t *pnread)
 {
-  struct _tls_stream *s = mu_stream_get_owner (stream);
-  *pstr = gnutls_strerror (s->last_err);
-  return 0;
+  struct _mu_tls_stream *sp = (struct _mu_tls_stream *)str;
+  return mu_stream_read (sp->transport[0], buf, bufsize, pnread);
 }
 
-int
-_tls_get_transport2 (mu_stream_t stream,
-                    mu_transport_t *pin, mu_transport_t *pout)
+static int
+_tls_write (struct _mu_stream *str, const char *buf, size_t bufsize,
+           size_t *pnwrite)
 {
-  struct _tls_stream *s = mu_stream_get_owner (stream);
-  *pin = (mu_transport_t) s->strin;
-  *pout = (mu_transport_t) s->strout;
-  return 0;
+  struct _mu_tls_stream *sp = (struct _mu_tls_stream *)str;
+  return mu_stream_write (sp->transport[1], buf, bufsize, pnwrite);
 }
 
-int
-_tls_wait (mu_stream_t stream, int *pflags, struct timeval *tvp)
+static int
+_tls_ioctl (struct _mu_stream *stream, int op, void *arg)
 {
-  struct _tls_stream *s = mu_stream_get_owner (stream);
-  if ((*pflags & (MU_STREAM_READY_RD|MU_STREAM_READY_WR))
-      == (MU_STREAM_READY_RD|MU_STREAM_READY_WR))
-    return EINVAL; /* Sorry, can't wait for both input and output. */
-  if (*pflags & MU_STREAM_READY_RD)
-    return mu_stream_wait (s->strin, pflags, tvp);
-  if (*pflags & MU_STREAM_READY_WR)
-    return mu_stream_wait (s->strout, pflags, tvp);
-  return EINVAL;
-}
+  struct _mu_tls_stream *sp = (struct _mu_tls_stream *) stream;
+  mu_transport_t *ptrans, trans[2];
 
-/* FIXME: if strin == strout sequential reads may intefere with
-   sequential writes (they would share stream->offset). This should
-   be fixed either in stream.c or here. In particular,
-   mu_tls_stream_create_client will malfunction */
-int
-mu_tls_stream_create (mu_stream_t *stream,
-                     mu_stream_t strin, mu_stream_t strout, int flags)
-{
-  struct _tls_stream *s;
-  int rc;
+  switch (op)
+    {
+    case MU_IOCTL_GET_TRANSPORT:
+      if (!arg)
+       return EINVAL;
+      ptrans = arg;
+      mu_stream_ioctl (sp->transport[0], MU_IOCTL_GET_TRANSPORT, trans);
+      ptrans[0] = trans[0];
+      mu_stream_ioctl (sp->transport[1], MU_IOCTL_GET_TRANSPORT, trans);
+      ptrans[1] = trans[0];
+      break;
 
-  if (stream == NULL)
-    return MU_ERR_OUT_PTR_NULL;
+    default:
+      return EINVAL;
+    }
+  return 0;
+}
 
-  s = calloc (1, sizeof (*s));
-  if (s == NULL)
-    return ENOMEM;
+static int
+_tls_wait (struct _mu_stream *stream, int *pflags, struct timeval *tvp)
+{
+  struct _mu_tls_stream *sp = (struct _mu_tls_stream *) stream;
+  int rc = EINVAL;
+  
+  if (*pflags == MU_STREAM_READY_RD)
+    rc = mu_stream_wait (sp->transport[0], pflags, tvp);
+  else if (*pflags == MU_STREAM_READY_WR)
+    rc = mu_stream_wait (sp->transport[1], pflags, tvp);
+  return rc;
+}
 
-  s->strin = strin;
-  s->strout = strout;
+static int
+_tls_flush (struct _mu_stream *stream)
+{
+  struct _mu_tls_stream *sp = (struct _mu_tls_stream *) stream;
+  return mu_stream_flush (sp->transport[1]);
+}
 
-  rc = mu_stream_create (stream, flags|MU_STREAM_NO_CHECK, s);
-  if (rc)
+static int
+_tls_close (mu_stream_t stream)
+{
+  struct _mu_tls_stream *sp = (struct _mu_tls_stream *) stream;
+  
+  if (sp->session && sp->state == state_open)
     {
-      free (s);
-      return rc;
+      gnutls_bye (sp->session, GNUTLS_SHUT_RDWR);
+      sp->state = state_closed;
     }
-
-  mu_stream_set_open (*stream, _tls_open, s);
-  mu_stream_set_close (*stream, _tls_close, s);
-  mu_stream_set_read (*stream, _tls_read, s);
-  mu_stream_set_readline (*stream, _tls_readline, s);
-  mu_stream_set_write (*stream, _tls_write, s);
-  mu_stream_set_flush (*stream, _tls_flush, s);
-  mu_stream_set_destroy (*stream, _tls_destroy, s);
-  mu_stream_set_strerror (*stream, _tls_strerror, s);
-  mu_stream_set_get_transport2 (*stream, _tls_get_transport2, s);
-  mu_stream_set_wait (*stream, _tls_wait, s);
-  _auth_lb_create (&s->lb);
   
-  s->state = state_init;
+  mu_stream_close (sp->transport[0]);
+  mu_stream_close (sp->transport[1]);
   return 0;
 }
 
-int
-mu_tls_stream_create_client (mu_stream_t *stream,
-                            mu_stream_t strin, mu_stream_t strout, int flags)
+static void
+_tls_done (struct _mu_stream *stream)
 {
-  struct _tls_stream *s;
-  int rc;
+  struct _mu_tls_stream *sp = (struct _mu_tls_stream *) stream;
+  
+  if (x509_cred)
+    gnutls_certificate_free_credentials (x509_cred);
+  if (sp->session && sp->state == state_closed)
+    {
+      gnutls_deinit (sp->session);
+      sp->state = state_destroyed;
+    }
 
-  if (stream == NULL)
-    return MU_ERR_OUT_PTR_NULL;
+  mu_stream_destroy (&sp->transport[0]);
+  mu_stream_destroy (&sp->transport[1]);
+}
 
-  s = calloc (1, sizeof (*s));
-  if (s == NULL)
+static int
+_mu_tls_stream_create (mu_stream_t *pstream,
+                      int (*openfn) (mu_stream_t stream),
+                      mu_stream_t strin, mu_stream_t strout, int flags)
+{
+  struct _mu_tls_stream *sp;
+  int autoclose = flags & MU_STREAM_AUTOCLOSE;
+  int rc;
+  
+  sp = (struct _mu_tls_stream *)
+    _mu_stream_create (sizeof (*sp), MU_STREAM_RDWR);
+  if (!sp)
     return ENOMEM;
 
-  s->strin = strin;
-  s->strout = strout;
-  
-  rc = mu_stream_create (stream, flags|MU_STREAM_NO_CHECK, s);
+  sp->stream.read = _tls_read; 
+  sp->stream.write = _tls_write;
+  sp->stream.flush = _tls_flush;
+  sp->stream.open = openfn; 
+  sp->stream.close = _tls_close;
+  sp->stream.done = _tls_done; 
+  sp->stream.ctl = _tls_ioctl;
+  sp->stream.wait = _tls_wait;
+  /* FIXME:
+     sp->stream.error_string = _tls_error_string;*/
+
+  mu_stream_set_buffer (strin, mu_buffer_none, 0);
+  mu_stream_set_buffer (strout, mu_buffer_none, 0);
+  rc = _mu_tls_io_stream_create (&sp->transport[0], strin,
+                                MU_STREAM_READ | autoclose, sp);
+  if (rc)
+    {
+      free (sp);
+      return rc;
+    }
+     
+  rc = _mu_tls_io_stream_create (&sp->transport[1], strout,
+                                MU_STREAM_WRITE | autoclose, sp);
   if (rc)
     {
-      free (s);
+      free (sp);
+      free (sp->transport[0]);
       return rc;
     }
 
-  mu_stream_set_open (*stream, _tls_open_client, s);
-  mu_stream_set_close (*stream, _tls_close, s);
-  mu_stream_set_read (*stream, _tls_read, s);
-  mu_stream_set_readline (*stream, _tls_readline, s);
-  mu_stream_set_write (*stream, _tls_write, s);
-  mu_stream_set_flush (*stream, _tls_flush, s);
-  mu_stream_set_destroy (*stream, _tls_destroy, s);
-  mu_stream_set_strerror (*stream, _tls_strerror, s);
-  mu_stream_set_get_transport2 (*stream, _tls_get_transport2, s);
-  mu_stream_set_wait (*stream, _tls_wait, s);
-  _auth_lb_create (&s->lb);
-  
-  s->state = state_init;
+  mu_stream_set_buffer ((mu_stream_t) sp, mu_buffer_line, 1024);
+  *pstream = (mu_stream_t) sp;
   return 0;
 }
 
 int
-mu_tls_stream_create_client_from_tcp (mu_stream_t *stream, mu_stream_t tcp_str,
-                                     int flags)
+mu_tls_server_stream_create (mu_stream_t *pstream,
+                            mu_stream_t strin, mu_stream_t strout, int flags)
 {
-  return mu_tls_stream_create_client (stream, tcp_str, tcp_str, flags);
+  return _mu_tls_stream_create (pstream,
+                               _tls_server_open,
+                               strin, strout, flags);
 }
 
+int
+mu_tls_client_stream_create (mu_stream_t *pstream,
+                            mu_stream_t strin, mu_stream_t strout, int flags)
+{
+  return _mu_tls_stream_create (pstream,
+                               _tls_client_open,
+                               strin, strout, flags);
+}
+
+
 #endif /* WITH_TLS */
 
 /* EOF */
diff --git a/libmu_scm/Makefile.am b/libmu_scm/Makefile.am
index a65df28..3a2ecb9 100644
--- a/libmu_scm/Makefile.am
+++ b/libmu_scm/Makefile.am
@@ -18,7 +18,7 @@
 ##   Foundation, Inc.  51 Franklin Street, Fifth Floor, Boston, MA
 ##   02110-1301 USA
 
-INCLUDES = -I. @MU_LIB_COMMON_INCLUDES@
+INCLUDES = -I. @MU_LIB_COMMON_INCLUDES@ @GUILE_INCLUDES@
 
 lib_LTLIBRARIES=libmu_scm.la
 
diff --git a/libmu_scm/mu_body.c b/libmu_scm/mu_body.c
index ff88759..a5c5cf5 100644
--- a/libmu_scm/mu_body.c
+++ b/libmu_scm/mu_body.c
@@ -25,10 +25,9 @@ struct mu_body
 {
   mu_body_t body;             /* Message body */
   mu_stream_t stream;         /* Associated stream */
-  int offset;              /* Current offset in the stream */
-  char *buffer;            /* I/O buffer */
-  int bufsize;             /* Size of allocated buffer */
-  SCM msg;                 /* Message the body belongs to */           
+  char *buffer;               /* I/O buffer */
+  size_t bufsize;             /* Size of allocated buffer */
+  SCM msg;                    /* Message the body belongs to */                
 };
 
 /* Initial buffer size */
@@ -48,8 +47,9 @@ mu_scm_body_free (SCM body_smob)
   struct mu_body *mbp = (struct mu_body *) SCM_CDR (body_smob);
   if (mbp->buffer)
     free (mbp->buffer);
+  mu_stream_unref (mbp->stream);
   free (mbp);
-  return sizeof (struct mu_body);
+  return 0;
 }
 
 static int
@@ -93,7 +93,6 @@ mu_scm_body_create (SCM msg, mu_body_t body)
   mbp->msg = msg;
   mbp->body = body;
   mbp->stream = NULL;
-  mbp->offset = 0;
   mbp->buffer = NULL;
   mbp->bufsize = 0;
   SCM_RETURN_NEWSMOB (body_tag, mbp);
@@ -108,7 +107,7 @@ SCM_DEFINE_PUBLIC (scm_mu_body_read_line, 
"mu-body-read-line", 1, 0, 0,
 #define FUNC_NAME s_scm_mu_body_read_line
 {
   struct mu_body *mbp;
-  size_t n, nread;
+  size_t nread;
   int status;
   
   SCM_ASSERT (mu_scm_is_body (body), body, SCM_ARG1, FUNC_NAME);
@@ -116,7 +115,7 @@ SCM_DEFINE_PUBLIC (scm_mu_body_read_line, 
"mu-body-read-line", 1, 0, 0,
 
   if (!mbp->stream)
     {
-      status = mu_body_get_stream (mbp->body, &mbp->stream);
+      status = mu_body_get_streamref (mbp->body, &mbp->stream);
       if (status)
        mu_scm_error (FUNC_NAME, status,
                      "Cannot get body stream",
@@ -131,30 +130,11 @@ SCM_DEFINE_PUBLIC (scm_mu_body_read_line, 
"mu-body-read-line", 1, 0, 0,
        mu_scm_error (FUNC_NAME, ENOMEM, "Cannot allocate memory", SCM_BOOL_F);
     }
 
-  nread = 0;
-  while (1)
-    {
-      status = mu_stream_readline (mbp->stream, mbp->buffer + nread,
-                                  mbp->bufsize - nread,
-                                  mbp->offset, &n);
-      if (status)
-       mu_scm_error (FUNC_NAME, status,
-                     "Error reading from stream", SCM_BOOL_F);
-      if (n == 0)
-       break;
-      nread += n;
-      mbp->offset += n;
-      if (mbp->buffer[n - 1] != '\n' && n == mbp->bufsize)
-       {
-         char *p = realloc (mbp->buffer, mbp->bufsize + BUF_SIZE);
-         if (!p)
-           break;
-         mbp->buffer = p;
-         mbp->bufsize += BUF_SIZE;
-       }
-      else
-       break;
-    }
+  status = mu_stream_getline (mbp->stream, (char**)&mbp->buffer, &mbp->bufsize,
+                             &nread);
+  if (status)
+    mu_scm_error (FUNC_NAME, status,
+                 "Error reading from stream", SCM_BOOL_F);
 
   if (nread == 0)
     return SCM_EOF_VAL;
@@ -169,7 +149,7 @@ SCM_DEFINE_PUBLIC (scm_mu_body_write, "mu-body-write", 2, 
0, 0,
 #define FUNC_NAME s_scm_mu_body_write
 {
   char *ptr;
-  size_t len, n;
+  size_t len;
   struct mu_body *mbp;
   int status;
   
@@ -179,7 +159,7 @@ SCM_DEFINE_PUBLIC (scm_mu_body_write, "mu-body-write", 2, 
0, 0,
   
   if (!mbp->stream)
     {
-      status = mu_body_get_stream (mbp->body, &mbp->stream);
+      status = mu_body_get_streamref (mbp->body, &mbp->stream);
       if (status)
        mu_scm_error (FUNC_NAME, status,
                      "Cannot get body stream", SCM_BOOL_F);
@@ -187,11 +167,11 @@ SCM_DEFINE_PUBLIC (scm_mu_body_write, "mu-body-write", 2, 
0, 0,
 
   ptr = scm_to_locale_string (text);
   len = strlen (ptr);
-  status = mu_stream_write (mbp->stream, ptr, len, mbp->offset, &n);
+  status = mu_stream_write (mbp->stream, ptr, len, NULL);
   free (ptr);
-  mu_scm_error (FUNC_NAME, status,
-               "Error writing to stream", SCM_BOOL_F);
-  mbp->offset += n;
+  if (status)
+    mu_scm_error (FUNC_NAME, status,
+                 "Error writing to stream", SCM_BOOL_F);
   return SCM_BOOL_T;
 }
 #undef FUNC_NAME
diff --git a/libmu_scm/mu_mailbox.c b/libmu_scm/mu_mailbox.c
index 90ee4da..4252e65 100644
--- a/libmu_scm/mu_mailbox.c
+++ b/libmu_scm/mu_mailbox.c
@@ -316,7 +316,7 @@ SCM_DEFINE_PUBLIC (scm_mu_mailbox_get_port, 
"mu-mailbox-get-port", 2, 0, 0,
   SCM_ASSERT (mu_scm_is_mailbox (mbox), mbox, SCM_ARG1, FUNC_NAME);
   SCM_ASSERT (scm_is_string (mode), mode, SCM_ARG2, FUNC_NAME);
   mum = (struct mu_mailbox *) SCM_CDR (mbox);
-  status = mu_mailbox_get_stream (mum->mbox, &stream);
+  status = mu_mailbox_get_streamref (mum->mbox, &stream);
   if (status)
     mu_scm_error (FUNC_NAME, status,
                  "Cannot get mailbox stream",
diff --git a/libmu_scm/mu_message.c b/libmu_scm/mu_message.c
index 27c96be..1cb06c0 100644
--- a/libmu_scm/mu_message.c
+++ b/libmu_scm/mu_message.c
@@ -195,14 +195,12 @@ SCM_DEFINE_PUBLIC (scm_mu_message_copy, 
"mu-message-copy", 1, 0, 0,
 {
   mu_message_t msg, newmsg;
   mu_stream_t in = NULL, out = NULL;
-  char buffer[512];
-  size_t off, n;
   int status;
   
   SCM_ASSERT (mu_scm_is_message (mesg), mesg, SCM_ARG1, FUNC_NAME);
   msg = mu_scm_message_get (mesg);
 
-  status = mu_message_get_stream (msg, &in);
+  status = mu_message_get_streamref (msg, &in);
   if (status)
     mu_scm_error (FUNC_NAME, status,
                  "Cannot get input stream from message ~A",
@@ -213,7 +211,7 @@ SCM_DEFINE_PUBLIC (scm_mu_message_copy, "mu-message-copy", 
1, 0, 0,
     mu_scm_error (FUNC_NAME, status,
                  "Cannot create message", SCM_BOOL_F);
   
-  status = mu_message_get_stream (newmsg, &out);
+  status = mu_message_get_streamref (newmsg, &out);
   if (status)
     {
       mu_message_destroy (&newmsg, NULL);
@@ -221,28 +219,14 @@ SCM_DEFINE_PUBLIC (scm_mu_message_copy, 
"mu-message-copy", 1, 0, 0,
                    "Cannot get output stream", SCM_BOOL_F);
     }
 
-  off = 0;
-  while ((status = mu_stream_read (in, buffer, sizeof (buffer) - 1, off, &n))
-        == 0
-        && n != 0)
+  status = mu_stream_copy (out, in, 0, NULL);
+  mu_stream_destroy (&in);
+  mu_stream_destroy (&out);
+  if (status)
     {
-      size_t wr;
-      int rc;
-      
-      rc = mu_stream_write (out, buffer, n, off, &wr);
-      if (rc)
-       {
-         mu_message_destroy (&newmsg, NULL);
-         mu_scm_error (FUNC_NAME, rc, "Error writing to stream", SCM_BOOL_F);
-       }
-      
-      off += n;
-      if (wr != n)
-       {
-         mu_message_destroy (&newmsg, NULL);
-         mu_scm_error (FUNC_NAME, rc, "Error writing to stream: Short write",
-                       SCM_BOOL_F);
-       }
+      mu_message_destroy (&newmsg, NULL);
+      mu_scm_error (FUNC_NAME, status,
+                   "Error writing to stream", SCM_BOOL_F);
     }
   
   return mu_scm_message_create (SCM_BOOL_F, newmsg);
@@ -915,7 +899,7 @@ SCM_DEFINE_PUBLIC (scm_mu_message_get_port, 
"mu-message-get-port", 2, 1, 0,
       SCM_ASSERT (scm_is_bool (full), full, SCM_ARG3, FUNC_NAME);
       if (full == SCM_BOOL_T)
        {
-         status = mu_message_get_stream (msg, &stream);
+         status = mu_message_get_streamref (msg, &stream);
          if (status)
            mu_scm_error (FUNC_NAME, status, "Cannot get message stream",
                          SCM_BOOL_F);
@@ -930,7 +914,7 @@ SCM_DEFINE_PUBLIC (scm_mu_message_get_port, 
"mu-message-get-port", 2, 1, 0,
       if (status)
        mu_scm_error (FUNC_NAME, status, "Cannot get message body",
                      SCM_BOOL_F);
-      status = mu_body_get_stream (body, &stream);
+      status = mu_body_get_streamref (body, &stream);
       if (status)
        mu_scm_error (FUNC_NAME, status, "Cannot get message body stream",
                      SCM_BOOL_F);
diff --git a/libmu_scm/mu_port.c b/libmu_scm/mu_port.c
index 6f3e452..0efa5e7 100644
--- a/libmu_scm/mu_port.c
+++ b/libmu_scm/mu_port.c
@@ -26,8 +26,7 @@ typedef off_t scm_t_off;
 
 struct mu_port
 {
-  mu_stream_t stream;         /* Associated stream */
-  int offset;              /* Current offset in the stream */
+  mu_stream_t stream;      /* Associated stream */
   SCM msg;                 /* Message the port belongs to */           
 };
 
@@ -85,15 +84,16 @@ mu_port_make_from_stream (SCM msg, mu_stream_t stream, long 
mode)
   struct mu_port *mp;
   SCM port;
   scm_port *pt;
+  int flags;
   
   mp = scm_gc_malloc (sizeof (struct mu_port), "mu-port");
   mp->msg = msg;
   mp->stream = stream;
-  mp->offset = 0;
 
   port = scm_new_port_table_entry (scm_tc16_smuport | mode);
   pt = SCM_PTAB_ENTRY (port);
-  pt->rw_random = mu_stream_is_seekable (stream);
+  mu_stream_get_flags (stream, &flags);
+  pt->rw_random = flags & MU_STREAM_SEEK;
   SCM_SETSTREAM (port, mp);
   mu_port_alloc_buffer (port, 0, 0);
   /* FIXME:
@@ -118,14 +118,13 @@ mu_port_flush (SCM port)
   struct mu_port *mp = MU_PORT (port);
   scm_port *pt = SCM_PTAB_ENTRY (port);
   int wrsize = pt->write_pos - pt->write_buf;
-  size_t n;
   
   if (wrsize)
     {
-      if (mu_stream_write (mp->stream, (const char*)pt->write_buf,
-                          wrsize, mp->offset, &n))
-       return;
-      mp->offset += n;
+      int status = mu_stream_write (mp->stream, pt->write_buf, wrsize, NULL);
+      if (status)
+       mu_scm_error ("mu_port_flush", status,
+                     "Error writing to stream", SCM_BOOL_F);
     }
   pt->write_pos = pt->write_buf;
   pt->rw_active = SCM_PORT_NEITHER;
@@ -152,6 +151,8 @@ mu_port_close (SCM port)
 static scm_sizet
 mu_port_free (SCM port)
 {
+  struct mu_port *mp = MU_PORT (port);
+  mu_stream_unref (mp->stream);
   mu_port_close (port);
   return 0;
 }
@@ -165,7 +166,7 @@ mu_port_fill_input (SCM port)
   int status;
   
   status = mu_stream_read (mp->stream, (char*) pt->read_buf, pt->read_buf_size,
-                          mp->offset, &nread);
+                          &nread);
   if (status)
     mu_scm_error ("mu_port_fill_input", status,
                  "Error reading from stream", SCM_BOOL_F);
@@ -173,7 +174,6 @@ mu_port_fill_input (SCM port)
   if (nread == 0)
     return EOF;
 
-  mp->offset += nread;
   pt->read_pos = pt->read_buf;
   pt->read_end = pt->read_buf + nread;
   return *pt->read_buf;
@@ -215,21 +215,20 @@ mu_port_end_input (SCM port, int offset)
   if (offset > 0)
     {
       pt->read_pos = pt->read_end;
-      mp->offset -= delta;
+      mu_stream_seek (mp->stream, - delta, MU_SEEK_CUR, NULL);
     }
   pt->rw_active = SCM_PORT_NEITHER;
 }
 
-static mu_off_t
-mu_port_seek (SCM port, mu_off_t offset, int whence)
+static scm_t_off
+mu_port_seek (SCM port, scm_t_off offset, int whence)
 {
   struct mu_port *mp = MU_PORT (port);
   scm_port *pt = SCM_PTAB_ENTRY (port);
-  mu_off_t size = 0;
+  int mwhence;
+  mu_off_t pos;
+  int status;
   
-  if (whence == SEEK_CUR && offset == 0)
-    return mp->offset;
-
   if (pt->rw_active == SCM_PORT_WRITE)
     {
       mu_port_flush (port);
@@ -239,22 +238,22 @@ mu_port_seek (SCM port, mu_off_t offset, int whence)
       scm_end_input (port);
     }
 
-  mu_stream_size (mp->stream, &size);
   switch (whence)
     {
     case SEEK_SET:
+      mwhence = MU_SEEK_SET;
       break;
     case SEEK_CUR:
-      offset += mp->offset;
+      mwhence = MU_SEEK_CUR;
       break;
     case SEEK_END:
-      offset += size;
+      mwhence = MU_SEEK_END;
     }
 
-  if (offset > size)
-    return -1;
-  mp->offset = offset;
-  return offset;
+  status = mu_stream_seek (mp->stream, offset, mwhence, &pos);
+  if (status)
+    pos = -1;
+  return (scm_t_off) pos;
 }
 
 static void
diff --git a/libmu_sieve/actions.c b/libmu_sieve/actions.c
index fc9fb3d..952626a 100644
--- a/libmu_sieve/actions.c
+++ b/libmu_sieve/actions.c
@@ -145,7 +145,6 @@ mime_create_reason (mu_mime_t mime, mu_message_t msg, const 
char *text)
   time_t t;
   struct tm *tm;
   char *sender;
-  mu_off_t off = 0;
   mu_body_t body;
   mu_header_t hdr;
   char datestr[80];
@@ -155,7 +154,7 @@ mime_create_reason (mu_mime_t mime, mu_message_t msg, const 
char *text)
  
   mu_message_create (&newmsg, NULL);
   mu_message_get_body (newmsg, &body);
-  mu_body_get_stream (body, &stream);
+  mu_body_get_streamref (body, &stream);
 
   time (&t);
   tm = localtime (&t);
@@ -163,16 +162,18 @@ mime_create_reason (mu_mime_t mime, mu_message_t msg, 
const char *text)
 
   mu_sieve_get_message_sender (msg, &sender);
 
-  mu_stream_printf (stream, &off,
+  mu_stream_printf (stream, 
                    "The original message was received at %s from %s.\n",
                    datestr, sender);
   free (sender);
-  mu_stream_printf (stream, &off,
+  mu_stream_printf (stream,
                    "Message was refused by recipient's mail filtering 
program.\n");
-  mu_stream_printf (stream, &off, "Reason given was as follows:\n\n");
-  mu_stream_printf (stream, &off, "%s", text);
+  mu_stream_printf (stream, "Reason given was as follows:\n\n");
+  mu_stream_printf (stream, "%s", text);
   mu_stream_close (stream);
-  mu_header_create (&hdr, content_header, strlen (content_header), newmsg);
+  mu_stream_destroy (&stream);
+  
+  mu_header_create (&hdr, content_header, strlen (content_header));
   mu_message_set_header (newmsg, hdr, NULL);
   mu_mime_add_part (mime, newmsg);
   mu_message_unref (newmsg);
@@ -184,7 +185,6 @@ mime_create_ds (mu_mime_t mime, mu_message_t orig)
   mu_message_t newmsg;
   mu_stream_t stream;
   mu_header_t hdr;
-  mu_off_t off = 0;
   mu_body_t body;
   char *email;
   char datestr[80];
@@ -198,8 +198,8 @@ mime_create_ds (mu_mime_t mime, mu_message_t orig)
   mu_message_get_header (newmsg, &hdr); 
   mu_header_set_value (hdr, "Content-Type", "message/delivery-status", 1);
   mu_message_get_body (newmsg, &body);
-  mu_body_get_stream (body, &stream);
-  mu_stream_printf (stream, &off, "Reporting-UA: sieve; %s\n", PACKAGE_STRING);
+  mu_body_get_streamref (body, &stream);
+  mu_stream_printf (stream, "Reporting-UA: sieve; %s\n", PACKAGE_STRING);
 
   mu_message_get_envelope (orig, &env);
   if (mu_envelope_sget_date (env, &p) == 0
@@ -212,23 +212,25 @@ mime_create_ds (mu_mime_t mime, mu_message_t orig)
       
   /* FIXME: timezone info is lost */
   mu_strftime (datestr, sizeof datestr, "%a, %b %d %H:%M:%S %Y %Z", tmp);
-  mu_stream_printf (stream, &off, "Arrival-Date: %s\n", datestr);
+  mu_stream_printf (stream, "Arrival-Date: %s\n", datestr);
 
   email = mu_get_user_email (NULL);
-  mu_stream_printf (stream, &off, "Final-Recipient: RFC822; %s\n",
+  mu_stream_printf (stream, "Final-Recipient: RFC822; %s\n",
                    email ? email : "unknown");
   free (email);
-  mu_stream_printf (stream, &off, "Action: deleted\n");
-  mu_stream_printf (stream, &off, 
+  mu_stream_printf (stream, "Action: deleted\n");
+  mu_stream_printf (stream,  
                    "Disposition: 
automatic-action/MDN-sent-automatically;deleted\n");
 
   t = time (NULL);
   tmp = localtime (&t);
   mu_strftime (datestr, sizeof datestr, "%a, %b %d %H:%M:%S %Y %Z", tmp);
-  mu_stream_printf (stream, &off, "Last-Attempt-Date: %s\n", datestr);
+  mu_stream_printf (stream, "Last-Attempt-Date: %s\n", datestr);
 
   mu_stream_close (stream);
-  mu_mime_add_part(mime, newmsg);
+  mu_stream_destroy (&stream);
+  
+  mu_mime_add_part (mime, newmsg);
   mu_message_unref (newmsg);
 }
 
@@ -240,31 +242,25 @@ mime_create_quote (mu_mime_t mime, mu_message_t msg)
   mu_message_t newmsg;
   mu_stream_t istream, ostream;
   mu_header_t hdr;
-  size_t ioff = 0, ooff = 0, n;
-  char buffer[512];
+  int rc;
   mu_body_t body;
-    
+  
   mu_message_create (&newmsg, NULL);
   mu_message_get_header (newmsg, &hdr); 
   mu_header_set_value (hdr, "Content-Type", "message/rfc822", 1);
   mu_message_get_body (newmsg, &body);
-  mu_body_get_stream (body, &ostream);
-  mu_message_get_stream (msg, &istream);
-  
-  while (mu_stream_read (istream, buffer, sizeof buffer - 1, ioff, &n) == 0
-        && n != 0)
-    {
-      size_t sz;
-      mu_stream_write (ostream, buffer, n, ooff, &sz);
-      if (sz != n)
-       return EIO;
-      ooff += n;
-      ioff += n;
-    }
+  mu_body_get_streamref (body, &ostream);
+  mu_message_get_streamref (msg, &istream);
+
+  rc = mu_stream_copy (ostream, istream, 0, NULL);
+
+  mu_stream_destroy (&istream);
   mu_stream_close (ostream);
+  mu_stream_destroy (&ostream);
+  
   mu_mime_add_part (mime, newmsg);
   mu_message_unref (newmsg);
-  return 0;
+  return rc;
 }
   
 static int
@@ -297,6 +293,7 @@ sieve_action_reject (mu_sieve_machine_t mach, mu_list_t 
args, mu_list_t tags)
   mu_message_t newmsg;
   char *addrtext;
   mu_address_t from, to;
+  mu_header_t hdr;
   
   mu_sieve_value_t *val = mu_sieve_value_get (args, 0);
   if (!val)
@@ -313,6 +310,9 @@ sieve_action_reject (mu_sieve_machine_t mach, mu_list_t 
args, mu_list_t tags)
   mu_mime_get_message (mime, &newmsg);
 
   mu_sieve_get_message_sender (mach->msg, &addrtext);
+  mu_message_get_header (newmsg, &hdr);
+  mu_header_prepend (hdr, MU_HEADER_TO, addrtext);
+
   rc = mu_address_create (&to, addrtext);
   if (rc)
     {
diff --git a/libmu_sieve/extensions/moderator.c 
b/libmu_sieve/extensions/moderator.c
index 9e0aecb..f3dc8c4 100644
--- a/libmu_sieve/extensions/moderator.c
+++ b/libmu_sieve/extensions/moderator.c
@@ -213,7 +213,7 @@ moderator_message_get_part (mu_sieve_machine_t mach,
 
       free (value);
       mu_message_get_body (tmp, &body);
-      mu_body_get_stream (body, &str);
+      mu_body_get_streamref (body, &str);
 
       rc = mu_stream_to_message (str, pmsg);
       if (rc)
@@ -223,6 +223,7 @@ moderator_message_get_part (mu_sieve_machine_t mach,
                          mu_strerror (rc));
          return 1;
        }
+      mu_stream_destroy (&str);
     }
   else if (value)
     {
diff --git a/libmu_sieve/extensions/pipe.c b/libmu_sieve/extensions/pipe.c
index fd61a2d..1378461 100644
--- a/libmu_sieve/extensions/pipe.c
+++ b/libmu_sieve/extensions/pipe.c
@@ -21,9 +21,9 @@
    The pipe action executes a shell command specified by its
    argument and pipes the entire message to its standard input.
    The envelope of the message is included, if the :envelope tag is given.
-   
+
    Notes/FIXME: 1. it would be nice to implement meta-variables in
-                <program call> which would expand to various
+               <program call> which would expand to various
                items from the message being handled.
                2. :mime tag could be useful too.
 */
@@ -41,38 +41,6 @@
 #include <regex.h>
 #include <mailutils/sieve.h>
 
-#define ASSERT(expr, diag, ec)                                                \
- if (!(expr))                                                                 \
-   {                                                                          \
-     if (ec)                                                                  \
-       mu_sieve_error (mach, "%lu: %s: %s",                                   \
-                      (unsigned long) mu_sieve_get_message_num (mach),       \
-                      diag,                                                  \
-                      mu_strerror (ec));                                     \
-     else                                                                     \
-       mu_sieve_error (mach, "%lu: %s",                                       \
-                      (unsigned long) mu_sieve_get_message_num (mach),       \
-                      diag);                                                 \
-     mu_sieve_abort (mach);                                                   \
-   }
-    
-#define ASSERT2(expr, diag, arg, ec)                                          \
- if (!(expr))                                                                 \
-   {                                                                          \
-     if (ec)                                                                  \
-       mu_sieve_error (mach, "%lu: `%s': %s: %s",                             \
-                      (unsigned long) mu_sieve_get_message_num (mach),       \
-                      arg,                                                   \
-                      diag,                                                  \
-                      mu_strerror (ec));                                     \
-     else                                                                     \
-       mu_sieve_error (mach, "%lu: `%s': %s",                                 \
-                      (unsigned long) mu_sieve_get_message_num (mach),       \
-                      arg,                                                   \
-                      diag);                                                 \
-     mu_sieve_abort (mach);                                                   \
-   }
-
 int
 sieve_action_pipe (mu_sieve_machine_t mach, mu_list_t args, mu_list_t tags)
 {
@@ -81,12 +49,25 @@ sieve_action_pipe (mu_sieve_machine_t mach, mu_list_t args, 
mu_list_t tags)
   mu_sieve_value_t *val;
   char *cmd;
   mu_stream_t mstr, pstr;
-  char buf[512];
-  size_t n;
   mu_envelope_t env;
-  
+  const char *error_diag = NULL;
+  const char *error_arg = NULL;
+#define ONERR(rc, diag, arg)                                           \
+  if (rc)                                                              \
+    {                                                                  \
+      error_diag = diag;                                               \
+      error_arg = arg;                                                 \
+      break;                                                           \
+    }
+
   val = mu_sieve_value_get (args, 0);
-  ASSERT (val, _("cannot get command!"), 0);
+  if (!val)
+    {
+      mu_sieve_error (mach, "%lu: %s",
+                     (unsigned long) mu_sieve_get_message_num (mach),
+                     _("cannot get command!"));
+      mu_sieve_abort (mach);
+    }
   cmd = val->v.string;
 
   mu_sieve_log_action (mach, "PIPE", NULL);
@@ -104,49 +85,64 @@ sieve_action_pipe (mu_sieve_machine_t mach, mu_list_t 
args, mu_list_t tags)
 
   msg = mu_sieve_get_message (mach);
   mu_message_get_envelope (msg, &env);
-  
-  rc = mu_message_get_stream (msg, &mstr);
-  ASSERT (rc == 0, _("cannot get message stream"), rc);
-  
-  rc = mu_prog_stream_create (&pstr, cmd, MU_STREAM_WRITE);
-  ASSERT2 (rc == 0, _("cannot create command stream"), cmd, rc);
 
-  rc = mu_stream_open (pstr);
-  ASSERT2 (rc == 0, _("cannot open command stream"), cmd, rc);
-
-  if (mu_sieve_tag_lookup (tags, "envelope", &val))
+  do
     {
-      char *p;
-
-      rc = mu_envelope_aget_sender (env, &p);
-      ASSERT (rc == 0, _("cannot get envelope sender"), rc);
-      rc = mu_stream_sequential_write (pstr, "From ", 5);
-      ASSERT (rc == 0, _("stream write failed"), rc);
-      mu_stream_sequential_write (pstr, p, strlen (p));
-      free (p);
-      rc = mu_stream_sequential_write (pstr, " ", 1);
-      ASSERT (rc == 0, _("stream write failed"), rc);
-      rc = mu_envelope_aget_date (env, &p);
-      ASSERT (rc == 0, _("cannot get envelope date"), rc);
-      rc = mu_stream_sequential_write (pstr, p, strlen (p));
-      ASSERT (rc == 0, _("stream write failed"), rc);
-      free (p);
-      rc = mu_stream_sequential_write (pstr, "\n", 1);
-      ASSERT (rc == 0, _("stream write failed"), rc);
+      rc = mu_message_get_streamref (msg, &mstr);
+      ONERR (rc, _("cannot get message stream"), NULL);
+
+      rc = mu_prog_stream_create (&pstr, cmd, MU_STREAM_WRITE);
+      ONERR (rc, _("cannot create command stream"), cmd);
+
+      rc = mu_stream_open (pstr);
+      ONERR (rc, _("cannot open command stream"), cmd);
+
+      if (mu_sieve_tag_lookup (tags, "envelope", &val))
+       {
+         char *p;
+
+         rc = mu_envelope_aget_sender (env, &p);
+         ONERR (rc, _("cannot get envelope sender"), NULL);
+         rc = mu_stream_write (pstr, "From ", 5, NULL);
+         ONERR (rc, _("stream write failed"), NULL);
+         mu_stream_write (pstr, p, strlen (p), NULL);
+         free (p);
+         rc = mu_stream_write (pstr, " ", 1, NULL);
+         ONERR (rc, _("stream write failed"), NULL);
+         rc = mu_envelope_aget_date (env, &p);
+         ONERR (rc, _("cannot get envelope date"), NULL);
+         rc = mu_stream_write (pstr, p, strlen (p), NULL);
+         ONERR (rc, _("stream write failed"), NULL);
+         free (p);
+         rc = mu_stream_write (pstr, "\n", 1, NULL);
+         ONERR (rc, _("stream write failed"), NULL);
+       }
+
+      rc = mu_stream_copy (pstr, mstr, 0, NULL);
+      ONERR (rc, _("command failed"), cmd);
     }
-  
-  mu_stream_seek (mstr, 0, SEEK_SET);
-  while (rc == 0
-        && mu_stream_sequential_read (mstr, buf, sizeof buf, &n) == 0
-        && n > 0)
-    rc = mu_stream_sequential_write (pstr, buf, n);
+  while (0);
 
+  mu_stream_destroy (&mstr);
   mu_stream_close (pstr);
-  mu_stream_destroy (&pstr, mu_stream_get_owner (pstr));
+  mu_stream_destroy (&pstr);
 
+  if (rc)
+    {
+      if (error_arg)
+       mu_sieve_error (mach, "%lu: %s: %s: %s",
+                       (unsigned long) mu_sieve_get_message_num (mach),
+                       error_diag,
+                       error_arg,
+                       mu_strerror (rc));
+      else
+       mu_sieve_error (mach, "%lu: %s: %s",
+                       (unsigned long) mu_sieve_get_message_num (mach),
+                       error_diag,
+                       mu_strerror (rc));
+      mu_sieve_abort (mach);
+    }
 
-  ASSERT2 (rc == 0, _("command failed"), cmd, rc);
-  
   return 0;
 }
 
@@ -155,9 +151,9 @@ static mu_sieve_tag_def_t pipe_tags[] = {
   { "envelope", SVT_VOID },
   { NULL }
 };
-  
+
 static mu_sieve_tag_group_t pipe_tag_groups[] = {
-  { pipe_tags, NULL }, 
+  { pipe_tags, NULL },
   { NULL }
 };
 
@@ -173,4 +169,3 @@ SIEVE_EXPORT (pipe, init) (mu_sieve_machine_t mach)
   return mu_sieve_register_action (mach, "pipe", sieve_action_pipe,
                                   pipe_args, pipe_tag_groups, 1);
 }
-
diff --git a/libmu_sieve/extensions/spamd.c b/libmu_sieve/extensions/spamd.c
index 0ee0a4c..e620e58 100644
--- a/libmu_sieve/extensions/spamd.c
+++ b/libmu_sieve/extensions/spamd.c
@@ -34,6 +34,8 @@
 #include <mailutils/sieve.h>
 #include <mailutils/mu_auth.h>
 #include <mailutils/nls.h>
+#include <mailutils/filter.h>
+#include <mailutils/stream.h>
 
 #define DEFAULT_SPAMD_PORT 783
 
@@ -44,7 +46,7 @@ static int
 spamd_connect_tcp (mu_sieve_machine_t mach, mu_stream_t *stream,
                   char *host, int port)
 {
-  int rc = mu_tcp_stream_create (stream, host, port, MU_STREAM_NO_CHECK);
+  int rc = mu_tcp_stream_create (stream, host, port, 0);
   if (rc)
     {
       mu_sieve_error (mach, "mu_tcp_stream_create: %s", mu_strerror (rc));
@@ -54,7 +56,7 @@ spamd_connect_tcp (mu_sieve_machine_t mach, mu_stream_t 
*stream,
   if (rc)
     {
       mu_sieve_error (mach, "opening tcp stream: %s", mu_strerror (rc));
-      mu_stream_destroy (stream, NULL);
+      mu_stream_destroy (stream);
     }
   return rc;
 }
@@ -62,7 +64,7 @@ spamd_connect_tcp (mu_sieve_machine_t mach, mu_stream_t 
*stream,
 static int
 spamd_connect_socket (mu_sieve_machine_t mach, mu_stream_t *stream, char *path)
 {
-  int rc = mu_socket_stream_create (stream, path, MU_STREAM_NO_CHECK);
+  int rc = mu_socket_stream_create (stream, path, 0);
   if (rc)
     {
       mu_sieve_error (mach, "mu_socket_stream_create: %s", mu_strerror (rc));
@@ -72,7 +74,7 @@ spamd_connect_socket (mu_sieve_machine_t mach, mu_stream_t 
*stream, char *path)
   if (rc)
     {
       mu_sieve_error (mach, "opening socket stream: %s", mu_strerror (rc));
-      mu_stream_destroy (stream, NULL);
+      mu_stream_destroy (stream);
     }
 
   return rc;
@@ -82,7 +84,7 @@ static void
 spamd_destroy (mu_stream_t *stream)
 {
   mu_stream_close (*stream);
-  mu_stream_destroy (stream, mu_stream_get_owner (*stream));
+  mu_stream_destroy (stream);
 }
 
 static void
@@ -95,33 +97,31 @@ spamd_send_command (mu_stream_t stream, const char *fmt, 
...)
   va_start (ap, fmt);
   n = vsnprintf (buf, sizeof buf, fmt, ap);
   va_end (ap);
-  mu_stream_sequential_write (stream, buf, n);
-  mu_stream_sequential_write (stream, "\r\n", 2);
+  mu_stream_writeline (stream, buf, n);
 }
 
-static void
+static int
 spamd_send_message (mu_stream_t stream, mu_message_t msg)
 {
-  size_t size;
-  char buf[512];
-  mu_stream_t mstr;
+  int rc;
+  mu_stream_t mstr, flt;
 
-  mu_message_get_stream (msg, &mstr);
-  mu_stream_seek (mstr, 0, SEEK_SET);
-  while (mu_stream_sequential_readline (mstr, buf, sizeof (buf), &size) == 0
-        && size > 0)
+  rc = mu_message_get_streamref (msg, &mstr);
+  if (rc)
+    return rc;
+  rc = mu_filter_create (&flt, mstr, "rfc822", MU_FILTER_ENCODE,
+                        MU_STREAM_READ|MU_STREAM_SEEK);
+  if (rc)
     {
-      char *nl = NULL;
-      
-      if (buf[size-1] == '\n')
-       {
-         size--;
-         nl = "\r\n";
-       }
-      mu_stream_sequential_write (stream, buf, size);
-      if (nl)
-       mu_stream_sequential_write (stream, nl, 2);
+      mu_stream_destroy (&mstr);
+      return rc;
     }
+
+  rc = mu_stream_copy (stream, flt, 0, NULL);
+
+  mu_stream_destroy (&mstr);
+  mu_stream_destroy (&flt);
+  return rc;
 }
 
 static size_t
@@ -129,7 +129,7 @@ spamd_read_line (mu_sieve_machine_t mach, mu_stream_t 
stream,
                 char *buffer, size_t size, size_t *pn)
 {
   size_t n = 0;
-  int rc = mu_stream_sequential_readline (stream, buffer, size, &n);
+  int rc = mu_stream_readline (stream, buffer, size, &n);
   if (rc == 0)
     {
       if (pn)
@@ -285,6 +285,9 @@ spamd_test (mu_sieve_machine_t mach, mu_list_t args, 
mu_list_t tags)
                   (u_long) mu_sieve_get_message_num (mach));
     }
   
+  if (mu_sieve_is_dry_run (mach))
+    return 0;
+  
   if (mu_sieve_tag_lookup (tags, "host", &arg))
     host = arg->v.string;
   else
diff --git a/libmu_sieve/extensions/vacation.c 
b/libmu_sieve/extensions/vacation.c
index a2debf5..6b220df 100644
--- a/libmu_sieve/extensions/vacation.c
+++ b/libmu_sieve/extensions/vacation.c
@@ -42,7 +42,6 @@
 
 /* Build a mime response message from original message MSG. TEXT
    is the message text.
-   FIXME: This is for future use, when I add :mime tag
 */
 static int
 build_mime (mu_sieve_machine_t mach, mu_list_t tags, mu_mime_t *pmime,
@@ -50,25 +49,25 @@ build_mime (mu_sieve_machine_t mach, mu_list_t tags, 
mu_mime_t *pmime,
 {
   mu_mime_t mime = NULL;
   mu_message_t newmsg;
-  mu_stream_t stream, input, save_input = NULL;
+  mu_stream_t stream, input;
   mu_header_t hdr;
   mu_body_t body;
-  char buf[512];
-  size_t n;
-  char *header = "Content-Type: text/plain;charset=" MU_SIEVE_CHARSET "\n"
-              "Content-Transfer-Encoding: 8bit\n\n";
+  const char *header =
+    "Content-Type: text/plain;charset=" MU_SIEVE_CHARSET "\n"
+    "Content-Transfer-Encoding: 8bit\n\n";
   int rc;
   
   mu_mime_create (&mime, NULL, 0);
   mu_message_create (&newmsg, NULL);
   mu_message_get_body (newmsg, &body);
-  mu_body_get_stream (body, &stream);
 
-  if ((rc = mu_memory_stream_create (&input, 0, MU_STREAM_RDWR)))
+  if ((rc = mu_memory_stream_create (&input, MU_STREAM_RDWR)))
     {
       mu_sieve_error (mach,
                      _("cannot create temporary stream: %s"),
                      mu_strerror (rc));
+      mu_mime_destroy (&mime);
+      mu_message_destroy (&newmsg, NULL);
       return 1;
     }
 
@@ -77,35 +76,57 @@ build_mime (mu_sieve_machine_t mach, mu_list_t tags, 
mu_mime_t *pmime,
       mu_sieve_error (mach,
                      _("cannot open temporary stream: %s"),
                      mu_strerror (rc));
+      mu_mime_destroy (&mime);
+      mu_message_destroy (&newmsg, NULL);
+      mu_stream_destroy (&input);
       return 1;
     }
   
-  mu_stream_write (input, text, strlen (text), 0, &n);
+  mu_stream_write (input, text, strlen (text), NULL);
 
   if (mu_sieve_tag_lookup (tags, "mime", NULL))
     {
       mu_stream_t fstr;
       rc = mu_filter_create (&fstr, input, "base64",
-                            MU_FILTER_ENCODE, MU_STREAM_READ);
+                            MU_FILTER_ENCODE, 
+                            MU_STREAM_READ | MU_STREAM_AUTOCLOSE);
       if (rc == 0) 
        {
          header = "Content-Type: text/plain;charset=" MU_SIEVE_CHARSET "\n"
                   "Content-Transfer-Encoding: base64\n\n";
-         save_input = input;
          input = fstr;
        }
     }
 
-  while (rc == 0
-        && mu_stream_sequential_read (input, buf, sizeof buf, &n) == 0
-        && n > 0)
-    rc = mu_stream_sequential_write (stream, buf, n);
+  rc = mu_body_get_streamref (body, &stream);
+  if (rc)
+    {
+      mu_sieve_error (mach,
+                     _("cannot get input body stream: %s"),
+                     mu_strerror (rc));
+      mu_mime_destroy (&mime);
+      mu_message_destroy (&newmsg, NULL);
+      mu_stream_destroy (&input);
+      return 1;
+    }
+
+  mu_stream_seek (input, 0, MU_SEEK_SET, NULL);
+  rc = mu_stream_copy (stream, input, 0, NULL);
+  if (rc)
+    {
+      mu_sieve_error (mach,
+                     _("stream copy failed: %s"),
+                     mu_strerror (rc));
+      mu_mime_destroy (&mime);
+      mu_message_destroy (&newmsg, NULL);
+      mu_stream_destroy (&input);
+      mu_stream_destroy (&stream);
+      return 1;
+    }
 
-  mu_stream_destroy (&input, mu_stream_get_owner (input));
-  if (save_input)
-    mu_stream_destroy (&save_input, mu_stream_get_owner (save_input));
+  mu_stream_destroy (&input);
   
-  mu_header_create (&hdr, header, strlen (header), newmsg);
+  mu_header_create (&hdr, header, strlen (header));
   mu_message_set_header (newmsg, hdr, NULL);
 
   mu_mime_add_part (mime, newmsg);
diff --git a/libproto/Makefile.am b/libproto/Makefile.am
index 314cfb7..3ba7d19 100644
--- a/libproto/Makefile.am
+++ b/libproto/Makefile.am
@@ -17,5 +17,25 @@
 ##   Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA
 ##   02110-1301 USA
 
-SUBDIRS = include mbox pop nntp imap mh maildir mailer
+if MU_COND_SUPPORT_POP
+  POP_DIR = pop
+endif
+
+if MU_COND_SUPPORT_IMAP
+  IMAP_DIR = imap
+endif
+
+if MU_COND_SUPPORT_NNTP
+  NNTP_DIR = nntp
+endif
+
+if MU_COND_SUPPORT_MH
+  MH_DIR = mh
+endif
+
+if MU_COND_SUPPORT_MAILDIR
+  MAILDIR_DIR = maildir
+endif
+
+SUBDIRS = mbox $(POP_DIR) $(NNTP_DIR) $(IMAP_DIR) $(MH_DIR) $(MAILDIR_DIR) 
mailer
 
diff --git a/libproto/imap/Makefile.am b/libproto/imap/Makefile.am
index 1acdfd4..dd37326 100644
--- a/libproto/imap/Makefile.am
+++ b/libproto/imap/Makefile.am
@@ -18,7 +18,7 @@
 ##   Foundation, Inc.  51 Franklin Street, Fifth Floor, Boston, MA
 ##   02110-1301 USA
 
-INCLUDES = @MU_LIB_COMMON_INCLUDES@ -I${top_srcdir}/libproto/include 
+INCLUDES = @MU_LIB_COMMON_INCLUDES@ 
 
 lib_LTLIBRARIES = libmu_imap.la
 libmu_imap_la_LDFLAGS=-version-info @VI_CURRENT@:@VI_REVISION@:@VI_AGE@
diff --git a/libproto/imap/folder.c b/libproto/imap/folder.c
index 77e7919..4f27c49 100644
--- a/libproto/imap/folder.c
+++ b/libproto/imap/folder.c
@@ -34,8 +34,8 @@
 # include <strings.h>
 #endif
 
-#include <imap0.h>
-#include <url0.h>
+#include <mailutils/sys/imap.h>
+#include <mailutils/sys/url.h>
 
 #include <mailutils/auth.h>
 #include <mailutils/attribute.h>
@@ -688,10 +688,12 @@ folder_imap_open (mu_folder_t folder, int flags)
              CHECK_EAGAIN (f_imap, status);
              CHECK_ERROR_CLOSE (folder, f_imap, status);
 
-             status = mu_tls_stream_create_client_from_tcp (&newstr, 
folder->stream, 0);
+             status = mu_tls_client_stream_create (&newstr, 
+                                                   folder->stream,
+                                                   folder->stream, 0);
              if (status != 0)
                {
-                 mu_error ("folder_imap_open: 
mu_tls_stream_create_client_from_tcp: %s",
+                 mu_error ("folder_imap_open: mu_tls_client_stream_create: %s",
                            mu_strerror (status));
                  return status;
                }
@@ -2610,7 +2612,7 @@ imap_parse (f_imap_t f_imap)
 
 #else
 #include <stdio.h>
-#include <registrar0.h>
+#include <mailutils/sys/registrar.h>
 mu_record_t mu_imap_record = NULL;
 mu_record_t mu_imaps_record = NULL;
 #endif /* ENABLE_IMAP */
diff --git a/libproto/imap/mbox.c b/libproto/imap/mbox.c
index 3bf1d1b..5163eeb 100644
--- a/libproto/imap/mbox.c
+++ b/libproto/imap/mbox.c
@@ -47,10 +47,10 @@
 #include <mailutils/stream.h>
 #include <mailutils/io.h>
 
-#include <imap0.h>
-#include <mailbox0.h>
-#include <registrar0.h>
-#include <url0.h>
+#include <mailutils/sys/imap.h>
+#include <mailutils/sys/mailbox.h>
+#include <mailutils/sys/registrar.h>
+#include <mailutils/sys/url.h>
 
 #undef min
 #define min(a,b) ((a) < (b) ? (a) : (b))
diff --git a/libproto/imap/url.c b/libproto/imap/url.c
index 5fa06f5..8e3ae1a 100644
--- a/libproto/imap/url.c
+++ b/libproto/imap/url.c
@@ -31,8 +31,8 @@
 # include <strings.h>
 #endif
 
-#include <registrar0.h>
-#include <url0.h>
+#include <mailutils/sys/registrar.h>
+#include <mailutils/sys/url.h>
 
 static void url_imap_destroy (mu_url_t url);
 
diff --git a/libproto/include/.gitignore b/libproto/include/.gitignore
deleted file mode 100644
index 282522d..0000000
--- a/libproto/include/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-Makefile
-Makefile.in
diff --git a/libproto/include/Makefile.am b/libproto/include/Makefile.am
deleted file mode 100644
index 0b59a44..0000000
--- a/libproto/include/Makefile.am
+++ /dev/null
@@ -1,43 +0,0 @@
-## Process this file with GNU Automake to create Makefile.in
-
-##   Copyright (C) 2000, 2001, 2002, 2007, 2009, 2010 Free Software
-##   Foundation, Inc.
-##
-##   GNU Mailutils is free software; you can redistribute it and/or
-##   modify it under the terms of the GNU General Public License as
-##   published by the Free Software Foundation; either version 3, or (at
-##   your option) any later version.
-##
-##   This program is distributed in the hope that it will be useful, but
-##   WITHOUT ANY WARRANTY; without even the implied warranty of
-##   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-##   General Public License for more details.
-##
-##   You should have received a copy of the GNU General Public License
-##   along with this program; if not, write to the Free Software
-##   Foundation, Inc.  51 Franklin Street, Fifth Floor, Boston, MA
-##   02110-1301 USA
-
-noinst_HEADERS = \
-attribute0.h \
-amd.h \
-auth0.h \
-body0.h \
-debug0.h \
-envelope0.h \
-filter0.h \
-folder0.h \
-header0.h \
-iterator0.h \
-imap0.h \
-list0.h \
-mailbox0.h \
-mailer0.h \
-message0.h \
-mime0.h \
-monitor0.h  \
-observer0.h \
-property0.h \
-registrar0.h \
-stream0.h \
-url0.h
diff --git a/libproto/include/amd.h b/libproto/include/amd.h
deleted file mode 100644
index f643453..0000000
--- a/libproto/include/amd.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008,
-   2010 Free Software Foundation, Inc.
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General
-   Public License along with this library; if not, write to the
-   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301 USA */
-
-#define MAX_OPEN_STREAMS 16
-
-/* Notifications ADD_MESG. */
-#define DISPATCH_ADD_MSG(mbox,mhd,n)                                   \
-  do                                                                   \
-    {                                                                  \
-      int bailing = 0;                                                 \
-      mu_monitor_unlock (mbox->monitor);                               \
-      if (mbox->observable)                                            \
-       {                                                               \
-         size_t tmp = n;                                               \
-         bailing = mu_observable_notify (mbox->observable,             \
-                                         MU_EVT_MESSAGE_ADD,           \
-                                         &tmp);                        \
-       }                                                               \
-      if (bailing != 0)                                                        
\
-       {                                                               \
-         if (pcount)                                                   \
-           *pcount = (mhd)->msg_count;                                 \
-         mu_locker_unlock (mbox->locker);                              \
-         return EINTR;                                                 \
-       }                                                               \
-      mu_monitor_wrlock (mbox->monitor);                               \
-} while (0);
-
-#define MU_AMD_SIZE_FILE_NAME ".mu-size"
-
-struct _amd_data;
-struct _amd_message
-{
-  mu_stream_t stream;       /* Associated file stream */
-  mu_off_t body_start;      /* Offset of body start in the message file */
-  mu_off_t body_end;        /* Offset of body end (size of file, effectively)*/
-
-  int orig_flags;           /* Original attribute flags */
-  int attr_flags;           /* Current attribute flags */
-       
-
-  time_t mtime;             /* Time of last modification */
-  size_t header_lines;      /* Number of lines in the header part */
-  size_t body_lines;        /* Number of lines in the body */
-
-  mu_message_t message;     /* Corresponding mu_message_t */
-  struct _amd_data *amd;    /* Back pointer.  */
-};
-
-struct _amd_data
-{
-  size_t msg_size;               /* Size of struct _amd_message */
-  int (*create) (struct _amd_data *, int flags);       
-  int (*msg_init_delivery) (struct _amd_data *, struct _amd_message *);
-  int (*msg_finish_delivery) (struct _amd_data *, struct _amd_message *,
-                             const mu_message_t);
-  void (*msg_free) (struct _amd_message *);
-  int (*cur_msg_file_name) (struct _amd_message *, char **);   
-  int (*new_msg_file_name) (struct _amd_message *, int, int, char **);
-  int (*scan0)     (mu_mailbox_t mailbox, size_t msgno, size_t *pcount,
-                   int do_notify);
-  int (*mailbox_size) (mu_mailbox_t mailbox, mu_off_t *psize);
-  int (*qfetch)    (struct _amd_data *, mu_message_qid_t qid);
-  int (*msg_cmp) (struct _amd_message *, struct _amd_message *);
-  int (*message_uid) (mu_message_t msg, size_t *puid);
-  size_t (*next_uid) (struct _amd_data *mhd);
-  
-  /* List of messages: */
-  size_t msg_count; /* number of messages in the list */
-  size_t msg_max;   /* maximum message buffer capacity */
-  struct _amd_message **msg_array;
-
-  unsigned long uidvalidity;
-  int has_new_msg;  /* New messages have been appended */
-  char *name;                    /* Directory name */
-
-  /* Pool of open message streams */
-  struct _amd_message *msg_pool[MAX_OPEN_STREAMS];
-  int pool_first;    /* Index to the first used entry in msg_pool */
-  int pool_last;     /* Index to the first free entry in msg_pool */
-
-  time_t mtime;      /* Time of last modification */
-
-  mu_mailbox_t mailbox; /* Back pointer. */
-};
-
-
-int amd_init_mailbox (mu_mailbox_t mailbox, size_t mhd_size,
-                     struct _amd_data **pmhd);
-int _amd_message_insert (struct _amd_data *mhd, struct _amd_message *msg);
-int amd_message_stream_open (struct _amd_message *mhm);
-void amd_message_stream_close (struct _amd_message *mhm);
-void amd_cleanup (void *arg);
-struct _amd_message *_amd_get_message (struct _amd_data *amd, size_t msgno);
-int amd_msg_lookup (struct _amd_data *amd, struct _amd_message *msg,
-                   size_t *pret);
diff --git a/libproto/include/attribute0.h b/libproto/include/attribute0.h
deleted file mode 100644
index f379f7f..0000000
--- a/libproto/include/attribute0.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 1999, 2000, 2005, 2007, 2010 Free Software Foundation,
-   Inc.
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General
-   Public License along with this library; if not, write to the
-   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301 USA */
-
-#ifndef _ATTRIBUTE0_H
-# define _ATTRIBUTE0_H
-
-#ifdef DMALLOC
-#  include <dmalloc.h>
-#endif
-
-#include <mailutils/attribute.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct _mu_attribute
-{
-  void *owner;
-
-  int flags;
-  int user_flags;
-
-  int (*_get_flags)   (mu_attribute_t, int *);
-  int (*_set_flags)   (mu_attribute_t, int);
-  int (*_unset_flags) (mu_attribute_t, int);
-};
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _ATTRIBUTE0_H */
diff --git a/libproto/include/auth0.h b/libproto/include/auth0.h
deleted file mode 100644
index 7868bad..0000000
--- a/libproto/include/auth0.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 1999, 2000, 2001, 2005, 2007, 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 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General
-   Public License along with this library; if not, write to the
-   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301 USA */
-
-#ifndef _AUTH0_H
-#define _AUTH0_H
-
-#ifdef DMALLOC
-#  include <dmalloc.h>
-#endif
-
-#include <mailutils/auth.h>
-#include <mailutils/list.h>
-#include <sys/types.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct _mu_ticket
-{
-  void *owner;           /* Object owner.  Not actually needed, but retained
-                           for a while. */
-  unsigned int refcnt;   /* Reference counter */
-  char *plain;           /* Plaintext credential (if any) */
-  mu_secret_t secret;    /* Secret credential (if any) */
-  void (*_destroy)  (mu_ticket_t); /* Destroy function */
-  /* Function for obtaining credentials */
-  int  (*_get_cred) (mu_ticket_t, mu_url_t, const char *, char **,
-                    mu_secret_t *);
-  /* Additional data for _get_cred */
-  void *data;
-};
-
-struct _mu_authority
-{
-  void *owner;
-  mu_ticket_t ticket;
-  mu_list_t auth_methods; /* list of int (*_authenticate) (mu_authority_t)s; */
-};
-
-struct _mu_wicket
-{
-  unsigned int refcnt;   /* Reference counter */
-  void *data;
-  int (*_get_ticket) (mu_wicket_t, void *, const char *, mu_ticket_t *);
-  void (*_destroy) (mu_wicket_t);
-};
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _AUTH0_H */
diff --git a/libproto/include/body0.h b/libproto/include/body0.h
deleted file mode 100644
index 156793c..0000000
--- a/libproto/include/body0.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 1999, 2000, 2001, 2007, 2010 Free Software Foundation,
-   Inc.
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General
-   Public License along with this library; if not, write to the
-   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301 USA */
-
-#ifndef _BODY0_H
-#define _BODY0_H
-
-#ifdef DMALLOC
-#  include <dmalloc.h>
-#endif
-
-#include <mailutils/stream.h>
-#include <mailutils/body.h>
-
-#include <stdio.h>
-#include <sys/types.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct _mu_body
-{
-  void *owner;
-  char *filename;
-  mu_stream_t stream;
-  mu_stream_t fstream;
-  int flags;
-
-  int (*_size)  (mu_body_t, size_t*);
-  int (*_lines) (mu_body_t, size_t*);
-};
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _BODY0_H */
diff --git a/libproto/include/debug0.h b/libproto/include/debug0.h
deleted file mode 100644
index 1b4fc46..0000000
--- a/libproto/include/debug0.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 1999, 2000, 2005, 2007, 2010 Free Software Foundation,
-   Inc.
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General
-   Public License along with this library; if not, write to the
-   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301 USA */
-
-#ifndef _DEBUG0_H
-#define _DEBUG0_H
-
-#ifdef DMALLOC
-#  include <dmalloc.h>
-#endif
-
-#include <mailutils/debug.h>
-#include <mailutils/stream.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct _mu_debug
-{
-  size_t level;
-  mu_stream_t stream;
-  void *owner;
-  struct mu_debug_locus locus;
-  const char *function;
-  void *data;
-  mu_debug_printer_fp printer;
-  void (*destroy) (void *data);
-};
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _DEBUG0_H */
diff --git a/libproto/include/envelope0.h b/libproto/include/envelope0.h
deleted file mode 100644
index 5e1cae4..0000000
--- a/libproto/include/envelope0.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 1999, 2000, 2005, 2007, 2010 Free Software Foundation,
-   Inc.
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General
-   Public License along with this library; if not, write to the
-   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301 USA */
-
-#ifndef _ENVELOPE0_H
-#define _ENVELOPE0_H
-
-#ifdef DMALLOC
-#include <dmalloc.h>
-#endif
-
-#include <mailutils/envelope.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct _mu_envelope
-{
-  void *owner;
-  char *date;
-  char *sender;
-  int (*_destroy) (mu_envelope_t);
-  int (*_get_sender)  (mu_envelope_t, char *, size_t, size_t *);
-  int (*_get_date)    (mu_envelope_t, char *, size_t , size_t *);
-};
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _ENVELOPE0_H */
diff --git a/libproto/include/filter0.h b/libproto/include/filter0.h
deleted file mode 100644
index 6de572b..0000000
--- a/libproto/include/filter0.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 1999, 2000, 2001, 2005, 2007, 2010 Free Software
-   Foundation, Inc.
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General
-   Public License along with this library; if not, write to the
-   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301 USA */
-
-#ifndef _FILTER0_H
-#define _FILTER0_H
-
-#include <mailutils/filter.h>
-#include <mailutils/list.h>
-#include <mailutils/monitor.h>
-#include <mailutils/property.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct _mu_filter
-{
-  mu_stream_t stream;
-  mu_stream_t filter_stream;
-  mu_property_t property;
-  int direction;
-  int type;
-  void *data;
-  int  (*_read)     (mu_filter_t, char *, size_t, mu_off_t, size_t *);
-  int  (*_readline) (mu_filter_t, char *, size_t, mu_off_t, size_t *);
-  int  (*_write)    (mu_filter_t, const char *, size_t, mu_off_t, size_t *);
-  void (*_destroy)  (mu_filter_t);
-};
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _FILTER0_H */
diff --git a/libproto/include/folder0.h b/libproto/include/folder0.h
deleted file mode 100644
index 060e6a3..0000000
--- a/libproto/include/folder0.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 1999, 2000, 2001, 2005, 2007, 2010 Free Software
-   Foundation, Inc.
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General
-   Public License along with this library; if not, write to the
-   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301 USA */
-
-#ifndef _FOLDER0_H
-#define _FOLDER0_H
-
-#ifdef DMALLOC
-#  include <dmalloc.h>
-#endif
-
-#include <sys/types.h>
-#include <stdio.h>
-
-#include <mailutils/monitor.h>
-#include <mailutils/folder.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define MU_FOLDER_LIST 0
-#define MU_FOLDER_ENUM 1
-  
-struct _mu_folder
-{
-  /* Data */
-  mu_authority_t authority;
-  mu_observable_t observable;
-  mu_debug_t debug;
-  mu_stream_t stream;
-  mu_monitor_t monitor;
-  mu_url_t url;
-  int flags;
-  int ref;
-  size_t uid;
-
-  /* Back pointer to the specific mailbox */
-  void *data;
-
-  /* Public methods */
-
-  void (*_destroy)     (mu_folder_t);
-
-  int  (*_open)        (mu_folder_t, int flag);
-  int  (*_close)       (mu_folder_t);
-  int  (*_list)        (mu_folder_t, const char *, void *, int, size_t,
-                       mu_list_t, mu_folder_enumerate_fp, void *);
-  int  (*_lsub)        (mu_folder_t, const char *, const char *,
-                       mu_list_t);
-  mu_folder_match_fp   _match;
-  int  (*_delete)      (mu_folder_t, const char *);
-  int  (*_rename)      (mu_folder_t, const char *, const char *);
-  int  (*_subscribe)   (mu_folder_t, const char *);
-  int  (*_unsubscribe) (mu_folder_t, const char *);
-};
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _FOLDER0_H */
diff --git a/libproto/include/header0.h b/libproto/include/header0.h
deleted file mode 100644
index c4a8a68..0000000
--- a/libproto/include/header0.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 1999, 2000, 2001, 2005, 2007, 2010 Free Software
-   Foundation, Inc.
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General
-   Public License along with this library; if not, write to the
-   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301 USA */
-
-#ifndef _HEADER0_H
-#define _HEADER0_H
-
-#ifdef DMALLOC
-# include <dmalloc.h>
-#endif
-
-#include <mailutils/header.h>
-#include <mailutils/assoc.h>
-#include <mailutils/iterator.h>
-#include <sys/types.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* The structure members are offset that point to the begin/end of header
-   fields.  */
-struct mu_hdrent
-{
-  struct mu_hdrent *prev;
-  struct mu_hdrent *next;
-  size_t fn;
-  size_t nlen;
-  size_t fv;
-  size_t vlen;
-  size_t nlines;
-};
-
-struct _mu_header
-{
-  /* Owner.  */
-  void *owner;
-
-  /* Data.  */
-  char *spool;
-  size_t spool_size;
-  size_t spool_used;
-  struct mu_hdrent *head, *tail;
-  int flags;
-
-  size_t numhdr;
-  size_t numlines;
-  size_t size;
-  
-  /* Temporary storage */
-  mu_stream_t mstream;
-  size_t mstream_size;
-  
-  /* Stream.  */
-  mu_stream_t stream;
-  size_t strpos;
-
-  /* Iterators */
-  mu_iterator_t itr;
-
-  /* Methods */
-  int (*_fill)      (mu_header_t, char *, size_t, mu_off_t, size_t *);
-};
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _HEADER0_H */
diff --git a/libproto/include/imap0.h b/libproto/include/imap0.h
deleted file mode 100644
index 0b4ff33..0000000
--- a/libproto/include/imap0.h
+++ /dev/null
@@ -1,241 +0,0 @@
-/* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 1999, 2000, 2001, 2005, 2007, 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 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General
-   Public License along with this library; if not, write to the
-   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301 USA */
-
-#ifndef _IMAP0_H
-#define _IMAP0_H
-
-#ifdef DMALLOC
-#  include <dmalloc.h>
-#endif
-
-#include <folder0.h>
-#include <mailbox0.h>
-#include <registrar0.h>
-#include <auth0.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define CLEAR_STATE(f_imap) \
- f_imap->selected = NULL, f_imap->state = IMAP_NO_STATE
-
-/* Clear the state and close the stream.  */
-#define CHECK_ERROR_CLOSE(folder, f_imap, status) \
-do \
-  { \
-     if (status != 0) \
-       { \
-          mu_stream_close (folder->stream); \
-          CLEAR_STATE (f_imap); \
-          return status; \
-       } \
-  } \
-while (0)
-
-/* Clear the state.  */
-#define CHECK_ERROR(f_imap, status) \
-do \
-  { \
-     if (status != 0) \
-       { \
-          CLEAR_STATE (f_imap); \
-          return status; \
-       } \
-  } \
-while (0)
-
-/* Clear the state for non recoverable error.  */
-#define CHECK_EAGAIN(f_imap, status) \
-do \
-  { \
-    if (status != 0) \
-      { \
-         if (status != EAGAIN && status != EINPROGRESS && status != EINTR) \
-           { \
-             CLEAR_STATE (f_imap); \
-           } \
-         return status; \
-      } \
-   }  \
-while (0)
-
-
-struct _f_imap;
-struct _m_imap;
-struct _msg_imap;
-typedef struct _f_imap *f_imap_t;
-typedef struct _m_imap *m_imap_t;
-typedef struct _msg_imap *msg_imap_t;
-
-enum imap_state
-{
-  IMAP_NO_STATE=0,
-  IMAP_AUTH, IMAP_AUTH_DONE,
-  IMAP_APPEND, IMAP_APPEND_CONT, IMAP_APPEND_SEND, IMAP_APPEND_ACK,
-  IMAP_BODY,
-  IMAP_CLOSE, IMAP_CLOSE_ACK,
-  IMAP_COPY, IMAP_COPY_ACK,
-  IMAP_CREATE, IMAP_CREATE_ACK,
-  IMAP_DELETE, IMAP_DELETE_ACK,
-  IMAP_EXPUNGE, IMAP_EXPUNGE_ACK,
-  IMAP_FETCH, IMAP_FETCH_ACK,
-  IMAP_GREETINGS,
-  IMAP_HEADER,
-  IMAP_HEADER_FIELD,
-  IMAP_LIST, IMAP_LIST_PARSE, IMAP_LIST_ACK,
-  IMAP_LOGIN, IMAP_LOGIN_ACK,
-  IMAP_LOGOUT, IMAP_LOGOUT_ACK,
-  IMAP_LSUB, IMAP_LSUB_ACK,
-  IMAP_MESSAGE,
-  IMAP_NOOP, IMAP_NOOP_ACK,
-  IMAP_OPEN_CONNECTION,
-  IMAP_RENAME, IMAP_RENAME_ACK,
-  IMAP_SCAN, IMAP_SCAN_ACK,
-  IMAP_SELECT, IMAP_SELECT_ACK,
-  IMAP_STORE, IMAP_STORE_ACK,
-  IMAP_SUBSCRIBE, IMAP_SUBSCRIBE_ACK,
-  IMAP_UNSUBSCRIBE, IMAP_UNSUBSCRIBE_ACK
-};
-
-enum imap_auth_state
-{
-  /* ANONYMOUS */
-  IMAP_AUTH_ANON_REQ_WRITE,
-  IMAP_AUTH_ANON_REQ_SEND,
-  IMAP_AUTH_ANON_WAIT_CONT,
-  IMAP_AUTH_ANON_MSG,
-  IMAP_AUTH_ANON_MSG_SEND,
-  IMAP_AUTH_ANON_WAIT_RESP
-};
-
-struct literal_string
-{
-  char *buffer;
-  size_t buflen;
-  size_t total;
-  msg_imap_t msg_imap;
-  enum imap_state type;
-  size_t nleft;  /* nleft to read in the literal. */
-};
-
-struct _f_imap
-{
-  /* Back pointer.  */
-  mu_folder_t folder;
-  m_imap_t selected;
-
-  enum imap_state state;
-  int imaps; /* IMAPS or IMAP? */
-
-  size_t seq; /* Sequence number to build a tag.  */
-  char **capav; /* Cabilities of the server.  */
-  int capac;    /* Number of capabilities in the above array */
-  int flags;
-
-  /* IO use to hold the literal and quoted strings send by
-     the IMAP server.  */
-  struct
-  {
-    mu_stream_t stream;
-    mu_off_t offset;
-    size_t nleft;  /* nleft to read in the literal. */
-    msg_imap_t msg_imap;
-    enum imap_state type;
-  } string;
-
-  /* Use for LIST and LSUB.  */
-  mu_list_t flist;
-  mu_folder_enumerate_fp enum_fun;
-  void *enum_data;
-  int enum_stop;
-  
-  int isopen;
-
-  /* Server channel buffer I/O  */
-  size_t buflen;
-  char *buffer;
-  char *ptr;
-  char *nl;
-  mu_off_t offset; /* Dummy, this is used because of the stream buffering.
-                   The mu_stream_t maintains and offset and the offset we
-                  use must be in sync.  */
-
-  /* Login  */
-  char *user;
-  mu_secret_t secret;
-
-  /* AUTHENTICATE states */
-  enum imap_auth_state auth_state;
-};
-
-struct _m_imap
-{
-  /* Back pointers.  */
-  mu_mailbox_t mailbox;
-  f_imap_t f_imap;
-  size_t messages_count;
-  size_t imessages_count;
-  msg_imap_t *imessages;
-  size_t recent;
-  size_t unseen;
-  unsigned long uidvalidity;
-  size_t uidnext;
-  char *name;
-  enum imap_state state;
-    /* mailbox operations can be sequences of folder operations, and
-       thus need to keep meta-state, mailbox_imap_open(), for example. */
-};
-
-struct _msg_imap
-{
-  /* Back pointers.  */
-  mu_message_t message;
-  m_imap_t m_imap;
-  size_t num;
-  size_t part;
-  size_t num_parts;
-  msg_imap_t *parts;
-  msg_imap_t parent;
-  int flags;
-  size_t uid;
-
-  mu_header_t fheader;
-  char *internal_date;
-
-  size_t mu_message_size;
-  size_t mu_message_lines;
-  size_t body_size;
-  size_t body_lines;
-  size_t header_size;
-  size_t header_lines;
-};
-
-int imap_writeline    (f_imap_t,  const char *format, ...) MU_PRINTFLIKE(2,3);
-int imap_write        (f_imap_t);
-int imap_send         (f_imap_t);
-int imap_parse        (f_imap_t);
-int imap_readline     (f_imap_t);
-char *section_name    (msg_imap_t);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _IMAP0_H */
diff --git a/libproto/include/iterator0.h b/libproto/include/iterator0.h
deleted file mode 100644
index 8abbb80..0000000
--- a/libproto/include/iterator0.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 1999, 2000, 2004, 2007, 2010 Free Software Foundation,
-   Inc.
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General
-   Public License along with this library; if not, write to the
-   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301 USA */
-
-#ifndef _ITERATOR0_H
-#define _ITERATOR0_H
-
-#ifdef DMALLOC
-#  include <dmalloc.h>
-#endif
-
-#include <mailutils/iterator.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct _mu_iterator
-{
-  struct _mu_iterator *next_itr; /* Next iterator in the chain */
-  void *owner;                /* Object whose contents is being iterated */
-  int is_advanced;            /* Is the iterator already advanced */
-
-  int (*dup) (void **ptr, void *owner);
-  int (*destroy) (mu_iterator_t itr, void *owner);
-  int (*first) (void *owner);
-  int (*next) (void *owner);
-  int (*getitem) (void *owner, void **pret, const void **pkey);
-  int (*curitem_p) (void *owner, void *item);
-  int (*finished_p) (void *owner);
-  int (*itrctl) (void *owner, enum mu_itrctl_req req, void *arg);
-};
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _ITERATOR0_H */
diff --git a/libproto/include/list0.h b/libproto/include/list0.h
deleted file mode 100644
index 3ac00fb..0000000
--- a/libproto/include/list0.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 1999, 2000, 2005, 2007, 2010 Free Software Foundation,
-   Inc.
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General
-   Public License along with this library; if not, write to the
-   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301 USA */
-
-#ifndef _LIST0_H
-#define _LIST0_H
-
-#ifdef DMALLOC
-#  include <dmalloc.h>
-#endif
-
-#include <sys/types.h>
-
-#include <mailutils/list.h>
-#include <mailutils/monitor.h>
-#include <mailutils/iterator.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct list_data
-{
-  void *item;
-  struct list_data *next;
-  struct list_data *prev;
-};
-
-struct _mu_list
-{
-  struct list_data head;
-  size_t count;
-  mu_monitor_t monitor;
-  mu_list_comparator_t comp;
-  void (*destroy_item) (void *item);
-  struct _mu_iterator *itr;
-};
-
-extern void _mu_list_clear (mu_list_t list);
-extern void _mu_list_insert_sublist (mu_list_t list,
-                                    struct list_data *current,
-                                    struct list_data *head,
-                                    struct list_data *tail,
-                                    size_t count,
-                                    int insert_before);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _LIST0_H */
diff --git a/libproto/include/mailbox0.h b/libproto/include/mailbox0.h
deleted file mode 100644
index a052e43..0000000
--- a/libproto/include/mailbox0.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 1999, 2000, 2001, 2005, 2007, 2010 Free Software
-   Foundation, Inc.
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General
-   Public License along with this library; if not, write to the
-   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301 USA */
-
-#ifndef _MAILBOX0_H
-#define _MAILBOX0_H
-
-#ifdef DMALLOC
-#  include <dmalloc.h>
-#endif
-
-#include <sys/types.h>
-#include <stdio.h>
-
-#include <mailutils/monitor.h>
-#include <mailutils/mailbox.h>
-#include <mailutils/iterator.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct _mu_mailbox
-{
-  /* Data */
-  mu_observable_t observable;
-  mu_debug_t debug;
-  mu_property_t property;
-  mu_locker_t locker;
-  mu_stream_t stream;
-  mu_url_t url;
-  int flags;
-  mu_folder_t folder;
-  mu_monitor_t monitor;
-  mu_iterator_t iterator;
-  
-  /* Back pointer to the specific mailbox */
-  void *data;
-
-  /* Public methods */
-
-  void (*_destroy)         (mu_mailbox_t);
-
-  int  (*_open)            (mu_mailbox_t, int);
-  int  (*_close)           (mu_mailbox_t);
-  
-  /* messages */
-  int  (*_get_message)     (mu_mailbox_t, size_t, mu_message_t *);
-  int  (*_append_message)  (mu_mailbox_t, mu_message_t);
-  int  (*_messages_count)  (mu_mailbox_t, size_t *);
-  int  (*_messages_recent) (mu_mailbox_t, size_t *);
-  int  (*_message_unseen)  (mu_mailbox_t, size_t *);
-  int  (*_expunge)         (mu_mailbox_t);
-  int  (*_sync)            (mu_mailbox_t);
-  int  (*_uidvalidity)     (mu_mailbox_t, unsigned long *);
-  int  (*_uidnext)         (mu_mailbox_t, size_t *);
-  int  (*_get_property)    (mu_mailbox_t, mu_property_t *);
-
-  int  (*_scan)            (mu_mailbox_t, size_t, size_t *);
-  int  (*_is_updated)      (mu_mailbox_t);
-
-  int  (*_get_size)        (mu_mailbox_t, mu_off_t *);
-
-  int  (*_quick_get_message) (mu_mailbox_t, mu_message_qid_t, mu_message_t *);
-  int  (*_get_uidls) (mu_mailbox_t, mu_list_t);
-};
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _MAILBOX0_H */
diff --git a/libproto/include/mailer0.h b/libproto/include/mailer0.h
deleted file mode 100644
index 949bb15..0000000
--- a/libproto/include/mailer0.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 1999, 2000, 2001, 2005, 2007, 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 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General
-   Public License along with this library; if not, write to the
-   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301 USA */
-
-#ifndef _MAILER0_H
-#define _MAILER0_H
-
-#ifdef DMALLOC
-#  include <dmalloc.h>
-#endif
-
-#include <sys/types.h>
-#include <mailutils/mailer.h>
-#include <mailutils/monitor.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Default mailer URL. */
-
-#define MAILER_URL_DEFAULT "sendmail:"
-
-#define MAILER_LINE_BUF_SIZE   1000
-
-struct _mu_mailer
-{
-  mu_stream_t stream;
-  mu_observable_t observable;
-  mu_debug_t debug;
-  mu_url_t url;
-  int flags;
-  mu_monitor_t monitor;
-  mu_property_t property;
-
-  /* Pointer to the specific mailer data.  */
-  void *data;
-
-  /* Public methods.  */
-  void (*_destroy)     (mu_mailer_t);
-  int (*_open)         (mu_mailer_t, int flags);
-  int (*_close)        (mu_mailer_t);
-  int (*_send_message) (mu_mailer_t, mu_message_t, mu_address_t, mu_address_t);
-};
-
-int _mu_mailer_mailbox_init (mu_mailbox_t mailbox);
-int _mu_mailer_folder_init (mu_folder_t folder MU_ARG_UNUSED);
-  
-#define MAILER_NOTIFY(mailer, type) \
-  if (mailer->observer) observer_notify (mailer->observer, type)
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* MAILER0_H */
diff --git a/libproto/include/message0.h b/libproto/include/message0.h
deleted file mode 100644
index cdaccc2..0000000
--- a/libproto/include/message0.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 1999, 2000, 2001, 2005, 2007, 2010 Free Software
-   Foundation, Inc.
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General
-   Public License along with this library; if not, write to the
-   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301 USA */
-
-#ifndef _MESSAGE0_H
-#define _MESSAGE0_H
-
-#ifdef DMALLOC
-#  include <dmalloc.h>
-#endif
-
-#include <mailutils/message.h>
-#include <mailutils/mime.h>
-#include <mailutils/monitor.h>
-
-#include <sys/types.h>
-#include <stdio.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct _mu_message
-{
-  /* Who is the owner.  */
-  void *owner;
-
-  mu_envelope_t envelope;
-  mu_header_t header;
-  mu_body_t body;
-
-  int flags;
-  mu_stream_t stream;
-  mu_attribute_t attribute;
-  mu_monitor_t monitor;
-  mu_mime_t mime;
-  mu_observable_t observable;
-  mu_mailbox_t mailbox;
-
-  /* Reference count.  */
-  int ref;
-
-  /* Holder for message_write. */
-  size_t hdr_buflen;
-  int hdr_done;
-
-  int (*_get_uidl)       (mu_message_t, char *, size_t, size_t *);
-  int (*_get_uid)        (mu_message_t, size_t *);
-  int (*_get_qid)        (mu_message_t,        mu_message_qid_t *);
-  int (*_get_num_parts)  (mu_message_t, size_t *);
-  int (*_get_part)       (mu_message_t, size_t, mu_message_t *);
-  int (*_is_multipart)   (mu_message_t, int *);
-  int (*_lines)          (mu_message_t, size_t *);
-  int (*_size)           (mu_message_t, size_t *);
-};
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _MESSAGE0_H */
diff --git a/libproto/include/mime0.h b/libproto/include/mime0.h
deleted file mode 100644
index c1bce64..0000000
--- a/libproto/include/mime0.h
+++ /dev/null
@@ -1,100 +0,0 @@
-/* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 1999, 2000, 2005, 2007, 2010 Free Software Foundation,
-   Inc.
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General
-   Public License along with this library; if not, write to the
-   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301 USA */
-
-#ifndef _MIME0_H
-#define _MIME0_H
-
-#ifdef DMALLOC
-#  include <dmalloc.h>
-#endif
-
-#include <sys/types.h>
-#include <mailutils/mime.h>
-
-#ifdef __cplusplus
-extern "C" { 
-#endif
-
-#define MIME_MAX_HDR_LEN           256
-#define MIME_DFLT_BUF_SIZE         2048
-
-/* Parser states */
-#define MIME_STATE_BEGIN_LINE      1
-#define MIME_STATE_SCAN_BOUNDARY   2
-#define MIME_STATE_HEADERS         3
-
-#define MIME_FLAG_MASK             0x0000ffff
-
-/* private */
-#define MIME_PARSER_ACTIVE         0x80000000
-#define MIME_PARSER_HAVE_CR        0x40000000
-#define MIME_NEW_MESSAGE           0x20000000
-#define MIME_ADDED_CT              0x10000000
-#define MIME_ADDED_MULTIPART_CT    0x08000000
-#define MIME_INSERT_BOUNDARY       0x04000000
-#define MIME_ADDING_BOUNDARY       0x02000000
-
-struct _mu_mime
-{
-  mu_message_t       msg;
-  mu_header_t        hdrs;
-  mu_stream_t        stream;
-  int             flags;
-  char           *content_type;
-
-  size_t          tparts;
-  size_t          nmtp_parts;
-  struct _mime_part **mtp_parts;      /* list of parts in the msg */
-  char           *boundary;
-  size_t          cur_offset;
-  size_t          cur_part;
-  size_t          part_offset;
-  size_t          boundary_len;
-  size_t          preamble;
-  size_t          postamble;
-  /* parser state */
-  char           *cur_line;
-  ssize_t         line_ndx;
-  size_t          line_size;
-  char           *cur_buf;
-  size_t          buf_size;
-  char           *header_buf;
-  size_t          header_buf_size;
-  size_t          header_length;
-  size_t          body_offset;
-  size_t          body_length;
-  size_t          body_lines;
-  int             parser_state;
-};
-
-struct _mime_part
-{
-  mu_mime_t          mime;
-  mu_message_t       msg;
-  int             body_created;
-  int             offset;
-  size_t          len;
-  size_t          lines;
-};
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif                          /* MIME0_H */
diff --git a/libproto/include/monitor0.h b/libproto/include/monitor0.h
deleted file mode 100644
index 3541e15..0000000
--- a/libproto/include/monitor0.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 1999, 2000, 2007, 2010 Free Software Foundation, Inc.
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General
-   Public License along with this library; if not, write to the
-   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301 USA */
-
-#ifndef _MONITOR0_H
-#define _MONITOR0_H
-
-#ifdef DMALLOC
-#  include <dmalloc.h>
-#endif
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <sys/types.h>
-#include <mailutils/monitor.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-/* FIXME: any protos? */
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _MONITOR0_H */
diff --git a/libproto/include/observer0.h b/libproto/include/observer0.h
deleted file mode 100644
index 164ac26..0000000
--- a/libproto/include/observer0.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 1999, 2000, 2005, 2007, 2010 Free Software Foundation,
-   Inc.
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General
-   Public License along with this library; if not, write to the
-   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301 USA */
-
-#ifndef _OBSERVER0_H
-#define _OBSERVER0_H
-
-#ifdef DMALLOC
-#  include <dmalloc.h>
-#endif
-
-#include <mailutils/observer.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct _mu_observer
-{
-  int flags;
-  void *owner;
-  int (*_action)  (mu_observer_t, size_t, void *, void *);
-  void *_action_data;
-  int (*_destroy) (mu_observer_t, void *data);
-};
-
-struct _mu_observable
-{
-  void *owner;
-  mu_list_t list;
-};
-
-struct _event
-{
-  size_t type;
-  mu_observer_t observer;
-};
-
-typedef struct _event *event_t;
-
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _OBSERVER0_H */
diff --git a/libproto/include/property0.h b/libproto/include/property0.h
deleted file mode 100644
index 25d1d2f..0000000
--- a/libproto/include/property0.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 1999, 2000, 2001, 2007, 2008, 2010 Free Software
-   Foundation, Inc.
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General
-   Public License along with this library; if not, write to the
-   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301 USA */
-
-#ifndef _PROPERTY0_H
-#define _PROPERTY0_H
-
-#ifdef DMALLOC
-#  include <dmalloc.h>
-#endif
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <mailutils/property.h>
-#include <mailutils/monitor.h>
-#include <mailutils/assoc.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct property_item
-{
-  char *value;
-};
-
-struct _mu_property
-{
-  mu_assoc_t assoc;
-  void *owner;
-  mu_monitor_t lock;
-};
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _PROPERTY0_H */
diff --git a/libproto/include/registrar0.h b/libproto/include/registrar0.h
deleted file mode 100644
index 13e15f6..0000000
--- a/libproto/include/registrar0.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 1999, 2000, 2004, 2005, 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 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General
-   Public License along with this library; if not, write to the
-   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301 USA */
-
-#ifndef _REGISTRAR0_H
-#define _REGISTRAR0_H
-
-#include <mailutils/registrar.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* The pop and imap defines are all wrong now, since they seem intertwined
-   with the old url parsing code. Also, "pop://" is not the POP scheme,
-   at least not as a scheme is described in the RFCs.
-
-   Perhaps they can be changed?
-*/
-#define MU_POP_PORT 110
-#define MU_POP_SCHEME "pop"
-#define MU_POP_SCHEME_LEN (sizeof (MU_POP_SCHEME) - 1)
-extern int _url_pop_init          (mu_url_t);
-extern int _mailbox_pop_init      (mu_mailbox_t);
-extern int _folder_pop_init       (mu_folder_t);
-
-#define MU_POPS_PORT 995
-#define MU_POPS_SCHEME "pops"
-#define MU_POPS_SCHEME_LEN (sizeof (MU_POPS_SCHEME) - 1)
-extern int _url_pops_init         (mu_url_t);
-extern int _mailbox_pops_init     (mu_mailbox_t);
-
-#define MU_IMAP_PORT 143
-#define MU_IMAP_SCHEME "imap"
-#define MU_IMAP_SCHEME_LEN (sizeof (MU_IMAP_SCHEME) - 1)
-extern int _url_imap_init         (mu_url_t);
-extern int _mailbox_imap_init     (mu_mailbox_t);
-extern int _folder_imap_init      (mu_folder_t);
-
-#define MU_IMAPS_PORT 993
-#define MU_IMAPS_SCHEME "imaps"
-#define MU_IMAPS_SCHEME_LEN (sizeof (MU_IMAPS_SCHEME) - 1)
-extern int _url_imaps_init        (mu_url_t);
-extern int _mailbox_imaps_init    (mu_mailbox_t);
-
-#define MU_MBOX_SCHEME "mbox"
-#define MU_MBOX_SCHEME_LEN (sizeof (MU_MBOX_SCHEME) - 1)
-extern int _mailbox_mbox_init     (mu_mailbox_t);
-extern int _folder_mbox_init      (mu_folder_t);
-
-#define MU_FILE_SCHEME "file"
-#define MU_FILE_SCHEME_LEN (sizeof (MU_FILE_SCHEME) - 1)
-
-#define MU_PATH_SCHEME "/"
-#define MU_PATH_SCHEME_LEN (sizeof (MU_PATH_SCHEME) - 1)
-extern int _mailbox_path_init     (mu_mailbox_t);
-extern int _folder_path_init      (mu_folder_t);
-
-#define MU_SMTP_SCHEME "smtp"
-#define MU_SMTP_SCHEME_LEN (sizeof (MU_SMTP_SCHEME) - 1)
-#define MU_SMTP_PORT 25
-
-#define MU_SENDMAIL_SCHEME "sendmail"
-#define MU_SENDMAIL_SCHEME_LEN (sizeof (MU_SENDMAIL_SCHEME) - 1)
-extern int _mu_mailer_sendmail_init (mu_mailer_t mailer);
-  
-#define MU_PROG_SCHEME "prog"
-#define MU_PROG_SCHEME_LEN (sizeof (MU_PROG_SCHEME) - 1)
-  extern int _mu_mailer_prog_init  (mu_mailer_t);  
-  
-#define MU_MH_SCHEME "mh"
-#define MU_MH_SCHEME_LEN (sizeof (MU_MH_SCHEME) - 1)
-extern int _mailbox_mh_init (mu_mailbox_t mailbox);
-
-#define MU_MAILDIR_SCHEME "maildir"
-#define MU_MAILDIR_SCHEME_LEN (sizeof (MU_MAILDIR_SCHEME) - 1)
-extern int _mailbox_maildir_init (mu_mailbox_t mailbox);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _REGISTRAR0_H */
diff --git a/libproto/include/stream0.h b/libproto/include/stream0.h
deleted file mode 100644
index ff8021b..0000000
--- a/libproto/include/stream0.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 1999, 2000, 2001, 2005, 2007, 2010 Free Software
-   Foundation, Inc.
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General
-   Public License along with this library; if not, write to the
-   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301 USA */
-
-#ifndef _STREAM0_H
-#define _STREAM0_H
-
-#include <mailutils/stream.h>
-#ifdef DMALLOC
-#include <dmalloc.h>
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Read buffer */
-struct rbuffer
-{
-  char *base;
-  char *ptr;
-  size_t count;
-  size_t bufsiz;
-  mu_off_t offset;
-};
-
-struct _mu_stream
-{
-  void *owner;
-  mu_property_t property;
-
-  int flags;
-  int state;
-
-  /* Read space */
-  struct rbuffer rbuffer;
-  
-  /* Stream pointer for sequential offset.  */
-  mu_off_t offset;
-  
-  void (*_destroy) (mu_stream_t);
-  int (*_open)     (mu_stream_t);
-  int (*_close)    (mu_stream_t);
-  int (*_get_transport2) (mu_stream_t, mu_transport_t *, mu_transport_t *);
-  int (*_read)     (mu_stream_t, char *, size_t, mu_off_t, size_t *);
-  int (*_readline) (mu_stream_t, char *, size_t, mu_off_t, size_t *);
-  int (*_write)    (mu_stream_t, const char *, size_t, mu_off_t, size_t *);
-  int (*_truncate) (mu_stream_t, mu_off_t);
-  int (*_size)     (mu_stream_t, mu_off_t *);
-  int (*_flush)    (mu_stream_t);
-  int (*_setbufsiz)(mu_stream_t, size_t);
-  int (*_strerror) (mu_stream_t, const char **);
-  int (*_wait)     (mu_stream_t, int *pflags, struct timeval *tvp);
-  int (*_shutdown) (mu_stream_t, int how);
-};
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _STREAM0_H */
diff --git a/libproto/include/url0.h b/libproto/include/url0.h
deleted file mode 100644
index 1cedd31..0000000
--- a/libproto/include/url0.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 1999, 2000, 2005, 2007, 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 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General
-   Public License along with this library; if not, write to the
-   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301 USA */
-
-#ifndef _URL0_H
-#define _URL0_H        1
-
-#ifdef DMALLOC
-#  include <dmalloc.h>
-#endif
-
-#include <mailutils/url.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct _mu_url
-{
-  /* Data */
-  char  *name;
-  char  *scheme;
-  char  *user;
-  mu_secret_t secret;
-  char  *auth;
-  char  *host;
-  long  port;
-  char  *path;
-  char  **fvpairs;
-  int   fvcount;
-
-  char  **qargv;
-  int   qargc;
-  
-  void  *data;
-
-  void  (*_destroy)    (mu_url_t url);
-
-  /* Methods */
-  int   (*_get_scheme) (const mu_url_t, char *, size_t, size_t *);
-  int   (*_get_user)   (const mu_url_t, char *, size_t, size_t *);
-  int   (*_get_secret) (const mu_url_t, mu_secret_t *);
-  int   (*_get_auth)   (const mu_url_t, char *, size_t, size_t *);
-  int   (*_get_host)   (const mu_url_t, char *, size_t, size_t *);
-  int   (*_get_port)   (const mu_url_t, long *);
-  int   (*_get_path)   (const mu_url_t, char *, size_t, size_t *);
-  int   (*_get_query)  (const mu_url_t, char *, size_t, size_t *);
-  int   (*_uplevel)    (const mu_url_t, mu_url_t *);
-};
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* URL_H */
diff --git a/libproto/maildir/Makefile.am b/libproto/maildir/Makefile.am
index 4e0da11..939cd03 100644
--- a/libproto/maildir/Makefile.am
+++ b/libproto/maildir/Makefile.am
@@ -18,7 +18,7 @@
 ##   Foundation, Inc.  51 Franklin Street, Fifth Floor, Boston, MA
 ##   02110-1301 USA
 
-INCLUDES = @MU_LIB_COMMON_INCLUDES@ -I${top_srcdir}/libproto/include 
+INCLUDES = @MU_LIB_COMMON_INCLUDES@ 
 
 lib_LTLIBRARIES = libmu_maildir.la
 libmu_maildir_la_LDFLAGS=-version-info @VI_CURRENT@:@VI_REVISION@:@VI_AGE@
diff --git a/libproto/maildir/folder.c b/libproto/maildir/folder.c
index 38a9d72..f6431a8 100644
--- a/libproto/maildir/folder.c
+++ b/libproto/maildir/folder.c
@@ -28,13 +28,13 @@
 #include <string.h>
 #include <errno.h>
 
-#include <folder0.h>
-#include <registrar0.h>
+#include <mailutils/sys/folder.h>
+#include <mailutils/sys/registrar.h>
 
 #include <maildir.h>
 #include <mailutils/mutil.h>
 #include <mailutils/url.h>
-#include <amd.h>
+#include <mailutils/sys/amd.h>
 
 static int
 _maildir_folder_init (mu_folder_t folder MU_ARG_UNUSED)
@@ -115,6 +115,6 @@ mu_record_t mu_maildir_record = &_maildir_record;
 
 #else
 #include <stdio.h>
-#include <registrar0.h>
+#include <mailutils/sys/registrar.h>
 mu_record_t mu_maildir_record = NULL;
 #endif
diff --git a/libproto/maildir/mbox.c b/libproto/maildir/mbox.c
index c9d7470..d2d7b9e 100644
--- a/libproto/maildir/mbox.c
+++ b/libproto/maildir/mbox.c
@@ -66,9 +66,9 @@
 #include <mailutils/observer.h>
 #include <mailutils/errno.h>
 #include <mailutils/locker.h>
-#include <mailbox0.h>
-#include <registrar0.h>
-#include <amd.h>
+#include <mailutils/sys/mailbox.h>
+#include <mailutils/sys/registrar.h>
+#include <mailutils/sys/amd.h>
 #include <maildir.h>
 
 #ifndef PATH_MAX 
diff --git a/libproto/mailer/Makefile.am b/libproto/mailer/Makefile.am
index bb272e0..bd952e6 100644
--- a/libproto/mailer/Makefile.am
+++ b/libproto/mailer/Makefile.am
@@ -17,7 +17,7 @@
 ##   Foundation, Inc.  51 Franklin Street, Fifth Floor, Boston, MA
 ##   02110-1301 USA
 
-INCLUDES = @MU_LIB_COMMON_INCLUDES@ -I${top_srcdir}/libproto/include 
+INCLUDES = @MU_LIB_COMMON_INCLUDES@
 
 lib_LTLIBRARIES = libmu_mailer.la
 libmu_mailer_la_LDFLAGS=-version-info @VI_CURRENT@:@VI_REVISION@:@VI_AGE@
diff --git a/libproto/mailer/mbox.c b/libproto/mailer/mbox.c
index 367492c..ab6f905 100644
--- a/libproto/mailer/mbox.c
+++ b/libproto/mailer/mbox.c
@@ -30,8 +30,8 @@
 #include <mailutils/mailer.h>
 #include <mailutils/url.h>
 #include <mailutils/mutil.h>
-#include <mailbox0.h>
-#include <mailer0.h>
+#include <mailutils/sys/mailbox.h>
+#include <mailutils/sys/mailer.h>
 
 struct remote_mbox_data
 {
diff --git a/libproto/mailer/prog.c b/libproto/mailer/prog.c
index 83b371a..216869c 100644
--- a/libproto/mailer/prog.c
+++ b/libproto/mailer/prog.c
@@ -34,9 +34,9 @@
 #include <mailutils/progmailer.h>
 #include <mailutils/vartab.h>
 
-#include <url0.h>
-#include <mailer0.h>
-#include <registrar0.h>
+#include <mailutils/sys/url.h>
+#include <mailutils/sys/mailer.h>
+#include <mailutils/sys/registrar.h>
 
 static int _url_prog_init     (mu_url_t);
 
@@ -379,6 +379,6 @@ prog_send_message (mu_mailer_t mailer, mu_message_t msg, 
mu_address_t from,
 
 #else
 #include <stdio.h>
-#include <registrar0.h>
+#include <mailutils/sys/registrar.h>
 mu_record_t mu_prog_record = NULL;
 #endif
diff --git a/libproto/mailer/remote.c b/libproto/mailer/remote.c
index a99e4ab..1781687 100644
--- a/libproto/mailer/remote.c
+++ b/libproto/mailer/remote.c
@@ -34,9 +34,9 @@
 #include <mailutils/error.h>
 #include <mailutils/diag.h>
 
-#include <url0.h>
-#include <mailer0.h>
-#include <registrar0.h>
+#include <mailutils/sys/url.h>
+#include <mailutils/sys/mailer.h>
+#include <mailutils/sys/registrar.h>
 
 #ifdef ENABLE_SMTP
 
diff --git a/libproto/mailer/sendmail.c b/libproto/mailer/sendmail.c
index 651603e..bc944d2 100644
--- a/libproto/mailer/sendmail.c
+++ b/libproto/mailer/sendmail.c
@@ -40,9 +40,9 @@
 #include <mailutils/errno.h>
 #include <mailutils/progmailer.h>
 
-#include <url0.h>
-#include <mailer0.h>
-#include <registrar0.h>
+#include <mailutils/sys/url.h>
+#include <mailutils/sys/mailer.h>
+#include <mailutils/sys/registrar.h>
 
 static void sendmail_destroy (mu_mailer_t);
 static int sendmail_open (mu_mailer_t, int);
@@ -293,6 +293,6 @@ mu_record_t mu_sendmail_record = &_sendmail_record;
 
 #else
 #include <stdio.h>
-#include <registrar0.h>
+#include <mailutils/sys/registrar.h>
 mu_record_t mu_sendmail_record = NULL;
 #endif
diff --git a/libproto/mailer/smtp.c b/libproto/mailer/smtp.c
index f5a6f1c..31b725f 100644
--- a/libproto/mailer/smtp.c
+++ b/libproto/mailer/smtp.c
@@ -20,7 +20,7 @@
 /** @file smtp.c
 @brief an SMTP mailer
 */
-
+/* FIXME: Bufferization stuff is spurious. Remove it */
 #ifdef HAVE_CONFIG_H
 # include <config.h>
 #endif
@@ -55,9 +55,9 @@
 #include <mailutils/cctype.h>
 #include <mailutils/cstr.h>
 
-#include <mailer0.h>
-#include <url0.h>
-#include <registrar0.h>
+#include <mailutils/sys/mailer.h>
+#include <mailutils/sys/url.h>
+#include <mailutils/sys/registrar.h>
 
 static int      _mailer_smtp_init (mu_mailer_t);
 
@@ -112,7 +112,6 @@ struct _smtp
 
   char           *ptr;
   char           *nl;
-  off_t           s_offset;
 
   enum smtp_state
   {
@@ -140,8 +139,6 @@ struct _smtp
   int             bccing;
   mu_message_t    msg;         /* Destroy this if not same argmsg. */
 
-  off_t           offset;
-
   /* The mu_mailer_send_message() args. */
   mu_message_t    argmsg;
   mu_address_t    argfrom;
@@ -202,7 +199,6 @@ CLEAR_STATE (smtp_t smtp)
 {
   smtp->ptr = smtp->buffer;
   smtp->nl = NULL;
-  smtp->s_offset = 0;
 
   smtp->state = SMTP_NO_STATE;
 
@@ -229,8 +225,6 @@ CLEAR_STATE (smtp_t smtp)
 
   smtp->msg = NULL;
 
-  smtp->offset = 0;
-
   smtp->argmsg = NULL;
   smtp->argfrom = NULL;
   smtp->argto = NULL;
@@ -426,7 +420,7 @@ smtp_open (mu_mailer_t mailer, int flags)
            mu_tcp_stream_create (&mailer->stream, smtp->mailhost, port,
                                  mailer->flags);
          CHECK_ERROR (smtp, status);
-         mu_stream_setbufsiz (mailer->stream, BUFSIZ);
+         mu_stream_set_buffer (mailer->stream, mu_buffer_line, BUFSIZ);
        }
       CHECK_ERROR (smtp, status);
       smtp->state = SMTP_OPEN;
@@ -560,68 +554,40 @@ smtp_close (mu_mailer_t mailer)
   return mu_stream_close (mailer->stream);
 }
 
-#ifdef WITH_TLS
 /*
   Client side STARTTLS support.
  */
 
 static int
-smtp_reader (void *iodata)
-{
-  int             status = 0;
-  smtp_t          iop = iodata;
-
-  status = smtp_read_ack (iop);
-  CHECK_EAGAIN (iop, status);
-  return status;
-}
-
-static int
-smtp_writer (void *iodata, char *buf)
-{
-  smtp_t          iop = iodata;
-  int             status;
-
-  if (mu_c_strncasecmp (buf, "EHLO", 4) == 0)
-    status = smtp_writeline (iop, "%s %s\r\n", buf, iop->localhost);
-  else
-    status = smtp_writeline (iop, "%s\r\n", buf);
-  CHECK_ERROR (iop, status);
-  status = smtp_write (iop);
-  CHECK_EAGAIN (iop, status);
-  return status;
-}
-
-static void
-smtp_stream_ctl (void *iodata, mu_stream_t * pold, mu_stream_t new)
-{
-  smtp_t          iop = iodata;
-
-  if (pold)
-    *pold = iop->mailer->stream;
-  if (new)
-    iop->mailer->stream = new;
-}
-#endif
-
-static int
 smtp_starttls (smtp_t smtp)
 {
 #ifdef WITH_TLS
   int             status;
   mu_mailer_t     mailer = smtp->mailer;
-  char           *keywords[] = { "STARTTLS", NULL };
-
+  mu_stream_t     newstr;
+  
   if (!mu_tls_enable || !(smtp->capa & CAPA_STARTTLS))
     return -1;
 
   smtp->capa = 0;
   smtp->auth_mechs = 0;
-  status = mu_tls_begin (smtp, smtp_reader, smtp_writer,
-                        smtp_stream_ctl, keywords);
 
+  status = smtp_writeline (smtp, "STARTTLS\r\n");
+  CHECK_ERROR (smtp, status);
+  status = smtp_write (smtp);
+  CHECK_EAGAIN (smtp, status);
+  status = smtp_read_ack (smtp);
+  CHECK_ERROR (smtp, status);
+  mu_stream_flush (mailer->stream);
+  status = mu_tls_client_stream_create (&newstr, mailer->stream,
+                                       mailer->stream, 0);
+  CHECK_ERROR (smtp, status);
+  status = mu_stream_open (newstr);
   MU_DEBUG1 (mailer->debug, MU_DEBUG_PROT, "TLS negotiation %s\n",
             status == 0 ? "succeeded" : "failed");
+  CHECK_ERROR (smtp, status);
+
+  mailer->stream = newstr;
 
   return status;
 #else
@@ -862,6 +828,84 @@ message_has_bcc (mu_message_t msg)
   return status == MU_ERR_NOENT ? 0 : 1;
 }
 
+static int
+send_header (smtp_t smtp, mu_stream_t stream)
+{
+  int status;
+  int found_nl;
+  char data[256] = "";
+  size_t          n = 0;
+
+  while ((status = mu_stream_readline (stream, data, sizeof (data),
+                                      &n)) == 0 && n > 0)
+    {
+      int             nl;
+
+      found_nl = (n == 1 && data[0] == '\n');
+      if ((nl = (data[n - 1] == '\n')))
+       data[n - 1] = '\0';
+      if (data[0] == '.')
+       {
+         status = smtp_writeline (smtp, ".%s", data);
+         CHECK_ERROR (smtp, status);
+       }
+      else if (mu_c_strncasecmp (data, MU_HEADER_FCC,
+                                sizeof (MU_HEADER_FCC) - 1))
+       {
+         status = smtp_writeline (smtp, "%s", data);
+         CHECK_ERROR (smtp, status);
+         status = smtp_write (smtp);
+         CHECK_EAGAIN (smtp, status);
+       }
+      else
+       nl = 0;
+
+      if (nl)
+       {
+         status = smtp_writeline (smtp, "\r\n");
+         CHECK_ERROR (smtp, status);
+         status = smtp_write (smtp);
+         CHECK_EAGAIN (smtp, status);
+       }
+    }
+
+  if (!found_nl)
+    {
+      status = smtp_writeline (smtp, "\r\n");
+      CHECK_ERROR (smtp, status);
+      status = smtp_write (smtp);
+      CHECK_EAGAIN (smtp, status);
+    }
+  return 0;
+}
+
+static int
+send_body (smtp_t smtp, mu_stream_t stream)
+{
+  int status;
+  char data[256] = "";
+  size_t          n = 0;
+
+  while ((status = mu_stream_readline (stream, data, sizeof (data) - 1,
+                                      &n)) == 0 && n > 0)
+    {
+      if (data[n - 1] == '\n')
+       data[n - 1] = '\0';
+      if (data[0] == '.')
+       status = smtp_writeline (smtp, ".%s\r\n", data);
+      else
+       status = smtp_writeline (smtp, "%s\r\n", data);
+      CHECK_ERROR (smtp, status);
+      status = smtp_write (smtp);
+      CHECK_EAGAIN (smtp, status);
+    }
+
+  status = smtp_writeline (smtp, ".\r\n");
+  CHECK_ERROR (smtp, status);
+  smtp->state = SMTP_SEND_DOT;
+  return 0;
+}
+  
 /*
 
 The smtp mailer doesn't deal with mail like:
@@ -1051,7 +1095,6 @@ smtp_send_message (mu_mailer_t mailer, mu_message_t 
argmsg,
          CLEAR_STATE (smtp);
          return EACCES;
        }
-      smtp->offset = 0;
       smtp->state = SMTP_SEND;
 
       if ((smtp->mailer->flags & MAILER_FLAG_DEBUG_DATA) == 0)
@@ -1060,11 +1103,8 @@ smtp_send_message (mu_mailer_t mailer, mu_message_t 
argmsg,
     case SMTP_SEND:
       {
        mu_stream_t     stream;
-       size_t          n = 0;
-       char            data[256] = "";
        mu_header_t     hdr;
        mu_body_t       body;
-       int             found_nl;
 
        /* We may be here after an EAGAIN so check if we have something
           in the buffer and flush it.  */
@@ -1072,73 +1112,19 @@ smtp_send_message (mu_mailer_t mailer, mu_message_t 
argmsg,
        CHECK_EAGAIN (smtp, status);
 
        mu_message_get_header (smtp->msg, &hdr);
-       mu_header_get_stream (hdr, &stream);
-       while ((status = mu_stream_readline (stream, data, sizeof (data),
-                                            smtp->offset, &n)) == 0 && n > 0)
-         {
-           int             nl;
-
-           found_nl = (n == 1 && data[0] == '\n');
-           if ((nl = (data[n - 1] == '\n')))
-             data[n - 1] = '\0';
-           if (data[0] == '.')
-             {
-               status = smtp_writeline (smtp, ".%s", data);
-               CHECK_ERROR (smtp, status);
-             }
-           else if (mu_c_strncasecmp (data, MU_HEADER_FCC,
-                                      sizeof (MU_HEADER_FCC) - 1))
-             {
-               status = smtp_writeline (smtp, "%s", data);
-               CHECK_ERROR (smtp, status);
-               status = smtp_write (smtp);
-               CHECK_EAGAIN (smtp, status);
-             }
-           else
-             nl = 0;
-
-           if (nl)
-             {
-               status = smtp_writeline (smtp, "\r\n");
-               CHECK_ERROR (smtp, status);
-               status = smtp_write (smtp);
-               CHECK_EAGAIN (smtp, status);
-             }
-           smtp->offset += n;
-         }
-
-       if (!found_nl)
-         {
-           status = smtp_writeline (smtp, "\r\n");
-           CHECK_ERROR (smtp, status);
-           status = smtp_write (smtp);
-           CHECK_EAGAIN (smtp, status);
-         }
-
+       mu_header_get_streamref (hdr, &stream);
+       mu_stream_seek (stream, 0, MU_SEEK_SET, NULL);
+       status = send_header (smtp, stream);
+       mu_stream_destroy (&stream);
+       if (status)
+         return status;
+       
        mu_message_get_body (smtp->msg, &body);
-       mu_body_get_stream (body, &stream);
-       smtp->offset = 0;
-       while ((status = mu_stream_readline (stream, data, sizeof (data) - 1,
-                                            smtp->offset, &n)) == 0 && n > 0)
-         {
-           if (data[n - 1] == '\n')
-             data[n - 1] = '\0';
-           if (data[0] == '.')
-             status = smtp_writeline (smtp, ".%s\r\n", data);
-           else
-             status = smtp_writeline (smtp, "%s\r\n", data);
-           CHECK_ERROR (smtp, status);
-           status = smtp_write (smtp);
-           CHECK_EAGAIN (smtp, status);
-           smtp->offset += n;
-         }
-
-       smtp->offset = 0;
-       status = smtp_writeline (smtp, ".\r\n");
-       CHECK_ERROR (smtp, status);
-       smtp->state = SMTP_SEND_DOT;
-      }
-
+       mu_body_get_streamref (body, &stream);
+       mu_stream_seek (stream, 0, MU_SEEK_SET, NULL);
+       status = send_body (smtp, stream);
+       mu_stream_destroy (&stream);
+      }          
     case SMTP_SEND_DOT:
       status = smtp_write (smtp);
       CHECK_EAGAIN (smtp, status);
@@ -1345,13 +1331,9 @@ smtp_write (smtp_t smtp)
   if (smtp->ptr > smtp->buffer)
     {
       len = smtp->ptr - smtp->buffer;
-      status = mu_stream_write (smtp->mailer->stream, smtp->buffer, len,
-                               0, &len);
+      status = mu_stream_write (smtp->mailer->stream, smtp->buffer, len, NULL);
       if (status == 0)
-       {
-         memmove (smtp->buffer, smtp->buffer + len, len);
-         smtp->ptr -= len;
-       }
+       memmove (smtp->buffer, smtp->buffer + len, len);
     }
   else
     {
@@ -1389,6 +1371,8 @@ smtp_parse_ehlo_ack (smtp_t smtp)
   int             status;
   int             multi;
 
+  smtp->ptr = smtp->buffer;
+
   do
     {
       multi = 0;
@@ -1463,7 +1447,7 @@ smtp_readline (smtp_t smtp)
   do
     {
       status = mu_stream_readline (smtp->mailer->stream, smtp->buffer + total,
-                                  smtp->buflen - total, smtp->s_offset, &n);
+                                  smtp->buflen - total, &n);
       if (status != 0)
        return status;
 
@@ -1472,7 +1456,6 @@ smtp_readline (smtp_t smtp)
        return EIO;
 
       total += n;
-      smtp->s_offset += n;
       smtp->nl = memchr (smtp->buffer, '\n', total);
       if (smtp->nl == NULL)    /* Do we have a full line.  */
        {
@@ -1504,7 +1487,7 @@ smtp_readline (smtp_t smtp)
 
 #else
 #include <stdio.h>
-#include <registrar0.h>
+#include <mailutils/sys/registrar.h>
 mu_record_t     mu_smtp_record = NULL;
 mu_record_t     mu_remote_smtp_record = NULL;
 #endif
diff --git a/libproto/mbox/Makefile.am b/libproto/mbox/Makefile.am
index 935659a..b65cf1e 100644
--- a/libproto/mbox/Makefile.am
+++ b/libproto/mbox/Makefile.am
@@ -18,7 +18,7 @@
 ##   Foundation, Inc.  51 Franklin Street, Fifth Floor, Boston, MA
 ##   02110-1301 USA
 
-INCLUDES = @MU_LIB_COMMON_INCLUDES@ -I${top_srcdir}/libproto/include 
+INCLUDES = @MU_LIB_COMMON_INCLUDES@ 
 
 lib_LTLIBRARIES = libmu_mbox.la
 libmu_mbox_la_LDFLAGS=-version-info @VI_CURRENT@:@VI_REVISION@:@VI_AGE@
diff --git a/libproto/mbox/folder.c b/libproto/mbox/folder.c
index 3557a88..0c44323 100644
--- a/libproto/mbox/folder.c
+++ b/libproto/mbox/folder.c
@@ -33,8 +33,8 @@
 #include <stdio.h>
 #include <stdlib.h>
 
-#include <folder0.h>
-#include <registrar0.h>
+#include <mailutils/sys/folder.h>
+#include <mailutils/sys/registrar.h>
 
 #include <mailutils/auth.h>
 #include <mailutils/url.h>
diff --git a/libproto/mbox/mbox.c b/libproto/mbox/mbox.c
index 826098d..7b14817 100644
--- a/libproto/mbox/mbox.c
+++ b/libproto/mbox/mbox.c
@@ -17,7 +17,9 @@
    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301 USA */
 
-/* First draft by Alain Magloire */
+/* First draft by Alain Magloire.
+ * Completely rewritten by Sergey Poznyakoff.
+ */
 
 #ifdef HAVE_CONFIG_H
 # include <config.h>
@@ -30,133 +32,8 @@
 #define ATTRIBUTE_IS_DELETED(flag)        (flag & MU_ATTRIBUTE_DELETED)
 #define ATTRIBUTE_IS_EQUAL(flag1, flag2)  (flag1 == flag2)
 
-static void mbox_destroy (mu_mailbox_t);
-
-/* Mailbox concrete implementation.  */
-static int mbox_open                  (mu_mailbox_t, int);
-static int mbox_close                 (mu_mailbox_t);
-static int mbox_get_message           (mu_mailbox_t, size_t, mu_message_t *);
-static int mbox_quick_get_message (mu_mailbox_t, mu_message_qid_t,
-                                  mu_message_t *);
-
-/* static int mbox_get_message_by_uid    (mu_mailbox_t, size_t, mu_message_t 
*); */
-static int mbox_append_message        (mu_mailbox_t, mu_message_t);
-static int mbox_messages_count        (mu_mailbox_t, size_t *);
-static int mbox_messages_recent       (mu_mailbox_t, size_t *);
-static int mbox_message_unseen        (mu_mailbox_t, size_t *);
-static int mbox_expunge0              (mu_mailbox_t, int);
-static int mbox_expunge               (mu_mailbox_t);
-static int mbox_sync                  (mu_mailbox_t);
-static int mbox_uidvalidity           (mu_mailbox_t, unsigned long *);
-static int mbox_uidnext               (mu_mailbox_t, size_t *);
-static int mbox_scan                  (mu_mailbox_t, size_t, size_t *);
-static int mbox_is_updated            (mu_mailbox_t);
-static int mbox_get_size              (mu_mailbox_t, mu_off_t *);
-
-/* private stuff */
-static int mbox_append_message0       (mu_mailbox_t, mu_message_t,
-                                      mu_off_t *, int, int);
-static int mbox_message_uid           (mu_message_t, size_t *);
-static int mbox_message_qid           (mu_message_t, mu_message_qid_t *);
-
-static int mbox_header_fill           (mu_header_t, char *, size_t,
-                                      mu_off_t, size_t *);
-static int mbox_get_body_transport    (mu_stream_t, mu_transport_t *,
-                                      mu_transport_t *);
-static int mbox_get_transport2        (mbox_message_t, mu_transport_t *,
-                                      mu_transport_t *);
-static int mbox_get_attr_flags        (mu_attribute_t, int *);
-static int mbox_set_attr_flags        (mu_attribute_t, int);
-static int mbox_unset_attr_flags      (mu_attribute_t, int);
-static int mbox_body_read             (mu_stream_t, char *, size_t,
-                                      mu_off_t, size_t *);
-static int mbox_body_readline         (mu_stream_t, char *, size_t,
-                                      mu_off_t, size_t *);
-static int mbox_readstream            (mbox_message_t, char *, size_t,
-                                      mu_off_t, size_t *, int, mu_off_t,
-                                      mu_off_t);
-static int mbox_stream_size           (mu_stream_t stream, mu_off_t *psize);
-
-static int mbox_body_size             (mu_body_t, size_t *);
-static int mbox_body_lines            (mu_body_t, size_t *);
-static int mbox_envelope_sender       (mu_envelope_t, char *, size_t,
-                                      size_t *);
-static int mbox_envelope_date         (mu_envelope_t, char *, size_t,
-                                      size_t *);
-static int mbox_tmpfile               (mu_mailbox_t, char **pbox);
-
-/* Allocate the mbox_data_t struct(concrete mailbox), but don't do any
-   parsing on the name or even test for existence.  However we do strip any
-   leading "mbox:" part of the name, this is suppose to be the
-   protocol/scheme name.  */
-int
-_mailbox_mbox_init (mu_mailbox_t mailbox)
-{
-  int status;
-  mbox_data_t mud;
-
-  if (mailbox == NULL)
-    return EINVAL;
-
-  /* Allocate specific mbox data.  */
-  mud = mailbox->data = calloc (1, sizeof (*mud));
-  if (mailbox->data == NULL)
-    return ENOMEM;
-
-  /* Back pointer.  */
-  mud->mailbox = mailbox;
-
-  /* Copy the name:
-     We do not do any further interpretation after the scheme "mbox:"
-     Because for example on distributed system like QnX4 a file name is
-     //390/etc/passwd.  So the best approach is to let the OS handle it
-     for example if we receive: "mbox:///var/mail/alain" the mailbox name
-     will be "///var/mail/alain", we let open() do the right thing.
-     So it will let things like this "mbox://390/var/mail/alain" where
-     the "//" _is_ part of the filename, pass correctely.  */
-  status = mu_url_aget_path (mailbox->url, &mud->name);
-  if (status)
-    {
-      free (mud);
-      mailbox->data = NULL;
-      return status;
-    }
-
-  mud->state = MBOX_NO_STATE;
-
-  /* Overloading the defaults.  */
-  mailbox->_destroy = mbox_destroy;
-
-  mailbox->_open = mbox_open;
-  mailbox->_close = mbox_close;
-
-  /* Overloading of the entire mailbox object methods.  */
-  mailbox->_get_message = mbox_get_message;
-  mailbox->_append_message = mbox_append_message;
-  mailbox->_messages_count = mbox_messages_count;
-  mailbox->_messages_recent = mbox_messages_recent;
-  mailbox->_message_unseen = mbox_message_unseen;
-  mailbox->_expunge = mbox_expunge;
-  mailbox->_sync = mbox_sync;
-  mailbox->_uidvalidity = mbox_uidvalidity;
-  mailbox->_uidnext = mbox_uidnext;
-  mailbox->_quick_get_message = mbox_quick_get_message;
-
-  mailbox->_scan = mbox_scan;
-  mailbox->_is_updated = mbox_is_updated;
-
-  mailbox->_get_size = mbox_get_size;
-
-  /* Set our properties.  */
-  {
-    mu_property_t property = NULL;
-    mu_mailbox_get_property (mailbox, &property);
-    mu_property_set_value (property, "TYPE", "MBOX", 1);
-  }
-
-  MU_DEBUG1 (mailbox->debug, MU_DEBUG_TRACE1, "mbox_init (%s)\n", mud->name);
-  return 0; /* okdoke */
-}
+static int mbox_is_updated (mu_mailbox_t mailbox);
+static int mbox_expunge0 (mu_mailbox_t mailbox, int remove_deleted);
 
 /* Free all ressources associated with Unix concrete mailbox.  */
 static void
@@ -167,14 +44,14 @@ mbox_destroy (mu_mailbox_t mailbox)
       size_t i;
       mbox_data_t mud = mailbox->data;
       MU_DEBUG1 (mailbox->debug, MU_DEBUG_TRACE1,
-                     "mbox_destroy (%s)\n", mud->name);
+                "mbox_destroy (%s)\n", mud->name);
       mu_monitor_wrlock (mailbox->monitor);
       for (i = 0; i < mud->umessages_count; i++)
        {
          mbox_message_t mum = mud->umessages[i];
          if (mum)
            {
-             mu_message_destroy (&(mum->message), mum);
+             mu_message_destroy (&mum->message, mum);
              free (mum);
            }
        }
@@ -206,35 +83,31 @@ mbox_open (mu_mailbox_t mailbox, int flags)
     {
       /* We do not try to mmap for CREAT or APPEND, it is not supported.  */
       status = (flags & MU_STREAM_CREAT)
-       || (mailbox->flags & MU_STREAM_APPEND);
+                 || (mailbox->flags & MU_STREAM_APPEND);
 
       /* Try to mmap () the file first.  */
       if (status == 0)
        {
-         status = mu_mapfile_stream_create (&mailbox->stream, mud->name, 
mailbox->flags);
-         if (status == 0)
-           {
-             status = mu_stream_open (mailbox->stream);
-           }
+         status = mu_mapfile_stream_create (&mailbox->stream, mud->name,
+                                            mailbox->flags);
        }
 
       /* Fall back to normal file if mmap() failed.  */
-      if (status != 0)
-       {
-         status = mu_file_stream_create (&mailbox->stream, mud->name, 
mailbox->flags);
-         if (status != 0)
-           return status;
-         status = mu_stream_open (mailbox->stream);
-       }
-      /* All failed, bail out.  */
-      if (status != 0)
+      if (status)
+       status = mu_file_stream_create (&mailbox->stream, mud->name,
+                                       mailbox->flags);
+
+      if (status)
+       return status;
+
+      status = mu_stream_open (mailbox->stream);
+      if (status)
        {
-         mu_stream_destroy (&mailbox->stream, NULL);
+         mu_stream_destroy (&mailbox->stream);
          return status;
        }
-      /* Even on top of normal FILE *, lets agressively cache.  But this
-        may not be suitable for system tight on memory.  */
-      mu_stream_setbufsiz (mailbox->stream, BUFSIZ);
+      
+      /* FIXME: Set up buffering */
     }
   else
     {
@@ -247,7 +120,7 @@ mbox_open (mu_mailbox_t mailbox, int flags)
             mud->name, mailbox->flags);
 
   if (mailbox->locker == NULL)
-    status = mu_locker_create (&(mailbox->locker), mud->name, 0);
+    status = mu_locker_create (&mailbox->locker, mud->name, 0);
   return status;
 }
 
@@ -260,17 +133,18 @@ mbox_close (mu_mailbox_t mailbox)
   if (mud == NULL)
     return EINVAL;
 
-  MU_DEBUG1 (mailbox->debug, MU_DEBUG_TRACE1,  "mbox_close (%s)\n", mud->name);
+  MU_DEBUG1 (mailbox->debug, MU_DEBUG_TRACE1,
+            "mbox_close (%s)\n", mud->name);
 
   /* Make sure that we do not hold any file locking.  */
   mu_locker_unlock (mailbox->locker);
 
   /* Alain: I'm not sure on the right approach especially if the client is
-     working in disconnected mode, where it can 
mu_mailbox_close/mu_mailbox_open
-     for each request, maybe we should keep them for a while.
+     working in disconnected mode, where it can mu_mailbox_close/
+     mu_mailbox_open for each request, maybe we should keep them for a while.
 
      Sergey: No, it actually breaks reopening the mailbox. We should make
-     sure that the sequence mu_mailbox_open();mu_mailbox_close() will catch all
+     sure that the sequence mu_mailbox_open();mu_mailbox_close() catches all
      the changes that might have been done to the mailbox */
   
   mu_monitor_wrlock (mailbox->monitor);
@@ -280,7 +154,7 @@ mbox_close (mu_mailbox_t mailbox)
   for (i = 0; i < mud->umessages_count; i++)
     {
       mbox_message_t mum = mud->umessages[i];
-      /* Destroy the attach messages.  */
+      /* Destroy attached messages.  */
       if (mum)
        {
          mu_message_destroy (&(mum->message), mum);
@@ -299,7 +173,7 @@ mbox_close (mu_mailbox_t mailbox)
   return mu_stream_close (mailbox->stream);
 }
 
-/* Cover function that call the real thing, mbox_scan(), with
+/* Cover function that calls the real thing, mbox_scan(), with
    notification set.  */
 static int
 mbox_scan (mu_mailbox_t mailbox, size_t msgno, size_t *pcount)
@@ -318,11 +192,10 @@ mbox_scan (mu_mailbox_t mailbox, size_t msgno, size_t 
*pcount)
       if (mu_observable_notify (mailbox->observable, MU_EVT_MESSAGE_ADD,
                                &tmp) != 0)
        break;
-      if (((i +1) % 50) == 0)
-       {
-         mu_observable_notify (mailbox->observable, MU_EVT_MAILBOX_PROGRESS,
-                               NULL);
-       }
+      /* FIXME: Hardcoded value! Must be configurable */
+      if (((i + 1) % 50) == 0)
+       mu_observable_notify (mailbox->observable, MU_EVT_MAILBOX_PROGRESS,
+                             NULL);
     }
   *pcount = mud->messages_count;
   return 0;
@@ -337,7 +210,10 @@ mbox_scan (mu_mailbox_t mailbox, size_t msgno, size_t 
*pcount)
    Sergey: Nope, we shouldn't abort. Handling it with MU_EVT_MAILBOX_CORRUPT
    is sensible enough. The caller must decide what's the best approach
    in this case. The simplest one is reopening the mailbox. Imap4d currently
-   does that. */
+   does that.
+
+   And yet another thought: if a user reads his mail with a ... browser (!),
+   he is incurable anyway. */
 
 static int
 mbox_is_updated (mu_mailbox_t mailbox)
@@ -352,435 +228,12 @@ mbox_is_updated (mu_mailbox_t mailbox)
                            mailbox);
       /* And be verbose.  ? */
       mu_diag_output (MU_DIAG_EMERG, _("mailbox corrupted, shrank in size"));
-      /* FIXME: should I crash.  */
+      /* FIXME: should I crash? */
       return 0;
     }
   return (mud->size == size);
 }
 
-/* Try to create an uniq file, we no race conditions.   */
-static int
-mbox_tmpfile (mu_mailbox_t mailbox, char **pbox)
-{
-  const char *tmpdir;
-  int fd;
-  const char *basename;
-  mbox_data_t mud = mailbox->data;
-
-  /*  P_tmpdir should be in <stdio.h>.  */
-#ifndef P_tmpdir
-#  define P_tmpdir "/tmp"
-#endif
-
-  basename = strrchr (mud->name, '/');
-  if (basename)
-    basename++;
-  else
-    basename = mud->name;
-
-  tmpdir =  getenv ("TMPDIR") ? getenv ("TMPDIR") : P_tmpdir;
-  /* (separator + null) == 2 + XXXXXX == 6 + ... */
-  *pbox = calloc (strlen (tmpdir) + /* '/' */ 1 + /*strlen ("MU_")*/ 3 +
-                 strlen (basename) + /*strlen ("_XXXXXX")*/ 7 + /*null*/1,
-                 sizeof (**pbox));
-  if (*pbox == NULL)
-    return -1;
-  sprintf (*pbox, "%s/MU_%s_XXXXXX", tmpdir, basename);
-#ifdef HAVE_MKSTEMP
-  fd = mkstemp (*pbox);
-#else
-  /* Create the file.  It must not exist.  If it does exist, fail.  */
-  if (mktemp (*pbox))
-    {
-      fd = open (*pbox, O_RDWR|O_CREAT|O_EXCL, 0600);
-    }
-  else
-    {
-      free (*pbox);
-      fd = -1;
-    }
-#endif
-  return fd;
-}
-
-/* For the expunge bits  we took a very cautionnary approach, meaning
-   we create a temporary mailbox in the tmpdir copy all the message not mark
-   deleted(Actually we copy all the message that may have been modified
-   i.e new header values set; UIDL or UID or etc ....
-   and skip the deleted ones, truncate the real mailbox to the desired size
-   and overwrite with the tmp mailbox.  The approach to do everyting
-   in core is tempting but require
-   - to much memory, it is not rare nowadays to have 30 Megs mailbox,
-   - also there is danger for filesystems with quotas,
-   - if we run out of disk space everything is lost.
-   - or some program may not respect the advisory lock and decide to append
-   a new message while your expunging etc ...
-   The real downside to the approach is that when things go wrong
-   the temporary file may be left in /tmp, which is not all that bad
-   because at least, we have something to recuperate when failure.  */
-static int
-mbox_expunge0 (mu_mailbox_t mailbox, int remove_deleted)
-{
-  mbox_data_t mud = mailbox->data;
-  mbox_message_t mum;
-  int status = 0;
-  sigset_t signalset;
-  int tempfile;
-  size_t i, j, dirty;  /* dirty will indicate the first modified message.  */
-  mu_off_t marker = 0;    /* marker will be the position to truncate.  */
-  mu_off_t total = 0;
-  char *tmpmboxname = NULL;
-  mu_mailbox_t tmpmailbox = NULL;
-  size_t save_imapbase = 0;  /* uidvalidity is save in the first message.  */
-#ifdef WITH_PTHREAD
-  int state;
-#endif
-
-  if (mud == NULL)
-    return EINVAL;
-
-  MU_DEBUG1 (mailbox->debug, MU_DEBUG_TRACE1, "mbox_expunge (%s)\n", 
mud->name);
-
-  /* Noop.  */
-  if (mud->messages_count == 0)
-    return 0;
-
-  /* Find the first dirty(modified) message.  */
-  for (dirty = 0; dirty < mud->messages_count; dirty++)
-    {
-      mum = mud->umessages[dirty];
-      /* Message may have been tampered, break here.  */
-      if ((mum->attr_flags & MU_ATTRIBUTE_MODIFIED) ||
-         (mum->attr_flags & MU_ATTRIBUTE_DELETED) ||
-         (mum->message && mu_message_is_modified (mum->message)))
-       break;
-    }
-
-  /* Did something change ?  */
-  if (dirty == mud->messages_count)
-    return 0; /* Nothing change, bail out.  */
-
-  /* Create a temporary file.  */
-  tempfile = mbox_tmpfile (mailbox, &tmpmboxname);
-  if (tempfile == -1)
-    {
-      if (tmpmboxname)
-       free (tmpmboxname);
-      mu_error (_("failed to create temporary file when expunging"));
-      return errno;
-    }
-
-  /* This is redundant, we go to the loop again.  But it's more secure here
-     since we don't want to be disturb when expunging.  Destroy all the
-     messages mark for deletion.  */
-  if (remove_deleted)
-    {
-      for (j = 0; j < mud->messages_count; j++)
-       {
-         mum = mud->umessages[j];
-         if (mum && mum->message && ATTRIBUTE_IS_DELETED (mum->attr_flags))
-           mu_message_destroy (&(mum->message), mum);
-       }
-    }
-
-  /* Create temporary mu_mailbox_t.  */
-  {
-    mbox_data_t tmp_mud;
-    char *m = malloc (5 + strlen (tmpmboxname) + 1);
-    if (!m)
-      return ENOMEM;
-    /* Try via the mbox: protocol.  */
-    sprintf (m, "mbox:%s", tmpmboxname);
-    status = mu_mailbox_create (&tmpmailbox, m);
-    if (status != 0)
-      {
-       /* Do not give up just yet, maybe they register the mu_path_record.  */
-       sprintf (m, "%s", tmpmboxname);
-       status = mu_mailbox_create (&tmpmailbox, m);
-       if (status != 0)
-         {
-           /* Ok give up.  */
-           close (tempfile);
-           remove (tmpmboxname);
-            free (m);
-           free (tmpmboxname);
-           return status;
-         }
-      }
-    free (m);
-    /* Must be flag CREATE if not the mu_mailbox_open will try to mmap()
-       the file.  */
-    status = mu_mailbox_open (tmpmailbox, MU_STREAM_CREAT | MU_STREAM_RDWR);
-    if (status != 0)
-      {
-       close (tempfile);
-       remove (tmpmboxname);
-       free (tmpmboxname);
-       return status;
-      }
-    close (tempfile); /* This one is useless the mailbox have its own.  */
-    tmp_mud = tmpmailbox->data;
-    /* May need when appending.  */
-    tmp_mud->uidvalidity = mud->uidvalidity;
-    tmp_mud->uidnext = mud->uidnext;
-  }
-
-  /* Get the File lock.  */
-  if ((status = mu_locker_lock (mailbox->locker)) != 0)
-    {
-      mu_mailbox_close (tmpmailbox);
-      mu_mailbox_destroy (&tmpmailbox);
-      remove (tmpmboxname);
-      free (tmpmboxname);
-      mu_error (_("failed to grab the lock: %s"), mu_strerror (status));
-      return status;
-    }
-
-  /* Critical section, we can not allowed signal here.  */
-#ifdef WITH_PTHREAD
-  pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &state);
-#endif
-  sigemptyset (&signalset);
-  sigaddset (&signalset, SIGTERM);
-  sigaddset (&signalset, SIGHUP);
-  sigaddset (&signalset, SIGTSTP);
-  sigaddset (&signalset, SIGINT);
-  sigaddset (&signalset, SIGWINCH);
-  sigprocmask (SIG_BLOCK, &signalset, 0);
-
-  /* Set the marker position.  */
-  marker = mud->umessages[dirty]->header_from;
-  total = 0;
-
-  /* Copy to the temporary mailbox emails not mark deleted.  */
-  for (i = dirty; i < mud->messages_count; i++)
-    {
-      mum = mud->umessages[i];
-
-      /* Skip it, if mark for deletion.  */
-      if (remove_deleted && ATTRIBUTE_IS_DELETED (mum->attr_flags))
-       {
-         /* We save the uidvalidity in the first message, if it is being
-            deleted we need to move the uidvalidity to the first available
-            (non-deleted) message.  */
-         if (i == save_imapbase)
-           {
-             save_imapbase = i + 1;
-             if (save_imapbase < mud->messages_count)
-               (mud->umessages[save_imapbase])->attr_flags |= 
MU_ATTRIBUTE_MODIFIED;
-           }
-         continue;
-       }
-
-      /* Do the expensive mbox_append_message0() only if mark dirty.  */
-      if ((mum->attr_flags & MU_ATTRIBUTE_MODIFIED) ||
-         (mum->message && mu_message_is_modified (mum->message)))
-       {
-         /* The message was not instantiated, probably the dirty flag was
-            set by mbox_scan(), create one here.  */
-         if (mum->message == 0)
-           {
-             mu_message_t msg;
-             status = mbox_get_message (mailbox, i + 1, &msg);
-             if (status != 0)
-               {
-                 mu_error (_("error expunging:%d: %s"), __LINE__,
-                           mu_strerror (status));
-                 goto bailout0;
-               }
-           }
-         status = mbox_append_message0 (tmpmailbox, mum->message,
-                                        &total, 1, (i == save_imapbase));
-         if (status != 0)
-           {
-             mu_error (_("error expunging:%d: %s"), __LINE__,
-                       mu_strerror (status));
-             goto bailout0;
-           }
-         /* Clear the dirty bits.  */
-         mum->attr_flags &= ~MU_ATTRIBUTE_MODIFIED;
-         mu_message_clear_modified (mum->message);
-       }
-      else
-       {
-         /* Nothing changed copy the message straight.  */
-         char buffer [1024];
-         size_t n;
-         mu_off_t offset = mum->header_from;
-         size_t len = mum->body_end - mum->header_from;
-         while (len > 0)
-           {
-             n = (len < sizeof (buffer)) ? len : sizeof (buffer);
-             if ((status = mu_stream_read (mailbox->stream, buffer, n, offset,
-                                        &n) != 0)
-                 || (status = mu_stream_write (tmpmailbox->stream, buffer, n,
-                                            total, &n) != 0))
-               {
-                 mu_error (_("error expunging:%d: %s"), __LINE__,
-                           mu_strerror (status));
-                 goto bailout0;
-               }
-             len -= n;
-             total += n;
-             offset += n;
-           }
-         /* Add the newline separator.  */
-         status = mu_stream_write (tmpmailbox->stream, "\n", 1, total, &n);
-         if (status != 0)
-           {
-             mu_error (_("error expunging:%d: %s"), __LINE__,
-                       mu_strerror (status));
-             goto bailout0;
-           }
-         total++;
-       }
-    } /* for (;;) */
-
-  /* Caution: before ftruncate()ing the file see
-     - if we've receive new mails.  Some programs may not respect the lock,
-     - or the lock was held for too long.
-     - The mailbox may not have been properly updated before expunging.  */
-  {
-    mu_off_t size = 0;
-    if (mu_stream_size (mailbox->stream, &size) == 0)
-      {
-       mu_off_t len = size - mud->size;
-       mu_off_t offset = mud->size;
-       char buffer [1024];
-       size_t n = 0;
-       if (len > 0 )
-         {
-           while ((status = mu_stream_read (mailbox->stream, buffer,
-                                         sizeof (buffer), offset, &n)) == 0
-                  && n > 0)
-             {
-               status = mu_stream_write (tmpmailbox->stream, buffer, n,
-                                      total, &n);
-               if (status != 0)
-                 {
-                   mu_error (_("error expunging:%d: %s"), __LINE__,
-                             mu_strerror (status));
-                   goto bailout0;
-                 }
-               total += n;
-               offset += n;
-             }
-         }
-       else if (len < 0)
-         {
-           /* Corrupted mailbox.  */
-           mu_error (_("error expunging:%d: %s"), __LINE__,
-                     mu_strerror (status));
-           goto bailout0;
-         }
-      }
-  } /* End of precaution.  */
-
-  /* Seek and rewrite it.  */
-  if (total > 0)
-    {
-      char buffer [1024];
-      size_t n = 0;
-      mu_off_t off = 0;
-      mu_off_t offset = marker;
-      while ((status = mu_stream_read (tmpmailbox->stream, buffer,
-                                   sizeof (buffer), off, &n)) == 0
-            && n > 0)
-       {
-         status = mu_stream_write (mailbox->stream, buffer, n, offset, &n);
-         if (status != 0)
-           {
-             mu_error (_("error expunging:%d: %s"), __LINE__,
-                       mu_strerror (status));
-             goto bailout;
-           }
-         off += n;
-         offset += n;
-       }
-    }
-
-  /* Flush/truncation. Need to flush before truncate.  */
-  mu_stream_flush (mailbox->stream);
-  status = mu_stream_truncate (mailbox->stream, total + marker);
-  if (status != 0)
-    {
-      mu_error (_("error expunging:%d: %s"), __LINE__,
-               mu_strerror (status));
-      goto bailout;
-    }
-
-  /* Don't remove the tmp mbox in case of errors, when writing back.  */
- bailout0:
-  remove (tmpmboxname);
-
- bailout:
-
-  free (tmpmboxname);
-  /* Release the File lock.  */
-  mu_locker_unlock (mailbox->locker);
-  mu_mailbox_close (tmpmailbox);
-  mu_mailbox_destroy (&tmpmailbox);
-
-  /* Reenable signal.  */
-#ifdef WITH_PTHREAD
-  pthread_setcancelstate (state, &state);
-#endif
-  sigprocmask (SIG_UNBLOCK, &signalset, 0);
-
-  /* We need to readjust the pointers.
-     It is a little hairy because we need to keep the message pointers alive
-     So we are going through the array and "defragmentize".  For example
-     in (1 2 3 4) if 2 was deleted we need to move 3 4 up by one etc ..
-  */
-  if (status == 0)
-    {
-      size_t dlast;
-      mu_monitor_wrlock (mailbox->monitor);
-      for (j = dirty, dlast = mud->messages_count - 1;
-          j <= dlast; j++)
-       {
-         /* Clear all the references, any attach messages been already
-            destroy above.  */
-         mum = mud->umessages[j];
-         if (remove_deleted && ATTRIBUTE_IS_DELETED (mum->attr_flags))
-           {
-             if ((j + 1) <= dlast)
-               {
-                 /* Move all the pointers up.  So the message pointer
-                    part of mum will be at the right position.  */
-                 memmove (mud->umessages + j, mud->umessages + j + 1,
-                          (dlast - j) * sizeof (mum));
-#if 0
-                 mum->header_from = mum->header_from_end = 0;
-                 mum->body = mum->body_end = 0;
-                 mum->header_lines = mum->body_lines = 0;
-#endif
-                 memset (mum, 0, sizeof (*mum));
-                 /* We are not free()ing the useless mum, but instead
-                    we put it back in the pool, to be reuse.  */
-                 mud->umessages[dlast] = mum;
-                 dlast--;
-                 /* Set mum to the new value after the memmove so it
-                    gets cleared to.  */
-                 mum = mud->umessages[j];
-               }
-             else
-               {
-                 memset (mum, 0, sizeof (*mum));
-               }
-           }
-         mum->header_from = mum->header_from_end = 0;
-         mum->body = mum->body_end = 0;
-         mum->header_lines = mum->body_lines = 0;
-       }
-      mu_monitor_unlock (mailbox->monitor);
-      /* This is should reset the messages_count, the last argument 0 means
-        not to send event notification.  */
-      mbox_scan0 (mailbox, dirty, NULL, 0);
-    }
-  return status;
-}
-
 static int
 mbox_expunge (mu_mailbox_t mailbox)
 {
@@ -806,144 +259,53 @@ static int
 mbox_message_qid (mu_message_t msg, mu_message_qid_t *pqid)
 {
   mbox_message_t mum = mu_message_get_owner (msg);
-  return mu_asprintf (pqid, "%lu", (unsigned long) mum->header_from);
-}
-
-static int
-mbox_get_body_transport (mu_stream_t is, mu_transport_t *pin,
-                        mu_transport_t *pout)
-{
-  mu_body_t body = mu_stream_get_owner (is);
-  mu_message_t msg = mu_body_get_owner (body);
-  mbox_message_t mum = mu_message_get_owner (msg);
-  return mbox_get_transport2 (mum, pin, pout);
-}
-
-static int
-mbox_get_transport2 (mbox_message_t mum, mu_transport_t *pin,
-                    mu_transport_t *pout)
-{
-  if (mum == NULL)
-    return EINVAL;
-  return mu_stream_get_transport2 (mum->mud->mailbox->stream, pin, pout);
-}
-
-static int
-mbox_get_attr_flags (mu_attribute_t attr, int *pflags)
-{
-  mu_message_t msg = mu_attribute_get_owner (attr);
-  mbox_message_t mum = mu_message_get_owner (msg);
-
-  if (mum == NULL)
-    return EINVAL;
-  if (pflags)
-    *pflags = mum->attr_flags;
-  return 0;
+  return mu_asprintf (pqid, "%lu", (unsigned long) mum->envel_from);
 }
 
-static int
-mbox_set_attr_flags (mu_attribute_t attr, int flags)
-{
-  mu_message_t msg = mu_attribute_get_owner (attr);
-  mbox_message_t mum = mu_message_get_owner (msg);
-
-  if (mum == NULL)
-    return EINVAL;
-  mum->attr_flags |= flags;
-  return 0;
-}
+
+/* Mbox message headers */
 
+#ifdef MU_MBOX_SET_HEADER
 static int
-mbox_unset_attr_flags (mu_attribute_t attr, int flags)
+mbox_header_fill (void *data, char **pbuf, size_t *plen)
 {
-  mu_message_t msg = mu_attribute_get_owner (attr);
-  mbox_message_t mum = mu_message_get_owner (msg);
-
-  if (mum == NULL)
-    return EINVAL;
-  mum->attr_flags &= ~flags;
-  return 0;
-}
-
-static int
-mbox_body_readline (mu_stream_t is, char *buffer, size_t buflen,
-                   mu_off_t off, size_t *pnread)
-{
-  mu_body_t body = mu_stream_get_owner (is);
-  mu_message_t msg = mu_body_get_owner (body);
-  mbox_message_t mum = mu_message_get_owner (msg);
-
-  return mbox_readstream (mum, buffer, buflen, off, pnread, 1,
-                         mum->body, mum->body_end);
+  /* FIXME: This would be almost exact copy of _header_fill from
+     mailbox/message.c. So there's perhaps no use defining this
+     method. Instead we prefer to use the default header machinery,
+     which relies on the message stream (see #else below). */
+  abort ();
 }
 
 static int
-mbox_body_read (mu_stream_t is, char *buffer, size_t buflen,
-               mu_off_t off, size_t *pnread)
+_msg_header_setup (mu_message_t msg, mbox_message_t mum)
 {
-  mu_body_t body = mu_stream_get_owner (is);
-  mu_message_t msg = mu_body_get_owner (body);
-  mbox_message_t mum = mu_message_get_owner (msg);
-  return mbox_readstream (mum, buffer, buflen, off, pnread, 0,
-                         mum->body, mum->body_end);
-}
-
-static int
-mbox_readstream (mbox_message_t mum, char *buffer, size_t buflen,
-                mu_off_t off, size_t *pnread, int isreadline,
-                mu_off_t start, mu_off_t end)
-{
-  size_t nread = 0;
-  int status = 0;
-
-  if (buffer == NULL || buflen == 0)
+  mu_header_t header;
+  int status = mu_header_create (&header, NULL, 0);
+  if (status == 0)
     {
-      if (pnread)
-       *pnread = nread;
-      return 0;
+      mu_header_set_fill (header, mbox_header_fill, msg);
+      mu_message_set_header (msg, header, mum);
     }
-
-  mu_monitor_rdlock (mum->mud->mailbox->monitor);
-#ifdef WITH_PTHREAD
-  /* read() is cancellation point since we're doing a potentially
-     long operation.  Lets make sure we clean the state.  */
-  pthread_cleanup_push (mbox_cleanup, (void *)mum->mud->mailbox);
-#endif
-  {
-    mu_off_t ln = end - (start + off);
-    if (ln > 0)
-      {
-       /* Position the file pointer and the buffer.  */
-       nread = ((size_t)ln < buflen) ? (size_t)ln : buflen;
-       if (isreadline)
-         status = mu_stream_readline (mum->mud->mailbox->stream,
-                                      buffer, buflen,
-                                      start + off, &nread);
-       else
-         status = mu_stream_read (mum->mud->mailbox->stream, buffer, nread,
-                                  start + off, &nread);
-      }
-  }
-  mu_monitor_unlock (mum->mud->mailbox->monitor);
-#ifdef WITH_PTHREAD
-  pthread_cleanup_pop (0);
-#endif
-
-  if (pnread)
-    *pnread = nread;
   return status;
 }
-
+#else
 static int
-mbox_header_fill (mu_header_t header, char *buffer, size_t len,
-                 mu_off_t off, size_t *pnread)
+_msg_stream_setup (mu_message_t msg, mbox_message_t mum)
 {
-  mu_message_t msg = mu_header_get_owner (header);
-  mbox_message_t mum = mu_message_get_owner (msg);
-  return mbox_readstream (mum, buffer, len, off, pnread, 0,
-                         mum->header_from_end, mum->body);
+  mu_stream_t stream;
+  int status;
+  
+  status = mu_streamref_create_abridged (&stream,
+                                        mum->mud->mailbox->stream,
+                                        mum->envel_from_end,
+                                        mum->body_end - 1);
+  if (status == 0)
+    status = mu_message_set_stream (msg, stream, mum);
+  return status;
 }
-
+#endif
+
+/* Mbox message body */
 static int
 mbox_body_size (mu_body_t body, size_t *psize)
 {
@@ -957,13 +319,6 @@ mbox_body_size (mu_body_t body, size_t *psize)
 }
 
 static int
-mbox_stream_size (mu_stream_t stream, mu_off_t *psize)
-{
-  mu_body_t body = mu_stream_get_owner (stream);
-  return mbox_body_size (body, (size_t*) psize);
-}
-
-static int
 mbox_body_lines (mu_body_t body, size_t *plines)
 {
   mu_message_t msg = mu_body_get_owner (body);
@@ -976,6 +331,34 @@ mbox_body_lines (mu_body_t body, size_t *plines)
 }
 
 static int
+_msg_body_setup (mu_message_t msg, mbox_message_t mum)
+{
+  mu_body_t body;
+  mu_stream_t stream;
+  int status;
+  
+  status = mu_body_create (&body, msg);
+  if (status)
+    return status;
+  status = mu_streamref_create_abridged (&stream,
+                                        mum->mud->mailbox->stream,
+                                        mum->body,
+                                        mum->body_end - 1);
+  if (status)
+    mu_body_destroy (&body, msg);
+  else
+    {
+      mu_body_set_stream (body, stream, msg);
+      mu_body_set_size (body, mbox_body_size, msg);
+      mu_body_set_lines (body, mbox_body_lines, msg);
+      mu_message_set_body (msg, body, mum);
+    }
+  return status;
+}
+
+/* Mbox message envelope */
+
+static int
 mbox_envelope_date (mu_envelope_t envelope, char *buf, size_t len,
                    size_t *pnwrite)
 {
@@ -989,16 +372,18 @@ mbox_envelope_date (mu_envelope_t envelope, char *buf, 
size_t len,
   if (mum == NULL)
     return EINVAL;
 
+  status = mu_stream_seek (mum->mud->mailbox->stream,
+                          mum->envel_from, MU_SEEK_SET,
+                          NULL);
+  if (status)
+    return status;
   status = mu_stream_readline (mum->mud->mailbox->stream,
                               buffer, sizeof(buffer),
-                              mum->header_from, &n);
-  if (status != 0)
-    {
-      if (pnwrite)
-       *pnwrite = 0;
-      return status;
-    }
-
+                              &n);
+  if (status)
+    return status;
+  mu_rtrim_cset (buffer, "\r\n");
+  
   /* Format:  "From [sender] [date]" */
   /* strlen ("From ") == 5 */
   if (n > 5 && (s = strchr (buffer + 5, ' ')) != NULL)
@@ -1034,15 +419,15 @@ mbox_envelope_sender (mu_envelope_t envelope, char *buf, 
size_t len,
   if (mum == NULL)
     return EINVAL;
 
+  status = mu_stream_seek (mum->mud->mailbox->stream,
+                          mum->envel_from, MU_SEEK_SET,
+                          NULL);
+  if (status)
+    return status;
   status = mu_stream_readline (mum->mud->mailbox->stream, buffer,
-                              sizeof(buffer),
-                              mum->header_from, &n);
-  if (status != 0)
-    {
-      if (pnwrite)
-       *pnwrite = 0;
-      return status;
-    }
+                              sizeof(buffer), &n);
+  if (status)
+    return status;
 
   /* Format:  "From [sender] [date]" */
   /* strlen ("From ") == 5 */
@@ -1067,6 +452,101 @@ mbox_envelope_sender (mu_envelope_t envelope, char *buf, 
size_t len,
   return 0;
 }
 
+int
+_msg_envelope_setup (mu_message_t msg, mbox_message_t mum)
+{
+  mu_envelope_t envelope;
+  int status = mu_envelope_create (&envelope, msg);
+  if (status == 0)
+    {
+      mu_envelope_set_sender (envelope, mbox_envelope_sender, msg);
+      mu_envelope_set_date (envelope, mbox_envelope_date, msg);
+      mu_message_set_envelope (msg, envelope, mum);
+    }
+  return status;
+}
+
+/* Mbox message attributes */
+
+static int
+mbox_get_attr_flags (mu_attribute_t attr, int *pflags)
+{
+  mu_message_t msg = mu_attribute_get_owner (attr);
+  mbox_message_t mum = mu_message_get_owner (msg);
+
+  if (mum == NULL)
+    return EINVAL;
+  if (pflags)
+    *pflags = mum->attr_flags;
+  return 0;
+}
+
+static int
+mbox_set_attr_flags (mu_attribute_t attr, int flags)
+{
+  mu_message_t msg = mu_attribute_get_owner (attr);
+  mbox_message_t mum = mu_message_get_owner (msg);
+
+  if (mum == NULL)
+    return EINVAL;
+  mum->attr_flags |= flags;
+  return 0;
+}
+
+static int
+mbox_unset_attr_flags (mu_attribute_t attr, int flags)
+{
+  mu_message_t msg = mu_attribute_get_owner (attr);
+  mbox_message_t mum = mu_message_get_owner (msg);
+
+  if (mum == NULL)
+    return EINVAL;
+  mum->attr_flags &= ~flags;
+  return 0;
+}
+
+int
+_msg_attribute_setup (mu_message_t msg, mbox_message_t mum)
+{
+  mu_attribute_t attribute;
+  int status = mu_attribute_create (&attribute, msg);
+  if (status == 0)
+    {
+      mu_attribute_set_get_flags (attribute, mbox_get_attr_flags, msg);
+      mu_attribute_set_set_flags (attribute, mbox_set_attr_flags, msg);
+      mu_attribute_set_unset_flags (attribute, mbox_unset_attr_flags, msg);
+      mu_message_set_attribute (msg, attribute, mum);
+    }
+  return status;
+}
+
+/* Initialize a message */
+static int
+_msg_setup (mu_message_t msg, mbox_message_t mum)
+{
+  int status;
+  
+#ifdef MU_MBOX_SET_HEADER
+  /* Set the header.  */
+  status = _msg_header_setup (msg, mum);
+#else
+  status = _msg_stream_setup (msg, mum);
+#endif
+  if (status)
+    return status;
+  
+  status = _msg_attribute_setup (msg, mum);
+  if (status)
+    return status;
+
+  status = _msg_body_setup (msg, mum);
+  if (status)
+    return status;
+
+  return _msg_envelope_setup (msg, mum);
+}
+
+/* Create new mu_message_t from mbox_message_t */
 static int
 new_message (mu_mailbox_t mailbox, mbox_message_t mum, mu_message_t *pmsg)
 {
@@ -1078,71 +558,12 @@ new_message (mu_mailbox_t mailbox, mbox_message_t mum, 
mu_message_t *pmsg)
   if (status != 0)
     return status;
 
-  /* Set the header.  */
-  {
-    mu_header_t header = NULL;
-    status = mu_header_create (&header, NULL, 0, msg);
-    if (status != 0)
-      {
-       mu_message_destroy (&msg, mum);
-       return status;
-      }
-    mu_header_set_fill (header, mbox_header_fill, msg);
-    mu_message_set_header (msg, header, mum);
-  }
-
-  /* Set the attribute.  */
-  {
-    mu_attribute_t attribute;
-    status = mu_attribute_create (&attribute, msg);
-    if (status != 0)
-      {
-       mu_message_destroy (&msg, mum);
-       return status;
-      }
-    mu_attribute_set_get_flags (attribute, mbox_get_attr_flags, msg);
-    mu_attribute_set_set_flags (attribute, mbox_set_attr_flags, msg);
-    mu_attribute_set_unset_flags (attribute, mbox_unset_attr_flags, msg);
-    mu_message_set_attribute (msg, attribute, mum);
-  }
-
-  /* Prepare the body.  */
-  {
-    mu_body_t body = NULL;
-    mu_stream_t stream = NULL;
-    if ((status = mu_body_create (&body, msg)) != 0
-       || (status = mu_stream_create (&stream,
-                                      mailbox->flags | MU_STREAM_SEEKABLE,
-                                      body)) != 0)
-      {
-       mu_body_destroy (&body, msg);
-       mu_stream_destroy (&stream, body);
-       mu_message_destroy (&msg, mum);
-       return status;
-      }
-    mu_stream_set_read (stream, mbox_body_read, body);
-    mu_stream_set_readline (stream, mbox_body_readline, body);
-    mu_stream_set_get_transport2 (stream, mbox_get_body_transport, body);
-    mu_stream_set_size (stream, mbox_stream_size, body);
-    mu_body_set_stream (body, stream, msg);
-    mu_body_set_size (body, mbox_body_size, msg);
-    mu_body_set_lines (body, mbox_body_lines, msg);
-    mu_message_set_body (msg, body, mum);
-  }
-
-  /* Set the envelope.  */
-  {
-    mu_envelope_t envelope= NULL;
-    status = mu_envelope_create (&envelope, msg);
-    if (status != 0)
-      {
-       mu_message_destroy (&msg, mum);
-       return status;
-      }
-    mu_envelope_set_sender (envelope, mbox_envelope_sender, msg);
-    mu_envelope_set_date (envelope, mbox_envelope_date, msg);
-    mu_message_set_envelope (msg, envelope, mum);
-  }
+  status = _msg_setup (msg, mum);
+  if (status)
+    {
+      mu_message_destroy (&msg, mum);
+      return status;
+    }
 
   /* Set the UID.  */
   mu_message_set_uid (msg, mbox_message_uid, mum);
@@ -1257,77 +678,164 @@ mbox_quick_get_message (mu_mailbox_t mailbox, 
mu_message_qid_t qid,
 
   return new_message (mailbox, mum, pmsg);
 }
-     
+
 static int
-mbox_append_message (mu_mailbox_t mailbox, mu_message_t msg)
+mbox_get_size (mu_mailbox_t mailbox, mu_off_t *psize)
+{
+  mu_off_t size;
+  int status;
+
+  /* Maybe was not open yet ??  */
+  status  = mu_stream_size (mailbox->stream, &size);
+  if (status != 0)
+    return status;
+  if (psize)
+    *psize = size;
+  return 0;
+}
+
+static int
+mbox_messages_count (mu_mailbox_t mailbox, size_t *pcount)
 {
-  int status = 0;
   mbox_data_t mud = mailbox->data;
-  mu_off_t qid;
-  
-  if (msg == NULL || mud == NULL)
+
+  if (mud == NULL)
     return EINVAL;
 
-  MU_DEBUG1 (mailbox->debug, MU_DEBUG_TRACE1, "mbox_append_message (%s)\n",
-                 mud->name);
+  if (! mbox_is_updated (mailbox))
+    return mbox_scan0 (mailbox,  mud->messages_count, pcount, 0);
+
+  if (pcount)
+    *pcount = mud->messages_count;
+
+  return 0;
+}
+
+/* A "recent" message is the one not marked with MU_ATTRIBUTE_SEEN
+   ('O' in the Status header), i.e. a message that is first seen
+   by the current session (see attributes.h) */
+static int
+mbox_messages_recent (mu_mailbox_t mailbox, size_t *pcount)
+{
+  mbox_data_t mud = mailbox->data;
+  mbox_message_t mum;
+  size_t j, recent;
 
-  switch (mud->state)
+  /* If we did not start a scanning yet do it now.  */
+  if (mud->messages_count == 0)
+    {
+      int status = mbox_scan0 (mailbox, 1, NULL, 0);
+      if (status != 0)
+       return status;
+    }
+  for (recent = j = 0; j < mud->messages_count; j++)
     {
-    case MBOX_NO_STATE:
-      if ((status = mu_locker_lock (mailbox->locker)) != 0)
+      mum = mud->umessages[j];
+      if (mum && MU_ATTRIBUTE_IS_UNSEEN(mum->attr_flags))
+       recent++;
+    }
+  *pcount = recent;
+  return 0;
+}
+
+/* An "unseen" message is the one that has not been read yet */
+static int
+mbox_message_unseen (mu_mailbox_t mailbox, size_t *pmsgno)
+{
+  mbox_data_t mud = mailbox->data;
+  mbox_message_t mum;
+  size_t j, unseen;
+
+  /* If we did not start a scanning yet do it now.  */
+  if (mud->messages_count == 0)
+    {
+      int status = mbox_scan0 (mailbox, 1, NULL, 0);
+      if (status != 0)
+       return status;
+    }
+  for (unseen = j = 0; j < mud->messages_count; j++)
+    {
+      mum = mud->umessages[j];
+      if (mum && MU_ATTRIBUTE_IS_UNREAD(mum->attr_flags))
        {
-         MU_DEBUG1 (mailbox->debug, MU_DEBUG_TRACE1,
-                         "mbox_append_message: %s\n",
-                         mu_strerror(status));
-         return status;
+         unseen = j + 1;
+         break;
        }
+    }
+  *pmsgno = unseen;
+  return 0;
+}
 
-    default:
-      {
-       mu_off_t size;
-       /* Move to the end of the file, not necesary if _APPEND mode.  */
-       if ((status = mu_stream_size (mailbox->stream, &size)) != 0
-           || (qid = size,
-               status = mbox_append_message0 (mailbox, msg,
-                                              &size, 0, 0)) != 0)
-         {
-           if (status != EAGAIN)
-             mu_locker_unlock (mailbox->locker);
-           return status;
-         }
-      }
+static int
+mbox_uidvalidity (mu_mailbox_t mailbox, unsigned long *puidvalidity)
+{
+  mbox_data_t mud = mailbox->data;
+  int status = mbox_messages_count (mailbox, NULL);
+  if (status != 0)
+    return status;
+  /* If we did not start a scanning yet do it now.  */
+  if (mud->messages_count == 0)
+    {
+      status = mbox_scan0 (mailbox, 1, NULL, 0);
+      if (status != 0)
+       return status;
     }
-  mu_locker_unlock (mailbox->locker);
+  if (puidvalidity)
+    *puidvalidity = mud->uidvalidity;
+  return 0;
+}
 
-  if (mailbox->observable)
+static int
+mbox_uidnext (mu_mailbox_t mailbox, size_t *puidnext)
+{
+  mbox_data_t mud = mailbox->data;
+  int status = mbox_messages_count (mailbox, NULL);
+  if (status != 0)
+    return status;
+  /* If we did not start a scanning yet do it now.  */
+  if (mud->messages_count == 0)
     {
-      char *buf = NULL;
-      mu_asprintf (&buf, "%lu", (unsigned long) qid);
-      mu_observable_notify (mailbox->observable, MU_EVT_MESSAGE_APPEND, buf);
-      free (buf);
+      status = mbox_scan0 (mailbox, 1, NULL, 0);
+      if (status != 0)
+       return status;
     }
-  
+  if (puidnext)
+    *puidnext = mud->uidnext;
   return 0;
 }
 
+#ifdef WITH_PTHREAD
+void
+mbox_cleanup (void *arg)
+{
+  mu_mailbox_t mailbox = arg;
+  mu_monitor_unlock (mailbox->monitor);
+  mu_locker_unlock (mailbox->locker);
+}
+#endif
+
+
+/* Support functions for appending a message to a stream or mbox */
+
+#define MBOX_FIRSTMSG 0x01
+#define MBOX_EXPUNGE  0x02
+
 int
-restore_sender (mu_message_t msg, mbox_data_t mud)
+restore_sender (mu_message_t msg, char **pret)
 {
   mu_header_t hdr;
+  const char *s = NULL;
   char *from = NULL;
-  int rc = 0;
   
   if (mu_message_get_header (msg, &hdr) == 0)
-    mu_header_aget_value (hdr, MU_HEADER_FROM, &from);
+    mu_header_sget_value (hdr, MU_HEADER_FROM, &s);
 
-  if (from)
+  if (s)
     {
       int status;
       mu_address_t addr;
       
-      status = mu_address_create (&addr, from);
-      free (from);
-      from = NULL;
+      status = mu_address_create (&addr, s);
       if (status == 0)
        mu_address_aget_email (addr, 1, &from);
       mu_address_destroy (&addr);
@@ -1339,533 +847,663 @@ restore_sender (mu_message_t msg, mbox_data_t mud)
       if (!from) 
        return ENOMEM;
     }
-
-  mud->sender = strdup (from);
-  if (!mud->sender)
-    rc = ENOMEM;
-  free (from);
-  return rc;
+  *pret = from;
+  return 0;
 }
 
 int
-restore_date (mu_message_t msg, mbox_data_t mud)
+restore_date (mu_message_t msg, char **pret)
 {
   mu_header_t hdr;
+  const char *s;
   char *date = NULL;
   time_t t;
-  int rc = 0;
   
   if (mu_message_get_header (msg, &hdr) == 0)
-    mu_header_aget_value (hdr, MU_HEADER_DATE, &date);
+    mu_header_sget_value (hdr, MU_HEADER_DATE, &s);
 
-  if (date && mu_parse_date (date, &t, NULL))
+  if (s && mu_parse_date (s, &t, NULL))
     {
       char datebuf[MU_ENVELOPE_DATE_LENGTH+1];
       
       /* FIXME: 1. Preserve TZ info */
       mu_strftime (datebuf, sizeof datebuf, MU_ENVELOPE_DATE_FORMAT,
                   localtime (&t));
-      free (date);
       date = strdup (datebuf);
     }
   else
     {
       time (&t);
-      free (date);
       date = strdup (ctime (&t));
     }
-
-  mud->date = date;
-  if (!mud->date)
-    rc = ENOMEM;
-  return rc;
+  if (!date)
+    return ENOMEM;
+  *pret = date;
+  return 0;
 }
 
 static int
-write_array (mu_stream_t stream, mu_off_t *poff, int count, const char **array)
+write_array (mu_stream_t stream, int count, const char **array)
 {
-  int status;
-  for (; count; count--, array++)
+  int i;
+  for (i = 0; i < count; i++)
     {
-      size_t len = strlen (*array);
-      size_t i = 0, n;
-      
-      do
-       {
-         status = mu_stream_write (stream, *array + i, len - i, *poff, &n);
-         if (status)
-           return status;
-         *poff += n;
-         i += n;
-       }
-      while (i < len);
+      int status = mu_stream_write (stream, array[i], strlen (array[i]), NULL);
+      if (status)
+       return status;
     }
   return 0;
 }
 
-
-/* FIXME: Do we need to escape body line that begins with "From "? This
-   will require reading the body line by line instead of by chunks,
-   considerably hurting perfomance when expunging.  But should not this
-   be the responsibility of the client ?  */
 static int
-mbox_append_message0 (mu_mailbox_t mailbox, mu_message_t msg, mu_off_t *psize,
-                     int is_expunging, int first)
+msg_envelope_to_stream (mu_stream_t out, mu_message_t msg)
 {
-  mbox_data_t mud = mailbox->data;
-  int status = 0;
-  size_t n = 0;
-  char nl = '\n';
-  size_t orig_size = *psize;
-  char *s;
+  mu_envelope_t env;
+  int status;
+  char *sender = NULL;
+  char *datestr = NULL;
+  const char *envarr[5];
   
-  switch (mud->state)
+  status = mu_message_get_envelope (msg, &env);
+  if (status)
+    return status;
+  
+  status = mu_envelope_aget_sender (env, &sender);
+  switch (status)
     {
-    case MBOX_NO_STATE:
-      mud->off = 0;
-      mud->state = MBOX_STATE_APPEND_SENDER;
-
-    case MBOX_STATE_APPEND_SENDER:
-      /* Generate the sender for the "From " separator.  */
-      {
-       char *s;
-       mu_envelope_t envelope = NULL;
-       mu_message_get_envelope (msg, &envelope);
-       status = mu_envelope_aget_sender (envelope, &mud->sender);
-       switch (status) {
-       case 0:
-         break;
-         
-       case EAGAIN:
-         return status;
-
-       case MU_ERR_NOENT: /* Envelope headers not found: try to guess */
-         free (mud->sender);
-          mud->sender = NULL;
-         status = restore_sender (msg, mud);
-         if (status == 0)
-            break;
-         
-       default:
-         free (mud->sender);
-         free (mud->date);
-         mud->date = mud->sender = NULL;
-         mud->state = MBOX_NO_STATE;
-         return status;
-       }
-
-       /* Nuke trailing newline.  */
-       s = strchr (mud->sender, nl);
-       if (s)
-         *s = '\0';
-       mud->state = MBOX_STATE_APPEND_DATE;
-      }
-
-    case MBOX_STATE_APPEND_DATE:
-      /* Generate a date for the "From "  separator.  */
-      {
-       mu_envelope_t envelope = NULL;
-       const char *envarr[5];
-       
-       mu_message_get_envelope (msg, &envelope);
-       status = mu_envelope_aget_date (envelope, &mud->date);
-       switch (status) {
-       case 0:
-         break;
-         
-       case EAGAIN:
-         return status;
-
-       case MU_ERR_NOENT: /* Envelope headers not found: try to guess */
-         free (mud->date);
-          mud->date = NULL;
-         status = restore_date (msg, mud);
-         if (status == 0)
-           break;
-         
-       default:
-         free (mud->sender);
-         free (mud->date);
-         mud->date = mud->sender = NULL;
-         mud->state = MBOX_NO_STATE;
-         return status;
-       }
+    case 0:
+      break;
 
-       /* Nuke trailing newline.  */
-       s = strchr (mud->date, nl);
-       if (s)
-         *s = '\0';
-
-       /* Write the separator to the mailbox.  */
-       envarr[0] = "From ";
-       envarr[1] = mud->sender;
-       envarr[2] = " ";
-       envarr[3] = mud->date;
-       envarr[4] = "\n";
-       
-       status = write_array (mailbox->stream, psize, 5, envarr);
-       if (status)
-         break;
+    case MU_ERR_NOENT:
+      status = restore_sender (msg, &sender);
+      if (status == 0)
+       break;
+    default:
+      return status;
+    }
 
-       free (mud->sender);
-       free (mud->date);
-       mud->sender = mud->date = NULL;
-       /* If we are not expunging get the message in one block via the stream
-          message instead of the header/body.  This is good for POP where
-          there is no separation between header and body(RETR).  */
-       if (! is_expunging)
-         {
-           mud->state = MBOX_STATE_APPEND_MESSAGE;
-           break;
-         }
-       mud->state = MBOX_STATE_APPEND_HEADER;
-      }
-
-    case MBOX_STATE_APPEND_HEADER:
-      /* Append the Header.  */
-      {
-       char buffer[1024];
-       size_t nread = 0;
-       mu_stream_t is = NULL;
-       mu_header_t header = NULL;
-       mu_message_get_header (msg, &header);
-       mu_header_get_stream (header, &is);
-       do
-         {
-           status = mu_stream_readline (is, buffer, sizeof (buffer), mud->off,
-                                        &nread);
-           if (status != 0)
-             {
-               if (status != EAGAIN)
-                 {
-                   mud->state = MBOX_NO_STATE;
-                   mud->off = 0;
-                 }
-               mu_stream_truncate (mailbox->stream, orig_size);
-               return status;
-             }
-           mud->off += nread;
-           if (*buffer == '\n')
-             break;
-
-           /* We do not copy the Status since it is rewritten by the
-              attribute code below. Ditto for X-UID and X-IMAPBase.
-              FIXME:
-              - We have a problem here the header may not fit the buffer.
-              - Should  we skip the IMAP "X-Status"? */
-           if ((mu_c_strncasecmp (buffer, "Status", 6) == 0)
-               || (mu_c_strncasecmp (buffer, "X-IMAPbase", 10) == 0)
-               /* FIXME: isn't the length of "X-UID" 5, not 4? And
-                this will match X-UID and X-UIDL, is this intended? */
-               || (mu_c_strncasecmp (buffer, "X-UID", 4) == 0
-                   && (buffer[5] == ':' || buffer[5] == ' '
-                       || buffer[5] == '\t')))
-             continue;
-
-           status = mu_stream_write (mailbox->stream, buffer, nread,
-                                     *psize, &n);
-           if (status)
-             break;
-           *psize += n;
-         }
-       while (nread > 0);
-       mud->off = 0;
-
-       /* Rewrite the X-IMAPbase marker. */
-       if (first && is_expunging)
-         {
-           n = sprintf (buffer, "X-IMAPbase: %lu %u\n",
-                        (unsigned long) mud->uidvalidity,
-                        (unsigned) mud->uidnext);
-           status = mu_stream_write (mailbox->stream, buffer, n, *psize, &n);
-           if (status)
-             break;
-           *psize += n;
-         }
-       mud->state = MBOX_STATE_APPEND_ATTRIBUTE;
-      }
-
-      case MBOX_STATE_APPEND_ATTRIBUTE:
-      /* Put the new attributes.  */
-      {
-#define STATUS_PREFIX_LEN (sizeof(MU_HEADER_STATUS) - 1 + 2)
-       char abuf[STATUS_PREFIX_LEN + MU_STATUS_BUF_SIZE + 1];
-       size_t na = 0;
-       mu_attribute_t attr = NULL;
-
-       strcpy(abuf, MU_HEADER_STATUS);
-       strcat(abuf, ": ");
-       mu_message_get_attribute (msg, &attr);
-       mu_attribute_to_string (attr, abuf + STATUS_PREFIX_LEN, 
-                               sizeof(abuf) - STATUS_PREFIX_LEN - 1, &na);
-       strcat (abuf, "\n");
-       na = strlen (abuf);
-       mu_stream_write (mailbox->stream, abuf, na, *psize, &n);
-       if (status != 0)
-         break;
-       *psize += n;
-
-       mud->state = MBOX_STATE_APPEND_UID;
-      }
-
-    case MBOX_STATE_APPEND_UID:
-      /* The new X-UID. */
-      {
-       char suid[64];
-       size_t uid = 0;
-       if (is_expunging)
-         {
-           status = mu_message_get_uid (msg, &uid);
-           if (status == EAGAIN)
-             return status;
-         }
-       else
-         uid = mud->uidnext++;
-
-       if (status == 0 || uid != 0)
-         {
-           n = sprintf (suid, "X-UID: %u\n", (unsigned) uid);
-           /* Put the UID.  */
-           status = mu_stream_write (mailbox->stream, suid, n, *psize, &n);
-           if (status)
-             break;
-           *psize += n;
-         }
-
-       /* New line separator of the Header.  */
-       status = mu_stream_write (mailbox->stream, &nl , 1, *psize, &n);
-       if (status)
-         break;
-       *psize += n;
-       mud->state = MBOX_STATE_APPEND_BODY;
-      }
-
-    case MBOX_STATE_APPEND_BODY:
-      /* Append the Body.  */
-      {
-       char buffer[1024];
-       size_t nread = 0;
-       mu_stream_t is = NULL;
-       mu_body_t body = NULL;
-       mu_message_get_body (msg, &body);
-       mu_body_get_stream (body, &is);
-       do
-         {
-           status = mu_stream_read (is, buffer, sizeof (buffer), mud->off,
-                                    &nread);
-           if (status != 0)
-             {
-               if (status != EAGAIN)
-                 {
-                   mud->state = MBOX_NO_STATE;
-                   mud->off = 0;
-                 }
-               return status;
-             }
-           mud->off += nread;
-           status = mu_stream_write (mailbox->stream, buffer, nread,
-                                     *psize, &n);
-           if (status)
-             break;
-           *psize += n;
-         }
-       while (nread > 0);
-       mud->off = 0;
-       n = 0;
-       status = mu_stream_write (mailbox->stream, &nl, 1, *psize, &n);
-       if (status)
-         break;
-       *psize += n;
-      }
+  status = mu_envelope_aget_date (env, &datestr);
+  switch (status)
+    {
+    case 0:
+      break;
 
+    case MU_ERR_NOENT:
+      status = restore_date (msg, &datestr);
+      if (status == 0)
+       break;
+      free (sender);
     default:
-      break;
+      return status;
     }
 
-  /* If not expunging we are taking the stream message.  */
-  if (!is_expunging)
-    {
-      switch (mud->state)
-        {
-       case MBOX_STATE_APPEND_MESSAGE:
-         {
-           /* Append the Message.  */
-           char buffer[1024];
-           size_t nread = 0;
-           mu_stream_t is = NULL;
-           mu_message_get_stream (msg, &is);
-           do
-             {
-               status = mu_stream_read (is, buffer, sizeof (buffer), mud->off,
-                                     &nread);
-               if (status != 0)
-                 {
-                   if (status != EAGAIN)
-                     {
-                       mud->state = MBOX_NO_STATE;
-                       mud->off = 0;
-                     }
-                   mu_stream_truncate (mailbox->stream, orig_size);
-                   return status;
-                 }
-               status = mu_stream_write (mailbox->stream, buffer, nread,
-                                         *psize, &n);
-               if (status)
-                 break;
-               mud->off += nread;
-               *psize += n;
-             }
-           while (nread > 0);
-           if (status)
-             break;
-                   status = mu_stream_write (mailbox->stream, &nl, 1, *psize, 
&n);
-           if (status == 0)
-             *psize += n;
-         }
-
-       default:
-         break;
-       }
-    } /* is_expunging */
-  mud->state = MBOX_NO_STATE;
-  if (status)
-    mu_stream_truncate (mailbox->stream, orig_size);
-  else
-    mu_stream_flush (mailbox->stream);
+  mu_rtrim_cset (datestr, "\r\n");
+
+  envarr[0] = "From ";
+  envarr[1] = sender;
+  envarr[2] = " ";
+  envarr[3] = datestr;
+  envarr[4] = "\n";
+
+  status = write_array (out, 5, envarr);
+  free (sender);
+  free (datestr);
   return status;
 }
 
+/* Headers */
 static int
-mbox_get_size (mu_mailbox_t mailbox, mu_off_t *psize)
+msg_header_to_stream (mu_stream_t ostr, mu_message_t msg)
 {
-  mu_off_t size;
   int status;
+  mu_header_t header;
+  mu_iterator_t itr;
+  const char *harr[4];
 
-  /* Maybe was not open yet ??  */
-  status  = mu_stream_size (mailbox->stream, &size);
-  if (status != 0)
+  status = mu_message_get_header (msg, &header);
+  if (status)
     return status;
-  if (psize)
-    *psize = size;
-  return 0;
+  status = mu_header_get_iterator (header, &itr);
+  if (status)
+    return status;
+
+  harr[1] = ": ";
+  harr[3] = "\n";
+  for (mu_iterator_first (itr);
+       status == 0 && !mu_iterator_is_done (itr); mu_iterator_next (itr))
+    {
+      mu_iterator_current_kv (itr, (const void **)&harr[0], (void **)&harr[2]);
+      if (mu_c_strcasecmp (harr[0], MU_HEADER_STATUS) == 0
+         || mu_c_strcasecmp (harr[0], MU_HEADER_X_IMAPBASE) == 0
+         || mu_c_strcasecmp (harr[0], MU_HEADER_X_UID) == 0)
+       continue;
+      status = write_array (ostr, 4, harr);
+    }
+  mu_iterator_destroy (&itr);
+  return status;
+  
 }
 
+/* Attributes */
 static int
-mbox_messages_count (mu_mailbox_t mailbox, size_t *pcount)
+msg_attr_to_stream (mu_stream_t ostr, mu_message_t msg)
 {
-  mbox_data_t mud = mailbox->data;
-
-  if (mud == NULL)
-    return EINVAL;
+  mu_attribute_t attr;
+  char abuf[MU_STATUS_BUF_SIZE + 1];
+  const char *harr[4];
+  int status;
+  
+  status = mu_message_get_attribute (msg, &attr);
+  if (status)
+    return status;
+  status = mu_attribute_to_string (attr, abuf, sizeof (abuf), NULL);
+  if (status)
+    return status;
 
-  if (! mbox_is_updated (mailbox))
-    return mbox_scan0 (mailbox,  mud->messages_count, pcount, 0);
+  harr[0] = MU_HEADER_STATUS;
+  harr[1] = ": ";
+  harr[2] = abuf;
+  harr[3] = "\n";
+  return write_array (ostr, 4, harr);
+}
 
-  if (pcount)
-    *pcount = mud->messages_count;
+/* X-UID header */
 
+static int
+uid_to_stream (mu_stream_t ostr, mu_message_t msg, mbox_data_t mud, int flags)
+{
+  size_t uid = 0;
+  
+  if (flags & MBOX_EXPUNGE)
+    {
+      int status = mu_message_get_uid (msg, &uid);
+      if (status)
+       return status;
+    }
+  else
+    uid = mud->uidnext++;
+  
+  mu_stream_printf (ostr, "%s: %u\n", MU_HEADER_X_UID, (unsigned) uid);
+  if (mu_stream_err (ostr))
+    return mu_stream_last_error (ostr);
   return 0;
 }
 
-/* A "recent" message is the one not marked with MU_ATTRIBUTE_SEEN
-   ('O' in the Status header), i.e. a message that is first seen
-   by the current session (see attributes.h) */
+/* Append MSG to stream OSTR in its current position */
 static int
-mbox_messages_recent (mu_mailbox_t mailbox, size_t *pcount)
+append_message_to_stream (mu_stream_t ostr, mu_message_t msg,
+                         mbox_data_t mud, int flags)
 {
-  mbox_data_t mud = mailbox->data;
-  mbox_message_t mum;
-  size_t j, recent;
+  int status;
+  mu_stream_t istr;
+  
+  status = msg_envelope_to_stream (ostr, msg);
+  if (status)
+    return status;
 
-  /* If we did not start a scanning yet do it now.  */
-  if (mud->messages_count == 0)
+  if (flags & MBOX_EXPUNGE)
     {
-      int status = mbox_scan0 (mailbox, 1, NULL, 0);
-      if (status != 0)
+      mu_body_t body;
+
+      status = msg_header_to_stream (ostr, msg);
+      if (status)
+       return status;
+
+      if (flags & MBOX_FIRSTMSG)
+       {
+         /* FIXME: Perhaps printf should return error code,
+            like the rest of stream functions. */
+         mu_stream_printf (ostr, "%s: %lu %u\n",
+                           MU_HEADER_X_IMAPBASE,
+                           (unsigned long) mud->uidvalidity,
+                           (unsigned) mud->uidnext);
+         if (mu_stream_err (ostr))
+           return mu_stream_last_error (ostr);
+       }
+
+      status = msg_attr_to_stream (ostr, msg);
+      if (status)
+       return status;
+
+      status = uid_to_stream (ostr, msg, mud, flags);
+      if (status)
+       return status;
+
+      status = mu_stream_write (ostr, "\n", 1, NULL);
+      if (status)
+       return status;
+      
+      status = mu_message_get_body (msg, &body);
+      if (status)
+       return status;
+      status = mu_body_get_streamref (body, &istr);
+      if (status)
        return status;
     }
-  for (recent = j = 0; j < mud->messages_count; j++)
+  else
     {
-      mum = mud->umessages[j];
-      if (mum && MU_ATTRIBUTE_IS_UNSEEN(mum->attr_flags))
-       recent++;
+      status = mu_message_get_streamref (msg, &istr);
+      if (status)
+       return status;
     }
-  *pcount = recent;
-  return 0;
+  status = mu_stream_copy (ostr, istr, 0, NULL);
+  mu_stream_destroy (&istr);
+  if (status == 0)
+    status = mu_stream_write (ostr, "\n", 1, NULL);
+  return status;
 }
 
-/* An "unseen" message is the one that has not been read yet */
 static int
-mbox_message_unseen (mu_mailbox_t mailbox, size_t *pmsgno)
+mbox_append_message (mu_mailbox_t mailbox, mu_message_t msg)
 {
+  int status = 0;
   mbox_data_t mud = mailbox->data;
-  mbox_message_t mum;
-  size_t j, unseen;
+  mu_off_t size;
+  
+  if (msg == NULL || mud == NULL)
+    return EINVAL;
 
-  /* If we did not start a scanning yet do it now.  */
-  if (mud->messages_count == 0)
+  MU_DEBUG1 (mailbox->debug, MU_DEBUG_TRACE1, "mbox_append_message (%s)\n",
+            mud->name);
+
+  if ((status = mu_locker_lock (mailbox->locker)) != 0)
     {
-      int status = mbox_scan0 (mailbox, 1, NULL, 0);
-      if (status != 0)
-       return status;
+      MU_DEBUG1 (mailbox->debug, MU_DEBUG_TRACE1,
+                "mbox_append_message: %s\n", mu_strerror(status));
+      return status;
     }
-  for (unseen = j = 0; j < mud->messages_count; j++)
+
+  status = mu_stream_seek (mailbox->stream, 0, MU_SEEK_END, &size);
+  if (status)
+    return status;
+  status = append_message_to_stream (mailbox->stream, msg, mud, 0);
+  mu_locker_unlock (mailbox->locker);
+
+  if (status)
     {
-      mum = mud->umessages[j];
-      if (mum && MU_ATTRIBUTE_IS_UNREAD(mum->attr_flags))
+      int rc = mu_stream_truncate (mailbox->stream, size);
+      if (rc)
+       mu_error (_("cannot truncate stream after failed append: %s"),
+                 mu_stream_strerror (mailbox->stream, rc));
+      return status;
+    }
+  
+  if (mailbox->observable)
+    {
+      char *buf = NULL;
+      mu_asprintf (&buf, "%lu", (unsigned long) size);
+      mu_observable_notify (mailbox->observable, MU_EVT_MESSAGE_APPEND, buf);
+      free (buf);
+    }
+  
+  return 0;
+}
+
+
+static void
+mbox_reset (mu_mailbox_t mailbox, size_t dirty, int remove_deleted)
+{
+  mbox_data_t mud = mailbox->data;
+  size_t i;
+  size_t dlast;
+
+  mu_monitor_wrlock (mailbox->monitor);
+  for (i = dirty, dlast = mud->messages_count - 1; i <= dlast; i++)
+    {
+      /* Clear all the references */
+      mbox_message_t mum = mud->umessages[i];
+      if (remove_deleted && ATTRIBUTE_IS_DELETED (mum->attr_flags))
        {
-         unseen = j + 1;
-         break;
+         if ((i + 1) <= dlast)
+           {
+             /* Move all the pointers up.  So the message pointer
+                part of mum will be at the right position.  */
+             memmove (mud->umessages + i, mud->umessages + i + 1,
+                      (dlast - i) * sizeof (mum));
+             memset (mum, 0, sizeof (*mum));
+             /* We are not free()ing the useless mum, but instead
+                we put it back in the pool, to be reused.  */
+             mud->umessages[dlast] = mum;
+             dlast--;
+             /* Set mum to the new value after the memmove so it
+                gets cleared to.  */
+             mum = mud->umessages[i];
+           }
+         else
+           memset (mum, 0, sizeof (*mum));
        }
+      mum->envel_from = mum->envel_from_end = 0;
+      mum->body = mum->body_end = 0;
+      mum->header_lines = mum->body_lines = 0;
     }
-  *pmsgno = unseen;
-  return 0;
+  mu_monitor_unlock (mailbox->monitor);
+  /* This resets the messages_count, the last argument 0 means
+     not to send event notification.  */
+  mbox_scan0 (mailbox, dirty, NULL, 0);
 }
 
 static int
-mbox_uidvalidity (mu_mailbox_t mailbox, unsigned long *puidvalidity)
+mbox_expunge_unlocked (mu_mailbox_t mailbox, size_t dirty, int remove_deleted,
+                      mu_stream_t tempstr)
 {
   mbox_data_t mud = mailbox->data;
-  int status = mbox_messages_count (mailbox, NULL);
-  if (status != 0)
-    return status;
-  /* If we did not start a scanning yet do it now.  */
-  if (mud->messages_count == 0)
+  int status;
+  size_t i;
+  size_t save_imapbase = 0;  /* uidvalidity is save in the first message.  */
+  mu_off_t start_off;
+  mu_off_t size;
+
+  /* Set the marker position.  */
+  start_off = mud->umessages[dirty]->envel_from;
+
+  for (i = dirty; i < mud->messages_count; i++)
     {
-      status = mbox_scan0 (mailbox, 1, NULL, 0);
-      if (status != 0)
-       return status;
+      mbox_message_t mum = mud->umessages[i];
+      
+      if (remove_deleted && ATTRIBUTE_IS_DELETED (mum->attr_flags))
+       {
+         mu_message_destroy (&mum->message, mum);
+         /* We save the uidvalidity in the first message, if it is being
+            deleted we need to move the uidvalidity to the first available
+            (non-deleted) message.  */
+         if (i == save_imapbase)
+           {
+             save_imapbase = i + 1;
+             if (save_imapbase < mud->messages_count)
+               mud->umessages[save_imapbase]->attr_flags
+                 |= MU_ATTRIBUTE_MODIFIED;
+           }
+         continue;
+       }
+
+      if ((mum->attr_flags & MU_ATTRIBUTE_MODIFIED) ||
+         (mum->message && mu_message_is_modified (mum->message)))
+       {
+         /* Use relatively expensive append_message_to_stream only if
+            the message is marked dirty.  */
+         
+         int flags = MBOX_EXPUNGE |
+                       ((i == save_imapbase) ? MBOX_FIRSTMSG : 0);
+                                            
+         /* The message was not instantiated, probably the dirty flag was
+            set by mbox_scan(), create one here.  */
+         if (mum->message == 0)
+           {
+             mu_message_t msg;
+             status = mbox_get_message (mailbox, i + 1, &msg);
+             if (status != 0)
+               {
+                 mu_error (_("%s:%d: error expunging: %s"),            
+                           __FILE__, __LINE__, mu_strerror (status));  
+                 return status;
+               }
+           }
+         status = append_message_to_stream (tempstr, mum->message, mud,
+                                            flags);
+         if (status != 0)
+           {
+             mu_error (_("%s:%d: error expunging: %s"),                
+                       __FILE__, __LINE__, mu_strerror (status));      
+             return status;
+           }
+         /* Clear the dirty bits.  */
+         mum->attr_flags &= ~MU_ATTRIBUTE_MODIFIED;
+         mu_message_clear_modified (mum->message);
+       }
+      else
+       {
+         /* Otherwise, copy bits from mailbox->stream as is. */
+         
+         status = mu_stream_seek (mailbox->stream, mum->envel_from,
+                                  MU_SEEK_SET, NULL);
+         if (status)
+           {
+             mu_error (_("%s:%d: seek error: %s"),
+                       __FILE__, __LINE__,
+                       mu_stream_strerror (mailbox->stream, status));
+             return status;
+           }
+         status = mu_stream_copy (tempstr, mailbox->stream,
+                                  mum->body_end - mum->envel_from, NULL);
+         if (status)
+           {
+             mu_error (_("%s:%d: error copying: %s"),
+                       __FILE__, __LINE__,
+                       mu_strerror (status));
+             return status;
+           }
+       }
     }
-  if (puidvalidity)
-    *puidvalidity = mud->uidvalidity;
-  return 0;
+
+  /* Caution: before moving data back to the mailbox see
+     - if we've receive new mails.  Some programs may not respect the lock,
+     - or the lock was held for too long.
+     - The mailbox may not have been properly updated before expunging.  */
+  if (mu_stream_size (mailbox->stream, &size) == 0)
+    {
+      if (size > mud->size)
+       {
+         mu_off_t len = size - mud->size;
+
+         status = mu_stream_seek (mailbox->stream, mud->size, MU_SEEK_SET,
+                                  NULL);
+         if (status)
+           {
+             mu_error (_("%s:%d: seek error: %s"),
+                       __FILE__, __LINE__,
+                       mu_stream_strerror (mailbox->stream, status));
+             return status;
+           }
+  
+         status = mu_stream_copy (tempstr, mailbox->stream, len, NULL);
+         if (status)
+           {
+             mu_error (_("%s:%d: error writing to temporary stream: %s"),
+                       __FILE__, __LINE__,
+                       mu_strerror (status));
+             return status;
+           }
+       }
+      else if (size < mud->size)
+       {
+         /* Corrupted mailbox. */
+         mu_error (_("%s:%d: mailbox shrunk while expunging"),
+                   __FILE__, __LINE__);
+         return MU_ERR_FAILURE; /* FIXME: need an error code for that */
+       }
+    }
+
+  
+  /* Copy data from tempstr back to the mailbox. */
+  status = mu_stream_seek (mailbox->stream, start_off, MU_SEEK_SET, NULL);
+  if (status)
+    {
+      mu_error (_("%s:%d: seek error: %s"),
+               __FILE__, __LINE__,
+               mu_stream_strerror (mailbox->stream, status));
+      return status;
+    }
+  
+  status = mu_stream_size (tempstr, &size);
+  if (status)
+    {
+      mu_error (_("%s:%d: cannot get size of the temp stream: %s"),
+               __FILE__, __LINE__,
+               mu_stream_strerror (tempstr, status));
+      return status;
+    }
+  
+  status = mu_stream_seek (tempstr, 0, MU_SEEK_SET, NULL);
+  if (status)
+    {
+      mu_error (_("%s:%d: seek error: %s"),
+               __FILE__, __LINE__,
+               mu_stream_strerror (mailbox->stream, status));
+      return status;
+    }
+
+  status = mu_stream_copy (mailbox->stream, tempstr, size, NULL);
+  if (status)
+    {
+      mu_error (_("%s:%d: copying from the temporary stream: %s"),
+               __FILE__, __LINE__,
+               mu_strerror (status));
+      return status;
+    }
+  
+  status = mu_stream_truncate (mailbox->stream, start_off + size);
+  if (status)
+    {
+      mu_error (_("%s:%d: error truncating stream: %s"),
+               __FILE__, __LINE__,
+               mu_strerror (status));
+    }
+  return status;
 }
 
 static int
-mbox_uidnext (mu_mailbox_t mailbox, size_t *puidnext)
+mbox_expunge0 (mu_mailbox_t mailbox, int remove_deleted)
 {
   mbox_data_t mud = mailbox->data;
-  int status = mbox_messages_count (mailbox, NULL);
-  if (status != 0)
-    return status;
-  /* If we did not start a scanning yet do it now.  */
+  size_t dirty;
+  int status;
+  mu_stream_t tempstr;
+  
+  if (mud == NULL)
+    return EINVAL;
+
+  MU_DEBUG1 (mailbox->debug, MU_DEBUG_TRACE1,
+            "mbox_expunge (%s)\n", mud->name);
+
+  /* Noop.  */
   if (mud->messages_count == 0)
+    return 0;
+
+  /* Find first dirty (modified) message. */
+  for (dirty = 0; dirty < mud->messages_count; dirty++)
     {
-      status = mbox_scan0 (mailbox, 1, NULL, 0);
-      if (status != 0)
-       return status;
+      mbox_message_t mum = mud->umessages[dirty];
+      /* Message may have been tampered, break here.  */
+      if ((mum->attr_flags & MU_ATTRIBUTE_MODIFIED) ||
+         (mum->attr_flags & MU_ATTRIBUTE_DELETED) ||
+         (mum->message && mu_message_is_modified (mum->message)))
+       break;
     }
-  if (puidnext)
-    *puidnext = mud->uidnext;
-  return 0;
-}
 
+  /* Did something change ?  */
+  if (dirty == mud->messages_count)
+    return 0; /* Nothing changed.  */
+
+  /* Lock the mailbox */
+  if ((status = mu_locker_lock (mailbox->locker)) != 0)
+    return status;
+
+  status = mu_temp_file_stream_create (&tempstr, NULL);
+  if (status == 0)
+    {
+      status = mu_stream_open (tempstr);
+      if (status == 0)
+       {
+         sigset_t signalset;
 #ifdef WITH_PTHREAD
-void
-mbox_cleanup (void *arg)
-{
-  mu_mailbox_t mailbox = arg;
-  mu_monitor_unlock (mailbox->monitor);
+         int state;
+         pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &state);
+#endif
+         sigemptyset (&signalset);
+         sigaddset (&signalset, SIGTERM);
+         sigaddset (&signalset, SIGHUP);
+         sigaddset (&signalset, SIGTSTP);
+         sigaddset (&signalset, SIGINT);
+         sigaddset (&signalset, SIGWINCH);
+         sigprocmask (SIG_BLOCK, &signalset, 0);
+         
+         status = mbox_expunge_unlocked (mailbox, dirty, remove_deleted,
+                                         tempstr);
+
+#ifdef WITH_PTHREAD
+         pthread_setcancelstate (state, &state);
+#endif
+         sigprocmask (SIG_UNBLOCK, &signalset, 0);
+      
+         mu_stream_destroy (&tempstr);
+
+         if (status == 0)
+           mbox_reset (mailbox, dirty, remove_deleted);
+       }
+    }
   mu_locker_unlock (mailbox->locker);
+  return status;
 }
-#endif
+
+
+/* Allocate the mbox_data_t struct(concrete mailbox), but don't do any
+   parsing on the name or even test for existence.  However we do strip any
+   leading "mbox:" part of the name, this is suppose to be the
+   protocol/scheme name.  */
+int
+_mailbox_mbox_init (mu_mailbox_t mailbox)
+{
+  int status;
+  mbox_data_t mud;
+
+  if (mailbox == NULL)
+    return EINVAL;
+
+  /* Allocate specific mbox data.  */
+  mud = mailbox->data = calloc (1, sizeof (*mud));
+  if (mailbox->data == NULL)
+    return ENOMEM;
+
+  /* Back pointer.  */
+  mud->mailbox = mailbox;
+
+  /* Copy the name:
+     We do not do any further interpretation after the scheme "mbox:"
+     Because for example on distributed system like QnX4 a file name is
+     //390/etc/passwd.  So the best approach is to let the OS handle it
+     for example if we receive: "mbox:///var/mail/alain" the mailbox name
+     will be "///var/mail/alain", we let open() do the right thing.
+     So it will let things like this "mbox://390/var/mail/alain" where
+     the "//" _is_ part of the filename, pass correctely.  */
+  status = mu_url_aget_path (mailbox->url, &mud->name);
+  if (status)
+    {
+      free (mud);
+      mailbox->data = NULL;
+      return status;
+    }
+
+  /* Overloading the defaults.  */
+  mailbox->_destroy = mbox_destroy;
+
+  mailbox->_open = mbox_open;
+  mailbox->_close = mbox_close;
+
+  /* Overloading of the entire mailbox object methods.  */
+  mailbox->_get_message = mbox_get_message;
+  mailbox->_append_message = mbox_append_message;
+  mailbox->_messages_count = mbox_messages_count;
+  mailbox->_messages_recent = mbox_messages_recent;
+  mailbox->_message_unseen = mbox_message_unseen;
+  mailbox->_expunge = mbox_expunge;
+  mailbox->_sync = mbox_sync;
+  mailbox->_uidvalidity = mbox_uidvalidity;
+  mailbox->_uidnext = mbox_uidnext;
+  mailbox->_quick_get_message = mbox_quick_get_message;
+
+  mailbox->_scan = mbox_scan;
+  mailbox->_is_updated = mbox_is_updated;
+
+  mailbox->_get_size = mbox_get_size;
+
+  /* Set our properties.  */
+  {
+    mu_property_t property = NULL;
+    mu_mailbox_get_property (mailbox, &property);
+    mu_property_set_value (property, "TYPE", "MBOX", 1);
+  }
+
+  MU_DEBUG1 (mailbox->debug, MU_DEBUG_TRACE1, "mbox_init (%s)\n", mud->name);
+  return 0; /* okdoke */
+}
+
diff --git a/libproto/mbox/mbox0.h b/libproto/mbox/mbox0.h
index e9304b6..85e8408 100644
--- a/libproto/mbox/mbox0.h
+++ b/libproto/mbox/mbox0.h
@@ -42,8 +42,8 @@
 # include <strings.h>
 #endif
 
-#include <mailbox0.h>
-#include <registrar0.h>
+#include <mailutils/sys/mailbox.h>
+#include <mailutils/sys/registrar.h>
 
 #include <mailutils/address.h>
 #include <mailutils/attribute.h>
@@ -65,28 +65,24 @@
 struct _mbox_message;
 struct _mbox_data;
 
-typedef struct _mbox_data* mbox_data_t;
-typedef struct _mbox_message* mbox_message_t;
+typedef struct _mbox_data *mbox_data_t;
+typedef struct _mbox_message *mbox_message_t;
 
-/* Keep the file positions of where the headers and bodies start and end.
-   attr_flags is the "Status:" message.  */
 struct _mbox_message
 {
   /* Offset of the messages in the mailbox.  */
-  off_t header_from;
-  off_t header_from_end;
-  off_t body;
-  off_t body_end;
-
-  size_t uid; /* IMAP uid.  */
-
-  int attr_flags; /* The attr_flags contains the "Status:" attribute  */
-
-  size_t header_lines;
-  size_t body_lines;
-
-  mu_message_t message; /* A message attach to it.  */
-  mbox_data_t mud; /* Back pointer.  */
+  mu_off_t envel_from;         /* Start of envelope (^From ) */
+  mu_off_t envel_from_end;     /* End of envelope (terminating \n) */
+  mu_off_t body;               /* Start of body */
+  mu_off_t body_end;           /* End of body */
+
+  size_t header_lines;         /* Number of lines in header */
+  size_t body_lines;           /* Number of lines in message body */
+  size_t uid;                  /* IMAP-style uid.  */
+  int attr_flags;              /* Packed "Status:" attribute flags */
+
+  mu_message_t message;        /* A message attached to it.  */
+  mbox_data_t mud;             /* Reference to the containing UNIX mailbox */
 };
 
 /* The umessages is an array of pointers that contains umessages_count of
@@ -96,25 +92,14 @@ struct _mbox_message
    messages_count is the count number of messages parsed so far.  */
 struct _mbox_data
 {
-  mbox_message_t *umessages; /* Array.  */
-  size_t umessages_count; /* How big is the umessages[].  */
-  size_t messages_count; /* How many valid entry in umessages[].  */
-  off_t size; /* Size of the mailbox.  */
+  mbox_message_t *umessages;   /* Array.  */
+  size_t umessages_count;      /* Number of slots in umessages. */
+  size_t messages_count;       /* Number of used slots in umessages. */
+  mu_off_t size;               /* Size of the mailbox.  */
   unsigned long uidvalidity;
-  size_t uidnext;
-  char *name;
-
-  /* The variables below are use to hold the state when appending messages.  */
-  enum mbox_state
-  {
-    MBOX_NO_STATE = 0,
-    MBOX_STATE_APPEND_SENDER, MBOX_STATE_APPEND_DATE, MBOX_STATE_APPEND_HEADER,
-    MBOX_STATE_APPEND_ATTRIBUTE, MBOX_STATE_APPEND_UID, MBOX_STATE_APPEND_BODY,
-    MBOX_STATE_APPEND_MESSAGE
-  } state ;
-  char *sender;
-  char *date;
-  off_t off;
+  size_t uidnext;              /* Expected next UID value */
+  char *name;                  /* Disk file name */
+
   mu_mailbox_t mailbox; /* Back pointer. */
 };
 
diff --git a/libproto/mbox/mboxscan.c b/libproto/mbox/mboxscan.c
index 44eacfe..db8a099 100644
--- a/libproto/mbox/mboxscan.c
+++ b/libproto/mbox/mboxscan.c
@@ -43,7 +43,7 @@
    ************************************                                       
    This is a classic case of premature optimisation being the root of all
    Evil(Donald E. Knuth).  But I'm under "pressure" ;-) to come with
-   something "faster".  I think it's wastefull * to spend time to gain a few
+   something "faster".  I think it's wastefull to spend time to gain a few
    seconds on 30Megs mailboxes ... but then again ... in computer time, 60
    seconds, is eternity.  If they use the event notification stuff to get
    some headers/messages early ... it's like pissing in the wind(sorry don't
@@ -302,16 +302,20 @@ mbox_scan_internal (mu_mailbox_t mailbox, mbox_message_t 
mum,
   newline = 1;
   errno = lines = inheader = inbody = 0;
 
-  stream = mailbox->stream;
-  while ((status = mu_stream_readline (stream, buf, sizeof (buf),
-                                      total, &n)) == 0 && n != 0)
+  status = mu_streamref_create (&stream, mailbox->stream);
+  if (status)
+    return status;
+  status = mu_stream_seek (stream, total, MU_SEEK_SET, NULL);
+  if (status)
+    return status;
+  while ((status = mu_stream_readline (stream, buf, sizeof (buf), &n)) == 0
+        && n != 0)
     {
       int nl;
       total += n;
 
       nl = (*buf == '\n') ? 1 : 0;
       VALID (buf, temp, isfrom, zn);
-      isfrom = (isfrom) ? 1 : 0;
 
       if ((flags & MBOX_SCAN_ONEMSG) && mum == NULL)
        {
@@ -321,8 +325,8 @@ mbox_scan_internal (mu_mailbox_t mailbox, mbox_message_t 
mum,
        }
       
       /* Which part of the message are we in ?  */
-      inheader = isfrom | ((!nl) & inheader);
-      inbody = (!isfrom) & (!inheader);
+      inheader = isfrom || ((!nl) & inheader);
+      inbody = !isfrom & !inheader;
 
       if (buf[n - 1] == '\n')
        lines++;
@@ -355,11 +359,10 @@ mbox_scan_internal (mu_mailbox_t mailbox, mbox_message_t 
mum,
                }
              /* Allocate_msgs will initialize mum.  */
              ALLOCATE_MSGS (mailbox, mud);
-             mud->messages_count++;
-             mum = mud->umessages[mud->messages_count - 1];
+             mum = mud->umessages[mud->messages_count++];
              mum->mud = mud;
-              mum->header_from = total - n;
-              mum->header_from_end = total;
+              mum->envel_from = total - n;
+              mum->envel_from_end = total;
              mum->body_end = mum->body = 0;
              mum->attr_flags = 0;
              lines = 0;
@@ -397,7 +400,8 @@ mbox_scan_internal (mu_mailbox_t mailbox, mbox_message_t 
mum,
          DISPATCH_PROGRESS (mailbox, mud);
 
     } /* while */
-
+  mu_stream_destroy (&stream);
+  
   if (mum)
     {
       mum->body_end = total - newline;
@@ -462,7 +466,7 @@ mbox_scan0 (mu_mailbox_t mailbox, size_t msgno, size_t 
*pcount, int do_notif)
     {
       mum = mud->umessages[msgno - 1];
       if (mum)
-       total = mum->header_from;
+       total = mum->envel_from;
       mud->messages_count = msgno - 1;
     }
   else
@@ -527,7 +531,7 @@ mbox_scan1 (mu_mailbox_t mailbox, mu_off_t offset, int 
do_notif)
       return status;
     }
 
-  status = mu_stream_seek (mailbox->stream, offset, SEEK_SET);
+  status = mu_stream_seek (mailbox->stream, offset, SEEK_SET, NULL);
   if (status)
     {
       mu_monitor_unlock (mailbox->monitor);
diff --git a/libproto/mh/Makefile.am b/libproto/mh/Makefile.am
index 7eadc92..a5be198 100644
--- a/libproto/mh/Makefile.am
+++ b/libproto/mh/Makefile.am
@@ -18,7 +18,7 @@
 ##   Foundation, Inc.  51 Franklin Street, Fifth Floor, Boston, MA
 ##   02110-1301 USA
 
-INCLUDES = @MU_LIB_COMMON_INCLUDES@ -I${top_srcdir}/libproto/include 
+INCLUDES = @MU_LIB_COMMON_INCLUDES@
 
 lib_LTLIBRARIES = libmu_mh.la
 libmu_mh_la_LDFLAGS=-version-info @VI_CURRENT@:@VI_REVISION@:@VI_AGE@
diff --git a/libproto/mh/folder.c b/libproto/mh/folder.c
index 80251b2..1b2c033 100644
--- a/libproto/mh/folder.c
+++ b/libproto/mh/folder.c
@@ -31,10 +31,10 @@
 #include <unistd.h>
 #include <dirent.h>
 
-#include <url0.h>
-#include <folder0.h>
-#include <registrar0.h>
-#include <amd.h>
+#include <mailutils/sys/url.h>
+#include <mailutils/sys/folder.h>
+#include <mailutils/sys/registrar.h>
+#include <mailutils/sys/amd.h>
 #include <mailutils/mutil.h>
 #include <mailutils/cctype.h>
 
@@ -155,6 +155,6 @@ mu_record_t mu_mh_record = &_mh_record;
 
 #else
 #include <stdio.h>
-#include <registrar0.h>
+#include <mailutils/sys/registrar.h>
 mu_record_t mu_mh_record = NULL;
 #endif
diff --git a/libproto/mh/mbox.c b/libproto/mh/mbox.c
index da7da4d..b39ce6c 100644
--- a/libproto/mh/mbox.c
+++ b/libproto/mh/mbox.c
@@ -64,9 +64,9 @@
 #include <mailutils/observer.h>
 #include <mailutils/io.h>
 #include <mailutils/cctype.h>
-#include <mailbox0.h>
-#include <registrar0.h>
-#include <amd.h>
+#include <mailutils/sys/mailbox.h>
+#include <mailutils/sys/registrar.h>
+#include <mailutils/sys/amd.h>
 
 struct _mh_message
 {
diff --git a/libproto/nntp/Makefile.am b/libproto/nntp/Makefile.am
index 6f1c2fa..aecc0c7 100644
--- a/libproto/nntp/Makefile.am
+++ b/libproto/nntp/Makefile.am
@@ -18,7 +18,7 @@
 ##   Foundation, Inc.  51 Franklin Street, Fifth Floor, Boston, MA
 ##   02110-1301 USA
 
-INCLUDES = @MU_LIB_COMMON_INCLUDES@ -I${top_srcdir}/libproto/include 
+INCLUDES = @MU_LIB_COMMON_INCLUDES@
 
 lib_LTLIBRARIES = libmu_nntp.la
 libmu_nntp_la_LDFLAGS=-version-info @VI_CURRENT@:@VI_REVISION@:@VI_AGE@
diff --git a/libproto/nntp/folder.c b/libproto/nntp/folder.c
index c6378c6..0e3b43d 100644
--- a/libproto/nntp/folder.c
+++ b/libproto/nntp/folder.c
@@ -36,8 +36,8 @@
 #include <mailutils/registrar.h>
 #include <mailutils/url.h>
 
-#include <folder0.h>
-#include "nntp0.h"
+#include <mailutils/sys/folder.h>
+#include "mailutils/sys/nntp.h"
 
 /* We export url parsing and the initialisation of
    the mailbox, via the register entry/record.  */
@@ -194,6 +194,6 @@ nntp_folder_list (mu_folder_t folder, const char *ref, void 
*pat, int flags,
 }
 #else
 #include <stdio.h>
-#include <registrar0.h>
+#include <mailutils/sys/registrar.h>
 mu_record_t mu_nntp_record = NULL;
 #endif
diff --git a/libproto/nntp/mbox.c b/libproto/nntp/mbox.c
index 3e58ada..2d09be2 100644
--- a/libproto/nntp/mbox.c
+++ b/libproto/nntp/mbox.c
@@ -51,9 +51,9 @@
 #include <mailutils/url.h>
 #include <mailutils/nntp.h>
 
-#include <folder0.h>
-#include <mailbox0.h>
-#include "nntp0.h"
+#include <mailutils/sys/folder.h>
+#include <mailutils/sys/mailbox.h>
+#include "mailutils/sys/nntp.h"
 
 
 /*  Functions/Methods that implements the mu_mailbox_t API.  */
diff --git a/libproto/nntp/nntp_article.c b/libproto/nntp/nntp_article.c
index 2987c10..9c3c58a 100644
--- a/libproto/nntp/nntp_article.c
+++ b/libproto/nntp/nntp_article.c
@@ -21,6 +21,7 @@
 # include <config.h>
 #endif
 
+#include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 #include <errno.h>
diff --git a/libproto/nntp/nntp_carrier.c b/libproto/nntp/nntp_carrier.c
index bfb8b67..1209a67 100644
--- a/libproto/nntp/nntp_carrier.c
+++ b/libproto/nntp/nntp_carrier.c
@@ -36,7 +36,7 @@ mu_nntp_set_carrier (mu_nntp_t nntp, mu_stream_t carrier)
     {
       /* Close any old carrier.  */
       mu_nntp_disconnect (nntp);
-      mu_stream_destroy (&nntp->carrier, nntp);
+      mu_stream_destroy (&nntp->carrier);
     }
   nntp->carrier = carrier;
   return 0;
diff --git a/libproto/nntp/nntp_destroy.c b/libproto/nntp/nntp_destroy.c
index c2eb897..3725bec 100644
--- a/libproto/nntp/nntp_destroy.c
+++ b/libproto/nntp/nntp_destroy.c
@@ -41,7 +41,7 @@ mu_nntp_destroy (mu_nntp_t *pnntp)
 
       /* Release the carrier.  */
       if (nntp->carrier)
-       mu_stream_destroy (&nntp->carrier, nntp);
+       mu_stream_destroy (&nntp->carrier);
 
       /* Any posting residue.  */
       if (nntp->post.buf)
diff --git a/libproto/nntp/nntp_ihave.c b/libproto/nntp/nntp_ihave.c
index 1214784..a166754 100644
--- a/libproto/nntp/nntp_ihave.c
+++ b/libproto/nntp/nntp_ihave.c
@@ -70,9 +70,9 @@ mu_nntp_ihave (mu_nntp_t nntp, const char *mid, mu_stream_t 
stream)
 
     ihave_loop:
     case MU_NNTP_IHAVE_0:
-      status = mu_stream_readline (stream, nntp->post.buf, nntp->post.len, 
nntp->post.offset, &(nntp->post.nread));
+      status = mu_stream_readline (stream, nntp->post.buf, nntp->post.len,
+                                  &nntp->post.nread);
       MU_NNTP_CHECK_EAGAIN (nntp, status);
-      nntp->post.offset += nntp->post.nread;
       if  (nntp->post.nread > 0)
        {
          if (nntp->post.buf[nntp->post.nread - 1] == '\n')
diff --git a/libproto/nntp/nntp_post.c b/libproto/nntp/nntp_post.c
index 3849f3e..22eb37e 100644
--- a/libproto/nntp/nntp_post.c
+++ b/libproto/nntp/nntp_post.c
@@ -70,7 +70,8 @@ mu_nntp_post (mu_nntp_t nntp, mu_stream_t stream)
 
     post_loop:
     case MU_NNTP_POST_0:
-      status = mu_stream_readline (stream, nntp->post.buf, nntp->post.len, 
nntp->post.offset, &(nntp->post.nread));
+      status = mu_stream_readline (stream, nntp->post.buf, nntp->post.len,
+                                  &nntp->post.nread);
       MU_NNTP_CHECK_EAGAIN (nntp, status);
       nntp->post.offset += nntp->post.nread;
       if  (nntp->post.nread > 0)
diff --git a/libproto/nntp/nntp_readline.c b/libproto/nntp/nntp_readline.c
index cac93b0..b369f38 100644
--- a/libproto/nntp/nntp_readline.c
+++ b/libproto/nntp/nntp_readline.c
@@ -73,7 +73,9 @@ mu_nntp_getline (mu_nntp_t nntp)
            return ETIMEDOUT;
        }
 
-      status = mu_stream_sequential_readline (nntp->carrier, nntp->io.buf + 
total, nntp->io.len - total, &n);
+      status = mu_stream_readline (nntp->carrier,
+                                  nntp->io.buf + total,
+                                  nntp->io.len - total, &n);
       if (status != 0)
        return status;
 
diff --git a/libproto/nntp/nntp_sendline.c b/libproto/nntp/nntp_sendline.c
index 86db395..f1e1a10 100644
--- a/libproto/nntp/nntp_sendline.c
+++ b/libproto/nntp/nntp_sendline.c
@@ -55,7 +55,7 @@ mu_nntp_send (mu_nntp_t nntp)
            return ETIMEDOUT;
        }
 
-      status = mu_stream_write (nntp->carrier, nntp->io.buf, len, 0, &n);
+      status = mu_stream_write (nntp->carrier, nntp->io.buf, len, &n);
       if (n)
        {
          /* Consume what we sent.  */
diff --git a/libproto/nntp/nntp_stream.c b/libproto/nntp/nntp_stream.c
index 9a6a9c7..f2f50ac 100644
--- a/libproto/nntp/nntp_stream.c
+++ b/libproto/nntp/nntp_stream.c
@@ -131,7 +131,7 @@ mu_nntp_stream_create (mu_nntp_t nntp, mu_stream_t *pstream)
   nntp_stream->nntp = nntp;
   nntp_stream->done = 0;
 
-  status = mu_stream_create (pstream, MU_STREAM_READ | MU_STREAM_NO_CLOSE | 
MU_STREAM_NO_CHECK, nntp_stream);
+  status = mu_stream_create (pstream, MU_STREAM_READ, nntp_stream);
   if (status != 0)
     {
       free (nntp_stream);
diff --git a/libproto/nntp/url.c b/libproto/nntp/url.c
index 73173dd..73a66eb 100644
--- a/libproto/nntp/url.c
+++ b/libproto/nntp/url.c
@@ -32,7 +32,7 @@
 
 #include <mailutils/nntp.h>
 
-#include <url0.h>
+#include <mailutils/sys/url.h>
 
 static void url_nntp_destroy (mu_url_t url);
 
diff --git a/libproto/pop/Makefile.am b/libproto/pop/Makefile.am
index 3a3ad8b..5865e4e 100644
--- a/libproto/pop/Makefile.am
+++ b/libproto/pop/Makefile.am
@@ -18,32 +18,35 @@
 ##   Foundation, Inc.  51 Franklin Street, Fifth Floor, Boston, MA
 ##   02110-1301 USA
 
-INCLUDES = @MU_LIB_COMMON_INCLUDES@ -I${top_srcdir}/libproto/include 
+INCLUDES = @MU_LIB_COMMON_INCLUDES@
 
 lib_LTLIBRARIES = libmu_pop.la
 libmu_pop_la_LDFLAGS=-version-info @VI_CURRENT@:@VI_REVISION@:@VI_AGE@
 libmu_pop_la_LIBADD = ${MU_LIB_AUTH} ${MU_LIB_MAILUTILS} @INTLLIBS@
 
 libmu_pop_la_SOURCES = \
+ mbox.c \
  folder.c\
- mbox.c\
- url.c \
+ url.c\
  \
  pop3_apop.c \
  pop3_capa.c \
+ pop3_capatst.c \
  pop3_carrier.c \
  pop3_connect.c \
  pop3_create.c \
- pop3_debug.c \
  pop3_dele.c \
  pop3_destroy.c \
  pop3_disconnect.c \
  pop3_iterator.c \
  pop3_lista.c \
+ pop3_listas.c \
  pop3_list.c \
+ pop3_list_cmd.c \
  pop3_noop.c \
  pop3_pass.c \
  pop3_quit.c \
+ pop3_rdlist.c \
  pop3_readline.c \
  pop3_response.c \
  pop3_retr.c \
@@ -54,7 +57,10 @@ libmu_pop_la_SOURCES = \
  pop3_stream.c \
  pop3_timeout.c \
  pop3_top.c \
+ pop3_trace.c \
+ pop3_uidl_cmd.c \
  pop3_uidla.c \
+ pop3_uidlas.c \
  pop3_uidl.c \
  pop3_user.c
 
diff --git a/libproto/pop/folder.c b/libproto/pop/folder.c
index 9e792b8..b1ab364 100644
--- a/libproto/pop/folder.c
+++ b/libproto/pop/folder.c
@@ -37,9 +37,9 @@
 #include <mailutils/cstr.h>
 #include <mailutils/cctype.h>
 
-#include <folder0.h>
-#include <registrar0.h>
-#include <url0.h>
+#include <mailutils/sys/folder.h>
+#include <mailutils/sys/registrar.h>
+#include <mailutils/sys/url.h>
 
 /* We export url parsing and the initialisation of
    the mailbox, via the register entry/record.  */
@@ -160,7 +160,7 @@ folder_pop_get_authority (mu_folder_t folder, 
mu_authority_t *pauth)
 
 #else
 #include <stdio.h>
-#include <registrar0.h>
+#include <mailutils/sys/registrar.h>
 mu_record_t mu_pop_record = NULL;
 mu_record_t mu_pops_record = NULL;
 #endif /* ENABLE_POP */
diff --git a/libproto/pop/mbox.c b/libproto/pop/mbox.c
index a9e28d5..f513295 100644
--- a/libproto/pop/mbox.c
+++ b/libproto/pop/mbox.c
@@ -23,21 +23,13 @@
 
 #ifdef ENABLE_POP
 
-#include <termios.h>
-#include <errno.h>
 #include <stdlib.h>
-#include <stdio.h>
 #include <string.h>
 #include <sys/time.h>
 #include <sys/types.h>
 #include <unistd.h>
-#include <fcntl.h>
-#include <stdarg.h>
-
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif
 
+#include <mailutils/pop3.h>
 #include <mailutils/attribute.h>
 #include <mailutils/auth.h>
 #include <mailutils/body.h>
@@ -49,6 +41,7 @@
 #include <mailutils/observer.h>
 #include <mailutils/property.h>
 #include <mailutils/stream.h>
+#include <mailutils/filter.h>
 #include <mailutils/url.h>
 #include <mailutils/secret.h>
 #include <mailutils/tls.h>
@@ -57,737 +50,69 @@
 #include <mailutils/mutil.h>
 #include <mailutils/cstr.h>
 #include <mailutils/cctype.h>
+#include <mailutils/opool.h>
 
-#include <folder0.h>
-#include <mailbox0.h>
-#include <registrar0.h>
-#include <url0.h>
-
-#define PROP_RFC822 1
-
-/* Advance declarations.  */
-struct _pop_data;
-struct _pop_message;
+#include <mailutils/sys/folder.h>
+#include <mailutils/sys/mailbox.h>
+#include <mailutils/sys/registrar.h>
+#include <mailutils/sys/url.h>
 
-typedef struct _pop_data * pop_data_t;
-typedef struct _pop_message * pop_message_t;
-
-/* The different possible states of a Pop client, Note that POP3 is not
-   reentrant i.e. it is only one channel, so it is not possible to start
-   Another operation while one is running.  The only resort is to close the
-   connection and reopen it again.  This is what we do, the downside is that
-   the client as to get the authentication again user/pass.  */
-enum pop_state
-{
-  POP_NO_STATE, POP_STATE_DONE,
-  POP_OPEN_CONNECTION,
-  POP_GREETINGS,
-  POP_CAPA, POP_CAPA_ACK,
-  POP_APOP, POP_APOP_ACK,
-  POP_DELE, POP_DELE_ACK,
-  POP_LIST, POP_LIST_ACK, POP_LIST_RX,
-  POP_QUIT, POP_QUIT_ACK,
-  POP_NOOP, POP_NOOP_ACK,
-  POP_RETR, POP_RETR_ACK, POP_RETR_RX_HDR, POP_RETR_RX_BODY,
-  POP_RSET, POP_RSET_ACK,
-  POP_STAT, POP_STAT_ACK,
-  POP_STLS, POP_STLS_ACK,
-  POP_TOP,  POP_TOP_ACK,  POP_TOP_RX,
-  POP_UIDL, POP_UIDL_ACK,
-  POP_AUTH, POP_AUTH_DONE,
-  POP_AUTH_USER, POP_AUTH_USER_ACK,
-  POP_AUTH_PASS, POP_AUTH_PASS_ACK
-};
+#define _POP3_MSG_CACHED  0x01      /* Message is already cached */
+#define _POP3_MSG_SIZE    0x02      /* Message size obtained */
+#define _POP3_MSG_SCANNED 0x04      /* Message has been scanned */
+#define _POP3_MSG_ATTRSET 0x08      /* Attributes has been set */
 
-/*  POP3 capabilities  */
-#define CAPA_TOP             0x00000001
-#define CAPA_USER            0x00000002
-#define CAPA_UIDL            0x00000004
-#define CAPA_RESP_CODES      0x00000008
-#define CAPA_LOGIN_DELAY     0x00000010
-#define CAPA_PIPELINING      0x00000020
-#define CAPA_EXPIRE          0x00000040
-#define CAPA_SASL            0x00000080
-#define CAPA_STLS            0x00000100
-#define CAPA_IMPLEMENTATION  0x00000200
-
-static void pop_destroy        (mu_mailbox_t);
-static int pop_capa            (mu_mailbox_t);
-static int pop_stls            (mu_mailbox_t);
-
-/*  Functions/Methods that implements the mu_mailbox_t API.  */
-static int pop_open            (mu_mailbox_t, int);
-static int pop_close           (mu_mailbox_t);
-static int pop_get_message     (mu_mailbox_t, size_t, mu_message_t *);
-static int pop_messages_count  (mu_mailbox_t, size_t *);
-static int pop_messages_recent (mu_mailbox_t, size_t *);
-static int pop_message_unseen  (mu_mailbox_t, size_t *);
-static int pop_expunge         (mu_mailbox_t);
-static int pop_scan            (mu_mailbox_t, size_t, size_t *);
-static int pop_is_updated      (mu_mailbox_t);
-
-/* The implementation of mu_message_t */
-int _pop_user            (mu_authority_t);
-int _pop_apop            (mu_authority_t);
-static int pop_get_size        (mu_mailbox_t, mu_off_t *);
-/* We use pop_top for retreiving headers.  */
-/* static int pop_header_read (mu_header_t, char *, size_t, mu_off_t, size_t 
*); */
-static int pop_body_transport  (mu_stream_t, mu_transport_t *, mu_transport_t 
*);
-static int pop_body_size       (mu_body_t, size_t *);
-static int pop_body_lines      (mu_body_t, size_t *);
-static int pop_body_read       (mu_stream_t, char *, size_t, mu_off_t, size_t 
*);
-static int pop_message_read    (mu_stream_t, char *, size_t, mu_off_t, size_t 
*);
-static int pop_message_size    (mu_message_t, size_t *);
-static int pop_message_transport (mu_stream_t, mu_transport_t *, 
mu_transport_t *);
-static int pop_top             (mu_header_t, char *, size_t, mu_off_t, size_t 
*);
-static int pop_retr            (pop_message_t, char *, size_t, mu_off_t, 
size_t *);
-static int pop_get_transport2   (pop_message_t, mu_transport_t *, 
mu_transport_t *);
-static int pop_get_attribute   (mu_attribute_t, int *);
-static int pop_set_attribute   (mu_attribute_t, int);
-static int pop_unset_attribute (mu_attribute_t, int);
-static int pop_uidl            (mu_message_t, char *, size_t, size_t *);
-static int pop_uid             (mu_message_t, size_t *);
-static int fill_buffer         (pop_data_t, char *, size_t);
-static int pop_sleep           (int);
-static int pop_readline        (pop_data_t);
-static int pop_read_ack        (pop_data_t);
-static int pop_writeline       (pop_data_t, const char *, ...)
-                                 MU_PRINTFLIKE(2,3);
-static int pop_write           (pop_data_t);
-static int pop_get_user        (mu_authority_t);
-static int pop_get_passwd      (mu_authority_t);
-static char *pop_get_timestamp (pop_data_t);
-static int pop_get_md5         (pop_data_t);
-
-/* This structure holds the info for a message. The pop_message_t
-   type, will serve as the owner of the mu_message_t and contains the command 
to
-   send to "RETR"eive the specify message.  The problem comes from the header.
-   If the  POP server supports TOP, we can cleanly fetch the header.
-   But otherwise we use the clumsy approach. .i.e for the header we read 'til
-   ^\n then discard the rest, for the body we read after ^\n and discard the
-   beginning.  This is a waste, Pop was not conceive for this obviously.  */
-struct _pop_message
+struct _pop3_message
 {
-  int inbody;
-  int skip_header;
-  int skip_body;
-  size_t body_size;
-  size_t header_size;
-  size_t body_lines;
-  size_t header_lines;
-  size_t mu_message_size;
-  size_t num;
-  char *uidl; /* Cache the uidl string.  */
-  int attr_flags;
-  mu_message_t message;
-  pop_data_t mpd; /* Back pointer.  */
+  int flags;
+  mu_off_t offset;          /* Offset in the message cache stream */
+  mu_off_t body_start;      /* Start of message, relative to offset */
+  mu_off_t body_end;        /* End of message, relative to offset */  
+  size_t header_lines;      /* Number of lines in the header */
+  size_t body_lines;        /* Number of lines in the body */
+  int attr_flags;           /* Message attributes */
+  size_t message_size;      /* Message size */ 
+  size_t num;               /* Message number */
+  char *uidl;               /* Cached uidl string.  */
+  mu_message_t message;     /* Pointer to the message structure */ 
+  struct _pop3_mailbox *mpd; /* Back pointer.  */
 };
-
-/* Structure to hold things general to the POP mailbox, like its state, how
-   many messages we have so far etc ...  */
-struct _pop_data
-{
-  void *func;  /*  Indicate a command is in operation, busy.  */
-  size_t id;   /* A second level of distincion, we maybe in the same function
-                 but working on a different message.  */
-  int pops; /* POPS or POP? */
-  char *greeting_banner; /* A greeting banner */
-  unsigned long capa; /* Server capabilities */
-  enum pop_state state;
-  pop_message_t *pmessages;
-  size_t pmessages_count;
-  size_t messages_count;
-  size_t size;
-
-  /* Working I/O buffers.  */
-  char *buffer;
-  size_t buflen; /* Len of buffer.  */
-  char *ptr; /* Points to the end of the buffer i.e the non consume chars.  */
-  char *nl;  /* Points to the '\n' char in te string.  */
-  mu_off_t offset; /* Dummy, this is use because of the stream buffering.
-                  The mu_stream_t maintains and offset and the offset we use 
must
-                  be in sync.  */
-
-  int is_updated;
-  char *user;     /* Temporary holders for user and passwd.  */
-  mu_secret_t secret;
-  char *digest;
-  mu_mailbox_t mbox; /* Back pointer.  */
-} ;
-
-/* Usefull little Macros, since these are very repetitive.  */
-
-/* Check if we're busy ?  */
-/* POP is a one channel download protocol, so if someone
-   is trying to execute a command while another is running
-   something is seriously incorrect,  So the best course
-   of action is to close down the connection and start a new one.
-   For example mu_mime_t only reads part of the message.  If a client
-   wants to read different part of the message via mime it should
-   download it first.  POP does not have the features of IMAP for
-   multipart messages.
-   Let see a concrete example:
-   {
-     mu_mailbox_t mbox; mu_message_t msg; mu_stream_t stream; char buffer[105];
-     mu_mailbox_create (&mbox, "pop://qnx.com");
-     mu_mailbox_get_message (mbox, 1, &msg);
-     mu_message_get_stream (msg, &stream);
-     while (mu_stream_readline (stream, buffer, sizeof(buffer), NULL) != 0) { 
..}
-   }
-   if in the while of the readline, one try to get another email.  The pop
-   server will get seriously confused, and the second message will still
-   be the first one,  There is no way to tell POP servers yo! stop/abort.
-   The approach is to close the stream and reopen again. So  every time
-   we go in to a function our state is preserve by the triplets
-   mpd->{func,state,id}.  The macro CHECK_BUSY checks if we are not
-   in another operation if not you get access if yes the stream is close
-   and pop_open() is recall again for a new connection.
- */
-#define CHECK_BUSY(mbox, mpd, function, identity) \
-do \
-  { \
-    int err = mu_monitor_wrlock (mbox->monitor); \
-    if (err != 0) \
-      return err; \
-    if ((mpd->func && mpd->func != function) \
-        || (mpd->id && mpd->id != (size_t)identity)) \
-      { \
-        mpd->id = 0; \
-        mpd->func = (void *)pop_open; \
-        mpd->state = POP_NO_STATE; \
-        mu_monitor_unlock (mbox->monitor); \
-        err = pop_open (mbox, mbox->flags); \
-        if (err != 0) \
-          { \
-            return err; \
-          } \
-      } \
-    else \
-      { \
-        mpd->id = (size_t)identity; \
-        mpd->func = func; \
-        mu_monitor_unlock (mbox->monitor); \
-      } \
-  } \
-while (0)
-
-/* Clear the state.  */
-#define CLEAR_STATE(mpd) \
- mpd->id = 0, mpd->func = NULL, mpd->state = POP_NO_STATE
-
-/* Clear the state and close the stream.  */
-#define CHECK_ERROR_CLOSE(mbox, mpd, status) \
-do \
-  { \
-     if (status != 0) \
-       { \
-          mu_stream_close (mbox->stream); \
-          CLEAR_STATE (mpd); \
-          mpd->func = (void *)-1; \
-          MU_DEBUG1 (mbox->debug, MU_DEBUG_PROT, \
-                     "CHECK_ERROR_CLOSE: %s\n", mu_strerror (status));\
-          return status; \
-       } \
-  } \
-while (0)
-
-/* If error, clear the state and return.  */
-#define CHECK_ERROR(mpd, status) \
-do \
-  { \
-     if (status != 0) \
-       { \
-          CLEAR_STATE (mpd); \
-          mpd->func = (void*)-1; \
-          MU_DEBUG1(mpd->mbox->debug, MU_DEBUG_PROT, \
-                    "CHECK_ERROR: %s\n", mu_strerror (status));\
-          return status; \
-       } \
-  } \
-while (0)
-
-/* Clear the state for non recoverable error.  */
-#define CHECK_EAGAIN(mpd, status) \
-do \
-  { \
-    if (status != 0) \
-      { \
-         if (status != EAGAIN && status != EINPROGRESS && status != EINTR) \
-           { \
-             CLEAR_STATE (mpd); \
-             mpd->func = (void *)-1; \
-             MU_DEBUG1(mpd->mbox->debug, MU_DEBUG_PROT, \
-                       "CHECK_EAGAIN: %s\n", mu_strerror (status));\
-           } \
-         return status; \
-      } \
-   }  \
-while (0)
-
-
-/* Allocate mu_mailbox_t, allocate pop internal structures.  */
-static int
-_mailbox_pop_and_pops_init (mu_mailbox_t mbox, int pops)
-{
-  pop_data_t mpd;
-  int status = 0;
-
-  /* Allocate specifics for pop data.  */
-  mpd = mbox->data = calloc (1, sizeof (*mpd));
-  if (mbox->data == NULL)
-    return ENOMEM;
-
-  mpd->mbox = mbox;            /* Back pointer.  */
-  mpd->state = POP_NO_STATE;   /* Init with no state.  */
-  mpd->pops = pops;
-
-  /* Initialize the structure.  */
-  mbox->_destroy = pop_destroy;
-
-  mbox->_open = pop_open;
-  mbox->_close = pop_close;
-
-  /* Messages.  */
-  mbox->_get_message = pop_get_message;
-  mbox->_messages_count = pop_messages_count;
-  mbox->_messages_recent = pop_messages_recent;
-  mbox->_message_unseen = pop_message_unseen;
-  mbox->_expunge = pop_expunge;
-
-  mbox->_scan = pop_scan;
-  mbox->_is_updated = pop_is_updated;
-
-  mbox->_get_size = pop_get_size;
-
-  /* Set our properties.  */
-  {
-    mu_property_t property = NULL;
-    mu_mailbox_get_property (mbox, &property);
-    mu_property_set_value (property, "TYPE", "POP3", 1);
-  }
-
-  /* Hack! POP does not really have a folder.  */
-  mbox->folder->data = mbox;
-
-  return status;
-}
-
-int
-_mailbox_pop_init (mu_mailbox_t mbox)
-{
-  return _mailbox_pop_and_pops_init (mbox, 0);
-}
-
-int
-_mailbox_pops_init (mu_mailbox_t mbox)
-{
-  return _mailbox_pop_and_pops_init (mbox, 1);
-}
-
-/*  Cleaning up all the ressources associate with a pop mailbox.  */
-static void
-pop_destroy (mu_mailbox_t mbox)
-{
-  if (mbox->data)
-    {
-      pop_data_t mpd = mbox->data;
-      size_t i;
-      mu_monitor_wrlock (mbox->monitor);
-      /* Destroy the pop messages and ressources associated to them.  */
-      for (i = 0; i < mpd->pmessages_count; i++)
-       {
-         if (mpd->pmessages[i])
-           {
-             mu_message_destroy (&(mpd->pmessages[i]->message),
-                              mpd->pmessages[i]);
-             if (mpd->pmessages[i]->uidl)
-               free (mpd->pmessages[i]->uidl);
-             free (mpd->pmessages[i]);
-             mpd->pmessages[i] = NULL;
-           }
-       }
-      if (mpd->greeting_banner)
-       free (mpd->greeting_banner);
-      if (mpd->buffer)
-       free (mpd->buffer);
-      if (mpd->pmessages)
-       free (mpd->pmessages);
-      free (mpd);
-      mbox->data = NULL;
-      mu_monitor_unlock (mbox->monitor);
-    }
-}
-
-static int
-pop_mbox_uidls (mu_mailbox_t mbox, mu_list_t list)
-{
-  pop_data_t mpd = mbox->data;
-  int status;
-
-  status = pop_writeline (mpd, "UIDL\r\n");
-  CHECK_ERROR (mpd, status);
-  MU_DEBUG (mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-
-  status = pop_write (mpd);
-  CHECK_EAGAIN (mpd, status);
-
-  status = pop_read_ack (mpd);
-  CHECK_EAGAIN (mpd, status);
-  MU_DEBUG (mpd->mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-
-  if (!mu_c_strncasecmp (mpd->buffer, "+OK", 3))
-    {
-      do
-       {
-         char *p;
-         size_t num;
-         struct mu_uidl *uidl;
-         
-         status = pop_read_ack (mpd);
-         MU_DEBUG (mpd->mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-
-         num = strtoul (mpd->buffer, &p, 10);
-         if (*p == 0 || !mu_isblank (*p))
-           continue; /* FIXME: or error? */
-         p = mu_str_skip_class (p, MU_CTYPE_SPACE);
-         mu_rtrim_cset (p, "\r\n");
-
-         uidl = malloc (sizeof (uidl[0]));
-         if (!uidl)
-           {
-             status = ENOMEM;
-             break;
-           }
-         uidl->msgno = num;
-         strncpy (uidl->uidl, p, MU_UIDL_BUFFER_SIZE);
-         status = mu_list_append (list, uidl);
-       }
-      while (mpd->nl);
-    }
-  else
-    status = ENOSYS;
-  return status;
-}
-
-/*
-  POP3 CAPA support.
- */
-
-static int
-pop_parse_capa (pop_data_t mpd)
-{
-  int status;
-  if (!mu_c_strncasecmp (mpd->buffer, "+OK", 3))
-    {
-      mpd->capa = 0;
-      do
-       {
-         status = pop_read_ack (mpd);
-         MU_DEBUG (mpd->mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-
-         /* Here we check some common capabilities like TOP, USER, UIDL,
-            and STLS. The rest are ignored. Please note that some
-            capabilities might have an extra arguments. For instance,
-            SASL can have CRAM-MD5 and/or KERBEROS_V4, and etc.
-            This is why I suggest adding (in a future) an extra variable,
-            for example `capa_sasl'. It would hold the following flags:
-            SASL_CRAM_MD5, SASL_KERBEROS_V4, and so on. Also the EXPIRE
-            and LOGIN-DELAY capabilities have an extra arguments!
-            Note that there is no APOP capability, even though APOP
-            is an optional command in POP3. -- W.P. */
-
-         if (!mu_c_strncasecmp (mpd->buffer, "TOP", 3))
-           mpd->capa |= CAPA_TOP;
-         else if (!mu_c_strncasecmp (mpd->buffer, "USER", 4))
-           mpd->capa |= CAPA_USER;
-         else if (!mu_c_strncasecmp (mpd->buffer, "UIDL", 4))
-           mpd->capa |= CAPA_UIDL;
-         else if (!mu_c_strncasecmp (mpd->buffer, "STLS", 4))
-           mpd->capa |= CAPA_STLS;
-       }
-      while (mpd->nl);
-
-      if (mpd->capa & CAPA_UIDL)
-       mpd->mbox->_get_uidls = pop_mbox_uidls;
   
-      return status;
-    }
-  else
-    {
-      /* mu_error ("CAPA not implemented"); */ /* FIXME */
-      return ENOSYS;
-    }
-}
-
-static int
-pop_capa (mu_mailbox_t mbox)
+struct _pop3_mailbox
 {
-  pop_data_t mpd = mbox->data;
-  int status;
-
-  status = pop_writeline (mpd, "CAPA\r\n");
-  CHECK_ERROR (mpd, status);
-  MU_DEBUG (mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-
-  status = pop_write (mpd);
-  CHECK_EAGAIN (mpd, status);
-  mpd->state = POP_CAPA_ACK;
-
-  /* POP_CAPA_ACK */
-  status = pop_read_ack (mpd);
-  CHECK_EAGAIN (mpd, status);
-  MU_DEBUG (mpd->mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-
-  return pop_parse_capa (mpd);
-}
-
-/* Simple User/pass authentication for pop. We ask for the info
-   from the standard input.  */
-int
-_pop_user (mu_authority_t auth)
-{
-  mu_folder_t folder = mu_authority_get_owner (auth);
-  mu_mailbox_t mbox = folder->data;
-  pop_data_t mpd = mbox->data;
-  int status;
-
-  switch (mpd->state)
-    {
-    case POP_AUTH:
-      /*  Fetch the user from them.  */
-      status = pop_get_user (auth);
-      if (status != 0 || mpd->user == NULL || mpd->user[0] == '\0')
-       {
-         pop_writeline (mpd, "QUIT\r\n");
-         MU_DEBUG (mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-         pop_write (mpd);
-         CHECK_ERROR_CLOSE (mbox, mpd, MU_ERR_NOUSERNAME);
-       }
-      status = pop_writeline (mpd, "USER %s\r\n", mpd->user);
-      CHECK_ERROR_CLOSE(mbox, mpd, status);
-      MU_DEBUG (mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-      free (mpd->user);
-      mpd->user = NULL;
-      mpd->state = POP_AUTH_USER;
-
-    case POP_AUTH_USER:
-      /* Send username.  */
-      status = pop_write (mpd);
-      CHECK_EAGAIN (mpd, status);
-      mpd->state = POP_AUTH_USER_ACK;
-
-    case POP_AUTH_USER_ACK:
-      /* Get the user ack.  */
-      status = pop_read_ack (mpd);
-      CHECK_EAGAIN (mpd, status);
-      MU_DEBUG (mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-      if (mu_c_strncasecmp (mpd->buffer, "+OK", 3) != 0)
-       {
-         mu_observable_t observable = NULL;
-         mu_mailbox_get_observable (mbox, &observable);
-         CLEAR_STATE (mpd);
-         mu_observable_notify (observable, MU_EVT_AUTHORITY_FAILED, NULL);
-         CHECK_ERROR_CLOSE (mbox, mpd, EACCES);
-       }
-      status = pop_get_passwd (auth);
-      if (status != 0 || mpd->secret == NULL)
-       {
-         pop_writeline (mpd, "QUIT\r\n");
-         MU_DEBUG (mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-         pop_write (mpd);
-         CHECK_ERROR_CLOSE (mbox, mpd, MU_ERR_NOPASSWORD);
-       }
-      status = pop_writeline (mpd, "PASS %s\r\n",
-                             mu_secret_password (mpd->secret));
-      mu_secret_password_unref (mpd->secret);
-      mu_secret_unref (mpd->secret);
-      mpd->secret = NULL;
-      MU_DEBUG (mbox->debug, MU_DEBUG_PROT, "PASS ***\n");
-      CHECK_ERROR_CLOSE (mbox, mpd, status);
-      mpd->state = POP_AUTH_PASS;
-      /* FIXME: Merge these two cases */
-        
-    case POP_AUTH_PASS:
-      /* Send passwd.  */
-      status = pop_write (mpd);
-      CHECK_EAGAIN (mpd, status);
-      /* Clear the buffer it contains the passwd.  */
-      memset (mpd->buffer, '\0', mpd->buflen);
-      mpd->state = POP_AUTH_PASS_ACK;
-
-    case POP_AUTH_PASS_ACK:
-      /* Get the ack from passwd.  */
-      status = pop_read_ack (mpd);
-      CHECK_EAGAIN (mpd, status);
-      MU_DEBUG (mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-      if (mu_c_strncasecmp (mpd->buffer, "+OK", 3) != 0)
-       {
-         mu_observable_t observable = NULL;
-         mu_mailbox_get_observable (mbox, &observable);
-         CLEAR_STATE (mpd);
-         mu_observable_notify (observable, MU_EVT_AUTHORITY_FAILED, NULL);
-         return MU_ERR_AUTH_FAILURE;
-       }
-      mpd->state = POP_AUTH_DONE;
-      break;  /* We're outta here.  */
-
-    default:
-      break;
-    }
-  CLEAR_STATE (mpd);
-  return 0;
-}
-
-int
-_pop_apop (mu_authority_t auth)
-{
-  mu_folder_t folder = mu_authority_get_owner (auth);
-  mu_mailbox_t mbox = folder->data;
-  pop_data_t mpd = mbox->data;
-  int status;
-
-  switch (mpd->state)
-    {
-    case POP_AUTH:
-      /* Fetch the user from them.  */
-      status = pop_get_user (auth);
-      if (status != 0 || mpd->user == NULL || mpd->user[0] == '\0')
-       {
-         CHECK_ERROR_CLOSE (mbox, mpd, EINVAL);
-       }
-
-      /* Fetch the secret from them.  */
-      status = pop_get_passwd (auth);
-      if (status != 0 || mpd->secret == NULL)
-       {
-         CHECK_ERROR_CLOSE (mbox, mpd, EINVAL);
-       }
-
-      /* Make the MD5 digest string.  */
-      status = pop_get_md5 (mpd);
-      if (status != 0)
-       {
-         CHECK_ERROR_CLOSE (mbox, mpd, status);
-       }
-      status = pop_writeline (mpd, "APOP %s %s\r\n", mpd->user, mpd->digest);
-      MU_DEBUG (mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-      /* We have to obscure the md5 string.  */
-      memset (mpd->digest, '\0', strlen (mpd->digest));
-      free (mpd->user);
-      free (mpd->digest);
-      mpd->user = NULL;
-      mpd->digest = NULL;
-      CHECK_ERROR_CLOSE (mbox, mpd, status);
-      mpd->state = POP_APOP;
-
-    case POP_APOP:
-      /* Send apop.  */
-      status = pop_write (mpd);
-      CHECK_EAGAIN (mpd, status);
-      /* Clear the buffer it contains the md5.  */
-      memset (mpd->buffer, '\0', mpd->buflen);
-      mpd->state = POP_APOP_ACK;
-
-    case POP_APOP_ACK:
-      status = pop_read_ack (mpd);
-      CHECK_EAGAIN (mpd, status);
-      MU_DEBUG (mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-      if (mu_c_strncasecmp (mpd->buffer, "+OK", 3) != 0)
-        {
-          mu_observable_t observable = NULL;
-          mu_mailbox_get_observable (mbox, &observable);
-          CLEAR_STATE (mpd);
-          mu_observable_notify (observable, MU_EVT_AUTHORITY_FAILED, NULL);
-          CHECK_ERROR_CLOSE (mbox, mpd, EACCES);
-        }
-      mpd->state = POP_AUTH_DONE;
-      break;  /* We're outta here.  */
-
-    default:
-      break;
-    }
-  CLEAR_STATE (mpd);
-  return 0;
-}
-
-/*
-  Client side STLS support.
- */
-
-static int
-pop_reader (void *iodata)
-{
-  int status = 0;
-  pop_data_t iop = iodata;
-  status = pop_read_ack (iop);
-  CHECK_EAGAIN (iop, status);
-  MU_DEBUG (iop->mbox->debug, MU_DEBUG_PROT, iop->buffer);
-  return status;/*mu_c_strncasecmp (iop->buffer, "+OK", 3) == 0;*/
-}
-
-static int
-pop_writer (void *iodata, char *buf)
-{
-  pop_data_t iop = iodata;
-  int status;
+  mu_pop3_t pop3;             /* mu_pop3_t is the working horse */
+  int pops;                   /* true if pop3 over SSL is being used */
+  int is_updated;             /* true if the mailbox info is up to date */
   
-  MU_DEBUG1 (iop->mbox->debug, MU_DEBUG_PROT, "%s\n", buf);
-  status = pop_writeline (iop, "%s\r\n", buf);
-  CHECK_ERROR (iop, status);
-  status = pop_write (iop);
-  CHECK_ERROR (iop, status);
-  return status;
-}
-
-static void
-pop_stream_ctl (void *iodata, mu_stream_t *pold, mu_stream_t new)
-{
-  pop_data_t iop = iodata;
-  if (pold)
-    *pold = iop->mbox->stream;
-  if (new)
-    iop->mbox->stream = new;
-}
-
-static int
-pop_stls (mu_mailbox_t mbox)
-{
-#ifdef WITH_TLS
-  int status;
-  pop_data_t mpd = mbox->data;
-  char *keywords[] = { "STLS", "CAPA", NULL };
-
-  if (!mu_tls_enable || !(mpd->capa & CAPA_STLS))
-    return -1;
-
-  status = mu_tls_begin (mpd, pop_reader, pop_writer,
-                        pop_stream_ctl, keywords);
-
-  MU_DEBUG1 (mbox->debug, MU_DEBUG_PROT, "TLS negotiation %s\n",
-                 status == 0 ? "succeeded" : "failed");
-
-  if (status == 0)
-    pop_parse_capa (mpd);
+  size_t msg_count;           /* Number of messages in the mailbox */
+  mu_off_t total_size;        /* Total mailbox size. */
+  struct _pop3_message **msg; /* Array of messages */
+  size_t msg_max;             /* Actual size of the array */  
+  mu_mailbox_t mbox;          /* MU mailbox corresponding to this one. */
+
+  mu_stream_t cache;          /* Message cache stream */
+   /* Temporary holders for user and passwd: */
+  char *user;    
+  mu_secret_t secret;
+};
 
-  return status;
-#else
-  return -1;
-#endif /* WITH_TLS */
-}
+
+/* ------------------------------------------------------------------------- */
+/* Basic operations */
 
-/* Open the connection to the sever, and send the authentication. */
 static int
 pop_open (mu_mailbox_t mbox, int flags)
 {
-  pop_data_t mpd = mbox->data;
+  struct _pop3_mailbox *mpd = mbox->data;
   int status;
   const char *host;
   long port = mpd->pops ? MU_POPS_PORT : MU_POP_PORT;
-
-  /* Sanity checks.  */
+  mu_stream_t stream;
+  
+  /* Sanity checks. */
   if (mpd == NULL)
     return EINVAL;
-
+  
   /* Fetch the pop server name and the port in the mu_url_t.  */
   status = mu_url_sget_host (mbox->url, &host);
   if (status != 0)
@@ -796,517 +121,160 @@ pop_open (mu_mailbox_t mbox, int flags)
 
   mbox->flags = flags;
 
-  /* Do not check for reconnect here.  */
-  /* CHECK_BUSY (mbox, mpd, func, 0); */
-
-  /* Enter the pop state machine, and boogy: AUTHORISATION State.  */
-  switch (mpd->state)
+  status = mu_tcp_stream_create (&stream, host, port, mbox->flags);
+  if (status)
+    return status;
+#ifdef WITH_TLS
+  if (mpd->pops)
     {
-    case POP_NO_STATE:
-      /* Allocate a working io buffer.  */
-      if (mpd->buffer == NULL)
+      mu_stream_t newstr;
+      
+      status = mu_stream_open (stream);
+      if (status)
        {
-         /* 255 is the limit lenght of a POP3 command according to RFCs.  */
-         mpd->buflen = 255;
-         mpd->buffer = calloc (mpd->buflen + 1, sizeof (char));
-         if (mpd->buffer == NULL)
-           {
-             CHECK_ERROR (mpd, ENOMEM);
-           }
+         mu_stream_destroy (&stream);
+         return status;
        }
-      else
+      
+      status = mu_tls_client_stream_create (&newstr, stream, stream, 0);
+      mu_stream_unref (stream);
+      if (status)
        {
-         /* Clear any residual from a previous connection.  */
-         memset (mpd->buffer, '\0', mpd->buflen);
+         mu_error ("pop_open: mu_tls_client_stream_create: %s",
+                   mu_strerror (status));
+         return status;
        }
-      mpd->ptr = mpd->buffer;
-
-      /* Create the networking stack.  */
-      if (mbox->stream == NULL)
-       {
-         status = mu_tcp_stream_create (&mbox->stream, host, port, 
mbox->flags);
-         CHECK_ERROR (mpd, status);
+      stream = newstr;
+    }
+#endif /* WITH_TLS */
 
-#ifdef WITH_TLS
-         if (mpd->pops)
-           {
-             mu_stream_t newstr;
+  /* FIXME: How to configure buffer size? */
+  mu_stream_set_buffer (stream, mu_buffer_line, 1024);
 
-             status = mu_stream_open (mbox->stream);
-             CHECK_EAGAIN (mpd, status);
-             CHECK_ERROR_CLOSE (mbox, mpd, status);
+  status = mu_pop3_create (&mpd->pop3);
+  if (status)
+    {
+      mu_stream_destroy (&stream);
+      return status;
+    }
+  mu_pop3_set_carrier (mpd->pop3, stream);
+
+  if (mu_debug_check_level (mbox->debug, MU_DEBUG_PROT))
+    mu_pop3_trace (mpd->pop3, MU_POP3_TRACE_SET);
+  if (mu_debug_check_level (mbox->debug, MU_DEBUG_TRACE6))
+    mu_pop3_trace_mask (mpd->pop3, MU_POP3_TRACE_SET, MU_XSCRIPT_SECURE);
+  if (mu_debug_check_level (mbox->debug, MU_DEBUG_TRACE7))
+    mu_pop3_trace_mask (mpd->pop3, MU_POP3_TRACE_SET, MU_XSCRIPT_PAYLOAD);
+    
+  do
+    {
+      status = mu_pop3_connect (mpd->pop3);
+      if (status)
+       break;
 
-             status = mu_tls_stream_create_client_from_tcp (&newstr, 
mbox->stream, 0);
-             if (status != 0)
-               {
-                 mu_error ("pop_open: mu_tls_stream_create_client_from_tcp: 
%s",
-                           mu_strerror (status));
-                 return status;
-               }
-             mbox->stream = newstr;
-           }
-#endif /* WITH_TLS */
+      status = mu_pop3_capa (mpd->pop3, 1, NULL);
+      if (status)
+       break;
 
-         /* Using the awkward mu_stream_t buffering.  */
-         mu_stream_setbufsiz (mbox->stream, BUFSIZ);
-       }
-      else
+      if (WITH_TLS && !mpd->pops &&
+         mu_pop3_capa_test (mpd->pop3, "STLS", NULL) == 0)
        {
-         /* This is sudden death: for many pop servers, it is important to
-            let them time to remove locks or move the .user.pop files.  This
-            happen when we do BUSY_CHECK().  For example, the user does not
-            want to read the entire file, and wants start to read a new
-            message, closing the connection and immediately contact the
-            server again, and we'll end up having "-ERR Mail Lock busy" or
-            something similar. To prevent this race condition we sleep 2
-            seconds. */
-         mu_stream_close (mbox->stream);
-         pop_sleep (2);
+         status = mu_pop3_stls (mpd->pop3);
+         if (status)
+           break;
        }
-      mpd->state = POP_OPEN_CONNECTION;
-
-    case POP_OPEN_CONNECTION:
-      /* Establish the connection.  */
-      MU_DEBUG2 (mbox->debug, MU_DEBUG_PROT, "open (%s:%ld)\n", host, port);
-      status = mu_stream_open (mbox->stream);
-      CHECK_EAGAIN (mpd, status);
-      /* Can't recover bailout.  */
-      CHECK_ERROR_CLOSE (mbox, mpd, status);
-      mpd->state = POP_GREETINGS;
-
-    case POP_GREETINGS:
-      {
-       int gblen = 0;
-       status = pop_read_ack (mpd);
-       CHECK_EAGAIN (mpd, status);
-       MU_DEBUG (mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-       if (mu_c_strncasecmp (mpd->buffer, "+OK", 3) != 0)
-         {
-           CHECK_ERROR_CLOSE (mbox, mpd, EACCES);
-         }
-       gblen = strlen (mpd->buffer);
-       mpd->greeting_banner = calloc (gblen, 1);
-       if (mpd->greeting_banner == NULL)
-         {
-           CHECK_ERROR (mpd, ENOMEM);
-         }
-       memcpy (mpd->greeting_banner, mpd->buffer, gblen);
-       mpd->state = POP_CAPA;
-      }
-
-    case POP_CAPA:
-    case POP_CAPA_ACK:
-      pop_capa (mbox);
-      mpd->state = POP_STLS;
-
-    case POP_STLS:
-    case POP_STLS_ACK:
-      if (!mpd->pops)
-       pop_stls (mbox);
-      mpd->state = POP_AUTH;
-
-    case POP_AUTH:
-    case POP_AUTH_USER:
-    case POP_AUTH_USER_ACK:
-    case POP_AUTH_PASS:
-    case POP_AUTH_PASS_ACK:
-    case POP_APOP:
-    case POP_APOP_ACK:
-      /* Authenticate.  */
-      status = mu_authority_authenticate (mbox->folder->authority);
-      CHECK_EAGAIN (mpd, status);
 
-    case POP_AUTH_DONE:
-      break;
-
-    default:
-      /*
-       mu_error ("pop_open: unknown state");
-      */
-      break;
-    }/* End AUTHORISATION state. */
-
-  /* Clear any state.  */
-  CLEAR_STATE (mpd);
-  return 0;
+      status = mu_authority_authenticate (mbox->folder->authority);
+    }
+  while (0);
+  
+  if (status)
+    mu_pop3_destroy (&mpd->pop3);
+  return status;
 }
-
-/* Send the QUIT and close the socket.  */
+  
 static int
 pop_close (mu_mailbox_t mbox)
 {
-  pop_data_t mpd = mbox->data;
-  void *func = (void *)pop_close;
+  struct _pop3_mailbox *mpd = mbox->data;
   int status;
-  size_t i;
-
-  if (mpd == NULL)
-    return EINVAL;
-
-  /* Should not check for Busy, we're shuting down anyway.  */
-  /* CHECK_BUSY (mbox, mpd, func, 0); */
-  mu_monitor_wrlock (mbox->monitor);
-  if (mpd->func && mpd->func != func)
-    mpd->state = POP_NO_STATE;
-  mpd->id = 0;
-  mpd->func = func;
-  mu_monitor_unlock (mbox->monitor);
-
-  /*  Ok boys, it's a wrap: UPDATE State.  */
-  switch (mpd->state)
-    {
-    case POP_NO_STATE:
-      /* Initiate the close.  */
-      status = pop_writeline (mpd, "QUIT\r\n");
-      CHECK_ERROR (mpd, status);
-      MU_DEBUG (mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-      mpd->state = POP_QUIT;
-
-    case POP_QUIT:
-      /* Send the quit.  */
-      status = pop_write (mpd);
-      CHECK_EAGAIN (mpd, status);
-      mpd->state = POP_QUIT_ACK;
-
-    case POP_QUIT_ACK:
-      /* Glob the acknowledge.  */
-      status = pop_read_ack (mpd);
-      CHECK_EAGAIN (mpd, status);
-      MU_DEBUG (mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-      /*  Now what ! and how can we tell them about errors ?  So far now
-         lets just be verbose about the error but close the connection
-         anyway.  */
-      if (mu_c_strncasecmp (mpd->buffer, "+OK", 3) != 0)
-       mu_error ("pop_close: %s", mpd->buffer);
-      mu_stream_close (mbox->stream);
-      break;
-
-    default:
-      /*
-       mu_error ("pop_close: unknown state");
-      */
-      break;
-    } /* UPDATE state.  */
-
-  /* Free the messages.  */
-  for (i = 0; i < mpd->pmessages_count; i++)
-    {
-      if (mpd->pmessages[i])
-       {
-         mu_message_destroy (&(mpd->pmessages[i]->message),
-                          mpd->pmessages[i]);
-         if (mpd->pmessages[i]->uidl)
-           free (mpd->pmessages[i]->uidl);
-         free (mpd->pmessages[i]);
-         mpd->pmessages[i] = NULL;
-       }
-    }
-  /* And clear any residue.  */
-  if (mpd->greeting_banner)
-    free (mpd->greeting_banner);
-  mpd->greeting_banner = NULL;
-  if (mpd->pmessages)
-    free (mpd->pmessages);
-  mpd->pmessages = NULL;
-  mpd->pmessages_count = 0;
-  mpd->is_updated = 0;
-  if (mpd->buffer)
-    free (mpd->buffer);
-  mpd->buffer = NULL;
-
-  CLEAR_STATE (mpd);
+  
+  status = mu_pop3_quit (mpd->pop3);
+  if (status)
+    mu_error ("mu_pop3_quit failed: %s", mu_strerror (status));
+  status = mu_pop3_disconnect (mpd->pop3);
+  if (status)
+    mu_error ("mu_pop3_disconnect failed: %s", mu_strerror (status));
+  mu_pop3_destroy (&mpd->pop3);
+  mu_stream_destroy (&mpd->cache);
   return 0;
 }
 
-/*  Only build/setup the mu_message_t structure for a mesgno. pop_message_t,
-    will act as the owner of messages.  */
-static int
-pop_get_message (mu_mailbox_t mbox, size_t msgno, mu_message_t *pmsg)
+static void
+pop_destroy (mu_mailbox_t mbox)
 {
-  pop_data_t mpd = mbox->data;
-  mu_message_t msg = NULL;
-  pop_message_t mpm;
-  int status;
-  size_t i;
-
-  /* Sanity.  */
-  if (pmsg == NULL || mpd == NULL)
-    return EINVAL;
-
-  /* If we did not start a scanning yet do it now.  */
-  if (!pop_is_updated (mbox))
-    pop_scan (mbox, 1, NULL);
-
-  if (msgno > mpd->messages_count)
-    return EINVAL;
-
-  mu_monitor_rdlock (mbox->monitor);
-  /* See if we have already this message.  */
-  for (i = 0; i < mpd->pmessages_count; i++)
+  struct _pop3_mailbox *mpd = mbox->data;
+  if (mpd)
     {
-      if (mpd->pmessages[i])
+       size_t i;
+      mu_monitor_wrlock (mbox->monitor);
+      /* Destroy the pop messages and resources associated to them.  */
+      for (i = 0; i < mpd->msg_count; i++)
        {
-         if (mpd->pmessages[i]->num == msgno)
+         if (mpd->msg[i])
            {
-             *pmsg = mpd->pmessages[i]->message;
-             mu_monitor_unlock (mbox->monitor);
-             return 0;
+             mu_message_destroy (&mpd->msg[i]->message, mpd->msg[i]);
+             if (mpd->msg[i]->uidl)
+               free (mpd->msg[i]->uidl);
+             free (mpd->msg[i]);
            }
        }
-    }
-  mu_monitor_unlock (mbox->monitor);
-
-  mpm = calloc (1, sizeof (*mpm));
-  if (mpm == NULL)
-    return ENOMEM;
-
-  /* Back pointer.  */
-  mpm->mpd = mpd;
-  mpm->num = msgno;
-
-  /* Create the message.  */
-  {
-    mu_stream_t stream = NULL;
-    if ((status = mu_message_create (&msg, mpm)) != 0
-       || (status = mu_stream_create (&stream, mbox->flags, msg)) != 0)
-      {
-       mu_stream_destroy (&stream, msg);
-       mu_message_destroy (&msg, mpm);
-       free (mpm);
-       return status;
-      }
-    /* Help for the readline()s  */
-    mu_stream_setbufsiz (stream, 128);
-    mu_stream_set_read (stream, pop_message_read, msg);
-    mu_stream_set_get_transport2 (stream, pop_message_transport, msg);
-    mu_message_set_stream (msg, stream, mpm);
-    mu_message_set_size (msg, pop_message_size, mpm);
-  }
-
-  /* Create the header.  */
-  {
-    mu_header_t header = NULL;
-    if ((status = mu_header_create (&header, NULL, 0,  msg)) != 0)
-      {
-       mu_message_destroy (&msg, mpm);
-       free (mpm);
-       return status;
-      }
-    mu_header_set_fill (header, pop_top, msg);
-    mu_message_set_header (msg, header, mpm);
-  }
-
-  /* Create the attribute.  */
-  {
-    mu_attribute_t attribute;
-    status = mu_attribute_create (&attribute, msg);
-    if (status != 0)
-      {
-       mu_message_destroy (&msg, mpm);
-       free (mpm);
-       return status;
-      }
-    mu_attribute_set_get_flags (attribute, pop_get_attribute, msg);
-    mu_attribute_set_set_flags (attribute, pop_set_attribute, msg);
-    mu_attribute_set_unset_flags (attribute, pop_unset_attribute, msg);
-    mu_message_set_attribute (msg, attribute, mpm);
-  }
-
-  /* Create the body and its stream.  */
-  {
-    mu_body_t body = NULL;
-    mu_stream_t stream = NULL;
-    if ((status = mu_body_create (&body, msg)) != 0
-       || (status = mu_stream_create (&stream, mbox->flags, body)) != 0)
-      {
-       mu_body_destroy (&body, msg);
-       mu_stream_destroy (&stream, body);
-       mu_message_destroy (&msg, mpm);
-       free (mpm);
-       return status;
-      }
-    /* Helps for the readline()s  */
-    mu_stream_setbufsiz (stream, 128);
-    mu_stream_set_read (stream, pop_body_read, body);
-    mu_stream_set_get_transport2 (stream, pop_body_transport, body);
-    mu_body_set_size (body, pop_body_size, msg);
-    mu_body_set_lines (body, pop_body_lines, msg);
-    mu_body_set_stream (body, stream, msg);
-    mu_message_set_body (msg, body, mpm);
-  }
-
-  /* Set the UIDL call on the message. */
-  if (mpd->capa & CAPA_UIDL)
-    mu_message_set_uidl (msg, pop_uidl, mpm);
-  
-  /* Set the UID on the message. */
-  mu_message_set_uid (msg, pop_uid, mpm);
-
-  /* Add it to the list.  */
-  mu_monitor_wrlock (mbox->monitor);
-  {
-    pop_message_t *m ;
-    m = realloc (mpd->pmessages, (mpd->pmessages_count + 1)*sizeof (*m));
-    if (m == NULL)
-      {
-       mu_message_destroy (&msg, mpm);
-       free (mpm);
-       mu_monitor_unlock (mbox->monitor);
-       return ENOMEM;
-      }
-    mpd->pmessages = m;
-    mpd->pmessages[mpd->pmessages_count] = mpm;
-    mpd->pmessages_count++;
-  }
-  mu_monitor_unlock (mbox->monitor);
-
-  /* Save The message pointer.  */
-  mu_message_set_mailbox (msg, mbox, mpm);
-  *pmsg = mpm->message = msg;
-
-  return 0;
-}
-
-/* FIXME: Should use strtoumax ideally */
-static int
-parse_answer0 (const char *buffer, size_t *n1, size_t *n2)
-{
-  char *p;
-  unsigned long m;
-  if (strlen (buffer) < 3 || memcmp (buffer, "+OK", 3))
-    return 1;
-  m = *n1 = strtoul (buffer + 3, &p, 10);
-  if (!mu_isspace (*p) || m != *n1)
-    return 1;
-  m = *n2 = strtoul (p, &p, 10);
-  if (!(*p == 0 || mu_isspace (*p)) || m != *n2)
-    return 1;
-  return 0;
-}
-
-/* FIXME: Should use strtoumax ideally */
-static int
-parse_answer1 (const char *buffer, size_t *n1, char *buf, size_t bufsize)
-{
-  char *p;
-  unsigned long m;
-  if (strlen (buffer) < 3 || memcmp (buffer, "+OK", 3))
-    return 1;
-  m = *n1 = strtoul (buffer + 3, &p, 0);
-  if (!mu_isspace (*p) || m != *n1)
-    return 1;
-  while (*p && mu_isspace (*p))
-    p++;
-  if (strlen (p) >= bufsize)
-    return 1;
-  strcpy (buf, p);
-  return 0;
-}
-  
-/* There is no such thing in pop all messages should be consider recent.
-   FIXME: We could cheat and peek at the status if it was not strip
-   by the server ...  */
-static int
-pop_messages_recent (mu_mailbox_t mbox, size_t *precent)
-{
-  return pop_messages_count (mbox, precent);
+      mu_pop3_destroy (&mpd->pop3);
+      if (mpd->user)
+       free (mpd->user);
+      if (mpd->secret)
+       mu_secret_unref (mpd->secret);
+      mu_stream_destroy (&mpd->cache);
+   }
 }
 
-/* There is no such thing in pop all messages should be consider unseen.
-   FIXME: We could cheat and peek at the status if it was not strip
-   by the server ...  */
+/* Update and scanning.  */
 static int
-pop_message_unseen (mu_mailbox_t mbox, size_t *punseen)
+pop_is_updated (mu_mailbox_t mbox)
 {
-  size_t count = 0;
-  int status = pop_messages_count (mbox, &count);
-  if (status != 0)
-    return status;
-  if (punseen)
-    *punseen = (count > 0) ? 1 : 0;
-  return 0;
+  struct _pop3_mailbox *mpd = mbox->data;
+  if (mpd == NULL)
+    return 0;
+  return mpd->is_updated;
 }
-
-/*  How many messages we have.  Done with STAT.  */
+      
+/* Return the number of messages in the mailbox */
 static int
 pop_messages_count (mu_mailbox_t mbox, size_t *pcount)
 {
-  pop_data_t mpd = mbox->data;
+  struct _pop3_mailbox *mpd = mbox->data;
   int status;
-  void *func = (void *)pop_messages_count;
-
+  
   if (mpd == NULL)
     return EINVAL;
 
-  /* Do not send a STAT if we know the answer.  */
   if (pop_is_updated (mbox))
     {
       if (pcount)
-       *pcount = mpd->messages_count;
+       *pcount = mpd->msg_count;
       return 0;
     }
 
-  /* Flag busy.  */
-  CHECK_BUSY (mbox, mpd, func, 0);
-
-  /* TRANSACTION state.  */
-  switch (mpd->state)
+  status = mu_pop3_stat (mpd->pop3, &mpd->msg_count, &mpd->total_size);
+  if (status == 0)
     {
-    case POP_NO_STATE:
-      status = pop_writeline (mpd, "STAT\r\n");
-      CHECK_ERROR (mpd, status);
-      MU_DEBUG (mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-      mpd->state = POP_STAT;
-
-    case POP_STAT:
-      /* Send the STAT.  */
-      status = pop_write (mpd);
-      CHECK_EAGAIN (mpd, status);
-      mpd->state = POP_STAT_ACK;
-
-    case POP_STAT_ACK:
-      /* Get the ACK.  */
-      status = pop_read_ack (mpd);
-      CHECK_EAGAIN (mpd, status);
-      MU_DEBUG (mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-      break;
-
-    default:
-      /*
-       mu_error ("pop_messages_count: unknown state");
-      */
-      break;
+      if (pcount)
+       *pcount = mpd->msg_count;
+      mpd->is_updated = 1;
     }
-
-
-  /* Parse the answer.  */
-
-  status = parse_answer0 (mpd->buffer, &mpd->messages_count, &mpd->size);
-  /*  Clear the state _after_ the scanf, since another thread could
-      start writing over mpd->buffer.  */
-  CLEAR_STATE (mpd);
-
-  if (status)
-    return EIO;
-
-  if (pcount)
-    *pcount = mpd->messages_count;
-  mpd->is_updated = 1;
-  return 0;
-}
-
-/* Update and scanning.  */
-static int
-pop_is_updated (mu_mailbox_t mbox)
-{
-  pop_data_t mpd = mbox->data;
-  if (mpd == NULL)
-    return 0;
-  return mpd->is_updated;
+  return status;
 }
-
-/* We just simulate by sending a notification for the total msgno.  */
-/* FIXME is message is set deleted should we sent a notif ?  */
+  
 static int
 pop_scan (mu_mailbox_t mbox, size_t msgno, size_t *pcount)
 {
@@ -1315,10 +283,10 @@ pop_scan (mu_mailbox_t mbox, size_t msgno, size_t 
*pcount)
   size_t count = 0;
 
   status = pop_messages_count (mbox, &count);
-  if (pcount)
-    *pcount = count;
   if (status != 0)
     return status;
+  if (pcount)
+    *pcount = count;
   if (mbox->observable == NULL)
     return 0;
   for (i = msgno; i <= count; i++)
@@ -1327,7 +295,7 @@ pop_scan (mu_mailbox_t mbox, size_t msgno, size_t *pcount)
       if (mu_observable_notify (mbox->observable, MU_EVT_MESSAGE_ADD,
                                &tmp) != 0)
        break;
-      if (((i +1) % 10) == 0)
+      if (((i + 1) % 10) == 0)
        {
          mu_observable_notify (mbox->observable, MU_EVT_MAILBOX_PROGRESS,
                                NULL);
@@ -1336,239 +304,336 @@ pop_scan (mu_mailbox_t mbox, size_t msgno, size_t 
*pcount)
   return 0;
 }
 
-/* This is where we actually send the DELE command. Meaning that when
-   the attribute on the message is set deleted the comand DELE is not
-   sent right away and if we did there is no way to mark a message undeleted
-   beside closing down the connection without going to the update state via
-   QUIT.  So DELE is send only when in expunge.  */
+/* There's no way to retrieve this info via POP3 */
 static int
-pop_expunge (mu_mailbox_t mbox)
+pop_message_unseen (mu_mailbox_t mbox, size_t *punseen)
 {
-  pop_data_t mpd = mbox->data;
-  size_t i;
-  mu_attribute_t attr;
-  int status;
-  void *func = (void *)pop_expunge;
+  size_t count = 0;
+  int status = pop_messages_count (mbox, &count);
+  if (status != 0)
+    return status;
+  if (punseen)
+    *punseen = (count > 0) ? 1 : 0;
+  return 0;
+}
+
+static int
+pop_get_size (mu_mailbox_t mbox, mu_off_t *psize)
+{
+  struct _pop3_mailbox *mpd = mbox->data;
+  int status = 0;
 
   if (mpd == NULL)
     return EINVAL;
 
-  /* Busy ?  */
-  CHECK_BUSY (mbox, mpd, func, 0);
+  if (!pop_is_updated (mbox))
+    status = pop_messages_count (mbox, NULL);
+  if (psize)
+    *psize = mpd->total_size;
+  return status;
+}
+
+
+/* ------------------------------------------------------------------------- */
+/* POP3 message streams */
 
-  for (i = (int)mpd->id; i < mpd->pmessages_count; mpd->id = ++i)
+static void
+pop_stream_drain (mu_stream_t str)
+{
+  char buf[2048];
+  size_t size;
+
+  while (mu_stream_read (str, buf, sizeof buf, &size) == 0 && size)
+    ;
+}
+     
+static int
+_pop_message_get_stream (struct _pop3_message *mpm, mu_stream_t *pstr)
+{
+  int status;
+  struct _pop3_mailbox *mpd = mpm->mpd;
+  
+  if (!(mpm->flags & _POP3_MSG_CACHED))
     {
-      if (mu_message_get_attribute (mpd->pmessages[i]->message, &attr) == 0)
+      mu_stream_t stream;
+      mu_off_t size;
+      
+      status = mu_pop3_retr (mpd->pop3, mpm->num, &stream);
+      if (status)
+       return status;
+
+      do
        {
-         if (mu_attribute_is_deleted (attr))
+         mu_stream_t flt;
+         
+         if (!mpd->cache)
            {
-             switch (mpd->state)
+             status = mu_temp_file_stream_create (&mpd->cache, NULL);
+             if (status)
+               /* FIXME: Try to recover first */
+               break;
+
+             status = mu_stream_open (mpd->cache);
+             if (status)
                {
-               case POP_NO_STATE:
-                 status = pop_writeline (mpd, "DELE %lu\r\n",
-                                         (unsigned long)
-                                           mpd->pmessages[i]->num);
-                 CHECK_ERROR (mpd, status);
-                 MU_DEBUG (mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-                 mpd->state = POP_DELE;
-
-               case POP_DELE:
-                 /* Send DELETE.  */
-                 status = pop_write (mpd);
-                 CHECK_EAGAIN (mpd, status);
-                 mpd->state = POP_DELE_ACK;
-
-               case POP_DELE_ACK:
-                 /* Ack Delete.  */
-                 status = pop_read_ack (mpd);
-                 CHECK_EAGAIN (mpd, status);
-                 MU_DEBUG (mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-                 if (mu_c_strncasecmp (mpd->buffer, "+OK", 3) != 0)
-                   {
-                     CHECK_ERROR (mpd, ERANGE);
-                   }
-                 mpd->state = POP_NO_STATE;
+                 mu_stream_destroy (&mpd->cache);
                  break;
+               }
+             mu_stream_set_buffer (mpd->cache, mu_buffer_full, 8192);
+           }
 
-               default:
-                 /* mu_error ("pop_expunge: unknown state); */
-                 break;
-               } /* switch (state) */
-           } /* if mu_attribute_is_deleted() */
-       } /* mu_message_get_attribute() */
-    } /* for */
-  CLEAR_STATE (mpd);
-  /* Invalidate.  But Really they should shutdown the channel POP protocol
-     is not meant for this like IMAP.  */
-  mpd->is_updated = 0;
-  return 0;
+         status = mu_stream_size (mpd->cache, &mpm->offset);
+         if (status)
+           break;
+
+         status = mu_filter_create (&flt, stream, "CRLF", MU_FILTER_DECODE,
+                                    MU_STREAM_READ);
+         if (status)
+           break;
+
+         status = mu_stream_copy (mpd->cache, flt, 0, &size);
+
+         mu_stream_destroy (&flt);
+       }
+      while (0);
+
+      if (status)
+       {
+         pop_stream_drain (stream);
+         mu_stream_unref (stream);
+         return status;
+       }
+
+      mu_stream_unref (stream);
+
+      mpm->message_size = size; /* FIXME: Possible overflow. */
+
+      mpm->flags |= _POP3_MSG_CACHED | _POP3_MSG_SIZE;
+    }
+  return mu_streamref_create_abridged (pstr, mpd->cache,
+                                      mpm->offset,
+                                      mpm->offset + mpm->message_size - 1);
 }
 
-/* Mailbox size ? It is part of the STAT command */
 static int
-pop_get_size (mu_mailbox_t mbox, mu_off_t *psize)
+pop_message_get_stream (mu_message_t msg, mu_stream_t *pstr)
 {
-  pop_data_t mpd = mbox->data;
-  int status = 0;
+  struct _pop3_message *mpm = mu_message_get_owner (msg);
+  return _pop_message_get_stream (mpm, pstr);
+}
+        
+static int
+pop_scan_message (struct _pop3_message *mpm)
+{
+  int status;
+  mu_stream_t stream;
+  struct mu_message_scan scan;
 
-  if (mpd == NULL)
-    return EINVAL;
+  if (mpm->flags & _POP3_MSG_SCANNED)
+    return 0;
+  
+  status = _pop_message_get_stream (mpm, &stream);
+  if (status)
+    return status;
+      
+  scan.flags = MU_SCAN_SEEK | MU_SCAN_SIZE;
+  scan.message_start = 0;
+  scan.message_size = mpm->message_size;
+  status = mu_stream_scan_message (stream, &scan);
+  mu_stream_unref (stream);
 
-  if (!pop_is_updated (mbox))
-    status = pop_messages_count (mbox, &mpd->size);
-  if (psize)
-    *psize = mpd->size;
+  if (status == 0)
+    {
+      mpm->body_start = scan.body_start;
+      mpm->body_end = scan.body_end;
+      mpm->header_lines = scan.header_lines;
+      mpm->body_lines = scan.body_lines;
+      if (!(mpm->flags & _POP3_MSG_ATTRSET))
+       {
+         mpm->attr_flags = scan.attr_flags;
+         mpm->flags |= _POP3_MSG_ATTRSET;
+       }
+
+      mpm->flags |= _POP3_MSG_SCANNED;
+    }
+  
   return status;
 }
 
-/* Form the RFC:
-   "It is important to note that the octet count for a message on the
-   server host may differ from the octet count assigned to that message
-   due to local conventions for designating end-of-line.  Usually,
-   during the AUTHORIZATION state of the POP3 session, the POP3 server
-   can calculate the size of each message in octets when it opens the
-   maildrop.  For example, if the POP3 server host internally represents
-   end-of-line as a single character, then the POP3 server simply counts
-   each occurrence of this character in a message as two octets."
-
-   This is not perfect if we do not know the number of lines in the message
-   then the octets returned will not be correct so we do our best.
- */
+
 static int
 pop_message_size (mu_message_t msg, size_t *psize)
 {
-  pop_message_t mpm = mu_message_get_owner (msg);
-  pop_data_t mpd;
-  int status = 0;
-  void *func = (void *)pop_message_size;
-  size_t num;
+  struct _pop3_message *mpm = mu_message_get_owner (msg);
+  struct _pop3_mailbox *mpd = mpm->mpd;
 
   if (mpm == NULL)
     return EINVAL;
 
-  /* Did we have it already ?  */
-  if (mpm->mu_message_size != 0)
-    {
-      *psize = mpm->mu_message_size;
-      return 0;
-    }
-
-  mpd = mpm->mpd;
-  /* Busy ? */
-  CHECK_BUSY (mpd->mbox, mpd, func, msg);
-
-  /* Get the size.  */
-  switch (mpd->state)
+  if (!(mpm->flags & _POP3_MSG_SIZE))
     {
-    case POP_NO_STATE:
-      status = pop_writeline (mpd, "LIST %lu\r\n", (unsigned long) mpm->num);
-      CHECK_ERROR (mpd, status);
-      MU_DEBUG (mpd->mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-      mpd->state = POP_LIST;
-
-    case POP_LIST:
-      /* Send the LIST.  */
-      status = pop_write (mpd);
-      CHECK_EAGAIN (mpd, status);
-      mpd->state = POP_LIST_ACK;
-
-    case POP_LIST_ACK:
-      /* Resp from LIST. */
-      status = pop_read_ack (mpd);
-      CHECK_EAGAIN (mpd, status);
-      MU_DEBUG (mpd->mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-      break;
-
-    default:
-      /*
-       mu_error ("pop_message_size: unknown state");
-      */
-      break;
+      /* FIXME: The size obtained this way may differ from the actual one
+        by the number of lines in the message. */
+      int status = mu_pop3_list (mpd->pop3, mpm->num, &mpm->message_size);
+      if (status)
+       return status;
+      mpm->flags |= _POP3_MSG_SIZE;
     }
-
-  /* FIXME */
-  status = parse_answer0 (mpd->buffer, &num, &mpm->mu_message_size);
-  CLEAR_STATE (mpd);
-
-  if (status != 0)
-    return MU_ERR_PARSE;
-
-  /* The size of the message is with the extra '\r' octet for everyline.
-     Substract to get, hopefully, a good count.  */
   if (psize)
-    *psize = mpm->mu_message_size - (mpm->header_lines + mpm->body_lines);
+    *psize = mpm->message_size;
   return 0;
 }
 
-/* Another source of trouble, POP only gives the size of the message
-   not the size of subparts like headers, body etc .. Again we're doing
-   our best with what we know but the only way to get a precise number
-   is by dowloading the whole message.  */
 static int
-pop_body_size (mu_body_t body, size_t *psize)
+pop_create_message (struct _pop3_message *mpm, struct _pop3_mailbox *mpd)
 {
-  mu_message_t msg = mu_body_get_owner (body);
-  pop_message_t mpm = mu_message_get_owner (msg);
+  int status;
+  mu_message_t msg;
+  
+  status = mu_message_create (&msg, mpm);
+  if (status)
+    return status;
 
-  if (mpm == NULL)
-    return EINVAL;
+  mu_message_set_get_stream (msg, pop_message_get_stream, mpm);
+  mu_message_set_size (msg, pop_message_size, mpm);
+  mpm->message = msg;
+  return 0;
+}
 
-  /* Did we have it already ?  */
-  if (mpm->body_size != 0)
+
+/* ------------------------------------------------------------------------- */
+/* Header */
+
+int
+pop_header_blurb (mu_stream_t stream, size_t maxlines,
+                 char **pbuf, size_t *plen)
+{
+  int status;
+  mu_opool_t opool;
+  size_t size = 0;
+  char *buf = NULL;
+  size_t n;
+  size_t nlines = 0;
+  
+  status = mu_opool_create (&opool, 0);
+  if (status)
+    return status;
+      
+  while ((status = mu_stream_getline (stream, &buf, &size, &n)) == 0 && n > 0)
     {
-      *psize = mpm->body_size;
+      size_t len = mu_rtrim_cset (buf, "\r\n");
+      if (len == 0)
+       break;
+      mu_opool_append (opool, buf, len);
+      mu_opool_append_char (opool, '\n');
+      if (maxlines && ++nlines >= maxlines)
+       break;
     }
-  else if (mpm->mu_message_size != 0)
+      
+  if (status == 0)
     {
-      /* Take a guest.  */
-      *psize = mpm->mu_message_size - mpm->header_size - mpm->body_lines;
+      n = mu_opool_size (opool);
+      if (n > size)
+       {
+         char *p = realloc (buf, n);
+         if (!p)
+           {
+             free (buf);
+             status = ENOMEM;
+           }
+         else
+           buf = p;
+       }
+    }
+
+  if (status == 0)
+    {
+      mu_opool_copy (opool, buf, n);
+      *pbuf = buf;
+      *plen = n;
     }
   else
-    *psize = 0;
+    free (buf);
+  mu_opool_destroy (&opool);
 
   return 0;
 }
 
-/* Not know until the whole message get downloaded.  */
 static int
-pop_body_lines (mu_body_t body, size_t *plines)
+pop_header_fill (void *data, char **pbuf, size_t *plen)
 {
-  mu_message_t msg = mu_body_get_owner (body);
-  pop_message_t mpm = mu_message_get_owner (msg);
-  if (mpm == NULL)
-    return EINVAL;
-  if (plines)
-    *plines = mpm->body_lines;
+  struct _pop3_message *mpm = data;
+  struct _pop3_mailbox *mpd = mpm->mpd;
+  mu_stream_t stream;
+  int status;
+
+  if (mpm->flags & _POP3_MSG_SCANNED)
+    status = _pop_message_get_stream (mpm, &stream);
+  else
+    {
+      status = mu_pop3_top (mpd->pop3, mpm->num, 0, &stream);
+      if (status == 0)
+       {
+         status = pop_header_blurb (stream, 0, pbuf, plen);
+         if (!mu_stream_eof (stream))
+           pop_stream_drain (stream);
+         mu_stream_destroy (&stream);
+         return status;
+       }
+      else
+       status = _pop_message_get_stream (mpm, &stream);
+    }
+
+  status = pop_header_blurb (stream, mpm->header_lines, pbuf, plen);
+  mu_stream_destroy (&stream);
+  return status;
+}
+
+static int
+pop_create_header (struct _pop3_message *mpm)
+{
+  int status;
+  mu_header_t header = NULL;
+
+  status = mu_header_create (&header, NULL, 0);
+  if (status)
+    return status;
+  mu_header_set_fill (header, pop_header_fill, mpm);
+  mu_message_set_header (mpm->message, header, mpm);
   return 0;
 }
 
-/* Pop does not have any command for this, We fake by reading the "Status: "
-   header.  But this is hackish some POP server(Qpopper) skip it.  Also
-   because we call mu_header_get_value the function may return EAGAIN... 
uncool.
-   To put it another way, many servers simply remove the "Status:" header
-   field, when you dowload a message, so a message will always look like
-   new even if you already read it.  There is also no way to set an attribute
-   on remote mailbox via the POP server and many server once you do a RETR
-   and in some cases a TOP will mark the message as read; "Status: RO"
-   or maybe worst some ISP configure there servers to delete after
-   the RETR some go as much as deleting after the TOP, since technicaly
-   you can download a message via TOP without RET'reiving it.  */
+
+/* ------------------------------------------------------------------------- */
+/* Attributes */
+
+/* There is no POP3 command to return message attributes, therefore we
+   have to recurse to reading the "Status:" header.  Unfortunately, some
+   servers remove it when you dowload a message, and in this case a message
+   will always look like new even if you already read it.  There is also
+   no way to set an attribute on remote mailbox via the POP server and
+   many server once you do a RETR (and in some cases a TOP) will mark the
+   message as read (Status: RO).  Even worse, some servers may be configured
+   to delete after the RETR, and some go as much as deleting after the TOP,
+   since technicaly you can download a message via TOP without RETR'eiving
+   it.  */
 static int
 pop_get_attribute (mu_attribute_t attr, int *pflags)
 {
-  mu_message_t msg = mu_attribute_get_owner (attr);
-  pop_message_t mpm = mu_message_get_owner (msg);
+  struct _pop3_message *mpm = mu_attribute_get_owner (attr);
   char hdr_status[64];
   mu_header_t header = NULL;
 
   if (mpm == NULL || pflags == NULL)
     return EINVAL;
-  if (mpm->attr_flags == 0)
+  if (!(mpm->flags & _POP3_MSG_ATTRSET))
     {
       hdr_status[0] = '\0';
+
       mu_message_get_header (mpm->message, &header);
-      mu_header_get_value (header, "Status", hdr_status, sizeof hdr_status, 
NULL);
-      mu_string_to_flags (hdr_status, &(mpm->attr_flags));
+      mu_header_get_value (header, MU_HEADER_STATUS,
+                          hdr_status, sizeof hdr_status, NULL);
+      mu_string_to_flags (hdr_status, &mpm->attr_flags);
     }
   *pflags = mpm->attr_flags;
   return 0;
@@ -1577,596 +642,322 @@ pop_get_attribute (mu_attribute_t attr, int *pflags)
 static int
 pop_set_attribute (mu_attribute_t attr, int flags)
 {
-  mu_message_t msg = mu_attribute_get_owner (attr);
-  pop_message_t mpm = mu_message_get_owner (msg);
+  struct _pop3_message *mpm = mu_attribute_get_owner (attr);
 
   if (mpm == NULL)
     return EINVAL;
   mpm->attr_flags |= flags;
+  mpm->flags |= _POP3_MSG_ATTRSET;
   return 0;
 }
 
 static int
 pop_unset_attribute (mu_attribute_t attr, int flags)
 {
-  mu_message_t msg = mu_attribute_get_owner (attr);
-  pop_message_t mpm = mu_message_get_owner (msg);
+  struct _pop3_message *mpm = mu_attribute_get_owner (attr);
 
   if (mpm == NULL)
     return EINVAL;
   mpm->attr_flags &= ~flags;
+  mpm->flags |= _POP3_MSG_ATTRSET;
   return 0;
 }
 
-/* Stub to call the fd from body object.  */
 static int
-pop_body_transport (mu_stream_t stream, mu_transport_t *ptr, mu_transport_t 
*ptr2)
+pop_create_attribute (struct _pop3_message *mpm)
+{
+  int status;
+  mu_attribute_t attribute;
+  
+  status = mu_attribute_create (&attribute, mpm);
+  if (status)
+    return status;
+
+  mu_attribute_set_get_flags (attribute, pop_get_attribute, mpm);
+  mu_attribute_set_set_flags (attribute, pop_set_attribute, mpm);
+  mu_attribute_set_unset_flags (attribute, pop_unset_attribute, mpm);
+  mu_message_set_attribute (mpm->message, attribute, mpm);
+  return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+/* Body */
+
+int
+pop_body_get_stream (mu_body_t body, mu_stream_t *pstr)
 {
-  mu_body_t body = mu_stream_get_owner (stream);
-  mu_message_t msg = mu_body_get_owner (body);
-  pop_message_t mpm = mu_message_get_owner (msg);
-  return pop_get_transport2 (mpm, ptr, ptr2);
+  struct _pop3_message *mpm = mu_body_get_owner (body);
+  struct _pop3_mailbox *mpd = mpm->mpd;
+  int status = pop_scan_message (mpm);
+  if (status)
+    return status;
+  return mu_streamref_create_abridged (pstr, mpd->cache,
+                                      mpm->offset + mpm->body_start,
+                                      mpm->offset + mpm->body_end - 1);
 }
 
-/* Stub to call the fd from message object.  */
 static int
-pop_message_transport (mu_stream_t stream, mu_transport_t *ptr, mu_transport_t 
*ptr2)
+pop_body_size (mu_body_t body, size_t *psize)
 {
-  mu_message_t msg = mu_stream_get_owner (stream);
-  pop_message_t mpm = mu_message_get_owner (msg);
-  return pop_get_transport2 (mpm, ptr, ptr2);
+  struct _pop3_message *mpm = mu_body_get_owner (body);
+  int status = pop_scan_message (mpm);
+  if (status)
+    return status;
+  *psize = mpm->body_end - mpm->body_start;
+  return 0;
 }
 
 static int
-pop_get_transport2 (pop_message_t mpm, mu_transport_t *ptr, mu_transport_t 
*ptr2)
+pop_body_lines (mu_body_t body, size_t *plines)
 {
-  if (mpm && mpm->mpd && mpm->mpd->mbox)
-       return mu_stream_get_transport2 (mpm->mpd->mbox->stream, ptr, ptr2);
-  return EINVAL;
+  struct _pop3_message *mpm = mu_body_get_owner (body);
+  int status = pop_scan_message (mpm);
+  if (status)
+    return status;
+  *plines = mpm->body_lines;
+  return 0;
 }
 
 static int
-pop_uid (mu_message_t msg,  size_t *puid)
+pop_create_body (struct _pop3_message *mpm)
 {
-  pop_message_t mpm = mu_message_get_owner (msg);
-  if (puid)
-    *puid = mpm->num;
+  int status;
+  mu_body_t body = NULL;
+
+  status = mu_body_create (&body, mpm);
+  if (status)
+    return status;
+
+  mu_body_set_get_stream (body, pop_body_get_stream, mpm);
+  mu_body_set_size (body, pop_body_size, mpm);
+  mu_body_set_lines (body, pop_body_lines, mpm);
+
+  mu_message_set_body (mpm->message, body, mpm);
+
   return 0;
 }
 
-/* Get the UIDL.  The client should be prepared, since it may fail.  UIDL is
-   optional on many POP servers.
-   FIXME:  We should check the "mpd->capa & CAPA_UIDL" and fall back to
-   a md5 scheme ? Or maybe check for "X-UIDL" a la Qpopper ?  */
+
+/* FIXME: change prototype to avoid fixed size buffer */
 static int
 pop_uidl (mu_message_t msg, char *buffer, size_t buflen, size_t *pnwriten)
 {
-  pop_message_t mpm = mu_message_get_owner (msg);
-  pop_data_t mpd;
-  int status = 0;
-  void *func = (void *)pop_uidl;
-  size_t num;
-  char uniq[MU_UIDL_BUFFER_SIZE];
-
-  if (mpm == NULL)
-    return EINVAL;
-
-  /* Is it cached ?  */
-  if (mpm->uidl)
+  struct _pop3_message *mpm = mu_message_get_owner (msg);
+  struct _pop3_mailbox *mpd = mpm->mpd;
+  size_t len;
+  
+  if (!mpm->uidl)
     {
-      size_t len = strlen (mpm->uidl);
-      if (buffer)
+      if (mu_pop3_capa_test (mpd->pop3, "UIDL", NULL) == 0)
        {
-         buflen--; /* Leave space for the null.  */
-         buflen = (len > buflen) ? buflen : len;
-         memcpy (buffer, mpm->uidl, buflen);
-         buffer[buflen] = '\0';
+         int status = mu_pop3_uidl (mpd->pop3, mpm->num, &mpm->uidl);
+         if (status)
+           return status;
        }
       else
-       buflen = len;
-      if (pnwriten)
-       *pnwriten = buflen;
-      return 0;
+       return ENOSYS;
     }
 
-  mpd = mpm->mpd;
-
-  /* Busy ? */
-  CHECK_BUSY (mpd->mbox, mpd, func, 0);
-
-  /* Get the UIDL.  */
-  switch (mpd->state)
+  len = strlen (mpm->uidl);
+  if (buffer)
     {
-    case POP_NO_STATE:
-      status = pop_writeline (mpd, "UIDL %lu\r\n", (unsigned long) mpm->num);
-      CHECK_ERROR (mpd, status);
-      MU_DEBUG (mpd->mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-      mpd->state = POP_UIDL;
-
-    case POP_UIDL:
-      /* Send the UIDL.  */
-      status = pop_write (mpd);
-      CHECK_EAGAIN (mpd, status);
-      mpd->state = POP_UIDL_ACK;
-
-    case POP_UIDL_ACK:
-      /* Resp from UIDL. */
-      status = pop_read_ack (mpd);
-      CHECK_EAGAIN (mpd, status);
-      MU_DEBUG (mpd->mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-      break;
-
-    default:
-      /*
-       mu_error ("pop_uidl: unknown state");
-      */
-      break;
-    }
-
-  /* FIXME:  I should cache the result.  */
-  *uniq = '\0';
-  status = parse_answer1 (mpd->buffer, &num, uniq, sizeof uniq);
-  if (status)
-    {
-      status = MU_ERR_PARSE;
-      buflen = 0;
+      buflen--; /* Leave space for the null.  */
+      buflen = (len > buflen) ? buflen : len;
+      memcpy (buffer, mpm->uidl, buflen);
+      buffer[buflen] = 0;
     }
   else
-    {
-      num = strlen (uniq);
-      uniq[num - 1] = '\0'; /* Nuke newline.  */
-      if (buffer)
-       {
-         buflen--; /* Leave space for the null.  */
-         buflen = (buflen < num) ? buflen : num;
-         memcpy (buffer, uniq, buflen);
-         buffer [buflen] = '\0';
-       }
-      else
-       buflen = num - 1; /* Do not count newline.  */
-      mpm->uidl = strdup (uniq);
-      status = 0;
-    }
-
-  CLEAR_STATE (mpd);
-
+    buflen = len;
   if (pnwriten)
     *pnwriten = buflen;
-  return status;
+  return 0;
 }
 
-/* How we retrieve the headers.  If it fails we jump to the pop_retr()
-   code i.e. send a RETR and skip the body, ugly.
-   NOTE: if the offset is different, flag an error, offset is meaningless
-   on a socket but we better warn them, some stuff like mu_mime_t may try to
-   read ahead, for example for the headers.  */
 static int
-pop_top (mu_header_t header, char *buffer, size_t buflen,
-        mu_off_t offset, size_t *pnread)
+pop_uid (mu_message_t msg,  size_t *puid)
 {
-  mu_message_t msg = mu_header_get_owner (header);
-  pop_message_t mpm = mu_message_get_owner (msg);
-  pop_data_t mpd;
-  size_t nread = 0;
-  int status = 0;
-  void *func = (void *)pop_top;
-
-  if (mpm == NULL)
-    return EINVAL;
+  struct _pop3_message *mpm = mu_message_get_owner (msg);
+  if (puid)
+    *puid = mpm->num;
+  return 0;
+}
 
-  mpd = mpm->mpd;
+static int
+pop_get_message (mu_mailbox_t mbox, size_t msgno, mu_message_t *pmsg)
+{
+  struct _pop3_mailbox *mpd = mbox->data;
+  struct _pop3_message *mpm;
+  int status;
 
-  /* Busy ? */
-  CHECK_BUSY (mpd->mbox, mpd, func, msg);
+  /* Sanity checks. */
+  if (pmsg == NULL || mpd == NULL)
+    return EINVAL;
 
-  /* We start fresh then reset the sizes.  */
-  if (mpd->state == POP_NO_STATE)
-    mpm->header_size = 0;
+  /* If we did not start a scanning yet do it now.  */
+  if (!pop_is_updated (mbox))
+    pop_scan (mbox, 1, NULL);
 
-  /* Throw an error if trying to seek back.  */
-  if ((size_t)offset < mpm->header_size)
-    return ESPIPE;
+  if (msgno > mpd->msg_count)
+    return EINVAL;
 
-  /* Get the header.  */
-  switch (mpd->state)
+  if (!mpd->msg)
     {
-    case POP_NO_STATE:
-      if (mpd->capa & CAPA_TOP)
-        {
-         status = pop_writeline (mpd, "TOP %lu 0\r\n",
-                                 (unsigned long) mpm->num);
-         CHECK_ERROR (mpd, status);
-         MU_DEBUG (mpd->mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-         mpd->state = POP_TOP;
-       }
-      else /* Fall back to RETR call.  */
-        {
-         mpd->state = POP_NO_STATE;
-         mpm->skip_header = 0;
-         mpm->skip_body = 1;
-         return pop_retr (mpm, buffer, buflen, offset, pnread);
-        }
-
-    case POP_TOP:
-      /* Send the TOP.  */
-      status = pop_write (mpd);
-      CHECK_EAGAIN (mpd, status);
-      mpd->state = POP_TOP_ACK;
-
-    case POP_TOP_ACK:
-      /* Ack from TOP. */
-      status = pop_read_ack (mpd);
-      CHECK_EAGAIN (mpd, status);
-      MU_DEBUG (mpd->mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-      if (mu_c_strncasecmp (mpd->buffer, "+OK", 3) != 0)
-       CHECK_ERROR (mpd, EINVAL);
-      mpd->state = POP_TOP_RX;
-
-    case POP_TOP_RX:
-      /* Get the header.  */
-      do
-       {
-         /* Seek in position.  */
-         ssize_t pos = offset - mpm->header_size;
-         /* Do we need to fill up.  */
-         if (mpd->nl == NULL || mpd->ptr == mpd->buffer)
-           {
-             status = pop_readline (mpd);
-             CHECK_EAGAIN (mpd, status);
-             mpm->header_lines++;
-           }
-         /* If we have to skip some data to get to the offset.  */
-         if (pos > 0)
-           nread = fill_buffer (mpd, NULL, pos);
-         else
-           nread = fill_buffer (mpd, buffer, buflen);
-         mpm->header_size += nread;
-       }
-      while (nread > 0 && (size_t)offset > mpm->header_size);
-      break;
-
-    default:
-      /* Probaly TOP was not supported so we have fall back to RETR.  */
-      mpm->skip_header = 0;
-      mpm->skip_body = 1;
-      return pop_retr (mpm, buffer, buflen, offset, pnread);
-    } /* switch (state) */
-
-  if (nread == 0)
+      mpd->msg = calloc (mpd->msg_count, sizeof (mpd->msg[0]));
+      if (!mpd->msg)
+       return ENOMEM;
+    }
+  if (mpd->msg[msgno - 1])
     {
-      CLEAR_STATE (mpd);
+      *pmsg = mpd->msg[msgno - 1]->message;
+      return 0;
     }
-  if (pnread)
-    *pnread = nread;
-  return 0;
-}
-
-/* This is no longer use, see pop_top to retreive headers, we still
-   keep it around for debugging purposes.  */
-#if 0
-/* Stub to call pop_retr ().   Call form the stream object of the header.  */
-static int
-pop_header_read (mu_header_t header, char *buffer, size_t buflen, mu_off_t 
offset,
-                size_t *pnread)
-{
-  mu_message_t msg = mu_header_get_owner (header);
-  pop_message_t mpm = mu_message_get_owner (msg);
-  pop_data_t mpd;
-  void *func = (void *)pop_header_read;
 
+  mpm = calloc (1, sizeof (*mpm));
   if (mpm == NULL)
-    return EINVAL;
+    return ENOMEM;
 
-  mpd = mpm->mpd;
+  /* Back pointer.  */
+  mpm->mpd = mpd;
+  mpm->num = msgno;
+  
+  status = pop_create_message (mpm, mpd);
+  if (status)
+    {
+      free (mpm);
+      return status;
+    }
 
-  /* Busy ? */
-  CHECK_BUSY (mpd->mbox, mpd, func, msg);
+  do
+    {
+      status = pop_create_header (mpm);
+      if (status)
+       break;
+      status = pop_create_attribute (mpm);
+      if (status)
+       break;
+      status = pop_create_body (mpm);
+    }
+  while (0);
+  
+  if (status)
+    {
+      mu_message_destroy (&mpm->message, mpm);
+      free (mpm);
+      return status;
+    }
 
-  /* We start fresh then reset the sizes.  */
-  if (mpd->state == POP_NO_STATE)
-    mpm->header_size = mpm->inbody = 0;
+  if (mu_pop3_capa_test (mpd->pop3, "UIDL", NULL) == 0)
+    mu_message_set_uidl (mpm->message, pop_uidl, mpm);
 
-  /* Throw an error if trying to seek back.  */
-  if ((size_t)offset < mpm->header_size)
-    return ESPIPE;
+  mu_message_set_uid (mpm->message, pop_uid, mpm);
 
-  mpm->skip_header = 0;
-  mpm->skip_body = 1;
-  return pop_retr (mpm, buffer, buflen, offset, pnread);
+  mpd->msg[msgno - 1] = mpm;
+  mu_message_set_mailbox (mpm->message, mbox, mpm);
+  *pmsg = mpm->message;
+  return 0;
 }
-#endif
-
-/* Stub to call pop_retr (). Call from the stream object of the body.  */
+
 static int
-pop_body_read (mu_stream_t is, char *buffer, size_t buflen, mu_off_t offset,
-              size_t *pnread)
+pop_expunge (mu_mailbox_t mbox)
 {
-  mu_body_t body = mu_stream_get_owner (is);
-  mu_message_t msg = mu_body_get_owner (body);
-  pop_message_t mpm = mu_message_get_owner (msg);
-  pop_data_t mpd;
-  void *func = (void *)pop_body_read;
-
-  if (mpm == NULL)
+  struct _pop3_mailbox *mpd = mbox->data;
+  int status = 0;
+  size_t i;
+  
+  if (mpd == NULL)
     return EINVAL;
 
-  mpd = mpm->mpd;
-
-  /* Busy ? */
-  CHECK_BUSY (mpd->mbox, mpd, func, msg);
-
-  /* We start fresh then reset the sizes.  */
-  if (mpd->state == POP_NO_STATE)
-    mpm->body_size = mpm->inbody = 0;
-
-  /* Can not seek back this a stream socket.  */
-  if ((size_t)offset < mpm->body_size)
-    return ESPIPE;
+  if (!mpd->msg)
+    return 0;
+  
+  for (i = 0; i < mpd->msg_count; i++)
+    {
+      struct _pop3_message *mpm = mpd->msg[i];
 
-  mpm->skip_header = 1;
-  mpm->skip_body = 0;
-  return pop_retr (mpm, buffer, buflen, offset, pnread);
+      if (mpm &&
+         (mpm->flags & _POP3_MSG_ATTRSET) &&
+         (mpm->attr_flags & MU_ATTRIBUTE_DELETED))
+       {
+         status = mu_pop3_dele (mpd->pop3, mpm->num);
+         if (status)
+           break;
+       }
+    }
+  return 0;
 }
+
+/* ------------------------------------------------------------------------- */
+/* Initialization */
 
-/* Stub to call pop_retr (), calling from the stream object of a message.  */
 static int
-pop_message_read (mu_stream_t is, char *buffer, size_t buflen, mu_off_t offset,
-                 size_t *pnread)
+_pop3_mailbox_init (mu_mailbox_t mbox, int pops)
 {
-  mu_message_t msg = mu_stream_get_owner (is);
-  pop_message_t mpm = mu_message_get_owner (msg);
-  pop_data_t mpd;
-  void *func = (void *)pop_message_read;
+  struct _pop3_mailbox *mpd;
+  int status = 0;
 
-  if (mpm == NULL)
-    return EINVAL;
+  /* Allocate specifics for pop data.  */
+  mpd = mbox->data = calloc (1, sizeof (*mpd));
+  if (mbox->data == NULL)
+    return ENOMEM;
 
-  mpd = mpm->mpd;
+  mpd->pop3 = NULL;
+  
+  mpd->mbox = mbox;            /* Back pointer.  */
+  mpd->pops = pops;
 
-  /* Busy ? */
-  CHECK_BUSY (mpd->mbox, mpd, func, msg);
+  /* Initialize the structure.  */
+  mbox->_destroy = pop_destroy;
 
-  /* We start fresh then reset the sizes.  */
-  if (mpd->state == POP_NO_STATE)
-    mpm->header_size = mpm->body_size = mpm->inbody = 0;
+  mbox->_open = pop_open;
+  mbox->_close = pop_close;
+  mbox->_messages_count = pop_messages_count;
+  /* FIXME: There is no way to retrieve the number of recent messages via
+     POP3 protocol, so we consider all messages recent. */
+  mbox->_messages_recent = pop_messages_count;
+  mbox->_is_updated = pop_is_updated;
+  mbox->_scan = pop_scan;
+  mbox->_message_unseen = pop_message_unseen;
+  mbox->_get_size = pop_get_size;
+  
+  /* Messages.  */
+  mbox->_get_message = pop_get_message;
+  mbox->_expunge = pop_expunge;
 
-  /* Can not seek back this is a stream socket.  */
-  if ((size_t)offset < (mpm->body_size + mpm->header_size))
-    return ESPIPE;
+  /* Set our properties.  */
+  {
+    mu_property_t property = NULL;
+    mu_mailbox_get_property (mbox, &property);
+    mu_property_set_value (property, "TYPE", "POP3", 1);
+  }
 
-  mpm->skip_header = mpm->skip_body = 0;
-  return pop_retr (mpm, buffer, buflen, offset, pnread);
+  /* Hack! POP does not really have a folder.  */
+  mbox->folder->data = mbox;
+  return status;
 }
 
-/* Little helper to fill the buffer without overflow.  */
-static int
-fill_buffer (pop_data_t mpd, char *buffer, size_t buflen)
+int
+_mailbox_pop_init (mu_mailbox_t mbox)
 {
-  int nleft, n, nread = 0;
-
-  /* How much we can copy ?  */
-  n = mpd->ptr - mpd->buffer;
-  nleft = buflen - n;
-
- /* We got more then requested.  */
-  if (nleft < 0)
-    {
-      size_t sentinel;
-      nread = buflen;
-      sentinel = mpd->ptr - (mpd->buffer + nread);
-      if (buffer)
-       memcpy (buffer, mpd->buffer, nread);
-      memmove (mpd->buffer, mpd->buffer + nread, sentinel);
-      mpd->ptr = mpd->buffer + sentinel;
-    }
-  else
-    {
-      /* Drain our buffer.  */;
-      nread = n;
-      if (buffer)
-       memcpy (buffer, mpd->buffer, nread);
-      mpd->ptr = mpd->buffer;
-    }
-
-  return nread;
+  return _pop3_mailbox_init (mbox, 0);
 }
 
-/* The heart of most funtions.  Send the RETR and skip different parts.  */
-static int
-pop_retr (pop_message_t mpm, char *buffer, size_t buflen,  
-          mu_off_t offset MU_ARG_UNUSED, size_t *pnread)
+int
+_mailbox_pops_init (mu_mailbox_t mbox)
 {
-  pop_data_t mpd;
-  size_t nread = 0;
-  int status = 0;
-  size_t oldbuflen = buflen;
-
-  mpd = mpm->mpd;
-
-  if (pnread)
-    *pnread = nread;
-
-  /*  Take care of the obvious.  */
-  if (buffer == NULL || buflen == 0)
-    {
-      CLEAR_STATE (mpd);
-      return 0;
-    }
-
-  /* pop_retr() is not call directly so we assume that the locks were set.  */
-
-  switch (mpd->state)
-    {
-    case POP_NO_STATE:
-      mpm->body_lines = mpm->body_size = 0;
-      status = pop_writeline (mpd, "RETR %lu\r\n",
-                             (unsigned long) mpm->num);
-      MU_DEBUG (mpd->mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-      CHECK_ERROR (mpd, status);
-      mpd->state = POP_RETR;
-
-    case POP_RETR:
-      /* Send the RETR command.  */
-      status = pop_write (mpd);
-      CHECK_EAGAIN (mpd, status);
-      mpd->state = POP_RETR_ACK;
-
-    case POP_RETR_ACK:
-      /* RETR ACK.  */
-      status = pop_read_ack (mpd);
-      CHECK_EAGAIN (mpd, status);
-      MU_DEBUG (mpd->mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-
-      if (mu_c_strncasecmp (mpd->buffer, "+OK", 3) != 0)
-       {
-         CHECK_ERROR (mpd, EACCES);
-       }
-      mpd->state = POP_RETR_RX_HDR;
-
-    case POP_RETR_RX_HDR:
-      /* Skip/Take the header.  */
-      while (!mpm->inbody)
-        {
-         /* Do we need to fill up.  */
-         if (mpd->nl == NULL || mpd->ptr == mpd->buffer)
-           {
-             status = pop_readline (mpd);
-             if (status != 0)
-               {
-                 /* Do we have something in the buffer flush it first.  */
-                 if (buflen != oldbuflen)
-                   return 0;
-                 CHECK_EAGAIN (mpd, status);
-               }
-             mpm->header_lines++;
-           }
-         /* Oops !! Hello houston we have a major problem here.  */
-         if (mpd->buffer[0] == '\0')
-           {
-             /* Still Do the right thing.  */
-             if (buflen != oldbuflen)
-               {
-                 CLEAR_STATE (mpd);
-               }
-             else
-               mpd->state = POP_STATE_DONE;
-             return 0;
-           }
-         /* The problem is that we are using RETR instead of TOP to retreive
-            headers, i.e the server contacted does not support it.  So we
-            have to make sure that the next line really means end of the
-            headers.  Still some cases we may loose.  But 99.9% of POPD
-            encounter support TOP.  In the 0.1% case get GNU pop3d, or the
-            hack below will suffice.  */
-         if (mpd->buffer[0] == '\n' && mpd->buffer[1] == '\0')
-           mpm->inbody = 1; /* break out of the while.  */
-         if (!mpm->skip_header)
-           {
-             ssize_t pos = offset  - mpm->header_size;
-             if (pos > 0)
-               {
-                 nread = fill_buffer (mpd, NULL, pos);
-                 mpm->header_size += nread;
-               }
-             else
-               {
-                 nread = fill_buffer (mpd, buffer, buflen);
-                 mpm->header_size += nread;
-                 if (pnread)
-                   *pnread += nread;
-                 buflen -= nread ;
-                 if (buflen > 0)
-                   buffer += nread;
-                 else
-                   return 0;
-               }
-           }
-         else
-           mpd->ptr = mpd->buffer;
-       }
-      mpd->state = POP_RETR_RX_BODY;
-
-    case POP_RETR_RX_BODY:
-      /* Start/Take the body.  */
-      while (mpm->inbody)
-       {
-         /* Do we need to fill up.  */
-         if (mpd->nl == NULL || mpd->ptr == mpd->buffer)
-           {
-             status = pop_readline (mpd);
-             if (status != 0)
-               {
-                 /* Flush The Buffer ?  */
-                 if (buflen != oldbuflen)
-                   return 0;
-                 CHECK_EAGAIN (mpd, status);
-               }
-             mpm->body_lines++;
-           }
-
-           if (mpd->buffer[0] == '\0')
-             mpm->inbody = 0; /* Breakout of the while.  */
-
-           if (!mpm->skip_body)
-             {
-               /* If we did not skip the header, it means that we are
-                  downloading the entire message and the mu_header_size should 
be
-                  part of the offset count.  */
-               ssize_t pos = offset - (mpm->body_size + ((mpm->skip_header) ?
-                                       0 : mpm->header_size));
-               if (pos > 0)
-                 {
-                   nread = fill_buffer (mpd, NULL, pos);
-                   mpm->body_size += nread;
-                 }
-               else
-                 {
-                   nread = fill_buffer (mpd, buffer, buflen);
-                   mpm->body_size += nread;
-                   if (pnread)
-                     *pnread += nread;
-                   buflen -= nread ;
-                   if (buflen > 0)
-                     buffer += nread;
-                   else
-                     return 0;
-                 }
-             }
-           else
-             {
-               mpm->body_size += (mpd->ptr - mpd->buffer);
-               mpd->ptr = mpd->buffer;
-             }
-         }
-      mpm->mu_message_size = mpm->body_size + mpm->header_size;
-      mpd->state = POP_STATE_DONE;
-      /* Return here earlier, because we want to return nread = 0 to notify
-        the callee that we've finish, since there is already data
-        we have to return them first and _then_ tell them its finish.  If we
-        don't we will start over again by sending another RETR.  */
-      if (buflen != oldbuflen)
-       return 0;
-
-    case POP_STATE_DONE:
-      /* A convenient break, this is here we can return 0, we're done.  */
-
-    default:
-      /* mu_error ("pop_retr: unknown state"); */
-      break;
-    } /* Switch state.  */
-
-  CLEAR_STATE (mpd);
-  mpm->skip_header = mpm->skip_body = 0;
-  return 0;
+  return _pop3_mailbox_init (mbox, 1);
 }
 
+
+/* ------------------------------------------------------------------------- */
+/* Authentication */
+
 /* Extract the User from the URL or the ticket.  */
 static int
 pop_get_user (mu_authority_t auth)
 {
   mu_folder_t folder = mu_authority_get_owner (auth);
   mu_mailbox_t mbox = folder->data;
-  pop_data_t mpd = mbox->data;
+  struct _pop3_mailbox *mpd = mbox->data;
   mu_ticket_t ticket = NULL;
   int status;
   /*  Fetch the user from them.  */
@@ -2193,7 +984,7 @@ pop_get_passwd (mu_authority_t auth)
 {
   mu_folder_t folder = mu_authority_get_owner (auth);
   mu_mailbox_t mbox = folder->data;
-  pop_data_t mpd = mbox->data;
+  struct _pop3_mailbox *mpd = mbox->data;
   mu_ticket_t ticket = NULL;
   int status;
 
@@ -2210,217 +1001,60 @@ pop_get_passwd (mu_authority_t auth)
   return 0;
 }
 
-
-static char *
-pop_get_timestamp (pop_data_t mpd)
-{
-  char *right, *left;
-  char *timestamp = NULL;
-  size_t len;
-
-  len = strlen (mpd->greeting_banner);
-  right = memchr (mpd->greeting_banner, '<', len);
-  if (right)
-    {
-      len = len - (right - mpd->greeting_banner);
-      left = memchr (right, '>', len);
-      if (left)
-       {
-         len = left - right + 1;
-         timestamp = calloc (len + 1, 1);
-         if (timestamp != NULL)
-           {
-             memcpy (timestamp, right, len);
-           }
-       }
-    }
-  return timestamp;
-}
-
-/*  Make the MD5 string.  */
-static int
-pop_get_md5 (pop_data_t mpd)
+int
+_pop_apop (mu_authority_t auth)
 {
-  struct mu_md5_ctx md5context;
-  unsigned char md5digest[16];
-  char digest[64]; /* Really it just has to be 32 + 1(null).  */
-  char *tmp;
-  size_t n;
-  char *timestamp;
-
-  timestamp = pop_get_timestamp (mpd);
-  if (timestamp == NULL)
-    return EINVAL;
+  mu_folder_t folder = mu_authority_get_owner (auth);
+  mu_mailbox_t mbox = folder->data;
+  struct _pop3_mailbox *mpd = mbox->data;
+  int status;
+  
+  status = pop_get_user (auth);
+  if (status)
+    return status;
 
-  mu_md5_init_ctx (&md5context);
-  mu_md5_process_bytes (timestamp, strlen (timestamp), &md5context);
-  mu_md5_process_bytes (mu_secret_password (mpd->secret),
-                       mu_secret_length (mpd->secret),
-                       &md5context);
+  /* Fetch the secret from them.  */
+  status = pop_get_passwd (auth);
+  if (status)
+    return status;
+  status = mu_pop3_apop (mpd->pop3, mpd->user,
+                        mu_secret_password (mpd->secret));
   mu_secret_password_unref (mpd->secret);
   mu_secret_unref (mpd->secret);
   mpd->secret = NULL;
-  mu_md5_finish_ctx (&md5context, md5digest);
-  
-  for (tmp = digest, n = 0; n < 16; n++, tmp += 2)
-    sprintf (tmp, "%02x", md5digest[n]);
-  *tmp = '\0';
-  free (timestamp);
-  mpd->digest = strdup (digest);
-  return 0;
-}
-
-/* GRRRRR!!  We can not use sleep in the library since this we'll
-   muck up any alarm() done by the user.  */
-static int
-pop_sleep (int seconds)
-{
-  struct timeval tval;
-  tval.tv_sec = seconds;
-  tval.tv_usec = 0;
-  return select (1, NULL, NULL, NULL, &tval);
-}
-
-/* C99 says that a conforming implementation of snprintf () should return the
-   number of char that would have been call but many old GNU/Linux && BSD
-   implementations return -1 on error.  Worse QnX/Neutrino actually does not
-   put the terminal null char.  So let's try to cope.  */
-static int
-pop_writeline (pop_data_t mpd, const char *format, ...)
-{
-  int len;
-  va_list ap;
-  int done = 1;
-
-  if (mpd->buffer == NULL)
-    return EINVAL;
-  va_start(ap, format);
-  do
-    {
-      len = vsnprintf (mpd->buffer, mpd->buflen - 1, format, ap);
-      if (len < 0 || len >= (int)mpd->buflen
-         || !memchr (mpd->buffer, '\0', len + 1))
-       {
-         mpd->buflen *= 2;
-         mpd->buffer = realloc (mpd->buffer, mpd->buflen);
-         if (mpd->buffer == NULL)
-           return ENOMEM;
-         done = 0;
-       }
-      else
-       done = 1;
-    }
-  while (!done);
-  va_end(ap);
-  mpd->ptr = mpd->buffer + len;
-  return 0;
-}
-
-/* A socket may write less then expected and we have to cope with nonblocking.
-   if the write failed we keep track and restart where left.  */
-static int
-pop_write (pop_data_t mpd)
-{
-  int status = 0;
-  if (mpd->ptr > mpd->buffer)
-    {
-      size_t len;
-      size_t n = 0;
-      len = mpd->ptr - mpd->buffer;
-      status = mu_stream_write (mpd->mbox->stream, mpd->buffer, len, 0, &n);
-      if (status == 0)
-       {
-         memmove (mpd->buffer, mpd->buffer + n, len - n);
-         mpd->ptr -= n;
-       }
-    }
-  else
-    mpd->ptr = mpd->buffer;
+  free (mpd->user);
+  mpd->user = NULL;
   return status;
 }
 
-/* Call readline and reset the mpd->ptr to the buffer, signalling that we have
-   done the read to completion. */
-static int
-pop_read_ack (pop_data_t mpd)
-{
-  int status = pop_readline (mpd);
-  if (status == 0)
-    mpd->ptr = mpd->buffer;
-  return status;
-}
-
-/* Read a complete line form the pop server. Transform CRLF to LF, remove
-   the stuff byte termination octet ".", put a null in the buffer
-   when done.  */
-static int
-pop_readline (pop_data_t mpd)
+int
+_pop_user (mu_authority_t auth)
 {
-  size_t n = 0;
-  size_t total = mpd->ptr - mpd->buffer;
+  mu_folder_t folder = mu_authority_get_owner (auth);
+  mu_mailbox_t mbox = folder->data;
+  struct _pop3_mailbox *mpd = mbox->data;
   int status;
-
-  /* Must get a full line before bailing out.  */
-  do
-    {
-      status = mu_stream_readline (mpd->mbox->stream, mpd->buffer + total,
-                               mpd->buflen - total,  mpd->offset, &n);
-      if (status != 0)
-       return status;
-
-      /* The server went away:  It maybe a timeout and some pop server
-        does not send the -ERR.  Consider this like an error.  */
-      if (n == 0)
-       return EIO;
-
-      total += n;
-      mpd->offset += n;
-      mpd->nl = memchr (mpd->buffer, '\n', total);
-      if (mpd->nl == NULL)  /* Do we have a full line.  */
-       {
-         /* Allocate a bigger buffer ?  */
-         if (total >= mpd->buflen -1)
-           {
-             mpd->buflen *= 2;
-             mpd->buffer = realloc (mpd->buffer, mpd->buflen + 1);
-             if (mpd->buffer == NULL)
-               return ENOMEM;
-           }
-       }
-      mpd->ptr = mpd->buffer + total;
-    }
-  while (mpd->nl == NULL);
-
-  /* When examining a multi-line response, the client checks to see if the
-     line begins with the termination octet "."(DOT). If yes and if octets
-     other than CRLF follow, the first octet of the line (the termination
-     octet) is stripped away.  */
-  if (total >= 3  && mpd->buffer[0] == '.')
+  
+  status = pop_get_user (auth);
+  if (status)
+    return status;
+  status = mu_pop3_user (mpd->pop3, mpd->user);
+  if (status == 0)
     {
-      if (mpd->buffer[1] != '\r' && mpd->buffer[2] != '\n')
-       {
-         memmove (mpd->buffer, mpd->buffer + 1, total - 1);
-         mpd->ptr--;
-         mpd->nl--;
-       }
-      /* And if CRLF immediately follows the termination character, then the
-        response from the POP server is ended and the line containing
-        ".CRLF" is not considered part of the multi-line response.  */
-      else if (mpd->buffer[1] == '\r' && mpd->buffer[2] == '\n')
+      /* Fetch the secret from them.  */
+      status = pop_get_passwd (auth);
+      if (status == 0) 
        {
-         mpd->buffer[0] = '\0';
-         mpd->ptr = mpd->buffer;
-         mpd->nl = NULL;
+         status = mu_pop3_pass (mpd->pop3, mu_secret_password (mpd->secret));
+         mu_secret_password_unref (mpd->secret);
+         mu_secret_unref (mpd->secret);
+         mpd->secret = NULL;
        }
     }
-  /* \r\n --> \n\0, conversion.  */
-  if (mpd->nl > mpd->buffer)
-    {
-      *(mpd->nl - 1) = '\n';
-      *(mpd->nl) = '\0';
-      mpd->ptr = mpd->nl;
-    }
-  return 0;
+  free (mpd->user);
+  mpd->user = NULL;
+  return status;
 }
 
-#endif
+
+#endif /* ENABLE_POP */
diff --git a/libproto/pop/pop3_apop.c b/libproto/pop/pop3_apop.c
index 454c3e5..c358b93 100644
--- a/libproto/pop/pop3_apop.c
+++ b/libproto/pop/pop3_apop.c
@@ -39,15 +39,11 @@ mu_pop3_apop (mu_pop3_t pop3, const char *user, const char 
*secret)
 
   /* Sanity checks.  */
   if (pop3 == NULL || user == NULL || secret == NULL)
-    {
-      return EINVAL;
-    }
+    return EINVAL;
 
   /* The server did not offer a timestamp in the greeting, bailout early.  */
   if (pop3->timestamp == NULL)
-    {
-      return ENOTSUP;
-    }
+    return ENOTSUP;
 
   switch (pop3->state)
     {
@@ -61,35 +57,25 @@ mu_pop3_apop (mu_pop3_t pop3, const char *user, const char 
*secret)
        size_t n;
 
        mu_md5_init_ctx (&md5context);
-       mu_md5_process_bytes (pop3->timestamp, strlen (pop3->timestamp), 
&md5context);
+       mu_md5_process_bytes (pop3->timestamp, strlen (pop3->timestamp),
+                             &md5context);
        mu_md5_process_bytes (secret, strlen (secret), &md5context);
        mu_md5_finish_ctx (&md5context, md5digest);
        for (tmp = digest, n = 0; n < 16; n++, tmp += 2)
-         {
-           sprintf (tmp, "%02x", md5digest[n]);
-         }
+         sprintf (tmp, "%02x", md5digest[n]);
        *tmp = '\0';
 
        status = mu_pop3_writeline (pop3, "APOP %s %s\r\n", user, digest);
        /* Obscure the digest, for security reasons.  */
        memset (digest, '\0', sizeof digest);
        MU_POP3_CHECK_ERROR (pop3, status);
-       mu_pop3_debug_cmd (pop3);
+       MU_POP3_FCLR (pop3, MU_POP3_ACK); 
        pop3->state = MU_POP3_APOP;
       }
 
     case MU_POP3_APOP:
-      status = mu_pop3_send (pop3);
-      MU_POP3_CHECK_EAGAIN (pop3, status);
-      /* Obscure the digest, for security reasons.  */
-      memset (pop3->io.buf, '\0', pop3->io.len);
-      pop3->acknowledge = 0;
-      pop3->state = MU_POP3_APOP_ACK;
-
-    case MU_POP3_APOP_ACK:
-      status = mu_pop3_response (pop3, NULL, 0, NULL);
+      status = mu_pop3_response (pop3, NULL);
       MU_POP3_CHECK_EAGAIN (pop3, status);
-      mu_pop3_debug_ack (pop3);
       MU_POP3_CHECK_OK (pop3);
       pop3->state = MU_POP3_NO_STATE;
       break;
diff --git a/libproto/pop/pop3_capa.c b/libproto/pop/pop3_capa.c
index 24646ee..e6402af 100644
--- a/libproto/pop/pop3_capa.c
+++ b/libproto/pop/pop3_capa.c
@@ -27,47 +27,77 @@
 #include <stdlib.h>
 #include <errno.h>
 #include <mailutils/error.h>
+#include <mailutils/list.h>
+#include <mailutils/cctype.h>
+#include <mailutils/cstr.h>
 #include <mailutils/sys/pop3.h>
 
+static int
+capa_comp (const void *item, const void *value)
+{
+  const char *capa = item;
+  const char *needle = value;
+  for (; *needle; capa++, needle++)
+    {
+      if (!*capa)
+       return 1;
+      if (mu_tolower (*capa) != mu_tolower (*needle))
+       return 1;
+    }
+  return !(*capa == 0 || mu_isspace (*capa));
+}
+
 /*
   CAPA command, return a list that contains the result.
   It is the responsability of the caller to destroy the list(mu_list_destroy).
  */
 int
-mu_pop3_capa (mu_pop3_t pop3, mu_iterator_t *piterator)
+mu_pop3_capa (mu_pop3_t pop3, int reread, mu_iterator_t *piter)
 {
   int status = 0;
-
+  
   if (pop3 == NULL)
     return EINVAL;
-  if (piterator == NULL)
-    return MU_ERR_OUT_PTR_NULL;
 
+  if (pop3->capa)
+    {
+      if (!reread)
+       {
+         if (!piter)
+           return 0;
+         return mu_list_get_iterator (pop3->capa, piter);
+       }
+      mu_list_destroy (&pop3->capa);
+    }
+
+  status = mu_list_create (&pop3->capa);
+  if (status)
+    return status;
+  mu_list_set_comparator (pop3->capa, capa_comp);
+  mu_list_set_destroy_item (pop3->capa, mu_list_free_item);
+  
   switch (pop3->state)
     {
     case MU_POP3_NO_STATE:
       status = mu_pop3_writeline (pop3, "CAPA\r\n");
       MU_POP3_CHECK_ERROR (pop3, status);
-      mu_pop3_debug_cmd (pop3);
+      MU_POP3_FCLR (pop3, MU_POP3_ACK);
       pop3->state = MU_POP3_CAPA;
 
     case MU_POP3_CAPA:
-      status = mu_pop3_send (pop3);
-      MU_POP3_CHECK_EAGAIN (pop3, status);
-      pop3->acknowledge = 0;
-      pop3->state = MU_POP3_CAPA_ACK;
-
-    case MU_POP3_CAPA_ACK:
-      status = mu_pop3_response (pop3, NULL, 0, NULL);
+      status = mu_pop3_response (pop3, NULL);
       MU_POP3_CHECK_EAGAIN (pop3, status);
-      mu_pop3_debug_ack (pop3);
       MU_POP3_CHECK_OK (pop3);
-      status = mu_pop3_iterator_create (pop3, piterator);
-      MU_POP3_CHECK_ERROR (pop3, status);
       pop3->state = MU_POP3_CAPA_RX;
 
     case MU_POP3_CAPA_RX:
-      /* The mu_iterator_t will read the stream and set the state to 
MU_POP3_NO_STATE when done.  */
+      status = mu_pop3_read_list (pop3, pop3->capa);
+      MU_POP3_CHECK_ERROR (pop3, status);
+      if (piter)
+       status = mu_list_get_iterator (pop3->capa, piter);
+      else
+       status = 0;
+      pop3->state = MU_POP3_NO_STATE;
       break;
 
       /* They must deal with the error first by reopening.  */
diff --git a/libproto/pop/pop3_capatst.c b/libproto/pop/pop3_capatst.c
new file mode 100644
index 0000000..37d740b
--- /dev/null
+++ b/libproto/pop/pop3_capatst.c
@@ -0,0 +1,37 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 2003, 2004, 2005, 2007, 2010 Free Software Foundation,
+   Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General
+   Public License along with this library; if not, write to the
+   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301 USA */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <mailutils/list.h>
+#include <mailutils/sys/pop3.h>
+
+int
+mu_pop3_capa_test (mu_pop3_t pop3, const char *name, const char **pret)
+{
+  int rc;
+
+  rc = mu_pop3_capa (pop3, 0, NULL);
+  if (rc)
+    return rc;
+  return mu_list_locate (pop3->capa, (void*) name, (void**)pret);
+}
diff --git a/libproto/pop/pop3_carrier.c b/libproto/pop/pop3_carrier.c
index 5c63574..7331756 100644
--- a/libproto/pop/pop3_carrier.c
+++ b/libproto/pop/pop3_carrier.c
@@ -36,12 +36,16 @@ mu_pop3_set_carrier (mu_pop3_t pop3, mu_stream_t carrier)
     {
       /* Close any old carrier.  */
       mu_pop3_disconnect (pop3);
-      mu_stream_destroy (&pop3->carrier, pop3);
+      mu_stream_destroy (&pop3->carrier);
     }
+  mu_stream_ref (carrier);
   pop3->carrier = carrier;
+  if (MU_POP3_FISSET (pop3, MU_POP3_TRACE))
+    _mu_pop3_trace_enable (pop3);
   return 0;
 }
 
+/* FIXME: Is it needed? */
 int
 mu_pop3_get_carrier (mu_pop3_t pop3, mu_stream_t *pcarrier)
 {
diff --git a/libproto/pop/pop3_connect.c b/libproto/pop/pop3_connect.c
index f71083c..9377e84 100644
--- a/libproto/pop/pop3_connect.c
+++ b/libproto/pop/pop3_connect.c
@@ -53,14 +53,15 @@ mu_pop3_connect (mu_pop3_t pop3)
 
     case MU_POP3_NO_STATE:
       /* If the stream was previoulsy open this is sudden death:
-         for many pop servers, it is important to let them time to remove any 
locks or move
-         the .user.pop files.  This happen when we do close() and immediately 
open().
-         For example, the user does not want to read the entire file, and 
wants to start
-        to read a new message, closing the connection and immediately
-        contacting the server again, and he'll end up having
-        "-ERR Mail Lock busy" or something similar. To prevent this race
-        condition we sleep 2 seconds.  You can see this behaviour in an
-        environment where QPopper(Qualcomm POP3 server) is use and the user as 
a big mailbox. */
+         For many pop servers, it is important to allow them some time to
+        remove any locks or move the .user.pop files.  This happen when we
+        do close() and immediately open().  For example, the user does not
+        want to read the entire file, and wants to start to read a new
+        message, closing the connection and immediately contacting the
+        server again, and he'll end up having "-ERR Mail Lock busy" or
+        something similar. To prevent this race condition we sleep 2 seconds.
+        You can see this behaviour in an environment where QPopper (Qualcomm
+        POP3 server) is used and the user has a big mailbox. */
       status = mu_pop3_disconnect (pop3);
       if (status != 0)
         mu_pop3_sleep (2);
@@ -70,7 +71,7 @@ mu_pop3_connect (mu_pop3_t pop3)
       /* Establish the connection.  */
       status = mu_stream_open (pop3->carrier);
       MU_POP3_CHECK_EAGAIN (pop3, status);
-      pop3->acknowledge = 0;
+      MU_POP3_FCLR (pop3, MU_POP3_ACK);
       pop3->state = MU_POP3_GREETINGS;
 
     case MU_POP3_GREETINGS:
@@ -78,10 +79,9 @@ mu_pop3_connect (mu_pop3_t pop3)
       {
        size_t len = 0;
        char *right, *left;
-       status = mu_pop3_response (pop3, NULL, 0, &len);
+       status = mu_pop3_response (pop3, &len);
        MU_POP3_CHECK_EAGAIN (pop3, status);
-       mu_pop3_debug_ack (pop3);
-       if (mu_c_strncasecmp (pop3->ack.buf, "+OK", 3) != 0)
+       if (mu_c_strncasecmp (pop3->ackbuf, "+OK", 3) != 0)
          {
            mu_stream_close (pop3->carrier);
            pop3->state = MU_POP3_NO_STATE;
@@ -89,10 +89,10 @@ mu_pop3_connect (mu_pop3_t pop3)
          }
 
        /* Get the timestamp.  */
-       right = memchr (pop3->ack.buf, '<', len);
+       right = memchr (pop3->ackbuf, '<', len);
        if (right)
          {
-           len = len - (right - pop3->ack.buf);
+           len = len - (right - pop3->ackbuf);
            left = memchr (right, '>', len);
            if (left)
              {
@@ -121,5 +121,5 @@ mu_pop3_sleep (int seconds)
   struct timeval tval;
   tval.tv_sec = seconds;
   tval.tv_usec = 0;
-  return select (1, NULL, NULL, NULL, &tval);
+  return select (0, NULL, NULL, NULL, &tval);
 }
diff --git a/libproto/pop/pop3_create.c b/libproto/pop/pop3_create.c
index c9169ba..dc92360 100644
--- a/libproto/pop/pop3_create.c
+++ b/libproto/pop/pop3_create.c
@@ -24,6 +24,7 @@
 #include <errno.h>
 #include <mailutils/errno.h>
 #include <mailutils/sys/pop3.h>
+#include <mailutils/list.h>
 
 /* Initialise a mu_pop3_t handle.  */
 
@@ -40,34 +41,25 @@ mu_pop3_create (mu_pop3_t *ppop3)
   if (pop3 == NULL)
     return ENOMEM;
 
-  /* Reserve space for the ack(nowledgement) response.
-     According to RFC 2449: The maximum length of the first line of a
-     command response (including the initial greeting) is unchanged at
-     512 octets (including the terminating CRLF).  */
-  pop3->ack.len = 512;
-  pop3->ack.buf = calloc (pop3->ack.len, 1);
-  if (pop3->ack.buf == NULL)
-    {
-      mu_pop3_destroy (&pop3);
-      return ENOMEM;
-    }
-  pop3->ack.ptr = pop3->ack.buf;
-
-  /* Reserve space for the data response/content.
-     RFC 2449 recommands 255, but we grow it as needed.  */
-  pop3->io.len = 255;
-  pop3->io.buf = calloc (pop3->io.len, 1);
-  if (pop3->io.buf == NULL)
-    {
-      mu_pop3_destroy (&pop3);
-      return ENOMEM;
-    }
-  pop3->io.ptr = pop3->io.buf;
-
   pop3->state = MU_POP3_NO_STATE; /* Init with no state.  */
   pop3->timeout = (10 * 60) * 100; /* The default Timeout is 10 minutes.  */
-  pop3->acknowledge = 0; /* No Ack received.  */
+  MU_POP3_FCLR (pop3, MU_POP3_ACK); /* No Ack received.  */
 
   *ppop3 = pop3;
   return 0; /* Okdoke.  */
 }
+
+int
+_mu_pop3_init (mu_pop3_t pop3)
+{
+  if (pop3 == NULL)
+    return EINVAL;
+  if (pop3->carrier == 0)
+    {
+      mu_list_destroy (&pop3->capa);
+      pop3->flags = 0;
+    }
+  return 0;
+}
+
+  
diff --git a/libproto/pop/pop3_debug.c b/libproto/pop/pop3_debug.c
deleted file mode 100644
index a196029..0000000
--- a/libproto/pop/pop3_debug.c
+++ /dev/null
@@ -1,51 +0,0 @@
-/* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 2003, 2007, 2010 Free Software Foundation, Inc.
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General
-   Public License along with this library; if not, write to the
-   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301 USA */
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <stdlib.h>
-#include <errno.h>
-#include <mailutils/sys/pop3.h>
-
-int
-mu_pop3_set_debug (mu_pop3_t pop3, mu_debug_t debug)
-{
-  if (pop3 == NULL)
-    return EINVAL;
-  if (pop3->debug)
-    mu_debug_destroy (&pop3->debug, NULL);
-  pop3->debug = debug;
-  return 0;
-}
-
-/* FIXME: This should be a macro */
-int
-mu_pop3_debug_cmd (mu_pop3_t pop3)
-{
-  MU_DEBUG (pop3->debug, MU_DEBUG_PROT, pop3->io.buf);
-  return 0;
-}
-
-int
-mu_pop3_debug_ack (mu_pop3_t pop3)
-{
-  MU_DEBUG1 (pop3->debug, MU_DEBUG_PROT, "%s\n", pop3->ack.buf);
-  return 0;
-}
diff --git a/libproto/pop/pop3_dele.c b/libproto/pop/pop3_dele.c
index 0e866dd..e4b06c4 100644
--- a/libproto/pop/pop3_dele.c
+++ b/libproto/pop/pop3_dele.c
@@ -38,19 +38,12 @@ mu_pop3_dele (mu_pop3_t pop3, unsigned msgno)
     case MU_POP3_NO_STATE:
       status = mu_pop3_writeline (pop3, "DELE %d\r\n", msgno);
       MU_POP3_CHECK_ERROR (pop3, status);
-      mu_pop3_debug_cmd (pop3);
+      MU_POP3_FCLR (pop3, MU_POP3_ACK);
       pop3->state = MU_POP3_DELE;
 
     case MU_POP3_DELE:
-      status = mu_pop3_send (pop3);
+      status = mu_pop3_response (pop3, NULL);
       MU_POP3_CHECK_EAGAIN (pop3, status);
-      pop3->acknowledge = 0;
-      pop3->state = MU_POP3_DELE_ACK;
-
-    case MU_POP3_DELE_ACK:
-      status = mu_pop3_response (pop3, NULL, 0, NULL);
-      MU_POP3_CHECK_EAGAIN (pop3, status);
-      mu_pop3_debug_ack (pop3);
       MU_POP3_CHECK_OK (pop3);
       pop3->state = MU_POP3_NO_STATE;
       break;
diff --git a/libproto/pop/pop3_destroy.c b/libproto/pop/pop3_destroy.c
index fd3d6c8..010a063 100644
--- a/libproto/pop/pop3_destroy.c
+++ b/libproto/pop/pop3_destroy.c
@@ -23,6 +23,7 @@
 #include <stdlib.h>
 #include <mailutils/errno.h>
 #include <mailutils/sys/pop3.h>
+#include <mailutils/list.h>
 
 void
 mu_pop3_destroy (mu_pop3_t *ppop3)
@@ -32,20 +33,21 @@ mu_pop3_destroy (mu_pop3_t *ppop3)
       mu_pop3_t pop3 = *ppop3;
 
       /* Free the response buffer.  */
-      if (pop3->ack.buf)
-       free (pop3->ack.buf);
-
-      /* Free the io buffer.  */
-      if (pop3->io.buf)
-       free (pop3->io.buf);
+      if (pop3->ackbuf)
+       free (pop3->ackbuf);
+      /* Free the read buffer.  */
+      if (pop3->rdbuf)
+       free (pop3->rdbuf);
 
       /* Free the timestamp use for APOP.  */
       if (pop3->timestamp)
        free (pop3->timestamp);
 
+      mu_list_destroy (&pop3->capa);
+      
       /* Release the carrier.  */
       if (pop3->carrier)
-       mu_stream_destroy (&pop3->carrier, pop3);
+       mu_stream_destroy (&pop3->carrier);
 
       free (pop3);
 
diff --git a/libproto/pop/pop3_disconnect.c b/libproto/pop/pop3_disconnect.c
index 558ffb6..621a566 100644
--- a/libproto/pop/pop3_disconnect.c
+++ b/libproto/pop/pop3_disconnect.c
@@ -36,13 +36,10 @@ mu_pop3_disconnect (mu_pop3_t pop3)
   /* We can keep some of the fields, if they decide to pop3_connect() again but
      clear the states.  */
   pop3->state = MU_POP3_NO_STATE;
-  pop3->acknowledge = 0;
+  MU_POP3_FCLR (pop3, MU_POP3_ACK);
 
-  /* Clear the buffers.  */
-  memset (pop3->io.buf, '\0', pop3->io.len);
-  pop3->io.ptr = pop3->io.buf;
-  memset (pop3->ack.buf, '\0', pop3->ack.len);
-  pop3->ack.ptr = pop3->ack.buf;
+  if (pop3->rdbuf)
+    pop3->rdbuf[0] = 0;
 
   /* Free the timestamp, it will be different on each connection.  */
   if (pop3->timestamp)
diff --git a/libproto/pop/pop3_iterator.c b/libproto/pop/pop3_iterator.c
index edffe75..d7a2313 100644
--- a/libproto/pop/pop3_iterator.c
+++ b/libproto/pop/pop3_iterator.c
@@ -25,7 +25,10 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <errno.h>
+#include <mailutils/pop3.h>
 #include <mailutils/sys/pop3.h>
+#include <mailutils/cctype.h>
+#include <mailutils/cstr.h>
 
 static int  pop3_itr_dup     (void **ptr, void *owner);
 static int  pop3_itr_destroy (mu_iterator_t itr, void *owner);
@@ -38,8 +41,11 @@ static int  pop3_itr_finished_p (void *owner);
 struct pop3_iterator
 {
   mu_pop3_t pop3;
+  mu_stream_t stream;
   int done;
   char *item;
+  char *rdbuf;
+  size_t rdsize;
 };
 
 int
@@ -53,9 +59,17 @@ mu_pop3_iterator_create (mu_pop3_t pop3, mu_iterator_t 
*piterator)
   if (pop3_iterator == NULL)
     return ENOMEM;
 
+  status = mu_pop3_stream_create (pop3, &pop3_iterator->stream);
+  if (status)
+    {
+      free (pop3_iterator);
+      return status;
+    }
   pop3_iterator->item = NULL;
+  pop3_iterator->rdbuf = NULL;
+  pop3_iterator->rdsize = 0;
   pop3_iterator->done = 0;
-  pop3_iterator->pop3= pop3;
+  pop3_iterator->pop3 = pop3;
 
   status = mu_iterator_create (&iterator, pop3_iterator);
   if (status != 0)
@@ -93,17 +107,21 @@ pop3_itr_destroy (mu_iterator_t iterator, void *owner)
 {
   struct pop3_iterator *pop3_iterator = (struct pop3_iterator *)owner;
   /* Delicate situation if they did not finish to drain the result
-     We take te approach to do it for the user.  FIXME: Not sure
+     We take the approach to do it for the user.  FIXME: Not sure
      if this is the rigth thing to do. The other way is to close the stream  */
   if (!pop3_iterator->done)
     {
       char buf[128];
       size_t n = 0;
-      while (mu_pop3_readline (pop3_iterator->pop3, buf, sizeof buf, &n) > 0 
&& n > 0)
+      mu_stream_t str = pop3_iterator->pop3->carrier;
+      while (mu_stream_readline (str, buf, sizeof buf, &n) > 0
+            && n > 0)
        n = 0;
     }
   if (pop3_iterator->item)
     free (pop3_iterator->item);
+  if (pop3_iterator->rdbuf)
+    free (pop3_iterator->rdbuf);
   pop3_iterator->pop3->state = MU_POP3_NO_STATE;
   free (pop3_iterator);
   return 0;
@@ -119,40 +137,27 @@ static int
 pop3_itr_next (void *owner)
 {
   struct pop3_iterator *pop3_iterator = (struct pop3_iterator *)owner;
-  size_t n = 0;
   int status = 0;
+  size_t n;
+  
+  status = mu_stream_getline (pop3_iterator->stream, &pop3_iterator->rdbuf,
+                             &pop3_iterator->rdsize, &n);
+  
+  if (status || n == 0)
+    {
+      pop3_iterator->done = 1;
+      pop3_iterator->pop3->state = MU_POP3_NO_STATE;
+      return 0;
+    }
 
-  if (!pop3_iterator->done)
+  n = mu_rtrim_class (pop3_iterator->rdbuf, MU_CTYPE_SPACE);
+  if (n == 1 && pop3_iterator->rdbuf[0] == '.')
     {
-      /* The first readline will not consume the buffer, we just need to
-        know how much to read.  */
-      status = mu_pop3_readline (pop3_iterator->pop3, NULL, 0, &n);
-      if (status == 0)
-       {
-         if (n)
-           {
-             char *buf;
-             buf = calloc (n + 1, 1);
-             if (buf)
-               {
-                 /* Consume.  */
-                 mu_pop3_readline (pop3_iterator->pop3, buf, n + 1, NULL);
-                 if (buf[n - 1] == '\n')
-                   buf[n - 1] = '\0';
-                 if (pop3_iterator->item)
-                   free (pop3_iterator->item);
-                 pop3_iterator->item = buf;
-               }
-             else
-               status = ENOMEM;
-           }
-         else
-           {
-             pop3_iterator->done = 1;
-             pop3_iterator->pop3->state = MU_POP3_NO_STATE;
-           }
-       }
+      pop3_iterator->done = 1;
+      pop3_iterator->pop3->state = MU_POP3_NO_STATE;
     }
+  else
+    pop3_iterator->item = pop3_iterator->rdbuf;
   return status;
 }
 
diff --git a/libproto/pop/pop3_list.c b/libproto/pop/pop3_list.c
index ed50f98..e6bccb5 100644
--- a/libproto/pop/pop3_list.c
+++ b/libproto/pop/pop3_list.c
@@ -40,27 +40,21 @@ mu_pop3_list (mu_pop3_t pop3, unsigned int msgno, size_t 
*psize)
   switch (pop3->state)
     {
     case MU_POP3_NO_STATE:
-      status = mu_pop3_writeline (pop3, "LIST %d\r\n", msgno);
+      status = mu_pop3_writeline (pop3, "LIST %u\r\n", msgno);
       MU_POP3_CHECK_ERROR (pop3, status);
-      mu_pop3_debug_cmd (pop3);
+      MU_POP3_FCLR (pop3, MU_POP3_ACK);
       pop3->state = MU_POP3_LIST;
 
     case MU_POP3_LIST:
-      status = mu_pop3_send (pop3);
-      MU_POP3_CHECK_EAGAIN (pop3, status);
-      pop3->acknowledge = 0;
-      pop3->state = MU_POP3_LIST_ACK;
-
-    case MU_POP3_LIST_ACK:
-      status = mu_pop3_response (pop3, NULL, 0, NULL);
-      mu_pop3_debug_ack (pop3);
+      status = mu_pop3_response (pop3, NULL);
       MU_POP3_CHECK_EAGAIN (pop3, status);
       MU_POP3_CHECK_OK (pop3);
       pop3->state = MU_POP3_NO_STATE;
 
       /* Parse the answer.  */
       lv = 0;
-      sscanf (pop3->ack.buf, "+OK %d %lu", &msgno, &lv);
+      /* FIXME: Error checking */
+      sscanf (pop3->ackbuf, "+OK %d %lu", &msgno, &lv);
       *psize = lv;
       break;
 
diff --git a/libproto/pop/pop3_list_cmd.c b/libproto/pop/pop3_list_cmd.c
new file mode 100644
index 0000000..2917e21
--- /dev/null
+++ b/libproto/pop/pop3_list_cmd.c
@@ -0,0 +1,64 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 1999, 2000, 2001, 2004, 2007, 2010 Free Software
+   Foundation, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General
+   Public License along with this library; if not, write to the
+   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301 USA */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <mailutils/sys/pop3.h>
+
+int
+mu_pop3_list_cmd (mu_pop3_t pop3)
+{
+  int status = 0;
+
+  if (pop3 == NULL)
+    return EINVAL;
+
+  switch (pop3->state)
+    {
+    case MU_POP3_NO_STATE:
+      status = mu_pop3_writeline (pop3, "LIST\r\n");
+      MU_POP3_CHECK_ERROR (pop3, status);
+      MU_POP3_FCLR (pop3, MU_POP3_ACK);
+      pop3->state = MU_POP3_LIST;
+
+    case MU_POP3_LIST:
+      status = mu_pop3_response (pop3, NULL);
+      MU_POP3_CHECK_EAGAIN (pop3, status);
+      MU_POP3_CHECK_OK (pop3);
+      pop3->state = MU_POP3_LIST_RX;
+
+    case MU_POP3_LIST_RX:
+      /* The mu_iterator_t will read the stream and set the state to
+        MU_POP3_NO_STATE when done.  */
+      break;
+
+      /* They must deal with the error first by reopening.  */
+    case MU_POP3_ERROR:
+      status = ECANCELED;
+      break;
+
+    default:
+      status = EINPROGRESS;
+    }
+
+  return status;
+}
diff --git a/libproto/pop/pop3_lista.c b/libproto/pop/pop3_lista.c
index d2f825d..4ce2ff1 100644
--- a/libproto/pop/pop3_lista.c
+++ b/libproto/pop/pop3_lista.c
@@ -21,57 +21,19 @@
 # include <config.h>
 #endif
 
-#include <string.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
 #include <mailutils/sys/pop3.h>
 
 int
 mu_pop3_list_all (mu_pop3_t pop3, mu_iterator_t *piterator)
 {
-  int status = 0;
+  int status = mu_pop3_list_cmd (pop3);
 
-  if (pop3 == NULL)
-    return EINVAL;
-  if (piterator == NULL)
-    return MU_ERR_OUT_PTR_NULL;
+  if (status)
+    return status;
 
-  switch (pop3->state)
-    {
-    case MU_POP3_NO_STATE:
-      status = mu_pop3_writeline (pop3, "LIST\r\n");
-      MU_POP3_CHECK_ERROR (pop3, status);
-      mu_pop3_debug_cmd (pop3);
-      pop3->state = MU_POP3_LIST;
-
-    case MU_POP3_LIST:
-      status = mu_pop3_send (pop3);
-      MU_POP3_CHECK_EAGAIN (pop3, status);
-      pop3->acknowledge = 0;
-      pop3->state = MU_POP3_LIST_ACK;
-
-    case MU_POP3_LIST_ACK:
-      status = mu_pop3_response (pop3, NULL, 0, NULL);
-      MU_POP3_CHECK_EAGAIN (pop3, status);
-      mu_pop3_debug_ack (pop3);
-      MU_POP3_CHECK_OK (pop3);
-      status = mu_pop3_iterator_create (pop3, piterator);
-      MU_POP3_CHECK_ERROR (pop3, status);
-      pop3->state = MU_POP3_LIST_RX;
-
-    case MU_POP3_LIST_RX:
-      /* The mu_iterator_t will read the stream and set the state to 
MU_POP3_NO_STATE when done.  */
-      break;
-
-      /* They must deal with the error first by reopening.  */
-    case MU_POP3_ERROR:
-      status = ECANCELED;
-      break;
-
-    default:
-      status = EINPROGRESS;
-    }
+  status = mu_pop3_iterator_create (pop3, piterator);
+  MU_POP3_CHECK_ERROR (pop3, status);
+  pop3->state = MU_POP3_LIST_RX;
 
   return status;
 }
diff --git a/libproto/pop/pop3_listas.c b/libproto/pop/pop3_listas.c
new file mode 100644
index 0000000..0227650
--- /dev/null
+++ b/libproto/pop/pop3_listas.c
@@ -0,0 +1,39 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 1999, 2000, 2001, 2004, 2007, 2010 Free Software
+   Foundation, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General
+   Public License along with this library; if not, write to the
+   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301 USA */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <mailutils/sys/pop3.h>
+
+int
+mu_pop3_list_all_stream (mu_pop3_t pop3, mu_stream_t *pstream)
+{
+  int status = mu_pop3_list_cmd (pop3);
+
+  if (status)
+    return status;
+
+  status = mu_pop3_stream_create (pop3, pstream);
+  MU_POP3_CHECK_ERROR (pop3, status);
+  pop3->state = MU_POP3_LIST_RX;
+
+  return status;
+}
diff --git a/libproto/pop/pop3_noop.c b/libproto/pop/pop3_noop.c
index 906ca93..beed039 100644
--- a/libproto/pop/pop3_noop.c
+++ b/libproto/pop/pop3_noop.c
@@ -38,19 +38,12 @@ mu_pop3_noop (mu_pop3_t pop3)
     case MU_POP3_NO_STATE:
       status = mu_pop3_writeline (pop3, "NOOP\r\n");
       MU_POP3_CHECK_ERROR (pop3, status);
-      mu_pop3_debug_cmd (pop3);
+      MU_POP3_FCLR (pop3, MU_POP3_ACK);
       pop3->state = MU_POP3_NOOP;
 
     case MU_POP3_NOOP:
-      status = mu_pop3_send (pop3);
+      status = mu_pop3_response (pop3, NULL);
       MU_POP3_CHECK_EAGAIN (pop3, status);
-      pop3->acknowledge = 0;
-      pop3->state = MU_POP3_NOOP_ACK;
-
-    case MU_POP3_NOOP_ACK:
-      status = mu_pop3_response (pop3, NULL, 0, NULL);
-      MU_POP3_CHECK_EAGAIN (pop3, status);
-      mu_pop3_debug_ack (pop3);
       MU_POP3_CHECK_OK (pop3);
       pop3->state = MU_POP3_NO_STATE;
       break;
diff --git a/libproto/pop/pop3_pass.c b/libproto/pop/pop3_pass.c
index b6cfa67..d72c511 100644
--- a/libproto/pop/pop3_pass.c
+++ b/libproto/pop/pop3_pass.c
@@ -28,30 +28,25 @@ int
 mu_pop3_pass (mu_pop3_t pop3, const char *passwd)
 {
   int status;
-
+  
   if (pop3 == NULL || passwd == NULL)
     return EINVAL;
 
   switch (pop3->state)
     {
     case MU_POP3_NO_STATE:
+      if (mu_pop3_trace_mask (pop3, MU_POP3_TRACE_QRY, MU_XSCRIPT_SECURE))
+       _mu_pop3_xscript_level (pop3, MU_XSCRIPT_SECURE);
       status = mu_pop3_writeline (pop3, "PASS %s\r\n", passwd);
+      _mu_pop3_xscript_level (pop3, MU_XSCRIPT_NORMAL);
       MU_POP3_CHECK_ERROR (pop3, status);
-      mu_pop3_debug_cmd (pop3);
+      /* FIXME: how to obscure the passwd in the stream buffer? */
+      MU_POP3_FCLR (pop3, MU_POP3_ACK);
       pop3->state = MU_POP3_PASS;
 
     case MU_POP3_PASS:
-      status = mu_pop3_send (pop3);
-      MU_POP3_CHECK_EAGAIN (pop3, status);
-      /* Obscure the passwd.  */
-      memset (pop3->io.buf, '\0', pop3->io.len);
-      pop3->acknowledge = 0;
-      pop3->state = MU_POP3_PASS_ACK;
-
-    case MU_POP3_PASS_ACK:
-      status = mu_pop3_response (pop3, NULL, 0, NULL);
+      status = mu_pop3_response (pop3, NULL);
       MU_POP3_CHECK_EAGAIN (pop3, status);
-      mu_pop3_debug_ack (pop3);
       MU_POP3_CHECK_OK (pop3);
       pop3->state = MU_POP3_NO_STATE;
       break;
diff --git a/libproto/pop/pop3_quit.c b/libproto/pop/pop3_quit.c
index f17d711..8ec8178 100644
--- a/libproto/pop/pop3_quit.c
+++ b/libproto/pop/pop3_quit.c
@@ -38,21 +38,15 @@ mu_pop3_quit (mu_pop3_t pop3)
     case MU_POP3_NO_STATE:
       status = mu_pop3_writeline (pop3, "QUIT\r\n");
       MU_POP3_CHECK_ERROR (pop3, status);
-      mu_pop3_debug_cmd (pop3);
+      MU_POP3_FCLR (pop3, MU_POP3_ACK);
       pop3->state = MU_POP3_QUIT;
 
     case MU_POP3_QUIT:
-      status = mu_pop3_send (pop3);
+      status = mu_pop3_response (pop3, NULL);
       MU_POP3_CHECK_EAGAIN (pop3, status);
-      pop3->acknowledge = 0;
-      pop3->state = MU_POP3_QUIT_ACK;
-
-    case MU_POP3_QUIT_ACK:
-      status = mu_pop3_response (pop3, NULL, 0, NULL);
-      MU_POP3_CHECK_EAGAIN (pop3, status);
-      mu_pop3_debug_ack (pop3);
       MU_POP3_CHECK_OK (pop3);
       pop3->state = MU_POP3_NO_STATE;
+      _mu_pop3_init (pop3);
       break;
 
     default:
diff --git a/libproto/pop/pop3_rdlist.c b/libproto/pop/pop3_rdlist.c
new file mode 100644
index 0000000..3544a31
--- /dev/null
+++ b/libproto/pop/pop3_rdlist.c
@@ -0,0 +1,65 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 2003, 2004, 2005, 2007, 2010 Free Software Foundation,
+   Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General
+   Public License along with this library; if not, write to the
+   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301 USA */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+#include <mailutils/stream.h>
+#include <mailutils/list.h>
+#include <mailutils/cctype.h>
+#include <mailutils/cstr.h>
+#include <mailutils/sys/pop3.h>
+
+int
+mu_pop3_stream_to_list (mu_pop3_t pop3, mu_stream_t stream, mu_list_t list)
+{
+  int status;
+  size_t n;
+  
+  while (mu_stream_getline (stream, &pop3->rdbuf, &pop3->rdsize, &n) == 0
+        && n > 0)
+    {
+      char *np = strdup (pop3->rdbuf);
+      if (!np)
+       {
+         status = ENOMEM;
+         break;
+       }
+      mu_rtrim_class (np, MU_CTYPE_SPACE);
+      status = mu_list_append (list, np);
+      if (status)
+       break;
+    }
+  return status;
+}
+
+int
+mu_pop3_read_list (mu_pop3_t pop3, mu_list_t list)
+{
+  mu_stream_t stream;
+  int status = mu_pop3_stream_create (pop3, &stream);
+  if (status)
+    return status;
+  status = mu_pop3_stream_to_list (pop3, stream, list);
+  mu_stream_destroy (&stream);
+  return status;
+}
+
diff --git a/libproto/pop/pop3_readline.c b/libproto/pop/pop3_readline.c
index 974ed3d..566735b 100644
--- a/libproto/pop/pop3_readline.c
+++ b/libproto/pop/pop3_readline.c
@@ -29,6 +29,8 @@
 #include <errno.h>
 #include <mailutils/sys/pop3.h>
 #include <mailutils/error.h>
+#include <mailutils/cctype.h>
+#include <mailutils/cstr.h>
 
 int
 mu_pop3_carrier_is_ready (mu_stream_t carrier, int flag, int timeout)
@@ -52,141 +54,28 @@ mu_pop3_carrier_is_ready (mu_stream_t carrier, int flag, 
int timeout)
 /* Read a complete line from the pop server. Transform CRLF to LF, remove
    the stuff byte termination octet ".", put a null in the buffer
    when done.  And Do a select() (stream_is_readready()) for the timeout.  */
-static int
+/* FIXME: Is it needed? */
+int
 mu_pop3_getline (mu_pop3_t pop3)
 {
-  size_t n = 0;
-  size_t total = pop3->io.ptr - pop3->io.buf;
-  int status = 0;
-
-  /* Must get a full line before bailing out.  */
-  do
+  size_t n;
+  int status = mu_stream_getline (pop3->carrier, &pop3->rdbuf,
+                                 &pop3->rdsize, &n);
+  if (status == 0)
     {
-      /* Timeout with select(), note that we have to reset select()
-        since on linux tv is modified when error.  */
-      if (pop3->timeout)
-       {
-         int ready = mu_pop3_carrier_is_ready (pop3->carrier,
-                                               MU_STREAM_READY_RD,
-                                               pop3->timeout);
-         if (ready == 0)
-           return ETIMEDOUT;
-       }
-
-      status = mu_stream_sequential_readline (pop3->carrier, pop3->io.buf + 
total, pop3->io.len - total, &n);
-      if (status != 0)
-       return status;
-
-      /* The server went away:  It maybe a timeout and some pop server
-        does not send the -ERR.  Consider this like an error.  */
       if (n == 0)
        return EIO;
-
-      total += n;
-      pop3->io.nl = memchr (pop3->io.buf, '\n', total);
-      if (pop3->io.nl == NULL)  /* Do we have a full line.  */
-       {
-         /* Allocate a bigger buffer ?  */
-         if (total >= pop3->io.len - 1)
-           {
-             pop3->io.len *= 2;
-             pop3->io.buf = realloc (pop3->io.buf, pop3->io.len + 1);
-             if (pop3->io.buf == NULL)
-               return ENOMEM;
-           }
-       }
-      pop3->io.ptr = pop3->io.buf + total;
-    }
-  while (pop3->io.nl == NULL); /* Bail only if we have a complete line.  */
-
-  /* When examining a multi-line response, the client checks to see if the
-     line begins with the termination octet "."(DOT). If yes and if octets
-     other than CRLF follow, the first octet of the line (the termination
-     octet) is stripped away.  */
-  if (total >= 3  && pop3->io.buf[0] == '.')
-    {
-      if (pop3->io.buf[1] != '\r' && pop3->io.buf[2] != '\n')
-       {
-         memmove (pop3->io.buf, pop3->io.buf + 1, total - 1);
-         pop3->io.ptr--;
-         pop3->io.nl--;
-       }
-      /* And if CRLF immediately follows the termination character, then
-        the response from the POP server is ended and the line containing
-        ".CRLF" is not considered part of the multi-line response.  */
-      else if (pop3->io.buf[1] == '\r' && pop3->io.buf[2] == '\n')
-       {
-         pop3->io.buf[0] = '\0';
-         pop3->io.ptr = pop3->io.buf;
-         pop3->io.nl = NULL;
-       }
-    }
-  /* \r\n --> \n\0, conversion.  */
-  if (pop3->io.nl > pop3->io.buf)
-    {
-      *(pop3->io.nl - 1) = '\n';
-      *(pop3->io.nl) = '\0';
-      pop3->io.ptr = pop3->io.nl;
+      n = mu_rtrim_class (pop3->rdbuf, MU_CTYPE_SPACE);
+
+      /* When examining a multi-line response, the client checks to see if the
+        line begins with the termination octet "."(DOT). If yes and if octets
+        other than CRLF follow, the first octet of the line (the termination
+        octet) is stripped away.  */
+      if (n >= 2 &&
+         pop3->rdbuf[0] == '.' &&
+         pop3->rdbuf[1] != '\n')
+       memmove (pop3->rdbuf, pop3->rdbuf + 1, n);
     }
   return status;
 }
 
-/* Call pop3_getline() for the dirty work,  and consume i.e. put
-   in the user buffer only buflen. If buflen == 0 or buffer == NULL
-   nothing is consume, the data is save for another call to pop3_readline()
-   with a buffer != NULL.
-  */
-int
-mu_pop3_readline (mu_pop3_t pop3, char *buffer, size_t buflen, size_t *pnread)
-{
-  size_t nread = 0;
-  size_t n = 0;
-  int status = 0;
-
-  /* Do we need to fill up? Yes if no NL or the buffer is empty.  */
-  if (pop3->carrier && (pop3->io.nl == NULL || pop3->io.ptr == pop3->io.buf))
-    {
-      status = mu_pop3_getline (pop3);
-      if (status != 0)
-       return status;
-    }
-
-  /* How much we can copy ?  */
-  n = pop3->io.ptr - pop3->io.buf;
-
-  /* Consume the line?  */
-  if (buffer && buflen)
-    {
-      buflen--; /* For the null.  */
-      if (buflen)
-       {
-         int nleft = buflen - n;
-         /* We got more then requested.  */
-         if (nleft < 0)
-           {
-             size_t sentinel;
-             nread = buflen;
-             sentinel = pop3->io.ptr - (pop3->io.buf + nread);
-             memcpy (buffer, pop3->io.buf, nread);
-             memmove (pop3->io.buf, pop3->io.buf + nread, sentinel);
-             pop3->io.ptr = pop3->io.buf + sentinel;
-           }
-         else
-           {
-             /* Drain our buffer.  */;
-             nread = n;
-             memcpy (buffer, pop3->io.buf, nread);
-             pop3->io.ptr = pop3->io.buf;
-             /* Clear of all residue.  */
-             memset (pop3->io.buf, '\0', pop3->io.len);
-           }
-       }
-      buffer[nread] = '\0';
-    }
-  else
-    nread = n;
-
-  if (pnread)
-    *pnread = nread;
-  return status;
-}
diff --git a/libproto/pop/pop3_response.c b/libproto/pop/pop3_response.c
index 8ff4144..2a106ab 100644
--- a/libproto/pop/pop3_response.c
+++ b/libproto/pop/pop3_response.c
@@ -20,14 +20,19 @@
 # include <config.h>
 #endif
 
+#include <stdlib.h>
 #include <string.h>
 #include <errno.h>
+#include <mailutils/cctype.h>
+#include <mailutils/cstr.h>
 #include <mailutils/sys/pop3.h>
 
+#define POP3_DEFERR "-ERR POP3 IO ERROR"
+
 /* If we did not grap the ack already, call pop3_readline() but handle
    Nonblocking also.  */
 int
-mu_pop3_response (mu_pop3_t pop3, char *buffer, size_t buflen, size_t *pnread)
+mu_pop3_response (mu_pop3_t pop3, size_t *pnread)
 {
   size_t n = 0;
   int status = 0;
@@ -35,37 +40,33 @@ mu_pop3_response (mu_pop3_t pop3, char *buffer, size_t 
buflen, size_t *pnread)
   if (pop3 == NULL)
     return EINVAL;
 
-  if (!pop3->acknowledge)
+  if (!MU_POP3_FISSET (pop3, MU_POP3_ACK))
     {
-      size_t len = pop3->ack.len - (pop3->ack.ptr  - pop3->ack.buf);
-      status = mu_pop3_readline (pop3, pop3->ack.ptr, len, &n);
-      pop3->ack.ptr += n;
+      status = mu_stream_getline (pop3->carrier, &pop3->ackbuf,
+                                 &pop3->acksize, NULL);
       if (status == 0)
        {
-         len = pop3->ack.ptr - pop3->ack.buf;
-         if (len && pop3->ack.buf[len - 1] == '\n')
-           pop3->ack.buf[len - 1] = '\0';
-         pop3->acknowledge = 1; /* Flag that we have the ack.  */
-         pop3->ack.ptr = pop3->ack.buf;
+         n = mu_rtrim_class (pop3->ackbuf, MU_CTYPE_SPACE);
+         MU_POP3_FSET (pop3, MU_POP3_ACK); /* Flag that we have the ack.  */
        }
       else
        {
          /* Provide them with an error.  */
-         const char *econ = "-ERR POP3 IO ERROR";
-         n = strlen (econ);
-         strcpy (pop3->ack.buf, econ);
+         if (pop3->acksize < sizeof (POP3_DEFERR))
+           {
+             char *p = realloc (pop3->ackbuf, sizeof (POP3_DEFERR));
+             if (p)
+               {
+                 pop3->ackbuf = p;
+                 pop3->acksize = sizeof (POP3_DEFERR);
+               }
+           }
+         if (pop3->ackbuf)
+           strncpy (pop3->ackbuf, POP3_DEFERR, pop3->acksize);
        }
     }
-  else
-    n = strlen (pop3->ack.buf);
-
-  if (buffer)
-    {
-      buflen--; /* Leave space for the NULL.  */
-      n = (buflen < n) ? buflen : n;
-      memcpy (buffer, pop3->ack.buf, n);
-      buffer[n] = '\0';
-    }
+  else if (pop3->ackbuf)
+    n = strlen (pop3->ackbuf);
 
   if (pnread)
     *pnread = n;
diff --git a/libproto/pop/pop3_retr.c b/libproto/pop/pop3_retr.c
index 7f1d071..aca24da 100644
--- a/libproto/pop/pop3_retr.c
+++ b/libproto/pop/pop3_retr.c
@@ -41,25 +41,20 @@ mu_pop3_retr (mu_pop3_t pop3, unsigned int msgno, 
mu_stream_t *pstream)
     case MU_POP3_NO_STATE:
       status = mu_pop3_writeline (pop3, "RETR %d\r\n", msgno);
       MU_POP3_CHECK_ERROR (pop3, status);
-      mu_pop3_debug_cmd (pop3);
+      MU_POP3_FCLR (pop3, MU_POP3_ACK);
       pop3->state = MU_POP3_RETR;
 
     case MU_POP3_RETR:
-      status = mu_pop3_send (pop3);
+      status = mu_pop3_response (pop3, NULL);
       MU_POP3_CHECK_EAGAIN (pop3, status);
-      pop3->acknowledge = 0;
-      pop3->state = MU_POP3_RETR_ACK;
-
-    case MU_POP3_RETR_ACK:
-      status = mu_pop3_response (pop3, NULL, 0, NULL);
-      MU_POP3_CHECK_EAGAIN (pop3, status);
-      mu_pop3_debug_ack (pop3);
       MU_POP3_CHECK_OK (pop3);
+      status = mu_pop3_stream_create (pop3, pstream);
+      MU_POP3_CHECK_ERROR (pop3, status);
+      if (mu_pop3_trace_mask (pop3, MU_POP3_TRACE_QRY, MU_XSCRIPT_PAYLOAD))
+       _mu_pop3_xscript_level (pop3, MU_XSCRIPT_PAYLOAD);
       pop3->state = MU_POP3_RETR_RX;
 
     case MU_POP3_RETR_RX:
-      status = mu_pop3_stream_create (pop3, pstream);
-      MU_POP3_CHECK_ERROR (pop3, status);
       break;
 
       /* They must deal with the error first by reopening.  */
diff --git a/libproto/pop/pop3_rset.c b/libproto/pop/pop3_rset.c
index 9ad5797..d233ec4 100644
--- a/libproto/pop/pop3_rset.c
+++ b/libproto/pop/pop3_rset.c
@@ -38,19 +38,12 @@ mu_pop3_rset (mu_pop3_t pop3)
     case MU_POP3_NO_STATE:
       status = mu_pop3_writeline (pop3, "RSET\r\n");
       MU_POP3_CHECK_ERROR (pop3, status);
-      mu_pop3_debug_cmd (pop3);
+      MU_POP3_FCLR (pop3, MU_POP3_ACK);
       pop3->state = MU_POP3_RSET;
 
     case MU_POP3_RSET:
-      status = mu_pop3_send (pop3);
+      status = mu_pop3_response (pop3, NULL);
       MU_POP3_CHECK_EAGAIN (pop3, status);
-      pop3->acknowledge = 0;
-      pop3->state = MU_POP3_RSET_ACK;
-
-    case MU_POP3_RSET_ACK:
-      status = mu_pop3_response (pop3, NULL, 0, NULL);
-      MU_POP3_CHECK_EAGAIN (pop3, status);
-      mu_pop3_debug_ack (pop3);
       MU_POP3_CHECK_OK (pop3);
       pop3->state = MU_POP3_NO_STATE;
       break;
diff --git a/libproto/pop/pop3_sendline.c b/libproto/pop/pop3_sendline.c
index 54c1cac..0de5e6a 100644
--- a/libproto/pop/pop3_sendline.c
+++ b/libproto/pop/pop3_sendline.c
@@ -31,91 +31,23 @@
 #include <errno.h>
 #include <mailutils/sys/pop3.h>
 
-/* A socket may write less then expected but stream.c:mu_stream_write() will
-   always try to send the entire buffer unless an error is reported.  We have
-   to cope with nonblocking, it is done by keeping track with the pop3->ptr
-   pointer if the write failed we keep track and restart where we left.  */
-int
-mu_pop3_send (mu_pop3_t pop3)
-{
-  int status = 0;
-  if (pop3->carrier && (pop3->io.ptr > pop3->io.buf))
-    {
-      size_t n = 0;
-      size_t len = pop3->io.ptr - pop3->io.buf;
-
-      /* Timeout with select(), note that we have to reset select()
-        since on linux tv is modified when error.  */
-      if (pop3->timeout)
-       {
-         int ready = mu_pop3_carrier_is_ready (pop3->carrier,
-                                               MU_STREAM_READY_WR,
-                                               pop3->timeout);
-         if (ready == 0)
-           return ETIMEDOUT;
-       }
-
-      status = mu_stream_write (pop3->carrier, pop3->io.buf, len, 0, &n);
-      if (n)
-       {
-         /* Consume what we sent.  */
-         memmove (pop3->io.buf, pop3->io.buf + n, len - n);
-         pop3->io.ptr -= n;
-       }
-    }
-  else
-    pop3->io.ptr = pop3->io.buf;
-  return status;
-}
-
-/* According to RFC 2449: The maximum length of a command is increased from
-   47 characters (4 character command, single space, 40 character argument,
-   CRLF) to 255 octets, including the terminating CRLF.  But we are flexible
-   on this and realloc() as needed. NOTE: The terminated CRLF is not
-   included.  */
 int
 mu_pop3_writeline (mu_pop3_t pop3, const char *format, ...)
 {
-  int len;
+  int status;
   va_list ap;
-  int done = 1;
 
-  va_start(ap, format);
-  /* C99 says that a conforming implementation of snprintf () should
-     return the number of char that would have been call but many old
-     GNU/Linux && BSD implementations return -1 on error.  Worse,
-     QnX/Neutrino actually does not put the terminal null char.  So
-     let's try to cope.  */
-  do
-    {
-      len = vsnprintf (pop3->io.buf, pop3->io.len - 1, format, ap);
-      if (len < 0 || len >= (int)pop3->io.len
-         || !memchr (pop3->io.buf, '\0', len + 1))
-       {
-         pop3->io.len *= 2;
-         pop3->io.buf = realloc (pop3->io.buf, pop3->io.len);
-         if (pop3->io.buf == NULL)
-           return ENOMEM;
-         done = 0;
-       }
-      else
-       done = 1;
-    }
-  while (!done);
+  va_start (ap, format);
+  status = mu_stream_vprintf (pop3->carrier, format, ap);
   va_end(ap);
-  pop3->io.ptr = pop3->io.buf + len;
-  return 0;
+  return status;
 }
 
 int
 mu_pop3_sendline (mu_pop3_t pop3, const char *line)
 {
   if (line)
-    {
-      int status = mu_pop3_writeline (pop3, line);
-      if (status)
-       return status;
-    }
-  return mu_pop3_send (pop3);
+    return mu_stream_write (pop3->carrier, line, strlen (line), NULL);
+  return mu_stream_flush (pop3->carrier);
 }
 
diff --git a/libproto/pop/pop3_stat.c b/libproto/pop/pop3_stat.c
index 779d10b..707fe7d 100644
--- a/libproto/pop/pop3_stat.c
+++ b/libproto/pop/pop3_stat.c
@@ -21,15 +21,16 @@
 # include <config.h>
 #endif
 
+#include <stdio.h>
 #include <string.h>
 #include <errno.h>
 #include <mailutils/sys/pop3.h>
 
 int
-mu_pop3_stat (mu_pop3_t pop3, unsigned *msg_count, size_t *size)
+mu_pop3_stat (mu_pop3_t pop3, size_t *msg_count, mu_off_t *size)
 {
   int status;
-  unsigned long lv;
+  unsigned long lv, count;
   
   if (pop3 == NULL || msg_count == NULL)
     return EINVAL;
@@ -41,26 +42,21 @@ mu_pop3_stat (mu_pop3_t pop3, unsigned *msg_count, size_t 
*size)
     case MU_POP3_NO_STATE:
       status = mu_pop3_writeline (pop3, "STAT\r\n");
       MU_POP3_CHECK_ERROR (pop3, status);
-      mu_pop3_debug_cmd (pop3);
+      MU_POP3_FCLR (pop3, MU_POP3_ACK);
       pop3->state = MU_POP3_STAT;
 
     case MU_POP3_STAT:
-      status = mu_pop3_send (pop3);
+      status = mu_pop3_response (pop3, NULL);
       MU_POP3_CHECK_EAGAIN (pop3, status);
-      pop3->acknowledge = 0;
-      pop3->state = MU_POP3_STAT_ACK;
-
-    case MU_POP3_STAT_ACK:
-      status = mu_pop3_response (pop3, NULL, 0, NULL);
-      MU_POP3_CHECK_EAGAIN (pop3, status);
-      mu_pop3_debug_ack (pop3);
       MU_POP3_CHECK_OK (pop3);
       pop3->state = MU_POP3_NO_STATE;
 
       /* Parse the answer.  */
       *msg_count = 0;
       lv = 0;
-      sscanf (pop3->ack.buf, "+OK %d %lu", msg_count, &lv);
+      /* FIXME: Error checking */
+      sscanf (pop3->ackbuf, "+OK %lu %lu", &count, &lv);
+      *msg_count = count;
       *size = lv;
       break;
 
diff --git a/libproto/pop/pop3_stls.c b/libproto/pop/pop3_stls.c
index b9984f6..ec31414 100644
--- a/libproto/pop/pop3_stls.c
+++ b/libproto/pop/pop3_stls.c
@@ -25,9 +25,29 @@
 #include <string.h>
 #include <errno.h>
 
+#include <mailutils/pop3.h>
 #include <mailutils/sys/pop3.h>
 #include <mailutils/tls.h>
-#include <mailutils/md5.h>
+#include <mailutils/list.h>
+
+static int
+pop3_swap_streams (mu_pop3_t pop3, mu_stream_t *streams)
+{
+  int rc;
+  
+  if (MU_POP3_FISSET (pop3, MU_POP3_TRACE))
+    rc = mu_stream_ioctl (pop3->carrier, MU_IOCTL_SWAP_STREAM, streams);
+  else if (streams[0] != streams[1])
+    rc = EINVAL;
+  else
+    {
+      mu_stream_t str = streams[0];
+      streams[0] = streams[1] = pop3->carrier;
+      pop3->carrier = str;
+      rc = 0;
+    }
+  return rc;
+}
 
 /*
  * STLS
@@ -38,47 +58,43 @@ mu_pop3_stls (mu_pop3_t pop3)
 {
 #ifdef WITH_TLS
   int status;
-
+  mu_stream_t tlsstream, streams[2];
+  
   /* Sanity checks.  */
   if (pop3 == NULL)
-    {
-      return EINVAL;
-    }
+    return EINVAL;
 
   switch (pop3->state)
     {
     case MU_POP3_NO_STATE:
       status = mu_pop3_writeline (pop3, "STLS\r\n");
       MU_POP3_CHECK_ERROR (pop3, status);
-      mu_pop3_debug_cmd (pop3);
+      MU_POP3_FCLR (pop3, MU_POP3_ACK);
       pop3->state = MU_POP3_STLS;
 
     case MU_POP3_STLS:
-      status = mu_pop3_send (pop3);
+      status = mu_pop3_response (pop3, NULL);
       MU_POP3_CHECK_EAGAIN (pop3, status);
-      pop3->acknowledge = 0;
-      pop3->state = MU_POP3_STLS_ACK;
-
-    case MU_POP3_STLS_ACK:
-      {
-        mu_stream_t tls_stream;
-        status = mu_pop3_response (pop3, NULL, 0, NULL);
-        MU_POP3_CHECK_EAGAIN (pop3, status);
-        mu_pop3_debug_ack (pop3);
-        MU_POP3_CHECK_OK (pop3);
-        status = mu_tls_stream_create_client_from_tcp (&tls_stream, 
pop3->carrier, 0);
-        MU_POP3_CHECK_ERROR (pop3, status);
-        pop3->carrier = tls_stream; 
-        pop3->state = MU_POP3_STLS_CONNECT;
-        break;
-      }
-
+      MU_POP3_CHECK_OK (pop3);
+      pop3->state = MU_POP3_STLS_CONNECT;
+      
     case MU_POP3_STLS_CONNECT:
-      status = mu_stream_open (pop3->carrier);
+      streams[0] = streams[1] = NULL;
+      status = pop3_swap_streams (pop3, streams);
+      MU_POP3_CHECK_EAGAIN (pop3, status);
+      status = mu_tls_client_stream_create (&tlsstream,
+                                           streams[0], streams[1], 0);
+      MU_POP3_CHECK_EAGAIN (pop3, status);
+      status = mu_stream_open (tlsstream);
       MU_POP3_CHECK_EAGAIN (pop3, status);
+      streams[0] = streams[1] = tlsstream;
+      status = pop3_swap_streams (pop3, streams);
+      MU_POP3_CHECK_EAGAIN (pop3, status);
+      /* Invalidate the capability list */
+      mu_list_destroy (&pop3->capa);
       pop3->state = MU_POP3_NO_STATE;
-      break;
-
+      return 0;
+      
       /* They must deal with the error first by reopening.  */
     case MU_POP3_ERROR:
       status = ECANCELED;
@@ -91,7 +107,6 @@ mu_pop3_stls (mu_pop3_t pop3)
 
   return status;
 #else
-  (void)pop3;
   return ENOTSUP;
 #endif
 }
diff --git a/libproto/pop/pop3_stream.c b/libproto/pop/pop3_stream.c
index c1ad6f5..25fdba6 100644
--- a/libproto/pop/pop3_stream.c
+++ b/libproto/pop/pop3_stream.c
@@ -23,124 +23,282 @@
 #include <string.h>
 #include <errno.h>
 #include <stdlib.h>
+#include <mailutils/filter.h>
+#include <mailutils/stream.h>
+#include <mailutils/sys/stream.h>
 #include <mailutils/sys/pop3.h>
 
 /* Implementation of the stream for TOP and RETR.  */
 struct mu_pop3_stream
 {
+  struct _mu_stream stream;
   mu_pop3_t pop3;
   int done;
 };
 
+enum pop3_decode_state
+  {
+    pds_init,  /* initial state */
+    pds_char,  /* Any character excepting [\r\n.] */
+    pds_cr,    /* prev. char was \r */
+    pds_crlf,  /* 2 prev. char were \r\n */
+    pds_dot,   /* 3 prev. chars were \r\n. */
+    pds_dotcr, /* 4 prev. chars were \r\n.\r */
+    pds_end    /* final state, a \r\n.\r\n seen. */
+  };
+
+static int
+newstate (int state, int c)
+{
+  switch (state)
+    {
+    case pds_init:
+      switch (c)
+       {
+       case '\r':
+         return pds_cr;
+       case '.':
+         return pds_dot;
+       }
+      break;
+      
+    case pds_char:
+      switch (c)
+       {
+       case '\r':
+         return pds_cr;
+       }
+      break;
+      
+    case pds_cr:
+      switch (c)
+       {
+       case '\r':
+         return pds_cr;
+       case '\n':
+         return pds_crlf;
+       }
+      break;
+      
+    case pds_crlf:
+      switch (c)
+       {
+       case '\r':
+         return pds_cr;
+       case '.':
+         return pds_dot;
+       }
+      
+    case pds_dot:
+      switch (c)
+       {
+       case '\r':
+         return pds_dotcr;
+       }
+      break;
+
+    case pds_dotcr:
+      switch (c)
+       {
+       case '\n':
+         return pds_end;
+       }
+    }
+  return pds_char;
+}
+
+/* Move min(isize,osize) bytes from iptr to optr, replacing each \r\n
+   with \n. */
+static enum mu_filter_result
+_pop3_decoder (void *xd,
+              enum mu_filter_command cmd,
+              struct mu_filter_io *iobuf)
+{
+  int *pstate = xd;
+  size_t i, j;
+  const unsigned char *iptr;
+  size_t isize;
+  char *optr;
+  size_t osize;
+
+  switch (cmd)
+    {
+    case mu_filter_init:
+      *pstate = pds_init;
+      return mu_filter_ok;
+      
+    case mu_filter_done:
+      return mu_filter_ok;
+      
+    default:
+      break;
+    }
+  
+  iptr = (const unsigned char *) iobuf->input;
+  isize = iobuf->isize;
+  optr = iobuf->output;
+  osize = iobuf->osize;
+
+  for (i = j = 0; *pstate != pds_end && i < isize && j < osize; i++)
+    {
+      unsigned char c = *iptr++;
+
+      if (c == '\r')
+       {
+         if (i + 1 == isize)
+           break;
+         *pstate = newstate (*pstate, c);
+         if (*iptr == '\n')
+           continue;
+       }
+      else if (c == '.' && (*pstate == pds_init || *pstate == pds_crlf))
+       {
+         /* Make sure we have two more characters in the buffer */
+         if (i + 2 == isize)
+           break;
+         *pstate = newstate (*pstate, c);
+         if (*iptr != '\r')
+           continue;
+       }
+      else
+       *pstate = newstate (*pstate, c);
+      optr[j++] = c;
+    }
+  
+  if (*pstate == pds_end)
+    {
+      j -= 2; /* remove the trailing .\n */
+      iobuf->eof = 1;
+    }
+  iobuf->isize = i;
+  iobuf->osize = j;
+  return mu_filter_ok;
+}
+
 static void
-mu_pop3_stream_destroy (mu_stream_t stream)
+_pop3_event_cb (mu_stream_t str, int ev, int flags)
+{
+  if (ev == _MU_STR_EVENT_SET)
+    {
+      mu_transport_t trans[2];
+
+      if (mu_stream_ioctl (str, MU_IOCTL_GET_TRANSPORT, trans) == 0)
+       {
+         struct mu_pop3_stream *sp = (struct mu_pop3_stream *) trans[0];
+         _mu_pop3_xscript_level (sp->pop3, MU_XSCRIPT_NORMAL);
+         sp->pop3->state = MU_POP3_NO_STATE;
+       }
+    }
+}
+
+static int
+mu_pop3_filter_create (mu_stream_t *pstream, mu_stream_t stream)
 {
-  struct mu_pop3_stream *pop3_stream = mu_stream_get_owner (stream);
-  if (pop3_stream)
+  int rc;
+  int *state = malloc (sizeof (*state));
+  if (!state)
+    return ENOMEM;
+  rc = mu_filter_stream_create (pstream, stream,
+                               MU_FILTER_DECODE,
+                               _pop3_decoder, state,
+                               MU_STREAM_READ);
+  if (rc == 0)
     {
-      free (pop3_stream);
+      mu_stream_t str = *pstream;
+      str->event_cb = _pop3_event_cb;
+      str->event_mask = _MU_STR_EOF;
     }
+  return rc;
 }
 
+
 static int
-mu_pop3_stream_read (mu_stream_t stream, char *buf, size_t buflen, mu_off_t 
offset, size_t *pn)
+_mu_pop3_read (struct _mu_stream *str, char *buf, size_t bufsize,
+              size_t *pnread)
 {
-  struct mu_pop3_stream *pop3_stream = mu_stream_get_owner (stream);
-  size_t n = 0;
+  struct mu_pop3_stream *sp = (struct mu_pop3_stream *)str;
+  mu_pop3_t pop3 = sp->pop3;
+  size_t nread;
   int status = 0;
-  char *p = buf;
 
-  (void)offset;
-  if (pop3_stream)
+  if (sp->done)
+    nread = 0;
+  else
     {
-      if (!pop3_stream->done)
+      status = mu_stream_read (pop3->carrier, buf, bufsize, &nread);
+      if (status == 0 && nread == 0)
        {
-         do
-           {
-             size_t nread = 0;
-
-             /* The pop3_readline () function will always read one less to
-                be able to null terminate the buffer, this will cause
-                serious grief for mu_stream_read() where it is legitimate to
-                have a buffer of 1 char.  So we must catch it here.  */
-             if (buflen == 1)
-               {
-                 char buffer[2];
-                 *buffer = '\0';
-                 status = mu_pop3_readline (pop3_stream->pop3, buffer, 2, 
&nread);
-                 *p = *buffer;
-               }
-             else
-               status = mu_pop3_readline (pop3_stream->pop3, p, buflen, 
&nread);
-
-             if (status != 0)
-               break;
-             if (nread == 0)
-               {
-                 pop3_stream->pop3->state = MU_POP3_NO_STATE;
-                 pop3_stream->done = 1;
-                 break;
-               }
-             n += nread;
-             buflen -= nread;
-             p += nread;
-           }
-         while (buflen > 0);
+         pop3->state = MU_POP3_NO_STATE;
+         sp->done = 1;
        }
     }
-  if (pn)
-    *pn = n;
+  *pnread = nread;
   return status;
 }
 
 static int
-mu_pop3_stream_readline (mu_stream_t stream, char *buf, size_t buflen, 
mu_off_t offset, size_t *pn)
+_mu_pop3_readdelim (struct _mu_stream *str, char *buf, size_t bufsize,
+                   int delim, size_t *pnread)
 {
-  struct mu_pop3_stream *pop3_stream = mu_stream_get_owner (stream);
-  size_t n = 0;
+  struct mu_pop3_stream *sp = (struct mu_pop3_stream *)str;
+  mu_pop3_t pop3 = sp->pop3;
+  size_t nread;
   int status = 0;
-
-  (void)offset;
-  if (pop3_stream)
+  
+  if (sp->done)
+    nread = 0;
+  else
     {
-      if (!pop3_stream->done)
+      status = mu_stream_readdelim (pop3->carrier, buf, bufsize, delim,
+                                   &nread);
+      if (status == 0 && nread == 0)
        {
-         status = mu_pop3_readline (pop3_stream->pop3, buf, buflen, &n);
-         if (n == 0)
-           {
-             pop3_stream->pop3->state = MU_POP3_NO_STATE;
-             pop3_stream->done = 1;
-           }
+         pop3->state = MU_POP3_NO_STATE;
+         sp->done = 1;
        }
     }
-  if (pn)
-    *pn = n;
+  *pnread = nread;
   return status;
 }
 
+static int
+_mu_pop3_flush (struct _mu_stream *str)
+{
+  struct mu_pop3_stream *sp = (struct mu_pop3_stream *)str;
+  mu_pop3_t pop3 = sp->pop3;
+  return mu_stream_flush (pop3->carrier);
+}
+
+static int
+_mu_pop3_wait (struct _mu_stream *str, int *pflags, struct timeval *tvp)
+{
+  struct mu_pop3_stream *sp = (struct mu_pop3_stream *)str;
+  mu_pop3_t pop3 = sp->pop3;
+  return mu_stream_wait (pop3->carrier, pflags, tvp);
+}
+
 int
 mu_pop3_stream_create (mu_pop3_t pop3, mu_stream_t *pstream)
 {
-  struct mu_pop3_stream *pop3_stream;
+  struct mu_pop3_stream *sp;
+  mu_stream_t str;
   int status;
-
-  pop3_stream = malloc (sizeof *pop3_stream);
-  if (pop3_stream == NULL)
+  
+  sp = (struct mu_pop3_stream *) _mu_stream_create (sizeof (*sp),
+                                                   MU_STREAM_READ);
+  if (!sp)
     return ENOMEM;
+  sp->stream.read = _mu_pop3_read; 
+  sp->stream.readdelim = _mu_pop3_readdelim; 
+  sp->stream.flush = _mu_pop3_flush;
+  sp->stream.wait = _mu_pop3_wait;
+  
+  sp->pop3 = pop3;
+  sp->done = 0;
+  str = (mu_stream_t) sp;
+  mu_stream_set_buffer (str, mu_buffer_line, 1024);
 
-  pop3_stream->pop3 = pop3;
-  pop3_stream->done = 0;
-
-  status = mu_stream_create (pstream, MU_STREAM_READ | MU_STREAM_NO_CLOSE | 
MU_STREAM_NO_CHECK, pop3_stream);
-  if (status != 0)
-    {
-      free (pop3_stream);
-      return status;
-    }
- 
-  mu_stream_set_read (*pstream, mu_pop3_stream_read, pop3_stream);
-  mu_stream_set_readline (*pstream, mu_pop3_stream_readline, pop3_stream);
-  mu_stream_set_destroy (*pstream, mu_pop3_stream_destroy, pop3_stream);
-                                                                               
                                              
-  return 0;
+  status = mu_pop3_filter_create (pstream, str);
+  mu_stream_unref (str);
+  return status;
 }
diff --git a/libproto/pop/pop3_top.c b/libproto/pop/pop3_top.c
index 4057bb1..c060736 100644
--- a/libproto/pop/pop3_top.c
+++ b/libproto/pop/pop3_top.c
@@ -26,7 +26,8 @@
 #include <mailutils/sys/pop3.h>
 
 int
-mu_pop3_top (mu_pop3_t pop3, unsigned msgno, unsigned int lines, mu_stream_t 
*pstream)
+mu_pop3_top (mu_pop3_t pop3, unsigned msgno, unsigned int lines,
+            mu_stream_t *pstream)
 {
   int status;
 
@@ -40,25 +41,20 @@ mu_pop3_top (mu_pop3_t pop3, unsigned msgno, unsigned int 
lines, mu_stream_t *ps
     case MU_POP3_NO_STATE:
       status = mu_pop3_writeline (pop3, "TOP %d %d\r\n", msgno, lines);
       MU_POP3_CHECK_ERROR (pop3, status);
-      mu_pop3_debug_cmd (pop3);
+      MU_POP3_FCLR (pop3, MU_POP3_ACK);
       pop3->state = MU_POP3_TOP;
 
     case MU_POP3_TOP:
-      status = mu_pop3_send (pop3);
+      status = mu_pop3_response (pop3, NULL);
       MU_POP3_CHECK_EAGAIN (pop3, status);
-      pop3->acknowledge = 0;
-      pop3->state = MU_POP3_TOP_ACK;
-
-    case MU_POP3_TOP_ACK:
-      status = mu_pop3_response (pop3, NULL, 0, NULL);
-      MU_POP3_CHECK_EAGAIN (pop3, status);
-      mu_pop3_debug_ack (pop3);
       MU_POP3_CHECK_OK (pop3);
+      status = mu_pop3_stream_create (pop3, pstream);
+      MU_POP3_CHECK_ERROR (pop3, status);
+      if (mu_pop3_trace_mask (pop3, MU_POP3_TRACE_QRY, MU_XSCRIPT_PAYLOAD))
+       _mu_pop3_xscript_level (pop3, MU_XSCRIPT_PAYLOAD);
       pop3->state = MU_POP3_TOP_RX;
 
     case MU_POP3_TOP_RX:
-      status = mu_pop3_stream_create (pop3, pstream);
-      MU_POP3_CHECK_ERROR (pop3, status);
       break;
 
       /* They must deal with the error first by reopening.  */
diff --git a/libproto/pop/pop3_trace.c b/libproto/pop/pop3_trace.c
new file mode 100644
index 0000000..5fa3d95
--- /dev/null
+++ b/libproto/pop/pop3_trace.c
@@ -0,0 +1,150 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 1999, 2000, 2001, 2007, 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 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General
+   Public License along with this library; if not, write to the
+   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301 USA */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <mailutils/error.h>
+#include <mailutils/nls.h>
+#include <mailutils/stream.h>
+#include <mailutils/sys/pop3.h>
+
+static const char *pop3_prefix[] = {
+  "S: ", "C: "
+};
+
+int
+_mu_pop3_trace_enable (mu_pop3_t pop3)
+{
+  int rc = 0;
+  mu_debug_t debug;
+  mu_stream_t dstr, xstr;
+
+  if (!pop3->carrier)
+    {
+      MU_POP3_FSET (pop3, MU_POP3_TRACE);
+      return 0;
+    }
+  
+  mu_diag_get_debug (&debug);
+  
+  rc = mu_dbgstream_create (&dstr, debug, MU_DIAG_DEBUG, 0);
+  if (rc)
+    mu_error (_("cannot create debug stream; transcript disabled: %s"),
+             mu_strerror (rc));
+  else
+    {
+      rc = mu_xscript_stream_create (&xstr, pop3->carrier, dstr,
+                                    pop3_prefix);
+      if (rc)
+       mu_error (_("cannot create transcript stream: %s"),
+                 mu_strerror (rc));
+      else
+       {
+         mu_stream_unref (pop3->carrier);
+         pop3->carrier = xstr;
+         MU_POP3_FSET (pop3, MU_POP3_TRACE);
+       }
+    }
+
+  return rc;
+}
+
+int
+_mu_pop3_trace_disable (mu_pop3_t pop3)
+{
+  mu_stream_t xstr = pop3->carrier;
+  mu_stream_t stream[2];
+  int rc;
+
+  if (!xstr)
+    return 0;
+  
+  rc = mu_stream_ioctl (xstr, MU_IOCTL_GET_TRANSPORT, stream);
+  if (rc)
+    return rc;
+
+  pop3->carrier = stream[0];
+  mu_stream_destroy (&xstr);
+  MU_POP3_FCLR (pop3, MU_POP3_TRACE);
+  return 0;
+}
+
+int
+mu_pop3_trace (mu_pop3_t pop3, int op)
+{
+  int trace_on = MU_POP3_FISSET (pop3, MU_POP3_TRACE);
+  
+  switch (op)
+    {
+    case MU_POP3_TRACE_SET:
+      if (trace_on)
+       return MU_ERR_EXISTS;
+      return _mu_pop3_trace_enable (pop3);
+      
+    case MU_POP3_TRACE_CLR:
+      if (!trace_on)
+       return MU_ERR_NOENT;
+      return _mu_pop3_trace_disable (pop3);
+
+    case MU_POP3_TRACE_QRY:
+      if (!trace_on)
+       return MU_ERR_NOENT;
+      return 0;
+    }
+  return EINVAL;
+}
+
+int
+mu_pop3_trace_mask (mu_pop3_t pop3, int op, int lev)
+{
+  switch (op)
+    {
+    case MU_POP3_TRACE_SET:
+      pop3->flags |= MU_POP3_XSCRIPT_MASK(lev);
+      break;
+      
+    case MU_POP3_TRACE_CLR:
+      pop3->flags &= ~MU_POP3_XSCRIPT_MASK(lev);
+      break;
+      
+    case MU_POP3_TRACE_QRY:
+      if (pop3->flags & MU_POP3_XSCRIPT_MASK(lev))
+       break;
+      return MU_ERR_NOENT;
+      
+    default:
+      return EINVAL;
+    }
+  return 0;
+}
+
+int
+_mu_pop3_xscript_level (mu_pop3_t pop3, int xlev)
+{
+  if (mu_stream_ioctl (pop3->carrier, MU_IOCTL_LEVEL, &xlev) == 0)
+    return xlev;
+  return MU_XSCRIPT_NORMAL;
+}
+
+  
diff --git a/libproto/pop/pop3_uidl.c b/libproto/pop/pop3_uidl.c
index 71c3ec3..c97cc32 100644
--- a/libproto/pop/pop3_uidl.c
+++ b/libproto/pop/pop3_uidl.c
@@ -30,6 +30,7 @@ int
 mu_pop3_uidl (mu_pop3_t pop3, unsigned int msgno, char **uidl)
 {
   int status;
+  char *space;
 
   if (pop3 == NULL)
     return EINVAL;
@@ -41,52 +42,44 @@ mu_pop3_uidl (mu_pop3_t pop3, unsigned int msgno, char 
**uidl)
     case MU_POP3_NO_STATE:
       status = mu_pop3_writeline (pop3, "UIDL %d\r\n", msgno);
       MU_POP3_CHECK_ERROR (pop3, status);
-      mu_pop3_debug_cmd (pop3);
+      MU_POP3_FCLR (pop3, MU_POP3_ACK);
       pop3->state = MU_POP3_UIDL;
 
     case MU_POP3_UIDL:
-      status = mu_pop3_send (pop3);
+      status = mu_pop3_response (pop3, NULL);
       MU_POP3_CHECK_EAGAIN (pop3, status);
-      pop3->acknowledge = 0;
-      pop3->state = MU_POP3_UIDL_ACK;
-
-    case MU_POP3_UIDL_ACK:
-      status = mu_pop3_response (pop3, NULL, 0, NULL);
-      MU_POP3_CHECK_EAGAIN (pop3, status);
-      mu_pop3_debug_ack (pop3);
       MU_POP3_CHECK_OK (pop3);
       pop3->state = MU_POP3_NO_STATE;
 
       *uidl = NULL;
-      {
-       char *space;
-       /* Format:  +OK msgno uidlstring  */
-
-       /* Pass the "+OK".  */
-       space = strchr (pop3->ack.buf, ' ');
-       if (space)
-         {
-           /* Skip spaces.  */
-           while (*space == ' ') space++;
-           /* Pass the number.  */
-           space = strchr (space, ' ');
-           if (space)
-             {
-               size_t len;
-               /* Skip spaces between msgno and uidlstring  */
-               while (*space == ' ') space++;
-               len = strlen (space);
-               if (space[len - 1] == '\n')
-                 {
-                   space[len - 1] = '\0';
-                   len--;
-                 }
-               *uidl = calloc (len + 1, 1);
-               if (*uidl)
-                 memcpy (*uidl, space, len);
-             }
-         }
-      }
+
+      /* Format:  +OK msgno uidlstring  */
+
+      /* Pass the "+OK".  */
+      space = strchr (pop3->ackbuf, ' ');
+      if (space)
+       {
+         /* Skip spaces.  */
+         while (*space == ' ') space++;
+         /* Pass the number.  */
+         space = strchr (space, ' ');
+         if (space)
+           {
+             size_t len;
+             /* Skip spaces between msgno and uidlstring  */
+             while (*space == ' ') space++;
+             len = strlen (space);
+             if (space[len - 1] == '\n')
+               {
+                 space[len - 1] = '\0';
+                 len--;
+               }
+             *uidl = calloc (len + 1, 1);
+             if (*uidl)
+               memcpy (*uidl, space, len);
+           }
+       }
+
       if (*uidl == NULL) /* What can we do?  */
        {
          *uidl = malloc (1);
diff --git a/libproto/pop/pop3_uidl_cmd.c b/libproto/pop/pop3_uidl_cmd.c
new file mode 100644
index 0000000..23d7866
--- /dev/null
+++ b/libproto/pop/pop3_uidl_cmd.c
@@ -0,0 +1,61 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 2003, 2004, 2007, 2010 Free Software Foundation, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General
+   Public License along with this library; if not, write to the
+   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301 USA */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <mailutils/sys/pop3.h>
+
+int
+mu_pop3_uidl_all_cmd (mu_pop3_t pop3)
+{
+  int status = 0;
+
+  if (pop3 == NULL)
+    return EINVAL;
+
+  switch (pop3->state)
+    {
+    case MU_POP3_NO_STATE:
+      status = mu_pop3_writeline (pop3, "UIDL\r\n");
+      MU_POP3_CHECK_ERROR (pop3, status);
+      MU_POP3_FCLR (pop3, MU_POP3_ACK);
+      pop3->state = MU_POP3_UIDL;
+
+    case MU_POP3_UIDL:
+      status = mu_pop3_response (pop3, NULL);
+      MU_POP3_CHECK_EAGAIN (pop3, status);
+      MU_POP3_CHECK_OK (pop3);
+      pop3->state = MU_POP3_UIDL_RX;
+
+    case MU_POP3_UIDL_RX:
+      break;
+
+      /* They must deal with the error first by reopening.  */
+    case MU_POP3_ERROR:
+      status = ECANCELED;
+      break;
+
+    default:
+      status = EINPROGRESS;
+    }
+
+  return status;
+}
diff --git a/libproto/pop/pop3_uidla.c b/libproto/pop/pop3_uidla.c
index f572e7f..78ff0ff 100644
--- a/libproto/pop/pop3_uidla.c
+++ b/libproto/pop/pop3_uidla.c
@@ -20,56 +20,17 @@
 # include <config.h>
 #endif
 
-#include <string.h>
-# include <errno.h>
-#include <stdlib.h>
 #include <mailutils/sys/pop3.h>
 
 int
 mu_pop3_uidl_all (mu_pop3_t pop3, mu_iterator_t *piterator)
 {
-  int status = 0;
-
-  if (pop3 == NULL)
-    return EINVAL;
-  if (piterator == NULL)
-    return MU_ERR_OUT_PTR_NULL;
-
-  switch (pop3->state)
-    {
-    case MU_POP3_NO_STATE:
-      status = mu_pop3_writeline (pop3, "UIDL\r\n");
-      MU_POP3_CHECK_ERROR (pop3, status);
-      mu_pop3_debug_cmd (pop3);
-      pop3->state = MU_POP3_UIDL;
-
-    case MU_POP3_UIDL:
-      status = mu_pop3_send (pop3);
-      MU_POP3_CHECK_EAGAIN (pop3, status);
-      pop3->acknowledge = 0;
-      pop3->state = MU_POP3_UIDL_ACK;
-
-    case MU_POP3_UIDL_ACK:
-      status = mu_pop3_response (pop3, NULL, 0, NULL);
-      MU_POP3_CHECK_EAGAIN (pop3, status);
-      mu_pop3_debug_ack (pop3);
-      MU_POP3_CHECK_OK (pop3);
-      status = mu_pop3_iterator_create (pop3, piterator);
-      MU_POP3_CHECK_ERROR (pop3, status);
-      pop3->state = MU_POP3_UIDL_RX;
-
-    case MU_POP3_UIDL_RX:
-      /* The mu_iterator_t will read the stream and set the state to 
MU_POP3_NO_STATE when done.  */
-      break;
-
-      /* They must deal with the error first by reopening.  */
-    case MU_POP3_ERROR:
-      status = ECANCELED;
-      break;
-
-    default:
-      status = EINPROGRESS;
-    }
+  int status = mu_pop3_uidl_all_cmd (pop3);
+  if (status)
+    return status;
+  status = mu_pop3_iterator_create (pop3, piterator);
+  MU_POP3_CHECK_ERROR (pop3, status);
+  pop3->state = MU_POP3_UIDL_RX;
 
   return status;
 }
diff --git a/libproto/pop/pop3_uidlas.c b/libproto/pop/pop3_uidlas.c
new file mode 100644
index 0000000..82771fd
--- /dev/null
+++ b/libproto/pop/pop3_uidlas.c
@@ -0,0 +1,36 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 2003, 2004, 2007, 2010 Free Software Foundation, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General
+   Public License along with this library; if not, write to the
+   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301 USA */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <mailutils/sys/pop3.h>
+
+int
+mu_pop3_uidl_all_stream (mu_pop3_t pop3, mu_stream_t *pstream)
+{
+  int status = mu_pop3_uidl_all_cmd (pop3);
+  if (status)
+    return status;
+  status = mu_pop3_stream_create (pop3, pstream);
+  MU_POP3_CHECK_ERROR (pop3, status);
+  pop3->state = MU_POP3_UIDL_RX;
+
+  return status;
+}
diff --git a/libproto/pop/pop3_user.c b/libproto/pop/pop3_user.c
index 334050f..5298a42 100644
--- a/libproto/pop/pop3_user.c
+++ b/libproto/pop/pop3_user.c
@@ -37,19 +37,12 @@ mu_pop3_user (mu_pop3_t pop3, const char *user)
     case MU_POP3_NO_STATE:
       status = mu_pop3_writeline (pop3, "USER %s\r\n", user);
       MU_POP3_CHECK_ERROR (pop3, status);
-      mu_pop3_debug_cmd (pop3);
+      MU_POP3_FCLR (pop3, MU_POP3_ACK);
       pop3->state = MU_POP3_USER;
 
     case MU_POP3_USER:
-      status = mu_pop3_send (pop3);
+      status = mu_pop3_response (pop3, NULL);
       MU_POP3_CHECK_EAGAIN (pop3, status);
-      pop3->acknowledge = 0;
-      pop3->state = MU_POP3_USER_ACK;
-
-    case MU_POP3_USER_ACK:
-      status = mu_pop3_response (pop3, NULL, 0, NULL);
-      MU_POP3_CHECK_EAGAIN (pop3, status);
-      mu_pop3_debug_ack (pop3);
       MU_POP3_CHECK_OK (pop3);
       pop3->state = MU_POP3_NO_STATE;
       break;
diff --git a/libproto/pop/url.c b/libproto/pop/url.c
index 1f112bc..e98b3a6 100644
--- a/libproto/pop/url.c
+++ b/libproto/pop/url.c
@@ -31,8 +31,8 @@
 # include <strings.h>
 #endif
 
-#include <url0.h>
-#include <registrar0.h>
+#include <mailutils/sys/url.h>
+#include <mailutils/sys/registrar.h>
 
 static void url_pop_destroy (mu_url_t url);
 
diff --git a/maidag/maidag.c b/maidag/maidag.c
index ea04f07..894fa61 100644
--- a/maidag/maidag.c
+++ b/maidag/maidag.c
@@ -518,7 +518,7 @@ main (int argc, char *argv[])
   maidag_cfg_init ();
   
   /* Parse command line */
-  mu_argp_init (program_version, NULL);
+  mu_argp_init (NULL, NULL);
 
   mu_m_server_create (&server, program_version);
   mu_m_server_set_conn (server, lmtp_connection);
diff --git a/maidag/mailtmp.c b/maidag/mailtmp.c
index 25e592c..f81bc30 100644
--- a/maidag/mailtmp.c
+++ b/maidag/mailtmp.c
@@ -87,9 +87,9 @@ mail_tmp_add_line (struct mail_tmp *mtmp, char *buf, size_t 
buflen)
              
              time (&t);
              asprintf (&envs, "From %s %s", from, ctime (&t));
-             status = mu_stream_sequential_write (mtmp->stream, 
-                                                  envs,
-                                                  strlen (envs));
+             status = mu_stream_write (mtmp->stream, 
+                                       envs,
+                                       strlen (envs), NULL);
              free (envs);
            }
          else
@@ -104,17 +104,17 @@ mail_tmp_add_line (struct mail_tmp *mtmp, char *buf, 
size_t buflen)
   else if (buflen >= 5 && !memcmp (buf, "From ", 5))
     {
       static char *escape = ">";
-      status = mu_stream_sequential_write (mtmp->stream, escape, 1);
+      status = mu_stream_write (mtmp->stream, escape, 1, NULL);
     }
 
   if (!status)
-    status = mu_stream_sequential_write (mtmp->stream, buf, buflen);
+    status = mu_stream_write (mtmp->stream, buf, buflen, NULL);
       
   if (status)
     {
       maidag_error (_("error writing temporary file: %s"), 
                     mu_strerror (status));
-      mu_stream_destroy (&mtmp->stream, mu_stream_get_owner (mtmp->stream));
+      mu_stream_destroy (&mtmp->stream);
     }
   mtmp->had_nl = buf[buflen-1] == '\n';
   return status;
@@ -128,9 +128,9 @@ mail_tmp_finish (struct mail_tmp *mtmp, mu_mailbox_t *mbox)
   size_t n;
   
   if (!mtmp->had_nl)
-    status = mu_stream_sequential_write (mtmp->stream, newline, 1);
+    status = mu_stream_write (mtmp->stream, newline, 1, NULL);
 
-  status = mu_stream_sequential_write (mtmp->stream, newline, 1);
+  status = mu_stream_write (mtmp->stream, newline, 1, NULL);
   unlink (mtmp->tempfile);
   free (mtmp->tempfile);
   mtmp->tempfile = NULL;
@@ -140,7 +140,7 @@ mail_tmp_finish (struct mail_tmp *mtmp, mu_mailbox_t *mbox)
       errno = status;
       maidag_error (_("error writing temporary file: %s"), 
                     mu_strerror (status));
-      mu_stream_destroy (&mtmp->stream, mu_stream_get_owner (mtmp->stream));
+      mu_stream_destroy (&mtmp->stream);
       return status;
     }
 
@@ -151,7 +151,7 @@ mail_tmp_finish (struct mail_tmp *mtmp, mu_mailbox_t *mbox)
     {
       maidag_error (_("error opening temporary file: %s"), 
                     mu_strerror (status));
-      mu_stream_destroy (&mtmp->stream, mu_stream_get_owner (mtmp->stream));
+      mu_stream_destroy (&mtmp->stream);
       return status;
     }
 
@@ -161,7 +161,7 @@ mail_tmp_finish (struct mail_tmp *mtmp, mu_mailbox_t *mbox)
       errno = status;
       maidag_error (_("error creating temporary message: %s"),
                    mu_strerror (status));
-      mu_stream_destroy (&mtmp->stream, mu_stream_get_owner (mtmp->stream));
+      mu_stream_destroy (&mtmp->stream);
       return status;
     }
 
@@ -184,7 +184,7 @@ mail_tmp_destroy (struct mail_tmp **pmtmp)
          unlink (mtmp->tempfile);
          free (mtmp->tempfile);
        }
-      mu_stream_destroy (&mtmp->stream, mu_stream_get_owner (mtmp->stream));
+      mu_stream_destroy (&mtmp->stream);
       free (*pmtmp);
       *pmtmp = NULL;
     }
diff --git a/mail/decode.c b/mail/decode.c
index 4beadc9..cd1d159 100644
--- a/mail/decode.c
+++ b/mail/decode.c
@@ -116,8 +116,11 @@ display_headers (FILE *out, mu_message_t mesg,
     {
       mu_stream_t stream = NULL;
       if (mu_message_get_header (mesg, &hdr) == 0
-         && mu_header_get_stream (hdr, &stream) == 0)
-       print_stream (stream, out);
+         && mu_header_get_streamref (hdr, &stream) == 0)
+       {
+         print_stream (stream, out);
+         mu_stream_destroy (&stream);
+       }
     }
 }
 
@@ -254,12 +257,12 @@ display_submessage (struct mime_descend_closure *closure, 
void *data)
       
       mu_message_get_body (closure->message, &body);
       mu_message_get_header (closure->message, &hdr);
-      mu_body_get_stream (body, &b_stream);
+      mu_body_get_streamref (body, &b_stream);
 
       /* Can we decode.  */
-      if (mu_filter_create(&d_stream, b_stream, closure->encoding,
-                          MU_FILTER_DECODE, 
-                          MU_STREAM_READ|MU_STREAM_NO_CLOSE) == 0)
+      if (mu_filter_create (&d_stream, b_stream, closure->encoding,
+                           MU_FILTER_DECODE, 
+                           MU_STREAM_READ | MU_STREAM_AUTOCLOSE) == 0)
        stream = d_stream;
       else
        stream = b_stream;
@@ -303,21 +306,20 @@ display_submessage (struct mime_descend_closure *closure, 
void *data)
          if (out != ofile)
            pclose (out);
        }
-      if (d_stream)
-       mu_stream_destroy (&d_stream, NULL);
+      mu_stream_destroy (&stream);
     }
   
   return 0;
 }
 
+/* FIXME: Try to use mu_stream_copy instead */
 static int
 print_stream (mu_stream_t stream, FILE *out)
 {
   char buffer[512];
-  off_t off = 0;
   size_t n = 0;
-
-  while (mu_stream_read (stream, buffer, sizeof (buffer) - 1, off, &n) == 0
+  
+  while (mu_stream_read (stream, buffer, sizeof (buffer) - 1, &n) == 0
         && n != 0)
     {
       if (ml_got_interrupt())
@@ -327,7 +329,6 @@ print_stream (mu_stream_t stream, FILE *out)
        }
       buffer[n] = '\0';
       fprintf (out, "%s", buffer);
-      off += n;
     }
   return 0;
 }
@@ -392,20 +393,18 @@ run_metamail (const char *mailcap_cmd, mu_message_t mesg)
     {
       /* Child process */
       int status;
-      mu_stream_t stream;
+      mu_stream_t stream = NULL;
 
       do /* Fake loop to avoid gotos */
        {
          mu_stream_t pstr;
-         char buffer[512];
-         size_t n;
          char *no_ask;
          
          setenv ("METAMAIL_PAGER", getenv ("PAGER"), 0);
          if (mailvar_get (&no_ask, "mimenoask", mailvar_type_string, 0))
            setenv ("MM_NOASK", no_ask, 1);
          
-         status = mu_message_get_stream (mesg, &stream);
+         status = mu_message_get_streamref (mesg, &stream);
          if (status)
            {
              mu_error ("mu_message_get_stream: %s", mu_strerror (status));
@@ -425,15 +424,9 @@ run_metamail (const char *mailcap_cmd, mu_message_t mesg)
              mu_error ("mu_stream_open: %s", mu_strerror (status));
              break;
            }
-         
-         while (mu_stream_sequential_read (stream,
-                                        buffer, sizeof buffer - 1,
-                                        &n) == 0
-                && n > 0)
-           mu_stream_sequential_write (pstr, buffer, n);
-
+         mu_stream_copy (pstr, stream, 0, NULL);
          mu_stream_close (pstr);
-         mu_stream_destroy (&pstr, mu_stream_get_owner (pstr));
+         mu_stream_destroy (&pstr);
          exit (0);
        }
       while (0);
diff --git a/mail/escape.c b/mail/escape.c
index 41b7f1b..0f3f57e 100644
--- a/mail/escape.c
+++ b/mail/escape.c
@@ -27,16 +27,24 @@ dump_headers (FILE *fp, compose_env_t *env)
 {
   char buffer[512];
   mu_stream_t stream = NULL;
-  size_t off = 0, n;
+  size_t n;
+  int rc;
   
-  mu_header_get_stream (env->header, &stream);
-  while (mu_stream_read (stream, buffer, sizeof buffer - 1, off, &n) == 0
+  rc = mu_header_get_streamref (env->header, &stream);
+  if (rc)
+    {
+      util_error ("mu_header_get_streamref: %s",
+                 mu_stream_strerror (stream, rc));
+      return;
+    }
+  /* FIXME: Use mu_stream_copy */
+  while (mu_stream_read (stream, buffer, sizeof buffer - 1, &n) == 0
         && n != 0)
     {
       buffer[n] = 0;
       fprintf (fp, "%s", buffer);
-      off += n;
     }
+  mu_stream_destroy (&stream);
 }
 
 #define STATE_INIT 0
@@ -55,7 +63,7 @@ parse_headers (FILE *fp, compose_env_t *env)
   size_t n = 0;
   int errcnt = 0, line = 0;
   
-  if ((status = mu_header_create (&header, NULL, 0, NULL)) != 0)
+  if ((status = mu_header_create (&header, NULL, 0)) != 0)
     {
       util_error (_("Cannot create header: %s"), mu_strerror (status));
       return 1;
@@ -139,7 +147,7 @@ parse_headers (FILE *fp, compose_env_t *env)
     {
       char *p;
       
-      mu_header_destroy (&header, NULL);
+      mu_header_destroy (&header);
       p = ml_readline (_("Edit again?"));
       if (mu_true_answer_p (p) == 1)
        return -1;
@@ -147,7 +155,7 @@ parse_headers (FILE *fp, compose_env_t *env)
        return 1;
     }
 
-  mu_header_destroy (&env->header, NULL);
+  mu_header_destroy (&env->header);
   env->header = header;
   return 0;
 }
@@ -425,11 +433,11 @@ escape_insert (int argc, char **argv, compose_env_t 
*send_env MU_ARG_UNUSED)
 int
 quote0 (msgset_t *mspec, mu_message_t mesg, void *data)
 {
+  int rc;
   mu_header_t hdr;
   mu_body_t body;
   mu_stream_t stream;
   char buffer[512];
-  off_t off = 0;
   size_t n = 0;
   char *prefix = "\t";
   
@@ -472,18 +480,25 @@ quote0 (msgset_t *mspec, mu_message_t mesg, void *data)
        }
       fprintf (ofile, "%s\n", prefix);
       mu_message_get_body (mesg, &body);
-      mu_body_get_stream (body, &stream);
+      rc = mu_body_get_streamref (body, &stream);
     }
   else
-    mu_message_get_stream (mesg, &stream);
+    rc = mu_message_get_streamref (mesg, &stream);
+
+  if (rc)
+    {
+      util_error (_("get_streamref error: %s"), mu_strerror (rc));
+      return rc;
+    }
 
-  while (mu_stream_readline (stream, buffer, sizeof buffer - 1, off, &n) == 0
+  /* FIXME: Use mu_stream_copy? */
+  while (mu_stream_readline (stream, buffer, sizeof buffer - 1, &n) == 0
         && n != 0)
     {
       buffer[n] = '\0';
       fprintf (ofile, "%s%s", prefix, buffer);
-      off += n;
     }
+  mu_stream_destroy (&stream);
   return 0;
 }
 
diff --git a/mail/mail.c b/mail/mail.c
index afeb4e1..dba26a2 100644
--- a/mail/mail.c
+++ b/mail/mail.c
@@ -394,7 +394,7 @@ main (int argc, char **argv)
 #ifdef WITH_TLS
   mu_gocs_register ("tls", mu_tls_module_init);
 #endif
-  mu_argp_init (program_version, NULL);
+  mu_argp_init (NULL, NULL);
   if (mu_app_init (&argp, mail_capa, NULL, argc, argv, 0, NULL, &args))
     exit (1);
   
diff --git a/mail/msgset.y b/mail/msgset.y
index 270cded..f2c2a52 100644
--- a/mail/msgset.y
+++ b/mail/msgset.y
@@ -620,7 +620,6 @@ select_body (mu_message_t msg, void *closure)
   size_t size = 0, lines = 0;
   char buffer[128];
   size_t n = 0;
-  off_t offset = 0;
 
   if (noregex)
     mu_strupper (expr);
@@ -630,13 +629,11 @@ select_body (mu_message_t msg, void *closure)
   mu_message_get_body (msg, &body);
   mu_body_size (body, &size);
   mu_body_lines (body, &lines);
-  mu_body_get_stream (body, &stream);
-  status = 0;
+  status = mu_body_get_streamref (body, &stream);
   while (status == 0
-        && mu_stream_readline (stream, buffer, sizeof(buffer)-1, offset, &n) 
== 0
+        && mu_stream_readline (stream, buffer, sizeof(buffer)-1, &n) == 0
         && n > 0)
     {
-      offset += n;
       if (noregex)
        {
          mu_strupper (buffer);
@@ -645,7 +642,7 @@ select_body (mu_message_t msg, void *closure)
       else
        status = regexec (&re, buffer, 0, NULL, 0);
     }
-
+  mu_stream_destroy (&stream);
   if (!noregex)
     regfree (&re);
 
diff --git a/mail/pipe.c b/mail/pipe.c
index 6efb869..bb7ab0a 100644
--- a/mail/pipe.c
+++ b/mail/pipe.c
@@ -33,7 +33,6 @@ mail_pipe (int argc, char **argv)
   FILE *tube;
   msgset_t *list, *mp;
   char buffer[512];
-  off_t off = 0;
   size_t n = 0;
 
   if (argc > 2)
@@ -50,15 +49,15 @@ mail_pipe (int argc, char **argv)
     {
       if (util_get_message (mbox, mp->msg_part[0], &msg) == 0)
        {
-         mu_message_get_stream (msg, &stream);
-         off = 0;
-         while (mu_stream_read (stream, buffer, sizeof (buffer) - 1, off,
-                             &n) == 0 && n != 0)
+         mu_message_get_streamref (msg, &stream);
+         /* FIXME: Use mu_stream_copy */
+         while (mu_stream_read (stream, buffer, sizeof (buffer) - 1, &n) == 0
+                && n != 0)
            {
              buffer[n] = '\0';
              fprintf (tube, "%s", buffer);
-             off += n;
            }
+         mu_stream_destroy (&stream);
          if (mailvar_get (NULL, "page", mailvar_type_boolean, 0) == 0)
            fprintf (tube, "\f\n");
        }
diff --git a/mail/print.c b/mail/print.c
index f4ddf94..89542f6 100644
--- a/mail/print.c
+++ b/mail/print.c
@@ -33,10 +33,10 @@ mail_print_msg (msgset_t *mspec, mu_message_t mesg, void 
*data)
   mu_body_t body;
   mu_stream_t stream;
   char buffer[512];
-  off_t off = 0;
   size_t n = 0, lines = 0;
   FILE *out = ofile;
   int pagelines = util_get_crt ();
+  int status;
   
   mu_message_lines (mesg, &lines);
   if (mailvar_get (NULL, "showenvelope", mailvar_type_boolean, 0) == 0)
@@ -90,12 +90,21 @@ mail_print_msg (msgset_t *mspec, mu_message_t mesg, void 
*data)
        }
       fprintf (out, "\n");
       mu_message_get_body (mesg, &body);
-      mu_body_get_stream (body, &stream);
+      status = mu_body_get_streamref (body, &stream);
     }
   else
-    mu_message_get_stream (mesg, &stream);
-  
-  while (mu_stream_read (stream, buffer, sizeof buffer - 1, off, &n) == 0
+    status = mu_message_get_streamref (mesg, &stream);
+
+  if (status)
+    {
+      mu_error (_("get_stream error: %s"), mu_strerror (status));
+      if (out != ofile)
+       pclose (out);
+      return 0;
+    }
+
+  /* FIXME: Use mu_stream_copy instead? */
+  while (mu_stream_read (stream, buffer, sizeof buffer - 1, &n) == 0
         && n != 0)
     {
       if (ml_got_interrupt())
@@ -105,8 +114,8 @@ mail_print_msg (msgset_t *mspec, mu_message_t mesg, void 
*data)
        }
       buffer[n] = '\0';
       fprintf (out, "%s", buffer);
-      off += n;
     }
+  mu_stream_destroy (&stream);
   if (out != ofile)
     pclose (out);
   
diff --git a/mail/send.c b/mail/send.c
index 6538a49..88c358e 100644
--- a/mail/send.c
+++ b/mail/send.c
@@ -223,7 +223,7 @@ compose_header_set (compose_env_t * env, const char *name,
     return EINVAL;
 
   if (!env->header
-      && (status = mu_header_create (&env->header, NULL, 0, NULL)) != 0)
+      && (status = mu_header_create (&env->header, NULL, 0)) != 0)
     {
       util_error (_("Cannot create header: %s"), mu_strerror (status));
       return status;
@@ -293,34 +293,37 @@ compose_header_get (compose_env_t * env, char *name, char 
*defval)
 }
 
 void
-compose_destroy (compose_env_t * env)
+compose_destroy (compose_env_t *env)
 {
-  mu_header_destroy (&env->header, NULL);
+  mu_header_destroy (&env->header);
   free (env->outfiles);
 }
 
+/* FIXME: Can we use mu_stream_t instead of FILE? If so,
+   replace the loop with a call to mu_stream_copy. */
 static int
 fill_body (mu_message_t msg, FILE *file)
 {
   mu_body_t body = NULL;
   mu_stream_t stream = NULL;
-  off_t offset = 0;
   char *buf = NULL;
   size_t n = 0;
   mu_message_get_body (msg, &body);
-  mu_body_get_stream (body, &stream);
-
+  mu_body_get_streamref (body, &stream);
+  int nullbody = 1;
+  
   while (getline (&buf, &n, file) >= 0)
     {
       size_t len = strlen (buf);
-      mu_stream_write (stream, buf, len, offset, &n);
-      offset += len;
+      if (len)
+       nullbody = 0;
+      mu_stream_write (stream, buf, len, NULL);
     }
-           
+  mu_stream_destroy (&stream);
   if (buf)
     free (buf);
 
-  if (offset == 0)
+  if (nullbody)
     {
       if (mailvar_get (NULL, "nullbody", mailvar_type_boolean, 0) == 0)
        {
@@ -523,7 +526,6 @@ mail_send0 (compose_env_t * env, int save_to)
          int rc;
          
          mu_message_create (&msg, NULL);
-         mu_message_set_header (msg, env->header, NULL);
 
          /* Fill the body.  */
          rc = fill_body (msg, file);
@@ -597,6 +599,8 @@ mail_send0 (compose_env_t * env, int save_to)
                  if (mailvar_get (&sendmail, "sendmail",
                                   mailvar_type_string, 0) == 0)
                    {
+                     mu_message_set_header (msg, env->header, NULL);
+                     env->header = NULL;
                      if (sendmail[0] == '/')
                        msg_to_pipe (sendmail, msg);
                      else
@@ -666,16 +670,16 @@ msg_to_pipe (const char *cmd, mu_message_t msg)
     {
       mu_stream_t stream = NULL;
       char buffer[512];
-      off_t off = 0;
       size_t n = 0;
-      mu_message_get_stream (msg, &stream);
-      while (mu_stream_read (stream, buffer, sizeof buffer - 1, off, &n) == 0
+      /* FIXME: Use mu_stream_copy */
+      mu_message_get_streamref (msg, &stream);
+      while (mu_stream_read (stream, buffer, sizeof buffer - 1, &n) == 0
             && n != 0)
        {
          buffer[n] = '\0';
          fprintf (fp, "%s", buffer);
-         off += n;
        }
+      mu_stream_destroy (&stream);
       pclose (fp);
     }
   else
diff --git a/mail/top.c b/mail/top.c
index 9fa296e..de030af 100644
--- a/mail/top.c
+++ b/mail/top.c
@@ -29,21 +29,22 @@ top0 (msgset_t *mspec, mu_message_t msg, void *data)
   mu_stream_t stream;
   char buf[512];
   size_t n;
-  off_t off;
   int lines;
   
   if (mailvar_get (&lines, "toplines", mailvar_type_number, 1)
       || lines < 0)
     return 1;
 
-  mu_message_get_stream (msg, &stream);
-  for (n = 0, off = 0; lines > 0; lines--, off += n)
+  /* FIXME: Use mu_stream_copy */
+  mu_message_get_streamref (msg, &stream);
+  for (; lines > 0; lines--)
     {
-      int status = mu_stream_readline (stream, buf, sizeof (buf), off, &n);
+      int status = mu_stream_readline (stream, buf, sizeof (buf), &n);
       if (status != 0 || n == 0)
        break;
       fprintf (ofile, "%s", buf);
     }
+  mu_stream_destroy (&stream);
   set_cursor (mspec->msg_part[0]);
 
   util_mark_read (msg);
diff --git a/mail/util.c b/mail/util.c
index 013ae83..c64496d 100644
--- a/mail/util.c
+++ b/mail/util.c
@@ -911,7 +911,7 @@ util_header_expand (mu_header_t *phdr)
   mu_header_t hdr;
   int errcnt = 0, rc;
   
-  rc = mu_header_create (&hdr, "", 0, NULL);
+  rc = mu_header_create (&hdr, "", 0);
   if (rc)
     {
       util_error (_("Cannot create temporary header: %s"), mu_strerror (rc));
@@ -990,11 +990,11 @@ util_header_expand (mu_header_t *phdr)
 
   if (errcnt == 0)
     {
-      mu_header_destroy (phdr, NULL);
+      mu_header_destroy (phdr);
       *phdr = hdr;
     }
   else
-    mu_header_destroy (&hdr, NULL);
+    mu_header_destroy (&hdr);
 
   return errcnt;
 }
diff --git a/mail/write.c b/mail/write.c
index dafb7b9..ffaa44f 100644
--- a/mail/write.c
+++ b/mail/write.c
@@ -86,7 +86,6 @@ mail_write (int argc, char **argv)
     {
       mu_attribute_t attr;
       char buffer[512];
-      off_t off = 0;
       size_t n = 0;
 
       if (util_get_message (mbox, mp->msg_part[0], &msg))
@@ -99,16 +98,17 @@ mail_write (int argc, char **argv)
       mu_body_lines (bod, &size);
       total_lines += size;
 
-      mu_body_get_stream (bod, &stream);
+      /* FIXME: Use mu_stream_copy */
+      mu_body_get_streamref (bod, &stream);
       /* should there be a separator? */
-      while (mu_stream_read(stream, buffer, sizeof (buffer) - 1, off, &n) == 0
+      while (mu_stream_read (stream, buffer, sizeof (buffer) - 1, &n) == 0
             && n != 0)
        {
          buffer[n] = '\0';
          fprintf (output, "%s", buffer);
-         off += n;
        }
-
+      mu_stream_destroy (&stream);
+      
       /* mark as saved. */
 
       mu_message_get_attribute (msg, &attr);
diff --git a/mailbox/Makefile.am b/mailbox/Makefile.am
index 96c203a..c24c257 100644
--- a/mailbox/Makefile.am
+++ b/mailbox/Makefile.am
@@ -56,17 +56,20 @@ libmailutils_la_SOURCES = \
  attribute.c\
  auth.c\
  base64.c\
+ binflt.c\
  body.c\
  cstrcasecmp.c\
  cfg_driver.c\
  cfg_format.c\
  cfg_lexer.c\
  cfg_parser.c\
+ crlfflt.c\
  cstrlower.c\
  cstrupper.c\
  daemon.c\
  date.c\
  dbgstderr.c\
+ dbgstream.c\
  dbgsyslog.c\
  debug.c\
  diag.c\
@@ -75,17 +78,18 @@ libmailutils_la_SOURCES = \
  file_stream.c\
  filter.c\
  filter_iconv.c\
- filter_rfc822.c\
- filter_trans.c\
+ fltstream.c\
  folder.c\
  freeitem.c\
  gdebug.c\
  gocs.c\
  hdritr.c\
  header.c\
+ iostream.c\
  iterator.c\
  ipsrv.c\
  kwd.c\
+ linelenflt.c\
  list.c\
  listlist.c\
  locale.c\
@@ -104,6 +108,7 @@ libmailutils_la_SOURCES = \
  mimehdr.c\
  mkfilename.c\
  monitor.c\
+ msgscan.c\
  msrv.c\
  mu_auth.c\
  muctype.c\
@@ -112,13 +117,17 @@ libmailutils_la_SOURCES = \
  muerror.c\
  muerrno.c\
  nls.c\
+ nullrec.c\
  observer.c\
  opool.c\
  parse822.c\
  parsedate.c\
  permstr.c\
  progmailer.c\
+ prog_stream.c\
  property.c\
+ qpflt.c\
+ rdcache_stream.c\
  registrar.c\
  refcount.c\
  rfc2047.c\
@@ -126,20 +135,27 @@ libmailutils_la_SOURCES = \
  secret.c\
  server.c\
  socket_stream.c\
+ stdio_stream.c\
  stream.c\
+ stream_printf.c\
+ stream_vprintf.c\
+ streamcpy.c\
+ streamref.c\
  strltrim.c\
  strskip.c\
  stripws.c\
  strrtrim.c\
  syslog.c\
  system.c\
+ temp_file_stream.c\
  ticket.c\
  tcp.c\
  url.c\
  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/alloc.c b/mailbox/alloc.c
index f2e0c64..05801bb 100644
--- a/mailbox/alloc.c
+++ b/mailbox/alloc.c
@@ -1,19 +1,19 @@
 /* Error-proof memory allocation functions.
    Copyright (C) 2008, 2010 Free Software Foundation, Inc.
 
-   GNU Mailutils is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public License as
-   published by the Free Software Foundation; either version 3, or (at
-   your option) any later version.
+   This 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 program is distributed in the hope that it will be useful, but
-   WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   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/>. */
 
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
 #ifdef HAVE_CONFIG_H
 # include <config.h>
 #endif
diff --git a/mailbox/amd.c b/mailbox/amd.c
index 3e275eb..a263178 100644
--- a/mailbox/amd.c
+++ b/mailbox/amd.c
@@ -68,10 +68,11 @@
 #include <mailutils/stream.h>
 #include <mailutils/url.h>
 #include <mailutils/observer.h>
-#include <mailbox0.h>
-#include <registrar0.h>
-#include <url0.h>
-#include <amd.h>
+#include <mailutils/sys/stream.h>
+#include <mailutils/sys/mailbox.h>
+#include <mailutils/sys/registrar.h>
+#include <mailutils/sys/url.h>
+#include <mailutils/sys/amd.h>
 
 static void amd_destroy (mu_mailbox_t mailbox);
 static int amd_open (mu_mailbox_t, int);
@@ -91,15 +92,10 @@ static int amd_scan (mu_mailbox_t, size_t, size_t *);
 static int amd_is_updated (mu_mailbox_t);
 static int amd_get_size (mu_mailbox_t, mu_off_t *);
 
-static int amd_body_read (mu_stream_t, char *, size_t, mu_off_t, size_t *);
-static int amd_body_readline (mu_stream_t, char *, size_t, mu_off_t, size_t *);
-static int amd_stream_size (mu_stream_t stream, mu_off_t *psize);
-
 static int amd_body_size (mu_body_t body, size_t *psize);
 static int amd_body_lines (mu_body_t body, size_t *plines);
 
-static int amd_header_fill (mu_header_t header, char *buffer, size_t len,
-                           mu_off_t off, size_t *pnread);
+static int amd_header_fill (void *data, char **pbuf, size_t *plen);
 
 static int amd_get_attr_flags (mu_attribute_t attr, int *pflags);
 static int amd_set_attr_flags (mu_attribute_t attr, int flags);
@@ -116,6 +112,26 @@ static int amd_envelope_date (mu_envelope_t envelope, char 
*buf, size_t len,
                              size_t *psize);
 static int amd_envelope_sender (mu_envelope_t envelope, char *buf, size_t len,
                                size_t *psize);
+
+
+static int amd_body_stream_read (mu_stream_t str, char *buffer,
+                                size_t buflen,
+                                size_t *pnread);
+static int amd_body_stream_readdelim (mu_stream_t is,
+                                     char *buffer, size_t buflen,
+                                     int delim,
+                                     size_t *pnread);
+static int amd_body_stream_size (mu_stream_t str, mu_off_t *psize);
+static int amd_body_stream_seek (mu_stream_t str, mu_off_t off, 
+                                mu_off_t *presult);
+
+struct _amd_body_stream
+{
+  struct _mu_stream stream;
+  mu_body_t body;
+  mu_off_t off;
+};
+
 
 /* Operations on message array */
 
@@ -429,7 +445,7 @@ _amd_attach_message (mu_mailbox_t mailbox, struct 
_amd_message *mhm,
   /* Set the header.  */
   {
     mu_header_t header = NULL;
-    status = mu_header_create (&header, NULL, 0, msg);
+    status = mu_header_create (&header, NULL, 0);
     if (status != 0)
       {
        mu_message_destroy (&msg, mhm);
@@ -460,25 +476,30 @@ _amd_attach_message (mu_mailbox_t mailbox, struct 
_amd_message *mhm,
   /* Prepare the body.  */
   {
     mu_body_t body = NULL;
-    mu_stream_t stream = NULL;
-    if ((status = mu_body_create (&body, msg)) != 0
-       || (status = mu_stream_create (&stream,
-                                   mailbox->flags | MU_STREAM_SEEKABLE,
-                                   body)) != 0)
+    struct _amd_body_stream *str;
+    
+    if ((status = mu_body_create (&body, msg)) != 0)
+      return status;
+
+    str = (struct _amd_body_stream *)
+              _mu_stream_create (sizeof (*str),
+                                mailbox->flags | MU_STREAM_SEEK);
+    if (!str)
       {
        mu_body_destroy (&body, msg);
-       mu_stream_destroy (&stream, body);
        mu_message_destroy (&msg, mhm);
-       return status;
+       return ENOMEM;
       }
-    mu_stream_set_read (stream, amd_body_read, body);
-    mu_stream_set_readline (stream, amd_body_readline, body);
-    mu_stream_set_size (stream, amd_stream_size, body);
-    mu_body_set_stream (body, stream, msg);
+    str->stream.read = amd_body_stream_read;
+    str->stream.readdelim = amd_body_stream_readdelim;
+    str->stream.size = amd_body_stream_size;
+    str->stream.seek = amd_body_stream_seek;
+    mu_body_set_stream (body, (mu_stream_t) str, msg);
     mu_body_clear_modified (body);
     mu_body_set_size (body, amd_body_size, msg);
     mu_body_set_lines (body, amd_body_lines, msg);
     mu_message_set_body (msg, body, mhm);
+    str->body = body;
   }
 
   /* Set the envelope.  */
@@ -602,7 +623,7 @@ _amd_message_save (struct _amd_data *amd, struct 
_amd_message *mhm,
 {
   mu_stream_t stream = NULL;
   char *name = NULL, *buf = NULL, *msg_name, *old_name;
-  size_t n, off = 0;
+  size_t n;
   size_t bsize;
   size_t nlines, nbytes;
   size_t new_body_start, new_header_lines;
@@ -657,10 +678,21 @@ _amd_message_save (struct _amd_data *amd, struct 
_amd_message *mhm,
 
   /* Copy flags */
   mu_message_get_header (msg, &hdr);
-  mu_header_get_stream (hdr, &stream);
-  off = 0;
+  mu_header_get_streamref (hdr, &stream);
+  status = mu_stream_seek (stream, 0, MU_SEEK_SET, NULL);
+  if (status)
+    {
+      /* FIXME: Provide a common exit point for all error
+        cases */
+      unlink (name);
+      free (name);
+      free (msg_name);
+      mu_stream_destroy (&stream);
+      return status;
+    }
+      
   nlines = nbytes = 0;
-  while ((status = mu_stream_readline (stream, buf, bsize, off, &n)) == 0
+  while ((status = mu_stream_readline (stream, buf, bsize, &n)) == 0
         && n != 0)
     {
       if (_amd_delim (buf))
@@ -677,10 +709,9 @@ _amd_message_save (struct _amd_data *amd, struct 
_amd_message *mhm,
          nlines++;
          nbytes += fprintf (fp, "%s", buf);
        }
-      
-      off += n;
     }
-
+  mu_stream_destroy (&stream);
+  
   /* Add imapbase */
   if (!(amd->mailbox->flags & MU_STREAM_APPEND)
       && amd->next_uid
@@ -729,20 +760,29 @@ _amd_message_save (struct _amd_data *amd, struct 
_amd_message *mhm,
   /* Copy message body */
 
   mu_message_get_body (msg, &body);
-  mu_body_get_stream (body, &stream);
-  off = 0;
+  mu_body_get_streamref (body, &stream);
+  status = mu_stream_seek (stream, 0, MU_SEEK_SET, NULL);
+  if (status)
+    {
+      unlink (name);
+      free (name);
+      free (msg_name);
+      mu_stream_destroy (&stream);
+      return status;
+    }
+    
   nlines = 0;
-  while (mu_stream_read (stream, buf, bsize, off, &n) == 0 && n != 0)
+  while (mu_stream_read (stream, buf, bsize, &n) == 0 && n != 0)
     {
       char *p;
       for (p = buf; p < buf + n; p++)
        if (*p == '\n')
          nlines++;
       fwrite (buf, 1, n, fp);
-      off += n;
       nbytes += n;
     }
-
+  mu_stream_destroy (&stream);
+  
   mhm->header_lines = new_header_lines;
   mhm->body_start = new_body_start;
   mhm->body_lines = nlines;
@@ -1300,75 +1340,78 @@ amd_scan_message (struct _amd_message *mhm)
 {
   mu_stream_t stream = mhm->stream;
   char buf[1024];
-  mu_off_t off = 0;
+  size_t off;
   size_t n;
   int status;
   int in_header = 1;
   size_t hlines = 0;
   size_t blines = 0;
   size_t body_start = 0;
+  struct stat st;
+  char *msg_name;
 
   /* Check if the message was modified after the last scan */
-  if (mhm->mtime)
-    {
-      struct stat st;
-      char *msg_name;
-
-      status = mhm->amd->cur_msg_file_name (mhm, &msg_name);
-      if (status)
-       return status;
+  status = mhm->amd->cur_msg_file_name (mhm, &msg_name);
+  if (status)
+    return status;
 
-      if (stat (msg_name, &st) == 0 && st.st_mtime == mhm->mtime)
-       {
-         /* Nothing to do */
-         free (msg_name);
-         return 0;
-       }
+  if (stat (msg_name, &st) == 0 && st.st_mtime == mhm->mtime)
+    {
+      /* Nothing to do */
       free (msg_name);
+      return 0;
     }
+  free (msg_name);
 
-  while ((status = mu_stream_readline (stream, buf, sizeof (buf), off, &n) == 
0)
-        && n != 0)
-    {
-      if (in_header)
-       {
-         if (buf[0] == '\n')
-           {
-             in_header = 0;
-             body_start = off+1;
-           }
-         if (buf[n - 1] == '\n')
-           hlines++;
+  off = 0;
+  status = mu_stream_seek (stream, 0, MU_SEEK_SET, NULL);
+  if (status == 0)
+    while ((status = mu_stream_readline (stream, buf, sizeof (buf), &n)) == 0
+          && n != 0)
+      {
+       if (in_header)
+         {
+           if (buf[0] == '\n')
+             {
+               in_header = 0;
+               body_start = off + 1;
+             }
+           if (buf[n - 1] == '\n')
+             hlines++;
+           
+           /* Process particular attributes */
+           if (mu_c_strncasecmp (buf, "status:", 7) == 0)
+             {
+               int deleted = mhm->attr_flags & MU_ATTRIBUTE_DELETED;
+               mu_string_to_flags (buf, &mhm->attr_flags);
+               mhm->attr_flags |= deleted;
+             }
+           else if (mu_c_strncasecmp (buf, "x-imapbase:", 11) == 0)
+             {
+               char *p;
+               mhm->amd->uidvalidity = strtoul (buf + 11, &p, 10);
+               /* second number is next uid. Ignored */
+             }
+         }
+       else
+         {
+           if (buf[n - 1] == '\n')
+             blines++;
+         }
+       off += n;
+      }
 
-         /* Process particular attributes */
-         if (mu_c_strncasecmp (buf, "status:", 7) == 0)
-           {
-             int deleted = mhm->attr_flags & MU_ATTRIBUTE_DELETED;
-             mu_string_to_flags (buf, &mhm->attr_flags);
-             mhm->attr_flags |= deleted;
-           }
-         else if (mu_c_strncasecmp (buf, "x-imapbase:", 11) == 0)
-           {
-             char *p;
-             mhm->amd->uidvalidity = strtoul (buf + 11, &p, 10);
-             /* second number is next uid. Ignored */
-           }
-       }
-      else
-       {
-         if (buf[n - 1] == '\n')
-           blines++;
-       }
-      off += n;
+  if (status == 0)
+    {
+      mhm->mtime = st.st_mtime;
+      if (!body_start)
+       body_start = off;
+      mhm->header_lines = hlines;
+      mhm->body_lines = blines;
+      mhm->body_start = body_start;
+      mhm->body_end = off;
     }
-
-  if (!body_start)
-    body_start = off;
-  mhm->header_lines = hlines;
-  mhm->body_lines = blines;
-  mhm->body_start = body_start;
-  mhm->body_end = off;
-  return 0;
+  return status;
 }
 
 static int
@@ -1512,10 +1555,13 @@ amd_message_stream_open (struct _amd_message *mhm)
   if (status != 0)
     return status;
 
+  /* FIXME: Select buffer size dynamically */
+  mu_stream_set_buffer (mhm->stream, mu_buffer_full, 16384);
+  
   status = mu_stream_open (mhm->stream);
 
   if (status != 0)
-    mu_stream_destroy (&mhm->stream, NULL);
+    mu_stream_destroy (&mhm->stream);
 
   if (status == 0)
     status = amd_scan_message (mhm);
@@ -1542,20 +1588,23 @@ amd_check_message (struct _amd_message *mhm)
 }
 
 /* Reading functions */
-
 static int
-amd_readstream (struct _amd_message *mhm, char *buffer, size_t buflen,
-              mu_off_t off, size_t *pnread, int isreadline,
-              mu_off_t start, mu_off_t end)
+amd_body_stream_read (mu_stream_t is, char *buffer, size_t buflen,
+                     size_t *pnread)
 {
+  struct _amd_body_stream *amdstr = (struct _amd_body_stream *)is;
+  mu_body_t body = amdstr->body;
+  mu_message_t msg = mu_body_get_owner (body);
+  struct _amd_message *mhm = mu_message_get_owner (msg);
   size_t nread = 0;
   int status = 0;
   mu_off_t ln;
 
+  amd_pool_open (mhm);
+
   if (buffer == NULL || buflen == 0)
     {
-      if (pnread)
-       *pnread = nread;
+      *pnread = nread;
       return 0;
     }
 
@@ -1566,60 +1615,112 @@ amd_readstream (struct _amd_message *mhm, char 
*buffer, size_t buflen,
   pthread_cleanup_push (amd_cleanup, (void *)mhm->amd->mailbox);
 #endif
 
-  ln = end - (start + off);
+  ln = mhm->body_end - (mhm->body_start + amdstr->off);
   if (ln > 0)
     {
-      /* Position the file pointer and the buffer.  */
       nread = ((size_t)ln < buflen) ? (size_t)ln : buflen;
-      if (isreadline)
-       status = mu_stream_readline (mhm->stream, buffer, buflen,
-                                 start + off, &nread);
-      else
-       status = mu_stream_read (mhm->stream, buffer, nread,
-                             start + off, &nread);
+      status = mu_stream_seek (mhm->stream, mhm->body_start + amdstr->off,
+                              MU_SEEK_SET, NULL);
+      if (status == 0)
+       {
+         status = mu_stream_read (mhm->stream, buffer, nread, &nread);
+         amdstr->off += nread;
+       }
     }
 
+  *pnread = nread;
+
   mu_monitor_unlock (mhm->amd->mailbox->monitor);
 #ifdef WITH_PTHREAD
   pthread_cleanup_pop (0);
 #endif
 
-  if (pnread)
-    *pnread = nread;
   return status;
 }
 
 static int
-amd_body_read (mu_stream_t is, char *buffer, size_t buflen, mu_off_t off,
-             size_t *pnread)
+amd_body_stream_readdelim (mu_stream_t is, char *buffer, size_t buflen,
+                          int delim,
+                          size_t *pnread)
 {
-  mu_body_t body = mu_stream_get_owner (is);
+  struct _amd_body_stream *amdstr = (struct _amd_body_stream *)is;
+  mu_body_t body = amdstr->body;
   mu_message_t msg = mu_body_get_owner (body);
   struct _amd_message *mhm = mu_message_get_owner (msg);
+  int status = 0;
+
   amd_pool_open (mhm);
-  return amd_readstream (mhm, buffer, buflen, off, pnread, 0,
-                       mhm->body_start, mhm->body_end);
+
+  if (buffer == NULL || buflen == 0)
+    {
+      if (pnread)
+       *pnread = 0;
+      return 0;
+    }
+
+  mu_monitor_rdlock (mhm->amd->mailbox->monitor);
+#ifdef WITH_PTHREAD
+  /* read() is cancellation point since we're doing a potentially
+     long operation.  Lets make sure we clean the state.  */
+  pthread_cleanup_push (amd_cleanup, (void *)mhm->amd->mailbox);
+#endif
+
+  status = mu_stream_seek (mhm->stream, mhm->body_start + amdstr->off,
+                          MU_SEEK_SET, NULL);
+  if (status == 0)
+    {
+      size_t nread = 0;
+      size_t ln;
+         
+      ln = mhm->body_end - (mhm->body_start + amdstr->off) + 1;
+      if (ln > 0)
+       {
+         size_t rdsize = ((size_t)ln < buflen) ? (size_t)ln : buflen;
+         status = mu_stream_readdelim (mhm->stream, buffer, rdsize,
+                                       delim, &nread);
+         amdstr->off += rdsize;
+       }
+
+      if (pnread)
+       *pnread = nread;
+    }
+
+  mu_monitor_unlock (mhm->amd->mailbox->monitor);
+#ifdef WITH_PTHREAD
+  pthread_cleanup_pop (0);
+#endif
+
+  return status;
 }
 
 static int
-amd_body_readline (mu_stream_t is, char *buffer, size_t buflen,
-                 mu_off_t off, size_t *pnread)
+amd_body_stream_seek (mu_stream_t str, mu_off_t off, mu_off_t *presult)
 {
-  mu_body_t body = mu_stream_get_owner (is);
-  mu_message_t msg = mu_body_get_owner (body);
-  struct _amd_message *mhm = mu_message_get_owner (msg);
-  amd_pool_open (mhm);
-  return amd_readstream (mhm, buffer, buflen, off, pnread, 1,
-                       mhm->body_start, mhm->body_end);
+  size_t size;
+  struct _amd_body_stream *amdstr = (struct _amd_body_stream *)str;
+  
+  amd_body_size (amdstr->body, &size);
+
+  if (off < 0 || off > size)
+    return ESPIPE;
+
+  amdstr->off = off;
+  if (presult)
+    *presult = off;
+  return 0;
 }
 
 /* Return corresponding sizes */
 
 static int
-amd_stream_size (mu_stream_t stream, mu_off_t *psize)
+amd_body_stream_size (mu_stream_t stream, mu_off_t *psize)
 {
-  mu_body_t body = mu_stream_get_owner (stream);
-  return amd_body_size (body, (size_t*) psize);
+  mu_body_t body = ((struct _amd_body_stream *)stream)->body;
+  size_t size;
+  int rc = amd_body_size (body, &size);
+  if (rc == 0)
+    *psize = size;
+  return rc;
 }
 
 static int
@@ -1650,16 +1751,46 @@ amd_body_lines (mu_body_t body, size_t *plines)
 
 /* Headers */
 static int
-amd_header_fill (mu_header_t header, char *buffer, size_t len,
-               mu_off_t off, size_t *pnread)
+amd_header_fill (void *data, char **pbuf, size_t *plen)
 {
-  mu_message_t msg = mu_header_get_owner (header);
+  char *buffer;
+  size_t len;
+  mu_message_t msg = data;
   struct _amd_message *mhm = mu_message_get_owner (msg);
-  int status = amd_pool_open (mhm);
+  int status, rc;
+  mu_off_t pos;
+  
+  status = amd_pool_open (mhm);
   if (status)
     return status;
-  return amd_readstream (mhm, buffer, len, off, pnread, 0,
-                        0, mhm->body_start);
+
+  len = mhm->body_start;
+  buffer = malloc (len);
+  if (!buffer)
+    return ENOMEM;
+  
+  status = mu_stream_seek (mhm->stream, 0, MU_SEEK_CUR, &pos);
+  if (status)
+    return status;
+  status = mu_stream_seek (mhm->stream, 0, MU_SEEK_SET, NULL);
+  if (status)
+    return status;
+
+  status = mu_stream_read (mhm->stream, buffer, len, NULL);
+  rc = mu_stream_seek (mhm->stream, pos, MU_SEEK_SET, NULL);
+
+  if (!status)
+    status = rc;
+  
+  if (status)
+    {
+      free (buffer);
+      return status;
+    }
+
+  *plen = len;
+  *pbuf = buffer;
+  return 0;
 }
 
 /* Attributes */
diff --git a/mailbox/argcv.c b/mailbox/argcv.c
index c31836c..636b9af 100644
--- a/mailbox/argcv.c
+++ b/mailbox/argcv.c
@@ -447,6 +447,8 @@ argcv_get (const char *command, const char *delim, const 
char *cmnt,
 void
 argcv_free (int argc, char **argv)
 {
+  if (argc <= 0)
+    return;
   while (--argc >= 0)
     if (argv[argc])
       free (argv[argc]);
diff --git a/mailbox/assoc.c b/mailbox/assoc.c
index 418fa08..a0c13a0 100644
--- a/mailbox/assoc.c
+++ b/mailbox/assoc.c
@@ -29,7 +29,7 @@
 #include <mailutils/iterator.h>
 #include <mailutils/mutil.h>
 #include <mailutils/cstr.h>
-#include <iterator0.h>
+#include <mailutils/sys/iterator.h>
 
 /* |hash_size| defines a sequence of symbol table sizes. These are prime
    numbers, the distance between each pair of them grows exponentially,
diff --git a/mailbox/attachment.c b/mailbox/attachment.c
index 8f02b4f..6bed79f 100644
--- a/mailbox/attachment.c
+++ b/mailbox/attachment.c
@@ -52,12 +52,9 @@ struct _mu_mime_io_buffer
   unsigned int refcnt;
   char *buf;
   size_t bufsize;
-  size_t nbytes;
   char *charset;
   mu_header_t hdr;
   mu_message_t msg;
-  size_t ioffset;
-  size_t ooffset;
   mu_stream_t stream;  /* output file/decoding stream for saving attachment */
   mu_stream_t fstream; /* output file stream for saving attachment */
 };
@@ -99,9 +96,8 @@ mu_message_create_attachment (const char *content_type, const 
char *encoding,
          else
            {
              sprintf (header, MSG_HDR, content_type, name, encoding, name);
-             if ((ret =
-                  mu_header_create (&hdr, header, strlen (header),
-                                    *newmsg)) == 0)
+             if ((ret = mu_header_create (&hdr, header, strlen (header)))
+                 == 0)
                {
                  mu_message_get_body (*newmsg, &body);
                  if ((ret =
@@ -130,9 +126,9 @@ mu_message_create_attachment (const char *content_type, 
const char *encoding,
       if (*newmsg)
        mu_message_destroy (newmsg, NULL);
       if (hdr)
-       mu_header_destroy (&hdr, NULL);
+       mu_header_destroy (&hdr);
       if (fstream)
-       mu_stream_destroy (&fstream, NULL);
+       mu_stream_destroy (&fstream);
       if (fname)
        free (fname);
     }
@@ -211,12 +207,10 @@ _attachment_free (struct _mu_mime_io_buffer *info, int 
free_message)
       if (info->msg)
        mu_message_destroy (&info->msg, NULL);
       else if (info->hdr)
-       mu_header_destroy (&info->hdr, NULL);
+       mu_header_destroy (&info->hdr);
     }
   info->msg = NULL;
   info->hdr = NULL;
-  info->ioffset = 0;
-  info->ooffset = 0;
   info->stream = NULL;
   info->fstream = NULL;
   if (--info->refcnt == 0)
@@ -229,15 +223,20 @@ _attachment_free (struct _mu_mime_io_buffer *info, int 
free_message)
 
 static int
 _attachment_setup (mu_mime_io_buffer_t *pinfo, mu_message_t msg,
-                  mu_stream_t *stream)
+                  mu_stream_t *pstream)
 {
   int ret;
   mu_body_t body;
   mu_mime_io_buffer_t info;
-  
+  mu_stream_t stream;
+    
   if ((ret = mu_message_get_body (msg, &body)) != 0 ||
-      (ret = mu_body_get_stream (body, stream)) != 0)
+      (ret = mu_body_get_streamref (body, &stream)) != 0)
+    return ret;
+  ret = mu_stream_seek (stream, 0, SEEK_SET, NULL);
+  if (ret)
     return ret;
+  *pstream = stream;
   if (*pinfo)
     {
       info = *pinfo;
@@ -255,6 +254,7 @@ _attachment_setup (mu_mime_io_buffer_t *pinfo, mu_message_t 
msg,
       _attachment_free (info, 0);
       return ENOMEM;
     }
+  info->msg = msg;
   *pinfo = info;
   return 0;
 }
@@ -314,42 +314,30 @@ mu_message_save_attachment (mu_message_t msg, const char 
*filename,
              ret =
                mu_filter_create (&info->stream, istream, content_encoding,
                                  MU_FILTER_DECODE,
-                                 MU_STREAM_READ | MU_STREAM_NO_CLOSE);
+                                 MU_STREAM_READ);
              free (content_encoding_mem);
            }
        }
     }
   if (info->stream && istream)
     {
-      if (info->nbytes)
-       memmove (info->buf, info->buf + (info->bufsize - info->nbytes),
-                info->nbytes);
-      while ((ret == 0 && info->nbytes)
-            ||
-            ((ret =
-              mu_stream_read (info->stream, info->buf, info->bufsize,
-                              info->ioffset, &info->nbytes)) == 0
-             && info->nbytes))
+      while (((ret =
+              mu_stream_read (info->stream, info->buf, BUF_SIZE, 
+                              &nbytes)) == 0 && nbytes))
        {
-         info->ioffset += info->nbytes;
-         while (info->nbytes)
-           {
-             if ((ret =
-                  mu_stream_write (info->fstream, info->buf, info->nbytes,
-                                   info->ooffset, &nbytes)) != 0)
-               break;
-             info->nbytes -= nbytes;
-             info->ooffset += nbytes;
-           }
+         if ((ret =
+              mu_stream_write (info->fstream, info->buf, nbytes, NULL)) != 0)
+           break;
        }
     }
   if (ret != EAGAIN && info)
     {
       mu_stream_close (info->fstream);
-      mu_stream_destroy (&info->stream, NULL);
-      mu_stream_destroy (&info->fstream, NULL);
+      mu_stream_destroy (&info->stream);
+      mu_stream_destroy (&info->fstream);
     }
 
+  mu_stream_destroy (&istream);
   _attachment_free (info, ret); /* FIXME: or 0? */
   
   /* Free fname if we allocated it. */
@@ -367,56 +355,52 @@ mu_message_encapsulate (mu_message_t msg, mu_message_t 
*newmsg,
   const char *header;
   int ret = 0;
   size_t nbytes;
-  mu_body_t body;
-
-  if (msg == NULL)
-    return EINVAL;
+  mu_message_t tmsg = NULL;
+  
   if (newmsg == NULL)
     return MU_ERR_OUT_PTR_NULL;
 
-  if ((ret = _attachment_setup (&info, msg, &ostream)) != 0)
-    return ret;
-
-  if (info->msg == NULL
-      && (ret = mu_message_create (&info->msg, NULL)) == 0)
+  if (msg == NULL)
     {
+      mu_header_t hdr;
+      
+      ret = mu_message_create (&tmsg, NULL);
+      if (ret)
+       return ret;
+      msg = tmsg;
       header =
        "Content-Type: message/rfc822\nContent-Transfer-Encoding: 7bit\n\n";
       if ((ret =
-          mu_header_create (&info->hdr, header, strlen (header),
-                            msg)) == 0)
-       ret = mu_message_set_header (info->msg, info->hdr, NULL);
+          mu_header_create (&hdr, header, strlen (header))) == 0)
+       ret = mu_message_set_header (msg, hdr, NULL);
+      if (ret)
+       {
+         mu_message_destroy (&msg, NULL);
+         return ret;
+       }
     }
-  if (ret == 0 && (ret = mu_message_get_stream (msg, &istream)) == 0)
+      
+  if ((ret = _attachment_setup (&info, msg, &ostream)) != 0)
+    {
+      mu_message_destroy (&tmsg, NULL);
+      return ret;
+    }
+
+  if (ret == 0 && (ret = mu_message_get_streamref (msg, &istream)) == 0)
     {
-      if ((ret = mu_message_get_body (info->msg, &body)) == 0 &&
-         (ret = mu_body_get_stream (body, &ostream)) == 0)
+      mu_stream_seek (istream, 0, MU_SEEK_SET, NULL);
+      while (((ret = mu_stream_read (istream, info->buf, BUF_SIZE, 
+                                    &nbytes)) == 0 && nbytes))
        {
-         if (info->nbytes)
-           memmove (info->buf, info->buf + (info->bufsize - info->nbytes),
-                    info->nbytes);
-         while ((ret == 0 && info->nbytes)
-                ||
-                ((ret =
-                  mu_stream_read (istream, info->buf, info->bufsize,
-                                  info->ioffset, &info->nbytes)) == 0
-                 && info->nbytes))
-           {
-             info->ioffset += info->nbytes;
-             while (info->nbytes)
-               {
-                 if ((ret =
-                      mu_stream_write (ostream, info->buf, info->nbytes,
-                                       info->ooffset, &nbytes)) != 0)
-                   break;
-                 info->nbytes -= nbytes;
-                 info->ooffset += nbytes;
-               }
-           }
+         if ((ret =
+              mu_stream_write (ostream, info->buf, nbytes, NULL)) != 0)
+           break;
        }
+      mu_stream_destroy (&istream);
     }
   if (ret == 0)
     *newmsg = info->msg;
+  mu_stream_destroy (&ostream);
   _attachment_free (info, ret && ret != EAGAIN);
   return ret;
 }
@@ -463,31 +447,21 @@ mu_message_unencapsulate (mu_message_t msg, mu_message_t 
*newmsg,
     ret = mu_message_create (&info->msg, NULL);
   if (ret == 0)
     {
-      mu_message_get_stream (info->msg, &ostream);
-      if (info->nbytes)
-       memmove (info->buf, info->buf + (info->bufsize - info->nbytes),
-                info->nbytes);
-      while ((ret == 0 && info->nbytes)
-            ||
-            ((ret =
-              mu_stream_read (istream, info->buf,
-                              info->bufsize, info->ioffset,
-                              &info->nbytes)) == 0 && info->nbytes))
+      mu_message_get_streamref (info->msg, &ostream);
+      mu_stream_seek (ostream, 0, MU_SEEK_SET, NULL);
+      while (((ret =
+              mu_stream_read (istream, info->buf, BUF_SIZE, 
+                              &nbytes)) == 0 && nbytes))
        {
-         info->ioffset += info->nbytes;
-         while (info->nbytes)
-           {
-             if ((ret =
-                  mu_stream_write (ostream, info->buf, info->nbytes,
-                                   info->ooffset, &nbytes)) != 0)
-               break;
-             info->nbytes -= nbytes;
-             info->ooffset += nbytes;
-           }
+         if ((ret =
+              mu_stream_write (ostream, info->buf, nbytes, NULL)) != 0)
+           break;
        }
+      mu_stream_destroy (&ostream);
     }
   if (ret == 0)
     *newmsg = info->msg;
+  mu_stream_destroy (&istream);
   _attachment_free (info, ret && ret != EAGAIN);
   return ret;
 }
diff --git a/mailbox/attribute.c b/mailbox/attribute.c
index d5c5d67..3e76855 100644
--- a/mailbox/attribute.c
+++ b/mailbox/attribute.c
@@ -33,7 +33,7 @@
 #include <mailutils/errno.h>
 #include <mailutils/mutil.h>
 #include <mailutils/cstr.h>
-#include <attribute0.h>
+#include <mailutils/sys/attribute.h>
 
 int
 mu_attribute_create (mu_attribute_t *pattr, void *owner)
diff --git a/mailbox/auth.c b/mailbox/auth.c
index 95f5faf..2d3e974 100644
--- a/mailbox/auth.c
+++ b/mailbox/auth.c
@@ -27,7 +27,7 @@
 #include <stdlib.h>
 
 #include <mailutils/errno.h>
-#include <auth0.h>
+#include <mailutils/sys/auth.h>
 
 static int
 _authenticate_null (mu_authority_t auth MU_ARG_UNUSED)
diff --git a/mailbox/base64.c b/mailbox/base64.c
index 65e8f5c..8ceba26 100644
--- a/mailbox/base64.c
+++ b/mailbox/base64.c
@@ -11,10 +11,8 @@
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.
 
-   You should have received a copy of the GNU Lesser General
-   Public License along with this library; if not, write to the
-   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301 USA */
+   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>
@@ -23,13 +21,25 @@
 #include <stdlib.h>
 #include <string.h>
 #include <mailutils/errno.h>
+#include <mailutils/filter.h>
+
+static char b64tab[] =
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static int b64val[128] = {
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
+  52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
+  -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+  15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
+  -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+  41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1
+};
 
 int
 mu_base64_encode (const unsigned char *input, size_t input_len,
                  unsigned char **output, size_t *output_len)
 {
-  static char b64tab[] =
-    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
   size_t olen = 4 * (input_len + 2) / 3 + 1;
   unsigned char *out = malloc (olen);
 
@@ -65,16 +75,6 @@ int
 mu_base64_decode (const unsigned char *input, size_t input_len,
                  unsigned char **output, size_t *output_len)
 {
-  static int b64val[128] = {
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
-    52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
-    -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
-    15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
-    -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
-    41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1
-  };
   int olen = input_len;
   unsigned char *out = malloc (olen);
 
@@ -88,7 +88,7 @@ mu_base64_decode (const unsigned char *input, size_t 
input_len,
          || input[2] > 127 || ((input[2] != '=') && (b64val[input[2]] == -1))
          || input[3] > 127 || ((input[3] != '=')
                                && (b64val[input[3]] == -1)))
-       return -1;
+       return EINVAL;
       *out++ = (b64val[input[0]] << 2) | (b64val[input[1]] >> 4);
       if (input[2] != '=')
        {
@@ -104,3 +104,167 @@ mu_base64_decode (const unsigned char *input, size_t 
input_len,
   return 0;
 }
 
+
+static enum mu_filter_result
+_base64_decoder (void *xd MU_ARG_UNUSED,
+                enum mu_filter_command cmd,
+                struct mu_filter_io *iobuf)
+{
+  int i = 0, tmp = 0, pad = 0;
+  size_t consumed = 0;
+  unsigned char data[4];
+  size_t nbytes = 0;
+  const char *iptr;
+  size_t isize;
+  char *optr;
+  size_t osize;
+
+  switch (cmd)
+    {
+    case mu_filter_init:
+    case mu_filter_done:
+      return mu_filter_ok;
+    default:
+      break;
+    }
+  
+  if (osize <= 3)
+    {
+      iobuf->osize = 3;
+      return mu_filter_moreoutput;
+    }
+
+  iptr = iobuf->input;
+  isize = iobuf->isize;
+  optr = iobuf->output;
+  osize = iobuf->osize;
+ 
+  while (consumed < isize && nbytes + 3 < osize)
+    {
+      while (i < 4 && consumed < isize)
+       {
+         tmp = b64val[*(const unsigned char*)iptr++];
+         consumed++;
+         if (tmp != -1)
+           data[i++] = tmp;
+         else if (*(iptr-1) == '=')
+           {
+             data[i++] = 0;
+             pad++;
+           }
+       }
+
+      /* I have a entire block of data 32 bits get the output data.  */
+      if (i == 4)
+       {
+         *optr++ = (data[0] << 2) | ((data[1] & 0x30) >> 4);
+         *optr++ = ((data[1] & 0xf) << 4) | ((data[2] & 0x3c) >> 2);
+         *optr++ = ((data[2] & 0x3) << 6) | data[3];
+         nbytes += 3 - pad;
+       }
+      else
+       {
+         /* I did not get all the data.  */
+         consumed -= i;
+         break;
+       }
+      i = 0;
+    }
+  iobuf->isize = consumed;
+  iobuf->osize = nbytes;
+  return mu_filter_ok;
+}
+
+static enum mu_filter_result
+_base64_encoder (void *xd MU_ARG_UNUSED,
+                enum mu_filter_command cmd,
+                struct mu_filter_io *iobuf)
+{
+  size_t consumed = 0;
+  int pad = 0;
+  const unsigned char *ptr = (const unsigned char*) iobuf->input;
+  size_t nbytes = 0;
+  size_t isize;
+  char *optr;
+  size_t osize;
+  
+  switch (cmd)
+    {
+    case mu_filter_init:
+    case mu_filter_done:
+      return mu_filter_ok;
+    default:
+      break;
+    }
+  
+  if (iobuf->isize <= 3)
+    {
+      if (cmd == mu_filter_lastbuf)
+       pad = 1;
+      else
+       {
+         iobuf->isize = 4;
+         return mu_filter_moreinput;
+       }
+    }
+  if (osize < 4)
+    {
+      iobuf->osize = 4;
+      return mu_filter_moreoutput;
+    }
+      
+  isize = iobuf->isize;
+  optr = iobuf->output;
+  osize = iobuf->osize;
+
+  while ((consumed + 3 <= isize && nbytes + 4 <= osize) || pad)
+    {
+      unsigned char c1 = 0, c2 = 0, x = '=', y = '=';
+       
+      *optr++ = b64tab[ptr[0] >> 2];
+      consumed++;
+      switch (isize - consumed)
+       {
+       default:
+         consumed++;
+         y = b64tab[ptr[2] & 0x3f];
+         c2 = ptr[2] >> 6;
+       case 1:
+         consumed++;
+         x = b64tab[((ptr[1] << 2) + c2) & 0x3f];
+         c1 = (ptr[1] >> 4);
+       case 0:
+         *optr++ = b64tab[((ptr[0] << 4) + c1) & 0x3f];
+         *optr++ = x;
+         *optr++ = y;
+       }
+      
+      ptr += 3;
+      nbytes += 4;
+      pad = 0;
+    }
+
+  iobuf->isize = consumed;
+  iobuf->osize = nbytes;
+  return mu_filter_ok;
+}
+
+static struct _mu_filter_record _base64_filter = {
+  "base64",
+  76,
+  NULL,
+  _base64_encoder,
+  _base64_decoder
+};
+
+mu_filter_record_t mu_base64_filter = &_base64_filter;
+
+static struct _mu_filter_record _B_filter = {
+  "B",
+  0,
+  NULL,
+  _base64_encoder,
+  _base64_decoder
+};
+
+mu_filter_record_t mu_rfc_2047_B_filter = &_B_filter;
diff --git a/mailbox/binflt.c b/mailbox/binflt.c
new file mode 100644
index 0000000..d3de518
--- /dev/null
+++ b/mailbox/binflt.c
@@ -0,0 +1,113 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 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 <mailutils/errno.h>
+#include <mailutils/filter.h>
+
+static enum mu_filter_result
+_copy_codec (void *xd MU_ARG_UNUSED,
+            enum mu_filter_command cmd,
+            struct mu_filter_io *iobuf)
+{
+  size_t osize;
+
+  switch (cmd)
+    {
+    case mu_filter_init:
+    case mu_filter_done:
+      return mu_filter_ok;
+    default:
+      break;
+    }
+  
+  osize = iobuf->osize;
+  if (osize > iobuf->isize)
+    osize = iobuf->isize;
+  memcpy (iobuf->output, iobuf->input, osize);
+  iobuf->isize = osize;
+  iobuf->osize = osize;
+  return mu_filter_ok;
+}
+
+static enum mu_filter_result
+_bit7_coder (void *xd MU_ARG_UNUSED,
+            enum mu_filter_command cmd,
+            struct mu_filter_io *iobuf)
+{
+  size_t i;
+  const unsigned char *iptr;
+  size_t isize;
+  char *optr;
+  size_t osize;
+
+  switch (cmd)
+    {
+    case mu_filter_init:
+    case mu_filter_done:
+      return mu_filter_ok;
+    default:
+      break;
+    }
+  
+  iptr = (const unsigned char *) iobuf->input;
+  isize = iobuf->isize;
+  optr = iobuf->output;
+  osize = iobuf->osize;
+
+  if (osize > isize)
+    osize = isize;
+  for (i = 0; i < osize; i++)
+    *optr++ = *iptr++ & 0x7f;
+  iobuf->isize = osize;
+  iobuf->osize = osize;
+  return mu_filter_ok;
+}
+
+static struct _mu_filter_record _binary_filter = {
+  "binary",
+  0,
+  NULL,
+  _copy_codec,
+  _copy_codec
+};
+
+mu_filter_record_t mu_binary_filter = &_binary_filter;
+
+
+static struct _mu_filter_record _bit8_filter = {
+  "bit8",
+  0,
+  NULL,
+  _copy_codec,
+  _copy_codec
+};
+
+mu_filter_record_t mu_bit8_filter = &_bit8_filter;
+
+static struct _mu_filter_record _bit7_filter = {
+  "bit7",
+  0,
+  NULL,
+  _bit7_coder,
+  _copy_codec
+};
+
+mu_filter_record_t mu_bit7_filter = &_bit7_filter;
diff --git a/mailbox/body.c b/mailbox/body.c
index cd430cd..513ad01 100644
--- a/mailbox/body.c
+++ b/mailbox/body.c
@@ -33,17 +33,19 @@
 #include <mailutils/stream.h>
 #include <mailutils/mutil.h>
 #include <mailutils/errno.h>
-#include <body0.h>
+#include <mailutils/sys/stream.h>
+#include <mailutils/sys/body.h>
 
 #define BODY_MODIFIED 0x10000
 
 static int _body_flush    (mu_stream_t);
-static int _body_get_transport2 (mu_stream_t, mu_transport_t *, mu_transport_t 
*);
-static int _body_read     (mu_stream_t, char *, size_t, mu_off_t, size_t *);
-static int _body_readline (mu_stream_t, char *, size_t, mu_off_t, size_t *);
+static int _body_read     (mu_stream_t, char *, size_t, size_t *);
 static int _body_truncate (mu_stream_t, mu_off_t);
 static int _body_size     (mu_stream_t, mu_off_t *);
-static int _body_write    (mu_stream_t, const char *, size_t, mu_off_t, size_t 
*);
+static int _body_write    (mu_stream_t, const char *, size_t, size_t *);
+static int _body_ioctl    (mu_stream_t, int, void *);
+static int _body_seek     (mu_stream_t, mu_off_t, mu_off_t *);
+static const char *_body_error_string (mu_stream_t, int);
 
 /* Our own defaults for the body.  */
 static int _body_get_size   (mu_body_t, size_t *);
@@ -86,12 +88,12 @@ mu_body_destroy (mu_body_t *pbody, void *owner)
            }
 
          if (body->stream)
-           mu_stream_destroy (&(body->stream), body);
+           mu_stream_destroy (&body->stream);
 
          if (body->fstream)
            {
              mu_stream_close (body->fstream);
-             mu_stream_destroy (&(body->fstream), NULL);
+             mu_stream_destroy (&body->fstream);
            }
 
          free (body);
@@ -142,8 +144,15 @@ mu_body_get_filename (mu_body_t body, char *filename, 
size_t len, size_t *pn)
   return 0;
 }
 
-int
-mu_body_get_stream (mu_body_t body, mu_stream_t *pstream)
+
+struct _mu_body_stream
+{
+  struct _mu_stream stream;
+  mu_body_t body;
+};
+
+static int
+_body_get_stream (mu_body_t body, mu_stream_t *pstream, int ref)
 {
   if (body == NULL)
     return EINVAL;
@@ -152,31 +161,65 @@ mu_body_get_stream (mu_body_t body, mu_stream_t *pstream)
 
   if (body->stream == NULL)
     {
-      int status = mu_stream_create (&body->stream, MU_STREAM_RDWR, body);
-      if (status != 0)
-       return status;
-      /* Create the temporary file.  */
-      body->filename = mu_tempname (NULL);
-      status = mu_file_stream_create (&body->fstream, 
-                                   body->filename, MU_STREAM_RDWR);
-      if (status != 0)
-       return status;
-      status = mu_stream_open (body->fstream);
-      if (status != 0)
-       return status;
-      mu_stream_set_get_transport2 (body->stream, _body_get_transport2, body);
-      mu_stream_set_read (body->stream, _body_read, body);
-      mu_stream_set_readline (body->stream, _body_readline, body);
-      mu_stream_set_write (body->stream, _body_write, body);
-      mu_stream_set_truncate (body->stream, _body_truncate, body);
-      mu_stream_set_size (body->stream, _body_size, body);
-      mu_stream_set_flush (body->stream, _body_flush, body);
-      /* Override the defaults.  */
-      body->_lines = _body_get_lines;
-      body->_size = _body_get_size;
+      if (body->_get_stream)
+       {
+         int status = body->_get_stream (body, &body->stream);
+         if (status)
+           return status;
+       }
+      else
+       {
+         int status;
+         struct _mu_body_stream *str =
+           (struct _mu_body_stream *)
+           _mu_stream_create (sizeof (*str),
+                              MU_STREAM_RDWR|MU_STREAM_SEEK);
+         if (!str)
+           return ENOMEM;
+         
+         /* Create the temporary file.  */
+         body->filename = mu_tempname (NULL);
+         status = mu_file_stream_create (&body->fstream, 
+                                         body->filename, MU_STREAM_RDWR);
+         if (status != 0)
+           return status;
+         status = mu_stream_open (body->fstream);
+         if (status != 0)
+           return status;
+         str->stream.ctl = _body_ioctl;
+         str->stream.read = _body_read;
+         str->stream.write = _body_write;
+         str->stream.truncate = _body_truncate;
+         str->stream.size = _body_size;
+         str->stream.seek = _body_seek;
+         str->stream.flush = _body_flush;
+         str->body = body;
+         body->stream = (mu_stream_t) str;
+         /* Override the defaults.  */
+         body->_lines = _body_get_lines;
+         body->_size = _body_get_size;
+       }
     }
-  *pstream = body->stream;
-  return 0;
+  
+  if (!ref)
+    {
+      *pstream = body->stream;
+      return 0;
+    }
+  return mu_streamref_create (pstream, body->stream);
+}
+
+int
+mu_body_get_stream (mu_body_t body, mu_stream_t *pstream)
+{
+  /* FIXME: Deprecation warning */
+  return _body_get_stream (body, pstream, 0);
+}
+
+int
+mu_body_get_streamref (mu_body_t body, mu_stream_t *pstream)
+{
+  return _body_get_stream (body, pstream, 1);
 }
 
 int
@@ -186,15 +229,29 @@ mu_body_set_stream (mu_body_t body, mu_stream_t stream, 
void *owner)
    return EINVAL;
   if (body->owner != owner)
     return EACCES;
-  /* make sure we destroy the old one if it is own by the body */
-  mu_stream_destroy (&(body->stream), body);
+  /* make sure we destroy the old one if it is owned by the body */
+  mu_stream_destroy (&body->stream);
   body->stream = stream;
   body->flags |= BODY_MODIFIED;
   return 0;
 }
 
 int
-mu_body_set_lines (mu_body_t body, int (*_lines) (mu_body_t, size_t *), void 
*owner)
+mu_body_set_get_stream (mu_body_t body,
+                       int (*_getstr) (mu_body_t, mu_stream_t *),
+                       void *owner)
+{
+  if (body == NULL)
+    return EINVAL;
+  if (body->owner != owner)
+    return EACCES;
+  body->_get_stream = _getstr;
+  return 0;
+}
+
+int
+mu_body_set_lines (mu_body_t body, int (*_lines) (mu_body_t, size_t *),
+                  void *owner)
 {
   if (body == NULL)
     return EINVAL;
@@ -248,51 +305,65 @@ mu_body_set_size (mu_body_t body, int (*_size)(mu_body_t, 
size_t*) , void *owner
 /* Stub function for the body stream.  */
 
 static int
-_body_get_transport2 (mu_stream_t stream, mu_transport_t *pin, mu_transport_t 
*pout)
+_body_seek (mu_stream_t stream, mu_off_t off, mu_off_t *presult)
 {
-  mu_body_t body = mu_stream_get_owner (stream);
-  return mu_stream_get_transport2 (body->fstream, pin, pout);
+  struct _mu_body_stream *str = (struct _mu_body_stream*) stream;
+  mu_body_t body = str->body;
+  return mu_stream_seek (body->fstream, off, MU_SEEK_SET, presult);
+}
+
+static const char *
+_body_error_string (mu_stream_t stream, int rc)
+{
+  /* FIXME: How to know if rc was returned by a body->stream? */
+  return NULL;
 }
 
 static int
-_body_read (mu_stream_t stream,  char *buffer, size_t n, mu_off_t off, size_t 
*pn)
+_body_ioctl (mu_stream_t stream, int code, void *ptr)
 {
-  mu_body_t body = mu_stream_get_owner (stream);
-  return mu_stream_read (body->fstream, buffer, n, off, pn);
+  struct _mu_body_stream *str = (struct _mu_body_stream*) stream;
+  mu_body_t body = str->body;
+  return mu_stream_ioctl (body->fstream, code, ptr);
 }
 
 static int
-_body_readline (mu_stream_t stream, char *buffer, size_t n, mu_off_t off, 
size_t *pn)
+_body_read (mu_stream_t stream, char *buf, size_t size, size_t *pret)
 {
-  mu_body_t body = mu_stream_get_owner (stream);
-  return mu_stream_readline (body->fstream, buffer, n, off, pn);
+  struct _mu_body_stream *str = (struct _mu_body_stream*) stream;
+  mu_body_t body = str->body;
+  return mu_stream_read (body->fstream, buf, size, pret);
 }
 
 static int
-_body_write (mu_stream_t stream, const char *buf, size_t n, mu_off_t off, 
size_t *pn)
+_body_write (mu_stream_t stream, const char *buf, size_t size, size_t *pret)
 {
-  mu_body_t body = mu_stream_get_owner (stream);
-  return mu_stream_write (body->fstream, buf, n, off, pn);
+  struct _mu_body_stream *str = (struct _mu_body_stream*) stream;
+  mu_body_t body = str->body;
+  return mu_stream_write (body->fstream, buf, size, pret);
 }
 
 static int
 _body_truncate (mu_stream_t stream, mu_off_t n)
 {
-  mu_body_t body = mu_stream_get_owner (stream);
+  struct _mu_body_stream *str = (struct _mu_body_stream*) stream;
+  mu_body_t body = str->body;
   return mu_stream_truncate (body->fstream, n);
 }
 
 static int
 _body_size (mu_stream_t stream, mu_off_t *size)
 {
-  mu_body_t body = mu_stream_get_owner (stream);
+  struct _mu_body_stream *str = (struct _mu_body_stream*) stream;
+  mu_body_t body = str->body;
   return mu_stream_size (body->fstream, size);
 }
 
 static int
 _body_flush (mu_stream_t stream)
 {
-  mu_body_t body = mu_stream_get_owner (stream);
+  struct _mu_body_stream *str = (struct _mu_body_stream*) stream;
+  mu_body_t body = str->body;
   return mu_stream_flush (body->fstream);
 }
 
@@ -324,17 +395,20 @@ _body_get_lines0 (mu_stream_t stream, size_t *plines)
 {
   int status =  mu_stream_flush (stream);
   size_t lines = 0;
+  
   if (status == 0)
     {
       char buf[128];
       size_t n = 0;
-      mu_off_t off = 0;
+
+      status = mu_stream_seek (stream, 0, MU_SEEK_SET, NULL);
+      if (status)
+       return status;
       while ((status = mu_stream_readline (stream, buf, sizeof buf,
-                                          off, &n)) == 0 && n > 0)
+                                          &n)) == 0 && n > 0)
        {
          if (buf[n - 1] == '\n')
            lines++;
-         off += n;
        }
     }
   if (plines)
diff --git a/mailbox/cfg_driver.c b/mailbox/cfg_driver.c
index 6d98771..f4d56f7 100644
--- a/mailbox/cfg_driver.c
+++ b/mailbox/cfg_driver.c
@@ -589,11 +589,10 @@ mu_cfg_tree_reduce (mu_cfg_tree_t *parse_tree, const char 
*progname,
   if (flags & MU_PARSE_CONFIG_DUMP)
     {
       mu_stream_t stream;
-      mu_stdio_stream_create (&stream, stderr,
-                             MU_STREAM_NO_CHECK|MU_STREAM_NO_CLOSE);
+      mu_stdio_stream_create (&stream, MU_STDERR_FD, 0);
       mu_stream_open (stream);
       mu_cfg_format_parse_tree (stream, parse_tree, MU_CFG_FMT_LOCUS);
-      mu_stream_destroy (&stream, NULL);
+      mu_stream_destroy (&stream);
     }
 
   if (root_container)
diff --git a/mailbox/cfg_format.c b/mailbox/cfg_format.c
index 4dcf6d5..be37bae 100644
--- a/mailbox/cfg_format.c
+++ b/mailbox/cfg_format.c
@@ -40,7 +40,7 @@ static void
 format_level (mu_stream_t stream, int level)
 {
   while (level--)
-    mu_stream_sequential_write (stream, "  ", 2);
+    mu_stream_write (stream, "  ", 2, NULL);
 }
 
 static void
@@ -70,7 +70,7 @@ format_string_value (struct tree_print *tp, const char *str)
     }
   tp->buf[size-1] = 0;
   mu_argcv_quote_copy (p, str);
-  mu_stream_sequential_write (tp->stream, tp->buf, size - 1);
+  mu_stream_write (tp->stream, tp->buf, size - 1, NULL);
 }
 
 static void format_value (struct tree_print *tp, mu_config_value_t *val);
@@ -80,7 +80,7 @@ format_list_value (struct tree_print *tp, mu_config_value_t 
*val)
 {
   int i;
   mu_iterator_t itr;
-  mu_stream_sequential_write (tp->stream, "(", 1);
+  mu_stream_write (tp->stream, "(", 1, NULL);
   mu_list_get_iterator (val->v.list, &itr);
   
   for (mu_iterator_first (itr), i = 0;
@@ -89,11 +89,11 @@ format_list_value (struct tree_print *tp, mu_config_value_t 
*val)
       mu_config_value_t *p;
       mu_iterator_current (itr, (void**)&p);
       if (i)
-       mu_stream_sequential_write (tp->stream, ", ", 2);
+       mu_stream_write (tp->stream, ", ", 2, NULL);
       format_value (tp, p);
     }
   mu_iterator_destroy (&itr);
-  mu_stream_sequential_write (tp->stream, ")", 1);
+  mu_stream_write (tp->stream, ")", 1, NULL);
 }
 
 static void
@@ -104,7 +104,7 @@ format_array_value (struct tree_print *tp, 
mu_config_value_t *val)
   for (i = 0; i < val->v.arg.c; i++)
     {
       if (i)
-       mu_stream_sequential_write (tp->stream, " ", 1);
+       mu_stream_write (tp->stream, " ", 1, NULL);
       format_value (tp, &val->v.arg.v[i]);
     }
 }
@@ -133,43 +133,41 @@ format_node (const mu_cfg_node_t *node, void *data)
   struct tree_print *tp = data;
 
   if ((tp->flags & MU_CFG_FMT_LOCUS) && node->locus.file)
-    mu_stream_sequential_printf (tp->stream, "# %lu \"%s\"\n",
-                                (unsigned long) node->locus.line, 
-                                 node->locus.file);
+    mu_stream_printf (tp->stream, "# %lu \"%s\"\n",
+                     (unsigned long) node->locus.line, 
+                     node->locus.file);
   format_level (tp->stream, tp->level);
   switch (node->type)
     {
     case mu_cfg_node_undefined:
-      mu_stream_sequential_printf (tp->stream, "%s",
-                                  _("ERROR: undefined statement"));
+      mu_stream_printf (tp->stream, "%s",
+                       _("ERROR: undefined statement"));
       break;
 
     case mu_cfg_node_statement:
       {
-       mu_stream_sequential_write (tp->stream, node->tag,
-                                   strlen (node->tag));
+       mu_stream_write (tp->stream, node->tag, strlen (node->tag), NULL);
        if (node->label)
          {
-           mu_stream_sequential_write (tp->stream, " ", 1);
+           mu_stream_write (tp->stream, " ", 1, NULL);
            format_value (tp, node->label);
          }
-       mu_stream_sequential_write (tp->stream, " {", 2);
+       mu_stream_write (tp->stream, " {", 2, NULL);
        tp->level++;
       }
       break;
 
     case mu_cfg_node_param:
-      mu_stream_sequential_write (tp->stream, node->tag,
-                                 strlen (node->tag));
+      mu_stream_write (tp->stream, node->tag, strlen (node->tag), NULL);
       if (node->label)
        {
-         mu_stream_sequential_write (tp->stream, " ", 1);
+         mu_stream_write (tp->stream, " ", 1, NULL);
          format_value (tp, node->label);
-         mu_stream_sequential_write (tp->stream, ";", 1);
+         mu_stream_write (tp->stream, ";", 1, NULL);
        }
       break;
     }
-  mu_stream_sequential_write (tp->stream, "\n", 1);
+  mu_stream_write (tp->stream, "\n", 1, NULL);
   return MU_CFG_ITER_OK;
 }
 
@@ -179,7 +177,7 @@ format_node_end (const mu_cfg_node_t *node, void *data)
   struct tree_print *tp = data;
   tp->level--;
   format_level (tp->stream, tp->level);
-  mu_stream_sequential_write (tp->stream, "};\n", 3);
+  mu_stream_write (tp->stream, "};\n", 3, NULL);
   return MU_CFG_ITER_OK;
 }
 
@@ -290,9 +288,9 @@ mu_cfg_format_docstring (mu_stream_t stream, const char 
*docstring, int level)
        seglen = p - docstring;
 
       format_level (stream, level);
-      mu_stream_sequential_write (stream, "# ", 2);
-      mu_stream_sequential_write (stream, docstring, seglen);
-      mu_stream_sequential_write (stream, "\n", 1);
+      mu_stream_write (stream, "# ", 2, NULL);
+      mu_stream_write (stream, docstring, seglen, NULL);
+      mu_stream_write (stream, "\n", 1, NULL);
       len -= seglen;
       docstring += seglen;
       if (*docstring == '\n')
@@ -316,23 +314,21 @@ format_param (mu_stream_t stream, struct mu_cfg_param 
*param, int level)
     mu_cfg_format_docstring (stream, gettext (param->docstring), level);
   format_level (stream, level);
   if (param->argname && strchr (param->argname, ':'))
-    mu_stream_sequential_printf (stream, "%s <%s>;\n",
-                                param->ident,
-                                gettext (param->argname));
+    mu_stream_printf (stream, "%s <%s>;\n",
+                     param->ident,
+                     gettext (param->argname));
   else if (MU_CFG_IS_LIST (param->type))
-    mu_stream_sequential_printf
-       (stream, "%s <%s: list of %s>;\n",
-       param->ident,
-       gettext (param->argname ?
-                param->argname : N_("arg")),
+    mu_stream_printf (stream, "%s <%s: list of %s>;\n",
+                     param->ident,
+                     gettext (param->argname ?
+                              param->argname : N_("arg")),
        gettext (mu_cfg_data_type_string (MU_CFG_TYPE (param->type))));
   else
-    mu_stream_sequential_printf
-      (stream, "%s <%s: %s>;\n",
-       param->ident,
-       gettext (param->argname ?
-               param->argname : N_("arg")),
-       gettext (mu_cfg_data_type_string (param->type)));
+    mu_stream_printf (stream, "%s <%s: %s>;\n",
+                     param->ident,
+                     gettext (param->argname ?
+                              param->argname : N_("arg")),
+                     gettext (mu_cfg_data_type_string (param->type)));
 }
 
 static void format_container (mu_stream_t stream, struct mu_cfg_cont *cont,
@@ -356,19 +352,18 @@ format_section (mu_stream_t stream, struct mu_cfg_section 
*sect, int level)
   format_level (stream, level);
   if (sect->ident)
     {
-      mu_stream_sequential_write (stream, sect->ident, strlen (sect->ident));
+      mu_stream_write (stream, sect->ident, strlen (sect->ident), NULL);
       if (sect->label)
        {
-         mu_stream_sequential_write (stream, " ", 1);
-         mu_stream_sequential_write (stream, sect->label,
-                                     strlen (sect->label));
+         mu_stream_write (stream, " ", 1, NULL);
+         mu_stream_write (stream, sect->label, strlen (sect->label), NULL);
        }
-      mu_stream_sequential_write (stream, " {\n", 3);
+      mu_stream_write (stream, " {\n", 3, NULL);
       c.stream = stream;
       c.level = level + 1; 
       mu_list_do (sect->children, _f_helper, &c);
       format_level (stream, level);
-      mu_stream_sequential_write (stream, "};\n\n", 4);
+      mu_stream_write (stream, "};\n\n", 4, NULL);
     }
   else
     {
diff --git a/mailbox/crlfflt.c b/mailbox/crlfflt.c
new file mode 100644
index 0000000..9dc147c
--- /dev/null
+++ b/mailbox/crlfflt.c
@@ -0,0 +1,182 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 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 <mailutils/errno.h>
+#include <mailutils/filter.h>
+
+enum crlf_state
+{
+  state_init,
+  state_cr
+};
+  
+/* Move min(isize,osize) bytes from iptr to optr, replacing each \n
+   with \r\n.  Any input \r\n sequences remain untouched. */
+static enum mu_filter_result
+_crlf_encoder (void *xd,
+              enum mu_filter_command cmd,
+              struct mu_filter_io *iobuf)
+{
+  size_t i, j;
+  const unsigned char *iptr;
+  size_t isize;
+  char *optr;
+  size_t osize;
+  enum crlf_state *state = xd;
+  
+  switch (cmd)
+    {
+    case mu_filter_init:
+      *state = state_init;
+    case mu_filter_done:
+      return mu_filter_ok;
+    default:
+      break;
+    }
+  
+  iptr = (const unsigned char *) iobuf->input;
+  isize = iobuf->isize;
+  optr = iobuf->output;
+  osize = iobuf->osize;
+
+  for (i = j = 0; i < isize && j < osize; i++)
+    {
+      unsigned char c = *iptr++;
+      if (c == '\n')
+       {
+         if (*state == state_cr)
+           {
+             *state = state_init;
+             optr[j++] = c;
+           }
+         else if (j + 1 == osize)
+           {
+             if (i == 0)
+               {
+                 iobuf->osize = 2;
+                 return mu_filter_moreoutput;
+               }
+             break;
+           }
+         else
+           {
+             optr[j++] = '\r';
+             optr[j++] = '\n';
+           }
+       }
+      else if (c == '\r')
+       {
+         *state = state_cr;
+         optr[j++] = c;
+       }
+      else
+       optr[j++] = c;
+    }
+  iobuf->isize = i;
+  iobuf->osize = j;
+  return mu_filter_ok;
+}
+
+/* Move min(isize,osize) bytes from iptr to optr, replacing each \r\n
+   with \n. */
+static enum mu_filter_result
+_crlf_decoder (void *xd MU_ARG_UNUSED,
+              enum mu_filter_command cmd,
+              struct mu_filter_io *iobuf)
+{
+  size_t i, j;
+  const unsigned char *iptr;
+  size_t isize;
+  char *optr;
+  size_t osize;
+
+  switch (cmd)
+    {
+    case mu_filter_init:
+    case mu_filter_done:
+      return mu_filter_ok;
+    default:
+      break;
+    }
+  
+  iptr = (const unsigned char *) iobuf->input;
+  isize = iobuf->isize;
+  optr = iobuf->output;
+  osize = iobuf->osize;
+
+  for (i = j = 0; i < isize && j < osize; i++)
+    {
+      unsigned char c = *iptr++;
+      if (c == '\r')
+       {
+         if (i + 1 == isize)
+           break;
+         if (*iptr == '\n')
+           continue;
+       }
+      optr[j++] = c;
+    }
+  iobuf->isize = i;
+  iobuf->osize = j;
+  return mu_filter_ok;
+}
+
+static int
+alloc_state (void **pret, int mode, void *data MU_ARG_UNUSED)
+{
+  switch (mode)
+    {
+    case MU_FILTER_ENCODE:
+      *pret = malloc (sizeof (int));
+      if (!*pret)
+       return ENOMEM;
+      break;
+
+    case MU_FILTER_DECODE:
+      *pret = NULL;
+    }
+  return 0;
+}
+  
+
+static struct _mu_filter_record _crlf_filter = {
+  "CRLF",
+  0,
+  alloc_state,
+  _crlf_encoder,
+  _crlf_decoder
+};
+
+mu_filter_record_t mu_crlf_filter = &_crlf_filter;
+
+
+/* For compatibility with previous versions */
+static struct _mu_filter_record _rfc822_filter = {
+  "RFC822",
+  0,
+  alloc_state,
+  _crlf_encoder,
+  _crlf_decoder
+};
+
+mu_filter_record_t mu_rfc822_filter = &_rfc822_filter;
+
+
diff --git a/mailbox/dbgstream.c b/mailbox/dbgstream.c
new file mode 100644
index 0000000..b03f299
--- /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_AUTOCLOSE)
+    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_AUTOCLOSE));
+  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/debug.c b/mailbox/debug.c
index 37f9e47..7570f23 100644
--- a/mailbox/debug.c
+++ b/mailbox/debug.c
@@ -28,7 +28,7 @@
 
 #include <mailutils/errno.h>
 #include <mailutils/nls.h>
-#include <debug0.h>
+#include <mailutils/sys/debug.h>
 
 mu_debug_printer_fp mu_debug_default_printer = mu_debug_stderr_printer;
 
@@ -55,14 +55,16 @@ mu_debug_destroy (mu_debug_t *pdebug, void *owner)
       mu_debug_t debug = *pdebug;
       if (debug->owner == owner)
        {
-         mu_off_t len = 0;
-         int rc = mu_stream_size (debug->stream, &len);
-         if (rc == 0 && len)
-           /* Flush leftover data */
-           mu_debug_printf (debug, 0, "\n");
-
-         mu_stream_destroy (&debug->stream,
-                            mu_stream_get_owner (debug->stream));
+         if (debug->stream)
+           {
+             mu_off_t len = 0;
+             int rc = mu_stream_size (debug->stream, &len);
+             if (rc == 0 && len)
+               /* Flush leftover data */
+               mu_debug_printf (debug, 0, "\n");
+
+             mu_stream_destroy (&debug->stream);
+           }
          if (debug->destroy)
            debug->destroy (debug->data);
          free (*pdebug);
@@ -126,20 +128,19 @@ debug_format_prefix (mu_debug_t debug)
   int need_space = 0;
   if (debug->locus.file)
     {
-      mu_stream_sequential_printf (debug->stream, "%s:%d:",
-                                  debug->locus.file, debug->locus.line);
+      mu_stream_printf (debug->stream, "%s:%d:",
+                       debug->locus.file, debug->locus.line);
       need_space = 1;
     }
   
   if (debug->function)
     {
-      mu_stream_sequential_printf (debug->stream, "%s:",
-                                  debug->function);
+      mu_stream_printf (debug->stream, "%s:", debug->function);
       need_space = 1;
     }
   
   if (need_space)
-    mu_stream_sequential_write (debug->stream, " ", 1);
+    mu_stream_write (debug->stream, " ", 1, NULL);
 }
 
 int
@@ -155,13 +156,13 @@ mu_debug_vprintf (mu_debug_t debug, mu_log_level_t level,
   if (printer)
     {
       mu_off_t len;
-      mu_transport_t tbuf;
+      mu_transport_t tbuf[2];
       char *ptr, *start, *p;
       size_t nseg;
       
       if (debug->stream == NULL)
        {
-         int rc = mu_memory_stream_create (&debug->stream, NULL, 0);
+         int rc = mu_memory_stream_create (&debug->stream, 0);
          if (rc)
            {
              fprintf (stderr,
@@ -176,10 +177,10 @@ mu_debug_vprintf (mu_debug_t debug, mu_log_level_t level,
       if (mu_stream_size (debug->stream, &len) == 0 && len == 0)
        debug_format_prefix (debug);
       
-      mu_stream_sequential_vprintf (debug->stream, format, ap);
-      
-      mu_stream_get_transport (debug->stream, &tbuf);
-      start = (char*) tbuf;
+      mu_stream_vprintf (debug->stream, format, ap);
+
+      mu_stream_ioctl (debug->stream, MU_IOCTL_GET_TRANSPORT, tbuf);
+      start = (char*) tbuf[0];
       mu_stream_size (debug->stream, &len);
       ptr = start;
       nseg = 0;
@@ -207,7 +208,7 @@ mu_debug_vprintf (mu_debug_t debug, mu_log_level_t level,
            len = 0;
 
          mu_stream_truncate (debug->stream, len);
-         mu_stream_seek (debug->stream, len, SEEK_SET);
+         mu_stream_seek (debug->stream, len, SEEK_SET, NULL);
        }
     }
   else
diff --git a/mailbox/envelope.c b/mailbox/envelope.c
index 21facf7..1e5aa4a 100644
--- a/mailbox/envelope.c
+++ b/mailbox/envelope.c
@@ -25,7 +25,7 @@
 #include <string.h>
 #include <mailutils/errno.h>
 #include <mailutils/mutil.h>
-#include <envelope0.h>
+#include <mailutils/sys/envelope.h>
 
 int
 mu_envelope_create (mu_envelope_t *penvelope, void *owner)
diff --git a/mailbox/errors b/mailbox/errors
index 49910ee..06eb98b 100644
--- a/mailbox/errors
+++ b/mailbox/errors
@@ -83,3 +83,5 @@ MU_ERR_NO_INTERFACE         _("No such interface")
 MU_ERR_BADOP                _("Inappropriate operation for this mode")
 MU_ERR_BAD_FILENAME         _("Badly formed file or directory name")
 MU_ERR_READ                 _("Read error")
+
+MU_ERR_NO_TRANSPORT         _("Transport stream not set")
diff --git a/mailbox/file_stream.c b/mailbox/file_stream.c
index edfa1a7..7ffde02 100644
--- a/mailbox/file_stream.c
+++ b/mailbox/file_stream.c
@@ -1,1137 +1,300 @@
 /* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2008,
-   2010 Free Software Foundation, Inc.
+   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 of the License, or (at your option) any later version.
+   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.
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU Lesser General
-   Public License along with this library; if not, write to the
-   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301 USA */
+   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 <assert.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
 #include <string.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-#include <fcntl.h>
+#include <stdlib.h>
 #include <unistd.h>
-#include <syslog.h>
-#include <signal.h>
+#include <fcntl.h>
+#include <sys/stat.h>
 
-#include <mailutils/stream.h>
+#include <mailutils/types.h>
+#include <mailutils/alloc.h>
 #include <mailutils/error.h>
 #include <mailutils/errno.h>
-#include <mailutils/argcv.h>
 #include <mailutils/nls.h>
-#include <mailutils/list.h>
+#include <mailutils/stream.h>
+#include <mailutils/sys/stream.h>
+#include <mailutils/sys/file_stream.h>
 #include <mailutils/mutil.h>
 
-struct _file_stream
-{
-  FILE *file;
-  mu_off_t offset;
-  int tempfile;
-  char *filename;
-  /* The following three members are used for stdio streams only. */
-  int size_computed;
-  mu_stream_t cache;
-  mu_off_t size;
-};
-
-static void
-_file_destroy (mu_stream_t stream)
-{
-  struct _file_stream *fs = mu_stream_get_owner (stream);
-
-  if (fs->filename)
-    free (fs->filename);
-
-  if (fs->cache)
-    mu_stream_destroy (&fs->cache, mu_stream_get_owner (fs->cache));
-  free (fs);
-}
-
-static int
-_file_read (mu_stream_t stream, char *optr, size_t osize,
-           mu_off_t offset, size_t *nbytes)
-{
-  struct _file_stream *fs = mu_stream_get_owner (stream);
-  size_t n;
-  int err = 0;
-
-  if (!fs->file)
-    {
-      if (nbytes)
-       *nbytes = 0;
-      return 0;
-    }
-
-  if (fs->offset != offset)
-    {
-      if (fseeko (fs->file, offset, SEEK_SET) != 0)
-       return errno;
-      fs->offset = offset;
-    }
-
-  if (feof (fs->file))
-    {
-      if (nbytes)
-       *nbytes = 0;
-      return 0;
-    }
-  
-  n = fread (optr, sizeof(char), osize, fs->file);
-  if (n == 0)
-    {
-      if (ferror(fs->file))
-       err = errno;
-    }
-  else
-    fs->offset += n;
-
-  if (nbytes)
-    *nbytes = n;
-  return err;
-}
-
-static int
-_file_readline (mu_stream_t stream, char *optr, size_t osize,
-               mu_off_t offset, size_t *nbytes)
-{
-  struct _file_stream *fs = mu_stream_get_owner (stream);
-  size_t n = 0;
-  int err = 0;
-
-  if (!fs->file)
-    {
-      optr[0] = 0;
-      if (nbytes)
-       *nbytes = 0;
-      return 0;
-    }
-
-  if (fs->offset != offset)
-    {
-      if (fseeko (fs->file, offset, SEEK_SET) != 0)
-       return errno;
-      fs->offset = offset;
-    }
-
-  if (feof (fs->file))
-    {
-      if (nbytes)
-       *nbytes = 0;
-      return 0;
-    }
-
-  if (fgets (optr, osize, fs->file) != NULL)
-    {
-      char *tmp = optr;
-      while (*tmp) tmp++; /* strlen(optr) */
-      n = tmp - optr;
-      /* !!!!! WTF ??? */
-      if (n == 0)
-       n++;
-      else
-       fs->offset += n;
-    }
-  else
-    {
-      if (ferror (fs->file))
-       err = errno;
-    }
-
-  optr[n] = 0;
-  if (nbytes)
-    *nbytes = n;
-  return err;
-}
+#define MU_FSTR_ERROR_NOREG (MU_ERR_LAST+1)
 
 static int
-_file_write (mu_stream_t stream, const char *iptr, size_t isize,
-            mu_off_t offset, size_t *nbytes)
+fd_read (struct _mu_stream *str, char *buf, size_t size, size_t *pret)
 {
-  struct _file_stream *fs = mu_stream_get_owner (stream);
-  size_t n;
-  int err = 0;
-
-  if (!fs->file)
-    {
-      if (nbytes)
-       *nbytes = 0;
-      return 0;
-    }
-
-  if (fs->offset != offset)
-    {
-      if (fseeko (fs->file, offset, SEEK_SET) != 0)
-       return errno;
-      fs->offset = offset;
-    }
-
-  n = fwrite (iptr, sizeof(char), isize, fs->file);
-  if (n != isize)
-    {
-      if (feof (fs->file) == 0)
-       err = EIO;
-      else if (n == 0)
-       err = ENOSPC; 
-      clearerr(fs->file);
-      n = 0;
-    }
-  else
-    fs->offset += n;
-
-  if (nbytes)
-    *nbytes = n;
-  return err;
-}
-
-static int
-_stdin_file_read (mu_stream_t stream, char *optr, size_t osize,
-                 mu_off_t offset, size_t *pnbytes)
-{
-  int status = 0;
-  size_t nbytes;
-  struct _file_stream *fs = mu_stream_get_owner (stream);
-  mu_off_t fs_offset = fs->offset;
-
-  if (offset < fs_offset)
-    return mu_stream_read (fs->cache, optr, osize, offset, pnbytes);
-  else if (offset > fs_offset)
-    {
-      int status = 0;
-      size_t n, left = offset - fs_offset + 1;
-      char *buf = malloc (left);
-      if (!buf)
-       return ENOMEM;
-      while (left > 0
-            && (status = mu_stream_read (stream, buf, left, fs_offset, &n)) == 0
-            && n > 0)
-       {
-         size_t k;
-         status = mu_stream_write (fs->cache, buf, n, fs_offset, &k);
-         if (status)
-           break;
-         if (k != n)
-           {
-             status = EIO;
-             break;
-           }
-         
-         fs_offset += n;
-         left -= n;
-       }
-      free (buf);
-      if (status)
-       return status;
-    }
-  
-  if (feof (fs->file))
-    nbytes = 0;
-  else
-    {
-      status = _file_read (stream, optr, osize, fs_offset, &nbytes);
-      if (status == 0 && nbytes)
-       {
-         size_t k;
-
-         status = mu_stream_write (fs->cache, optr, nbytes, fs_offset, &k);
-         if (status)
-           return status;
-         if (k != nbytes)
-           return EIO;
-       }
-    }
-  if (pnbytes)
-    *pnbytes = nbytes;
-  return status;
-}
-
-static int
-_stdin_file_readline (mu_stream_t stream, char *optr, size_t osize,
-                     mu_off_t offset, size_t *pnbytes)
-{
-  int status;
-  size_t nbytes;
-  struct _file_stream *fs = mu_stream_get_owner (stream);
-  mu_off_t fs_offset = fs->offset;
-  
-  if (offset < fs->offset)
-    return mu_stream_readline (fs->cache, optr, osize, offset, pnbytes);
-  else if (offset > fs->offset)
-    return ESPIPE;
-
-  fs_offset = fs->offset;
-  status = _file_readline (stream, optr, osize, fs_offset, &nbytes);
-  if (status == 0)
-    {
-      size_t k;
-
-      status = mu_stream_write (fs->cache, optr, nbytes, fs_offset, &k);
-      if (status)
-       return status;
-      if (k != nbytes)
-       return EIO;
-    }
-  if (pnbytes)
-    *pnbytes = nbytes;
-  return status;
-}
-
-/* Used only if stream->cache is not NULL */ 
-static int
-_stdin_file_size (mu_stream_t stream, mu_off_t *psize)
-{
-  struct _file_stream *fs = mu_stream_get_owner (stream);
-
-  if (!fs->size_computed)
-    {
-      char buf[512];
-      mu_off_t fs_offset = fs->offset;
-      size_t n;
-      int status;
-      
-      /* Fill in the cache */ 
-      while ((status = mu_stream_read (stream, buf, sizeof (buf),
-                                      fs_offset, &n)) == 0
-            && n > 0)
-       fs_offset += n;
-      fs->size = fs_offset;
-      fs->size_computed = 1;
-    }
-  *psize = fs->size;
-  return 0;
-}
-
-static int
-_stdout_file_write (mu_stream_t stream, const char *iptr, size_t isize,
-                   mu_off_t offset, size_t *nbytes)
-{
-  struct _file_stream *fs = mu_stream_get_owner (stream);
-  return _file_write (stream, iptr, isize, fs->offset, nbytes);
-}
-
-static int
-_file_truncate (mu_stream_t stream, mu_off_t len)
-{
-  struct _file_stream *fs = mu_stream_get_owner (stream);
-  if (fs->file && ftruncate (fileno(fs->file), len) != 0)
+  struct _mu_file_stream *fstr = (struct _mu_file_stream *) str;
+  ssize_t n = read (fstr->fd, buf, size);
+  if (n == -1)
     return errno;
+  *pret = n;
   return 0;
 }
 
 static int
-_file_size (mu_stream_t stream, mu_off_t *psize)
+fd_write (struct _mu_stream *str, const char *buf, size_t size, size_t *pret)
 {
-  struct _file_stream *fs = mu_stream_get_owner (stream);
-  struct stat stbuf;
-  if (!fs->file)
-    {
-      if (psize)
-       *psize = 0;
-      return 0;
-    }
-  fflush (fs->file);
-  if (fstat(fileno(fs->file), &stbuf) == -1)
+  struct _mu_file_stream *fstr = (struct _mu_file_stream *) str;
+  ssize_t n = write (fstr->fd, (char*) buf, size);
+  if (n == -1)
     return errno;
-  if (psize)
-    *psize = stbuf.st_size;
+  *pret = n;
   return 0;
 }
 
 static int
-_file_flush (mu_stream_t stream)
+fd_close (struct _mu_stream *str)
 {
-  struct _file_stream *fs = mu_stream_get_owner (stream);
-  if (fs->file)
-    return fflush (fs->file);
-  return 0;
-}
-
-int
-_file_wait (mu_stream_t stream, int *pflags, struct timeval *tvp)
-{
-  struct _file_stream *fs = mu_stream_get_owner (stream);
-
-  if (!fs->file)
-    return EINVAL;
-  return mu_fd_wait (fileno (fs->file), pflags, tvp);
-}
-
-static int
-_file_get_transport2 (mu_stream_t stream,
-                     mu_transport_t *pin, mu_transport_t *pout)
-{
-  struct _file_stream *fs = mu_stream_get_owner (stream);
-  int status = 0;
-
-  if (pin)
+  struct _mu_file_stream *fstr = (struct _mu_file_stream *) str;
+  if (fstr->fd != -1)
     {
-      if (fs->file)
-       *pin = (mu_transport_t) fs->file;
-      else
-       status = EINVAL;
-    }
-  if (pout)
-    *pout = NULL;
-  return status;
-}
-
-static int
-_file_close (mu_stream_t stream)
-{
-  struct _file_stream *fs = mu_stream_get_owner (stream);
-  int err = 0;
-
-  if (!stream)
-    return EINVAL;
-
-  if (fs->file)
-    {
-      int flags = 0;
-
-      mu_stream_get_flags (stream, &flags);
-
-      if ((flags & MU_STREAM_NO_CLOSE) == 0)
-       {
-         if (fclose (fs->file) != 0)
-           err = errno;
-       }
-      
-      fs->file = NULL;
+      if ((str->flags & MU_STREAM_AUTOCLOSE) && close (fstr->fd))
+       return errno;
+      fstr->fd = -1;
     }
-  return err;
-}
-
-static int
-_temp_file_open (mu_stream_t stream)
-{
-  struct _file_stream *fs = mu_stream_get_owner (stream);
-  int fd;
-
-  fd = mu_tempfile (fs->filename, NULL);
-  if (fd == -1)
-    return errno;
-  fs->file = fdopen (fd, "r+b");
-  if (fs->file == NULL)
-    return errno;
-
   return 0;
 }
 
 static int
-_file_open (mu_stream_t stream)
+fd_open (struct _mu_stream *str)
 {
-  struct _file_stream *fs = mu_stream_get_owner (stream);
-  int flg;
+  struct _mu_file_stream *fstr = (struct _mu_file_stream *) str;
+  int oflg;
   int fd;
-  const char *mode;
-  char* filename = 0;
-  int flags = 0;
   
-  if (!fs || !fs->filename)
+  if (!fstr->filename)
     return EINVAL;
-  
-  filename = fs->filename;
-
-  if (fs->file)
-    {
-      fclose (fs->file);
-      fs->file = NULL;
-    }
-
-  mu_stream_get_flags (stream, &flags);
+  if (fstr->fd != -1)
+    fd_close (str);
 
   /* Map the flags to the system equivalent.  */
-  if (flags & MU_STREAM_WRITE && flags & MU_STREAM_READ)
-    return EINVAL;
-  else if (flags & (MU_STREAM_WRITE|MU_STREAM_APPEND))
-    flg = O_WRONLY;
-  else if (flags & MU_STREAM_RDWR)
-    flg = O_RDWR;
+  if ((fstr->stream.flags & MU_STREAM_RDWR) == MU_STREAM_RDWR)
+    oflg = O_RDWR;
+  else if (fstr->stream.flags & (MU_STREAM_WRITE|MU_STREAM_APPEND))
+    oflg = O_WRONLY;
   else /* default */
-    flg = O_RDONLY;
+    oflg = O_RDONLY;
 
-  /* Local folders should not block it is local disk ???
-     We simply ignore the O_NONBLOCK flag
-     But take care of the APPEND.  */
-  if (flags & MU_STREAM_APPEND)
-    flg |= O_APPEND;
+  if (fstr->stream.flags & MU_STREAM_APPEND)
+    oflg |= O_APPEND;
 
   /* Handle CREAT with care, not to follow symlinks.  */
-  if (flags & MU_STREAM_CREAT)
+  if (fstr->stream.flags & MU_STREAM_CREAT)
     {
       /* First see if the file already exists.  */
-      fd = open (filename, flg);
+      fd = open (fstr->filename, oflg);
       if (fd == -1)
        {
          /* Oops bail out.  */
          if (errno != ENOENT)
            return errno;
          /* Race condition here when creating the file ??.  */
-         fd = open (filename, flg|O_CREAT|O_EXCL,
-                    0600 | mu_stream_flags_to_mode (flags, 0));
-         if (fd < 0)
-           return errno;
+         fd = open (fstr->filename, oflg|O_CREAT|O_EXCL,
+                    0600 | mu_stream_flags_to_mode (fstr->stream.flags, 0));
        }
     }
   else
-    {
-      fd = open (filename, flg);
-      if (fd < 0)
-        return errno;
-    }
+    fd = open (fstr->filename, oflg);
 
-  /* We have to make sure that We did not open
-     a symlink. From Casper D. in bugtraq.  */
-  if (flg & (MU_STREAM_CREAT | MU_STREAM_RDWR
-            | MU_STREAM_WRITE | MU_STREAM_APPEND))
+  if (fd == -1)
+    return errno;
+  
+  if (!(fstr->stream.flags & MU_STREAM_ALLOW_LINKS)
+      && (fstr->stream.flags & (MU_STREAM_CREAT | MU_STREAM_RDWR |
+                               MU_STREAM_APPEND)))
     {
       struct stat fdbuf, filebuf;
 
       /* The next two stats should never fail.  */
-      if (fstat (fd, &fdbuf) == -1)
-       return errno;
-      if (lstat (filename, &filebuf) == -1)
-       return errno;
+      if (fstat (fd, &fdbuf) == -1
+         || lstat (fstr->filename, &filebuf) == -1)
+       {
+         close (fd);
+         return errno;
+       }
 
       /* Now check that: file and fd reference the same file,
         file only has one link, file is plain file.  */
-      if (!(flags & MU_STREAM_ALLOW_LINKS)
-         && (fdbuf.st_dev != filebuf.st_dev
-             || fdbuf.st_ino != filebuf.st_ino
-             || fdbuf.st_nlink != 1
-             || filebuf.st_nlink != 1
-             || (fdbuf.st_mode & S_IFMT) != S_IFREG))
+      if ((fdbuf.st_dev != filebuf.st_dev
+          || fdbuf.st_ino != filebuf.st_ino
+          || fdbuf.st_nlink != 1
+          || filebuf.st_nlink != 1
+          || (fdbuf.st_mode & S_IFMT) != S_IFREG))
        {
-         mu_error (_("%s must be a plain file with one link"), filename);
+         /* FIXME: Be silent */
          close (fd);
-         return EINVAL;
+         return MU_FSTR_ERROR_NOREG;
        }
     }
-  /* We use FILE * object.  */
-  if (flags & MU_STREAM_APPEND)
-    mode = "a";
-  else if (flags & MU_STREAM_RDWR)
-    mode = "r+b";
-  else if (flags & MU_STREAM_WRITE)
-    mode = "wb";
-  else /* Default readonly.  */
-    mode = "rb";
-
-  fs->file = fdopen (fd, mode);
-  if (fs->file == NULL)
+  
+  if (fd < 0)
     return errno;
 
-  return 0;
-}
-
-int
-_file_strerror (mu_stream_t unused, const char **pstr)
-{
-  *pstr = strerror (errno);
-  return 0;
-}
-
-int
-mu_file_stream_create (mu_stream_t *stream, const char* filename, int flags)
-{
-  struct _file_stream *fs;
-  int ret;
-
-  if (stream == NULL)
-    return MU_ERR_OUT_PTR_NULL;
+  /* Make sure it will be closed */
+  fstr->flags |= MU_STREAM_AUTOCLOSE;
 
-  fs = calloc (1, sizeof (struct _file_stream));
-  if (fs == NULL)
-    return ENOMEM;
-
-  if ((fs->filename = strdup(filename)) == NULL)
-    {
-      free (fs);
-      return ENOMEM;
-    }
-
-  ret = mu_stream_create (stream, flags|MU_STREAM_NO_CHECK, fs);
-  if (ret != 0)
-    {
-      free (fs->filename);
-      free (fs);
-      return ret;
-    }
-
-  mu_stream_set_open (*stream, _file_open, fs);
-  mu_stream_set_close (*stream, _file_close, fs);
-  mu_stream_set_get_transport2 (*stream, _file_get_transport2, fs);
-  mu_stream_set_read (*stream, _file_read, fs);
-  mu_stream_set_readline (*stream, _file_readline, fs);
-  mu_stream_set_write (*stream, _file_write, fs);
-  mu_stream_set_truncate (*stream, _file_truncate, fs);
-  mu_stream_set_size (*stream, _file_size, fs);
-  mu_stream_set_flush (*stream, _file_flush, fs);
-  mu_stream_set_destroy (*stream, _file_destroy, fs);
-  mu_stream_set_strerror (*stream, _file_strerror, fs);
-  mu_stream_set_wait (*stream, _file_wait, fs);
-  
+  fstr->fd = fd;
   return 0;
 }
 
 int
-mu_temp_file_stream_create (mu_stream_t *stream, const char *dir)
-{
-  struct _file_stream *fs;
-  int ret;
-
-  if (stream == NULL)
-    return MU_ERR_OUT_PTR_NULL;
-
-  fs = calloc (1, sizeof (struct _file_stream));
-  if (fs == NULL)
-    return ENOMEM;
-  fs->tempfile = 1;
-
-  if (!dir)
-    fs->filename = NULL;
-  else if ((fs->filename = strdup (dir)) == NULL)
-    {
-      free (fs);
-      return ENOMEM;
-    }
-  
-  ret = mu_stream_create (stream,
-                         MU_STREAM_RDWR|MU_STREAM_CREAT|MU_STREAM_NO_CHECK,
-                         fs);
-  if (ret != 0)
-    {
-      free (fs);
-      return ret;
-    }
-
-  mu_stream_set_open (*stream, _temp_file_open, fs);
-  mu_stream_set_close (*stream, _file_close, fs);
-  mu_stream_set_get_transport2 (*stream, _file_get_transport2, fs);
-  mu_stream_set_read (*stream, _file_read, fs);
-  mu_stream_set_readline (*stream, _file_readline, fs);
-  mu_stream_set_write (*stream, _file_write, fs);
-  mu_stream_set_truncate (*stream, _file_truncate, fs);
-  mu_stream_set_size (*stream, _file_size, fs);
-  mu_stream_set_flush (*stream, _file_flush, fs);
-  mu_stream_set_destroy (*stream, _file_destroy, fs);
-  mu_stream_set_strerror (*stream, _file_strerror, fs);
-  mu_stream_set_wait (*stream, _file_wait, fs);
-  
+fd_seek (struct _mu_stream *str, mu_off_t off, mu_off_t *presult)
+{ 
+  struct _mu_file_stream *fstr = (struct _mu_file_stream *) str;
+  off = lseek (fstr->fd, off, SEEK_SET);
+  if (off < 0)
+    return errno;
+  *presult = off;
   return 0;
 }
 
 int
-mu_stdio_stream_create (mu_stream_t *stream, FILE *file, int flags)
+fd_size (struct _mu_stream *str, mu_off_t *psize)
 {
-  struct _file_stream *fs;
-  int ret;
-
-  if (stream == NULL)
-    return MU_ERR_OUT_PTR_NULL;
-
-  if (file == NULL)
-    return EINVAL;
-
-  fs = calloc (1, sizeof (struct _file_stream));
-  if (fs == NULL)
-    return ENOMEM;
-
-  fs->file = file;
-
-  ret = mu_stream_create (stream, flags|MU_STREAM_NO_CHECK, fs);
-  if (ret != 0)
-    {
-      free (fs);
-      return ret;
-    }
-
-  /* Check if we need to enable caching */
-
-  if ((flags & MU_STREAM_SEEKABLE) && lseek (fileno (file), 0, 0))
-    {
-      if ((ret = mu_memory_stream_create (&fs->cache, 0, MU_STREAM_RDWR))
-         || (ret = mu_stream_open (fs->cache)))
-       {
-         mu_stream_destroy (stream, fs);
-         free (fs);
-         return ret;
-       }
-      mu_stream_set_read (*stream, _stdin_file_read, fs);
-      mu_stream_set_readline (*stream, _stdin_file_readline, fs);
-      mu_stream_set_write (*stream, _stdout_file_write, fs);
-      mu_stream_set_size (*stream, _stdin_file_size, fs);
-    }
-  else
-    {
-      mu_stream_set_read (*stream, _file_read, fs);
-      mu_stream_set_readline (*stream, _file_readline, fs);
-      mu_stream_set_write (*stream, _file_write, fs);
-    }
-  
-  /* We don't need to open the FILE, just return success. */
-
-  mu_stream_set_open (*stream, NULL, fs);
-  mu_stream_set_close (*stream, _file_close, fs);
-  mu_stream_set_get_transport2 (*stream, _file_get_transport2, fs);
-  mu_stream_set_flush (*stream, _file_flush, fs);
-  mu_stream_set_destroy (*stream, _file_destroy, fs);
-  mu_stream_set_wait (*stream, _file_wait, fs);
-  
+  struct _mu_file_stream *fstr = (struct _mu_file_stream *) str;
+  struct stat st;
+  if (fstat (fstr->fd, &st))
+    return errno;
+  *psize = st.st_size;
   return 0;
 }
 
-
-struct _prog_stream
-{
-  pid_t pid;
-  int status;
-  pid_t writer_pid;
-  int argc;
-  char **argv;
-  mu_stream_t in, out;
-
-  mu_stream_t input;
-};
-
-static mu_list_t prog_stream_list;
-
-static int
-_prog_stream_register (struct _prog_stream *stream)
+void
+fd_done (struct _mu_stream *str)
 {
-  if (!prog_stream_list)
-    {
-      int rc = mu_list_create (&prog_stream_list);
-      if (rc)
-       return rc;
-    }
-  return mu_list_append (prog_stream_list, stream);
+  struct _mu_file_stream *fstr = (struct _mu_file_stream *) str;
+  if (fstr->fd != -1)
+    fd_close (str);
+  if (fstr->filename)
+    free (fstr->filename);
 }
 
-static void
-_prog_stream_unregister (struct _prog_stream *stream)
+const char *
+fd_error_string (struct _mu_stream *str, int rc)
 {
-  mu_list_remove (prog_stream_list, stream);
+  if (rc == MU_FSTR_ERROR_NOREG)
+    return _("must be a plain file with one link");
+  else
+    return mu_strerror (rc);
 }
 
-#if defined (HAVE_SYSCONF) && defined (_SC_OPEN_MAX)
-# define getmaxfd() sysconf (_SC_OPEN_MAX)
-#elif defined (HAVE_GETDTABLESIZE)
-# define getmaxfd() getdtablesize ()
-#else
-# define getmaxfd() 64
-#endif
-
-#define REDIRECT_STDIN_P(f) ((f) & (MU_STREAM_WRITE|MU_STREAM_RDWR))
-#define REDIRECT_STDOUT_P(f) ((f) & (MU_STREAM_READ|MU_STREAM_RDWR))
-
 static int
-start_program_filter (pid_t *pid, int *p, int argc, char **argv,
-                     char *errfile, int flags)
+fd_ioctl (struct _mu_stream *str, int code, void *ptr)
 {
-  int rightp[2], leftp[2];
-  int i;
-  int rc = 0;
-  
-  if (REDIRECT_STDIN_P (flags))
-    pipe (leftp);
-  if (REDIRECT_STDOUT_P (flags))
-    pipe (rightp);
+  struct _mu_file_stream *fstr = (struct _mu_file_stream *) str;
+  mu_transport_t *ptrans;
   
-  switch (*pid = fork ())
-    {
-      /* The child branch.  */
-    case 0:
-      /* attach the pipes */
-
-      /* Right-end */
-      if (REDIRECT_STDOUT_P (flags))
-       {
-         if (rightp[1] != 1)
-           {
-             close (1);
-             dup2 (rightp[1], 1);
-           }
-         close (rightp[0]);
-       }
-
-      /* Left-end */
-      if (REDIRECT_STDIN_P (flags))
-       {
-         if (leftp[0] != 0)
-           {
-             close (0);
-             dup2 (leftp[0], 0);
-           }
-         close (leftp[1]);
-       }
-      
-      /* Error output */
-      if (errfile)
-       {
-         i = open (errfile, O_CREAT|O_WRONLY|O_APPEND, 0644);
-         if (i > 0 && i != 2)
-           {
-             dup2 (i, 2);
-             close (i);
-           }
-       }
-      /* Close unneded descripitors */
-      for (i = getmaxfd (); i > 2; i--)
-       close (i);
-
-      syslog (LOG_ERR|LOG_USER, "run %s %s",
-             argv[0], argv[1]);
-      /*FIXME: Switch to other uid/gid if desired */
-      execvp (argv[0], argv);
-               
-      /* Report error via syslog */
-      syslog (LOG_ERR|LOG_USER, "can't run %s (ruid=%d, euid=%d): %m",
-             argv[0], getuid (), geteuid ());
-      exit (127);
-      /********************/
-
-      /* Parent branches: */
-    case -1:
-      /* Fork has failed */
-      /* Restore things */
-      rc = errno;
-      if (REDIRECT_STDOUT_P (flags))
-       {
-         close (rightp[0]);
-         close (rightp[1]);
-       }
-      if (REDIRECT_STDIN_P (flags))
-       {
-         close (leftp[0]);
-         close (leftp[1]);
-       }
+  switch (code)
+    {
+    case MU_IOCTL_GET_TRANSPORT:
+      if (!ptr)
+       return EINVAL;
+      ptrans = ptr;
+      ptrans[0] = (mu_transport_t) fstr->fd;
+      ptrans[1] = NULL;
       break;
-               
-    default:
-      if (REDIRECT_STDOUT_P (flags))
-       {
-         p[0] = rightp[0];
-         close (rightp[1]);
-       }
-      else
-       p[0] = -1;
-
-      if (REDIRECT_STDIN_P (flags))
-       {
-         p[1] = leftp[1];
-         close (leftp[0]);
-       }
-      else
-       p[1] = -1;
-    }
-  return rc;
-}
 
-static void
-_prog_wait (pid_t pid, int *pstatus)
-{
-  if (pid > 0)
-    {
-      pid_t t;
-      do
-       t = waitpid (pid, pstatus, 0);
-      while (t == -1 && errno == EINTR);
-    }
-}
-
-static void
-_prog_destroy (mu_stream_t stream)
-{
-  struct _prog_stream *fs = mu_stream_get_owner (stream);
-  int status;
-    
-  mu_argcv_free (fs->argc, fs->argv);
-  if (fs->in)
-    mu_stream_destroy (&fs->in, mu_stream_get_owner (fs->in));
-  if (fs->out)
-    mu_stream_destroy (&fs->out, mu_stream_get_owner (fs->out));
-  
-  _prog_wait (fs->pid, &fs->status);
-  fs->pid = -1;
-  _prog_wait (fs->writer_pid, &status);
-  fs->writer_pid = -1;
-  
-  _prog_stream_unregister (fs);
-}
-
-static int
-_prog_close (mu_stream_t stream)
-{
-  struct _prog_stream *fs = mu_stream_get_owner (stream);
-  int status;
-  
-  if (!stream)
-    return EINVAL;
-  
-  if (fs->pid <= 0)
-    return 0;
-
-  mu_stream_close (fs->out);
-  mu_stream_destroy (&fs->out, mu_stream_get_owner (fs->out));
-
-  _prog_wait (fs->pid, &fs->status);
-  fs->pid = -1;
-  _prog_wait (fs->writer_pid, &status);
-  fs->writer_pid = -1;
-  
-  mu_stream_close (fs->in);
-  mu_stream_destroy (&fs->in, mu_stream_get_owner (fs->in));
-
-  if (WIFEXITED (fs->status))
-    {
-      if (WEXITSTATUS (fs->status) == 0)
-       return 0;
-      else if (WEXITSTATUS (fs->status) == 127)
-       return MU_ERR_PROCESS_NOEXEC;
-      else
-       return MU_ERR_PROCESS_EXITED;
-    }
-  else if (WIFSIGNALED (fs->status))
-    return MU_ERR_PROCESS_SIGNALED;
-  return MU_ERR_PROCESS_UNKNOWN_FAILURE;
-}
-
-static int
-feed_input (struct _prog_stream *fs)
-{
-  pid_t pid;
-  size_t size;
-  char buffer[128];
-  int rc = 0;
-
-  pid = fork ();
-  switch (pid)
-    {
-    default:
-      /* Master */
-      fs->writer_pid = pid;
-      mu_stream_close (fs->out);
-      mu_stream_destroy (&fs->out, mu_stream_get_owner (fs->out));
+    case MU_IOCTL_SET_TRANSPORT:
+      if (!ptr)
+       return EINVAL;
+      ptrans = ptr;
+      fstr->fd = (int) ptrans[0];
       break;
       
-    case 0:
-      /* Child */
-      while (mu_stream_sequential_read (fs->input, buffer, sizeof (buffer),
-                                    &size) == 0
-            && size > 0)
-       mu_stream_sequential_write (fs->out, buffer, size);
-      mu_stream_close (fs->out);
-      exit (0);
-      
-    case -1:
-      rc = errno;
-    }
-
-  return rc;
-}
-  
-static int
-_prog_open (mu_stream_t stream)
-{
-  struct _prog_stream *fs = mu_stream_get_owner (stream);
-  int rc;
-  int pfd[2];
-  int flags;
-  int seekable_flag;
-  
-  if (!fs || fs->argc == 0)
-    return EINVAL;
-
-  if (fs->pid)
-    {
-      _prog_close (stream);
-    }
-
-  mu_stream_get_flags (stream, &flags);
-  seekable_flag = (flags & MU_STREAM_SEEKABLE);
-  
-  rc = start_program_filter (&fs->pid, pfd, fs->argc, fs->argv, NULL, flags);
-  if (rc)
-    return rc;
-
-  if (REDIRECT_STDOUT_P (flags))
-    {
-      FILE *fp = fdopen (pfd[0], "r");
-      setvbuf (fp, NULL, _IONBF, 0);
-      rc = mu_stdio_stream_create (&fs->in, fp, MU_STREAM_READ|seekable_flag);
-      if (rc)
-       {
-         _prog_close (stream);
-         return rc;
-       }
-      rc = mu_stream_open (fs->in);
-      if (rc)
-       {
-         _prog_close (stream);
-         return rc;
-       }
-    }
-  
-  if (REDIRECT_STDIN_P (flags))
-    {
-      FILE *fp = fdopen (pfd[1], "w");
-      setvbuf (fp, NULL, _IONBF, 0);
-      rc = mu_stdio_stream_create (&fs->out, fp, 
MU_STREAM_WRITE|seekable_flag);
-      if (rc)
-       {
-         _prog_close (stream);
-         return rc;
-       }
-      rc = mu_stream_open (fs->out);
-      if (rc)
-       {
-         _prog_close (stream);
-         return rc;
-       }
+    default:
+      return EINVAL;
     }
-
-  _prog_stream_register (fs);
-  if (fs->input)
-    return feed_input (fs);
   return 0;
 }
 
-static int
-_prog_read (mu_stream_t stream, char *optr, size_t osize,
-           mu_off_t offset, size_t *pnbytes)
-{
-  struct _prog_stream *fs = mu_stream_get_owner (stream);
-  return mu_stream_read (fs->in, optr, osize, offset, pnbytes);
-}
-
-static int
-_prog_readline (mu_stream_t stream, char *optr, size_t osize,
-               mu_off_t offset, size_t *pnbytes)
+int
+fd_wait (mu_stream_t stream, int *pflags, struct timeval *tvp)
 {
-  struct _prog_stream *fs = mu_stream_get_owner (stream);
-  return mu_stream_readline (fs->in, optr, osize, offset, pnbytes);
-}
+  struct _mu_file_stream *fstr = (struct _mu_file_stream *) stream;
 
-static int
-_prog_write (mu_stream_t stream, const char *iptr, size_t isize,
-            mu_off_t offset, size_t *pnbytes)
-{
-  struct _prog_stream *fs = mu_stream_get_owner (stream);
-  return mu_stream_write (fs->out, iptr, isize, offset, pnbytes);
+  if (fstr->fd == -1)
+    return EINVAL;
+  return mu_fd_wait (fstr->fd, pflags, tvp);
 }
 
-static int
-_prog_flush (mu_stream_t stream)
+int
+fd_truncate (mu_stream_t stream, mu_off_t size)
 {
-  struct _prog_stream *fs = mu_stream_get_owner (stream);
-  mu_stream_flush (fs->in);
-  mu_stream_flush (fs->out);
+  struct _mu_file_stream *fstr = (struct _mu_file_stream *) stream;
+  if (ftruncate (fstr->fd, size))
+    return errno;
   return 0;
 }
 
-static int
-_prog_get_transport2 (mu_stream_t stream, mu_transport_t *pin, mu_transport_t 
*pout)
-{
-  int rc;
-  struct _prog_stream *fs = mu_stream_get_owner (stream);
-  
-  if ((rc = mu_stream_get_transport (fs->in, pin)) != 0)
-    return rc;
-  return mu_stream_get_transport (fs->out, pout);
-}
-
 int
-_prog_stream_create (struct _prog_stream **pfs,
-                    mu_stream_t *stream, const char *progname, int flags)
+_mu_file_stream_create (struct _mu_file_stream **pstream, size_t size,
+                       const char *filename, int fd, int flags)
 {
-  struct _prog_stream *fs;
-  int ret;
-
-  if (stream == NULL)
-    return MU_ERR_OUT_PTR_NULL;
-
-  if (progname == NULL || (flags & MU_STREAM_NO_CLOSE))
-    return EINVAL;
-
-  if ((flags & (MU_STREAM_READ|MU_STREAM_WRITE)) ==
-      (MU_STREAM_READ|MU_STREAM_WRITE))
-    {
-      flags &= ~(MU_STREAM_READ|MU_STREAM_WRITE);
-      flags |= MU_STREAM_RDWR;
-    }
-  
-  fs = calloc (1, sizeof (*fs));
-  if (fs == NULL)
+  struct _mu_file_stream *str =
+    (struct _mu_file_stream *) _mu_stream_create (size, flags);
+  if (!str)
     return ENOMEM;
-  if (mu_argcv_get (progname, "", "#", &fs->argc, &fs->argv))
-    {
-      mu_argcv_free (fs->argc, fs->argv);
-      free (fs);
-      return ENOMEM;
-    }
-
-  ret = mu_stream_create (stream, flags|MU_STREAM_NO_CHECK, fs);
-  if (ret != 0)
-    {
-      mu_argcv_free (fs->argc, fs->argv);
-      free (fs);
-      return ret;
-    }
-
-  mu_stream_set_read (*stream, _prog_read, fs);
-  mu_stream_set_readline (*stream, _prog_readline, fs);
-  mu_stream_set_write (*stream, _prog_write, fs);
-  
-  /* We don't need to open the FILE, just return success. */
 
-  mu_stream_set_open (*stream, _prog_open, fs);
-  mu_stream_set_close (*stream, _prog_close, fs);
-  mu_stream_set_get_transport2 (*stream, _prog_get_transport2, fs);
-  mu_stream_set_flush (*stream, _prog_flush, fs);
-  mu_stream_set_destroy (*stream, _prog_destroy, fs);
-
-  if (pfs)
-    *pfs = fs;
+  str->stream.read = fd_read;
+  str->stream.write = fd_write;
+  str->stream.open = fd_open;
+  str->stream.close = fd_close;
+  str->stream.done = fd_done;
+  str->stream.seek = fd_seek;
+  str->stream.size = fd_size;
+  str->stream.ctl = fd_ioctl;
+  str->stream.wait = fd_wait;
+  str->stream.truncate = fd_truncate;
+  str->stream.error_string = fd_error_string;
+
+  if (filename)
+    str->filename = mu_strdup (filename);
+  else
+    str->filename = NULL;
+  str->fd = fd;
+  str->flags = 0;
+  *pstream = str;
   return 0;
 }
 
 int
-mu_prog_stream_create (mu_stream_t *stream, const char *progname, int flags)
-{
-  return _prog_stream_create (NULL, stream, progname, flags);
+mu_file_stream_create (mu_stream_t *pstream, const char *filename, int flags)
+{
+  struct _mu_file_stream *fstr;
+  int rc = _mu_file_stream_create (&fstr,
+                                  sizeof (struct _mu_file_stream),
+                                  filename, -1,
+                                  flags | MU_STREAM_SEEK | 
MU_STREAM_AUTOCLOSE);
+  if (rc == 0)
+    *pstream = (mu_stream_t) fstr;
+  return rc;
 }
 
 int
-mu_filter_prog_stream_create (mu_stream_t *stream, const char *progname,
-                             mu_stream_t input)
-{
-  struct _prog_stream *fs;
-  int rc = _prog_stream_create (&fs, stream, progname, MU_STREAM_RDWR);
-  if (rc)
-    return rc;
-  fs->input = input;
-
-  return 0;
+mu_fd_stream_create (mu_stream_t *pstream, char *filename, int fd, int flags)
+{
+  struct _mu_file_stream *fstr;
+  int rc = _mu_file_stream_create (&fstr,
+                                  sizeof (struct _mu_file_stream),
+                                  filename, fd, flags);
+  if (rc == 0)
+    *pstream = (mu_stream_t) fstr;
+  return rc;
 }
 
diff --git a/mailbox/filter.c b/mailbox/filter.c
index e7ad3d2..13bd43d 100644
--- a/mailbox/filter.c
+++ b/mailbox/filter.c
@@ -18,9 +18,9 @@
    Boston, MA 02110-1301 USA */
 
 /* Notes:
-First draft: Alain Magloire.
-
- */
+   First draft: Alain Magloire.
+   Complete rewrite: Sergey Poznyakoff.
+*/
 
 #ifdef HAVE_CONFIG_H
 # include <config.h>
@@ -34,110 +34,26 @@ First draft: Alain Magloire.
 # include <strings.h>
 #endif
 
-#include <filter0.h>
-#include <stream0.h>
-#include <mailutils/iterator.h>
+#include <mailutils/filter.h>
+#include <mailutils/monitor.h>
+#include <mailutils/list.h>
 #include <mailutils/stream.h>
 #include <mailutils/errno.h>
-#include <mailutils/mutil.h>
 #include <mailutils/cstr.h>
 
-static void
-filter_destroy (mu_stream_t stream)
-{
-  mu_filter_t filter = mu_stream_get_owner (stream);
-  if (!(stream->flags & MU_STREAM_NO_CLOSE))
-    mu_stream_destroy (&filter->stream, mu_stream_get_owner (filter->stream));
-  if (filter->_destroy)
-    filter->_destroy (filter);
-  if (filter->property)
-    mu_property_destroy (&(filter->property), filter);
-  free (filter);
-}
-
-static int
-filter_read (mu_stream_t stream, char *buffer, size_t buflen, mu_off_t offset,
-            size_t *nbytes)
-{
-  mu_filter_t filter = mu_stream_get_owner (stream);
-  if (filter->_read && (filter->direction & MU_STREAM_READ
-                     || filter->direction & MU_STREAM_RDWR))
-    return filter->_read (filter, buffer, buflen, offset, nbytes);
-  return mu_stream_read (filter->stream, buffer, buflen, offset, nbytes);
-}
-
-static int
-filter_readline (mu_stream_t stream, char *buffer, size_t buflen,
-                mu_off_t offset, size_t *nbytes)
-{
-  mu_filter_t filter = mu_stream_get_owner (stream);
-  if (filter->_readline && (filter->direction & MU_STREAM_READ
-                         || filter->direction & MU_STREAM_RDWR))
-    return filter->_readline (filter, buffer, buflen, offset, nbytes);
-  return mu_stream_readline (filter->stream, buffer, buflen, offset, nbytes);
-}
-
-static int
-filter_write (mu_stream_t stream, const char *buffer, size_t buflen,
-             mu_off_t offset, size_t *nbytes)
-{
-  mu_filter_t filter = mu_stream_get_owner (stream);
-  if (filter->_write && (filter->direction & MU_STREAM_WRITE
-                      || filter->direction & MU_STREAM_RDWR))
-    return filter->_write (filter, buffer, buflen, offset, nbytes);
-  return mu_stream_write (filter->stream, buffer, buflen, offset, nbytes);
-}
-
-static int
-filter_open (mu_stream_t stream)
-{
-  mu_filter_t filter = mu_stream_get_owner (stream);
-
-  return mu_stream_open (filter->stream);
-}
-
-static int
-filter_truncate (mu_stream_t stream, mu_off_t len)
-{
-  mu_filter_t filter = mu_stream_get_owner (stream);
-  return mu_stream_truncate (filter->stream, len);
-}
-
-static int
-filter_size (mu_stream_t stream, mu_off_t *psize)
-{
-  mu_filter_t filter = mu_stream_get_owner (stream);
-  return mu_stream_size (filter->stream, psize);
-}
-
-static int
-filter_flush (mu_stream_t stream)
-{
-  mu_filter_t filter = mu_stream_get_owner(stream);
-  return mu_stream_flush (filter->stream);
-}
-
-static int
-filter_get_transport2 (mu_stream_t stream, mu_transport_t *pin, mu_transport_t 
*pout)
-{
-  mu_filter_t filter = mu_stream_get_owner (stream);
-  return mu_stream_get_transport2 (filter->stream, pin, pout);
-}
-
-static int
-filter_close (mu_stream_t stream)
-{
-  mu_filter_t filter = mu_stream_get_owner (stream);
-  if (stream->flags & MU_STREAM_NO_CLOSE)
-    return 0;
-  return mu_stream_close (filter->stream);
-}
-
 /* NOTE: We will leak here since the monitor of the filter will never
    be release.  That's ok we can leave with this, it's only done once.  */
 static mu_list_t filter_list;
 struct mu_monitor filter_monitor = MU_MONITOR_INITIALIZER;
 
+static int
+filter_name_cmp (const void *item, const void *data)
+{
+  struct _mu_filter_record const *rec = item;
+  char const *name = data;
+  return mu_c_strcasecmp (rec->name, name);
+}
+
 int
 mu_filter_get_list (mu_list_t *plist)
 {
@@ -149,6 +65,7 @@ mu_filter_get_list (mu_list_t *plist)
       int status = mu_list_create (&filter_list);
       if (status != 0)
        return status;
+      mu_list_set_comparator (filter_list, filter_name_cmp);
       /* Default filters.  */
       mu_list_append (filter_list, mu_base64_filter);
       mu_list_append (filter_list, mu_qp_filter);
@@ -156,6 +73,7 @@ mu_filter_get_list (mu_list_t *plist)
       mu_list_append (filter_list, mu_bit8_filter);
       mu_list_append (filter_list, mu_bit7_filter);
       mu_list_append (filter_list, mu_rfc822_filter);
+      mu_list_append (filter_list, mu_crlf_filter);
       mu_list_append (filter_list, mu_rfc_2047_Q_filter);
       mu_list_append (filter_list, mu_rfc_2047_B_filter);
       /* FIXME: add the default encodings?  */
@@ -165,106 +83,109 @@ mu_filter_get_list (mu_list_t *plist)
   return 0;
 }
 
-int
-mu_filter_create (mu_stream_t *pstream, mu_stream_t stream, const char *name,
-                 int type, int flags)
+static int
+filter_create_rd (mu_stream_t *pstream, mu_stream_t stream,
+                 size_t max_line_length,
+                 int mode,
+                 mu_filter_xcode_t xcode, void *xdata,
+                 int flags)
 {
-  mu_iterator_t iterator = NULL;
-  mu_filter_record_t filter_record = NULL;
-  int  (*f_init)  (mu_filter_t)  = NULL;
-  int found = 0;
   int status;
-  mu_list_t list = NULL;
-
-  if (pstream == NULL)
-    return MU_ERR_OUT_PTR_NULL;
-  if (stream == NULL || name == NULL)
-    return EINVAL;
-
-  mu_filter_get_list (&list);
-  status = mu_list_get_iterator (list, &iterator);
-  if (status != 0)
-    return status;
-
-  for (mu_iterator_first (iterator); !mu_iterator_is_done (iterator);
-       mu_iterator_next (iterator))
-    {
-      mu_iterator_current (iterator, (void **)&filter_record);
-      if ((filter_record->_is_filter
-          && filter_record->_is_filter (filter_record, name))
-         || (mu_c_strcasecmp (filter_record->name, name) == 0))
-        {
-         found = 1;
-         if (filter_record->_get_filter)
-           filter_record->_get_filter (filter_record, &f_init);
-         else
-           f_init = filter_record->_mu_filter;
-         break;
-        }
-    }
-  mu_iterator_destroy (&iterator);
-
-  if (found)
+  mu_stream_t fltstream;
+
+  flags &= ~MU_STREAM_AUTOCLOSE;
+  
+  status = mu_filter_stream_create (&fltstream, stream,
+                                   mode, xcode, xdata,
+                                   flags);
+  if (status == 0)
     {
-      mu_filter_t filter;
-
-      filter = calloc (1, sizeof (*filter));
-      if (filter == NULL)
-       return ENOMEM;
-
-      status = mu_stream_create (pstream, flags | MU_STREAM_NO_CHECK, filter);
-      if (status != 0)
+      if (max_line_length)
        {
-         free (filter);
-         return status;
+         status = mu_linelen_filter_create (pstream, fltstream,
+                                            max_line_length,
+                                            flags);
+         mu_stream_unref (fltstream);
+         if (status)
+           return status;
        }
+      else
+       *pstream = fltstream;
 
-      filter->stream = stream;
-      filter->filter_stream = *pstream;
-      filter->direction = (flags == 0) ? MU_STREAM_READ
-                             : (flags
-                                & (MU_STREAM_READ |
-                                   MU_STREAM_WRITE |
-                                   MU_STREAM_RDWR));
-      filter->type = type;
+      if (flags & MU_STREAM_AUTOCLOSE)
+       mu_stream_unref (stream);
+    }
+  return status;
+}
 
-      status = mu_property_create (&(filter->property), filter);
-      if (status != 0)
-       {
-         mu_stream_destroy (pstream, filter);
-         free (filter);
-         return status;
-       }
-      mu_property_set_value (filter->property, "DIRECTION",
-                         ((filter->direction == MU_STREAM_WRITE) ? "WRITE":
-                          (filter->direction == MU_STREAM_RDWR) ? "RDWR" :
-                          "READ"), 1);
-      mu_property_set_value (filter->property, "TYPE", filter_record->name, 1);
-      mu_stream_set_property (*pstream, filter->property, filter);
+static int
+filter_create_wr (mu_stream_t *pstream, mu_stream_t stream,
+                 size_t max_line_length,
+                 int mode,
+                 mu_filter_xcode_t xcode, void *xdata,
+                 int flags)
+{
+  int status;
+  mu_stream_t fltstream, instream = NULL, tmpstr;
 
-      if (f_init != NULL)
-       {
-         status = f_init (filter);
-         if (status != 0)
-           {
-             mu_stream_destroy (pstream, filter);
-             free (filter);
-             return status;
-           }
-        }
+  flags &= ~MU_STREAM_AUTOCLOSE;
 
-      mu_stream_set_open (*pstream, filter_open, filter);
-      mu_stream_set_close (*pstream, filter_close, filter);
-      mu_stream_set_read (*pstream, filter_read, filter);
-      mu_stream_set_readline (*pstream, filter_readline, filter);
-      mu_stream_set_write (*pstream, filter_write, filter);
-      mu_stream_set_get_transport2 (*pstream, filter_get_transport2, filter );
-      mu_stream_set_truncate (*pstream, filter_truncate, filter );
-      mu_stream_set_size (*pstream, filter_size, filter );
-      mu_stream_set_flush (*pstream, filter_flush, filter );
-      mu_stream_set_destroy (*pstream, filter_destroy, filter);
+  if (max_line_length)
+    {
+      status = mu_linelen_filter_create (&instream, stream,
+                                        max_line_length,
+                                        flags);
+      if (status)
+       return status;
+      tmpstr = instream;
     }
   else
-    status = MU_ERR_NOENT;
+    tmpstr = stream;
+  
+  status = mu_filter_stream_create (&fltstream, tmpstr,
+                                   mode, xcode, xdata,
+                                   flags);
+  mu_stream_unref (instream);
+  if (status)
+    return status;
+  *pstream = fltstream;
+  if (flags & MU_STREAM_AUTOCLOSE)
+    mu_stream_unref (stream);
+  return status;
+}
+
+int
+mu_filter_create (mu_stream_t *pstream, mu_stream_t stream, const char *name,
+                 int mode, int flags)
+{
+  int status;
+  mu_filter_record_t frec;
+  mu_list_t list;
+  void *xdata = NULL;
+  
+  if ((flags & MU_STREAM_RDWR) == MU_STREAM_RDWR)
+    return EINVAL;
+  
+  mu_filter_get_list (&list);
+  status = mu_list_locate (list, (void*)name, (void**)&frec);
+  if (status)
+    return status;
+
+  if (frec->newdata)
+    {
+      status = frec->newdata (&xdata, mode, NULL);
+      if (status)
+       return status;
+    }
+
+  status = ((flags & MU_STREAM_WRITE) ? filter_create_wr : filter_create_rd)
+                   (pstream, stream,
+                   frec->max_line_length,
+                   mode,
+                   mode == MU_FILTER_ENCODE ? frec->encoder : frec->decoder,
+                   xdata,
+                   flags);
+  if (status)
+    free (xdata);
   return status;
 }
diff --git a/mailbox/filter_iconv.c b/mailbox/filter_iconv.c
index e47c5db..93b9cb4 100644
--- a/mailbox/filter_iconv.c
+++ b/mailbox/filter_iconv.c
@@ -20,11 +20,12 @@
 # include <config.h>
 #endif
 
-#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <errno.h>
-#include <ctype.h>
 #include <mailutils/stream.h>
+#include <mailutils/sys/stream.h>
 #include <mailutils/filter.h>
 #include <mailutils/errno.h>
 #include <mailutils/nls.h>
@@ -61,21 +62,22 @@ enum _icvt_state
 
 struct icvt_stream
 {
-  mu_stream_t stream;   /* I/O stream */
+  struct _mu_stream stream;
+  mu_stream_t transport;/* I/O stream */
   int fallback_mode;
-  iconv_t cd;        /* Conversion descriptor */
-  char *buf;         /* Conversion buffer */
-  size_t bufsize;    /* Size of buf */
-  size_t bufpos;     /* Current position in buf */
+  iconv_t cd;           /* Conversion descriptor */
+  char *buf;            /* Conversion buffer */
+  size_t bufsize;       /* Size of buf */
+  size_t bufpos;        /* Current position in buf */
   enum _icvt_state state;
-  int ec;            /* Error code */
-  char errbuf[128];  /* Error message buffer */
+  int ec;               /* Error code */
+  char errbuf[128];     /* Error message buffer */
 };
 
 static int
 _icvt_open (mu_stream_t stream)
 {
-  struct icvt_stream *s = mu_stream_get_owner (stream);
+  struct icvt_stream *s = (struct icvt_stream *)stream;
   if (s->cd == (iconv_t) -1)
     return EINVAL;
   s->state = state_open;
@@ -85,13 +87,10 @@ _icvt_open (mu_stream_t stream)
 static int
 _icvt_close (mu_stream_t stream)
 {
-  struct icvt_stream *s = mu_stream_get_owner (stream);
+  struct icvt_stream *s = (struct icvt_stream *)stream;
   if (s->state != state_closed)
     {
-      int flags;
-      mu_stream_get_flags (stream, &flags);
-      if (!(flags & MU_STREAM_NO_CLOSE))
-       mu_stream_close (s->stream);
+      mu_stream_close (s->transport);
       iconv_close (s->cd);
       s->cd = (iconv_t) -1;
       s->state = state_closed;
@@ -100,30 +99,24 @@ _icvt_close (mu_stream_t stream)
 }
 
 static void
-_icvt_destroy (mu_stream_t stream)
+_icvt_done (mu_stream_t stream)
 {
-  struct icvt_stream *s = mu_stream_get_owner (stream);
-  int flags;
+  struct icvt_stream *s = (struct icvt_stream *)stream;
 
   if (s->state != state_closed)
     _icvt_close (stream);
-  mu_stream_get_flags (stream, &flags);
-  if (!(flags & MU_STREAM_NO_CLOSE))
-    mu_stream_destroy (&s->stream, mu_stream_get_owner (s->stream));
+  mu_stream_destroy (&s->transport);
   free (s->buf);
-  s->buf = NULL;
-  if (s->cd != (iconv_t) -1)
-    iconv_close (s->cd);
-  free (s);
 }
 
 static int _icvt_read (mu_stream_t stream, char *optr, size_t osize,
-                      mu_off_t offset, size_t *pnbytes);
+                      size_t *pnbytes);
 
 static int
-internal_icvt_read (mu_stream_t stream, char *optr, size_t osize, size_t 
*pnbytes)
+internal_icvt_read (mu_stream_t stream, char *optr, size_t osize,
+                   size_t *pnbytes)
 {
-  struct icvt_stream *s = mu_stream_get_owner (stream);
+  struct icvt_stream *s = (struct icvt_stream *)stream;
   size_t nbytes = 0;
   int rc, status = 0;
   char *ob = optr;
@@ -131,7 +124,7 @@ internal_icvt_read (mu_stream_t stream, char *optr, size_t 
osize, size_t *pnbyte
 
   if (s->bufpos == 0)
     {
-      status = mu_stream_sequential_read (s->stream, s->buf, s->bufsize, 
&nbytes);
+      status = mu_stream_read (s->transport, s->buf, s->bufsize, &nbytes);
       if (status)
        {
          s->state = state_transport_error;
@@ -174,8 +167,6 @@ internal_icvt_read (mu_stream_t stream, char *optr, size_t 
osize, size_t *pnbyte
            }
          else if (errno == EILSEQ)
            {
-             int flags = 0; 
-             mu_stream_get_flags (stream, &flags);
              switch (s->fallback_mode)
                {
                case mu_fallback_none:
@@ -188,13 +179,13 @@ internal_icvt_read (mu_stream_t stream, char *optr, 
size_t osize, size_t *pnbyte
                case mu_fallback_copy_pass:
                  s->state = state_copy_pass;
                  if (ob == optr)
-                   return _icvt_read (stream, optr, osize, 0, pnbytes);
+                   return _icvt_read (stream, optr, osize, pnbytes);
                  break;
                  
                case mu_fallback_copy_octal:
                  s->state = state_copy_octal;
                  if (ob == optr)
-                   return _icvt_read (stream, optr, osize, 0, pnbytes);
+                   return _icvt_read (stream, optr, osize, pnbytes);
                  break;
                }
            }
@@ -220,10 +211,10 @@ internal_icvt_read (mu_stream_t stream, char *optr, 
size_t osize, size_t *pnbyte
        }
     }
   while (olen > 0 
-        && (status = mu_stream_sequential_read (s->stream,
-                                             s->buf + s->bufpos,
-                                             s->bufsize - s->bufpos,
-                                             &nbytes)) == 0
+        && (status = mu_stream_read (s->transport,
+                                     s->buf + s->bufpos,
+                                     s->bufsize - s->bufpos,
+                                     &nbytes)) == 0
         && nbytes);
 
   if (status)
@@ -239,7 +230,7 @@ internal_icvt_read (mu_stream_t stream, char *optr, size_t 
osize, size_t *pnbyte
   return 0;
 }
 
-#define ISPRINT(c) (((c)>=' '&&(c)<127)||c=='\n')
+#define ISPRINT(c) (((c)>=' '&&(c)<127)||(c)=='\n')
 
 static int
 copy_octal (struct icvt_stream *s, char *optr, size_t osize, size_t *pnbytes)
@@ -266,10 +257,10 @@ copy_octal (struct icvt_stream *s, char *optr, size_t 
osize, size_t *pnbytes)
            rdcount = s->bufsize;
        }
 
-      status = mu_stream_sequential_read (s->stream,
-                                      s->buf + s->bufpos,
-                                      rdcount - s->bufpos,
-                                      &rdcount);
+      status = mu_stream_read (s->transport,
+                              s->buf + s->bufpos,
+                              rdcount - s->bufpos,
+                              &rdcount);
       if (status)
        {
          s->state = state_transport_error;
@@ -318,7 +309,7 @@ copy_pass (struct icvt_stream *s, char *optr, size_t osize, 
size_t *pnbytes)
       return 0;
     }
 
-  status = mu_stream_sequential_read (s->stream, optr, osize, &nbytes);
+  status = mu_stream_read (s->transport, optr, osize, &nbytes);
   if (status)
     {
       s->state = state_transport_error;
@@ -332,10 +323,9 @@ copy_pass (struct icvt_stream *s, char *optr, size_t 
osize, size_t *pnbytes)
 }
 
 static int
-_icvt_read (mu_stream_t stream, char *optr, size_t osize,
-           mu_off_t offset MU_ARG_UNUSED, size_t *pnbytes)
+_icvt_read (mu_stream_t stream, char *optr, size_t osize, size_t *pnbytes)
 {
-  struct icvt_stream *s = mu_stream_get_owner (stream);
+  struct icvt_stream *s = (struct icvt_stream *)stream;
 
   switch (s->state)
     {
@@ -357,16 +347,16 @@ _icvt_read (mu_stream_t stream, char *optr, size_t osize,
   return MU_ERR_FAILURE;
 }
 
-int
-_icvt_strerror (mu_stream_t stream, const char **pstr)
+const char *
+_icvt_strerror (mu_stream_t stream, int rc)
 {
-  struct icvt_stream *s = mu_stream_get_owner (stream);
+  struct icvt_stream *s = (struct icvt_stream *)stream;
+
   switch (s->state)
     {
     case state_transport_error:
       snprintf (s->errbuf, sizeof s->errbuf,
                _("Transport error: %s"), mu_strerror (s->ec));
-      *pstr = s->errbuf;
       break;
 
     case state_iconv_error:
@@ -382,56 +372,80 @@ _icvt_strerror (mu_stream_t stream, const char **pstr)
          snprintf (s->errbuf, sizeof s->errbuf,
                    _("Iconv error: %s"), mu_strerror (s->ec));
        }
-      *pstr = s->errbuf;
       break;
 
     case state_closed:
-      *pstr = _("Stream is closed"); 
-      break;
+      return _("Stream is closed"); 
       
     default:
-      *pstr = mu_strerror (s->ec);
+      return mu_strerror (s->ec);
     }
   
-  return 0;
+  return s->errbuf;
 }
 
-int
-_icvt_get_transport2 (mu_stream_t stream,
-                    mu_transport_t *pt, mu_transport_t *pt2)
+static int
+_icvt_ioctl (mu_stream_t stream, int code, void *ptr)
 {
-  struct icvt_stream *s = mu_stream_get_owner (stream);
-  if (pt)
-    *pt = s->stream;
-  if (*pt2)
-    *pt2 = NULL;
+  struct icvt_stream *s = (struct icvt_stream *)stream;
+  mu_transport_t *ptrans;
+  
+  switch (code)
+    {
+    case MU_IOCTL_GET_TRANSPORT:
+      if (!ptr)
+       return EINVAL;
+      ptrans = ptr;
+      ptrans[0] = (mu_transport_t) s->transport;
+      ptrans[1] = NULL;
+      break;
+
+    case MU_IOCTL_SWAP_STREAM:
+      return mu_stream_ioctl (s->transport, code, ptr);
+      
+    default:
+      return EINVAL;
+    }
   return 0;
 }
 
 int
 _icvt_wait (mu_stream_t stream, int *pflags, struct timeval *tvp)
 {
-  struct icvt_stream *s = mu_stream_get_owner (stream);
-  return mu_stream_wait (s->stream, pflags, tvp);
+  struct icvt_stream *s = (struct icvt_stream *)stream;
+  return mu_stream_wait (s->transport, pflags, tvp);
+}
+
+/* FIXME: Seeks in the *transport* stream. */
+int
+_icvt_seek (mu_stream_t stream, mu_off_t off, mu_off_t *presult)
+{
+  struct icvt_stream *s = (struct icvt_stream *)stream;
+  return mu_stream_seek (s->transport, off, MU_SEEK_SET, presult);
 }
 
 int
 mu_filter_iconv_create (mu_stream_t *s, mu_stream_t transport,
-                    const char *fromcode, const char *tocode, int flags,
-                    enum mu_iconv_fallback_mode fallback_mode)
+                       const char *fromcode, const char *tocode, int flags,
+                       enum mu_iconv_fallback_mode fallback_mode)
 {
   struct icvt_stream *iptr;
   iconv_t cd;
-  int rc;
   
   cd = iconv_open (tocode, fromcode);
   if (cd == (iconv_t) -1)
     return MU_ERR_FAILURE;
-  
-  iptr = malloc (sizeof *iptr);
+
+  iptr = (struct icvt_stream *) _mu_stream_create (sizeof (*iptr), flags);
   if (!iptr)
-    return ENOMEM;
-  iptr->stream = transport;
+    {
+      iconv_close (cd);
+      return ENOMEM;
+    }
+  
+  if (!(flags & MU_STREAM_AUTOCLOSE))
+    mu_stream_ref (transport);
+  iptr->transport = transport;
   iptr->fallback_mode = fallback_mode;
   iptr->cd = cd;
   iptr->state = state_closed;
@@ -444,18 +458,15 @@ mu_filter_iconv_create (mu_stream_t *s, mu_stream_t 
transport,
     }
   iptr->bufpos = 0;
   
-  rc = mu_stream_create (s, flags, iptr);
-  if (rc)
-    {
-      free (iptr);
-      return rc;
-    }
-  mu_stream_set_open (*s, _icvt_open, iptr);
-  mu_stream_set_close (*s, _icvt_close, iptr);
-  mu_stream_set_read (*s, _icvt_read, iptr);
-  mu_stream_set_destroy (*s, _icvt_destroy, iptr);
-  mu_stream_set_strerror (*s, _icvt_strerror, iptr);
-  mu_stream_set_get_transport2 (*s, _icvt_get_transport2, iptr);
-  mu_stream_set_wait (*s, _icvt_wait, iptr);
+  iptr->stream.open = _icvt_open;
+  iptr->stream.close = _icvt_close;
+  iptr->stream.read = _icvt_read;
+  iptr->stream.done = _icvt_done;
+  iptr->stream.error_string = _icvt_strerror;
+  iptr->stream.ctl = _icvt_ioctl;
+  iptr->stream.wait = _icvt_wait;
+  iptr->stream.seek = _icvt_seek;
+  iptr->stream.flags = MU_STREAM_READ | MU_STREAM_SEEK;
+  *s = (mu_stream_t)iptr;
   return 0;
 }
diff --git a/mailbox/filter_rfc822.c b/mailbox/filter_rfc822.c
deleted file mode 100644
index d9e0704..0000000
--- a/mailbox/filter_rfc822.c
+++ /dev/null
@@ -1,203 +0,0 @@
-/* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 1999, 2000, 2001, 2005, 2007, 2010 Free Software
-   Foundation, Inc.
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General
-   Public License along with this library; if not, write to the
-   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301 USA */
-
-/* First draft by Alain Magloire */
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <stdlib.h>
-#include <errno.h>
-
-#include <mailutils/property.h>
-#include <mailutils/stream.h>
-
-#include <filter0.h>
-
-static int rfc822_init (mu_filter_t);
-static void rfc822_destroy (mu_filter_t);
-static int rfc822_read (mu_filter_t, char *, size_t, mu_off_t, size_t *);
-static int rfc822_readline (mu_filter_t, char *, size_t, mu_off_t, size_t *);
-static int rfc822_read0 (mu_filter_t, char *, size_t, mu_off_t, size_t *, int);
-
-struct rfc822
-{
-  mu_off_t r_offset; /* rfc822 offset.  */
-  mu_off_t s_offset; /* stream offset.  */
-  size_t lines;
-  int residue;
-};
-
-static struct _mu_filter_record _rfc822_filter =
-{
-  "RFC822",
-  rfc822_init,
-  NULL,
-  NULL,
-  NULL,
-};
-
-/* Exported.  */
-mu_filter_record_t mu_rfc822_filter = &_rfc822_filter;
-
-static int
-rfc822_init (mu_filter_t filter)
-{
-  mu_property_t property;
-  int status;
-  filter->data = calloc (1, sizeof (struct rfc822));
-  if (filter->data == NULL)
-    return ENOMEM;
-
-  filter->_read = rfc822_read;
-  filter->_readline = rfc822_readline;
-  filter->_destroy = rfc822_destroy;
-
-  /* We are interested in this property.  */
-  if ((status = mu_stream_get_property (filter->filter_stream, &property) != 0)
-      || (status = mu_property_set_value (property, "LINES", "0", 1)) != 0)
-    {
-      free (filter->data);
-      filter->data = NULL;
-      return status;
-    }
-  return 0;
-}
-
-static void
-rfc822_destroy (mu_filter_t filter)
-{
-  if (filter->data)
-    free (filter->data);
-}
-
-static int
-rfc822_read (mu_filter_t filter, char *buffer, size_t buflen,
-             mu_off_t off, size_t *pnread)
-{
-  return rfc822_read0 (filter, buffer, buflen, off, pnread, 0);
-}
-
-static int
-rfc822_readline (mu_filter_t filter, char *buffer, size_t buflen,
-                mu_off_t off, size_t *pnread)
-{
-  return rfc822_read0 (filter, buffer, buflen, off, pnread, 1);
-}
-
-/* RFC 822 converter "\n" --> "\r\n"
-   We maintain two offsets, the rfc822 offset (r_offset) and the offset of
-   the stream (s_offset).  If they do not match we go back as far as possible
-   and start to read by 1 'till we reach the current offset.  */
-
-static int
-rfc822_read0 (mu_filter_t filter, char *buffer, size_t buflen,
-             mu_off_t off, size_t *pnread, int isreadline)
-{
-  size_t total = 0;
-  int status = 0;
-  struct rfc822 *rfc822 = filter->data;
-
-  /* Catch up i.e bring us to the current offset.  */
-  if (rfc822->r_offset != off)
-    {
-      rfc822->residue = 0;
- 
-      /* Try to find a starting point.  */
-      if (rfc822->lines)
-       {
-         rfc822->r_offset = off - rfc822->lines;
-         if (rfc822->r_offset < 0)
-           rfc822->r_offset = 0;
-       }
-      else
-       rfc822->r_offset = 0;
-
-      rfc822->s_offset = rfc822->r_offset;
-
-      while (rfc822->r_offset < off)
-       {
-         char c;
-         size_t n = 0;
-         status = mu_stream_read (filter->stream, &c, 1, rfc822->s_offset, &n);
-         if (status != 0)
-           return status;
-         if (n == 0)
-           {
-             if (pnread)
-               *pnread = 0;
-             return 0;
-           }
-         if (c == '\n')
-           {
-             rfc822->r_offset++;
-             if (rfc822->r_offset == off)
-               {
-                 rfc822->residue = 1;
-                 break;
-               }
-           }
-         rfc822->r_offset++;
-         rfc822->s_offset++;
-       }
-    }
-
-  do
-    {
-      size_t nread = 0;
-      status = mu_stream_readline (filter->stream, buffer, buflen,
-                                  rfc822->s_offset, &nread);
-      if (status != 0)
-       return status;
-      if (nread == 0)
-       break;
-      rfc822->r_offset += nread;
-      rfc822->s_offset += nread;
-      total += nread;
-      buflen -= nread;
-      if (buffer[nread - 1] == '\n')
-       {
-         if (!rfc822->residue)
-           {
-             buffer[nread - 1] = '\r';
-             if (buflen == 0)
-               {
-                 rfc822->residue = 1;
-                 break;
-               }
-             buffer[nread] = '\n';
-             buflen--;
-             nread++;
-             total++;
-             rfc822->r_offset++;
-           }
-         else
-           rfc822->residue = 0;
-       }
-      buffer += nread;
-    } while (buflen > 0 && !isreadline);
-
-  if (isreadline && buffer)
-    *buffer = '\0';
-
-  if (pnread)
-    *pnread = total;
-  return status;
-}
diff --git a/mailbox/filter_trans.c b/mailbox/filter_trans.c
deleted file mode 100644
index 411a07e..0000000
--- a/mailbox/filter_trans.c
+++ /dev/null
@@ -1,796 +0,0 @@
-/* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 1999, 2000, 2001, 2004, 2005, 2007, 2010 Free Software
-   Foundation, Inc.
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General
-   Public License along with this library; if not, write to the
-   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301 USA */
-
-/* Notes:
-First Draft: Dave Inglis.
- */
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <mailutils/stream.h>
-#include <mailutils/errno.h>
-
-#include <filter0.h>
-
-#define MU_TRANS_DECODE                1
-#define MU_TRANS_ENCODE                2
-#define MU_TRANS_BSIZE         2048
-
-
-/* General-purpose implementation */
-struct _trans_stream
-{
-  int t_offset; /* Orignal stream offset.  */
-
-  size_t min_size;
-  int s_offset;
-  char *s_buf;     /* Used when read if not big enough to handle min_size
-                     for decoder/encoder */
-
-  int offset;      /* Current stream offset */
-  int line_len;
-
-  int w_rhd;       /* Working buffer read ahead  */
-  int w_whd;       /* Working buffer write ahead */
-  char w_buf[MU_TRANS_BSIZE]; /* working source/dest buffer */
-
-  int (*transcoder) (const char *iptr, size_t isize, char *optr,
-                    size_t osize, size_t *nbytes, int *line_len);
-};
-
-static void
-trans_destroy (mu_filter_t filter)
-{
-  struct _trans_stream *ts = filter->data;
-  if (ts->s_buf)
-    free (ts->s_buf);
-  free (ts);
-}
-
-static int
-trans_read (mu_filter_t filter, char *optr, size_t osize, mu_off_t offset,
-           size_t *n_bytes)
-{
-  struct _trans_stream *ts = filter->data;
-  size_t obytes, wbytes = 0, tbytes = 0;
-  int ret = 0, i;
-  size_t bytes, *nbytes = &bytes;
-
-  if (optr == NULL)
-    return MU_ERR_OUT_NULL;
-  if (osize == 0)
-    return EINVAL;
-
-  if (n_bytes)
-    nbytes = n_bytes;
-  *nbytes = 0;
-
-  if (offset && ts->t_offset != offset)
-    return ESPIPE;
-
-  if (offset == 0)
-    ts->s_offset = ts->t_offset = ts->w_whd = ts->w_rhd =
-      ts->offset = ts->line_len = 0;
-
-  while (*nbytes < osize)
-    {
-      if ((ts->w_rhd + (int)ts->min_size) >= ts->w_whd)
-       {
-         memmove (ts->w_buf, ts->w_buf + ts->w_rhd, ts->w_whd - ts->w_rhd);
-         ts->w_whd = ts->w_whd - ts->w_rhd;
-         ts->w_rhd = 0;
-         ret = mu_stream_read (filter->stream, ts->w_buf + ts->w_whd,
-                            MU_TRANS_BSIZE - ts->w_whd, ts->offset,
-                            &wbytes);
-         if (ret != 0)
-           break;
-         ts->offset += wbytes;
-         ts->w_whd += wbytes;
-       }
-      if ((osize - *nbytes) >= ts->min_size
-         && ts->s_offset == 0
-         && ts->w_whd - ts->w_rhd)
-       {
-         tbytes = ts->transcoder (ts->w_buf + ts->w_rhd,
-                                  ts->w_whd - ts->w_rhd,
-                                  optr + *nbytes, osize - *nbytes,
-                                  &obytes, &ts->line_len);
-         ts->w_rhd += tbytes;
-         if (ts->w_rhd > ts->w_whd) /* over shot due to padding */
-           ts->w_rhd = ts->w_whd;
-         *nbytes += obytes;
-         ts->t_offset += obytes;
-       }
-      else
-       {
-         if (ts->s_offset == 0 && ts->w_whd - ts->w_rhd)
-           {
-             tbytes = ts->transcoder (ts->w_buf + ts->w_rhd,
-                                          ts->w_whd - ts->w_rhd, ts->s_buf,
-                                          ts->min_size, &obytes,
-                                          &ts->line_len);
-             ts->w_rhd += tbytes;
-             if (ts->w_rhd > ts->w_whd) /* over shot due to padding */
-               ts->w_rhd = ts->w_whd;
-             ts->s_offset = obytes;
-           }
-         for (i = ts->s_offset; i > 0; i--)
-           {
-             optr[(*nbytes)++] = ts->s_buf[ts->s_offset - i];
-             ts->t_offset++;
-             if (*nbytes >= osize)
-               {
-                 i--;
-                 memmove (ts->s_buf, &ts->s_buf[ts->s_offset - i], i);
-                 break;
-               }
-           }
-         ts->s_offset = i;
-       }
-      /* FIXME: Should return error code if tbytes == 0? */
-      if (wbytes == 0 && (tbytes == 0 || ts->w_whd - ts->w_rhd == 0))
-       break;
-    }
-  return ret;
-}
-
-
-/*------------------------------------------------------
- * quoted-printable decoder/encoder
- *------------------------------------------------------*/
-static const char _hexdigits[] = "0123456789ABCDEF";
-
-#define QP_LINE_MAX    76
-#define ISWS(c) ((c)==' ' || (c)=='\t')
-
-static int
-qp_decode (const char *iptr, size_t isize, char *optr, size_t osize,
-          size_t *nbytes, int *line_len MU_ARG_UNUSED)
-{
-  char c;
-  int last_char = 0;
-  size_t consumed = 0;
-  size_t wscount = 0;
-  
-  *nbytes = 0;
-  while (consumed < isize && *nbytes < osize)
-    {
-      c = *iptr++;
-
-      if (ISWS (c))
-       {
-         wscount++;
-         consumed++;
-       }
-      else
-       {
-         /* Octets with values of 9 and 32 MAY be
-            represented as US-ASCII TAB (HT) and SPACE characters,
-            respectively, but MUST NOT be so represented at the end
-            of an encoded line.  Any TAB (HT) or SPACE characters
-            on an encoded line MUST thus be followed on that line
-            by a printable character. */
-         
-         if (wscount)
-           {
-             if (c != '\r' && c != '\n')
-               {
-                 size_t sz;
-                 
-                 if (consumed >= isize)
-                   break;
-
-                 if (*nbytes + wscount > osize)
-                   sz = osize - *nbytes;
-                 else
-                   sz = wscount;
-                 memcpy (optr, iptr - wscount - 1, sz);
-                 optr += sz;
-                 (*nbytes) += sz;
-                 if (wscount > sz)
-                   {
-                     wscount -= sz;
-                     break;
-                   }
-               }
-             wscount = 0;
-             if (*nbytes == osize)
-               break;
-           }
-               
-         if (c == '=')
-           {
-             /* There must be 2 more characters before I consume this.  */
-             if (consumed + 2 >= isize)
-               break;
-             else
-               {
-                 /* you get =XX where XX are hex characters.  */
-                 char  chr[3];
-                 int   new_c;
-
-                 chr[2] = 0;
-                 chr[0] = *iptr++;
-                 /* Ignore LF.  */
-                 if (chr[0] != '\n')
-                   {
-                     chr[1] = *iptr++;
-                     new_c = strtoul (chr, NULL, 16);
-                     *optr++ = new_c;
-                     (*nbytes)++;
-                     consumed += 3;
-                   }
-                 else
-                   consumed += 2;
-               }
-           }
-         /* CR character.  */
-         else if (c == '\r')
-           {
-             /* There must be at least 1 more character before
-                I consume this.  */
-             if (consumed + 1 >= isize)
-               break;
-             else
-               {
-                 iptr++; /* Skip the CR character.  */
-                 *optr++ = '\n';
-                 (*nbytes)++;
-                 consumed += 2;
-               }
-           }
-         else
-           {
-             *optr++ = c;
-             (*nbytes)++;
-             consumed++;
-           }
-       }         
-      last_char = c;
-    }
-  return consumed - wscount;
-}
-
-static int
-qp_encode (const char *iptr, size_t isize, char *optr, size_t osize,
-          size_t *nbytes, int *line_len)
-{
-  unsigned int c;
-  size_t consumed = 0;
-
-  *nbytes = 0;
-
-  /* Strategy: check if we have enough room in the output buffer only
-     once the required size has been computed. If there is not enough,
-     return and hope that the caller will free up the output buffer a
-     bit. */
-
-  while (consumed < isize)
-    {
-      int simple_char;
-      
-      /* candidate byte to convert */
-      c = *(unsigned char*) iptr;
-      simple_char = (c >= 32 && c <= 60)
-                    || (c >= 62 && c <= 126)
-                    || c == '\t'
-                    || c == '\n';
-
-      if (*line_len == QP_LINE_MAX
-         || (c == '\n' && consumed && ISWS (optr[-1]))
-         || (!simple_char && *line_len >= (QP_LINE_MAX - 3)))
-       {
-         /* to cut a qp line requires two bytes */
-         if (*nbytes + 2 > osize) 
-           break;
-
-         *optr++ = '=';
-         *optr++ = '\n';
-         (*nbytes) += 2;
-         *line_len = 0;
-       }
-         
-      if (simple_char)
-       {
-         /* a non-quoted character uses up one byte */
-         if (*nbytes + 1 > osize) 
-           break;
-
-         *optr++ = c;
-         (*nbytes)++;
-         (*line_len)++;
-
-         iptr++;
-         consumed++;
-
-         if (c == '\n')
-           *line_len = 0;
-       }
-      else
-       {
-         /* a quoted character uses up three bytes */
-         if ((*nbytes) + 3 > osize) 
-           break;
-
-         *optr++ = '=';
-         *optr++ = _hexdigits[(c >> 4) & 0xf];
-         *optr++ = _hexdigits[c & 0xf];
-
-         (*nbytes) += 3;
-         (*line_len) += 3;
-
-         /* we've actuall used up one byte of input */
-         iptr++;
-         consumed++;
-       }
-    }
-  return consumed;
-}
-
-static int
-qp_init (mu_filter_t filter)
-{
-  struct _trans_stream *ts;
-  ts = calloc (sizeof (*ts), 1);
-  if (ts == NULL)
-    return ENOMEM;
-
-  ts->min_size = QP_LINE_MAX;
-  ts->s_buf = calloc (ts->min_size, 1);
-  if (ts->s_buf == NULL)
-    {
-      free (ts);
-      return ENOMEM;
-    }
-  ts->transcoder = (filter->type == MU_FILTER_DECODE) ? qp_decode : qp_encode;
-
-  filter->_read = trans_read;
-  filter->_destroy = trans_destroy;
-  filter->data = ts;
-  return 0;
-}
-
-static struct _mu_filter_record _qp_filter =
-{
-  "quoted-printable",
-  qp_init,
-  NULL,
-  NULL,
-  NULL
-};
-
-
-/*------------------------------------------------------
- * base64 encode/decode
- *----------------------------------------------------*/
-
-static int
-b64_input (char c)
-{
-  const char table[64] =
-    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-  int i;
-
-  for (i = 0; i < 64; i++)
-    {
-      if (table[i] == c)
-       return i;
-    }
-  return -1;
-}
-
-static int
-base64_decode (const char *iptr, size_t isize, char *optr, size_t osize,
-              size_t *nbytes, int *line_len MU_ARG_UNUSED)
-{
-  int i = 0, tmp = 0, pad = 0;
-  size_t consumed = 0;
-  unsigned char data[4];
-
-  *nbytes = 0;
-  while (consumed < isize && (*nbytes)+3 < osize)
-    {
-      while (( i < 4 ) && (consumed < isize))
-       {
-         tmp = b64_input (*iptr++);
-         consumed++;
-         if (tmp != -1)
-           data[i++] = tmp;
-         else if (*(iptr-1) == '=')
-           {
-             data[i++] = '\0';
-             pad++;
-           }
-       }
-
-      /* I have a entire block of data 32 bits get the output data.  */
-      if (i == 4)
-       {
-         *optr++ = (data[0] << 2) | ((data[1] & 0x30) >> 4);
-         *optr++ = ((data[1] & 0xf) << 4) | ((data[2] & 0x3c) >> 2);
-         *optr++ = ((data[2] & 0x3) << 6) | data[3];
-         (*nbytes) += 3 - pad;
-       }
-      else
-       {
-         /* I did not get all the data.  */
-         consumed -= i;
-         return consumed;
-       }
-      i = 0;
-    }
-  return consumed;
-}
-
-static int
-base64_encode_internal (const char *iptr, size_t isize,
-                       char *optr, size_t osize,
-                       size_t *nbytes, int *line_len, int line_max)
-{
-  size_t consumed = 0;
-  int pad = 0;
-  const char *b64 =
-    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-  const unsigned char* ptr = (const unsigned char*) iptr;
-       
-  *nbytes = 0;
-  if (isize <= 3)
-    pad = 1;
-  while (((consumed + 3) <= isize && (*nbytes + 4) <= osize) || pad)
-    {
-      if (line_max && *line_len == line_max)
-       {
-         *optr++ = '\n';
-         (*nbytes)++;
-         (*line_len) = 0;
-         if ((*nbytes + 4) > osize)
-           return consumed;
-       }
-      *optr++ = b64[ptr[0] >> 2];
-      *optr++ = b64[((ptr[0] << 4) + (--isize ? (ptr[1] >> 4): 0)) & 0x3f];
-      *optr++ = isize ? b64[((ptr[1] << 2) + (--isize ? (ptr[2] >> 6) : 0 )) & 
0x3f] : '=';
-      *optr++ = isize ? b64[ptr[2] & 0x3f] : '=';
-      ptr += 3;
-      consumed += 3;
-      (*nbytes) += 4;
-      (*line_len) +=4;
-      pad = 0;
-    }
-  return consumed;
-}
-
-static int
-base64_encode (const char *iptr, size_t isize,
-              char *optr, size_t osize,
-              size_t *nbytes, int *line_len)
-{
-  return  base64_encode_internal (iptr, isize, optr, osize,
-                                 nbytes, line_len, 76);
-}
-    
-static int
-base64_init (mu_filter_t filter)
-{
-  struct _trans_stream *ts;
-  ts = calloc (sizeof (*ts), 1);
-  if (ts == NULL)
-    return ENOMEM;
-
-  ts->min_size = 4;
-  ts->s_buf = calloc (ts->min_size, 1);
-  if (ts->s_buf == NULL)
-    {
-      free (ts);
-      return ENOMEM;
-    }
-  ts->transcoder = (filter->type == MU_FILTER_DECODE) ? base64_decode : 
base64_encode;
-
-  filter->_read = trans_read;
-  filter->_destroy = trans_destroy;
-  filter->data = ts;
-  return 0;
-}
-
-static struct _mu_filter_record _base64_filter =
-{
-  "base64",
-  base64_init,
-  NULL,
-  NULL,
-  NULL
-};
-
-static int
-B_encode (const char *iptr, size_t isize,
-              char *optr, size_t osize,
-              size_t *nbytes, int *line_len)
-{
-  return  base64_encode_internal (iptr, isize, optr, osize,
-                                 nbytes, line_len, 0);
-}
-
-static int
-B_init (mu_filter_t filter)
-{
-  struct _trans_stream *ts;
-  ts = calloc (sizeof (*ts), 1);
-  if (ts == NULL)
-    return ENOMEM;
-
-  ts->min_size = 4;
-  ts->s_buf = calloc (ts->min_size, 1);
-  if (ts->s_buf == NULL)
-    {
-      free (ts);
-      return ENOMEM;
-    }
-  ts->transcoder = (filter->type == MU_FILTER_DECODE) ? base64_decode : 
B_encode;
-
-  filter->_read = trans_read;
-  filter->_destroy = trans_destroy;
-  filter->data = ts;
-  return 0;
-}
-
-static struct _mu_filter_record _B_filter =
-{
-  "B",
-  B_init,
-  NULL,
-  NULL,
-  NULL
-};
-
-
-
-/* RFC 2047 "Q" Encoding */
-static int
-Q_decode (const char *iptr, size_t isize, char *optr, size_t osize,
-          size_t *nbytes, int *line_len MU_ARG_UNUSED)
-{
-  char c;
-  size_t consumed = 0;
-  
-  *nbytes = 0;
-  while (consumed < isize && *nbytes < osize)
-    {
-      c = *iptr++;
-
-      if (c == '=')
-       {
-         /* There must be 2 more characters before I consume this.  */
-         if (consumed + 2 >= isize)
-           break;
-         else
-           {
-             /* you get =XX where XX are hex characters.  */
-             char chr[3];
-             int  new_c;
-             
-             chr[2] = 0;
-             chr[0] = *iptr++;
-             /* Ignore LF.  */
-             if (chr[0] != '\n')
-               {
-                 chr[1] = *iptr++;
-                 new_c = strtoul (chr, NULL, 16);
-                 *optr++ = new_c;
-                 (*nbytes)++;
-                 consumed += 3;
-               }
-             else
-               consumed += 2;
-           }
-       }
-      /* CR character.  */
-      else if (c == '\r')
-       {
-         /* There must be at least 1 more character before
-            I consume this.  */
-         if (consumed + 1 >= isize)
-           break;
-         else
-           {
-             iptr++; /* Skip the CR character.  */
-             *optr++ = '\n';
-             (*nbytes)++;
-             consumed += 2;
-           }
-       }
-      else if (c == '_')
-       {
-         *optr++ = ' ';
-         (*nbytes)++;
-         consumed++;
-       }
-      else
-       {
-         *optr++ = c;
-         (*nbytes)++;
-         consumed++;
-       }
-    }    
-  return consumed;
-}
-
-static int
-Q_printable_char_p (unsigned c)
-{
-  switch (c)
-    {
-      /* FIXME: This is not quite so. Says RFC 2047:
-        
-      (3) 8-bit values which correspond to printable ASCII characters other
-      than "=", "?", and "_" (underscore), MAY be represented as those
-      characters.  (But see section 5 for restrictions.)  In
-      particular, SPACE and TAB MUST NOT be represented as themselves
-      within encoded words. (see Page 6)*/
-                                       
-    case '=':
-    case '?':
-    case '_':
-    case ' ':
-    case '\t':
-      return 0;
-    default:
-      return c > 32 && c < 127;
-    }
-}
-
-static int
-Q_encode (const char *iptr, size_t isize, char *optr, size_t osize,
-          size_t *nbytes, int *line_len)
-{
-  unsigned int c;
-  size_t consumed = 0;
-
-  *nbytes = 0;
-
-  while (consumed < isize)
-    {
-      c = *(unsigned char*) iptr;
-      if (Q_printable_char_p (c))
-       {
-         /* a non-quoted character uses up one byte */
-         if (*nbytes + 1 > osize) 
-           break;
-         
-         *optr++ = c;
-         (*nbytes)++;
-         (*line_len)++;
-         
-         iptr++;
-         consumed++;
-       }
-      else if (c == 0x20)
-       {
-         /* RFC2047, 4.2.2:
-            Note that the "_"
-            always represents hexadecimal 20, even if the SPACE character
-            occupies a different code position in the character set in use. */
-         *optr++ = '_';
-         (*nbytes)++;
-         (*line_len)++;
-         iptr++;
-         consumed++;
-       }
-      else 
-       {
-         /* a quoted character uses up three bytes */
-         if ((*nbytes) + 3 > osize) 
-           break;
-
-         *optr++ = '=';
-         *optr++ = _hexdigits[(c >> 4) & 0xf];
-         *optr++ = _hexdigits[c & 0xf];
-
-         (*nbytes) += 3;
-         (*line_len) += 3;
-
-         /* we've actuall used up one byte of input */
-         iptr++;
-         consumed++;
-       }
-    }
-  return consumed;
-}
-
-static int
-Q_init (mu_filter_t filter)
-{
-  struct _trans_stream *ts;
-  ts = calloc (sizeof (*ts), 1);
-  if (ts == NULL)
-    return ENOMEM;
-
-  ts->min_size = QP_LINE_MAX;
-  ts->s_buf = calloc (ts->min_size, 1);
-  if (ts->s_buf == NULL)
-    {
-      free (ts);
-      return ENOMEM;
-    }
-  ts->transcoder = (filter->type == MU_FILTER_DECODE) ? Q_decode : Q_encode;
-
-  filter->_read = trans_read;
-  filter->_destroy = trans_destroy;
-  filter->data = ts;
-  return 0;
-}
-
-static struct _mu_filter_record _Q_filter =
-{
-  "Q",
-  Q_init,
-  NULL,
-  NULL,
-  NULL
-};
-
-
-/* Pass-through encodings */
-
-static struct _mu_filter_record _bit8_filter =
-{
-  "8bit",
-  NULL,
-  NULL,
-  NULL,
-  NULL
-};
-
-static struct _mu_filter_record _bit7_filter =
-{
-  "7bit",
-  NULL,
-  NULL,
-  NULL,
-  NULL
-};
-
-static struct _mu_filter_record _binary_filter =
-{
-  "binary",
-  NULL,
-  NULL,
-  NULL,
-  NULL
-};
-
-
-
-/* Export.  */
-mu_filter_record_t mu_qp_filter = &_qp_filter;
-mu_filter_record_t mu_base64_filter = &_base64_filter;
-mu_filter_record_t mu_binary_filter = &_binary_filter;
-mu_filter_record_t mu_bit8_filter = &_bit8_filter;
-mu_filter_record_t mu_bit7_filter = &_bit7_filter;
-mu_filter_record_t mu_rfc_2047_Q_filter = &_Q_filter;
-mu_filter_record_t mu_rfc_2047_B_filter = &_B_filter;
-
-
-
-
diff --git a/mailbox/fltstream.c b/mailbox/fltstream.c
new file mode 100644
index 0000000..5e9b78d
--- /dev/null
+++ b/mailbox/fltstream.c
@@ -0,0 +1,491 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 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 <mailutils/types.h>
+#include <mailutils/alloc.h>
+#include <mailutils/error.h>
+#include <mailutils/errno.h>
+#include <mailutils/nls.h>
+#include <mailutils/stream.h>
+#include <mailutils/sys/filter.h>
+
+#define MFB_BASE(buf) ((buf).base)
+#define MFB_CURPTR(buf) ((buf).base + (buf).pos)
+#define MFB_ENDPTR(buf) ((buf).base + (buf).level)
+
+#define MFB_SIZE(buf) ((buf).size)
+#define MFB_LEVEL(buf) ((buf).level)
+#define MFB_POS(buf) ((buf).pos)
+#define MFB_RDBYTES(buf) \
+  (MFB_LEVEL (buf) - MFB_POS (buf))
+#define MFB_FREESIZE(buf) \
+  (MFB_SIZE (buf) - MFB_LEVEL (buf))
+
+#define MBF_CLEAR(buf) ((buf).pos = (buf).level = 0)
+#define MBF_FREE(buf) free ((buf).base)
+  
+static void
+init_iobuf (struct mu_filter_io *io, struct _mu_filter_stream *fs)
+{
+  io->input = MFB_BASE (fs->inbuf);
+  io->isize = MFB_LEVEL (fs->inbuf);
+  io->output = MFB_ENDPTR (fs->outbuf);
+  io->osize = MFB_FREESIZE (fs->outbuf);
+  io->errcode = 0;
+  io->eof = 0;
+}
+
+static int
+filter_stream_init (struct _mu_filter_stream *fs)
+{
+  if (fs->xdata)
+    {
+      struct mu_filter_io iobuf;
+      memset (&iobuf, 0, sizeof (iobuf));
+      if (fs->xcode (fs->xdata, mu_filter_init, &iobuf) == mu_filter_falure)
+       return iobuf.errcode;
+    }
+  return 0;
+}
+
+static int
+MFB_require (struct _mu_filter_buffer *buf, size_t size)
+{
+  if (size > MFB_FREESIZE (*buf))
+    {
+      /* Compact the buffer */
+      if (MFB_POS (*buf))
+       {
+         memmove (MFB_BASE (*buf), MFB_CURPTR (*buf), MFB_RDBYTES (*buf));
+         buf->level -= buf->pos;
+         buf->pos = 0;
+       }
+      if (size > MFB_FREESIZE (*buf))
+       {
+         char *p;
+
+         size += MFB_LEVEL (*buf);
+         p = realloc (buf->base, size);
+         if (!p)
+           return ENOMEM;
+         buf->size = size;
+         buf->base = p;
+       }
+    }
+  return 0;
+}
+
+static void
+MFB_advance_pos (struct _mu_filter_buffer *buf, size_t delta)
+{
+  buf->pos += delta;
+  if (buf->pos == buf->level)
+    buf->pos = buf->level = 0;
+}
+
+static void
+MFB_advance_level (struct _mu_filter_buffer *buf, size_t delta)
+{
+  buf->level += delta;
+}
+
+static int
+filter_read (mu_stream_t stream, char *buf, size_t size, size_t *pret)
+{
+  struct _mu_filter_stream *fs = (struct _mu_filter_stream *)stream;
+  enum mu_filter_command cmd = mu_filter_xcode;
+  struct mu_filter_io iobuf;
+  size_t min_input_level = MU_FILTER_BUF_SIZE;
+  size_t min_output_size = MU_FILTER_BUF_SIZE;
+  size_t total = 0;
+  int stop = 0;
+  
+  while (!stop && total < size && cmd != mu_filter_lastbuf)
+    {
+      size_t rdsize;
+
+      if (MFB_RDBYTES (fs->outbuf) == 0)
+       {
+         enum mu_filter_result res;
+         int rc;
+         
+         if (MFB_RDBYTES (fs->inbuf) < min_input_level)
+           {
+             rc = MFB_require (&fs->inbuf, min_input_level);
+             if (rc)
+               return rc;
+             rc = mu_stream_read (fs->transport,
+                                  MFB_ENDPTR (fs->inbuf),
+                                  MFB_FREESIZE (fs->inbuf),
+                                  &rdsize);
+             if (rc)
+               return rc;
+             if (rdsize == 0 &&
+                 MFB_RDBYTES (fs->outbuf) == 0
+                 && MFB_RDBYTES (fs->inbuf) == 0)
+               break;
+             MFB_advance_level (&fs->inbuf, rdsize);
+           }
+
+         if (min_output_size < MFB_RDBYTES (fs->inbuf))
+           min_output_size = MFB_RDBYTES (fs->inbuf);
+         rc = MFB_require (&fs->outbuf, min_output_size);
+         if (rc)
+           return rc;
+      
+         init_iobuf (&iobuf, fs);
+
+         cmd = mu_stream_eof (fs->transport) ?
+           mu_filter_lastbuf : mu_filter_xcode;
+         res = fs->xcode (fs->xdata, cmd, &iobuf);
+         switch (res)
+           {
+           case mu_filter_ok:
+             if (iobuf.isize > MFB_RDBYTES (fs->inbuf)
+                 || iobuf.osize > MFB_FREESIZE (fs->outbuf))
+               return MU_ERR_FAILURE; /* FIXME: special error code? */
+             if (iobuf.eof)
+               {
+                 _mu_stream_seteof (stream);
+                 stop = 1;
+               }
+             break;
+         
+           case mu_filter_falure:
+             return iobuf.errcode;
+             
+           case mu_filter_moreinput:
+             min_input_level = iobuf.isize;
+             continue;
+             
+           case mu_filter_moreoutput:
+             min_output_size = iobuf.osize;
+             continue;
+           }
+      
+         /* iobuf.osize contains number of bytes written to output */
+         MFB_advance_level (&fs->outbuf, iobuf.osize);
+         
+         /* iobuf.isize contains number of bytes read from input */
+         MFB_advance_pos (&fs->inbuf, iobuf.isize);
+       }
+
+      rdsize = size - total;
+      if (rdsize > MFB_RDBYTES (fs->outbuf))
+       rdsize = MFB_RDBYTES (fs->outbuf);
+      memcpy (buf + total, MFB_CURPTR (fs->outbuf), rdsize);
+      MFB_advance_pos (&fs->outbuf, rdsize);
+      total += rdsize;
+    }
+
+  *pret = total;
+  return 0;
+}
+
+static int
+filter_rd_flush (mu_stream_t stream)
+{
+  struct _mu_filter_stream *fs = (struct _mu_filter_stream *)stream;
+  return filter_stream_init (fs);
+}
+
+static int
+filter_write_internal (mu_stream_t stream, enum mu_filter_command cmd,
+                      const char *buf, size_t size, size_t *pret)
+{
+  struct _mu_filter_stream *fs = (struct _mu_filter_stream *)stream;
+  struct mu_filter_io iobuf;
+  size_t min_input_level = cmd == mu_filter_xcode ? MU_FILTER_BUF_SIZE : 0;
+  size_t min_output_size = MU_FILTER_BUF_SIZE;
+  size_t total = 0;
+  int rc = 0;
+  
+  do
+    {
+      size_t rdsize;
+      enum mu_filter_result res;
+
+      if (MFB_RDBYTES (fs->inbuf) < min_input_level)
+       {
+         rdsize = size - total;
+         if (rdsize == 0)
+           break;
+         rc = MFB_require (&fs->inbuf, min_input_level);
+         if (rc)
+           break;
+         if (rdsize > MFB_FREESIZE (fs->inbuf))
+           rdsize = MFB_FREESIZE (fs->inbuf);
+         memcpy (MFB_ENDPTR (fs->inbuf), buf + total, rdsize);
+         MFB_advance_level (&fs->inbuf, rdsize);
+         total += rdsize;
+       }
+
+      if (min_output_size < MFB_RDBYTES (fs->inbuf))
+       min_output_size = MFB_RDBYTES (fs->inbuf);
+      rc = MFB_require (&fs->outbuf, min_output_size);
+      if (rc)
+       return rc;
+      
+      init_iobuf (&iobuf, fs);
+
+      res = fs->xcode (fs->xdata, cmd, &iobuf);
+      switch (res)
+       {
+       case mu_filter_ok:
+         if (iobuf.isize == 0 || iobuf.osize == 0)
+           {
+             /* FIXME: Hack to handle eventual buggy filters */
+             if (iobuf.isize == 0)
+               min_input_level++;
+             if (iobuf.osize == 0)
+               min_output_size++;
+             continue;
+           }
+         if (iobuf.isize > MFB_RDBYTES (fs->inbuf)
+             || iobuf.osize > MFB_FREESIZE (fs->outbuf))
+           return MU_ERR_FAILURE; /* FIXME: special error code? */
+         break;
+         
+       case mu_filter_falure:
+         return iobuf.errcode;
+         
+       case mu_filter_moreinput:
+         min_input_level = iobuf.isize;
+         continue;
+         
+       case mu_filter_moreoutput:
+         min_output_size = iobuf.osize;
+         continue;
+       }
+      
+      /* iobuf.osize contains number of bytes written to output */
+      MFB_advance_level (&fs->outbuf, iobuf.osize);
+      
+      /* iobuf.isize contains number of bytes read from input */
+      MFB_advance_pos (&fs->inbuf, iobuf.isize);
+      
+      rdsize = size - total;
+      if (rdsize > MFB_RDBYTES (fs->outbuf))
+       rdsize = MFB_RDBYTES (fs->outbuf);
+
+      rc = mu_stream_write (fs->transport,
+                           MFB_CURPTR (fs->outbuf), MFB_RDBYTES (fs->outbuf),
+                           &rdsize);
+      MFB_advance_pos (&fs->outbuf, rdsize);
+      if (rc)
+       break;
+    }
+  while (MFB_RDBYTES (fs->outbuf));
+  if (pret)
+    *pret = total;
+  else if (total < size && rc == 0)
+    rc = MU_ERR_FAILURE;
+  return rc;
+}
+
+static int
+filter_write (mu_stream_t stream, const char *buf, size_t size, size_t *pret)
+{
+  return filter_write_internal (stream, mu_filter_xcode, buf, size, pret);
+}
+
+static int
+filter_wr_flush (mu_stream_t stream)
+{
+  struct _mu_filter_stream *fs = (struct _mu_filter_stream *)stream;
+  int rc = filter_write_internal (stream, mu_filter_lastbuf, NULL, 0, NULL);
+  if (rc == 0)
+    rc = mu_stream_flush (fs->transport);
+  return rc;
+}
+
+static int
+filter_seek (struct _mu_stream *stream, mu_off_t off, mu_off_t *ppos)
+{
+  struct _mu_filter_stream *fs = (struct _mu_filter_stream *)stream;
+  int status;
+
+  status = mu_stream_seek (fs->transport, 0, MU_SEEK_SET, NULL);
+  if (status)
+    return status;
+  stream->offset = 0;
+  return mu_stream_skip_input_bytes (stream, off, ppos);
+}
+
+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;
+
+  switch (op)
+    {
+    case MU_IOCTL_GET_TRANSPORT:
+      if (!ptr)
+       return EINVAL;
+      ptrans = ptr;
+      ptrans[0] = (mu_transport_t) fs->transport;
+      ptrans[1] = NULL;
+      break;
+
+    default:
+      return mu_stream_ioctl (fs->transport, op, ptr);
+    }
+  return 0;
+}
+
+static const char *
+filter_error_string (struct _mu_stream *stream, int rc)
+{
+  struct _mu_filter_stream *fs = (struct _mu_filter_stream *)stream;
+  const char *p = mu_stream_strerror (fs->transport, rc);
+  if (!p)
+    p = mu_strerror (rc);
+  return p;
+}
+
+static void
+filter_done (mu_stream_t stream)
+{
+  struct _mu_filter_stream *fs = (struct _mu_filter_stream *)stream;
+  MBF_FREE (fs->inbuf);
+  MBF_FREE (fs->outbuf);
+  if (fs->xdata)
+    {
+      fs->xcode (fs->xdata, mu_filter_done, NULL);
+      free (fs->xdata);
+    }
+  mu_stream_destroy (&fs->transport);
+}
+
+static int
+filter_close (mu_stream_t stream)
+{
+  struct _mu_filter_stream *fs = (struct _mu_filter_stream *)stream;
+  MBF_CLEAR (fs->inbuf);
+  MBF_CLEAR (fs->outbuf);
+  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);
+}
+
+static int
+filter_wait (struct _mu_stream *stream, int *pflags, struct timeval *tvp)
+{
+  struct _mu_filter_stream *fs = (struct _mu_filter_stream *)stream;
+  /* FIXME: Take into account internal buffer state. */
+  return mu_stream_wait (fs->transport, pflags, tvp);
+}
+
+
+int
+mu_filter_stream_create (mu_stream_t *pflt,
+                        mu_stream_t str,
+                        int mode, 
+                        mu_filter_xcode_t xcode,
+                        void *xdata, int flags)
+{
+  int rc;
+  struct _mu_filter_stream *fs;
+
+  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_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);
+  if (!fs)
+    return ENOMEM;
+  
+  if (flags & MU_STREAM_READ)
+    {
+      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;
+  if (flags & MU_STREAM_SEEK)
+    fs->stream.seek = filter_seek;
+  fs->stream.ctl = filter_ctl;
+  fs->stream.wait = filter_wait;
+  fs->stream.error_string = filter_error_string;
+  fs->stream.flags = flags;
+
+  if (!(flags & MU_STREAM_AUTOCLOSE))
+    mu_stream_ref (str);
+  fs->transport = str;
+  fs->xcode = xcode;
+  fs->xdata = xdata;
+  fs->mode = mode;
+  
+  mu_stream_set_buffer ((mu_stream_t) fs, mu_buffer_full, MU_FILTER_BUF_SIZE);
+
+  rc = filter_stream_init (fs);
+  if (rc)
+    {
+      free (fs);
+      return rc;
+    }
+    
+  *pflt = (mu_stream_t) fs;
+  return 0;
+}
+
+
diff --git a/mailbox/folder.c b/mailbox/folder.c
index 432c507..3ce430a 100644
--- a/mailbox/folder.c
+++ b/mailbox/folder.c
@@ -37,7 +37,7 @@
 #include <mailutils/url.h>
 #include <mailutils/errno.h>
 
-#include <folder0.h>
+#include <mailutils/sys/folder.h>
 
 /* Internal folder list.  */
 static mu_list_t known_folder_list;
@@ -201,11 +201,11 @@ mu_folder_destroy (mu_folder_t *pfolder)
            folder->_destroy (folder);
          mu_monitor_wrlock (monitor);
          if (folder->authority)
-           mu_authority_destroy (&(folder->authority), folder);
+           mu_authority_destroy (&folder->authority, folder);
          if (folder->stream)
-           mu_stream_destroy (&(folder->stream), folder);
+           mu_stream_destroy (&folder->stream);
          if (folder->url)
-           mu_url_destroy (&(folder->url));
+           mu_url_destroy (&folder->url);
          free (folder);
        }
       mu_monitor_unlock (monitor);
@@ -238,7 +238,7 @@ mu_folder_set_stream (mu_folder_t folder, mu_stream_t 
stream)
   if (folder == NULL)
     return EINVAL;
   if (folder->stream)
-    mu_stream_destroy (&(folder->stream), folder);
+    mu_stream_destroy (&folder->stream);
   folder->stream = stream;
   return 0;
 }
@@ -246,6 +246,7 @@ mu_folder_set_stream (mu_folder_t folder, mu_stream_t 
stream)
 int
 mu_folder_get_stream (mu_folder_t folder, mu_stream_t *pstream)
 {
+  /* FIXME: Deprecation warning */
   if (folder == NULL)
     return EINVAL;
   if (pstream == NULL)
@@ -255,12 +256,22 @@ mu_folder_get_stream (mu_folder_t folder, mu_stream_t 
*pstream)
 }
 
 int
+mu_folder_get_streamref (mu_folder_t folder, mu_stream_t *pstream)
+{
+  if (folder == NULL)
+    return EINVAL;
+  if (pstream == NULL)
+    return MU_ERR_OUT_PTR_NULL;
+  return mu_streamref_create (pstream, folder->stream);
+}
+
+int
 mu_folder_set_authority (mu_folder_t folder, mu_authority_t authority)
 {
   if (folder == NULL)
     return EINVAL;
   if (folder->authority)
-    mu_authority_destroy (&(folder->authority), folder);
+    mu_authority_destroy (&folder->authority, folder);
   folder->authority = authority;
   return 0;
 }
@@ -286,7 +297,7 @@ mu_folder_get_observable (mu_folder_t folder, 
mu_observable_t *pobservable)
 
   if (folder->observable == NULL)
     {
-      int status = mu_observable_create (&(folder->observable), folder);
+      int status = mu_observable_create (&folder->observable, folder);
       if (status != 0)
         return status;
     }
@@ -329,7 +340,7 @@ mu_folder_set_debug (mu_folder_t folder, mu_debug_t debug)
   if (folder == NULL)
     return EINVAL;
   if (folder->debug)
-    mu_debug_destroy (&(folder->debug), folder);
+    mu_debug_destroy (&folder->debug, folder);
   folder->debug = debug;
   return 0;
 }
@@ -343,7 +354,7 @@ mu_folder_get_debug (mu_folder_t folder, mu_debug_t *pdebug)
     return MU_ERR_OUT_PTR_NULL;
   if (folder->debug == NULL)
     {
-      int status = mu_debug_create (&(folder->debug), folder);
+      int status = mu_debug_create (&folder->debug, folder);
       if (status != 0)
         return status;
     }
diff --git a/mailbox/hdritr.c b/mailbox/hdritr.c
index 28fac2e..595735f 100644
--- a/mailbox/hdritr.c
+++ b/mailbox/hdritr.c
@@ -24,7 +24,7 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include <header0.h>
+#include <mailutils/sys/header.h>
 #include <mailutils/errno.h>
 
 struct header_iterator
diff --git a/mailbox/header.c b/mailbox/header.c
index 81cc5b3..f49ea86 100644
--- a/mailbox/header.c
+++ b/mailbox/header.c
@@ -46,8 +46,8 @@
 #include <mailutils/mutil.h>
 #include <mailutils/errno.h>
 #include <mailutils/cstr.h>
-
-#include <header0.h>
+#include <mailutils/sys/header_stream.h>
+#include <mailutils/sys/header.h>
 
 #define HEADER_MODIFIED   0x01
 #define HEADER_INVALIDATE 0x02
@@ -329,7 +329,7 @@ header_parse (mu_header_t header, const char *blurb, int 
len)
        *[ (' ' | '\t') field-value '\r' '\n' ]
   */
   /* First loop goes through the blurb */
-  for (header_start = blurb;  ; header_start = ++header_end)
+  for (header_start = blurb; len > 0; header_start = ++header_end)
     {
       const char *fn, *fn_end, *fv, *fv_end;
       struct mu_hdrent *ent;
@@ -340,7 +340,7 @@ header_parse (mu_header_t header, const char *blurb, int 
len)
        break;
 
       /* Second loop extract one header field. */
-      for (header_start2 = header_start;  ;header_start2 = ++header_end)
+      for (header_start2 = header_start; len; header_start2 = ++header_end)
        {
          header_end = memchr (header_start2, '\n', len);
          if (header_end == NULL)
@@ -348,21 +348,14 @@ header_parse (mu_header_t header, const char *blurb, int 
len)
          else
            {
              len -= (header_end - header_start2 + 1);
-             if (len < 0)
-               {
-                 header_end = NULL;
-                 break;
-               }
-             if (header_end[1] != ' '
-                 && header_end[1] != '\t')
+             if (!len
+                 || (header_end[1] != ' '
+                     && header_end[1] != '\t'))
                break; /* New header break the inner for. */
            }
          /* *header_end = ' ';  smash LF ? NO */
        }
 
-      if (header_end == NULL)
-       break; /* FIXME: Bail out.  */
-      
       /* Now save the header in the data structure.  */
 
       /* Treats unix "From " specially.  FIXME: Should we? */
@@ -413,11 +406,8 @@ static int
 mu_header_fill (mu_header_t header)
 {
   int status;
-  char buf[1024];
-  size_t nread;
-  mu_stream_t mstream;
-  size_t stream_len;
-  char *blurb;
+  size_t blurb_len = 0;
+  char *blurb = NULL;
   
   if (header->spool_used)
     return 0;
@@ -425,59 +415,19 @@ mu_header_fill (mu_header_t header)
   if (header->_fill == NULL)
     return 0; /* FIXME: Really? */
 
-  status = mu_memory_stream_create (&mstream, NULL, MU_STREAM_RDWR);
-  if (status != 0)
-    return status;
-  mu_stream_open (mstream);
-  stream_len = 0;
-
   /* Bring in the entire header.  */
-  do
-    {
-      nread = 0;
-      status = header->_fill (header, buf, sizeof buf,
-                             stream_len, &nread);
-      if (status)
-       {
-         if (status != EAGAIN && status != EINTR)
-           mu_stream_destroy (&mstream, NULL);
-         return status;
-       }
-      if (nread > 0)
-       {
-         status = mu_stream_write (mstream, buf, nread, stream_len, NULL);
-         if (status)
-           {
-             mu_stream_destroy (&mstream, NULL);
-             return status;
-           }
-         stream_len += nread;
-       }
-    }
-  while (nread > 0);
-
-  /* parse it. */
-  blurb = calloc (1, stream_len + 1);
-  if (blurb)
-    {
-      size_t len;
-      
-      status = mu_stream_read (mstream, blurb, stream_len, 0, &len);
-      if (status == 0)
-       status = header_parse (header, blurb, len);
-      free (blurb);
-    }
-  else
-    status = ENOMEM;
-  
-  mu_stream_destroy (&mstream, NULL);
+  status = header->_fill (header->data, &blurb, &blurb_len);
+  if (status)
+    return status;
+  status = header_parse (header, blurb, blurb_len);
+  free (blurb);
   return status;
 }
 
 
 
 int
-mu_header_create (mu_header_t *ph, const char *blurb, size_t len, void *owner)
+mu_header_create (mu_header_t *ph, const char *blurb, size_t len)
 {
   mu_header_t header;
   int status = 0;
@@ -486,8 +436,6 @@ mu_header_create (mu_header_t *ph, const char *blurb, 
size_t len, void *owner)
   if (header == NULL)
     return ENOMEM;
   
-  header->owner = owner;
-
   status = header_parse (header, blurb, len);
 
   *ph = header;
@@ -495,21 +443,17 @@ mu_header_create (mu_header_t *ph, const char *blurb, 
size_t len, void *owner)
 }
 
 void
-mu_header_destroy (mu_header_t *ph, void *owner)
+mu_header_destroy (mu_header_t *ph)
 {
   if (ph && *ph)
     {  
       mu_header_t header = *ph;
 
-      if (header->owner == owner)
-       {
-         mu_stream_destroy (&header->stream, header);
-         mu_hdrent_free_list (header);
-         free (header->spool);
-
-         free (header);
-         *ph = NULL;
-       }
+      mu_stream_destroy (&header->stream);
+      mu_hdrent_free_list (header);
+      free (header->spool);
+      free (header);
+      *ph = NULL;
     }
 }
 
@@ -706,7 +650,7 @@ mu_header_aget_value_n (mu_header_t header,
 
 int
 mu_header_get_value_n (mu_header_t header, const char *name, int n,
-                    char *buffer, size_t buflen, size_t *pn)
+                      char *buffer, size_t buflen, size_t *pn)
 {
   const char *s;
   int status = mu_header_sget_value_n (header, name, n, &s);
@@ -967,6 +911,15 @@ mu_header_size (mu_header_t header, size_t *psize)
   return status;
 }
 
+int
+mu_header_invalidate (mu_header_t hdr)
+{
+  if (hdr == NULL)
+    return EINVAL;
+  mu_hdrent_free_list (hdr);
+  return 0;
+}
+
 
 static void
 mu_hdrent_fixup (mu_header_t hdr, struct mu_hdrent *ent)
@@ -986,10 +939,28 @@ mu_hdrent_unroll_fixup (mu_header_t hdr, struct mu_hdrent 
*ent)
   s[ent->vlen] = 0;
 }
 
+int
+header_seek (mu_stream_t str, mu_off_t off, mu_off_t *presult)
+{ 
+  struct _mu_header_stream *hstr = (struct _mu_header_stream *) str;
+  size_t size;
+  int status;
+    
+  status = mu_header_size (hstr->hdr, &size);
+  if (status)
+    return status;
+  
+  if (off < 0 || off > size)
+    return ESPIPE;
+  hstr->off = off;
+  *presult = off;
+  return 0;
+}
+
 static int
-header_read (mu_stream_t is, char *buffer, size_t buflen,
-            mu_off_t off, size_t *pnread)
+header_read (mu_stream_t is, char *buffer, size_t buflen, size_t *pnread)
 {
+  struct _mu_header_stream *hstr = (struct _mu_header_stream *) is;
   mu_header_t header;
   struct mu_hdrent *ent;
   size_t ent_off;
@@ -999,12 +970,12 @@ header_read (mu_stream_t is, char *buffer, size_t buflen,
   if (is == NULL)
     return EINVAL;
 
-  header = mu_stream_get_owner (is);
+  header = hstr->hdr;
   status = mu_header_fill (header);
   if (status)
     return status;
   
-  if (mu_hdrent_find_stream_pos (header, off, &ent, &ent_off))
+  if (mu_hdrent_find_stream_pos (header, hstr->off, &ent, &ent_off))
     {
       if (pnread)
        *pnread = 0;
@@ -1021,7 +992,7 @@ header_read (mu_stream_t is, char *buffer, size_t buflen,
       memcpy (buffer + nread, MU_HDRENT_NAME (header, ent) + ent_off, rest);
       mu_hdrent_unroll_fixup (header, ent);
       nread += rest;
-      off += rest;
+      hstr->off += rest;
       ent_off = 0;
     }
   if (pnread)
@@ -1029,25 +1000,27 @@ header_read (mu_stream_t is, char *buffer, size_t 
buflen,
   return 0;
 }
 
+#if 0
+/* FIXME: Implement header_readdelim based on this: */
 static int
-header_readline (mu_stream_t is, char *buffer, size_t buflen,
-                mu_off_t off, size_t *pnread)
+_header_readline (mu_stream_t is, char *buffer, size_t buflen, size_t *pnread)
 {
-  mu_header_t header;
+  struct _mu_header_stream *hstr = (struct _mu_header_stream *) is;
+  mu_header_t header = hstr->hdr;
   struct mu_hdrent *ent;
   size_t ent_off;
   int status;
   size_t strsize;
   char *start, *end;
-  
-  if (is == NULL || buflen == 0)
+
+  if (buflen == 0)
     return EINVAL;
 
   header = mu_stream_get_owner (is);
   status = mu_header_fill (header);
   if (status)
     return status;
-  if (mu_hdrent_find_stream_pos (header, off, &ent, &ent_off))
+  if (mu_hdrent_find_stream_pos (header, hstr->off, &ent, &ent_off))
     {
       if (pnread)
        *pnread = 0;
@@ -1069,31 +1042,35 @@ header_readline (mu_stream_t is, char *buffer, size_t 
buflen,
 
   if (strsize < buflen)
     buflen = strsize;
-  
+
   memcpy (buffer, start, buflen);
   buffer[buflen] = 0;
+  hstr->off += buflen;
   mu_hdrent_unroll_fixup (header, ent);
   if (pnread)
     *pnread = buflen;
   return 0;
 }
+#endif
 
 static int
-header_write (mu_stream_t os, const char *buf, size_t buflen,
-             mu_off_t off, size_t *pnwrite)
+header_write (mu_stream_t os, const char *buf, size_t buflen, size_t *pnwrite)
 {
-  size_t wrsize = 0;
-  mu_header_t header = mu_stream_get_owner (os);
+  struct _mu_header_stream *hstr;
+  mu_header_t header;
   int status;
+  mu_off_t mstream_size;
   
-  if (header == NULL)
+  if (!os || !buf)
     return EINVAL;
 
-  if ((size_t)off != header->mstream_size)
-    return ESPIPE;
-
+  hstr = (struct _mu_header_stream *) os;
+  header = hstr->hdr;
+  if (header == NULL)
+    return EINVAL;
+  
   /* Skip the obvious.  */
-  if (buf == NULL || *buf == '\0' || buflen == 0)
+  if (*buf == '\0' || buflen == 0)
     {
       if (pnwrite)
         *pnwrite = 0;
@@ -1102,63 +1079,51 @@ header_write (mu_stream_t os, const char *buf, size_t 
buflen,
 
   if (!header->mstream)
     {
-      status = mu_memory_stream_create (&header->mstream, NULL,
-                                       MU_STREAM_RDWR);
+      status = mu_memory_stream_create (&header->mstream, MU_STREAM_RDWR);
       if (status)
        return status;
       status = mu_stream_open (header->mstream);
       if (status)
        {
-         mu_stream_destroy (&header->mstream, NULL);
+         mu_stream_destroy (&header->mstream);
          return status;
        }
-      header->mstream_size = 0;
     }
 
-  do
+  status = mu_stream_write (header->mstream, buf, buflen, NULL);
+  if (status)
     {
-      size_t nbytes;
-      status = mu_stream_write (header->mstream, buf + wrsize, buflen - wrsize,
-                               header->mstream_size, &nbytes);
-      if (status)
-       {
-         mu_stream_destroy (&header->mstream, NULL);
-         header->mstream_size = 0;
-         return status;
-       }
-      if (nbytes == 0)
-       break;
-      wrsize += nbytes;
-      header->mstream_size += nbytes;
+      mu_stream_destroy (&header->mstream);
+      return status;
     }
-  while (buflen);
 
-  if (header->mstream_size > 1)
+  status = mu_stream_size (header->mstream, &mstream_size);
+  if (status == 0 && mstream_size > 1)
     {
       char nlbuf[2];
-      size_t len;
-      status = mu_stream_read (header->mstream, nlbuf, 2,
-                              header->mstream_size - 2, &len);
-      if (status == 0 && len == 2 && memcmp (nlbuf, "\n\n", 2) == 0)
+
+      status = mu_stream_seek (header->mstream, -2, MU_SEEK_END, NULL);
+      if (status == 0)
+       status = mu_stream_read (header->mstream, nlbuf, 2, NULL);
+      if (status == 0 && memcmp (nlbuf, "\n\n", 2) == 0)
        {
          char *blurb;
-         size_t len = header->mstream_size;
-         blurb = calloc (1, len + 1);
+
+         blurb = calloc (1, mstream_size + 1);
          if (blurb)
            {
-             mu_stream_read (header->mstream, blurb, len, 0, &len);
-             status = header_parse (header, blurb, len);
+             mu_stream_read (header->mstream, blurb, mstream_size, NULL);
+             status = header_parse (header, blurb, mstream_size);
            }
          free (blurb);
-         mu_stream_destroy (&header->mstream, NULL);
-         header->mstream_size = 0;
+         mu_stream_destroy (&header->mstream);
        }
     }
   
   if (pnwrite)
-    *pnwrite = wrsize;
+    *pnwrite = buflen;
   
-  return 0;
+  return status;
 }
 
 static int
@@ -1173,7 +1138,7 @@ header_size (mu_stream_t str, mu_off_t *psize)
   if (psize == NULL)
     return MU_ERR_OUT_PTR_NULL;
   
-  header = mu_stream_get_owner (str);
+  header = ((struct _mu_header_stream *) str)->hdr;
   status = mu_header_fill (header);
   if (status)
     return status;
@@ -1183,8 +1148,8 @@ header_size (mu_stream_t str, mu_off_t *psize)
   return status;
 }
 
-int
-mu_header_get_stream (mu_header_t header, mu_stream_t *pstream)
+static int
+_header_get_stream (mu_header_t header, mu_stream_t *pstream, int ref)
 {
   if (header == NULL)
     return EINVAL;
@@ -1194,44 +1159,58 @@ mu_header_get_stream (mu_header_t header, mu_stream_t 
*pstream)
 
   if (header->stream == NULL)
     {
-      int status = mu_stream_create (&header->stream, MU_STREAM_RDWR, header);
-      if (status != 0)
-       return status;
-      mu_stream_set_read (header->stream, header_read, header);
-      mu_stream_set_readline (header->stream, header_readline, header);
-      mu_stream_set_write (header->stream, header_write, header);
-      mu_stream_set_size (header->stream, header_size, header);
+      struct _mu_header_stream *str = 
+       (struct _mu_header_stream *) _mu_stream_create (sizeof (*str),
+                                                       
MU_STREAM_RDWR|MU_STREAM_SEEK);
+      if (!str)
+       return ENOMEM;
+      str->stream.read = header_read;
+      /*str->stream.rdelim? */
+      str->stream.write = header_write;
+      str->stream.seek = header_seek;
+      str->stream.size = header_size;
+      str->hdr = header;
+      header->stream = (mu_stream_t) str;
     }
-  *pstream = header->stream;
-  return 0;
+  if (!ref)
+    {
+      *pstream = header->stream;
+      return 0;
+    }
+  return mu_streamref_create (pstream, header->stream);
 }
 
+int
+mu_header_get_stream (mu_header_t header, mu_stream_t *pstream)
+{
+  /* FIXME: Deprecation warning */
+  return _header_get_stream (header, pstream, 0);
+}
+
+int
+mu_header_get_streamref (mu_header_t header, mu_stream_t *pstream)
+{
+  return _header_get_stream (header, pstream, 1);
+}
 
 
 int
 mu_header_set_fill (mu_header_t header, int
-                   (*_fill) (mu_header_t, char *, size_t, mu_off_t, size_t *),
-                   void *owner)
+                   (*_fill) (void *data, char **, size_t *),
+                   void *data)
 {
   if (header == NULL)
     return EINVAL;
-  if (header->owner != owner)
-    return EACCES;
   header->_fill = _fill;
+  header->data = data;
   return 0;
 }
 
 
-void *
-mu_header_get_owner (mu_header_t header)
-{
-  return (header) ? header->owner : NULL;
-}
-
 int
 mu_header_is_modified (mu_header_t header)
 {
-  return (header) ? (header->flags & HEADER_MODIFIED) : 0;
+  return header ? (header->flags & HEADER_MODIFIED) : 0;
 }
 
 int
diff --git a/mailbox/iostream.c b/mailbox/iostream.c
new file mode 100644
index 0000000..4267a81
--- /dev/null
+++ b/mailbox/iostream.c
@@ -0,0 +1,248 @@
+/* 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;
+  mu_stream_close (sp->transport[_MU_STREAM_INPUT]);
+  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]);
+  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;
+
+    case MU_IOCTL_SWAP_STREAM:
+      if (!arg)
+       return EINVAL;
+      return _mu_stream_swap_streams (str, sp->transport, arg, 0);
+      
+    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)
+{
+  struct _mu_iostream *sp;
+
+  sp = (struct _mu_iostream *)
+    _mu_stream_create (sizeof (*sp),
+                      MU_STREAM_READ | MU_STREAM_WRITE);
+  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/iterator.c b/mailbox/iterator.c
index aba94ab..3897925 100644
--- a/mailbox/iterator.c
+++ b/mailbox/iterator.c
@@ -24,8 +24,8 @@
 #include <errno.h>
 #include <stdlib.h>
 
-#include <list0.h>
-#include <iterator0.h>
+#include <mailutils/sys/list.h>
+#include <mailutils/sys/iterator.h>
 #include <mailutils/errno.h>
 
 int
diff --git a/mailbox/linelenflt.c b/mailbox/linelenflt.c
new file mode 100644
index 0000000..e3817de
--- /dev/null
+++ b/mailbox/linelenflt.c
@@ -0,0 +1,110 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 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 <mailutils/errno.h>
+#include <mailutils/filter.h>
+
+struct _mu_linelen_filter
+{
+  size_t max_len;
+  size_t cur_len;
+};
+
+static enum mu_filter_result
+_ll_encoder (void *xd,
+            enum mu_filter_command cmd,
+            struct mu_filter_io *iobuf)
+{
+  struct _mu_linelen_filter *flt = xd;
+  const char *iptr;
+  size_t isize;
+  char *optr;
+  size_t osize;
+  size_t consumed, written;
+  
+  switch (cmd)
+    {
+    case mu_filter_init:
+      flt->cur_len = 0;
+    case mu_filter_done:
+      return mu_filter_ok;
+    default:
+      break;
+    }
+
+  iptr = iobuf->input;
+  isize = iobuf->isize;
+  optr = iobuf->output;
+  osize = iobuf->osize;
+
+  for (consumed = written = 0; consumed < isize && written < osize; )
+    {
+      char *p;
+      size_t rest = flt->max_len - flt->cur_len;
+      size_t len = isize - consumed;
+
+      if (len > rest)
+       len = rest;
+      
+      p = memchr (iptr + consumed, '\n', len);
+      if (p)
+       len = p - iptr - consumed + 1;
+      
+      rest = osize - written;
+      if (len > rest)
+       {
+         len = rest;
+         p = NULL;
+       }
+      memcpy (optr + written, iptr + consumed, len);      
+      written += len;
+      consumed += len;
+      if (p)
+       flt->cur_len = 0;
+      else
+       {
+         flt->cur_len += len;
+         if (flt->cur_len == flt->max_len)
+           {
+             if (written < osize)
+               optr[written++] = '\n';
+             flt->cur_len = 0;
+           }
+       }
+    }
+  iobuf->isize = consumed;
+  iobuf->osize = written;
+  return mu_filter_ok;
+}
+
+int
+mu_linelen_filter_create (mu_stream_t *pstream, mu_stream_t stream,
+                         size_t limit,
+                         int flags)
+{
+  struct _mu_linelen_filter *flt = calloc (1, sizeof (*flt));
+  if (!flt)
+    return ENOMEM;
+  flt->max_len = limit;
+  return mu_filter_stream_create (pstream, stream,
+                                 MU_FILTER_ENCODE, _ll_encoder, flt, flags);
+}
+  
diff --git a/mailbox/list.c b/mailbox/list.c
index f47af25..91f6a6e 100644
--- a/mailbox/list.c
+++ b/mailbox/list.c
@@ -25,8 +25,8 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include <list0.h>
-#include <iterator0.h>
+#include <mailutils/sys/list.h>
+#include <mailutils/sys/iterator.h>
 #include <mailutils/errno.h>
 
 #define DESTROY_ITEM(list, elt)                        \
diff --git a/mailbox/listlist.c b/mailbox/listlist.c
index 060c724..94172ac 100644
--- a/mailbox/listlist.c
+++ b/mailbox/listlist.c
@@ -25,8 +25,8 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include <list0.h>
-#include <iterator0.h>
+#include <mailutils/sys/list.h>
+#include <mailutils/sys/iterator.h>
 #include <mailutils/errno.h>
 
 void
diff --git a/mailbox/mailbox.c b/mailbox/mailbox.c
index b06fe3d..e7c0dcc 100644
--- a/mailbox/mailbox.c
+++ b/mailbox/mailbox.c
@@ -41,8 +41,8 @@
 #include <mailutils/message.h>
 #include <mailutils/mutil.h>
 
-#include <mailbox0.h>
-#include <url0.h>
+#include <mailutils/sys/mailbox.h>
+#include <mailutils/sys/url.h>
 
 static int
 mailbox_folder_create (mu_mailbox_t mbox, const char *name,
@@ -230,7 +230,7 @@ mu_mailbox_destroy (mu_mailbox_t *pmbox)
          /* FIXME: Is this right, should the client be responsible
             for closing the stream?  */
          /* mu_stream_close (mbox->stream); */
-         mu_stream_destroy (&mbox->stream, mbox);
+         mu_stream_destroy (&mbox->stream);
        }
 
       if (mbox->url)
@@ -522,7 +522,7 @@ mu_mailbox_set_stream (mu_mailbox_t mbox, mu_stream_t 
stream)
   if (mbox->flags & MU_STREAM_QACCESS)
     return MU_ERR_BADOP;
   if (mbox->stream)
-    mu_stream_destroy (&mbox->stream, mbox);
+    mu_stream_destroy (&mbox->stream);
   mbox->stream = stream;
   return 0;
 }
@@ -538,6 +538,7 @@ mu_mailbox_set_stream (mu_mailbox_t mbox, mu_stream_t 
stream)
 int
 mu_mailbox_get_stream (mu_mailbox_t mbox, mu_stream_t *pstream)
 {
+  /* FIXME: Deprecation warning */
   if (mbox == NULL)
     return MU_ERR_MBX_NULL;
   if (pstream == NULL)
@@ -556,6 +557,25 @@ mu_mailbox_get_stream (mu_mailbox_t mbox, mu_stream_t 
*pstream)
 }
 
 int
+mu_mailbox_get_streamref (mu_mailbox_t mbox, mu_stream_t *pstream)
+{
+  if (mbox == NULL)
+    return MU_ERR_MBX_NULL;
+  if (pstream == NULL)
+    return MU_ERR_OUT_PTR_NULL;
+
+  /* If null two cases:
+     - it is no open yet.
+     - it a remote stream and the socket stream is on the folder.  */
+  if (mbox->stream == NULL)
+    {
+      if (mbox->folder)
+       return mu_folder_get_streamref (mbox->folder, pstream);
+    }
+  return mu_streamref_create (pstream, mbox->stream);
+}
+
+int
 mu_mailbox_get_observable (mu_mailbox_t mbox, mu_observable_t *pobservable)
 {
   if (mbox == NULL)
diff --git a/mailbox/mailcap.c b/mailbox/mailcap.c
index 70f3427..d9e96f2 100644
--- a/mailbox/mailcap.c
+++ b/mailbox/mailcap.c
@@ -506,14 +506,13 @@ application/pgp; gpg < %s | metamail; needsterminal; \
 static int
 mu_mailcap_parse (mu_mailcap_t mailcap, mu_stream_t stream)
 {
-  off_t off;
   int status;
   size_t n;
   char *previous;
   char *buffer;
-  int buflen = 512;
+  size_t buflen = 512;
 
-  buffer = malloc (buflen * sizeof (*buffer));
+  buffer = malloc (buflen);
   if (buffer == NULL)
     {
       return ENOMEM;
@@ -529,10 +528,12 @@ mu_mailcap_parse (mu_mailcap_t mailcap, mu_stream_t 
stream)
    * The old continuation line is saved in the "previous" pointer and
    * prepended to the buffer.
    */
-  for (previous = NULL, off = n = 0;
-       (status = mu_stream_readline (stream, buffer, buflen, off, &n)) == 0
-        && n > 0;
-       off += n)
+  status = mu_stream_seek (stream, 0, MU_SEEK_SET, NULL);
+  if (status)
+    return status;
+  previous = NULL;
+  while ((status = mu_stream_readline (stream, buffer, buflen, &n)) == 0
+        && n > 0)
     {
       int len;
 
@@ -667,10 +668,11 @@ int main()
   mu_stream_t stream = NULL;
   int status = 0;
 
-  status = mu_file_stream_create (&stream, "/home/alain/mailcap", 
MU_STREAM_READ);
+  status = mu_file_stream_create (&stream, "/home/alain/mailcap",
+                                 MU_STREAM_READ);
   if (status == 0)
     {
-      status = mu_stream_open(stream);
+      status = mu_stream_open (stream);
       if (status == 0)
        {
          mu_mailcap_t mailcap;
diff --git a/mailbox/mailer.c b/mailbox/mailer.c
index f2786c8..2240b65 100644
--- a/mailbox/mailer.c
+++ b/mailbox/mailer.c
@@ -50,7 +50,7 @@
 #include <mailutils/mime.h>
 #include <mailutils/io.h>
 
-#include <mailer0.h>
+#include <mailutils/sys/mailer.h>
 
 static char *mailer_url_default;
 
@@ -201,7 +201,7 @@ mu_mailer_destroy (mu_mailer_t * pmailer)
        {
          /* FIXME: Should be the client responsability to close this?  */
          /* mu_stream_close (mailer->stream); */
-         mu_stream_destroy (&(mailer->stream), mailer);
+         mu_stream_destroy (&mailer->stream);
        }
 
       if (mailer->url)
@@ -422,24 +422,26 @@ create_part (mu_mime_t mime, mu_stream_t istr,
   free (str);
   
   mu_message_get_body (newmsg, &body);
-  mu_body_get_stream (body, &ostr);
+  mu_body_get_streamref (body, &ostr);
 
-  mu_stream_seek (ostr, 0, SEEK_SET);
-
-  while (fragsize)
-    {
-      size_t rds = fragsize;
-      if (rds > sizeof buffer)
-       rds = sizeof buffer;
-      
-      status = mu_stream_sequential_read (istr, buffer, rds, &rds);
-      if (status || rds == 0)
-       break;
-      status = mu_stream_sequential_write (ostr, buffer, rds);
-      if (status)
-       break;
-      fragsize -= rds;
-    }
+  status = mu_stream_seek (ostr, 0, SEEK_SET, NULL);
+  if (status == 0)
+    while (fragsize)
+      {
+       size_t rds = fragsize;
+       if (rds > sizeof buffer)
+         rds = sizeof buffer;
+       
+       status = mu_stream_read (istr, buffer, rds, &rds);
+       if (status || rds == 0)
+         break;
+       status = mu_stream_write (ostr, buffer, rds, NULL);
+       if (status)
+         break;
+       fragsize -= rds;
+      }
+  mu_stream_destroy (&ostr);
+  
   if (status == 0)
     {
       mu_mime_add_part (mime, newmsg);
@@ -570,10 +572,13 @@ mu_mailer_send_fragments (mu_mailer_t mailer,
          else
            {
              mu_stream_t str;
-             mu_body_get_stream (body, &str);
-             
-             status = send_fragments (mailer, hdr, str, nparts, fragsize,
-                                      delay, from, to);
+             status = mu_body_get_streamref (body, &str);
+             if (status)
+               {
+                 status = send_fragments (mailer, hdr, str, nparts,
+                                          fragsize, delay, from, to);
+                 mu_stream_destroy (&str);
+               }
            }
        }
     }
@@ -600,6 +605,7 @@ mu_mailer_set_stream (mu_mailer_t mailer, mu_stream_t 
stream)
 int
 mu_mailer_get_stream (mu_mailer_t mailer, mu_stream_t * pstream)
 {
+  /* FIXME: Deprecation warning */
   if (mailer == NULL)
     return EINVAL;
   if (pstream == NULL)
@@ -609,6 +615,16 @@ mu_mailer_get_stream (mu_mailer_t mailer, mu_stream_t * 
pstream)
 }
 
 int
+mu_mailer_get_streamref (mu_mailer_t mailer, mu_stream_t * pstream)
+{
+  if (mailer == NULL)
+    return EINVAL;
+  if (pstream == NULL)
+    return MU_ERR_OUT_PTR_NULL;
+  return mu_streamref_create (pstream, mailer->stream);
+}
+
+int
 mu_mailer_get_observable (mu_mailer_t mailer, mu_observable_t * pobservable)
 {
   /* FIXME: I should check for invalid types */
diff --git a/mailbox/mapfile_stream.c b/mailbox/mapfile_stream.c
index e70d701..aeb85e5 100644
--- a/mailbox/mapfile_stream.c
+++ b/mailbox/mapfile_stream.c
@@ -1,38 +1,36 @@
 /* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 1999, 2000, 2001, 2004, 2007, 2010 Free Software
-   Foundation, Inc.
+   Copyright (C) 1999, 2000, 2001, 2004, 2007,
+   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 of the License, or (at your option) any later version.
+   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.
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU Lesser General
-   Public License along with this library; if not, write to the
-   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301 USA */
+   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 <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
 #include <string.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
+#include <stdlib.h>
 #include <unistd.h>
+#include <fcntl.h>
 
-#include <mailutils/stream.h>
+#include <mailutils/types.h>
+#include <mailutils/alloc.h>
+#include <mailutils/error.h>
 #include <mailutils/errno.h>
+#include <mailutils/nls.h>
+#include <mailutils/stream.h>
+#include <mailutils/sys/stream.h>
+#include <mailutils/sys/mapfile_stream.h>
 
 #ifdef _POSIX_MAPPED_FILES
 #include <sys/mman.h>
@@ -41,19 +39,10 @@
 # define MAP_FAILED (void*)-1
 #endif
 
-struct _mapfile_stream
-{
-  int fd;
-  int flags;
-  char *ptr;
-  size_t size;
-  char* filename;
-};
-
 static void
-_mapfile_destroy (mu_stream_t stream)
+_mapfile_done (mu_stream_t stream)
 {
-  struct _mapfile_stream *mfs = mu_stream_get_owner (stream);
+  struct _mu_mapfile_stream *mfs = (struct _mu_mapfile_stream *)stream;
 
   if (mfs->ptr != MAP_FAILED)
     {
@@ -62,23 +51,24 @@ _mapfile_destroy (mu_stream_t stream)
       close (mfs->fd);
     }
   free (mfs->filename);
-  free (mfs);
 }
 
 static int
 _mapfile_read (mu_stream_t stream, char *optr, size_t osize,
-              mu_off_t offset, size_t *nbytes)
+              size_t *nbytes)
 {
-  struct _mapfile_stream *mfs = mu_stream_get_owner (stream);
+  struct _mu_mapfile_stream *mfs = (struct _mu_mapfile_stream *) stream;
   size_t n = 0;
 
   if (mfs->ptr == MAP_FAILED)
     return EINVAL;
 
-  if (offset < (mu_off_t)mfs->size)
+  if (mfs->offset < (mu_off_t) mfs->size)
     {
-      n = ((offset + osize) > mfs->size) ? mfs->size - offset :  osize;
-      memcpy (optr, mfs->ptr + offset, n);
+      n = ((mfs->offset + osize) > mfs->size) ?
+           mfs->size - mfs->offset : osize;
+      memcpy (optr, mfs->ptr + mfs->offset, n);
+      mfs->offset += n;
     }
 
   if (nbytes)
@@ -87,46 +77,18 @@ _mapfile_read (mu_stream_t stream, char *optr, size_t osize,
 }
 
 static int
-_mapfile_readline (mu_stream_t stream, char *optr, size_t osize,
-               mu_off_t offset, size_t *nbytes)
-{
-  struct _mapfile_stream *mfs = mu_stream_get_owner (stream);
-  char *nl;
-  size_t n = 0;
-
-  if (mfs->ptr == MAP_FAILED)
-    return EINVAL;
-
-  if (offset < (mu_off_t)mfs->size)
-    {
-      /* Save space for the null byte.  */
-      osize--;
-      nl = memchr (mfs->ptr + offset, '\n', mfs->size - offset);
-      n = (nl) ? (size_t)(nl - (mfs->ptr + offset) + 1) : mfs->size - offset;
-      n = (n > osize)  ? osize : n;
-      memcpy (optr, mfs->ptr + offset, n);
-      optr[n] = '\0';
-    }
-  if (nbytes)
-    *nbytes = n;
-  return 0;
-}
-
-static int
 _mapfile_write (mu_stream_t stream, const char *iptr, size_t isize,
-           mu_off_t offset, size_t *nbytes)
+               size_t *nbytes)
 {
-  struct _mapfile_stream *mfs = mu_stream_get_owner (stream);
+  struct _mu_mapfile_stream *mfs = (struct _mu_mapfile_stream *) stream;
 
   if (mfs->ptr == MAP_FAILED)
     return EINVAL;
 
-  if (! (mfs->flags & PROT_WRITE))
+  if (!(mfs->flags & PROT_WRITE))
     return EACCES;
 
-  /* Not recommanded, really.  */
-  /* Bigger we have to remmap.  */
-  if (mfs->size < (offset + isize))
+  if (mfs->size < (mfs->offset + isize))
     {
       if (mfs->ptr && munmap (mfs->ptr, mfs->size) != 0)
        {
@@ -135,20 +97,25 @@ _mapfile_write (mu_stream_t stream, const char *iptr, 
size_t isize,
          close (mfs->fd);
          return err;
        }
-      if (ftruncate (mfs->fd, offset + isize) != 0)
+      if (ftruncate (mfs->fd, mfs->offset + isize) != 0)
        return errno;
-      mfs->ptr = mmap (0, offset + isize, mfs->flags, MAP_SHARED, mfs->fd, 0);
+      mfs->ptr = mmap (0, mfs->offset + isize, mfs->flags,
+                      MAP_SHARED, mfs->fd, 0);
       if (mfs->ptr == MAP_FAILED)
        {
          int err = errno;
          close (mfs->fd);
          return err;
        }
-      mfs->size = offset + isize;
+      mfs->size = mfs->offset + isize;
     }
 
   if (isize)
-    memcpy (mfs->ptr + offset, iptr, isize);
+    {
+      memcpy (mfs->ptr + mfs->offset, iptr, isize);
+      mfs->offset += isize;
+    }
+  
   if (nbytes)
     *nbytes = isize;
   return 0;
@@ -157,7 +124,8 @@ _mapfile_write (mu_stream_t stream, const char *iptr, 
size_t isize,
 static int
 _mapfile_truncate (mu_stream_t stream, mu_off_t len)
 {
-  struct _mapfile_stream *mfs = mu_stream_get_owner (stream);
+  struct _mu_mapfile_stream *mfs = (struct _mu_mapfile_stream *) stream;
+  
   if (mfs->ptr == MAP_FAILED)
     return EINVAL;
   /* Remap.  */
@@ -170,7 +138,7 @@ _mapfile_truncate (mu_stream_t stream, mu_off_t len)
     }
   if (ftruncate (mfs->fd, len) != 0)
     return errno;
-   mfs->ptr = (len) ? mmap (0, len, mfs->flags, MAP_SHARED, mfs->fd, 0) : NULL;
+   mfs->ptr = len ? mmap (0, len, mfs->flags, MAP_SHARED, mfs->fd, 0) : NULL;
    if (mfs->ptr == MAP_FAILED)
      {
        int err = errno;
@@ -184,7 +152,7 @@ _mapfile_truncate (mu_stream_t stream, mu_off_t len)
 static int
 _mapfile_size (mu_stream_t stream, mu_off_t *psize)
 {
-  struct _mapfile_stream *mfs = mu_stream_get_owner (stream);
+  struct _mu_mapfile_stream *mfs = (struct _mu_mapfile_stream *) stream;
   struct stat stbuf;
   int err = 0;
 
@@ -192,9 +160,9 @@ _mapfile_size (mu_stream_t stream, mu_off_t *psize)
     return EINVAL;
   if (mfs->ptr && (mfs->flags & PROT_WRITE))
     msync (mfs->ptr, mfs->size, MS_SYNC);
-  if (fstat(mfs->fd, &stbuf) != 0)
+  if (fstat (mfs->fd, &stbuf) != 0)
     return errno;
-  if (mfs->size != (size_t)stbuf.st_size)
+  if (mfs->size != (size_t) stbuf.st_size)
     {
       if (mfs->ptr)
        err = munmap (mfs->ptr, mfs->size);
@@ -231,30 +199,37 @@ _mapfile_size (mu_stream_t stream, mu_off_t *psize)
 static int
 _mapfile_flush (mu_stream_t stream)
 {
-  struct _mapfile_stream *mfs = mu_stream_get_owner (stream);
+  struct _mu_mapfile_stream *mfs = (struct _mu_mapfile_stream *) stream;
   if (mfs->ptr != MAP_FAILED && mfs->ptr != NULL && (mfs->flags & PROT_WRITE))
     return msync (mfs->ptr, mfs->size, MS_SYNC);
   return 0;
 }
 
 static int
-_mapfile_get_transport2 (mu_stream_t stream, mu_transport_t *pin, 
mu_transport_t *pout)
+_mapfile_ioctl (struct _mu_stream *str, int code, void *ptr)
 {
-  struct _mapfile_stream *mfs = mu_stream_get_owner (stream);
-
-  if (pout)
-    *pout = NULL;
+  struct _mu_mapfile_stream *mfs = (struct _mu_mapfile_stream *) str;
+  mu_transport_t ptrans[2];
   
-  if (pin)
-    *pin = (mu_transport_t) mfs->fd;
+  switch (code)
+    {
+    case MU_IOCTL_GET_TRANSPORT:
+      ptrans[0] = (mu_transport_t) mfs->fd;
+      ptrans[1] = NULL;
+      break;
+
+    default:
+      return EINVAL;
+    }
   return 0;
 }
 
 static int
 _mapfile_close (mu_stream_t stream)
 {
-  struct _mapfile_stream *mfs = mu_stream_get_owner (stream);
+  struct _mu_mapfile_stream *mfs = (struct _mu_mapfile_stream *) stream;
   int err = 0;
+
   if (mfs->ptr != MAP_FAILED)
     {
       if (mfs->ptr && munmap (mfs->ptr, mfs->size) != 0)
@@ -270,10 +245,10 @@ _mapfile_close (mu_stream_t stream)
 static int
 _mapfile_open (mu_stream_t stream)
 {
-  struct _mapfile_stream *mfs = mu_stream_get_owner (stream);
+  struct _mu_mapfile_stream *mfs = (struct _mu_mapfile_stream *) stream;
   int mflag, flg;
   struct stat st;
-  char* filename = mfs->filename;
+  char *filename = mfs->filename;
   int flags;
 
   mu_stream_get_flags (stream, &flags);
@@ -291,18 +266,16 @@ _mapfile_open (mu_stream_t stream)
       mfs->fd = -1;
     }
   /* Map the flags to the system equivalent */
-  if ((flags & MU_STREAM_WRITE) && (flags & MU_STREAM_READ))
-    return EINVAL;
+  if ((flags & MU_STREAM_RDWR) == MU_STREAM_RDWR)
+    {
+      mflag = PROT_READ | PROT_WRITE;
+      flg = O_RDWR;
+    }
   else if (flags & MU_STREAM_WRITE)
     {
       mflag = PROT_WRITE;
       flg = O_WRONLY;
     }
-  else if (flags & MU_STREAM_RDWR)
-    {
-      mflag = PROT_READ | PROT_WRITE;
-      flg = O_RDWR;
-    }
   else if (flags & MU_STREAM_CREAT)
     return ENOSYS;
   else /* default */
@@ -335,58 +308,59 @@ _mapfile_open (mu_stream_t stream)
   else
     mfs->ptr = NULL;
   mfs->flags = mflag;
-  mu_stream_set_flags (stream, MU_STREAM_NO_CHECK);
+  return 0;
+}
+
+static int
+_mapfile_seek (struct _mu_stream *str, mu_off_t off, mu_off_t *presult)
+{ 
+  struct _mu_mapfile_stream *mfs = (struct _mu_mapfile_stream *) str;
+  
+  if (off < 0 || off > mfs->size)
+    return ESPIPE;
+  mfs->offset = off;
+  *presult = off;
   return 0;
 }
 
 #endif /* _POSIX_MAPPED_FILES */
 
 int
-mu_mapfile_stream_create (mu_stream_t *stream, const char* filename, int flags)
+mu_mapfile_stream_create (mu_stream_t *pstream, const char *filename,
+                         int flags)
 {
 #ifndef _POSIX_MAPPED_FILES
   return ENOSYS;
 #else
-  struct _mapfile_stream *fs;
-  int ret;
-
-  if (stream == NULL)
-    return MU_ERR_OUT_PTR_NULL;
-  if (filename == NULL)
-    return EINVAL;
-
-  fs = calloc (1, sizeof (struct _mapfile_stream));
-  if (fs == NULL)
-    return ENOMEM;
-
-  fs->filename = strdup (filename);
-  if (!fs->filename)
-  {
-    free (fs);
+  struct _mu_mapfile_stream *str =
+    (struct _mu_mapfile_stream *) _mu_stream_create (sizeof (*str),
+                                                    flags | MU_STREAM_SEEK);
+  if (!str)
     return ENOMEM;
-  }
 
-  fs->fd = -1;
-  fs->ptr = MAP_FAILED;
-
-  ret = mu_stream_create (stream, flags | MU_STREAM_NO_CHECK, fs);
-  if (ret != 0)
+  str->filename = mu_strdup (filename);
+  if (!str->filename)
     {
-      free (fs->filename);
-      free (fs);
-      return ret;
+      free (str);
+      return ENOMEM;
     }
-
-  mu_stream_set_open (*stream, _mapfile_open, fs);
-  mu_stream_set_close (*stream, _mapfile_close, fs);
-  mu_stream_set_get_transport2 (*stream, _mapfile_get_transport2, fs);
-  mu_stream_set_read (*stream, _mapfile_read, fs);
-  mu_stream_set_readline (*stream, _mapfile_readline, fs);
-  mu_stream_set_write (*stream, _mapfile_write, fs);
-  mu_stream_set_truncate (*stream, _mapfile_truncate, fs);
-  mu_stream_set_size (*stream, _mapfile_size, fs);
-  mu_stream_set_flush (*stream, _mapfile_flush, fs);
-  mu_stream_set_destroy (*stream, _mapfile_destroy, fs);
+  str->fd = -1;
+  str->ptr = MAP_FAILED;
+
+  str->stream.open = _mapfile_open;
+  str->stream.close = _mapfile_close;
+  str->stream.ctl = _mapfile_ioctl;
+  str->stream.read = _mapfile_read;
+  str->stream.write = _mapfile_write;
+  str->stream.truncate = _mapfile_truncate;
+  str->stream.size = _mapfile_size;
+  str->stream.flush = _mapfile_flush;
+  str->stream.done = _mapfile_done;
+  str->stream.seek = _mapfile_seek;
+  
+  *pstream = (mu_stream_t) str;
   return 0;
-#endif /* _POSIX_MAPPED_FILES */
+#endif
 }
+
+
diff --git a/mailbox/mbx_default.c b/mailbox/mbx_default.c
index e970d15..348e7f7 100644
--- a/mailbox/mbx_default.c
+++ b/mailbox/mbx_default.c
@@ -40,7 +40,7 @@
 #include <mailutils/folder.h>
 #include <mailutils/auth.h>
 
-#include <mailbox0.h>
+#include <mailutils/sys/mailbox.h>
 
 char *mu_ticket_file = "~/.mu-tickets";
 
diff --git a/mailbox/mbxitr.c b/mailbox/mbxitr.c
index 6137e12..8463201 100644
--- a/mailbox/mbxitr.c
+++ b/mailbox/mbxitr.c
@@ -29,7 +29,7 @@
 #include <mailutils/error.h>
 #include <mailutils/iterator.h>
 
-#include <mailbox0.h>
+#include <mailutils/sys/mailbox.h>
 
 struct mailbox_iterator
 {
diff --git a/mailbox/memory_stream.c b/mailbox/memory_stream.c
index e433961..19d4590 100644
--- a/mailbox/memory_stream.c
+++ b/mailbox/memory_stream.c
@@ -1,94 +1,56 @@
 /* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 1999, 2000, 2001, 2004, 2007, 2010 Free Software
-   Foundation, Inc.
+   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 of the License, or (at your option) any later version.
+   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.
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU Lesser General
-   Public License along with this library; if not, write to the
-   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301 USA */
+   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 <errno.h>
-#include <stdlib.h>
 #include <string.h>
-#include <sys/stat.h>
+#include <stdlib.h>
 #include <unistd.h>
-#include <stdio.h>
+#include <fcntl.h>
 
-#include <sys/types.h>
-
-#include <mailutils/stream.h>
+#include <mailutils/types.h>
+#include <mailutils/alloc.h>
+#include <mailutils/error.h>
 #include <mailutils/errno.h>
-
-#undef min
-#define min(a,b) ((a) < (b) ? (a) : (b))
-
-#define MU_STREAM_MEMORY_BLOCKSIZE 128
-
-struct _memory_stream
-{
-  char *filename;
-  char *ptr;
-  size_t size;
-  size_t capacity;
-};
+#include <mailutils/nls.h>
+#include <mailutils/stream.h>
+#include <mailutils/sys/memory_stream.h>
+#include <mailutils/mutil.h>
 
 static void
-_memory_destroy (mu_stream_t stream)
+_memory_done (mu_stream_t stream)
 {
-  struct _memory_stream *mfs = mu_stream_get_owner (stream);
+  struct _mu_memory_stream *mfs = (struct _mu_memory_stream *) stream;
   if (mfs && mfs->ptr != NULL)
     free (mfs->ptr);
-  if (mfs->filename)
-    free (mfs->filename);
-  free (mfs);
 }
 
 static int
-_memory_read (mu_stream_t stream, char *optr, size_t osize,
-             mu_off_t offset, size_t *nbytes)
+_memory_read (mu_stream_t stream, char *optr, size_t osize, size_t *nbytes)
 {
-  struct _memory_stream *mfs = mu_stream_get_owner (stream);
+  struct _mu_memory_stream *mfs = (struct _mu_memory_stream *) stream;
   size_t n = 0;
-  if (mfs->ptr != NULL && ((size_t)offset <= mfs->size))
+  if (mfs->ptr != NULL && ((size_t)mfs->offset <= mfs->size))
     {
-      n = ((offset + osize) > mfs->size) ? mfs->size - offset :  osize;
-      memcpy (optr, mfs->ptr + offset, n);
-    }
-  if (nbytes)
-    *nbytes = n;
-  return 0;
-}
-
-static int
-_memory_readline (mu_stream_t stream, char *optr, size_t osize,
-                 mu_off_t offset, size_t *nbytes)
-{
-  struct _memory_stream *mfs = mu_stream_get_owner (stream);
-  char *nl;
-  size_t n = 0;
-  if (mfs->ptr && ((size_t)offset < mfs->size))
-    {
-      /* Save space for the null byte.  */
-      osize--;
-      nl = memchr (mfs->ptr + offset, '\n', mfs->size - offset);
-      n = (nl) ? (size_t)(nl - (mfs->ptr + offset) + 1) : mfs->size - offset;
-      n = min (n, osize);
-      memcpy (optr, mfs->ptr + offset, n);
-      optr[n] = '\0';
+      n = ((mfs->offset + osize) > mfs->size) ?
+           mfs->size - mfs->offset :  osize;
+      memcpy (optr, mfs->ptr + mfs->offset, n);
+      mfs->offset += n;
     }
   if (nbytes)
     *nbytes = n;
@@ -97,25 +59,29 @@ _memory_readline (mu_stream_t stream, char *optr, size_t 
osize,
 
 static int
 _memory_write (mu_stream_t stream, const char *iptr, size_t isize,
-              mu_off_t offset, size_t *nbytes)
+              size_t *nbytes)
 {
-  struct _memory_stream *mfs = mu_stream_get_owner (stream);
-
-  /* Bigger we have to realloc.  */
-  if (mfs->capacity < ((size_t)offset + isize))
+  struct _mu_memory_stream *mfs = (struct _mu_memory_stream *) stream;
+  
+  if (mfs->capacity < mfs->offset + isize)
     {
-      /* Realloc by fixed blocks of 128.  */
+      /* Realloc by fixed blocks of MU_STREAM_MEMORY_BLOCKSIZE. */
       size_t newsize = MU_STREAM_MEMORY_BLOCKSIZE *
-       (((offset + isize)/MU_STREAM_MEMORY_BLOCKSIZE) + 1);
-      char *tmp =  realloc (mfs->ptr, newsize);
+       (((mfs->offset + isize) / MU_STREAM_MEMORY_BLOCKSIZE) + 1);
+      char *tmp = mu_realloc (mfs->ptr, newsize);
       if (tmp == NULL)
        return ENOMEM;
       mfs->ptr = tmp;
       mfs->capacity = newsize;
     }
 
-  mfs->size = offset + isize;
-  memcpy (mfs->ptr + offset, iptr, isize);
+  memcpy (mfs->ptr + mfs->offset, iptr, isize);
+  
+  mfs->offset += isize;
+
+  if (mfs->offset > mfs->size)
+    mfs->size = mfs->offset;
+
   if (nbytes)
     *nbytes = isize;
   return 0;
@@ -124,24 +90,26 @@ _memory_write (mu_stream_t stream, const char *iptr, 
size_t isize,
 static int
 _memory_truncate (mu_stream_t stream, mu_off_t len)
 {
-  struct _memory_stream *mfs = mu_stream_get_owner (stream);
+  struct _mu_memory_stream *mfs = (struct _mu_memory_stream *) stream;
 
-  if (len > (mu_off_t)mfs->size)
+  if (len > (mu_off_t) mfs->size)
     {
-      char *tmp = realloc (mfs->ptr, len);
+      char *tmp = mu_realloc (mfs->ptr, len);
       if (tmp == NULL)
        return ENOMEM;
       mfs->ptr = tmp;
       mfs->capacity = len;
     }
   mfs->size = len;
+  if (mfs->offset > mfs->size)
+    mfs->offset = mfs->size;
   return 0;
 }
 
 static int
 _memory_size (mu_stream_t stream, mu_off_t *psize)
 {
-  struct _memory_stream *mfs = mu_stream_get_owner (stream);
+  struct _mu_memory_stream *mfs = (struct _mu_memory_stream *) stream;
   if (psize)
     *psize = mfs->size;
   return 0;
@@ -150,7 +118,7 @@ _memory_size (mu_stream_t stream, mu_off_t *psize)
 static int
 _memory_close (mu_stream_t stream)
 {
-  struct _memory_stream *mfs = mu_stream_get_owner (stream);
+  struct _mu_memory_stream *mfs = (struct _mu_memory_stream *) stream;
   if (mfs->ptr)
     free (mfs->ptr);
   mfs->ptr = NULL;
@@ -162,111 +130,83 @@ _memory_close (mu_stream_t stream)
 static int
 _memory_open (mu_stream_t stream)
 {
-  struct _memory_stream *mfs = mu_stream_get_owner (stream);
+  struct _mu_memory_stream *mfs = (struct _mu_memory_stream *) stream;
   int status = 0;
 
-  /* Close any previous file.  */
+  /* Close any previous stream. */
   if (mfs->ptr)
     free (mfs->ptr);
   mfs->ptr = NULL;
   mfs->size = 0;
   mfs->capacity = 0;
 
-  /* Initialize the data with file contents, if a filename was provided. */
-  if (mfs->filename)
-    {
-      struct stat statbuf;
-      if (stat (mfs->filename, &statbuf) == 0)
-        {
-          mfs->ptr = calloc (statbuf.st_size, 1);
-          if (mfs->ptr)
-            {
-              FILE *fp;
-              mfs->capacity = statbuf.st_size;
-              mfs->size = statbuf.st_size;
-              fp = fopen (mfs->filename, "r");
-              if (fp)
-                {
-                  size_t r = fread (mfs->ptr, mfs->size, 1, fp);
-                  if (r != mfs->size)
-                    status = EIO;
-                  fclose (fp);
-                }
-              else
-                status = errno;
-              if (status != 0)
-                {
-                  free (mfs->ptr);
-                  mfs->ptr = NULL;
-                  mfs->capacity = 0;
-                  mfs->size = 0;
-                }
-            }
-          else
-            status = ENOMEM;
-        }
-      else
-        status = EIO;
-    }
   return status;
 }
 
 static int
-_memory_get_transport2 (mu_stream_t stream,
-                       mu_transport_t *pin, mu_transport_t *pout)
+_memory_ioctl (struct _mu_stream *stream, int code, void *ptr)
 {
-  struct _memory_stream *mfs = mu_stream_get_owner (stream);
-  *pin = mfs->ptr;
-  if (pout)
-    *pout = mfs->ptr;
+  struct _mu_memory_stream *mfs = (struct _mu_memory_stream *) stream;
+  mu_transport_t *ptrans;
+  
+  switch (code)
+    {
+    case MU_IOCTL_GET_TRANSPORT:
+      if (!ptr)
+       return EINVAL;
+      ptrans = ptr;
+      ptrans[0] = (mu_transport_t) mfs->ptr;
+      ptrans[1] = NULL;
+      break;
+
+    default:
+      return EINVAL;
+    }
+  return 0;
+}
+
+static int
+_memory_seek (struct _mu_stream *stream, mu_off_t off, mu_off_t *presult)
+{ 
+  struct _mu_memory_stream *mfs = (struct _mu_memory_stream *) stream;
+
+  if (off < 0)
+    return ESPIPE;
+  mfs->offset = off;
+  *presult = off;
   return 0;
 }
 
 int
-mu_memory_stream_create (mu_stream_t * stream, const char *filename, int flags)
+mu_memory_stream_create (mu_stream_t *pstream, int flags)
 {
-  struct _memory_stream *mfs;
-  int ret;
-
-  if (stream == NULL)
-    return MU_ERR_OUT_PTR_NULL;
+  struct _mu_memory_stream *str;
 
-  mfs = calloc (1, sizeof (*mfs));
-
-  if (mfs == NULL)
+  if (!flags)
+    flags = MU_STREAM_RDWR;
+  str = (struct _mu_memory_stream *) _mu_stream_create (sizeof (*str),
+                                                       flags | MU_STREAM_SEEK);
+  
+  if (!str)
     return ENOMEM;
 
-  if (filename)
-    {
-      mfs->filename = strdup (filename);
-      if (!mfs->filename)
-       {
-         free (mfs);
-         return ENOMEM;
-       }
-    }
+  str->ptr = NULL;
+  str->size = 0;
+  str->offset = 0;
+  str->capacity = 0;
 
-  mfs->ptr = NULL;
-  mfs->size = 0;
+  str->stream.open = _memory_open;
+  str->stream.close = _memory_close;
+  str->stream.read = _memory_read;
+  str->stream.write = _memory_write;
+  str->stream.truncate = _memory_truncate;
+  str->stream.size = _memory_size;
+  str->stream.done = _memory_done;
+  str->stream.ctl = _memory_ioctl;
+  str->stream.seek = _memory_seek;
 
-  ret = mu_stream_create (stream, flags | MU_STREAM_NO_CHECK, mfs);
-  if (ret != 0)
-    {
-      free (mfs->filename);
-      free (mfs);
-
-      return ret;
-    }
+  *pstream = (mu_stream_t) str;
 
-  mu_stream_set_open (*stream, _memory_open, mfs);
-  mu_stream_set_close (*stream, _memory_close, mfs);
-  mu_stream_set_read (*stream, _memory_read, mfs);
-  mu_stream_set_readline (*stream, _memory_readline, mfs);
-  mu_stream_set_write (*stream, _memory_write, mfs);
-  mu_stream_set_truncate (*stream, _memory_truncate, mfs);
-  mu_stream_set_size (*stream, _memory_size, mfs);
-  mu_stream_set_destroy (*stream, _memory_destroy, mfs);
-  mu_stream_set_get_transport2 (*stream, _memory_get_transport2, mfs);
-  
   return 0;
 }
+  
diff --git a/mailbox/message.c b/mailbox/message.c
index b05d2dd..f276d0a 100644
--- a/mailbox/message.c
+++ b/mailbox/message.c
@@ -31,8 +31,6 @@
 #include <string.h>
 #include <pwd.h>
 
-#include <message0.h>
-
 #include <mailutils/cctype.h>
 #include <mailutils/address.h>
 #include <mailutils/attribute.h>
@@ -52,25 +50,434 @@
 #include <mailutils/md5.h>
 #include <mailutils/io.h>
 
-#define MESSAGE_MODIFIED 0x10000;
-
-static int message_read   (mu_stream_t is, char *buf, size_t buflen,
-                          mu_off_t off, size_t *pnread );
-static int message_write  (mu_stream_t os, const char *buf, size_t buflen,
-                          mu_off_t off, size_t *pnwrite);
-static int message_get_transport2 (mu_stream_t stream, mu_transport_t *pin, 
-                                   mu_transport_t *pout);
-static int message_sender (mu_envelope_t envelope, char *buf, size_t len,
-                          size_t *pnwrite);
-static int message_date   (mu_envelope_t envelope, char *buf, size_t len,
-                          size_t *pnwrite);
-static int message_stream_size (mu_stream_t stream, mu_off_t *psize);
-static int message_header_fill (mu_header_t header, char *buffer,
-                               size_t buflen, mu_off_t off,
-                               size_t * pnread);
-static int message_body_read (mu_stream_t stream,  char *buffer,
-                             size_t n, mu_off_t off, size_t *pn);
+#include <mailutils/sys/message.h>
+#include <mailutils/sys/stream.h>
+
+#define MESSAGE_MODIFIED        0x10000
+#define MESSAGE_INTERNAL_STREAM 0x20000
+
+
+/* Message stream */
+
+enum _message_stream_state
+  {
+    _mss_init,
+    _mss_header,
+    _mss_body,
+    _mss_eof
+  };
+
+struct _mu_message_stream
+{
+  struct _mu_stream stream;
+  mu_message_t msg;
+  enum _message_stream_state state;
+  mu_stream_t transport;
+  mu_off_t limit;
+};
+
+static int
+_check_stream_state (struct _mu_message_stream *str)
+{
+  int rc = 0;
+  
+  if (str->transport && mu_stream_eof (str->transport))
+    mu_stream_destroy (&str->transport);
+  
+  switch (str->state)
+    {
+    case _mss_init:
+      if (!str->transport)
+       {
+         rc = mu_header_get_streamref (str->msg->header, &str->transport);
+         if (rc == 0)
+           {
+             str->state = _mss_header;
+             rc = mu_stream_seek (str->transport, 0, MU_SEEK_SET, NULL);
+           }
+       }
+      break;
+      
+    case _mss_header:
+      if (!str->transport)
+       {
+         rc = mu_body_get_streamref (str->msg->body, &str->transport);
+         if (rc == 0)
+           {
+             str->state = _mss_body;
+             rc = mu_stream_seek (str->transport, 0, MU_SEEK_SET, NULL);
+           }
+       }
+      break;
+      
+    case _mss_body:
+      if (!str->transport)
+       str->state = _mss_eof;
+    case _mss_eof:
+      break;
+    }
+  return rc;
+}
+
+static void
+_message_stream_done (struct _mu_stream *str)
+{
+  struct _mu_message_stream *sp = (struct _mu_message_stream *)str;
+  mu_stream_destroy (&sp->transport);
+}
+
+static int
+_message_stream_flush (struct _mu_stream *str)
+{
+  struct _mu_message_stream *sp = (struct _mu_message_stream *)str;
+  int rc = _check_stream_state (sp);
+  if (rc)
+    return rc;
+  return mu_stream_flush (sp->transport);
+}
+  
+static int
+_message_stream_size (struct _mu_stream *str, mu_off_t *psize)
+{
+  struct _mu_message_stream *sp = (struct _mu_message_stream *)str;
+  size_t hsize, bsize;
+  mu_header_size (sp->msg->header, &hsize);
+  mu_body_size (sp->msg->body, &bsize);
+  if (psize)
+    *psize = hsize + bsize;
+  return 0;
+}
+
+static int
+_message_stream_seek (struct _mu_stream *str, mu_off_t off, mu_off_t *ppos)
+{
+  struct _mu_message_stream *sp = (struct _mu_message_stream *)str;
+  size_t hsize, size;
+  int rc;
+  
+  rc = _check_stream_state (sp);
+  if (rc)
+    return rc;
+  mu_header_size (sp->msg->header, &hsize);
+  mu_body_size (sp->msg->body, &size);
+  size += hsize;
+  
+  if (off < 0 || off >= size)
+    return ESPIPE;
+
+  switch (sp->state)
+    {
+    case _mss_eof:
+      sp->state = _mss_init;
+      rc = _check_stream_state (sp);
+      if (rc)
+       return rc;
+      /* fall through */
+    case _mss_header:
+      if (off < hsize)
+       break;
+      mu_stream_destroy (&sp->transport);
+      rc = _check_stream_state (sp);
+      if (rc)
+       return rc;
+      /* fall through */
+    case _mss_body:
+      if (off > hsize)
+       off -= hsize;   
+      else
+       {
+         mu_stream_destroy (&sp->transport);
+         sp->state = _mss_init;
+         rc = _check_stream_state (sp);
+         if (rc)
+           return rc;
+       }
+
+      break;
+
+    default:
+      break;
+    }
+  rc = mu_stream_seek (sp->transport, off, MU_SEEK_SET, &off);
+  if (rc == 0)
+    {
+      if (sp->state == _mss_body)
+       off += hsize;
+      *ppos = off;
+    }
+  return rc;
+}
+
+static int
+_message_stream_read (struct _mu_stream *str, char *buf, size_t bufsize,
+                     size_t *pnread)
+{
+  struct _mu_message_stream *sp = (struct _mu_message_stream *)str;
+  size_t nread = 0;
+  int rc;
+  
+  while (bufsize)
+    {
+      size_t n;
+      rc = _check_stream_state (sp);
+      if (rc)
+       break;
+      if (sp->state == _mss_eof)
+       break;
+      rc = mu_stream_read (sp->transport, buf, bufsize, &n);
+      nread += n;
+      buf += n;
+      bufsize -= n;
+    }
+  *pnread = nread;
+  return rc;
+}
+
+static int
+_message_stream_readdelim (struct _mu_stream *str, char *buf, size_t bufsize,
+                          int delim, size_t *pnread)
+{
+  struct _mu_message_stream *sp = (struct _mu_message_stream *)str;
+  size_t nread = 0;
+  int rc;
+  
+  while (bufsize)
+    {
+      size_t n;
+      rc = _check_stream_state (sp);
+      if (rc)
+       break;
+      if (sp->state == _mss_eof)
+       break;
+      rc = mu_stream_readdelim (sp->transport, buf, bufsize, delim, &n);
+      if (rc || n == 0)
+       break;
+      nread += n;
+      buf += n;
+      bufsize -= n;
+    }
+  *pnread = nread;
+  return rc;
+}  
+
+#if 0
+static int
+_message_stream_write (struct _mu_stream *str,
+                      const char *buf, size_t bufsize,
+                      size_t *pnwritten)
+{
+  struct _mu_message_stream *sp = (struct _mu_message_stream *)str;
+  
+  /* FIXME */
+}
+#endif
+
+static int
+_message_stream_create (mu_stream_t *pmsg, mu_message_t msg, int flags)
+{
+  struct _mu_message_stream *sp;
+
+  sp = (struct _mu_message_stream *) _mu_stream_create (sizeof (*sp),
+                                                       flags | MU_STREAM_SEEK);
+  if (!sp)
+    return ENOMEM;
+
+  sp->stream.read = _message_stream_read;
+  sp->stream.readdelim = _message_stream_readdelim;
+  /* FIXME: Write is not defined */
+  /*  sp->stream.write = _message_stream_write;*/
+  sp->stream.done = _message_stream_done;
+  sp->stream.flush = _message_stream_flush;
+  sp->stream.seek = _message_stream_seek; 
+  sp->stream.size = _message_stream_size;
+  sp->state = _mss_init;
+  sp->msg = msg;
+  *pmsg = (mu_stream_t) sp;
+  return 0;
+}
+
+
+enum eoh_state
+  {
+    eoh_no,
+    eoh_maybe,
+    eoh_yes
+  };
+
+/* Message header stuff */
+static enum eoh_state
+string_find_eoh (enum eoh_state eoh, const char *str, size_t len,
+                size_t *ppos)
+{
+  size_t pos;
+
+  if (eoh == eoh_maybe && *str == '\n')
+    {
+      *ppos = 0;
+      return eoh_yes;
+    }
+  
+  for (pos = 0; pos < len - 1; pos++)
+    if (str[pos] == '\n' && str[pos + 1] == '\n')
+      {
+       *ppos = pos + 1;
+       return eoh_yes;
+      }
+  
+  *ppos = pos + 1;
+  return str[pos] == '\n' ? eoh_maybe : eoh_no;
+}
+
+#define MIN_HEADER_BUF_SIZE 2048
+
+static int
+_header_fill (mu_stream_t stream, char **pbuf, size_t *plen)
+{
+  int status = 0;
+  char *buffer = NULL;
+  size_t bufsize = 0;
+  char inbuf[MIN_HEADER_BUF_SIZE];
+  size_t nread;
+  enum eoh_state eoh = eoh_no;
+  
+  status = mu_stream_seek (stream, 0, MU_SEEK_SET, NULL);
+  if (status)
+    return status;
+      
+  while (eoh != eoh_yes
+        && (status = mu_stream_read (stream, inbuf, sizeof (inbuf), &nread))
+           == 0
+        && nread)
+    {
+      char *nbuf;
+      size_t len;
+
+      eoh = string_find_eoh (eoh, inbuf, nread, &len);
+      
+      nbuf = realloc (buffer, bufsize + len);
+      if (!nbuf)
+       {
+         status = ENOMEM;
+         break;
+       }
+      memcpy (nbuf + bufsize, inbuf, len);
+      buffer = nbuf;
+      bufsize += len;
+    }
+
+  if (status)
+    free (buffer);
+  else
+    {
+      *pbuf = buffer;
+      *plen = bufsize;
+    }
+  return status;
+}
+    
+static int
+message_header_fill (void *data, char **pbuf, size_t *plen)
+{
+  int status = 0;
+  mu_message_t msg = data;
+  mu_stream_t stream;
+
+  status = mu_message_get_streamref (msg, &stream);
+  if (status == 0)
+    {
+      status = _header_fill (stream, pbuf, plen);
+      mu_stream_destroy (&stream);
+    }
+  return status;
+}
+
+
+/* Message envelope */
+static int
+message_envelope_date (mu_envelope_t envelope, char *buf, size_t len,
+                      size_t *pnwrite)
+{
+  mu_message_t msg = mu_envelope_get_owner (envelope);
+  time_t t;
+  size_t n;
+
+  if (msg == NULL)
+    return EINVAL;
+
+  /* FIXME: extract the time from "Date:".  */
+
+  if (buf == NULL || len == 0)
+    {
+      n = MU_ENVELOPE_DATE_LENGTH;
+    }
+  else
+    {
+      char tmpbuf[MU_ENVELOPE_DATE_LENGTH+1];
+      t = time (NULL);
+      n = mu_strftime (tmpbuf, sizeof tmpbuf, 
+                       MU_ENVELOPE_DATE_FORMAT, localtime (&t));
+      n = mu_cpystr (buf, tmpbuf, len);
+    }
+  if (pnwrite)
+    *pnwrite = n;
+  return 0;
+}
+
+static int
+message_envelope_sender (mu_envelope_t envelope, char *buf, size_t len,
+                        size_t *pnwrite)
+{
+  mu_message_t msg = mu_envelope_get_owner (envelope);
+  mu_header_t header = NULL;
+  size_t n = 0;
+  int status;
+
+  if (msg == NULL)
+    return EINVAL;
+
+  /* Can it be extracted from the From:  */
+  mu_message_get_header (msg, &header);
+  status = mu_header_get_value (header, MU_HEADER_FROM, NULL, 0, &n);
+  if (status == 0 && n != 0)
+    {
+      char *sender;
+      mu_address_t address = NULL;
+      sender = calloc (1, n + 1);
+      if (sender == NULL)
+       return ENOMEM;
+      mu_header_get_value (header, MU_HEADER_FROM, sender, n + 1, NULL);
+      if (mu_address_create (&address, sender) == 0)
+       mu_address_get_email (address, 1, buf, n + 1, pnwrite);
+      free (sender);
+      mu_address_destroy (&address);
+      return 0;
+    }
+  else if (status == EAGAIN)
+    return status;
 
+  /* oops! We are still here */
+  {
+    struct mu_auth_data *auth = mu_get_auth_by_uid (getuid ());
+    const char *sender = auth ? auth->name : "unknown";
+    n = strlen (sender);
+    if (buf && len > 0)
+      {
+       len--; /* One for the null.  */
+       n = (n < len) ? n : len;
+       memcpy (buf, auth->name, n);
+       buf[n] = '\0';
+      }
+    if (auth)
+      mu_auth_data_free (auth);
+  }
+
+  if (pnwrite)
+    *pnwrite = n;
+  return 0;
+}
+
+
+
 /*  Allocate ressources for the mu_message_t.  */
 int
 mu_message_create (mu_message_t *pmsg, void *owner)
@@ -83,7 +490,7 @@ mu_message_create (mu_message_t *pmsg, void *owner)
   msg = calloc (1, sizeof (*msg));
   if (msg == NULL)
     return ENOMEM;
-  status = mu_monitor_create (&(msg->monitor), 0, msg);
+  status = mu_monitor_create (&msg->monitor, 0, msg);
   if (status != 0)
     {
       free (msg);
@@ -127,48 +534,37 @@ mu_message_destroy (mu_message_t *pmsg, void *owner)
            {
              mu_observable_notify (msg->observable, MU_EVT_MESSAGE_DESTROY,
                                    msg);
-             mu_observable_destroy (&(msg->observable), msg);
+             mu_observable_destroy (&msg->observable, msg);
            }
 
          /* Envelope.  */
          if (msg->envelope)
-           mu_envelope_destroy (&(msg->envelope), msg);
+           mu_envelope_destroy (&msg->envelope, msg);
 
          /* Header.  */
          if (msg->header)
-           mu_header_destroy (&(msg->header), msg);
+           mu_header_destroy (&msg->header);
 
          /* Body.  */
          if (msg->body)
-           mu_body_destroy (&(msg->body), msg);
+           mu_body_destroy (&msg->body, msg);
 
          /* Attribute.  */
          if (msg->attribute)
-           mu_attribute_destroy (&(msg->attribute), msg);
+           mu_attribute_destroy (&msg->attribute, msg);
 
          /* Stream.  */
          if (msg->stream)
-           mu_stream_destroy (&(msg->stream), msg);
+           mu_stream_destroy (&msg->stream);
 
          /*  Mime.  */
          if (msg->mime)
-           mu_mime_destroy (&(msg->mime));
+           mu_mime_destroy (&msg->mime);
 
          /* Loose the owner.  */
          msg->owner = NULL;
 
-         /* Mailbox maybe created floating i.e they were created
-            implicitely by the message when doing something like:
-            mu_message_create (&msg, "pop://localhost/msgno=2", NULL);
-            mu_message_create (&msg, "imap://localhost/alain;uid=xxxxx", NULL);
-            althought the semantics about this is still flaky we our
-            making some provisions here for it.
-            if (msg->floating_mailbox && msg->mailbox)
-            mu_mailbox_destroy (&(msg->mailbox));
-         */
-         
-         if (msg->ref <= 0)
-           free (msg);
+         free (msg);
        }
       mu_monitor_unlock (monitor);
       if (destroy_lock)
@@ -183,35 +579,36 @@ mu_message_create_copy (mu_message_t *to, mu_message_t 
from)
 {
   int status = 0;
   mu_stream_t fromstr = NULL;
-  mu_stream_t tostr = NULL;
-  mu_off_t off = 0;
-  size_t n = 0;
-  char buf[512];
+  mu_stream_t tmp = NULL;
 
   if (!to)
     return MU_ERR_OUT_PTR_NULL;
   if (!from)
     return EINVAL;
 
-  if((status = mu_message_create (to, NULL)))
+  status = mu_memory_stream_create (&tmp, MU_STREAM_RDWR|MU_STREAM_SEEK);
+  if (status)
     return status;
 
-  mu_message_get_stream (from, &fromstr);
-  mu_message_get_stream (*to, &tostr);
+  status = mu_message_get_streamref (from, &fromstr);
+  if (status)
+    {
+      mu_stream_destroy (&tmp);
+      return status;
+    }
 
-  while (
-      (status = mu_stream_readline (fromstr, buf, sizeof(buf), off, &n)) == 0
-        &&
-      n > 0
-      )
+  status = mu_stream_copy (tmp, fromstr, 0, NULL);
+  if (status == 0)
     {
-      mu_stream_write (tostr, buf, n, off, NULL);
-      off += n;
+      status = mu_message_create (to, NULL);
+      if (status == 0)
+       mu_message_set_stream (*to, tmp, NULL);
     }
 
-  if(status)
-    mu_message_destroy(to, NULL);
-  
+  if (status)
+    mu_stream_destroy (&tmp);
+  mu_stream_destroy (&fromstr);
+
   return status;
 }
 
@@ -293,26 +690,24 @@ mu_message_get_header (mu_message_t msg, mu_header_t 
*phdr)
   if (phdr == NULL)
     return MU_ERR_OUT_PTR_NULL;
 
-  /* Is it a floating mesg */
   if (msg->header == NULL)
     {
       mu_header_t header;
-      int status = mu_header_create (&header, NULL, 0, msg);
+      int status = mu_header_create (&header, NULL, 0);
       if (status != 0)
        return status;
       if (msg->stream)
-       {
-         /* Was it created by us?  */
-         mu_message_t mesg = mu_stream_get_owner (msg->stream);
-         if (mesg != msg)
-           mu_header_set_fill (header, message_header_fill, msg);
-       }
+       mu_header_set_fill (header, message_header_fill, msg);
+      status = mu_header_size (header, &msg->orig_header_size);
+      if (status)
+       return status;
       msg->header = header;
     }
   *phdr = msg->header;
   return 0;
 }
 
+/* Note: mu_message_set_header steals the reference to hdr */
 int
 mu_message_set_header (mu_message_t msg, mu_header_t hdr, void *owner)
 {
@@ -320,10 +715,8 @@ mu_message_set_header (mu_message_t msg, mu_header_t hdr, 
void *owner)
     return EINVAL;
   if (msg->owner != owner)
      return EACCES;
-  /* Make sure we destroy the old if it was own by the mesg */
-  /* FIXME:  I do not know if somebody has already a ref on this ? */
   if (msg->header)
-    mu_header_destroy (&(msg->header), msg);
+    mu_header_destroy (&msg->header);
   msg->header = hdr;
   msg->flags |= MESSAGE_MODIFIED;
   return 0;
@@ -344,25 +737,25 @@ mu_message_get_body (mu_message_t msg, mu_body_t *pbody)
       int status = mu_body_create (&body, msg);
       if (status != 0)
        return status;
-      /* If a stream is already set use it to create the body stream.  */
-      if (msg->stream)
+      /* If a stream is already set, use it to create the body stream.  */
+      /* FIXME: I'm not sure if the second condition is really needed */
+      if (msg->stream/* && (msg->flags & MESSAGE_INTERNAL_STREAM)*/)
        {
-         /* Was it created by us?  */
-         mu_message_t mesg = mu_stream_get_owner (msg->stream);
-         if (mesg != msg)
+         mu_stream_t stream;
+         int flags = 0;
+
+         /* FIXME: The actual mu_header_size cannot be used as offset,
+            because the headers might have been modified in between. */
+         
+         mu_stream_get_flags (msg->stream, &flags);
+         status = mu_streamref_create_abridged (&stream, msg->stream,
+                                                msg->orig_header_size, 0);
+         if (status)
            {
-             mu_stream_t stream;
-             int flags = 0;
-             mu_stream_get_flags (msg->stream, &flags);
-             if ((status = mu_stream_create (&stream, flags, body)) != 0)
-               {
-                 mu_body_destroy (&body, msg);
-                 return status;
-               }
-             mu_stream_set_read (stream, message_body_read, body);
-             mu_stream_setbufsiz (stream, 128);
-             mu_body_set_stream (body, stream, msg);
+             mu_body_destroy (&body, msg);
+             return status;
            }
+         mu_body_set_stream (body, stream, msg);
        }
       msg->body = body;
     }
@@ -377,10 +770,10 @@ mu_message_set_body (mu_message_t msg, mu_body_t body, 
void *owner)
     return EINVAL;
   if (msg->owner != owner)
     return EACCES;
-  /* Make sure we destoy the old if it was own by the mesg.  */
+  /* Make sure we destroy the old if it was owned by the mesg.  */
   /* FIXME:  I do not know if somebody has already a ref on this ? */
   if (msg->body)
-    mu_body_destroy (&(msg->body), msg);
+    mu_body_destroy (&msg->body, msg);
   msg->body = body;
   msg->flags |= MESSAGE_MODIFIED;
   return 0;
@@ -393,18 +786,19 @@ mu_message_set_stream (mu_message_t msg, mu_stream_t 
stream, void *owner)
     return EINVAL;
   if (msg->owner != owner)
     return EACCES;
-  /* Make sure we destoy the old if it was own by the mesg.  */
-  /* FIXME:  I do not know if somebody has already a ref on this ? */
   if (msg->stream)
-    mu_stream_destroy (&(msg->stream), msg);
+    mu_stream_destroy (&msg->stream);
   msg->stream = stream;
   msg->flags |= MESSAGE_MODIFIED;
+  msg->flags &= ~MESSAGE_INTERNAL_STREAM;
   return 0;
 }
 
-int
-mu_message_get_stream (mu_message_t msg, mu_stream_t *pstream)
+static int
+_message_get_stream (mu_message_t msg, mu_stream_t *pstream, int ref)
 {
+  int status;
+
   if (msg == NULL)
     return EINVAL;
   if (pstream == NULL)
@@ -412,20 +806,64 @@ mu_message_get_stream (mu_message_t msg, mu_stream_t 
*pstream)
 
   if (msg->stream == NULL)
     {
-      mu_stream_t stream;
-      int status;
-      status = mu_stream_create (&stream, MU_STREAM_RDWR, msg);
-      if (status != 0)
-       return status;
-      mu_stream_set_read (stream, message_read, msg);
-      mu_stream_set_write (stream, message_write, msg);
-      mu_stream_set_get_transport2 (stream, message_get_transport2, msg);
-      mu_stream_set_size (stream, message_stream_size, msg);
-      mu_stream_set_flags (stream, MU_STREAM_RDWR);
-      msg->stream = stream;
+      if (msg->_get_stream)
+       {
+         status = msg->_get_stream (msg, &msg->stream);
+         if (status)
+           return status;
+       }
+      else
+       {
+         mu_header_t hdr;
+         mu_body_t body;
+
+         /* FIXME: Kind of a kludge: make sure the message has header
+            and body initialized. */
+         status = mu_message_get_header (msg, &hdr);
+         if (status)
+           return status;
+         status = mu_message_get_body (msg, &body);
+         if (status)
+           return status;
+         
+         status = _message_stream_create (&msg->stream, msg, MU_STREAM_RDWR);
+         if (status)
+           return status;
+         msg->flags |= MESSAGE_INTERNAL_STREAM;
+       }
+    }
+  
+  if (!ref)
+    {
+      *pstream = msg->stream;
+      return 0;
     }
+  return mu_streamref_create (pstream, msg->stream);
+}
 
-  *pstream = msg->stream;
+int
+mu_message_get_stream (mu_message_t msg, mu_stream_t *pstream)
+{
+  /* FIXME: Deprecation warning */
+  return _message_get_stream (msg, pstream, 0);
+}
+
+int
+mu_message_get_streamref (mu_message_t msg, mu_stream_t *pstream)
+{
+  return _message_get_stream (msg, pstream, 1);
+}
+
+int
+mu_message_set_get_stream (mu_message_t msg,
+                          int (*_getstr) (mu_message_t, mu_stream_t *),
+                          void *owner)
+{
+  if (msg == NULL)
+    return EINVAL;
+  if (msg->owner != owner)
+    return EACCES;
+  msg->_get_stream = _getstr;
   return 0;
 }
 
@@ -514,8 +952,8 @@ mu_message_get_envelope (mu_message_t msg, mu_envelope_t 
*penvelope)
       int status = mu_envelope_create (&envelope, msg);
       if (status != 0)
        return status;
-      mu_envelope_set_sender (envelope, message_sender, msg);
-      mu_envelope_set_date (envelope, message_date, msg);
+      mu_envelope_set_sender (envelope, message_envelope_sender, msg);
+      mu_envelope_set_date (envelope, message_envelope_date, msg);
       msg->envelope = envelope;
     }
   *penvelope = msg->envelope;
@@ -530,7 +968,7 @@ mu_message_set_envelope (mu_message_t msg, mu_envelope_t 
envelope, void *owner)
   if (msg->owner != owner)
     return EACCES;
   if (msg->envelope)
-    mu_envelope_destroy (&(msg->envelope), msg);
+    mu_envelope_destroy (&msg->envelope, msg);
   msg->envelope = envelope;
   msg->flags |= MESSAGE_MODIFIED;
   return 0;
@@ -563,7 +1001,7 @@ mu_message_set_attribute (mu_message_t msg, mu_attribute_t 
attribute, void *owne
   if (msg->owner != owner)
     return EACCES;
   if (msg->attribute)
-    mu_attribute_destroy (&(msg->attribute), owner);
+    mu_attribute_destroy (&msg->attribute, owner);
   msg->attribute = attribute;
   msg->flags |= MESSAGE_MODIFIED;
   return 0;
@@ -610,32 +1048,32 @@ mu_message_get_uidl (mu_message_t msg, char *buffer, 
size_t buflen,
       struct mu_md5_ctx md5context;
       mu_stream_t stream = NULL;
       char buf[1024];
-      mu_off_t offset = 0;
       unsigned char md5digest[16];
       char *tmp;
       n = 0;
       mu_message_get_uid (msg, &uid);
-      mu_message_get_stream (msg, &stream);
+      mu_message_get_streamref (msg, &stream);
       mu_md5_init_ctx (&md5context);
-      while (mu_stream_read (stream, buf, sizeof (buf), offset, &n) == 0
-            && n > 0)
+      status = mu_stream_seek (stream, 0, MU_SEEK_SET, NULL);
+      if (status == 0)
        {
-         mu_md5_process_bytes (buf, n, &md5context);
-         offset += n;
+         while (mu_stream_read (stream, buf, sizeof (buf), &n) == 0
+                && n > 0)
+           mu_md5_process_bytes (buf, n, &md5context);
+         mu_md5_finish_ctx (&md5context, md5digest);
+         tmp = buf;
+         for (n = 0; n < 16; n++, tmp += 2)
+           sprintf (tmp, "%02x", md5digest[n]);
+         *tmp = '\0';
+         /* POP3 rfc says that an UID should not be longer than 70.  */
+         snprintf (buf + 32, 70, ".%lu.%lu", (unsigned long)time (NULL), 
+                   (unsigned long) uid);
+
+         mu_header_set_value (header, "X-UIDL", buf, 1);
+         buflen--; /* leave space for the NULL.  */
+         strncpy (buffer, buf, buflen)[buflen] = '\0';
        }
-      mu_md5_finish_ctx (&md5context, md5digest);
-      tmp = buf;
-      for (n = 0; n < 16; n++, tmp += 2)
-       sprintf (tmp, "%02x", md5digest[n]);
-      *tmp = '\0';
-      /* POP3 rfc says that an UID should not be longer than 70.  */
-      snprintf (buf + 32, 70, ".%lu.%lu", (unsigned long)time (NULL), 
-                (unsigned long) uid);
-
-      mu_header_set_value (header, "X-UIDL", buf, 1);
-      buflen--; /* leave space for the NULL.  */
-      strncpy (buffer, buf, buflen)[buflen] = '\0';
-      status = 0;
+      mu_stream_destroy (&stream);
     }
   return status;
 }
@@ -710,7 +1148,7 @@ mu_message_is_multipart (mu_message_t msg, int *pmulti)
        return msg->_is_multipart (msg, pmulti);
       if (msg->mime == NULL)
        {
-         int status = mu_mime_create (&(msg->mime), msg, 0);
+         int status = mu_mime_create (&msg->mime, msg, 0);
          if (status != 0)
            return 0;
        }
@@ -730,7 +1168,7 @@ mu_message_get_num_parts (mu_message_t msg, size_t *pparts)
 
   if (msg->mime == NULL)
     {
-      int status = mu_mime_create (&(msg->mime), msg, 0);
+      int status = mu_mime_create (&msg->mime, msg, 0);
       if (status != 0)
        return status;
     }
@@ -762,7 +1200,7 @@ mu_message_get_part (mu_message_t msg, size_t part, 
mu_message_t *pmsg)
 
   if (msg->mime == NULL)
     {
-      int status = mu_mime_create (&(msg->mime), msg, 0);
+      int status = mu_mime_create (&msg->mime, msg, 0);
       if (status != 0)
        return status;
     }
@@ -790,7 +1228,7 @@ mu_message_get_observable (mu_message_t msg, 
mu_observable_t *pobservable)
 
   if (msg->observable == NULL)
     {
-      int status = mu_observable_create (&(msg->observable), msg);
+      int status = mu_observable_create (&msg->observable, msg);
       if (status != 0)
        return status;
     }
@@ -798,309 +1236,6 @@ mu_message_get_observable (mu_message_t msg, 
mu_observable_t *pobservable)
   return 0;
 }
 
-/* Implements the mu_stream_read () on the message stream.  */
-static int
-message_read (mu_stream_t is, char *buf, size_t buflen,
-             mu_off_t off, size_t *pnread )
-{
-  mu_message_t msg =  mu_stream_get_owner (is);
-  mu_stream_t his, bis;
-  size_t hread, hsize, bread, bsize;
-
-  if (msg == NULL)
-    return EINVAL;
-
-  bsize = hsize = bread = hread = 0;
-  his = bis = NULL;
-
-  mu_header_size (msg->header, &hsize);
-  mu_body_size (msg->body, &bsize);
-
-  /* On some remote sever (POP) the size of the header and body is not known
-     until you start reading them.  So by checking hsize == bsize == 0,
-     this kludge is a way of detecting the anomalie and start by the
-     header.  */
-  if ((size_t)off < hsize || (hsize == 0 && bsize == 0))
-    {
-      mu_header_get_stream (msg->header, &his);
-      mu_stream_read (his, buf, buflen, off, &hread);
-    }
-  else
-    {
-      mu_body_get_stream (msg->body, &bis);
-      mu_stream_read (bis, buf, buflen, off - hsize, &bread);
-    }
-
-  if (pnread)
-    *pnread = hread + bread;
-  return 0;
-}
-
-/* Implements the mu_stream_write () on the message stream.  */
-static int
-message_write (mu_stream_t os, const char *buf, size_t buflen,
-              mu_off_t off, size_t *pnwrite)
-{
-  mu_message_t msg = mu_stream_get_owner (os);
-  int status = 0;
-  size_t bufsize = buflen;
-
-  if (msg == NULL)
-    return EINVAL;
-
-  /* Skip the obvious.  */
-  if (buf == NULL || buflen == 0)
-    {
-      if (pnwrite)
-       *pnwrite = 0;
-      return 0;
-    }
-
-  if (!msg->hdr_done)
-    {
-      size_t len;
-      char *nl;
-      mu_header_t header = NULL;
-      mu_stream_t hstream = NULL;
-      mu_message_get_header (msg, &header);
-      mu_header_get_stream (header, &hstream);
-      while (!msg->hdr_done && (nl = memchr (buf, '\n', buflen)) != NULL)
-       {
-         len = nl - buf + 1;
-         status = mu_stream_write (hstream, buf, len, msg->hdr_buflen, NULL);
-         if (status != 0)
-           return status;
-         msg->hdr_buflen += len;
-         /* We detect an empty line .i.e "^\n$" this signal the end of the
-            header.  */
-         if (buf == nl)
-           msg->hdr_done = 1;
-         buf = nl + 1;
-         buflen -= len;
-       }
-    }
-
-  /* Message header is not complete but was not a full line.  */
-  if (!msg->hdr_done && buflen > 0)
-    {
-      mu_header_t header = NULL;
-      mu_stream_t hstream = NULL;
-      mu_message_get_header (msg, &header);
-      mu_header_get_stream (header, &hstream);
-      status = mu_stream_write (hstream, buf, buflen, msg->hdr_buflen, NULL);
-      if (status != 0)
-       return status;
-      msg->hdr_buflen += buflen;
-      buflen = 0;
-    }
-  else if (buflen > 0) /* In the body.  */
-    {
-      mu_stream_t bs;
-      mu_body_t body;
-      size_t written = 0;
-      if ((status = mu_message_get_body (msg, &body)) != 0 ||
-         (status = mu_body_get_stream (msg->body, &bs)) != 0)
-       {
-         msg->hdr_buflen = msg->hdr_done = 0;
-         return status;
-       }
-      if (off < (mu_off_t)msg->hdr_buflen)
-       off = 0;
-      else
-       off -= msg->hdr_buflen;
-      status = mu_stream_write (bs, buf, buflen, off, &written);
-      buflen -= written;
-    }
-  if (pnwrite)
-    *pnwrite = bufsize - buflen;
-  return status;
-}
-
-static int
-message_get_transport2 (mu_stream_t stream, mu_transport_t *pin,
-                       mu_transport_t *pout)
-{
-  mu_message_t msg = mu_stream_get_owner (stream);
-  mu_body_t body;
-  mu_stream_t is;
-
-  if (msg == NULL)
-    return EINVAL;
-  if (pout)
-    *pout = NULL;
-
-  /* Probably being lazy, then create a body for the stream.  */
-  if (msg->body == NULL)
-    {
-      int status = mu_body_create (&body, msg);
-      if (status != 0 )
-       return status;
-      msg->body = body;
-    }
-  else
-      body = msg->body;
-
-  mu_body_get_stream (body, &is);
-  return mu_stream_get_transport2 (is, pin, pout);
-}
-
-/* Implements the stream_stream_size () on the message stream.  */
-static int
-message_stream_size (mu_stream_t stream, mu_off_t *psize)
-{
-  mu_message_t msg = mu_stream_get_owner (stream);
-  size_t size;
-  int rc = mu_message_size (msg, &size); /* FIXME: should it get mu_off_t as
-                                            its 2nd argument */
-  if (rc == 0)
-    *psize = size;
-  return rc;
-}
-
-static int
-message_date (mu_envelope_t envelope, char *buf, size_t len, size_t *pnwrite)
-{
-  mu_message_t msg = mu_envelope_get_owner (envelope);
-  time_t t;
-  size_t n;
-
-  if (msg == NULL)
-    return EINVAL;
-
-  /* FIXME: extract the time from "Date:".  */
-
-  if (buf == NULL || len == 0)
-    {
-      n = MU_ENVELOPE_DATE_LENGTH;
-    }
-  else
-    {
-      char tmpbuf[MU_ENVELOPE_DATE_LENGTH+1];
-      t = time (NULL);
-      n = mu_strftime (tmpbuf, sizeof tmpbuf, 
-                       MU_ENVELOPE_DATE_FORMAT, localtime (&t));
-      n = mu_cpystr (buf, tmpbuf, len);
-    }
-  if (pnwrite)
-    *pnwrite = n;
-  return 0;
-}
-
-static int
-message_sender (mu_envelope_t envelope, char *buf, size_t len, size_t *pnwrite)
-{
-  mu_message_t msg = mu_envelope_get_owner (envelope);
-  mu_header_t header = NULL;
-  size_t n = 0;
-  int status;
-
-  if (msg == NULL)
-    return EINVAL;
-
-  /* Can it be extracted from the From:  */
-  mu_message_get_header (msg, &header);
-  status = mu_header_get_value (header, MU_HEADER_FROM, NULL, 0, &n);
-  if (status == 0 && n != 0)
-    {
-      char *sender;
-      mu_address_t address = NULL;
-      sender = calloc (1, n + 1);
-      if (sender == NULL)
-       return ENOMEM;
-      mu_header_get_value (header, MU_HEADER_FROM, sender, n + 1, NULL);
-      if (mu_address_create (&address, sender) == 0)
-       mu_address_get_email (address, 1, buf, n + 1, pnwrite);
-      free (sender);
-      mu_address_destroy (&address);
-      return 0;
-    }
-  else if (status == EAGAIN)
-    return status;
-
-  /* oops! We are still here */
-  {
-    struct mu_auth_data *auth = mu_get_auth_by_uid (getuid ());
-    const char *sender = auth ? auth->name : "unknown";
-    n = strlen (sender);
-    if (buf && len > 0)
-      {
-       len--; /* One for the null.  */
-       n = (n < len) ? n : len;
-       memcpy (buf, auth->name, n);
-       buf[n] = '\0';
-      }
-    if (auth)
-      mu_auth_data_free (auth);
-  }
-
-  if (pnwrite)
-    *pnwrite = n;
-  return 0;
-}
-
-static int
-message_header_fill (mu_header_t header, char *buffer, size_t buflen,
-                    mu_off_t off, size_t * pnread)
-{
-  int status = 0;
-  mu_message_t msg = mu_header_get_owner (header);
-  mu_stream_t stream = NULL;
-  size_t nread = 0;
-
-  /* Noop.  */
-  if (buffer == NULL || buflen == 0)
-    {
-      if (pnread)
-        *pnread = nread;
-      return 0;
-    }
-
-  if (!msg->hdr_done)
-    {
-      status = mu_message_get_stream (msg, &stream);
-      if (status == 0)
-       {
-         /* Position the file pointer and the buffer.  */
-         status = mu_stream_readline (stream, buffer, buflen, off, &nread);
-         /* Detect the end of the headers. */
-         if (nread  && buffer[0] == '\n' && buffer[1] == '\0')
-           {
-             msg->hdr_done = 1;
-           }
-         msg->hdr_buflen += nread;
-       }
-    }
-
-  if (pnread)
-    *pnread = nread;
-
-  return status;
-}
-
-static int
-message_body_read (mu_stream_t stream,  char *buffer, size_t n, mu_off_t off,
-                  size_t *pn)
-{
-  mu_body_t body = mu_stream_get_owner (stream);
-  mu_message_t msg = mu_body_get_owner (body);
-  size_t nread = 0;
-  mu_header_t header = NULL;
-  mu_stream_t bstream = NULL;
-  size_t size = 0;
-  int status;
-
-  mu_message_get_header (msg, &header);
-  status = mu_header_size (msg->header, &size);
-  if (status == 0)
-    {
-      mu_message_get_stream (msg, &bstream);
-      status = mu_stream_read (bstream, buffer, n, size + off, &nread);
-    }
-  if (pn)
-    *pn = nread;
-  return status;
-}
-
 int
 mu_message_save_to_mailbox (mu_message_t msg, 
                             mu_debug_t debug,
diff --git a/mailbox/message_stream.c b/mailbox/message_stream.c
index 98f022b..cfcd2dd 100644
--- a/mailbox/message_stream.c
+++ b/mailbox/message_stream.c
@@ -31,6 +31,7 @@
 
 #include <mailutils/types.h>
 #include <mailutils/address.h>
+#include <mailutils/alloc.h>
 #include <mailutils/envelope.h>
 #include <mailutils/message.h>
 #include <mailutils/header.h>
@@ -39,70 +40,92 @@
 #include <mailutils/mutil.h>
 #include <mailutils/errno.h>
 #include <mailutils/error.h>
+#include <mailutils/cctype.h>
 #include <mailutils/cstr.h>
+#include <mailutils/sys/message_stream.h>
 
-struct _mu_rfc822_stream
+
+static int
+_env_msg_date (mu_envelope_t envelope, char *buf, size_t len, size_t *pnwrite)
 {
-  mu_stream_t stream;  /* Actual stream */
-  char *envelope;
-  size_t envelope_length; 
-  size_t mark_offset;  /* Offset of the header separator */
-  size_t mark_length;  /* Length of the header separator (not counting the
-                         newline) */
-};
+  struct _mu_message_stream *str = mu_envelope_get_owner (envelope);
+  
+  if (!str || !str->date)
+    return EINVAL;
+  if (buf)
+    {
+      strncpy (buf, str->date, len);
+      buf[len-1] = 0;
+      if (pnwrite)
+       *pnwrite = len;
+    }
+  else if (!pnwrite)
+    return EINVAL;
+  else
+    *pnwrite = strlen (str->date);
+  return 0;
+}
 
 static int
-_mu_rfc822_read (mu_stream_t stream, char *optr, size_t osize,
-                mu_off_t offset, size_t *nbytes)
+_env_msg_sender (mu_envelope_t envelope, char *buf, size_t len,
+                size_t *pnwrite)
 {
-  struct _mu_rfc822_stream *s = mu_stream_get_owner (stream);
-
-  offset += s->envelope_length;
-  if (offset < s->mark_offset)
+  struct _mu_message_stream *str = mu_envelope_get_owner (envelope);
+  
+  if (!str || !str->from)
+    return EINVAL;
+  if (buf)
     {
-      if (offset + osize >= s->mark_offset)
-       osize = s->mark_offset - offset;
+      strncpy (buf, str->from, len);
+      buf[len-1] = 0;
+      if (pnwrite)
+       *pnwrite = len;
     }
+  else if (!pnwrite)
+    return EINVAL;
   else
-    offset += s->mark_length;
-  return mu_stream_read (s->stream, optr, osize, offset, nbytes);
+    *pnwrite = strlen (str->from);
+    
+  return 0;
 }
-  
+
+
 static int
-_mu_rfc822_readline (mu_stream_t stream, char *optr, size_t osize,
-                    mu_off_t offset, size_t *nbytes)
+_message_read (mu_stream_t stream, char *optr, size_t osize, size_t *nbytes)
 {
-  struct _mu_rfc822_stream *s = mu_stream_get_owner (stream);
-    
-  offset += s->envelope_length;
+  int rc;
+  struct _mu_message_stream *s = (struct _mu_message_stream*) stream;
+  mu_off_t offset = s->offset + s->envelope_length;
+  size_t rsize;
+  
   if (offset < s->mark_offset)
     {
       if (offset + osize >= s->mark_offset)
-       {
-         int rc;
-         size_t n;
-         size_t rdsize = s->mark_offset - offset + 1;
-
-         rc = mu_stream_readline (s->stream, optr, rdsize, offset, &n);
-         if (rc == 0)
-           {
-             if (nbytes)
-               *nbytes = n;
-           }
-         return rc;
-       }
+       osize = s->mark_offset - offset;
     }
   else
     offset += s->mark_length;
-
-  return mu_stream_readline (s->stream, optr, osize, offset, nbytes);
+  /* FIXME: Seeking each time before read is awkward. The streamref
+     should be modified to take care of it */
+  rc = mu_stream_seek (s->transport, offset, MU_SEEK_SET, NULL);
+  if (rc == 0)
+    rc = mu_stream_read (s->transport, optr, osize, &rsize);
+  if (rc == 0)
+    {
+      s->offset += rsize;
+      if (nbytes)
+       *nbytes = rsize;
+    }
+  else
+    s->stream.last_err = rc;
+  return rc;
 }
   
 static int
-_mu_rfc822_size (mu_stream_t stream, mu_off_t *psize)
+_message_size (mu_stream_t stream, mu_off_t *psize)
 {
-  struct _mu_rfc822_stream *s = mu_stream_get_owner (stream);
-  int rc = mu_stream_size (s->stream, psize);
+  struct _mu_message_stream *s = (struct _mu_message_stream*) stream;
+  int rc = mu_stream_size (s->transport, psize);
   
   if (rc == 0)
     *psize -= s->envelope_length + s->mark_length;
@@ -110,120 +133,8 @@ _mu_rfc822_size (mu_stream_t stream, mu_off_t *psize)
 }
   
 static int
-_mu_rfc822_open (mu_stream_t stream)
-{
-  struct _mu_rfc822_stream *s = mu_stream_get_owner (stream);
-  size_t offset, len;
-  char *buffer = NULL;
-  size_t bufsize = 0;
-  int rc;
-
-  offset = 0;
-  while ((rc = mu_stream_getline (s->stream, &buffer, &bufsize,
-                                 offset, &len)) == 0
-        && len > 0)
-    {
-      if (offset == 0 && memcmp (buffer, "From ", 5) == 0)
-       {
-         s->envelope_length = len;
-         s->envelope = strdup (buffer);
-         if (!s->envelope)
-           return ENOMEM;
-         s->envelope[len - 1] = 0;
-       }
-      else if (mu_mh_delim (buffer))
-       {
-         s->mark_offset = offset;
-         s->mark_length = len - 1; /* do not count the terminating newline */
-         break;
-       }
-
-      offset += len;
-    }
-  free (buffer);
-  return 0;
-}
-
-static int
-_mu_rfc822_close (mu_stream_t stream)
+scan_stream (mu_stream_t stream)
 {
-  struct _mu_rfc822_stream *s = mu_stream_get_owner (stream);
-  return mu_stream_close (s->stream);
-}
-
-static void
-_mu_rfc822_destroy (mu_stream_t stream)
-{
-  struct _mu_rfc822_stream *s = mu_stream_get_owner (stream);
-
-  free (s->envelope);
-  if (s->stream)
-    mu_stream_destroy (&s->stream, mu_stream_get_owner (s->stream));
-  free (s);
-}
-    
-int
-mu_rfc822_stream_create (mu_stream_t *stream, mu_stream_t src, int flags)
-{
-  struct _mu_rfc822_stream *s;
-  int rc;
-
-  if (!flags)
-    flags = MU_STREAM_READ;
-  if (flags != MU_STREAM_READ)
-    return EINVAL;
-
-  s = calloc (1, sizeof (*s));
-  if (s == NULL)
-    return ENOMEM;
-
-  s->stream = src;
-  
-  rc = mu_stream_create (stream, flags|MU_STREAM_NO_CHECK, s);
-  if (rc)
-    {
-      free (s);
-      return rc;
-    }
-  
-  mu_stream_set_open (*stream, _mu_rfc822_open, s);
-  mu_stream_set_close (*stream, _mu_rfc822_close, s);
-  mu_stream_set_destroy (*stream, _mu_rfc822_destroy, s);
-  mu_stream_set_readline (*stream, _mu_rfc822_readline, s);
-  mu_stream_set_read (*stream, _mu_rfc822_read, s);
-  mu_stream_set_size (*stream, _mu_rfc822_size, s);
-
-  return 0;  
-}
-
-
-
-/* *************************** MH draft message **************************** */
-
-static char *
-skipws (char *p, size_t off)
-{
-  int len;
-  for (p += off; *p && isspace (*p); p++)
-    ;
-  len = strlen (p);
-  if (len > 0 && p[len-1] == '\n')
-    p[len-1] = 0;
-  return p;
-}
-
-struct _mu_rfc822_message
-{
-  char *from;
-  char *date;
-  mu_off_t body_start;
-  mu_off_t body_end;
-};
-
-static int
-restore_envelope (mu_stream_t str, struct _mu_rfc822_message **pmenv)
-{
-  size_t offset = 0;
   char *from = NULL;
   char *env_from = NULL;
   char *env_date = NULL;
@@ -232,23 +143,23 @@ restore_envelope (mu_stream_t str, struct 
_mu_rfc822_message **pmenv)
   size_t bufsize = 0;
   size_t len;
   mu_off_t body_start, body_end;
-  struct _mu_rfc822_stream *s822 = mu_stream_get_owner (str);
+  struct _mu_message_stream *str = (struct _mu_message_stream *) stream;
 
-  if (s822->envelope)
+  if (str->envelope)
     {
-      char *s = s822->envelope + 5;
+      char *s = str->envelope + 5;
       char *p = strchr (s, ' ');
       size_t len;
 
       if (p)
        {
          len = p - s;
-         env_from = malloc (len + 1);
+         env_from = mu_alloc (len + 1);
          if (!env_from)
            return ENOMEM;
-         memcpy(env_from, s, len);
+         memcpy (env_from, s, len);
          env_from[len] = 0;
-         env_date = strdup (p + 1);
+         env_date = mu_strdup (p + 1);
          if (!env_date)
            {
              free (env_from);
@@ -256,34 +167,47 @@ restore_envelope (mu_stream_t str, struct 
_mu_rfc822_message **pmenv)
            }
        }
     }
-  
-  while ((rc = mu_stream_getline (str, &buffer, &bufsize, offset, &len)) == 0
+
+  rc = mu_stream_seek (stream, 0, MU_SEEK_SET, NULL);
+  if (rc)
+    return rc;
+  while ((rc = mu_stream_getline (stream, &buffer, &bufsize, &len)) == 0
         && len > 0)
     {
       if (buffer[0] == '\n')
        break;
-      offset += len;
 
       if (!env_from || !env_date)
        {
          if (!from && mu_c_strncasecmp (buffer, MU_HEADER_FROM,
                                         sizeof (MU_HEADER_FROM) - 1) == 0)
-           from = strdup (skipws (buffer, sizeof (MU_HEADER_FROM)));
+           
+           from = mu_strdup (mu_str_skip_class (buffer +
+                                                sizeof (MU_HEADER_FROM),
+                                                MU_CTYPE_SPACE));
          else if (!env_from
                   && mu_c_strncasecmp (buffer, MU_HEADER_ENV_SENDER,
                                        sizeof (MU_HEADER_ENV_SENDER) - 1) == 0)
-           env_from = strdup (skipws (buffer, sizeof (MU_HEADER_ENV_SENDER)));
+           env_from = mu_strdup (mu_str_skip_class (buffer +
+                                       sizeof (MU_HEADER_ENV_SENDER),
+                                                    MU_CTYPE_SPACE));
          else if (!env_date
                   && mu_c_strncasecmp (buffer, MU_HEADER_ENV_DATE,
                                        sizeof (MU_HEADER_ENV_DATE) - 1) == 0)
-           env_date = strdup (skipws (buffer, sizeof (MU_HEADER_ENV_DATE)));
+           env_date = mu_strdup (mu_str_skip_class (buffer +
+                                                 sizeof (MU_HEADER_ENV_DATE),
+                                                    MU_CTYPE_SPACE));
        }
     }
 
   free (buffer);
-  
-  body_start = offset + 1;
-  mu_stream_size (str, &body_end);
+
+  rc = mu_stream_seek (stream, 0, MU_SEEK_CUR, &body_start);
+  if (rc)
+    return rc;
+  else
+    body_start++;
+  mu_stream_size (stream, &body_end);
   
   if (!env_from)
     {
@@ -294,13 +218,14 @@ restore_envelope (mu_stream_t str, struct 
_mu_rfc822_message **pmenv)
          mu_address_create (&addr, from);
          if (!addr
              || mu_address_aget_email (addr, 1, &env_from))
-           env_from = strdup ("GNU-Mailutils");
+           env_from = mu_strdup ("GNU-Mailutils");
          mu_address_destroy (&addr);
        }
       else
-       env_from = strdup ("GNU-MH");
+       env_from = mu_strdup ("GNU-MH");
     }
-         
+  free (from);
+  
   if (!env_date)
     {
       struct tm *tm;
@@ -313,183 +238,200 @@ restore_envelope (mu_stream_t str, struct 
_mu_rfc822_message **pmenv)
       env_date = strdup (date);
     }
 
-  *pmenv = malloc (sizeof (**pmenv)
-                  + strlen (env_from)
-                  + strlen (env_date)
-                  + 2);
-  if (!*pmenv)
-    {
-      free (env_from);
-      free (env_date);
-      return ENOMEM;
-    }
-  
-  (*pmenv)->from = (char*) (*pmenv + 1);
-  (*pmenv)->date = (char*) ((*pmenv)->from + strlen (env_from) + 1);
-
-  strcpy ((*pmenv)->from, env_from);
-  strcpy ((*pmenv)->date, env_date);
+  str->from = env_from;
+  str->date = env_date;
 
-  (*pmenv)->body_start = body_start;
-  (*pmenv)->body_end = body_end;
+  str->body_start = body_start;
+  str->body_end = body_end;
   
-  free (env_from);
-  free (env_date);
-  free (from);
   return 0;
 }
 
 static int
-_env_msg_date (mu_envelope_t envelope, char *buf, size_t len, size_t *pnwrite)
+_message_open (mu_stream_t stream)
 {
-  mu_message_t msg = mu_envelope_get_owner (envelope);
-  struct _mu_rfc822_message *env = mu_message_get_owner (msg);
-  
-  if (!env || !env->date)
-    return EINVAL;
-  if (buf)
+  struct _mu_message_stream *s = (struct _mu_message_stream*) stream;
+  size_t offset, len;
+  char *buffer = NULL;
+  size_t bufsize = 0;
+  int rc;
+
+  offset = 0;
+  mu_stream_seek (s->transport, 0, MU_SEEK_SET, NULL);
+  while ((rc = mu_stream_getline (s->transport, &buffer, &bufsize,
+                                 &len)) == 0
+        && len > 0)
     {
-      strncpy (buf, env->date, len);
-      buf[len-1] = 0;
-      if (pnwrite)
-       *pnwrite = len;
+      if (offset == 0 && memcmp (buffer, "From ", 5) == 0)
+       {
+         s->envelope_length = len;
+         s->envelope = mu_strdup (buffer);
+         if (!s->envelope)
+           return ENOMEM;
+         s->envelope[len - 1] = 0;
+       }
+      else if (mu_mh_delim (buffer))
+       {
+         s->mark_offset = offset;
+         s->mark_length = len - 1; /* do not count the terminating newline */
+         break;
+       }
+
+      offset += len;
     }
-  else if (!pnwrite)
-    return EINVAL;
-  else
-    *pnwrite = strlen (env->date);
-  return 0;
+  free (buffer);
+
+  return scan_stream (s->transport);
 }
 
 static int
-_env_msg_sender (mu_envelope_t envelope, char *buf, size_t len,
-                size_t *pnwrite)
+_message_close (mu_stream_t stream)
 {
-  mu_message_t msg = mu_envelope_get_owner (envelope);
-  struct _mu_rfc822_message *env = mu_message_get_owner (msg);
-  
-  if (!env || !env->from)
-    return EINVAL;
-  if (buf)
-    {
-      strncpy (buf, env->from, len);
-      buf[len-1] = 0;
-      if (pnwrite)
-       *pnwrite = len;
-    }
-  else if (!pnwrite)
-    return EINVAL;
-  else
-    *pnwrite = strlen (env->from);
-    
-  return 0;
+  struct _mu_message_stream *s = (struct _mu_message_stream*) stream;
+  return s->stream.last_err = mu_stream_close (s->transport);
 }
 
-static int
-_body_size (mu_body_t body, size_t *size)
+static void
+_message_done (mu_stream_t stream)
 {
-  mu_message_t msg = mu_body_get_owner (body);
-  struct _mu_rfc822_message *mp = mu_message_get_owner (msg);
+  struct _mu_message_stream *s = (struct _mu_message_stream*) stream;
 
-  if (size)
-    *size = mp->body_end - mp->body_start;
+  free (s->envelope);
+  free (s->date);
+  free (s->from);
+  mu_stream_destroy (&s->transport);
+}
+
+static int
+_message_seek (struct _mu_stream *stream, mu_off_t off, mu_off_t *presult)
+{ 
+  struct _mu_message_stream *s = (struct _mu_message_stream*) stream;
+  mu_off_t size;
+
+  mu_stream_size (stream, &size);
+  if (off < 0 || off >= size)
+    return ESPIPE;
+  s->offset = off;
+  *presult = off;
   return 0;
 }
 
-static int 
-_body_read (mu_stream_t stream, char *optr, size_t osize,
-           mu_off_t offset, size_t *nbytes)
+const char *
+_message_error_string (struct _mu_stream *stream, int rc)
 {
-  mu_body_t body = mu_stream_get_owner (stream);
-  mu_message_t msg = mu_body_get_owner (body);
-  struct _mu_rfc822_message *mp = mu_message_get_owner (msg);
-  mu_stream_t str;
-
-  mu_message_get_stream (msg, &str);
-  return mu_stream_read (str, optr, osize, mp->body_start + offset, nbytes);
+  struct _mu_message_stream *str = (struct _mu_message_stream*) stream;
+  return mu_stream_strerror (str->transport, rc);
 }
 
-static int
-_body_readline (mu_stream_t stream, char *optr, size_t osize,
-               mu_off_t offset, size_t *nbytes)
+int
+mu_message_stream_create (mu_stream_t *stream, mu_stream_t src, int flags)
 {
-  mu_body_t body = mu_stream_get_owner (stream);
-  mu_message_t msg = mu_body_get_owner (body);
-  struct _mu_rfc822_message *mp = mu_message_get_owner (msg);
-  mu_stream_t str;
+  struct _mu_message_stream *s;
+  int sflag;
+  int rc;
+  
+  mu_stream_get_flags (src, &sflag);
+  sflag &= MU_STREAM_SEEK;
+  
+  if (!flags)
+    flags = MU_STREAM_READ;
+  if (flags & (MU_STREAM_WRITE|MU_STREAM_CREAT|MU_STREAM_APPEND))
+    return EINVAL;
+  s = (struct _mu_message_stream *) _mu_stream_create (sizeof (*s),
+                                                      flags | sflag);
+  if (!s)
+    return ENOMEM;
 
-  mu_message_get_stream (msg, &str);
-  return mu_stream_readline (str, optr, osize,
-                            mp->body_start + offset, nbytes);
+  rc = mu_streamref_create (&s->transport, src);
+  if (rc)
+    {
+      free (s);
+      return rc;
+    }
+  s->stream.open = _message_open;
+  s->stream.close = _message_close;
+  s->stream.done = _message_done;
+  s->stream.read = _message_read;
+  s->stream.size = _message_size;
+  s->stream.seek = _message_seek;
+  s->stream.error_string = _message_error_string;
+  return 0;  
 }
 
+
+/* *************************** MH draft message **************************** */
+
+
+
 static int
-_body_stream_size (mu_stream_t stream, mu_off_t *psize)
+_body_obj_size (mu_body_t body, size_t *size)
 {
-  mu_body_t body = mu_stream_get_owner (stream);
   mu_message_t msg = mu_body_get_owner (body);
-  struct _mu_rfc822_message *mp = mu_message_get_owner (msg);
-  
-  if (psize)
-    *psize = mp->body_end - mp->body_start;
-  return 0;
-}
+  struct _mu_message_stream *str = mu_message_get_owner (msg);
 
-static int
-_body_stream_flush (mu_stream_t str MU_ARG_UNUSED)
-{
+  if (size)
+    *size = str->body_end - str->body_start;
   return 0;
 }
 
+
+
 int
 mu_stream_to_message (mu_stream_t instream, mu_message_t *pmsg)
 {
-  struct _mu_rfc822_message *mp;
   mu_envelope_t env;
   mu_message_t msg;
   mu_body_t body;
   mu_stream_t bstream;
   mu_stream_t draftstream;
   int rc;
+  struct _mu_message_stream *sp;
   
-  if ((rc = mu_rfc822_stream_create (&draftstream, instream, 0)))
+  /* FIXME: Perhaps MU_STREAM_NO_CLOSE is needed */
+  if ((rc = mu_message_stream_create (&draftstream, instream, 0)))
     return rc;
 
   if ((rc = mu_stream_open (draftstream)))
     {
-      mu_stream_destroy (&draftstream, mu_stream_get_owner (draftstream));
+      mu_stream_destroy (&draftstream);
       return rc;
     }
 
-  if ((rc = restore_envelope (draftstream, &mp)
-       || (rc = mu_message_create (&msg, mp))))
+  if ((rc = mu_message_create (&msg, draftstream)))
     {
-      mu_stream_destroy (&draftstream, mu_stream_get_owner (draftstream));
+      mu_stream_destroy (&draftstream);
       return rc;
     }
   
-  mu_message_set_stream (msg, draftstream, mp);
+  mu_message_set_stream (msg, draftstream, draftstream);
   
-  if ((rc = mu_envelope_create (&env, msg)))
+  if ((rc = mu_envelope_create (&env, draftstream)))
     {
-      mu_stream_destroy (&draftstream, mu_stream_get_owner (draftstream));
+      mu_message_destroy (&msg, draftstream);
+      mu_stream_destroy (&draftstream);
       return rc;
     }
   
   mu_envelope_set_date (env, _env_msg_date, msg);
   mu_envelope_set_sender (env, _env_msg_sender, msg);
-  mu_message_set_envelope (msg, env, mp);
+  mu_message_set_envelope (msg, env, draftstream);
 
   mu_body_create (&body, msg);
-  mu_stream_create (&bstream,  MU_STREAM_RDWR | MU_STREAM_SEEKABLE, body);
-
-  mu_stream_set_read (bstream, _body_read, body);
-  mu_stream_set_readline (bstream, _body_readline, body);
-  mu_stream_set_size (bstream, _body_stream_size, body);
-  mu_stream_set_flush (bstream, _body_stream_flush, body);
+  /* FIXME: It would be cleaner to use ioctl here */
+  sp = (struct _mu_message_stream *) draftstream;
+  rc = mu_streamref_create_abridged (&bstream, instream,
+                                    sp->body_start, sp->body_end);
+  if (rc)
+    {
+      mu_body_destroy (&body, msg);
+      mu_message_destroy (&msg, draftstream);
+      mu_stream_destroy (&draftstream);
+      return rc;
+    }
+  
   mu_body_set_stream (body, bstream, msg);
-  mu_body_set_size (body, _body_size, msg);
-  mu_message_set_body (msg, body, mp);
+  mu_body_set_size (body, _body_obj_size, msg);
+  mu_message_set_body (msg, body, draftstream);
 
   *pmsg = msg;
   return 0;
diff --git a/mailbox/mime.c b/mailbox/mime.c
index d2f6aab..2f90b64 100644
--- a/mailbox/mime.c
+++ b/mailbox/mime.c
@@ -39,13 +39,18 @@
 #include <mailutils/header.h>
 #include <mailutils/errno.h>
 #include <mailutils/mutil.h>
-#include <mime0.h>
+
+#include <mailutils/sys/mime.h>
+#include <mailutils/sys/stream.h>
 
 #ifndef TRUE
 #define TRUE (1)
 #define FALSE (0)
 #endif
 
+#define CT_MULTIPART_DIGEST "multipart/digest"
+#define CT_MULTIPART_DIGEST_LEN (sizeof (CT_MULTIPART_DIGEST) - 1)
+
 /* TODO:
  *  Need to prevent re-entry into mime lib, but allow non-blocking re-entry
  *  into lib.
@@ -55,9 +60,8 @@ static int
 _mime_is_multipart_digest (mu_mime_t mime)
 {
   if (mime->content_type)
-    return (mu_c_strncasecmp
-           ("multipart/digest", mime->content_type,
-            strlen ("multipart/digest")) ? 0 : 1);
+    return mu_c_strncasecmp (CT_MULTIPART_DIGEST, mime->content_type,
+                            CT_MULTIPART_DIGEST_LEN) == 0;
   return 0;
 }
 
@@ -91,7 +95,7 @@ _mime_append_part (mu_mime_t mime, mu_message_t msg, int 
offset, int len, int li
        {
          if ((ret =
               mu_header_create (&hdr, mime->header_buf,
-                                mime->header_length, mime_part->msg)) != 0)
+                                mime->header_length)) != 0)
            {
              mu_message_destroy (&mime_part->msg, mime_part);
              free (mime_part);
@@ -282,9 +286,10 @@ _mime_parse_mpart_message (mu_mime_t mime)
   mb_lines = mime->body_lines;
   blength = strlen (mime->boundary);
 
+  mu_stream_seek (mime->stream, mime->cur_offset, MU_SEEK_SET, NULL);
   while ((ret =
          mu_stream_read (mime->stream, mime->cur_buf, mime->buf_size,
-                      mime->cur_offset, &nbytes)) == 0 && nbytes)
+                         &nbytes)) == 0 && nbytes)
     {
       cp = mime->cur_buf;
       while (nbytes)
@@ -414,63 +419,6 @@ _mime_parse_mpart_message (mu_mime_t mime)
 /*------ Mime message functions for READING a multipart message -----*/
 
 static int
-_mimepart_body_stream_size (mu_stream_t stream, mu_off_t *psize)
-{
-  size_t s;
-  mu_body_t body = mu_stream_get_owner (stream);
-  int rc =  mu_body_size (body, &s);
-  *psize = s;
-  return rc;
-}
-
-static int
-_mimepart_body_read (mu_stream_t stream,
-                    char *buf, size_t buflen, mu_off_t off,
-                    size_t *nbytes)
-{
-  mu_body_t          body = mu_stream_get_owner (stream);
-  mu_message_t       msg = mu_body_get_owner (body);
-  struct _mime_part *mime_part = mu_message_get_owner (msg);
-  size_t          read_len;
-  int             ret = 0;
-
-  if (nbytes == NULL)
-    return MU_ERR_OUT_NULL;
-
-  *nbytes = 0;
-  read_len = (int) mime_part->len - (int) off;
-  if (read_len <= 0)
-    {
-      if (!mu_stream_is_seekable (mime_part->mime->stream))
-       {
-         while ((ret =
-                 mu_stream_read (mime_part->mime->stream,
-                              buf, buflen,
-                              mime_part->offset + off,
-                              nbytes)) == 0 && *nbytes)
-           off += *nbytes;
-         *nbytes = 0;
-       }
-      return ret;
-    }
-  read_len = (buflen <= read_len) ? buflen : read_len;
-
-  return mu_stream_read (mime_part->mime->stream, buf, read_len,
-                     mime_part->offset + off, nbytes);
-}
-
-static int
-_mimepart_body_transport (mu_stream_t stream, mu_transport_t *tr1,
-                         mu_transport_t *tr2)
-{
-  mu_body_t          body = mu_stream_get_owner (stream);
-  mu_message_t       msg = mu_body_get_owner (body);
-  struct _mime_part *mime_part = mu_message_get_owner (msg);
-
-  return mu_stream_get_transport2 (mime_part->mime->stream, tr1, tr2);
-}
-
-static int
 _mimepart_body_size (mu_body_t body, size_t *psize)
 {
   mu_message_t       msg = mu_body_get_owner (body);
@@ -587,27 +535,57 @@ _mime_set_content_type (mu_mime_t mime)
   return ret;
 }
 
-#define ADD_CHAR(buf, c, offset, buflen, nbytes) do {\
- *(buf)++ = c;\
- (offset)++;\
- (nbytes)++;\
- if (--(buflen) == 0) return 0;\
-} while (0)
-
+
 static int
-_mime_body_read (mu_stream_t stream, char *buf, size_t buflen, mu_off_t off,
-                size_t *nbytes)
+_mime_part_size (mu_mime_t mime, size_t *psize)
 {
-  mu_body_t          body = mu_stream_get_owner (stream);
-  mu_message_t       msg = mu_body_get_owner (body);
-  mu_mime_t          mime = mu_message_get_owner (msg);
-  int                ret = 0;
-  size_t             part_nbytes = 0;
-  mu_stream_t        msg_stream = NULL;
+  int i, ret;
+  size_t size, total = 0;
 
   if (mime->nmtp_parts == 0)
     return EINVAL;
 
+  if ((ret = _mime_set_content_type (mime)) != 0)
+    return ret;
+  for (i = 0; i < mime->nmtp_parts; i++)
+    {
+      mu_message_size (mime->mtp_parts[i]->msg, &size);
+      total += size;
+      if (mime->nmtp_parts > 1)        /* boundary line */
+       total += strlen (mime->boundary) + 3;
+    }
+  if (mime->nmtp_parts > 1)    /* ending boundary line */
+    total += 2;
+  *psize = total;
+  return 0;
+}
+
+
+struct _mime_body_stream
+{
+  struct _mu_stream stream;
+  mu_mime_t mime;
+};
+
+static int
+_mime_body_stream_size (mu_stream_t stream, mu_off_t *psize)
+{
+  struct _mime_body_stream *mstr = (struct _mime_body_stream *)stream;
+  mu_mime_t mime = mstr->mime;
+  size_t sz;
+  int rc = _mime_part_size (mime, &sz);
+  if (rc == 0)
+    *psize = sz;
+  return rc;
+}
+
+/* FIXME: The seek method is defective */
+static int
+_mime_body_stream_seek (mu_stream_t stream, mu_off_t off, mu_off_t *presult)
+{
+  struct _mime_body_stream *mstr = (struct _mime_body_stream *)stream;
+  mu_mime_t mime = mstr->mime;
+
   if (off == 0)
     {                          /* reset message */
       mime->cur_offset = 0;
@@ -620,18 +598,47 @@ _mime_body_read (mu_stream_t stream, char *buf, size_t 
buflen, mu_off_t off,
 
   if (off != mime->cur_offset)
     return ESPIPE;
+  *presult = off;
+  return 0;
+}
 
-  if (nbytes)
-    *nbytes = 0;
+#define ADD_CHAR(buf, c, offset, buflen, total, nbytes)        \
+  do                                                   \
+    {                                                  \
+      *(buf)++ = c;                                    \
+      (offset)++;                                      \
+      (total)++;                                       \
+      if (--(buflen) == 0)                             \
+       {                                               \
+         *(nbytes) = total;                            \
+         return 0;                                     \
+       }                                               \
+    }                                                  \
+  while (0)
 
+static int
+_mime_body_stream_read (mu_stream_t stream, char *buf, size_t buflen, size_t 
*nbytes)
+{
+  struct _mime_body_stream *mstr = (struct _mime_body_stream *)stream;
+  mu_mime_t mime = mstr->mime;
+  int                ret = 0;
+  size_t             total = 0;
+  
+  if (mime->nmtp_parts == 0)
+    return EINVAL;
+  
   if ((ret = _mime_set_content_type (mime)) == 0)
     {
       do
        {
+         size_t             part_nbytes = 0;
+
+         if (buflen == 0)
+           break;
          if (mime->nmtp_parts > 1)
            {
-             int             len;
-
+             size_t len;
+             
              if (mime->flags & MIME_INSERT_BOUNDARY)
                {
                  if ((mime->flags & MIME_ADDING_BOUNDARY) == 0)
@@ -645,104 +652,150 @@ _mime_body_read (mu_stream_t stream, char *buf, size_t 
buflen, mu_off_t off,
                  while (mime->preamble)
                    {
                      mime->preamble--;
-                     ADD_CHAR (buf, '-', mime->cur_offset, buflen, *nbytes);
+                     ADD_CHAR (buf, '-', mime->cur_offset, buflen,
+                               total, nbytes);
                    }
                  len = strlen (mime->boundary) - mime->boundary_len;
                  while (mime->boundary_len)
                    {
                      mime->boundary_len--;
                      ADD_CHAR (buf,
-                               mime->
-                               boundary
-                               [len++], mime->cur_offset, buflen, *nbytes);
+                               mime->boundary[len++],
+                               mime->cur_offset, buflen,
+                               total, nbytes);
                    }
                  while (mime->postamble)
                    {
                      mime->postamble--;
-                     ADD_CHAR (buf, '-', mime->cur_offset, buflen, *nbytes);
+                     ADD_CHAR (buf, '-', mime->cur_offset, buflen,
+                               total, nbytes);
                    }
                  mime->flags &=
                    ~(MIME_INSERT_BOUNDARY | MIME_ADDING_BOUNDARY);
                  mime->part_offset = 0;
-                 ADD_CHAR (buf, '\n', mime->cur_offset, buflen, *nbytes);
+                 ADD_CHAR (buf, '\n', mime->cur_offset, buflen,
+                           total, nbytes);
+               }
+
+             if (!mime->part_stream)
+               {
+                 if (mime->cur_part >= mime->nmtp_parts)
+                   {
+                     *nbytes = total;
+                     return 0;
+                   }
+                 ret = mu_message_get_streamref 
(mime->mtp_parts[mime->cur_part]->msg,
+                                                 &mime->part_stream);
                }
-             if (mime->cur_part >= mime->nmtp_parts)
-               return 0;
-             mu_message_get_stream (mime->mtp_parts[mime->cur_part]->msg,
-                                    &msg_stream);
            }
-         else
+         else if (!mime->part_stream)
            {
-             mu_body_t          part_body;
+             mu_body_t part_body;
 
              if (mime->cur_part >= mime->nmtp_parts)
-               return 0;
+               {
+                 *nbytes = total;
+                 return 0;
+               }
              mu_message_get_body (mime->mtp_parts[mime->cur_part]->msg,
                                   &part_body);
-             mu_body_get_stream (part_body, &msg_stream);
+             ret = mu_body_get_streamref (part_body, &mime->part_stream);
            }
-         ret =
-           mu_stream_read (msg_stream, buf, buflen,
-                        mime->part_offset, &part_nbytes);
-         if (part_nbytes)
+         if (ret)
+           break;
+         ret = mu_stream_seek (mime->part_stream, mime->part_offset,
+                               MU_SEEK_SET, NULL);
+         if (ret)
            {
-             mime->part_offset += part_nbytes;
-             mime->cur_offset += part_nbytes;
-             if (nbytes)
-               *nbytes += part_nbytes;
+             mu_stream_destroy (&mime->part_stream);
+             break;
            }
-         if (ret == 0 && part_nbytes == 0)
+         while (buflen > 0 &&
+                (ret = mu_stream_read (mime->part_stream, buf, buflen,
+                                       &part_nbytes)) == 0)
            {
-             mime->flags |= MIME_INSERT_BOUNDARY;
-             mime->cur_part++;
-             ADD_CHAR (buf, '\n', mime->cur_offset, buflen, *nbytes);
+             if (part_nbytes)
+               {
+                 mime->part_offset += part_nbytes;
+                 mime->cur_offset += part_nbytes;
+                 total += part_nbytes;
+                 buflen -= part_nbytes;
+                 buf += part_nbytes;
+               }
+             else 
+               {
+                 mu_stream_destroy (&mime->part_stream);
+                 mime->flags |= MIME_INSERT_BOUNDARY;
+                 mime->cur_part++;
+                 ADD_CHAR (buf, '\n', mime->cur_offset, buflen,
+                           total, nbytes);
+                 break;
+               }
            }
        }
-      while (ret == 0 && part_nbytes == 0
-            && mime->cur_part <= mime->nmtp_parts);
+      while (ret == 0 && mime->cur_part <= mime->nmtp_parts);
     }
+  if (ret)
+    mu_stream_destroy (&mime->part_stream);
+  
+  *nbytes = total;
   return ret;
 }
 
 static int
-_mime_body_transport (mu_stream_t stream, mu_transport_t *tr1,
-                     mu_transport_t *tr2)
+_mime_body_stream_ioctl (mu_stream_t stream, int code, void *arg)
 {
-  mu_body_t          body = mu_stream_get_owner (stream);
-  mu_message_t       msg = mu_body_get_owner (body);
-  mu_mime_t          mime = mu_message_get_owner (msg);
-  mu_stream_t        msg_stream = NULL;
+  struct _mime_body_stream *mstr = (struct _mime_body_stream *)stream;
+  mu_mime_t mime = mstr->mime;
+  mu_stream_t msg_stream;
+  int rc;
+  
+  switch (code)
+    {
+    case MU_IOCTL_GET_TRANSPORT:
+      if (!arg)
+       return EINVAL;
+      
+      if (mime->nmtp_parts == 0 || mime->cur_offset == 0)
+       return EINVAL;
+      rc = mu_message_get_streamref (mime->mtp_parts[mime->cur_part]->msg,
+                                    &msg_stream);
+      if (rc)
+       break;
+      rc = mu_stream_ioctl (msg_stream, code, arg);
+      mu_stream_destroy (&msg_stream);
+      break;
 
-  if (mime->nmtp_parts == 0 || mime->cur_offset == 0)
-    return EINVAL;
-  mu_message_get_stream (mime->mtp_parts[mime->cur_part]->msg, &msg_stream);
-  return mu_stream_get_transport2 (msg_stream, tr1, tr2);
+    default:
+      rc = EINVAL;
+    }
+  return rc;
 }
 
 static int
+create_mime_body_stream (mu_stream_t *pstr, mu_mime_t mime)
+{
+  struct _mime_body_stream *sp =
+    (struct _mime_body_stream *)_mu_stream_create (sizeof (*sp),
+                                                  MU_STREAM_READ | 
MU_STREAM_SEEK);
+  if (!sp)
+    return ENOMEM;
+  sp->stream.read = _mime_body_stream_read;
+  sp->stream.seek = _mime_body_stream_seek;
+  sp->stream.ctl = _mime_body_stream_ioctl;
+  sp->stream.size = _mime_body_stream_size;
+  sp->mime = mime;
+  *pstr = (mu_stream_t) sp;
+  return 0;
+}
+
+
+static int
 _mime_body_size (mu_body_t body, size_t *psize)
 {
   mu_message_t       msg = mu_body_get_owner (body);
   mu_mime_t          mime = mu_message_get_owner (msg);
-  int                i, ret;
-  size_t             size;
-
-  if (mime->nmtp_parts == 0)
-    return EINVAL;
-
-  if ((ret = _mime_set_content_type (mime)) != 0)
-    return ret;
-  for (i = 0; i < mime->nmtp_parts; i++)
-    {
-      mu_message_size (mime->mtp_parts[i]->msg, &size);
-      *psize += size;
-      if (mime->nmtp_parts > 1)        /* boundary line */
-       *psize += strlen (mime->boundary) + 3;
-    }
-  if (mime->nmtp_parts > 1)    /* ending boundary line */
-    *psize += 2;
-
-  return 0;
+  return _mime_part_size (mime, psize);
 }
 
 static int
@@ -815,7 +868,7 @@ mu_mime_create (mu_mime_t *pmime, mu_message_t msg, int 
flags)
              mime->buf_size = MIME_DFLT_BUF_SIZE;
              mime->line_size = MIME_MAX_HDR_LEN;
              mu_message_get_body (msg, &body);
-             mu_body_get_stream (body, &(mime->stream));
+             mu_body_get_streamref (body, &mime->stream);
            }
        }
     }
@@ -860,6 +913,8 @@ mu_mime_destroy (mu_mime_t *pmime)
            }
          free (mime->mtp_parts);
        }
+      mu_stream_destroy (&mime->stream);
+      mu_stream_destroy (&mime->part_stream);
       if (mime->msg && mime->flags & MIME_NEW_MESSAGE)
        mu_message_destroy (&mime->msg, mime);
       if (mime->content_type)
@@ -901,19 +956,16 @@ mu_mime_get_part (mu_mime_t mime, size_t part, 
mu_message_t *msg)
              mu_body_set_size (body, _mimepart_body_size, mime_part->msg);
              mu_body_set_lines (body, _mimepart_body_lines, mime_part->msg);
              mu_stream_get_flags (mime->stream, &flags);
-             if ((ret =
-                  mu_stream_create (&stream,
-                                 MU_STREAM_READ | (flags &
-                                                   (MU_STREAM_SEEKABLE
-                                                    | MU_STREAM_NONBLOCK)),
-                                 body)) == 0)
+             ret = mu_streamref_create_abridged (&stream, mime->stream,
+                                                 mime_part->offset,
+                                                 mime_part->offset +
+                                                   mime_part->len - 1);
+             if (ret == 0)
                {
-                 mu_stream_set_read (stream, _mimepart_body_read, body);
-                 mu_stream_set_get_transport2 (stream,
-                                               _mimepart_body_transport,
-                                               body);
-                 mu_stream_set_size (stream, _mimepart_body_stream_size,
-                                     body);
+                 mu_stream_set_flags (stream,
+                                      MU_STREAM_READ | (flags &
+                                                        (MU_STREAM_SEEK
+                                                         | 
MU_STREAM_NONBLOCK)));
                  mu_body_set_stream (body, stream, mime_part->msg);
                  mu_message_set_body (mime_part->msg, body, mime_part);
                  mime_part->body_created = 1;
@@ -973,7 +1025,7 @@ mu_mime_get_message (mu_mime_t mime, mu_message_t *msg)
        return EINVAL;
       if ((ret = mu_message_create (&mime->msg, mime)) == 0)
        {
-         if ((ret = mu_header_create (&mime->hdrs, NULL, 0, mime->msg)) == 0)
+         if ((ret = mu_header_create (&mime->hdrs, NULL, 0)) == 0)
            {
              mu_message_set_header (mime->msg, mime->hdrs, mime);
              mu_header_set_value (mime->hdrs, MU_HEADER_MIME_VERSION, "1.0",
@@ -985,15 +1037,9 @@ mu_mime_get_message (mu_mime_t mime, mu_message_t *msg)
                      mu_message_set_body (mime->msg, body, mime);
                      mu_body_set_size (body, _mime_body_size, mime->msg);
                      mu_body_set_lines (body, _mime_body_lines, mime->msg);
-                     if ((ret =
-                          mu_stream_create (&body_stream,
-                                            MU_STREAM_READ, body)) == 0)
+                     ret = create_mime_body_stream (&body_stream, mime);
+                     if (ret == 0)
                        {
-                         mu_stream_set_read (body_stream, _mime_body_read,
-                                             body);
-                         mu_stream_set_get_transport2 (body_stream,
-                                                       _mime_body_transport,
-                                                       body);
                          mu_body_set_stream (body, body_stream, mime->msg);
                          *msg = mime->msg;
                          return 0;
diff --git a/mailbox/mimehdr.c b/mailbox/mimehdr.c
index 731e485..0314734 100644
--- a/mailbox/mimehdr.c
+++ b/mailbox/mimehdr.c
@@ -508,19 +508,19 @@ mu_mimehdr_decode_param (const char *value, int flags,
                  size_t total = 0, pos;
                  size_t nbytes;
 
-                 rc = mu_memory_stream_create (&instr, 0, 0);
+                 rc = mu_memory_stream_create (&instr, 0);
                  if (rc)
                    break;
-                 rc = mu_stream_write (instr, data, strlen (data), 0, NULL);
+                 rc = mu_stream_write (instr, data, strlen (data), NULL);
                  if (rc)
                    break;
 
-                 rc = mu_memory_stream_create (&outstr, 0, 0);
+                 rc = mu_memory_stream_create (&outstr, 0);
                  if (rc)
                    break;
                  
                  rc = mu_filter_iconv_create (&cvt, instr, source_cs, charset,
-                                              MU_STREAM_NO_CLOSE,
+                                              0,
                                               mu_default_fallback_mode);
                  if (rc)
                    break;
@@ -529,11 +529,11 @@ mu_mimehdr_decode_param (const char *value, int flags,
                  if (rc)
                    break;
 
-                 while (mu_stream_sequential_read (cvt, iobuf, sizeof (iobuf),
-                                                   &nbytes) == 0
+                 while (mu_stream_read (cvt, iobuf, sizeof (iobuf),
+                                        &nbytes) == 0
                         && nbytes)
                    {
-                     rc = mu_stream_sequential_write (outstr, iobuf, nbytes);
+                     rc = mu_stream_write (outstr, iobuf, nbytes, NULL);
                      if (rc)
                        break;
                      total += nbytes;
@@ -549,10 +549,10 @@ mu_mimehdr_decode_param (const char *value, int flags,
                      break;
                    }
 
-                 mu_stream_seek (outstr, 0, SEEK_SET);
+                 mu_stream_seek (outstr, 0, MU_SEEK_SET, NULL);
                  pos = 0;
-                 while (mu_stream_sequential_read (outstr, outval + pos,
-                                                   total - pos, &nbytes) == 0
+                 while (mu_stream_read (outstr, outval + pos,
+                                        total - pos, &nbytes) == 0
                         && nbytes)
                    pos += nbytes;
                  outval[pos] = 0;
@@ -560,11 +560,11 @@ mu_mimehdr_decode_param (const char *value, int flags,
              while (0);
              
              mu_stream_close (cvt);
-             mu_stream_destroy (&cvt, mu_stream_get_owner (cvt));
+             mu_stream_destroy (&cvt);
              mu_stream_close (instr);
-             mu_stream_destroy (&instr, mu_stream_get_owner (instr));
+             mu_stream_destroy (&instr);
              mu_stream_close (outstr);
-             mu_stream_destroy (&outstr, mu_stream_get_owner (outstr));
+             mu_stream_destroy (&outstr);
              
              free (decoded);
          
diff --git a/mailbox/monitor.c b/mailbox/monitor.c
index 55c94a9..45e7dc9 100644
--- a/mailbox/monitor.c
+++ b/mailbox/monitor.c
@@ -34,7 +34,7 @@
 #include <errno.h>
 #include <stdlib.h>
 
-#include <monitor0.h>
+#include <mailutils/sys/monitor.h>
 #include <mailutils/errno.h>
 
 #ifdef WITH_PTHREAD
diff --git a/mailbox/msgscan.c b/mailbox/msgscan.c
new file mode 100644
index 0000000..dbbafed
--- /dev/null
+++ b/mailbox/msgscan.c
@@ -0,0 +1,106 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+
+   GNU Mailutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GNU Mailutils is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GNU Mailutils.  If not, see <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <mailutils/types.h>
+#include <mailutils/stream.h>
+#include <mailutils/message.h>
+#include <mailutils/attribute.h>
+#include <mailutils/cstr.h>
+
+int
+mu_stream_scan_message (mu_stream_t stream, struct mu_message_scan *sp)
+{
+  char buf[1024];
+  mu_off_t off;
+  size_t n;
+  int status;
+  int in_header = 1;
+  size_t hlines = 0;
+  size_t blines = 0;
+  size_t body_start = 0;
+  int attr_flags = 0;
+  unsigned long uidvalidity = 0;
+  
+  if (sp->flags & MU_SCAN_SEEK)
+    {
+      status = mu_stream_seek (stream, sp->message_start, MU_SEEK_SET, NULL);
+      if (status)
+       return status;
+    }
+  
+  off = 0;
+  while (1)
+    {
+      size_t rdsize;
+      
+      status = mu_stream_readline (stream, buf, sizeof (buf), &n);
+      if (status || n == 0)
+       break;
+      
+      if (sp->flags & MU_SCAN_SIZE)
+       {
+         rdsize = sp->message_size - off;
+         if (n > rdsize)
+           n = rdsize;
+       }
+      
+      if (in_header)
+       {
+         if (buf[0] == '\n')
+           {
+             in_header = 0;
+             body_start = off + 1;
+           }
+         if (buf[n - 1] == '\n')
+           hlines++;
+           
+         /* Process particular attributes */
+         if (mu_c_strncasecmp (buf, "status:", 7) == 0)
+           mu_string_to_flags (buf, &attr_flags);
+         else if (mu_c_strncasecmp (buf, "x-imapbase:", 11) == 0)
+           {
+             char *p;
+             uidvalidity = strtoul (buf + 11, &p, 10);
+             /* second number is next uid. Ignored */
+           }
+       }
+      else
+       {
+         if (buf[n - 1] == '\n')
+           blines++;
+       }
+      off += n;
+    }
+
+  if (status == 0)
+    {
+      if (!body_start)
+       body_start = off;
+      sp->body_start = body_start;
+      sp->body_end = off;
+      sp->header_lines = hlines;
+      sp->body_lines = blines;
+      sp->attr_flags = attr_flags;
+      sp->uidvalidity = uidvalidity;
+    }
+  return status;
+}
diff --git a/mailbox/mutil.c b/mailbox/mutil.c
index 656a31f..aa11d56 100644
--- a/mailbox/mutil.c
+++ b/mailbox/mutil.c
@@ -64,7 +64,7 @@
 #include <mailutils/cctype.h>
 #include <mailutils/cstr.h>
 
-#include <registrar0.h>
+#include <mailutils/sys/registrar.h>
 
 /* convert a sequence of hex characters into an integer */
 
@@ -1328,17 +1328,17 @@ mu_decode_filter (mu_stream_t *pfilter, mu_stream_t 
input,
   if (fromcode && tocode && mu_c_strcasecmp (fromcode, tocode))
     {
       mu_stream_t cvt;
+
       status = mu_filter_iconv_create (&cvt, filter, fromcode, tocode,
-                                      MU_STREAM_NO_CLOSE,
-                                      mu_default_fallback_mode);
+                                      0, mu_default_fallback_mode);
       if (status == 0)
        {
          if (mu_stream_open (cvt))
-           mu_stream_destroy (&cvt, mu_stream_get_owner (cvt));
+           mu_stream_destroy (&cvt);
          else
-           {
-             mu_stream_clr_flags (cvt, MU_STREAM_NO_CLOSE);
-             filter = cvt;
+            {
+              mu_stream_unref (filter);
+              filter = cvt;
            }
        }
     }
diff --git a/mailbox/nullrec.c b/mailbox/nullrec.c
new file mode 100644
index 0000000..9d080cd
--- /dev/null
+++ b/mailbox/nullrec.c
@@ -0,0 +1,49 @@
+/* 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/>. */
+
+/* This file provides replacement definitions for mu_record_t defined
+   in those MU libraries which are disabled at configure time. */
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <mailutils/types.h>
+#include <mailutils/registrar.h>
+
+#ifndef ENABLE_IMAP
+mu_record_t mu_imap_record = NULL;
+mu_record_t mu_imaps_record = NULL;
+#endif
+
+#ifndef ENABLE_POP
+mu_record_t mu_pop_record = NULL;
+mu_record_t mu_pops_record = NULL;
+#endif
+
+#ifndef ENABLE_NNTP
+mu_record_t mu_nntp_record = NULL;
+#endif
+
+#ifndef ENABLE_MH
+mu_record_t mu_mh_record = NULL;
+#endif
+
+#ifndef ENABLE_MAILDIR
+mu_record_t mu_maildir_record = NULL;
+#endif
+
diff --git a/mailbox/observer.c b/mailbox/observer.c
index 355a4fa..51b0260 100644
--- a/mailbox/observer.c
+++ b/mailbox/observer.c
@@ -27,7 +27,7 @@
 #include <mailutils/list.h>
 #include <mailutils/iterator.h>
 #include <mailutils/errno.h>
-#include <observer0.h>
+#include <mailutils/sys/observer.h>
 
 int
 mu_observer_create (mu_observer_t *pobserver, void *owner)
diff --git a/mailbox/opool.c b/mailbox/opool.c
index acb29ac..991b527 100644
--- a/mailbox/opool.c
+++ b/mailbox/opool.c
@@ -205,6 +205,25 @@ mu_opool_size (mu_opool_t opool)
   return size;
 }
 
+size_t
+mu_opool_copy (mu_opool_t opool, void *buf, size_t size)
+{
+  char *cp = buf;
+  size_t total = 0;
+  struct mu_opool_bucket *p;
+  
+  for (p = opool->head; p && total < size; p = p->next)
+    {
+      size_t cpsize = size - total;
+      if (cpsize > p->level)
+       cpsize = p->level;
+      memcpy (cp, p->buf, cpsize);
+      cp += cpsize;
+      total += cpsize;
+    }
+  return total;
+}
+
 int
 mu_opool_coalesce (mu_opool_t opool, size_t *psize)
 {
diff --git a/mailbox/prog_stream.c b/mailbox/prog_stream.c
new file mode 100644
index 0000000..8b20f96
--- /dev/null
+++ b/mailbox/prog_stream.c
@@ -0,0 +1,462 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 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 <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <syslog.h>
+
+#include <mailutils/types.h>
+#include <mailutils/alloc.h>
+#include <mailutils/argcv.h>
+#include <mailutils/error.h>
+#include <mailutils/errno.h>
+#include <mailutils/nls.h>
+#include <mailutils/stream.h>
+#include <mailutils/sys/stream.h>
+#include <mailutils/sys/prog_stream.h>
+#include <mailutils/mutil.h>
+
+static mu_list_t prog_stream_list;
+
+static int
+_prog_stream_register (struct _mu_prog_stream *stream)
+{
+  if (!prog_stream_list)
+    {
+      int rc = mu_list_create (&prog_stream_list);
+      if (rc)
+       return rc;
+    }
+  return mu_list_append (prog_stream_list, stream);
+}
+
+static void
+_prog_stream_unregister (struct _mu_prog_stream *stream)
+{
+  mu_list_remove (prog_stream_list, stream);
+}
+
+
+
+#if defined (HAVE_SYSCONF) && defined (_SC_OPEN_MAX)
+# define getmaxfd() sysconf (_SC_OPEN_MAX)
+#elif defined (HAVE_GETDTABLESIZE)
+# define getmaxfd() getdtablesize ()
+#else
+# define getmaxfd() 64
+#endif
+
+#define REDIRECT_STDIN_P(f) ((f) & (MU_STREAM_WRITE|MU_STREAM_RDWR))
+#define REDIRECT_STDOUT_P(f) ((f) & (MU_STREAM_READ|MU_STREAM_RDWR))
+
+static int
+start_program_filter (pid_t *pid, int *p, int argc, char **argv,
+                     char *errfile, int flags)
+{
+  int rightp[2], leftp[2];
+  int i;
+  int rc = 0;
+  
+  if (REDIRECT_STDIN_P (flags))
+    pipe (leftp);
+  if (REDIRECT_STDOUT_P (flags))
+    pipe (rightp);
+  
+  switch (*pid = fork ())
+    {
+      /* The child branch.  */
+    case 0:
+      /* attach the pipes */
+
+      /* Right-end */
+      if (REDIRECT_STDOUT_P (flags))
+       {
+         if (rightp[1] != 1)
+           {
+             close (1);
+             dup2 (rightp[1], 1);
+           }
+         close (rightp[0]);
+       }
+
+      /* Left-end */
+      if (REDIRECT_STDIN_P (flags))
+       {
+         if (leftp[0] != 0)
+           {
+             close (0);
+             dup2 (leftp[0], 0);
+           }
+         close (leftp[1]);
+       }
+      
+      /* Error output */
+      if (errfile)
+       {
+         i = open (errfile, O_CREAT|O_WRONLY|O_APPEND, 0644);
+         if (i > 0 && i != 2)
+           {
+             dup2 (i, 2);
+             close (i);
+           }
+       }
+      /* Close unneded descripitors */
+      for (i = getmaxfd (); i > 2; i--)
+       close (i);
+
+      /*FIXME: Switch to other uid/gid if desired */
+      execvp (argv[0], argv);
+               
+      /* Report error via syslog */
+      syslog (LOG_ERR|LOG_USER, "can't run %s (ruid=%d, euid=%d): %m",
+             argv[0], getuid (), geteuid ());
+      exit (127);
+      /********************/
+
+      /* Parent branches: */
+    case -1:
+      /* Fork has failed */
+      /* Restore things */
+      rc = errno;
+      if (REDIRECT_STDOUT_P (flags))
+       {
+         close (rightp[0]);
+         close (rightp[1]);
+       }
+      if (REDIRECT_STDIN_P (flags))
+       {
+         close (leftp[0]);
+         close (leftp[1]);
+       }
+      break;
+               
+    default:
+      if (REDIRECT_STDOUT_P (flags))
+       {
+         p[0] = rightp[0];
+         close (rightp[1]);
+       }
+      else
+       p[0] = -1;
+
+      if (REDIRECT_STDIN_P (flags))
+       {
+         p[1] = leftp[1];
+         close (leftp[0]);
+       }
+      else
+       p[1] = -1;
+    }
+  return rc;
+}
+
+static void
+_prog_wait (pid_t pid, int *pstatus)
+{
+  if (pid > 0)
+    {
+      pid_t t;
+      do
+       t = waitpid (pid, pstatus, 0);
+      while (t == -1 && errno == EINTR);
+    }
+}
+
+static void
+_prog_done (mu_stream_t stream)
+{
+  struct _mu_prog_stream *fs = (struct _mu_prog_stream *) stream;
+  int status;
+    
+  mu_argcv_free (fs->argc, fs->argv);
+  if (fs->in)
+    mu_stream_destroy (&fs->in);
+  if (fs->out)
+    mu_stream_destroy (&fs->out);
+  
+  _prog_wait (fs->pid, &fs->status);
+  fs->pid = -1;
+  _prog_wait (fs->writer_pid, &status);
+  fs->writer_pid = -1;
+  
+  _prog_stream_unregister (fs);
+}
+
+static int
+_prog_close (mu_stream_t stream)
+{
+  struct _mu_prog_stream *fs = (struct _mu_prog_stream *) stream;
+  int status;
+  
+  if (!stream)
+    return EINVAL;
+  
+  if (fs->pid <= 0)
+    return 0;
+
+  mu_stream_close (fs->out);
+  mu_stream_destroy (&fs->out);
+
+  _prog_wait (fs->pid, &fs->status);
+  fs->pid = -1;
+  _prog_wait (fs->writer_pid, &status);
+  fs->writer_pid = -1;
+  
+  mu_stream_close (fs->in);
+  mu_stream_destroy (&fs->in);
+
+  if (WIFEXITED (fs->status))
+    {
+      if (WEXITSTATUS (fs->status) == 0)
+       return 0;
+      else if (WEXITSTATUS (fs->status) == 127)
+       return MU_ERR_PROCESS_NOEXEC;
+      else
+       return MU_ERR_PROCESS_EXITED;
+    }
+  else if (WIFSIGNALED (fs->status))
+    return MU_ERR_PROCESS_SIGNALED;
+  return MU_ERR_PROCESS_UNKNOWN_FAILURE;
+}
+
+static int
+feed_input (struct _mu_prog_stream *fs)
+{
+  pid_t pid;
+  size_t size;
+  char buffer[128];
+  int rc = 0;
+
+  pid = fork ();
+  switch (pid)
+    {
+    default:
+      /* Master */
+      fs->writer_pid = pid;
+      mu_stream_close (fs->out);
+      mu_stream_destroy (&fs->out);
+      break;
+      
+    case 0:
+      /* Child */
+      while (mu_stream_read (fs->input, buffer, sizeof (buffer),
+                            &size) == 0
+            && size > 0)
+       mu_stream_write (fs->out, buffer, size, NULL);
+      mu_stream_close (fs->out);
+      exit (0);
+      
+    case -1:
+      rc = errno;
+    }
+
+  return rc;
+}
+
+static int
+_prog_open (mu_stream_t stream)
+{
+  struct _mu_prog_stream *fs = (struct _mu_prog_stream *) stream;
+  int rc;
+  int pfd[2];
+  int flags;
+  int seekable_flag;
+  
+  if (!fs || fs->argc == 0)
+    return EINVAL;
+
+  if (fs->pid)
+    {
+      _prog_close (stream);
+    }
+
+  mu_stream_get_flags (stream, &flags);
+  seekable_flag = (flags & MU_STREAM_SEEK);
+  
+  rc = start_program_filter (&fs->pid, pfd, fs->argc, fs->argv, NULL, flags);
+  if (rc)
+    return rc;
+
+  if (REDIRECT_STDOUT_P (flags))
+    {
+      rc = mu_stdio_stream_create (&fs->in, pfd[0],
+                                  
MU_STREAM_READ|MU_STREAM_AUTOCLOSE|seekable_flag);
+      if (rc)
+       {
+         _prog_close (stream);
+         return rc;
+       }
+      rc = mu_stream_open (fs->in);
+      if (rc)
+       {
+         _prog_close (stream);
+         return rc;
+       }
+    }
+  
+  if (REDIRECT_STDIN_P (flags))
+    {
+      rc = mu_stdio_stream_create (&fs->out, pfd[1],
+                                  
MU_STREAM_WRITE|MU_STREAM_AUTOCLOSE|seekable_flag);
+      if (rc)
+       {
+         _prog_close (stream);
+         return rc;
+       }
+      rc = mu_stream_open (fs->out);
+      if (rc)
+       {
+         _prog_close (stream);
+         return rc;
+       }
+    }
+
+  _prog_stream_register (fs);
+  if (fs->input)
+    return feed_input (fs);
+  return 0;
+}
+
+static int
+_prog_read (mu_stream_t stream, char *optr, size_t osize, size_t *pnbytes)
+{
+  struct _mu_prog_stream *fs = (struct _mu_prog_stream *) stream;
+  return mu_stream_read (fs->in, optr, osize, pnbytes);
+}
+
+static int
+_prog_write (mu_stream_t stream, const char *iptr, size_t isize,
+            size_t *pnbytes)
+{
+  struct _mu_prog_stream *fs = (struct _mu_prog_stream *) stream;
+  return mu_stream_write (fs->out, iptr, isize, pnbytes);
+}
+
+static int
+_prog_flush (mu_stream_t stream)
+{
+  struct _mu_prog_stream *fs = (struct _mu_prog_stream *) stream;
+  mu_stream_flush (fs->in);
+  mu_stream_flush (fs->out);
+  return 0;
+}
+
+static int
+_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;
+  
+  switch (code)
+    {
+    case MU_IOCTL_GET_TRANSPORT:
+      if (!ptr)
+       return EINVAL;
+      mu_stream_ioctl (fstr->in, MU_IOCTL_GET_TRANSPORT, t);
+      ptrans[0] = t[0];
+      mu_stream_ioctl (fstr->out, MU_IOCTL_GET_TRANSPORT, t);
+      ptrans[1] = t[1];
+      break;
+
+    case MU_IOCTL_GET_STATUS:
+      if (!ptr)
+       return EINVAL;
+      *(int*)ptr = fstr->status;
+      break;
+
+    case MU_IOCTL_GET_PID:
+      if (!ptr)
+       return EINVAL;
+      *(int*)ptr = fstr->pid;
+      break;
+      
+    default:
+      return EINVAL;
+    }
+  return 0;
+}
+
+struct _mu_prog_stream *
+_prog_stream_create (const char *progname, int flags)
+{
+  struct _mu_prog_stream *fs;
+  
+  fs = (struct _mu_prog_stream *) _mu_stream_create (sizeof (*fs), flags);
+  if (!fs)
+    return NULL;
+
+  if (mu_argcv_get (progname, "", "#", &fs->argc, &fs->argv))
+    {
+      mu_argcv_free (fs->argc, fs->argv);
+      free (fs);
+      return NULL;
+    }
+
+  fs->stream.read = _prog_read;
+  fs->stream.write = _prog_write;
+  fs->stream.open = _prog_open;
+  fs->stream.close = _prog_close;
+  fs->stream.ctl = _prog_ioctl;
+  fs->stream.flush = _prog_flush;
+  fs->stream.done = _prog_done;
+
+  return fs;
+}
+
+int
+mu_prog_stream_create (mu_stream_t *pstream, const char *progname, int flags)
+{
+  if (pstream == NULL)
+    return MU_ERR_OUT_PTR_NULL;
+
+  if (progname == NULL)
+    return EINVAL;
+
+  if ((*pstream = (mu_stream_t) _prog_stream_create (progname, flags)) == NULL)
+    return ENOMEM;
+  return 0;
+}
+
+int
+mu_filter_prog_stream_create (mu_stream_t *pstream, const char *progname,
+                             mu_stream_t input)
+{
+  struct _mu_prog_stream *fs;
+
+  if (pstream == NULL)
+    return MU_ERR_OUT_PTR_NULL;
+
+  if (progname == NULL)
+    return EINVAL;
+
+  fs = _prog_stream_create (progname, MU_STREAM_RDWR);
+  if (!fs)
+    return ENOMEM;
+  mu_stream_ref (input);
+  fs->input = input;
+  *pstream = (mu_stream_t) fs;
+  return 0;
+}
+
diff --git a/mailbox/progmailer.c b/mailbox/progmailer.c
index 6af0934..f39440f 100644
--- a/mailbox/progmailer.c
+++ b/mailbox/progmailer.c
@@ -180,7 +180,6 @@ mu_progmailer_send (struct _mu_progmailer *pm, mu_message_t 
msg)
   char buffer[512];
   size_t len = 0;
   int rc;
-  size_t offset = 0;
   mu_header_t hdr;
   mu_body_t body;
   int found_nl = 0;
@@ -189,11 +188,17 @@ mu_progmailer_send (struct _mu_progmailer *pm, 
mu_message_t msg)
   if (!pm || !msg)
     return EINVAL;
   mu_message_get_header (msg, &hdr);
-  mu_header_get_stream (hdr, &stream);
-
+  status = mu_header_get_streamref (hdr, &stream);
+  if (status)
+    {
+      MU_DEBUG1 (pm->debug, MU_DEBUG_ERROR,
+                "cannot get header stream: %s\n", mu_strerror (status));
+      return status;
+    }
   MU_DEBUG (pm->debug, MU_DEBUG_TRACE, "Sending headers...\n");
+  mu_stream_seek (stream, 0, MU_SEEK_SET, NULL);
   while ((status = mu_stream_readline (stream, buffer, sizeof (buffer),
-                                      offset, &len)) == 0
+                                      &len)) == 0
         && len != 0)
     {
       if (mu_c_strncasecmp (buffer, MU_HEADER_FCC, sizeof (MU_HEADER_FCC) - 1))
@@ -209,8 +214,6 @@ mu_progmailer_send (struct _mu_progmailer *pm, mu_message_t 
msg)
            }
        }
       found_nl = (len == 1 && buffer[0] == '\n');
-             
-      offset += len;
     }
 
   if (!found_nl)
@@ -223,14 +226,21 @@ mu_progmailer_send (struct _mu_progmailer *pm, 
mu_message_t msg)
                     "write failed: %s\n", strerror (status));
        }
     }
-       
+  mu_stream_destroy (&stream);
+  
+  MU_DEBUG (pm->debug, MU_DEBUG_TRACE, "Sending body...\n");
   mu_message_get_body (msg, &body);
-  mu_body_get_stream (body, &stream);
+  status = mu_body_get_streamref (body, &stream);
+  if (status)
+    {
+      MU_DEBUG1 (pm->debug, MU_DEBUG_ERROR,
+                "cannot get body stream: %s\n", mu_strerror (status));
+      return status;
+    }
 
-  MU_DEBUG (pm->debug, MU_DEBUG_TRACE, "Sending body...\n");
-  offset = 0;
+  mu_stream_seek (stream, 0, MU_SEEK_SET, NULL);
   while ((status = mu_stream_read (stream, buffer, sizeof (buffer),
-                                  offset, &len)) == 0
+                                  &len)) == 0
         && len != 0)
     {
       if (write (pm->fd, buffer, len) == -1)
@@ -241,8 +251,8 @@ mu_progmailer_send (struct _mu_progmailer *pm, mu_message_t 
msg)
                     "write failed: %s\n", strerror (status));
          break;
        }
-      offset += len;
     }
+  mu_body_get_streamref (body, &stream);
 
   close (pm->fd);
 
diff --git a/mailbox/property.c b/mailbox/property.c
index e5980b9..435d8e2 100644
--- a/mailbox/property.c
+++ b/mailbox/property.c
@@ -24,7 +24,7 @@
 # include <strings.h>
 #endif
 
-#include <property0.h>
+#include <mailutils/sys/property.h>
 #include <mailutils/errno.h>
 #include <mailutils/assoc.h>
 #include <stdlib.h>
diff --git a/mailbox/qpflt.c b/mailbox/qpflt.c
new file mode 100644
index 0000000..aaada1e
--- /dev/null
+++ b/mailbox/qpflt.c
@@ -0,0 +1,262 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 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 <mailutils/errno.h>
+#include <mailutils/filter.h>
+
+#define ISWS(c) ((c)==' ' || (c)=='\t')
+
+static enum mu_filter_result
+_qp_decoder (void *xd MU_ARG_UNUSED,
+            enum mu_filter_command cmd,
+            struct mu_filter_io *iobuf)
+{
+  char c;
+  size_t consumed = 0;
+  size_t wscount = 0;
+  size_t nbytes = 0;
+  const char *iptr;
+  size_t isize;
+  char *optr;
+  size_t osize;
+
+  switch (cmd)
+    {
+    case mu_filter_init:
+    case mu_filter_done:
+      return mu_filter_ok;
+    default:
+      break;
+    }
+  
+  iptr = iobuf->input;
+  isize = iobuf->isize;
+  optr = iobuf->output;
+  osize = iobuf->osize;
+
+  while (consumed < isize && nbytes < osize)
+    {
+      c = *iptr++;
+
+      if (ISWS(c))
+       {
+         wscount++;
+         consumed++;
+       }
+      else
+       {
+         /* Octets with values of 9 and 32 MAY be
+            represented as US-ASCII TAB (HT) and SPACE characters,
+            respectively, but MUST NOT be so represented at the end
+            of an encoded line.  Any TAB (HT) or SPACE characters
+            on an encoded line MUST thus be followed on that line
+            by a printable character. */
+         
+         if (wscount)
+           {
+             if (c != '\r' && c != '\n')
+               {
+                 size_t sz;
+                 
+                 if (consumed >= isize)
+                   break;
+
+                 if (nbytes + wscount > osize)
+                   sz = osize - nbytes;
+                 else
+                   sz = wscount;
+                 memcpy(optr, iptr - wscount - 1, sz);
+                 optr += sz;
+                 nbytes += sz;
+                 if (wscount > sz)
+                   {
+                     wscount -= sz;
+                     break;
+                   }
+               }
+             wscount = 0;
+             if (nbytes == osize)
+               break;
+           }
+         
+         if (c == '=')
+           {
+             /* There must be 2 more characters before I consume this.  */
+             if (consumed + 2 >= isize)
+               break;
+             else
+               {
+                 /* you get =XX where XX are hex characters.  */
+                 char chr[3];
+                 int new_c;
+                 
+                 chr[2] = 0;
+                 chr[0] = *iptr++;
+                 /* Ignore LF.  */
+                 if (chr[0] != '\n')
+                   {
+                     chr[1] = *iptr++;
+                     new_c = strtoul (chr, NULL, 16);
+                     *optr++ = new_c;
+                     nbytes++;
+                     consumed += 3;
+                   }
+                 else
+                   consumed += 2;
+               }
+           }
+         /* CR character.  */
+         else if (c == '\r')
+           {
+             /* There must be at least 1 more character before
+                I consume this.  */
+             if (consumed + 1 >= isize)
+               {
+                 if (cmd == mu_filter_lastbuf)
+                   consumed++;
+                 break;
+               }
+             else
+               {
+                 iptr++; /* Skip the CR character.  */
+                 *optr++ = '\n';
+                 nbytes++;
+                 consumed += 2;
+               }
+           }
+         else if (c == '_')
+           {
+             *optr++ = ' ';
+             nbytes++;
+             consumed++;
+           }
+         else
+           {
+             *optr++ = c;
+             nbytes++;
+             consumed++;
+           }
+       }         
+    }
+  iobuf->isize = consumed - wscount;
+  iobuf->osize = nbytes;
+  return mu_filter_ok;
+}
+
+static enum mu_filter_result
+_qp_encoder (void *xd MU_ARG_UNUSED,
+            enum mu_filter_command cmd,
+            struct mu_filter_io *iobuf)
+{
+  unsigned int c;
+  size_t consumed = 0;
+  size_t nbytes = 0;
+  static const char _hexdigits[] = "0123456789ABCDEF";
+  const char *iptr;
+  size_t isize;
+  char *optr;
+  size_t osize;
+
+  switch (cmd)
+    {
+    case mu_filter_init:
+    case mu_filter_done:
+      return mu_filter_ok;
+    default:
+      break;
+    }
+
+  iptr = iobuf->input;
+  isize = iobuf->isize;
+  optr = iobuf->output;
+  osize = iobuf->osize;
+  nbytes = 0;
+
+  /* Strategy: check if we have enough room in the output buffer only
+     once the required size has been computed. If there is not enough,
+     return and hope that the caller will free up the output buffer a
+     bit. */
+  
+  while (consumed < isize)
+    {
+      int simple_char;
+      
+      /* candidate byte to convert */
+      c = *(unsigned char*) iptr;
+      simple_char = (c >= 32 && c <= 60)
+                      || (c >= 62 && c <= 126)
+                      || c == '\t'
+                      || c == '\n';
+
+      if (simple_char)
+       {
+         /* a non-quoted character uses up one byte */
+         if (nbytes + 1 > osize) 
+           break;
+
+         *optr++ = c;
+         nbytes++;
+           
+         iptr++;
+         consumed++;
+
+       }
+      else
+       {
+         /* a quoted character uses up three bytes */
+         if (nbytes + 3 > osize) 
+           break;
+
+         *optr++ = '=';
+         *optr++ = _hexdigits[(c >> 4) & 0xf];
+         *optr++ = _hexdigits[c & 0xf];
+         
+         nbytes += 3;
+         
+         /* we've actuall used up one byte of input */
+         iptr++;
+         consumed++;
+       }
+    }
+  iobuf->isize = consumed;
+  iobuf->osize = nbytes;
+  return mu_filter_ok;
+}
+
+static struct _mu_filter_record _qp_filter = {
+  "quoted-printable",
+  0,
+  NULL,
+  _qp_encoder,
+  _qp_decoder
+};
+
+mu_filter_record_t mu_qp_filter = &_qp_filter;
+
+static struct _mu_filter_record _Q_filter = {
+  "Q",
+  0,
+  NULL,
+  _qp_encoder,
+  _qp_decoder
+};
+
+mu_filter_record_t mu_rfc_2047_Q_filter = &_Q_filter;
diff --git a/mailbox/rdcache_stream.c b/mailbox/rdcache_stream.c
new file mode 100644
index 0000000..0d7eed7
--- /dev/null
+++ b/mailbox/rdcache_stream.c
@@ -0,0 +1,201 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 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 <errno.h>
+#include <mailutils/types.h>
+#include <mailutils/sys/rdcache_stream.h>
+
+size_t mu_rdcache_stream_max_memory_size = 4096;
+
+static int
+rdcache_read (struct _mu_stream *str, char *buf, size_t size, size_t *pnbytes)
+{
+  struct _mu_rdcache_stream *sp = (struct _mu_rdcache_stream *) str;
+  int status = 0;
+  size_t nbytes = 0;
+  
+  if (sp->offset < sp->size)
+    {
+      status = mu_stream_read (sp->cache, buf, size, &nbytes);
+      if (status)
+       return status;
+      sp->offset += nbytes;
+      sp->size += nbytes;
+      buf += nbytes;
+      size -= nbytes;
+    }
+  else if (sp->offset > sp->size)
+    {
+      size_t left = sp->offset - sp->size;
+      status = mu_stream_seek (sp->cache, 0, MU_SEEK_END, NULL);
+      if (status)
+       return status;
+      status = mu_stream_copy (sp->cache, sp->transport, left, NULL);
+      if (status)
+       return status;
+      sp->size = sp->offset;
+    }
+
+  if (size)
+    {
+      size_t rdbytes;
+      status = mu_stream_read (sp->transport, buf, size, &rdbytes);
+      if (rdbytes)
+       {
+         int rc;
+
+         sp->offset += rdbytes;
+         sp->size += rdbytes;
+         nbytes += rdbytes;
+         rc = mu_stream_write (sp->cache, buf, rdbytes, NULL);
+         if (rc)
+           {
+             if (status == 0)
+               status = rc;
+           }
+       }
+    }
+  if (pnbytes)
+    *pnbytes = nbytes;
+  return status;
+}
+
+static int
+rdcache_size (struct _mu_stream *str, off_t *psize)
+{
+  struct _mu_rdcache_stream *sp = (struct _mu_rdcache_stream *) str;
+  *psize = sp->size;
+  return 0;
+}
+
+static int
+rdcache_seek (struct _mu_stream *str, mu_off_t off, mu_off_t *presult)
+{ 
+  struct _mu_rdcache_stream *sp = (struct _mu_rdcache_stream *) str;
+
+  if (off < 0)
+    return ESPIPE;
+
+  if (off < sp->size)
+    {
+      int status = mu_stream_seek (sp->cache, off, MU_SEEK_SET, NULL);
+      if (status)
+       return status;
+    }
+  
+  sp->offset = off;
+  *presult = sp->offset;
+  return 0;
+}
+
+static int
+rdcache_wait (struct _mu_stream *str, int *pflags, struct timeval *tvp)
+{
+  struct _mu_rdcache_stream *sp = (struct _mu_rdcache_stream *) str;
+  return mu_stream_wait (sp->transport, pflags, tvp);
+}
+
+/* FIXME: Truncate? */
+
+static int
+rdcache_ioctl (struct _mu_stream *str, int op, void *arg)
+{
+  struct _mu_rdcache_stream *sp = (struct _mu_rdcache_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] = NULL;
+      break;
+
+    default:
+      return EINVAL;
+    }
+  return 0;
+}
+
+static int
+rdcache_open (struct _mu_stream *str)
+{
+  struct _mu_rdcache_stream *sp = (struct _mu_rdcache_stream *) str;
+  return mu_stream_open (sp->transport);
+}
+
+static int
+rdcache_close (struct _mu_stream *str)
+{
+  struct _mu_rdcache_stream *sp = (struct _mu_rdcache_stream *) str;
+  return mu_stream_close (sp->transport);
+}
+
+static void
+rdcache_done (struct _mu_stream *str)
+{
+  struct _mu_rdcache_stream *sp = (struct _mu_rdcache_stream *) str;
+  mu_stream_unref (sp->transport);
+  mu_stream_unref (sp->cache);
+}
+  
+int
+mu_rdcache_stream_create (mu_stream_t *pstream, mu_stream_t transport,
+                         int flags)
+{
+  struct _mu_rdcache_stream *sp;
+  int rc;
+  int sflags = MU_STREAM_READ | MU_STREAM_SEEK | (flags & MU_STREAM_AUTOCLOSE);
+
+  if (flags & ~sflags)
+    return EINVAL;
+  
+  sp = (struct _mu_rdcache_stream *)
+          _mu_stream_create (sizeof (*sp), sflags);
+  if (!sp)
+    return ENOMEM;
+
+  sp->stream.read = rdcache_read;
+  sp->stream.open = rdcache_open;
+  sp->stream.close = rdcache_close;
+  sp->stream.done = rdcache_done;
+  sp->stream.seek = rdcache_seek; 
+  sp->stream.size = rdcache_size; 
+  sp->stream.ctl = rdcache_ioctl;
+  sp->stream.wait = rdcache_wait;
+
+  if (!(flags & MU_STREAM_AUTOCLOSE))
+    mu_stream_ref (transport);
+  sp->transport = transport;
+
+  if ((rc = mu_memory_stream_create (&sp->cache, MU_STREAM_RDWR))
+      || (rc = mu_stream_open (sp->cache)))
+    {
+      mu_stream_destroy ((mu_stream_t*) &sp);
+      return rc;
+    }
+  
+  *pstream = (mu_stream_t) sp;
+  return 0;
+}
+
diff --git a/mailbox/registrar.c b/mailbox/registrar.c
index 1f6cc6f..a1a2b4f 100644
--- a/mailbox/registrar.c
+++ b/mailbox/registrar.c
@@ -36,7 +36,7 @@
 #include <mailutils/error.h>
 #include <mailutils/url.h>
 #include <mailutils/mutil.h>
-#include <registrar0.h>
+#include <mailutils/sys/registrar.h>
 
 /* NOTE: We will leak here since the monitor and the registrar will never
    be released. That's ok we can live with this, it's only done once.  */
diff --git a/mailbox/rfc2047.c b/mailbox/rfc2047.c
index 9e043d6..c30ba2f 100644
--- a/mailbox/rfc2047.c
+++ b/mailbox/rfc2047.c
@@ -22,6 +22,7 @@
 #endif
 
 #include <string.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <errno.h>
 #include <ctype.h>
@@ -160,15 +161,16 @@ mu_rfc2047_decode (const char *tocode, const char *input, 
char **ptostr)
          if (status != 0)
            break;
 
-         mu_memory_stream_create (&in_stream, 0, 0);
-         mu_stream_write (in_stream, encoded_text, size, 0, NULL);
+         mu_memory_stream_create (&in_stream, 0);
+         mu_stream_write (in_stream, encoded_text, size, NULL);
+         mu_stream_seek (in_stream, 0, MU_SEEK_SET, NULL);
          status = mu_decode_filter (&filter, in_stream, filter_type, fromcode,
                                     tocode);
+         mu_stream_unref (in_stream);
          if (status != 0)
            break;
 
-         while (mu_stream_sequential_read (filter, tmp, sizeof (tmp),
-                                           &nbytes) == 0
+         while (mu_stream_read (filter, tmp, sizeof (tmp), &nbytes) == 0
                 && nbytes)
            {
              CHKBUF (nbytes);
@@ -177,7 +179,7 @@ mu_rfc2047_decode (const char *tocode, const char *input, 
char **ptostr)
            }
 
          mu_stream_close (filter);
-         mu_stream_destroy (&filter, mu_stream_get_owner (filter));
+         mu_stream_destroy (&filter);
          
          fromstr = sp + 1;
          run_count = 1;
@@ -265,14 +267,15 @@ mu_rfc2047_encode (const char *charset, const char 
*encoding,
   else if (encoding[1] || !strchr ("BQ", encoding[0]))
     return MU_ERR_BAD_2047_ENCODING;
 
-  rc = mu_memory_stream_create (&input_stream, 0, 0);
+  rc = mu_memory_stream_create (&input_stream, 0);
   if (rc)
     return rc;
   
-  mu_stream_sequential_write (input_stream, text, strlen (text));
-
+  mu_stream_write (input_stream, text, strlen (text), NULL);
+  mu_stream_seek (input_stream, 0, MU_SEEK_SET, NULL);
   rc = mu_filter_create (&output_stream, input_stream,
-                        encoding, MU_FILTER_ENCODE, MU_STREAM_READ);
+                        encoding, MU_FILTER_ENCODE,
+                        MU_STREAM_READ | MU_STREAM_AUTOCLOSE);
   if (rc == 0)
     {
       /* Assume strlen(qp_encoded_text) <= strlen(text) * 3 */
@@ -294,18 +297,18 @@ mu_rfc2047_encode (const char *charset, const char 
*encoding,
          
          p += sprintf (p, "=?%s?%s?", charset, encoding);
          
-         rc = mu_stream_sequential_read (output_stream,
-                                      p,
-                                      strlen (text) * 3, &s);
+         rc = mu_stream_read (output_stream,
+                              p,
+                              strlen (text) * 3, &s);
 
          strcpy (p + s, "?=");
        }
       else
        rc = ENOMEM;
-      mu_stream_destroy (&output_stream, NULL);
+      mu_stream_destroy (&output_stream);
     }
   else
-    mu_stream_destroy (&input_stream, NULL);
+    mu_stream_destroy (&input_stream);
 
   return rc;
 }
diff --git a/mailbox/socket_stream.c b/mailbox/socket_stream.c
index a28a447..2764b2b 100644
--- a/mailbox/socket_stream.c
+++ b/mailbox/socket_stream.c
@@ -1,90 +1,44 @@
 /* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2010
-   Free Software Foundation, Inc.
+   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 of the License, or (at your option) any later version.
+   GNU Mailutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
 
-   This library is distributed in the hope that it will be useful,
+   GNU Mailutils is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General
-   Public License along with this library; if not, write to the
-   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301 USA */
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
 
+   You should have received a copy of the GNU General Public License
+   along with GNU Mailutils.  If not, see <http://www.gnu.org/licenses/>. */
 #ifdef HAVE_CONFIG_H
 # include <config.h>
 #endif
-
-#include <unistd.h>
-#include <stdlib.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/un.h>
 #include <string.h>
-#include <signal.h>
-#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
 
-#include <mailutils/stream.h>
+#include <mailutils/types.h>
+#include <mailutils/alloc.h>
 #include <mailutils/error.h>
 #include <mailutils/errno.h>
-
-struct _socket_stream
-{
-  mu_stream_t fstream;
-  char *filename;
-  int ec; /* Last error code if fstream == NULL */
-};
-
-static void
-_s_destroy (mu_stream_t stream)
-{
-  struct _socket_stream *s = mu_stream_get_owner (stream);
-
-  if (s->filename)
-    free (s->filename);
-  mu_stream_destroy (&s->fstream, mu_stream_get_owner (s->fstream));
-  free (s);
-}
-
-static int
-_s_read (mu_stream_t stream, char *optr, size_t osize,
-        mu_off_t offset, size_t *nbytes)
-{
-  struct _socket_stream *s = mu_stream_get_owner (stream);
-  return mu_stream_read (s->fstream, optr, osize, offset, nbytes);
-}
-
-static int
-_s_readline (mu_stream_t stream, char *optr, size_t osize,
-            mu_off_t offset, size_t *nbytes)
-{
-  struct _socket_stream *s = mu_stream_get_owner (stream);
-  return mu_stream_readline (s->fstream, optr, osize, offset, nbytes);
-}
-
-static int
-_s_write (mu_stream_t stream, const char *iptr, size_t isize,
-         mu_off_t offset, size_t *nbytes)
-{
-  struct _socket_stream *s = mu_stream_get_owner (stream);
-  return mu_stream_write (s->fstream, iptr, isize, offset, nbytes);
-}
+#include <mailutils/nls.h>
+#include <mailutils/stream.h>
+#include <mailutils/sys/file_stream.h>
 
 static int
-_s_open (mu_stream_t stream)
+_socket_open (mu_stream_t stream)
 {
-  struct _socket_stream *s = mu_stream_get_owner (stream);
-  int fd, rc;
-  FILE *fp;
+  struct _mu_file_stream *s = (struct _mu_file_stream *) stream;
+  int fd;
   struct sockaddr_un addr;
-  char *fstr;
-  int flags;
   
   if (!s)
     return EINVAL;
@@ -103,86 +57,17 @@ _s_open (mu_stream_t stream)
       return errno;
     }
 
-  mu_stream_get_flags(stream, &flags);
-  if (flags & MU_STREAM_WRITE)
-    fstr = "w";
-  else if (flags & MU_STREAM_RDWR)
-    fstr = "w+";
-  else if (flags & MU_STREAM_READ)
-    fstr = "r";
-  else
-    fstr = "w+";
-  
-  fp = fdopen (fd, fstr);
-  if (!fp)
-    {
-      close (fd);
-      return errno;
-    }
+  s->fd = fd;
       
-  rc = mu_stdio_stream_create (&s->fstream, fp, flags);
-  if (rc)
-    {
-      fclose (fp);
-      return rc;
-    }
-  
-  rc = mu_stream_open (s->fstream);
-  if (rc)
-    {
-      mu_stream_destroy (&s->fstream, mu_stream_get_owner (s->fstream));
-      fclose (fp);
-    }
-  return rc;
-}
-
-static int
-_s_close (mu_stream_t stream)
-{
-  struct _socket_stream *s = mu_stream_get_owner (stream);
-  return mu_stream_close (s->fstream);
-}
-
-static int
-_s_flush (mu_stream_t stream)
-{
-  struct _socket_stream *s = mu_stream_get_owner (stream);
-  return mu_stream_flush (s->fstream);
-}
-
-int
-_s_wait (mu_stream_t stream, int *pflags, struct timeval *tvp)
-{
-  struct _socket_stream *s = mu_stream_get_owner (stream);
-  return mu_stream_wait (s->fstream, pflags, tvp);
-}
-
-int
-_s_strerror (mu_stream_t stream, const char **pstr)
-{
-  struct _socket_stream *s = mu_stream_get_owner (stream);
-  return mu_stream_strerror (s->fstream, pstr);
-}
-
-static int
-_s_get_transport2 (mu_stream_t stream,
-                  mu_transport_t *pin, mu_transport_t *pout)
-{
-  struct _socket_stream *s = mu_stream_get_owner (stream);
-  return mu_stream_get_transport2 (s->fstream, pin, pout);
+  return 0;
 }
 
 int
-_s_shutdown (mu_stream_t stream, int how)
+_socket_shutdown (mu_stream_t stream, int how)
 {
-  struct _socket_stream *s = mu_stream_get_owner (stream);
+  struct _mu_file_stream *s = (struct _mu_file_stream *) stream;
   int flag;
-  mu_transport_t trans;
 
-  if (s->fstream == NULL)
-    return EINVAL;
-
-  mu_stream_get_transport(s->fstream, &trans);
   switch (how)
     {
     case MU_STREAM_READ:
@@ -192,54 +77,46 @@ _s_shutdown (mu_stream_t stream, int how)
     case MU_STREAM_WRITE:
       flag = SHUT_WR;
     }
-
-  if (shutdown ((int) trans, flag))
+  
+  if (shutdown (s->fd, flag))
     return errno;
   return 0;
 }
 
 int
-mu_socket_stream_create (mu_stream_t *stream, const char *filename, int flags)
+mu_socket_stream_create (mu_stream_t *pstream, const char *filename, int flags)
 {
-  struct _socket_stream *s;
   int rc;
+  mu_stream_t transport;
+  int need_cache;
+  struct _mu_file_stream *fstr;
+  
+  need_cache = flags & MU_STREAM_SEEK;
+  if (need_cache && (flags & MU_STREAM_WRITE))
+    /* Write caches are not supported */
+    return EINVAL;
 
-  if (stream == NULL)
-    return MU_ERR_OUT_PTR_NULL;
-
-  s = calloc (1, sizeof (struct _socket_stream));
-  if (s == NULL)
-    return ENOMEM;
-
-  if ((s->filename = strdup (filename)) == NULL)
-    {
-      free (s);
-      return ENOMEM;
-    }
-
-  rc = mu_stream_create (stream, flags | MU_STREAM_NO_CHECK, s);
+  /* Create transport stream. */
+  rc = _mu_file_stream_create (&fstr, sizeof (*fstr),
+                              filename, -1,
+                              (flags | MU_STREAM_AUTOCLOSE) & ~MU_STREAM_SEEK);
   if (rc)
+    return rc;
+  fstr->stream.open = _socket_open;
+  fstr->stream.shutdown = _socket_shutdown;
+  transport = (mu_stream_t) fstr;
+  
+  /* Wrap it in cache, if required */
+  if (need_cache)
     {
-      free (s);
-      free (s->filename);
-      return rc;
+      mu_stream_t str;
+      rc = mu_rdcache_stream_create (&str, transport, flags);
+      mu_stream_unref (transport);
+      if (rc)
+       return rc;
+      transport = str;
     }
 
-  mu_stream_set_open (*stream, _s_open, s);
-  mu_stream_set_close (*stream, _s_close, s);
-  mu_stream_set_get_transport2 (*stream, _s_get_transport2, s);
-  mu_stream_set_read (*stream, _s_read, s);
-  mu_stream_set_readline (*stream, _s_readline, s);
-  mu_stream_set_write (*stream, _s_write, s);
-  mu_stream_set_flush (*stream, _s_flush, s);
-  mu_stream_set_destroy (*stream, _s_destroy, s);
-  mu_stream_set_strerror (*stream, _s_strerror, s);
-  mu_stream_set_wait (*stream, _s_wait, s);
-  mu_stream_set_shutdown (*stream, _s_shutdown, s);
-  
+  *pstream = transport;
   return 0;
 }
-
-
-
-
diff --git a/mailbox/stdio_stream.c b/mailbox/stdio_stream.c
new file mode 100644
index 0000000..93ff011
--- /dev/null
+++ b/mailbox/stdio_stream.c
@@ -0,0 +1,83 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 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 <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <errno.h>
+#include <mailutils/types.h>
+#include <mailutils/stream.h>
+#include <mailutils/sys/stream.h>
+#include <mailutils/sys/file_stream.h>
+
+int
+mu_stdio_stream_create (mu_stream_t *pstream, int fd, int flags)
+{
+  int rc;
+  char *filename;
+  mu_stream_t transport;
+  int need_cache;
+  struct _mu_file_stream *fstr;
+  
+  switch (fd)
+    {
+    case MU_STDIN_FD:
+      flags |= MU_STREAM_READ;
+      break;
+      
+    case MU_STDOUT_FD:
+    case MU_STDERR_FD:
+      flags |= MU_STREAM_WRITE;
+    }
+
+  need_cache = flags & MU_STREAM_SEEK;
+  if (need_cache && (flags & MU_STREAM_WRITE))
+    /* Write caches are not supported */
+    return EINVAL;
+
+  if (flags & MU_STREAM_READ)
+    filename = "<stdin>";
+  else
+    filename = "<stdout>";
+
+  /* Create transport stream. */
+  rc = _mu_file_stream_create (&fstr, sizeof (*fstr),
+                              filename, fd, flags & ~MU_STREAM_SEEK);
+  if (rc)
+    return rc;
+  fstr->stream.open = NULL;
+  transport = (mu_stream_t) fstr;
+  
+  /* Wrap it in cache, if required */
+  if (need_cache)
+    {
+      mu_stream_t str;
+      rc = mu_rdcache_stream_create (&str, transport, flags);
+      mu_stream_unref (transport);
+      if (rc)
+       return rc;
+      transport = str;
+    }
+
+  *pstream = transport;
+  return 0;
+}
+
diff --git a/mailbox/stream.c b/mailbox/stream.c
index 79a077a..1ea8b52 100644
--- a/mailbox/stream.c
+++ b/mailbox/stream.c
@@ -1,1019 +1,1070 @@
 /* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 1999, 2000, 2001, 2004, 2005, 2006, 2007, 2009, 2010
-   Free Software Foundation, Inc.
+   Copyright (C) 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 of the License, or (at your option) any later version.
+   GNU Mailutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
 
-   This library is distributed in the hope that it will be useful,
+   GNU Mailutils 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.
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
 
-   You should have received a copy of the GNU Lesser General
-   Public License along with this library; if not, write to the
-   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301 USA */
-
-
-/* Credits.  Some of the Readline an buffering scheme was taken
-   from 4.4BSDLite2.
-
-   Copyright (c) 1990, 1993
-   The Regents of the University of California.  All rights reserved.
-
-   This code is derived from software contributed to Berkeley by
-   Chris Torek.
- */
+   You should have received a copy of the GNU General Public License
+   along with GNU Mailutils.  If not, see <http://www.gnu.org/licenses/>. */
 
 #ifdef HAVE_CONFIG_H
 # include <config.h>
 #endif
-
-#include <errno.h>
-#include <stdlib.h>
-#include <stdio.h>
 #include <string.h>
-#include <stdarg.h>
+#include <stdlib.h>
+#include <limits.h>
+#ifndef SIZE_MAX
+# define SIZE_MAX (~((size_t)0))
+#endif
 
-#include <mailutils/property.h>
+#include <mailutils/types.h>
+#include <mailutils/alloc.h>
+#include <mailutils/error.h>
 #include <mailutils/errno.h>
-#include <mailutils/io.h>
-#include <stream0.h>
-
-static int refill (mu_stream_t, mu_off_t);
-
-/* A stream provides a way for an object to do I/O. It overloads
-   stream read/write functions. Only a minimal buffering is done
-   and that if stream's bufsiz member is set. If the requested
-   offset does not equal the one maintained internally the buffer
-   is flushed and refilled. This buffering scheme is more convenient
-   for networking streams (POP/IMAP).
-   Writes are always unbuffered. */
-int
-mu_stream_create (mu_stream_t *pstream, int flags, void *owner)
-{
-  mu_stream_t stream;
-  if (pstream == NULL)
-    return MU_ERR_OUT_PTR_NULL;
-  if (owner == NULL)
-    return EINVAL;
-  stream = calloc (1, sizeof (*stream));
-  if (stream == NULL)
-    return ENOMEM;
-  stream->owner = owner;
-  stream->flags = flags;
-  /* By default unbuffered, the buffering scheme is not for all models, it
-     really makes sense for network streams, where there is no offset.  */
-  /* stream->rbuffer.bufsiz = BUFSIZ; */
-  *pstream = stream;
-  return 0;
-}
+#include <mailutils/nls.h>
+#include <mailutils/stream.h>
+#include <mailutils/sys/stream.h>
 
-void
-mu_stream_destroy (mu_stream_t *pstream, void *owner)
+static void
+_stream_setflag (struct _mu_stream *stream, int flag)
 {
-   if (pstream && *pstream)
-    {
-      mu_stream_t stream = *pstream;
-      if ((stream->flags & MU_STREAM_NO_CHECK) || stream->owner == owner)
-       {
-         mu_stream_close (stream);
-         if (stream->rbuffer.base)
-           free (stream->rbuffer.base);
-
-         if (stream->_destroy)
-           stream->_destroy (stream);
-
-         free (stream);
-       }
-      *pstream = NULL;
-    }
+  if (stream->event_cb && (stream->event_mask & flag))
+    stream->event_cb (stream, _MU_STR_EVENT_SET, flag);
+  stream->flags |= flag;
 }
 
-void *
-mu_stream_get_owner (mu_stream_t stream)
+static void
+_stream_clrflag (struct _mu_stream *stream, int flag)
 {
-  return (stream) ? stream->owner : NULL;
+  if (stream->event_cb && (stream->event_mask & flag))
+    stream->event_cb (stream, _MU_STR_EVENT_CLR, flag);
+  stream->flags &= ~flag;
 }
 
 int
-mu_stream_open (mu_stream_t stream)
+mu_stream_seterr (struct _mu_stream *stream, int code, int perm)
 {
-  if (stream == NULL)
-    return EINVAL;
-  stream->state = MU_STREAM_STATE_OPEN;
-
-  if (stream->_open)
-    return stream->_open (stream);
-  return  0;
-}
-
-int
-mu_stream_close (mu_stream_t stream)
-{
-  if (stream == NULL)
-    return EINVAL;
-  if (stream->state == MU_STREAM_STATE_CLOSE)
-    return 0;
-
-  stream->state = MU_STREAM_STATE_CLOSE;
-  /* Clear the buffer of any residue left.  */
-  if (stream->rbuffer.base)
+  stream->last_err = code;
+  switch (code)
     {
-      stream->rbuffer.ptr = stream->rbuffer.base;
-      stream->rbuffer.count = 0;
-      memset (stream->rbuffer.base, '\0', stream->rbuffer.bufsiz);
+    case 0:
+    case EAGAIN:
+    case EINPROGRESS:
+      break;
+
+    default:
+      if (perm)
+       _stream_setflag (stream, _MU_STR_ERR);
     }
-  if (stream->_close)
-    return stream->_close (stream);
-  return  0;
+  return code;
 }
 
-int
-mu_stream_is_seekable (mu_stream_t stream)
+void
+_mu_stream_cleareof (mu_stream_t str)
 {
-  return (stream) ? stream->flags & MU_STREAM_SEEKABLE : 0;
+  _stream_clrflag (str, _MU_STR_EOF);
 }
 
-int
-mu_stream_setbufsiz (mu_stream_t stream, size_t size)
+void
+_mu_stream_seteof (mu_stream_t str)
 {
-  if (stream == NULL)
-    return EINVAL;
-  stream->rbuffer.bufsiz = size;
-  return 0;
+  _stream_setflag (str, _MU_STR_EOF);
 }
 
-/* We have to be clear about the buffering scheme, it is not designed to be
-   used as a full-fledged buffer mechanism.  It is a simple mechanism for
-   networking. Lots of code between POP and IMAP can be shared this way.
-   - First caveat; the code maintains its own offset (rbuffer.offset member)
-   and if it does not match the requested one, the data is flushed
-   and the underlying _read is called. It is up to the latter to return
-   EISPIPE when appropriate.
-   - Again, this is targeting networking stream to make readline()
-   a little bit more efficient, instead of reading a char at a time.  */
+#define _stream_advance_buffer(s,n) ((s)->cur += n, (s)->level -= n)
+#define _stream_buffer_offset(s) ((s)->cur - (s)->buffer)
+#define _stream_orig_level(s) ((s)->level + _stream_buffer_offset (s))
+#define _stream_buffer_freespace(s) \
+  ((s)->bufsize - (s)->level - _stream_buffer_offset(s))
+#define _stream_buffer_is_full(s) (_stream_buffer_freespace(s) == 0)
 
-int
-mu_stream_read (mu_stream_t is, char *buf, size_t count,
-               mu_off_t offset, size_t *pnread)
+static int
+_stream_fill_buffer (struct _mu_stream *stream)
 {
-  int status = 0;
-  if (is == NULL || is->_read == NULL)
-    return EINVAL;
-
-  is->state = MU_STREAM_STATE_READ;
-
-  /* Sanity check; noop.  */
-  if (count == 0)
+  size_t n;
+  size_t rdn;
+  int rc = 0;
+  char c;
+    
+  switch (stream->buftype)
     {
-      if (pnread)
-       *pnread = 0;
+    case mu_buffer_none:
       return 0;
-    }
-
-  /* If rbuffer.bufsiz == 0.  It means they did not want the buffer
-     mechanism.  Good for them.  */
-  if (is->rbuffer.bufsiz == 0)
-    status = is->_read (is, buf, count, offset, pnread);
-  else
-    {
-      size_t residue = count;
-      size_t r;
-
-      /* If the amount requested is bigger than the buffer cache size,
-        bypass it.  Do no waste time and let it through.  */
-      if (count > is->rbuffer.bufsiz)
-       {
-         r = 0;
-         /* Drain the buffer first.  */
-         if (is->rbuffer.count > 0 && offset == is->rbuffer.offset)
-           {
-             memcpy(buf, is->rbuffer.ptr, is->rbuffer.count);
-             is->rbuffer.offset += is->rbuffer.count;
-             residue -= is->rbuffer.count;
-             buf += is->rbuffer.count;
-             offset += is->rbuffer.count;
-           }
-         is->rbuffer.count = 0;
-         status = is->_read (is, buf, residue, offset, &r);
-         is->rbuffer.offset += r;
-         residue -= r;
-         if (pnread)
-           *pnread = count - residue;
-         return status;
-       }
-
-      /* Fill the buffer, do not want to start empty hand.  */
-      if (is->rbuffer.count <= 0 || offset != is->rbuffer.offset)
-       {
-         status = refill (is, offset);
-         if (status != 0)
-           return status;
-         /* Reached the end ??  */
-         if (is->rbuffer.count == 0)
-           {
-             if (pnread)
-               *pnread = 0;
-             return status;
-           }
-       }
-
-      /* Drain the buffer, if we have less then requested.  */
-      while (residue > (size_t)(r = is->rbuffer.count))
+       
+    case mu_buffer_full:
+      rc = mu_stream_read_unbuffered (stream,
+                                     stream->buffer, stream->bufsize,
+                                     0,
+                                     &stream->level);
+      break;
+       
+    case mu_buffer_line:
+      for (n = 0;
+          n < stream->bufsize
+            && (rc = mu_stream_read_unbuffered (stream,
+                                                &c, 1, 0, &rdn)) == 0;)
        {
-         memcpy (buf, is->rbuffer.ptr, (size_t)r);
-         /* stream->rbuffer.count = 0 ... done in refill */
-         is->rbuffer.ptr += r;
-         is->rbuffer.offset += r;
-         buf += r;
-         residue -= r;
-         status = refill (is, is->rbuffer.offset);
-         if (status != 0)
-           {
-             /* We have something in the buffer return the error on the
-                next call .  */
-             if (count != residue)
-               {
-                 if (pnread)
-                   *pnread = count - residue;
-                 status = 0;
-               }
-             return status;
-           }
-         /* Did we reach the end.  */
-         if (is->rbuffer.count == 0)
+         if (rdn == 0)
            {
-             if (pnread)
-               *pnread = count - residue;
-             return status;
+             _stream_setflag (stream, _MU_STR_EOF);
+             break;
            }
+         stream->buffer[n++] = c;
+         if (c == '\n')
+           break;
        }
-      memcpy(buf, is->rbuffer.ptr, residue);
-      is->rbuffer.count -= residue;
-      is->rbuffer.ptr += residue;
-      is->rbuffer.offset += residue;
-      if (pnread)
-       *pnread = count;
+      stream->level = n;
+      break;
     }
-  return status;
+  stream->cur = stream->buffer;
+  return rc;
 }
 
-/*
- * Read at most n-1 characters.
- * Stop when a newline has been read, or the count runs out.
- */
-int
-mu_stream_readline (mu_stream_t is, char *buf, size_t count,
-                   mu_off_t offset, size_t *pnread)
+static int
+_stream_buffer_full_p (struct _mu_stream *stream)
 {
-  int status = 0;
-
-  if (is == NULL)
-    return EINVAL;
-
-  is->state = MU_STREAM_STATE_READ;
+    switch (stream->buftype)
+      {
+      case mu_buffer_none:
+       break;
+       
+      case mu_buffer_line:
+       return _stream_buffer_is_full (stream)
+              || memchr (stream->cur, '\n', stream->level) != NULL;
 
-  switch (count)
-    {
-    case 1:
-      /* why would they do a thing like that?
-        mu_stream_readline() is __always null terminated.  */
-      if (buf)
-       *buf = '\0';
-    case 0: /* Buffer is empty noop.  */
-      if (pnread)
-       *pnread = 0;
-      return 0;
-    }
+      case mu_buffer_full:
+       return _stream_buffer_is_full (stream);
+      }
+    return 0;
+}
 
-  /* Use the provided readline.  */
-  if (is->rbuffer.bufsiz == 0 &&  is->_readline != NULL)
-    status = is->_readline (is, buf, count, offset, pnread);
-  else if (is->rbuffer.bufsiz == 0) /* No Buffering.  */
-    {
-      size_t n, nr = 0;
-      char c;
-      /* Grossly inefficient hopefully they override this */
-      count--;  /* Leave space for the null.  */
-      for (n = 0; n < count; )
-       {
-         status = is->_read (is, &c, 1, offset, &nr);
-         if (status != 0) /* Error.  */
-           return status;
-         else if (nr == 1)
-           {
-             *buf++ = c;
-             offset++;
-             n++;
-             if (c == '\n') /* Newline is stored like fgets().  */
-               break;
-           }
-         else if (nr == 0)
-           break; /* EOF */
-       }
-      *buf = '\0';
-      if (pnread)
-       *pnread = n;
-    }
-  else /* Buffered.  */
+static int
+_stream_flush_buffer (struct _mu_stream *stream, int all)
+{
+  int rc;
+  char *end;
+                 
+  if (stream->flags & _MU_STR_DIRTY)
     {
-      char *s = buf;
-      char *p, *nl;
-      size_t len;
-      size_t total = 0;
-
-      count--;  /* Leave space for the null.  */
-
-      /* If out of range refill.  */
-      /*      if ((offset < is->rbuffer.offset */
-      /*          || offset > (is->rbuffer.offset + is->rbuffer.count))) */
-      if (offset != is->rbuffer.offset)
+      if ((stream->flags & MU_STREAM_SEEK) && stream->seek)
        {
-         status = refill (is, offset);
-         if (status != 0)
-           return status;
-         if (is->rbuffer.count == 0)
-           {
-             if (pnread)
-               *pnread = 0;
-             return 0;
-           }
+         mu_off_t off;
+         rc = stream->seek (stream, stream->offset, &off);
+         if (rc)
+           return rc;
        }
 
-      while (count != 0)
+      switch (stream->buftype)
        {
-         /* If the buffer is empty refill it.  */
-         len = is->rbuffer.count;
-         if (len <= 0)
+       case mu_buffer_none:
+           abort(); /* should not happen */
+           
+       case mu_buffer_full:
+         if ((rc = mu_stream_write_unbuffered (stream, stream->cur,
+                                               stream->level, 1, NULL)))
+           return rc;
+         _stream_advance_buffer (stream, stream->level);
+         break;
+           
+       case mu_buffer_line:
+         if (stream->level == 0)
+           break;
+         for (end = memchr (stream->cur, '\n', stream->level);
+              end;
+              end = memchr (stream->cur, '\n', stream->level))
            {
-             status = refill (is, is->rbuffer.offset);
-             if (status != 0)
-               {
-                 if (s != buf)
-                   break;
-               }
-             len = is->rbuffer.count;
-             if (len == 0)
-               break;
+             size_t size = end - stream->cur + 1;
+             rc = mu_stream_write_unbuffered (stream,
+                                              stream->cur,
+                                              size, 1, NULL);
+             if (rc)
+               return rc;
+             _stream_advance_buffer (stream, size);
            }
-         p = is->rbuffer.ptr;
-
-         /* Scan through at most n bytes of the current buffer,
-            looking for '\n'.  If found, copy up to and including
-            newline, and stop.  Otherwise, copy entire chunk
-            and loop.  */
-         if (len > count)
-           len = count;
-         nl = memchr ((void *)p, '\n', len);
-         if (nl != NULL)
+         if ((all && stream->level) || _stream_buffer_is_full (stream))
            {
-             len = ++nl - p;
-             is->rbuffer.count -= len;
-             is->rbuffer.ptr = nl;
-             is->rbuffer.offset += len;
-             memcpy ((void *)s, (void *)p, len);
-             total += len;
-             s[len] = 0;
-             if (pnread)
-               *pnread = total;
-             return 0;
+             rc = mu_stream_write_unbuffered (stream,
+                                              stream->cur,
+                                              stream->level,
+                                              1, NULL);
+             if (rc)
+               return rc;
+             _stream_advance_buffer (stream, stream->level);
            }
-         is->rbuffer.count -= len;
-         is->rbuffer.ptr += len;
-         is->rbuffer.offset += len;
-         memcpy((void *)s, (void *)p, len);
-         total += len;
-         s += len;
-         count -= len;
-        }
-      *s = 0;
-      if (pnread)
-       *pnread = s - buf;
+       }
     }
-  return status;
-}
-
-int
-mu_stream_getline (mu_stream_t is, char **pbuf, size_t *pbufsize,
-                  mu_off_t offset, size_t *pnread)
-{
-  char *buf = *pbuf;
-  size_t bufsize = *pbufsize;
-  size_t total = 0, off = 0;
-  int rc = 0;
-#define DELTA 128
+  else if (all)
+    _stream_advance_buffer (stream, stream->level);
   
-  if (buf == NULL)
+  if (stream->level)
     {
-      bufsize = DELTA;
-      buf = malloc (bufsize);
-      if (!buf)
-       return ENOMEM;
+      if (stream->cur > stream->buffer)
+       memmove (stream->buffer, stream->cur, stream->level);
     }
-
-  do
-    {
-      size_t nread;
-      int rc;
-
-      if (off == bufsize)
-       {
-         char *p;
-         p = realloc (buf, bufsize + DELTA);
-         if (!p)
-           {
-             rc = ENOMEM;
-             break;
-           }
-         bufsize += DELTA;
-         buf = p;
-       }
-      
-      rc = mu_stream_readline (is, buf + off, bufsize - off, offset + off,
-                              &nread);
-      if (rc)
-       {
-         if (*pbuf)
-           free (buf);
-         return rc;
-       }
-      if (nread == 0)
-       break;
-      off += nread;
-      total += nread;
-    }
-  while (buf[off - 1] != '\n');
-
-  if (rc && !*pbuf)
-    free (buf);
   else
     {
-      *pbuf = buf;
-      *pbufsize = bufsize;
-      if (pnread)
-       *pnread = total;
+      _stream_clrflag (stream, _MU_STR_DIRTY);
+      stream->level = 0;
     }
-  return rc;
+  stream->cur = stream->buffer;
+  return 0;
 }
 
-int
-mu_stream_write (mu_stream_t os, const char *buf, size_t count,
-                mu_off_t offset, size_t *pnwrite)
+
+mu_stream_t
+_mu_stream_create (size_t size, int flags)
 {
-  int nleft;
-  int err = 0;
-  size_t nwriten = 0;
-  size_t total = 0;
-
-  if (os == NULL || os->_write == NULL)
-      return EINVAL;
-  os->state = MU_STREAM_STATE_WRITE;
-
-  nleft = count;
-  /* First try to send it all.  */
-  while (nleft > 0)
-    {
-      err = os->_write (os, buf, nleft, offset, &nwriten);
-      if (err != 0 || nwriten == 0)
-        break;
-      nleft -= nwriten;
-      total += nwriten;
-      buf += nwriten;
-    }
-  if (pnwrite)
-    *pnwrite = total;
-  return err;
+  struct _mu_stream *str;
+  if (size < sizeof (str))
+    abort ();
+  str = mu_zalloc (size);
+  str->flags = flags;
+  mu_stream_ref (str);
+  return str;
 }
 
-int
-mu_stream_vprintf (mu_stream_t os, mu_off_t *poff, const char *fmt, va_list ap)
+void
+mu_stream_destroy (mu_stream_t *pstream)
 {
-  char *buf = NULL, *p;
-  size_t buflen = 0;
-  size_t n;
-  int rc;
-
-  rc = mu_vasnprintf (&buf, &buflen, fmt, ap);
-  if (rc)
-    return rc;
-  p = buf;
-  n = strlen (buf);
-  do
+  if (pstream)
     {
-      size_t wrs;
-
-      rc = mu_stream_write (os, p, n, *poff, &wrs);
-      if (rc || wrs == 0)
-        break;
-      p += wrs;
-      *poff += wrs;
-      n -= wrs;
+      mu_stream_t str = *pstream;
+      if (str && (str->ref_count == 0 || --str->ref_count == 0))
+       {
+         mu_stream_close (str);
+         if (str->done)
+           str->done (str);
+         free (str);
+         *pstream = NULL;
+       }
     }
-  while (n > 0);
-  free (buf);
-  return rc;
 }
 
-int
-mu_stream_printf (mu_stream_t os, mu_off_t *poff, const char *fmt, ...)
-{ 
-  va_list ap;
-  int rc;
-       
-  va_start (ap, fmt);
-  rc = mu_stream_vprintf (os, poff, fmt, ap);
-  va_end (ap);
-  return rc;
+void
+mu_stream_get_flags (mu_stream_t str, int *pflags)
+{
+  *pflags = str->flags & ~_MU_STR_INTERN_MASK;
 }
-
-int
-mu_stream_sequential_vprintf (mu_stream_t os, const char *fmt, va_list ap)
+  
+void
+mu_stream_ref (mu_stream_t stream)
 {
-  return mu_stream_vprintf (os, &os->offset, fmt, ap);
+  stream->ref_count++;
 }
 
-int
-mu_stream_sequential_printf (mu_stream_t os, const char *fmt, ...)
+void
+mu_stream_unref (mu_stream_t stream)
 {
-  va_list ap;
-  int rc;
-       
-  va_start (ap, fmt);
-  rc = mu_stream_sequential_vprintf (os, fmt, ap);
-  va_end (ap);
-  return rc;
+  mu_stream_destroy (&stream);
 }
 
 int
-mu_stream_get_transport2 (mu_stream_t stream,
-                         mu_transport_t *p1, mu_transport_t *p2)
+mu_stream_open (mu_stream_t stream)
 {
-  if (stream == NULL || stream->_get_transport2 == NULL)
-    return EINVAL;
-  return stream->_get_transport2 (stream, p1, p2);
+  int rc;
+
+  if (stream->open && (rc = stream->open (stream)))
+    return mu_stream_seterr (stream, rc, 1);
+  stream->bytes_in = stream->bytes_out = 0;
+  return 0;
 }
 
-int
-mu_stream_get_transport (mu_stream_t stream, mu_transport_t *pt)
+const char *
+mu_stream_strerror (mu_stream_t stream, int rc)
 {
-  return mu_stream_get_transport2 (stream, pt, NULL);
+  const char *str;
+
+  if (stream->error_string)
+    str = stream->error_string (stream, rc);
+  else
+    str = mu_strerror (rc);
+  return str;
 }
 
 int
-mu_stream_get_flags (mu_stream_t stream, int *pfl)
+mu_stream_err (mu_stream_t stream)
 {
-  if (stream == NULL)
-    return EINVAL;
-  if (pfl == NULL)
-    return MU_ERR_OUT_NULL;
-  *pfl = stream->flags;
-  return 0;
+  return stream->flags & _MU_STR_ERR;
 }
 
 int
-mu_stream_set_property (mu_stream_t stream, mu_property_t property, void 
*owner)
+mu_stream_last_error (mu_stream_t stream)
 {
-  if (stream == NULL)
-    return EINVAL;
-  if (stream->owner != owner)
-    return EACCES;
-  if (stream->property)
-    mu_property_destroy (&(stream->property), stream);
-  stream->property = property;
-  return 0;
+  return stream->last_err;
 }
 
-int
-mu_stream_get_property (mu_stream_t stream, mu_property_t *pp)
+void
+mu_stream_clearerr (mu_stream_t stream)
 {
-  if (stream == NULL)
-    return EINVAL;
-  if (stream->property == NULL)
-    {
-      int status = mu_property_create (&(stream->property), stream);
-      if (status != 0)
-       return status;
-    }
-  *pp = stream->property;
-  return 0;
+  stream->last_err = 0;
+  _stream_clrflag (stream, _MU_STR_ERR);
 }
 
 int
-mu_stream_size (mu_stream_t stream, mu_off_t *psize)
+mu_stream_eof (mu_stream_t stream)
 {
-  if (stream == NULL || stream->_size == NULL)
-    return EINVAL;
-  return stream->_size (stream, psize);
+  return stream->flags & _MU_STR_EOF;
 }
 
 int
-mu_stream_truncate (mu_stream_t stream, mu_off_t len)
-{
-  if (stream == NULL || stream->_truncate == NULL )
-    return EINVAL;
+mu_stream_seek (mu_stream_t stream, mu_off_t offset, int whence,
+               mu_off_t *pres)
+{    
+  int rc;
+  mu_off_t size;
+  
+  if (!stream->seek)
+    return mu_stream_seterr (stream, ENOSYS, 0);
 
-  return stream->_truncate (stream, len);
-}
+  if (!(stream->flags & MU_STREAM_SEEK))
+    return mu_stream_seterr (stream, EACCES, 1);
 
+  switch (whence)
+    {
+    case MU_SEEK_SET:
+      break;
 
-int
-mu_stream_flush (mu_stream_t stream)
-{
-  if (stream == NULL || stream->_flush == NULL)
-    return EINVAL;
-  return stream->_flush (stream);
-}
+    case MU_SEEK_CUR:
+      if (offset == 0)
+       {
+         *pres = stream->offset + _stream_buffer_offset (stream);
+         return 0;
+       }
+      offset += stream->offset;
+      break;
 
+    case MU_SEEK_END:
+      rc = mu_stream_size (stream, &size);
+      if (rc)
+       return mu_stream_seterr (stream, rc, 1);
+      offset += size;
+      break;
 
-int
-mu_stream_get_state (mu_stream_t stream, int *pstate)
-{
-  if (stream == NULL)
-    return EINVAL;
-  if (pstate == NULL)
-    return MU_ERR_OUT_PTR_NULL;
-  *pstate = stream->state;
+    default:
+      return mu_stream_seterr (stream, EINVAL, 1);
+    }
+
+  if (stream->buftype == mu_buffer_none
+      || offset < stream->offset
+      || offset > stream->offset + _stream_buffer_offset (stream))
+    {
+      if ((rc = _stream_flush_buffer (stream, 1)))
+       return rc;
+      rc = stream->seek (stream, offset, &stream->offset);
+      if (rc == ESPIPE)
+       return rc;
+      if (rc)
+       return mu_stream_seterr (stream, rc, 1);
+      _mu_stream_cleareof (stream);
+    }
+  
+  if (pres)
+    *pres = stream->offset + _stream_buffer_offset (stream);
   return 0;
 }
 
+/* Skip COUNT bytes from the current position in stream by reading from
+   it.  Return new offset in PRES.
+
+   Return 0 on success, EACCES if STREAM was not opened for reading.
+   Another non-zero exit codes are propagated from the underlying
+   input operations.
+   
+   This function is designed to help implement seek method in otherwise
+   unseekable streams (such as filters).  Do not use it if you absolutely
+   have to.  Using it on an unbuffered stream is a terrible waste of CPU. */
 int
-mu_stream_shutdown (mu_stream_t stream, int how)
+mu_stream_skip_input_bytes (mu_stream_t stream, mu_off_t count, mu_off_t *pres)
 {
-  if (stream == NULL)
-    return EINVAL;
-  if (!stream->_shutdown)
-    return ENOSYS;
-  switch (how)
-    {
-    case MU_STREAM_READ:
-    case MU_STREAM_WRITE:
-      break;
+  mu_off_t pos;
+  int rc;
 
-    default:
-      return EINVAL;
+  if (!(stream->flags & MU_STREAM_READ))
+    return mu_stream_seterr (stream, EACCES, 1);
+
+  if (stream->buftype == mu_buffer_none)
+    {
+      for (pos = 0; pos < count; pos++)
+       {
+         char c;
+         size_t nrd;
+         rc = mu_stream_read (stream, &c, 1, &nrd);
+         if (nrd == 0)
+           rc = ESPIPE;
+         if (rc)
+           break;
+       }
     }
-  return stream->_shutdown (stream, how);
+  else
+    {
+      for (pos = 0;;)
+       {
+         if ((rc = _stream_flush_buffer (stream, 1)))
+           return rc;
+         if (stream->level == 0)
+           {
+             rc = _stream_fill_buffer (stream);
+             if (rc)
+               break;
+             if (stream->level == 0)
+               {
+                 rc = ESPIPE;
+                 break;
+               }
+           }
+         if (pos <= count && count < pos + stream->level)
+           {
+             size_t delta = count - pos;
+             _stream_advance_buffer (stream, delta);
+             pos = count;
+             rc = 0;
+             break;
+           }
+         pos += stream->level;
+       }
+    }
+  
+  stream->offset += pos;
+  if (pres)
+    *pres = stream->offset;
+  return rc;
 }
 
 int
-mu_stream_set_destroy (mu_stream_t stream,
-                      void (*_destroy) (mu_stream_t), void *owner)
+mu_stream_set_buffer (mu_stream_t stream, enum mu_buffer_type type,
+                     size_t size)
 {
-  if (stream == NULL)
-    return EINVAL;
+  if (size == 0)
+    type = mu_buffer_none;
 
-  if (stream->owner != owner)
-    return EACCES;
+  if (stream->buffer)
+    {
+      mu_stream_flush (stream);
+      free (stream->buffer);
+    }
 
-  stream->_destroy = _destroy;
+  stream->buftype = type;
+  if (type == mu_buffer_none)
+    {
+      stream->buffer = NULL;
+      return 0;
+    }
+
+  stream->buffer = mu_alloc (size);
+  if (stream->buffer == NULL)
+    {
+      stream->buftype = mu_buffer_none;
+      return mu_stream_seterr (stream, ENOMEM, 1);
+    }
+  stream->bufsize = size;
+  stream->cur = stream->buffer;
+  stream->level = 0;
+    
   return 0;
 }
 
 int
-mu_stream_set_open (mu_stream_t stream,
-                   int (*_open) (mu_stream_t), void *owner)
+mu_stream_read_unbuffered (mu_stream_t stream, void *buf, size_t size,
+                          int full_read,
+                          size_t *pnread)
 {
-  if (stream == NULL)
-    return EINVAL;
-  if (owner == stream->owner)
+  int rc;
+  size_t nread;
+    
+  if (!stream->read) 
+    return mu_stream_seterr (stream, ENOSYS, 0);
+
+  if (!(stream->flags & MU_STREAM_READ)) 
+    return mu_stream_seterr (stream, EACCES, 1);
+    
+  if (stream->flags & _MU_STR_ERR)
+    return stream->last_err;
+    
+  if ((stream->flags & _MU_STR_EOF) || size == 0)
     {
-      stream->_open = _open;
+      if (pnread)
+       *pnread = 0;
       return 0;
     }
-  return EACCES;
+    
+    if (full_read)
+      {
+       size_t rdbytes;
+
+       nread = 0;
+       while (size > 0
+              && (rc = stream->read (stream, buf, size, &rdbytes)) == 0)
+         {
+           if (rdbytes == 0)
+             {
+               _stream_setflag (stream, _MU_STR_EOF);
+               break;
+             }
+           buf += rdbytes;
+           nread += rdbytes;
+           size -= rdbytes;
+           stream->bytes_in += rdbytes;
+           
+         }
+       if (size && rc)
+         rc = mu_stream_seterr (stream, rc, 0);
+      }
+    else
+      {
+       rc = stream->read (stream, buf, size, &nread);
+       if (rc == 0)
+         {
+           if (nread == 0)
+             _stream_setflag (stream, _MU_STR_EOF);
+           stream->bytes_in += nread;
+         }
+       mu_stream_seterr (stream, rc, rc != 0);
+      }
+    stream->offset += nread;
+    if (pnread)
+      *pnread = nread;
+    
+    return rc;
 }
 
 int
-mu_stream_set_close (mu_stream_t stream,
-                    int (*_close) (mu_stream_t), void *owner)
+mu_stream_write_unbuffered (mu_stream_t stream,
+                           const void *buf, size_t size,
+                           int full_write,
+                           size_t *pnwritten)
 {
-  if (stream == NULL)
-    return EINVAL;
-  if (owner == stream->owner)
+  int rc;
+  size_t nwritten;
+  
+  if (!stream->write) 
+    return mu_stream_seterr (stream, ENOSYS, 0);
+
+  if (!(stream->flags & MU_STREAM_WRITE)) 
+    return mu_stream_seterr (stream, EACCES, 1);
+
+  if (stream->flags & _MU_STR_ERR)
+    return stream->last_err;
+
+  if (size == 0)
     {
-      stream->_close = _close;
+      if (pnwritten)
+       *pnwritten = 0;
       return 0;
     }
-  return EACCES;
+    
+  if (full_write)
+    {
+      size_t wrbytes;
+      const char *bufp = buf;
+
+      nwritten = 0;
+      while (size > 0
+            && (rc = stream->write (stream, bufp, size, &wrbytes))
+                    == 0)
+       {
+         if (wrbytes == 0)
+           {
+             rc = EIO;
+             break;
+           }
+         bufp += wrbytes;
+         nwritten += wrbytes;
+         size -= wrbytes;
+         stream->bytes_out += wrbytes;
+       }
+    }
+  else
+    {
+      rc = stream->write (stream, buf, size, &nwritten);
+      if (rc == 0)
+       stream->bytes_out += nwritten;
+    }
+  _stream_setflag (stream, _MU_STR_WRT);
+  stream->offset += nwritten;
+  if (pnwritten)
+    *pnwritten = nwritten;
+  mu_stream_seterr (stream, rc, rc != 0);
+  return rc;
 }
 
 int
-mu_stream_set_get_transport2 (mu_stream_t stream,
-                             int (*_get_trans) (mu_stream_t,
-                                                mu_transport_t *,
-                                                mu_transport_t *),
-                             void *owner)
+mu_stream_read (mu_stream_t stream, void *buf, size_t size, size_t *pread)
 {
-  if (stream == NULL)
-    return EINVAL;
-  if (owner == stream->owner)
+  if (stream->buftype == mu_buffer_none)
+    return mu_stream_read_unbuffered (stream, buf, size, !pread, pread);
+  else
     {
-      stream->_get_transport2 = _get_trans;
-      return 0;
+      char *bufp = buf;
+      size_t nbytes = 0;
+      while (size)
+       {
+         size_t n;
+         int rc;
+         
+         if (stream->level == 0)
+           {
+             if ((rc = _stream_fill_buffer (stream)))
+               {
+                 if (nbytes)
+                   break;
+                 return rc;
+               }
+             if (stream->level == 0)
+               break;
+           }
+         
+         n = size;
+         if (n > stream->level)
+           n = stream->level;
+         memcpy (bufp, stream->cur, n);
+         _stream_advance_buffer (stream, n);
+         nbytes += n;
+         bufp += n;
+         size -= n;
+         if (stream->buftype == mu_buffer_line && bufp[-1] == '\n')
+           break;
+       }
+      
+      if (pread)
+       *pread = nbytes;
     }
-  return EACCES;
+  return 0;
 }
 
 int
-mu_stream_set_read (mu_stream_t stream,
-                   int (*_read) (mu_stream_t, char *, size_t,
-                                 mu_off_t, size_t *),
-                   void *owner)
+_stream_scandelim (mu_stream_t stream, char *buf, size_t size, int delim,
+                  size_t *pnread)
 {
-  if (stream == NULL)
-    return EINVAL;
-  if (owner == stream->owner)
+  int rc = 0;
+  size_t nread = 0;
+  
+  size--;
+  if (size == 0)
+    return MU_ERR_BUFSPACE;
+  while (size)
     {
-      stream->_read = _read;
-      return 0;
+      char *p;
+      size_t len;
+      
+      if (stream->level == 0)
+       {
+         if ((rc = _stream_fill_buffer (stream)) || stream->level == 0)
+           break;
+       }
+      
+      p = memchr (stream->cur, delim, stream->level);
+      len = p ? p - stream->cur + 1 : stream->level;
+      if (len > size)
+       len = size;
+      memcpy (buf, stream->cur, len);
+      _stream_advance_buffer (stream, len);
+      buf += len;
+      size -= len;
+      nread += len;
+      if (p) /* Delimiter found */
+       break;
     }
-  return EACCES;
+  *buf = 0;
+  *pnread = nread;
+  return rc;
 }
 
-int
-mu_stream_set_readline (mu_stream_t stream,
-                       int (*_readline) (mu_stream_t, char *, size_t,
-                                         mu_off_t, size_t *),
-                       void *owner)
+static int
+_stream_readdelim (mu_stream_t stream, char *buf, size_t size,
+                  int delim, size_t *pread)
 {
-  if (stream == NULL)
-    return EINVAL;
-  if (owner == stream->owner)
+  int rc;
+  char c;
+  size_t n = 0, rdn;
+    
+  size--;
+  if (size == 0)
+    return MU_ERR_BUFSPACE;
+  for (n = 0;
+       n < size && (rc = mu_stream_read (stream, &c, 1, &rdn)) == 0 && rdn;)
     {
-      stream->_readline = _readline;
-      return 0;
+      *buf++ = c;
+      n++;
+      if (c == delim)
+       break;
     }
-  return EACCES;
+  *buf = 0;
+  if (pread)
+    *pread = n;
+  return rc;
 }
 
 int
-mu_stream_set_write (mu_stream_t stream,
-                    int (*_write) (mu_stream_t, const char *, size_t,
-                                   mu_off_t, size_t *),
-                    void *owner)
+mu_stream_readdelim (mu_stream_t stream, char *buf, size_t size,
+                    int delim, size_t *pread)
 {
-  if (stream == NULL)
+  int rc;
+  
+  if (size == 0)
     return EINVAL;
-  if (stream->owner == owner)
+    
+  if (stream->readdelim)
+    rc = stream->readdelim (stream, buf, size, delim, pread);
+  else if (stream->buftype != mu_buffer_none)
+    rc = _stream_scandelim (stream, buf, size, delim, pread);
+  else
+    rc = _stream_readdelim (stream, buf, size, delim, pread);
+  return rc;
+}
+
+int
+mu_stream_readline (mu_stream_t stream, char *buf, size_t size, size_t *pread)
+{
+  return mu_stream_readdelim (stream, buf, size, '\n', pread);
+}
+
+int
+mu_stream_getdelim (mu_stream_t stream, char **pbuf, size_t *psize,
+                   int delim, size_t *pread)
+{
+  int rc;
+  char *lineptr = *pbuf;
+  size_t n = *psize;
+  size_t cur_len = 0;
+    
+  if (lineptr == NULL || n == 0)
     {
-      stream->_write = _write;
-      return 0;
+      char *new_lineptr;
+      n = 120;
+      new_lineptr = mu_realloc (lineptr, n);
+      if (new_lineptr == NULL) 
+       return ENOMEM;
+      lineptr = new_lineptr;
     }
-  return EACCES;
-}
+    
+  for (;;)
+    {
+      size_t rdn;
+
+      /* Make enough space for len+1 (for final NUL) bytes.  */
+      if (cur_len + 1 >= n)
+       {
+         size_t needed_max =
+           SSIZE_MAX < SIZE_MAX ? (size_t) SSIZE_MAX + 1 : SIZE_MAX;
+         size_t needed = 2 * n + 1;   /* Be generous. */
+         char *new_lineptr;
+         
+         if (needed_max < needed)
+           needed = needed_max;
+         if (cur_len + 1 >= needed)
+           {
+             rc = EOVERFLOW;
+             break;
+           }
+           
+         new_lineptr = mu_realloc (lineptr, needed);
+         if (new_lineptr == NULL)
+           {
+             rc = ENOMEM;
+             break;
+           }
+           
+         lineptr = new_lineptr;
+         n = needed;
+       }
 
+      if (stream->readdelim)
+       rc = stream->readdelim (stream, lineptr + cur_len, n - cur_len, delim,
+                               &rdn);
+      else if (stream->buftype != mu_buffer_none)
+       rc = _stream_scandelim (stream, lineptr + cur_len, n - cur_len, delim,
+                               &rdn);
+      else
+       rc = mu_stream_read (stream, lineptr + cur_len, 1, &rdn);
+
+      if (rc || rdn == 0)
+       break;
+      cur_len += rdn;
+      
+      if (lineptr[cur_len - 1] == delim)
+       break;
+    }
+  lineptr[cur_len] = '\0';
+    
+  *pbuf = lineptr;
+  *psize = n;
+  
+  if (pread)
+    *pread = cur_len;
+  return rc;
+}
 
 int
-mu_stream_set_size (mu_stream_t stream,
-                   int (*_size) (mu_stream_t, mu_off_t *),
-                   void *owner)
+mu_stream_getline (mu_stream_t stream, char **pbuf, size_t *psize,
+                  size_t *pread)
 {
-  if (stream == NULL)
-    return EINVAL;
-  if (stream->owner != owner)
-    return EACCES;
-  stream->_size = _size;
-  return 0;
+    return mu_stream_getdelim (stream, pbuf, psize, '\n', pread);
 }
 
 int
-mu_stream_set_truncate (mu_stream_t stream,
-                       int (*_truncate) (mu_stream_t, mu_off_t),
-                       void *owner)
+mu_stream_write (mu_stream_t stream, const void *buf, size_t size,
+                size_t *pnwritten)
 {
-  if (stream == NULL)
-    return EINVAL;
-  if (stream->owner != owner)
-    return EACCES;
-  stream->_truncate = _truncate;
-  return 0;
+  int rc = 0;
+  
+  if (stream->buftype == mu_buffer_none)
+    rc = mu_stream_write_unbuffered (stream, buf, size,
+                                    !pnwritten, pnwritten);
+  else
+    {
+      size_t nbytes = 0;
+      const char *bufp = buf;
+       
+      while (1)
+       {
+         size_t n;
+         
+         if (_stream_buffer_full_p (stream)
+             && (rc = _stream_flush_buffer (stream, 0)))
+           break;
+
+         if (size == 0)
+           break;
+           
+         n = _stream_buffer_freespace (stream);
+         if (n > size)
+           n = size;
+         memcpy (stream->cur + stream->level, bufp, n);
+         stream->level += n;
+         nbytes += n;
+         bufp += n;
+         size -= n;
+         _stream_setflag (stream, _MU_STR_DIRTY);
+       }
+      if (pnwritten)
+       *pnwritten = nbytes;
+    }
+  return rc;
 }
 
 int
-mu_stream_set_flush (mu_stream_t stream,
-                    int (*_flush) (mu_stream_t), void *owner)
+mu_stream_writeline (mu_stream_t stream, const char *buf, size_t size)
 {
-  if (stream == NULL)
-    return EINVAL;
-  if (stream->owner != owner)
-    return EACCES;
-  stream->_flush = _flush;
-  return 0;
+  int rc;
+  if ((rc = mu_stream_write (stream, buf, size, NULL)) == 0)
+    rc = mu_stream_write (stream, "\r\n", 2, NULL);
+  return rc;
 }
 
 int
-mu_stream_set_flags (mu_stream_t stream, int fl)
+mu_stream_flush (mu_stream_t stream)
 {
-  if (stream == NULL)
+  int rc;
+  
+  if (!stream)
     return EINVAL;
-  stream->flags |= fl;
+  rc = _stream_flush_buffer (stream, 1);
+  if (rc)
+    return rc;
+  if ((stream->flags & _MU_STR_WRT) && stream->flush)
+    return stream->flush (stream);
+  _stream_clrflag (stream, _MU_STR_WRT);
   return 0;
 }
 
 int
-mu_stream_clr_flags (mu_stream_t stream, int fl)
+mu_stream_close (mu_stream_t stream)
 {
-  if (stream == NULL)
+  int rc = 0;
+    
+  if (!stream)
     return EINVAL;
-  stream->flags &= ~fl;
-  return 0;
+  mu_stream_flush (stream);
+  /* Do close the stream only if it is not used by anyone else */
+  if (stream->ref_count > 1)
+    return 0;
+  if (stream->close)
+    rc = stream->close (stream);
+  return rc;
 }
 
 int
-mu_stream_set_strerror (mu_stream_t stream,
-                       int (*fp) (mu_stream_t, const char **), void *owner)
+mu_stream_size (mu_stream_t stream, mu_off_t *psize)
 {
-  if (stream == NULL)
-    return EINVAL;
-  if (stream->owner != owner)
-    return EACCES;
-  stream->_strerror = fp;
-  return 0;
+  int rc;
+    
+  if (!stream->size)
+    return mu_stream_seterr (stream, ENOSYS, 0);
+  rc = stream->size (stream, psize);
+  return mu_stream_seterr (stream, rc, rc != 0);
+}
+
+mu_off_t
+mu_stream_bytes_in (mu_stream_t stream)
+{
+  return stream->bytes_in;
+}
+
+mu_off_t
+mu_stream_bytes_out (mu_stream_t stream)
+{
+  return stream->bytes_out;
 }
 
 int
-mu_stream_set_wait (mu_stream_t stream,
-                   int (*wait) (mu_stream_t, int *, struct timeval *),
-                   void *owner)
+mu_stream_ioctl (mu_stream_t stream, int code, void *ptr)
 {
-  if (stream == NULL)
-    return EINVAL;
-  if (stream->owner != owner)
-    return EACCES;
-  stream->_wait = wait;
-  return 0;
+  if (stream->ctl == NULL)
+    return ENOSYS;
+  return stream->ctl (stream, code, ptr);
 }
 
 int
-mu_stream_set_shutdown (mu_stream_t stream,
-                       int (*_shutdown) (mu_stream_t, int how), void *owner)
+mu_stream_wait (mu_stream_t stream, int *pflags, struct timeval *tvp)
 {
+  int flg = 0;
   if (stream == NULL)
     return EINVAL;
-  if (owner == stream->owner)
+  
+  /* Take to acount if we have any buffering.  */
+  /* FIXME: How about MU_STREAM_READY_WR? */
+  if ((*pflags) & MU_STREAM_READY_RD 
+      && stream->buftype != mu_buffer_none
+      && stream->level > 0)
     {
-      stream->_shutdown = _shutdown;
-      return 0;
+      flg = MU_STREAM_READY_RD;
+      *pflags &= ~MU_STREAM_READY_RD;
     }
-  return EACCES;
-}
 
-int
-mu_stream_sequential_read (mu_stream_t stream, char *buf, size_t size,
-                          size_t *nbytes)
-{
-  size_t rdbytes;
-  int rc = mu_stream_read (stream, buf, size, stream->offset, &rdbytes);
-  if (!rc)
+  if (stream->wait)
     {
-      stream->offset += rdbytes;
-      if (nbytes)
-       *nbytes = rdbytes;
+      int rc = stream->wait (stream, pflags, tvp);
+      if (rc == 0)
+       *pflags |= flg;
+      return rc;
     }
-  return rc;
+  
+  return ENOSYS;
 }
 
 int
-mu_stream_sequential_readline (mu_stream_t stream, char *buf, size_t size,
-                              size_t *nbytes)
+mu_stream_truncate (mu_stream_t stream, mu_off_t size)
 {
-  size_t rdbytes;
-  int rc = mu_stream_readline (stream, buf, size, stream->offset, &rdbytes);
-  if (!rc)
-    {
-      stream->offset += rdbytes;
-      if (nbytes)
-       *nbytes = rdbytes;
-    }
-  return rc;
+  if (stream->truncate)
+    return stream->truncate (stream, size);
+  return ENOSYS;
 }
 
 int
-mu_stream_sequential_getline  (mu_stream_t stream,
-                              char **pbuf, size_t *pbufsize,
-                              size_t *nbytes)
+mu_stream_shutdown (mu_stream_t stream, int how)
 {
-  size_t rdbytes;
-  int rc = mu_stream_getline (stream, pbuf, pbufsize, stream->offset, 
&rdbytes);
-  if (!rc)
-    {
-      stream->offset += rdbytes;
-      if (nbytes)
-       *nbytes = rdbytes;
-    }
-  return rc;
-}  
-
+  if (stream->shutdown)
+    return stream->shutdown (stream, how);
+  return ENOSYS;
+}
 
 int
-mu_stream_sequential_write (mu_stream_t stream, const char *buf, size_t size)
+mu_stream_set_flags (mu_stream_t stream, int fl)
 {
   if (stream == NULL)
     return EINVAL;
-  while (size > 0)
-    {
-      size_t sz;
-      int rc = mu_stream_write (stream, buf, size, stream->offset, &sz);
-      if (rc)
-       return rc;
-
-      buf += sz;
-      size -= sz;
-      stream->offset += sz;
-    }
+  stream->flags |= (fl & ~_MU_STR_INTERN_MASK);
   return 0;
 }
 
 int
-mu_stream_seek (mu_stream_t stream, mu_off_t off, int whence)
+mu_stream_clr_flags (mu_stream_t stream, int fl)
 {
-  mu_off_t size = 0;
-  size_t pos;
-  int rc;
+  if (stream == NULL)
+    return EINVAL;
+  stream->flags &= ~(fl & ~_MU_STR_INTERN_MASK);
+  return 0;
+}
 
-  if ((rc = mu_stream_size (stream, &size)))
-    return rc;
+static void
+swapstr (mu_stream_t stream, mu_stream_t *curstr, mu_stream_t *newstr)
+{
+  mu_stream_t tmp;
 
-  switch (whence)
+  tmp = *newstr;
+  *newstr = *curstr;
+  *curstr = tmp;
+  if (!(stream->flags & MU_STREAM_AUTOCLOSE))
     {
-    case SEEK_SET:
-      pos = off;
-      break;
-
-    case SEEK_CUR:
-      pos = off + stream->offset;
-      break;
-
-    case SEEK_END:
-      pos = size + off;
-      break;
-
-    default:
-      return EINVAL;
+      if (*newstr)
+       mu_stream_unref (*newstr);
+      if (tmp)
+       mu_stream_ref (tmp);
     }
-
-  if (pos > size)
-    return EIO;
-
-  stream->offset = pos;
-  return 0;
+  if (!tmp)
+    mu_stream_seterr (stream, MU_ERR_NO_TRANSPORT, 1);
+  else if (stream->last_err == MU_ERR_NO_TRANSPORT)
+    mu_stream_clearerr (stream);
 }
 
-int
-mu_stream_wait (mu_stream_t stream, int *pflags, struct timeval *tvp)
+static int
+swapstr_recursive (mu_stream_t stream, mu_stream_t *curstr,
+                  mu_stream_t *newstr, int flags)
 {
-  if (stream == NULL)
-    return EINVAL;
+  mu_stream_t strtab[2];
+  int rc = ENOSYS;
 
-  /* Take to acount if we have any buffering.  */
-  if ((*pflags) & MU_STREAM_READY_RD)
+  if (*curstr == NULL && *newstr == NULL)
+    return 0;
+  
+  if (*curstr)
     {
-      if (stream->rbuffer.count > 0)
+      strtab[0] = *newstr;
+      strtab[1] = NULL;
+      rc = mu_stream_ioctl (*curstr, MU_IOCTL_SWAP_STREAM, strtab);
+      if (rc)
        {
-         *pflags = 0;
-         *pflags |= MU_STREAM_READY_RD;
-         return 0;
+         if ((flags & _MU_SWAP_IOCTL_MUST_SUCCEED)
+             || !(rc == ENOSYS || rc == EINVAL))
+           return rc;
        }
     }
-
-  if (stream->_wait)
-    return stream->_wait (stream, pflags, tvp);
-  return ENOSYS;
+  if (rc == 0)
+    *newstr = strtab[0];
+  else
+    swapstr (stream, curstr, newstr);
+  return 0;
 }
 
+/* CURTRANS[2] contains I/O transport streams used by STREAM,
+   NEWTRANS[2] contains another pair of streams.
+   This function swaps the items of these two arrays using the
+   MU_IOCTL_SWAP_STREAM ioctl.  It is intended for use by STREAM's
+   ioctl method and is currently used by iostream.c */
+   
 int
-mu_stream_strerror (mu_stream_t stream, const char **p)
+_mu_stream_swap_streams (mu_stream_t stream, mu_stream_t *curtrans,
+                        mu_stream_t *newtrans, int flags)
 {
-  if (stream == NULL)
-    return EINVAL;
-  if (stream->_strerror)
-    return stream->_strerror (stream, p);
-  return ENOSYS;
-}
+  int rc;
 
-static int
-refill (mu_stream_t stream, mu_off_t offset)
-{
-  if (stream->_read)
+  rc = swapstr_recursive (stream, &curtrans[0], &newtrans[0], flags);
+  if (rc)
+    return rc;
+  if (flags & _MU_SWAP_FIRST_ONLY)
+    return 0;
+  rc = swapstr_recursive (stream, &curtrans[1], &newtrans[1], flags);
+  if (rc)
     {
-      int status;
-      if (stream->rbuffer.base == NULL)
+      int rc1 = swapstr_recursive (stream, &curtrans[0], &newtrans[0], flags);
+      if (rc1)
        {
-         stream->rbuffer.base = calloc (1, stream->rbuffer.bufsiz);
-         if (stream->rbuffer.base == NULL)
-           return ENOMEM;
+         mu_diag_output (MU_DIAG_CRIT,
+                         _("restoring streams on %p failed: %s"),
+                         stream, mu_strerror (rc1));
+         abort ();
        }
-      stream->rbuffer.ptr = stream->rbuffer.base;
-      stream->rbuffer.offset = offset;
-      stream->rbuffer.count = 0;
-      status = stream->_read (stream, stream->rbuffer.ptr,
-                             stream->rbuffer.bufsiz, offset,
-                             &stream->rbuffer.count);
-      return status;
     }
-  return ENOSYS;
+  return rc;
 }
+  
+
+
+
diff --git a/mailbox/stream_printf.c b/mailbox/stream_printf.c
new file mode 100644
index 0000000..947fd3b
--- /dev/null
+++ b/mailbox/stream_printf.c
@@ -0,0 +1,32 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 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 <mailutils/stream.h>
+
+int
+mu_stream_printf (mu_stream_t stream, const char *fmt, ...)
+{ 
+  va_list ap;
+  int rc;
+       
+  va_start (ap, fmt);
+  rc = mu_stream_vprintf (stream, fmt, ap);
+  va_end (ap);
+  return rc;
+}
diff --git a/mailbox/stream_vprintf.c b/mailbox/stream_vprintf.c
new file mode 100644
index 0000000..5bd9c09
--- /dev/null
+++ b/mailbox/stream_vprintf.c
@@ -0,0 +1,42 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 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 <mailutils/types.h>
+#include <mailutils/stream.h>
+#include <mailutils/io.h>
+#include <stdlib.h>
+#include <string.h>
+
+int
+mu_stream_vprintf (mu_stream_t str, const char *fmt, va_list ap)
+{
+  char *buf = NULL;
+  size_t buflen = 0;
+  size_t n;
+  int rc;
+
+  rc = mu_vasnprintf (&buf, &buflen, fmt, ap);
+  if (rc)
+    return rc;
+  n = strlen (buf);
+  rc = mu_stream_write (str, buf, n, NULL);
+  free (buf);
+  return rc;
+}
+
diff --git a/mailbox/streamcpy.c b/mailbox/streamcpy.c
new file mode 100644
index 0000000..4812667
--- /dev/null
+++ b/mailbox/streamcpy.c
@@ -0,0 +1,128 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 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 <mailutils/types.h>
+#include <mailutils/alloc.h>
+#include <mailutils/error.h>
+#include <mailutils/errno.h>
+#include <mailutils/stream.h>
+#include <mailutils/sys/stream.h>
+
+#define STREAMCPY_MIN_BUF_SIZE 2
+#define STREAMCPY_MAX_BUF_SIZE 16384
+
+/* Copy SIZE bytes from SRC to DST.  If SIZE is 0, copy everything up to
+   EOF. */
+int
+mu_stream_copy (mu_stream_t dst, mu_stream_t src, mu_off_t size,
+               mu_off_t *pcsz)
+{
+  int status;
+  size_t bufsize, n;
+  char *buf;
+  mu_off_t total = 0;
+  
+  if (pcsz)
+    *pcsz = 0;
+  if (size == 0)
+    {
+      status = mu_stream_size (src, &size);
+      switch (status)
+       {
+       case 0:
+         break;
+
+       case ENOSYS:
+         size = 0;
+         break;
+
+       default:
+         return status;
+       }
+      
+      if (size)
+       {
+         mu_off_t pos;
+         status = mu_stream_seek (src, 0, MU_SEEK_CUR, &pos);
+         switch (status)
+           {
+           case 0:
+             if (pos > size)
+               return ESPIPE;
+             size -= pos;
+             break;
+      
+           case EACCES:
+             mu_stream_clearerr (src);
+           case ENOSYS:
+             break;
+
+           default:
+             return status;
+           }
+       }
+    }
+
+  bufsize = size;
+  if (!bufsize)
+    bufsize = STREAMCPY_MAX_BUF_SIZE;
+
+  for (; (buf = malloc (bufsize)) == NULL; bufsize >>= 1)
+    if (bufsize < STREAMCPY_MIN_BUF_SIZE)
+      return ENOMEM;
+
+  if (size)
+    while (size)
+      {
+       size_t rdsize = bufsize < size ? bufsize : size;
+
+       status = mu_stream_read (src, buf, rdsize, &n);
+       if (status)
+         break;
+       if (n == 0)
+         {
+           status = EIO;
+           break;
+         }
+       status = mu_stream_write (dst, buf, n, NULL);
+       if (status)
+         break;
+       size -= rdsize;
+       total += rdsize;
+      }
+  else
+    while ((status = mu_stream_read (src, buf, bufsize, &n)) == 0
+          && n > 0)
+      {
+       status = mu_stream_write (dst, buf, n, NULL);
+       if (status)
+         break;
+       total += n;
+      }
+
+  if (pcsz)
+    *pcsz = total;
+  free (buf);
+  return status;
+}
+      
+
+  
+  
diff --git a/mailbox/streamref.c b/mailbox/streamref.c
new file mode 100644
index 0000000..b773983
--- /dev/null
+++ b/mailbox/streamref.c
@@ -0,0 +1,311 @@
+/* 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 <errno.h>
+#include <mailutils/types.h>
+#include <mailutils/stream.h>
+#include <mailutils/errno.h>
+#include <mailutils/sys/streamref.h>
+
+#define _MU_STR_ERRMASK (_MU_STR_ERR|_MU_STR_EOF)
+
+static int
+streamref_return (struct _mu_streamref *sp, int rc)
+{
+  if (rc)
+    sp->stream.last_err = sp->transport->last_err;
+  sp->stream.flags = (sp->stream.flags & ~_MU_STR_ERRMASK) |
+                   (sp->transport->flags & _MU_STR_ERRMASK);
+  return rc;
+}
+
+static int
+_streamref_read (struct _mu_stream *str, char *buf, size_t bufsize,
+                size_t *pnread)
+{
+  struct _mu_streamref *sp = (struct _mu_streamref *)str;
+  int rc;
+  size_t nread;
+  mu_off_t off;
+  
+  rc = mu_stream_seek (sp->transport, sp->offset, MU_SEEK_SET, &off);
+  if (rc == 0)
+    {
+      if (sp->end)
+       {
+         size_t size = sp->end - off + 1;
+         if (size < bufsize)
+           bufsize = size;
+       }
+      rc = mu_stream_read (sp->transport, buf, bufsize, &nread);
+      if (rc == 0)
+       {
+         sp->offset += nread;
+         *pnread = nread;
+       }
+    }
+  else if (rc == ESPIPE)
+    {
+      *pnread = 0;
+      mu_stream_clearerr (sp->transport);
+      return 0;
+    }
+  return streamref_return (sp, rc);
+}
+
+static int
+_streamref_readdelim (struct _mu_stream *str, char *buf, size_t bufsize,
+                     int delim, size_t *pnread)
+{
+  struct _mu_streamref *sp = (struct _mu_streamref *)str;
+  int rc;
+  size_t nread;
+  mu_off_t off;
+  
+  rc = mu_stream_seek (sp->transport, sp->offset, MU_SEEK_SET, &off);
+  if (rc == 0)
+    {
+      rc = mu_stream_readdelim (sp->transport, buf, bufsize, delim, &nread);
+      if (rc == 0)
+       {
+         if (sp->end)
+           {
+             size_t size = sp->end - off + 1;
+             if (nread > size)
+               nread = size;
+           }
+         sp->offset += nread;
+         *pnread = nread;
+       }
+    }
+  else if (rc == ESPIPE)
+    {
+      *pnread = 0;
+      mu_stream_clearerr (sp->transport);
+      return 0;
+    }
+  return streamref_return (sp, rc);
+}
+
+static int
+_streamref_write (struct _mu_stream *str, const char *buf, size_t bufsize,
+                 size_t *pnwrite)
+{
+  struct _mu_streamref *sp = (struct _mu_streamref *)str;
+  int rc;
+  size_t nwrite;
+  rc = mu_stream_seek (sp->transport, sp->offset, MU_SEEK_SET, NULL);
+  if (rc == 0)
+    {
+      rc = mu_stream_write (sp->transport, buf, bufsize, &nwrite);
+      if (rc == 0)
+       {
+         sp->offset += nwrite;
+         *pnwrite = nwrite;
+       }
+    }
+  return streamref_return (sp, rc);
+}
+
+static int
+_streamref_flush (struct _mu_stream *str)
+{
+  struct _mu_streamref *sp = (struct _mu_streamref *)str;
+  return streamref_return (sp, mu_stream_flush (sp->transport));
+}
+
+static int
+_streamref_open (struct _mu_stream *str)
+{
+  struct _mu_streamref *sp = (struct _mu_streamref *)str;
+  return streamref_return (sp, mu_stream_open (sp->transport));
+}
+
+static int
+_streamref_close (struct _mu_stream *str)
+{
+  struct _mu_streamref *sp = (struct _mu_streamref *)str;
+  return streamref_return (sp, mu_stream_close (sp->transport));
+}
+
+static void
+_streamref_done (struct _mu_stream *str)
+{
+  struct _mu_streamref *sp = (struct _mu_streamref *)str;
+  mu_stream_unref (sp->transport);
+}
+
+static int
+_streamref_seek (struct _mu_stream *str, mu_off_t off, mu_off_t *ppos)
+{
+  struct _mu_streamref *sp = (struct _mu_streamref *)str;
+  mu_off_t size;
+  int rc;
+  
+  if (sp->end)
+    size = sp->end - sp->start + 1;
+  else
+    {
+      rc = mu_stream_size (sp->transport, &size);
+      if (rc)
+       return streamref_return (sp, rc);
+      size -= sp->start;
+    }
+  
+  if (off < 0 || off > size)
+    return sp->stream.last_err = ESPIPE;
+  rc = mu_stream_seek (sp->transport, sp->start + off, MU_SEEK_SET,
+                      &sp->offset);
+  if (rc)
+    return streamref_return (sp, rc);
+  *ppos = sp->offset - sp->start;
+  return 0;
+}
+
+static int
+_streamref_size (struct _mu_stream *str, mu_off_t *psize)
+{
+  struct _mu_streamref *sp = (struct _mu_streamref *)str;
+  mu_off_t size;
+  int rc = 0;
+  
+  if (sp->end)
+    size = sp->end - sp->start + 1;
+  else
+    {
+      rc = mu_stream_size (sp->transport, &size);
+      if (rc)
+       return streamref_return (sp, rc);
+      size -= sp->start;
+    }
+  if (rc == 0)
+    *psize = size;
+  return rc;
+}
+
+static int
+_streamref_ctl (struct _mu_stream *str, int op, void *arg)
+{
+  struct _mu_streamref *sp = (struct _mu_streamref *)str;
+  mu_off_t *lim;
+  
+  switch (op)
+    {
+    case MU_IOCTL_ABRIDGE_SEEK:
+      if (!arg)
+       return EINVAL;
+      lim = arg;
+      sp->start = lim[0];
+      sp->end = lim[1];
+      return 0;
+
+    case MU_IOCTL_GET_SEEK_LIMITS:
+      if (!arg)
+       return EINVAL;
+      lim = arg;
+      lim[0] = sp->start;
+      lim[1] = sp->end;
+      return 0;
+    }
+  return streamref_return (sp, mu_stream_ioctl (sp->transport, op, arg));
+}
+
+static int
+_streamref_wait (struct _mu_stream *str, int *pflags, struct timeval *tvp)
+{
+  struct _mu_streamref *sp = (struct _mu_streamref *)str;
+  return streamref_return (sp, mu_stream_wait (sp->transport, pflags, tvp));
+}
+
+static int
+_streamref_truncate (struct _mu_stream *str, mu_off_t size)
+{
+  struct _mu_streamref *sp = (struct _mu_streamref *)str;
+  return streamref_return (sp, mu_stream_truncate (sp->transport, size));
+}
+  
+static int
+_streamref_shutdown (struct _mu_stream *str, int how)
+{
+  struct _mu_streamref *sp = (struct _mu_streamref *)str;
+  return streamref_return (sp, mu_stream_shutdown (sp->transport, how));
+}
+
+static const char *
+_streamref_error_string (struct _mu_stream *str, int rc)
+{
+  struct _mu_streamref *sp = (struct _mu_streamref *)str;
+  const char *p = mu_stream_strerror (sp->transport, rc);
+  if (!p)
+    p = mu_strerror (rc);
+  return p;
+}
+
+int
+mu_streamref_create_abridged (mu_stream_t *pref, mu_stream_t str,
+                             mu_off_t start, mu_off_t end)
+{
+  int rc;
+  mu_off_t off;
+  int flags;
+  struct _mu_streamref *sp;
+
+  rc = mu_stream_seek (str, 0, MU_SEEK_SET, &off);
+  if (rc)
+    return rc;
+  mu_stream_get_flags (str, &flags);
+  sp = (struct _mu_streamref *)
+         _mu_stream_create (sizeof (*sp), flags & ~MU_STREAM_AUTOCLOSE);
+  if (!sp)
+    return ENOMEM;
+
+  mu_stream_ref (str);
+
+  sp->stream.read = _streamref_read; 
+  sp->stream.readdelim = _streamref_readdelim; 
+  sp->stream.write = _streamref_write;
+  sp->stream.flush = _streamref_flush;
+  sp->stream.open = _streamref_open; 
+  sp->stream.close = _streamref_close;
+  sp->stream.done = _streamref_done; 
+  sp->stream.seek = _streamref_seek; 
+  sp->stream.size = _streamref_size; 
+  sp->stream.ctl = _streamref_ctl;
+  sp->stream.wait = _streamref_wait;
+  sp->stream.truncate = _streamref_truncate;
+  sp->stream.shutdown = _streamref_shutdown;
+  sp->stream.error_string = _streamref_error_string;
+
+  sp->transport = str;
+  sp->start = start;
+  sp->end = end;
+  if (off < start || off > end)
+    off = start;
+  sp->offset = off;
+  *pref = (mu_stream_t) sp;
+  return 0;
+}
+
+int
+mu_streamref_create (mu_stream_t *pref, mu_stream_t str)
+{
+  return mu_streamref_create_abridged (pref, str, 0, 0);
+}
+
diff --git a/mailbox/tcp.c b/mailbox/tcp.c
index 4d36648..08f8fff 100644
--- a/mailbox/tcp.c
+++ b/mailbox/tcp.c
@@ -40,6 +40,8 @@
 #include <mailutils/stream.h>
 #include <mailutils/mutil.h>
 
+#include <mailutils/sys/stream.h>
+
 #define TCP_STATE_INIT                 1
 #define TCP_STATE_RESOLVE      2
 #define TCP_STATE_RESOLVING    3
@@ -48,6 +50,7 @@
 
 struct _tcp_instance
 {
+  struct _mu_stream stream;
   int          fd;
   char                 *host;
   int          port;
@@ -64,7 +67,7 @@ struct _tcp_instance
 static int
 _tcp_close (mu_stream_t stream)
 {
-  struct _tcp_instance *tcp = mu_stream_get_owner (stream);
+  struct _tcp_instance *tcp = (struct _tcp_instance *)stream;
   int err = 0;
 
   if (tcp->fd != -1)
@@ -97,14 +100,14 @@ resolve_hostname (const char *host, unsigned long *ip)
 static int
 _tcp_open (mu_stream_t stream)
 {
-  struct _tcp_instance *tcp = mu_stream_get_owner (stream);
+  struct _tcp_instance *tcp = (struct _tcp_instance *)stream;
   int flgs, ret;
   socklen_t namelen;
   struct sockaddr_in peer_addr;
   struct sockaddr_in soc_addr;
   int flags;
 
-  mu_stream_get_flags(stream, &flags);
+  mu_stream_get_flags (stream, &flags);
 
   switch (tcp->state)
     {
@@ -137,6 +140,7 @@ _tcp_open (mu_stream_t stream)
        }
       
       tcp->state = TCP_STATE_RESOLVING;
+      
     case TCP_STATE_RESOLVING:
       if (!(tcp->host != NULL && tcp->port > 0))
        {
@@ -150,6 +154,7 @@ _tcp_open (mu_stream_t stream)
          return ret;
        }
       tcp->state = TCP_STATE_RESOLVE;
+      
     case TCP_STATE_RESOLVE:
       memset (&soc_addr, 0, sizeof (soc_addr));
       soc_addr.sin_family = AF_INET;
@@ -157,7 +162,7 @@ _tcp_open (mu_stream_t stream)
       soc_addr.sin_addr.s_addr = tcp->address;
 
       if ((connect (tcp->fd,
-             (struct sockaddr *) &soc_addr, sizeof (soc_addr))) == -1)
+                   (struct sockaddr *) &soc_addr, sizeof (soc_addr))) == -1)
        {
          ret = errno;
          if (ret == EINPROGRESS || ret == EAGAIN)
@@ -170,10 +175,11 @@ _tcp_open (mu_stream_t stream)
          return ret;
        }
       tcp->state = TCP_STATE_CONNECTING;
+      
     case TCP_STATE_CONNECTING:
       namelen = sizeof (peer_addr);
       if (getpeername (tcp->fd,
-           (struct sockaddr *) &peer_addr, &namelen) == 0)
+                      (struct sockaddr *) &peer_addr, &namelen) == 0)
        tcp->state = TCP_STATE_CONNECTED;
       else
        {
@@ -186,81 +192,67 @@ _tcp_open (mu_stream_t stream)
   return 0;
 }
 
-
 static int
-_tcp_get_transport2 (mu_stream_t stream, mu_transport_t *tr,
-                    mu_transport_t *tr2)
+_tcp_ioctl (mu_stream_t stream, int code, void *ptr)
 {
-  struct _tcp_instance *tcp = mu_stream_get_owner (stream);
+  struct _tcp_instance *tcp = (struct _tcp_instance *)stream;
+  mu_transport_t *ptrans;
 
-  if (tcp->fd == -1)
-    return EINVAL;
+  switch (code)
+    {
+    case MU_IOCTL_GET_TRANSPORT:
+      if (!ptr)
+       return EINVAL;
+      ptrans = ptr;
+      ptrans[0] = (mu_transport_t) tcp->fd;
+      ptrans[1] = NULL;
+      break;
 
-  if (tr)
-    *tr = (mu_transport_t) tcp->fd;
-  if (tr2)
-    *tr2 = NULL;
+    default:
+      return EINVAL;
+    }
   return 0;
 }
 
 static int
-_tcp_read (mu_stream_t stream, char *buf, size_t buf_size,
-          mu_off_t offset, size_t * br)
+_tcp_read (mu_stream_t stream, char *buf, size_t size, size_t *pret)
 {
-  struct _tcp_instance *tcp = mu_stream_get_owner (stream);
-  int bytes;
-
-  offset = offset;
-  if (br == NULL)
-    return MU_ERR_OUT_NULL;
-  *br = 0;
-  if ((bytes = recv (tcp->fd, buf, buf_size, 0)) == -1)
-    {
-      *br = 0;
-      return errno;
-    }
-  *br = bytes;
+  struct _tcp_instance *tcp = (struct _tcp_instance *)stream;
+  ssize_t bytes;
+
+  if ((bytes = recv (tcp->fd, buf, size, 0)) == -1)
+    return errno;
+  *pret = bytes;
   return 0;
 }
 
 static int
-_tcp_write (mu_stream_t stream, const char *buf, size_t buf_size,
-           mu_off_t offset,
-           size_t * bw)
+_tcp_write (mu_stream_t stream, const char *buf, size_t size, size_t *pret)
 {
-  struct _tcp_instance *tcp = mu_stream_get_owner (stream);
-  int bytes;
-
-  offset = offset;
-  if (bw == NULL)
-    return MU_ERR_OUT_NULL;
-  *bw = 0;
-  if ((bytes = send (tcp->fd, buf, buf_size, 0)) == -1)
-    {
-      *bw = 0;
-      return errno;
-    }
-  *bw = bytes;
+  struct _tcp_instance *tcp = (struct _tcp_instance *)stream;
+  ssize_t bytes;
+
+  if ((bytes = send (tcp->fd, buf, size, 0)) == -1)
+    return errno;
+  *pret = bytes;
   return 0;
 }
 
 static void
-_tcp_destroy (mu_stream_t stream)
+_tcp_done (mu_stream_t stream)
 {
-  struct _tcp_instance *tcp = mu_stream_get_owner (stream);
+  struct _tcp_instance *tcp = (struct _tcp_instance *)stream;
 
   if (tcp->host)
     free (tcp->host);
   if (tcp->fd != -1)
     close (tcp->fd);
-
-  free (tcp);
 }
 
 int
 _tcp_wait (mu_stream_t stream, int *pflags, struct timeval *tvp)
 {
-  struct _tcp_instance *tcp = mu_stream_get_owner (stream);
+  struct _tcp_instance *tcp = (struct _tcp_instance *)stream;
   if (tcp->fd == -1)
     return EINVAL;
   return mu_fd_wait (tcp->fd, pflags, tvp);
@@ -269,7 +261,7 @@ _tcp_wait (mu_stream_t stream, int *pflags, struct timeval 
*tvp)
 int
 _tcp_shutdown (mu_stream_t stream, int how)
 {
-  struct _tcp_instance *tcp = mu_stream_get_owner (stream);
+  struct _tcp_instance *tcp = (struct _tcp_instance *)stream;
   int flag;
   if (tcp->fd == -1)
     return EINVAL;
@@ -289,17 +281,26 @@ _tcp_shutdown (mu_stream_t stream, int how)
   return 0;
 }
 
-static void
-_tcp_stream_init (mu_stream_t stream, struct _tcp_instance *tcp)
+static struct _tcp_instance *
+_create_tcp_stream (int flags)
 {
-  mu_stream_set_open (stream, _tcp_open, tcp);
-  mu_stream_set_close (stream, _tcp_close, tcp);
-  mu_stream_set_read (stream, _tcp_read, tcp);
-  mu_stream_set_write (stream, _tcp_write, tcp);
-  mu_stream_set_get_transport2 (stream, _tcp_get_transport2, tcp);
-  mu_stream_set_destroy (stream, _tcp_destroy, tcp);
-  mu_stream_set_wait (stream, _tcp_wait, tcp);
-  mu_stream_set_shutdown (stream, _tcp_shutdown, tcp);
+  struct _tcp_instance *tcp =
+    (struct _tcp_instance *)_mu_stream_create (sizeof (*tcp), flags);
+
+  if (tcp)
+    {
+      tcp->stream.open = _tcp_open;
+      tcp->stream.close = _tcp_close;
+      tcp->stream.read = _tcp_read;
+      tcp->stream.write = _tcp_write;
+      tcp->stream.ctl = _tcp_ioctl;
+      tcp->stream.done = _tcp_done;
+      tcp->stream.wait = _tcp_wait;
+      tcp->stream.shutdown = _tcp_shutdown;
+      tcp->fd = -1;
+      tcp->state = TCP_STATE_INIT;
+    }
+  return tcp;
 }
 
 int
@@ -309,7 +310,6 @@ mu_tcp_stream_create_with_source_ip (mu_stream_t *stream,
                                     int flags)
 {
   struct _tcp_instance *tcp;
-  int ret;
 
   if (host == NULL)
     return MU_ERR_TCP_NO_HOST;
@@ -317,9 +317,9 @@ mu_tcp_stream_create_with_source_ip (mu_stream_t *stream,
   if (port < 1)
     return MU_ERR_TCP_NO_PORT;
 
-  if ((tcp = malloc (sizeof (*tcp))) == NULL)
+  tcp = _create_tcp_stream (flags | MU_STREAM_RDWR);
+  if (!tcp)
     return ENOMEM;
-  tcp->fd = -1;
   tcp->host = strdup (host);
   if (!tcp->host)
     {
@@ -329,17 +329,7 @@ mu_tcp_stream_create_with_source_ip (mu_stream_t *stream,
   tcp->port = port;
   tcp->state = TCP_STATE_INIT;
   tcp->source_addr = source_ip;
-  if ((ret = mu_stream_create (stream,
-                              flags | MU_STREAM_NO_CHECK | MU_STREAM_RDWR,
-                              tcp)))
-  {
-    free (tcp->host);
-    free (tcp);
-
-    return ret;
-  }
-
-  _tcp_stream_init (*stream, tcp);
+  *stream = (mu_stream_t) tcp;
   return 0;
 }
 
diff --git a/mailbox/temp_file_stream.c b/mailbox/temp_file_stream.c
new file mode 100644
index 0000000..c5346b2
--- /dev/null
+++ b/mailbox/temp_file_stream.c
@@ -0,0 +1,65 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 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 <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <mailutils/types.h>
+#include <mailutils/alloc.h>
+#include <mailutils/error.h>
+#include <mailutils/errno.h>
+#include <mailutils/nls.h>
+#include <mailutils/stream.h>
+#include <mailutils/sys/stream.h>
+#include <mailutils/sys/file_stream.h>
+#include <mailutils/mutil.h>
+
+
+static int
+fd_temp_open (struct _mu_stream *str)
+{
+  struct _mu_file_stream *fstr = (struct _mu_file_stream *) str;
+  int fd = mu_tempfile (fstr->filename, NULL);
+  if (fd == -1)
+    return errno;
+  fstr->fd = fd;
+  return 0;
+}
+  
+int
+mu_temp_file_stream_create (mu_stream_t *pstream, const char *dir)
+{
+  int rc;
+  struct _mu_file_stream *str;
+
+  rc = _mu_file_stream_create (&str,
+                              sizeof (struct _mu_file_stream),
+                              dir,
+                              -1,
+                              MU_STREAM_RDWR | MU_STREAM_SEEK |
+                              MU_STREAM_CREAT | 
+                              MU_STREAM_AUTOCLOSE);
+
+  str->stream.open = fd_temp_open;
+  str->flags = _MU_FILE_STREAM_TEMP;
+  *pstream = (mu_stream_t) str;
+  return 0;
+}
diff --git a/mailbox/testsuite/mailbox/base64.exp 
b/mailbox/testsuite/mailbox/base64.exp
index 64e8168..b86ca6f 100644
--- a/mailbox/testsuite/mailbox/base64.exp
+++ b/mailbox/testsuite/mailbox/base64.exp
@@ -29,7 +29,9 @@ mu_exec -message "encode" -arg -i${srcdir}/Encode \
 
 ## Expect chokes on binary data, so let's switch base64 to printable
 ## octal output.
-mu_exec -message "decode" -arg -i${srcdir}/Decode -arg -dp \
+## The -l0 option ensures that the output is not split by inserting
+## additional newlines.
+mu_exec -message "decode" -arg -i${srcdir}/Decode -arg -dpl0 \
 
"\\000\\001\\002\\003\\004\\005\\006\\007\\010\\011\\012\\013\\014\\015\\016\\017\\020\\021\\022\\023\\024\\025\\026\\027\\030\\031\\032\\033\\034\\035\\036\\037
 
!\"#$%&'()*+,-./0123456789:;<=>address@hidden|}~\\177\\200\\201\\202\\203\\204\\205\\206\\207\\210\\211\\212\\213\\214\\215\\216\\217\\220\\221\\222\\223\\224\\225\\226\\227\\230\\231\\232\\233\\234\\235\\236\\237\\240\\241\\242\\243\\244\\245\\246\\247\\250\\251\\252\\253\\254\\255\\256\\257\\260\\261\\262\\263\\264\\265\\266\\267\\270\\271\\272\\273\\274\\275\\276\\277\\300\\301\\302\\303\\304\\305\\306\\307\\310\\311\\312\\313\\314\\315\\316\\317\\320\\321\\322\\323\\324\\325\\326\\327\\330\\331\\332\\333\\334\\335\\336\\337\\340\\341\\342\\343\\344\\345\\346\\347\\350\\351\\352\\353\\354\\355\\356\\357\\360\\361\\362\\363\\364\\365\\366\\367\\370\\371\\372\\373\\374\\375\\376\\377"
 
 # End of base64.exp
diff --git a/mailbox/ticket.c b/mailbox/ticket.c
index 774b711..ae49520 100644
--- a/mailbox/ticket.c
+++ b/mailbox/ticket.c
@@ -32,7 +32,7 @@
 #include <mailutils/mutil.h>
 #include <mailutils/errno.h>
 #include <mailutils/secret.h>
-#include <auth0.h>
+#include <mailutils/sys/auth.h>
 
 static void
 echo_off (struct termios *stored_settings)
diff --git a/mailbox/url.c b/mailbox/url.c
index 1b833bf..92f762b 100644
--- a/mailbox/url.c
+++ b/mailbox/url.c
@@ -35,7 +35,7 @@
 #include <mailutils/secret.h>
 #include <mailutils/cctype.h>
 #include <mailutils/cstr.h>
-#include <url0.h>
+#include <mailutils/sys/url.h>
 
 #define AC2(a,b) a ## b
 #define AC4(a,b,c,d) a ## b ## c ## d
diff --git a/mailbox/vartab.c b/mailbox/vartab.c
index 10649f5..7364ba8 100644
--- a/mailbox/vartab.c
+++ b/mailbox/vartab.c
@@ -98,7 +98,7 @@ mu_vartab_destroy (mu_vartab_t *pvar)
   mu_iterator_destroy (&itr);
 
   mu_assoc_destroy (&var->assoc);
-  mu_stream_destroy (&var->stream, NULL);
+  mu_stream_destroy (&var->stream);
   free (var->buf);
   free (var);
   *pvar = NULL;
@@ -224,14 +224,14 @@ mu_vartab_expand (mu_vartab_t vt, const char *str, char 
**pres)
     return EINVAL;
   if (!vt->stream)
     {
-      rc = mu_memory_stream_create (&vt->stream, NULL, MU_STREAM_NO_CHECK);
+      rc = mu_memory_stream_create (&vt->stream, 0);
       if (rc)
        return rc;
       rc = mu_stream_open (vt->stream);
     }
   else
     mu_stream_truncate (vt->stream, 0);
-  mu_stream_seek (vt->stream, 0, SEEK_SET);
+  mu_stream_seek (vt->stream, 0, MU_SEEK_SET, NULL);
 
   for (p = str; *p; )
     {
@@ -240,7 +240,7 @@ mu_vartab_expand (mu_vartab_t vt, const char *str, char 
**pres)
          switch (*++p)
            {
            case '$':
-             mu_stream_sequential_write (vt->stream, str, p - str);
+             mu_stream_write (vt->stream, str, p - str, NULL);
              str = p + 1;
              p = str + 1;
              break;
@@ -256,10 +256,9 @@ mu_vartab_expand (mu_vartab_t vt, const char *str, char 
**pres)
                    rc = mu_vartab_getvar (vt, name, &pvalue);
                    if (rc == 0)
                      {
-                       mu_stream_sequential_write (vt->stream, str,
-                                                   p - str - 1);
-                       mu_stream_sequential_write (vt->stream, pvalue,
-                                                   strlen (pvalue));
+                       mu_stream_write (vt->stream, str, p - str - 1, NULL);
+                       mu_stream_write (vt->stream, pvalue, strlen (pvalue),
+                                        NULL);
                        str = e + 1;
                        p = str + 1;
                      }
@@ -280,10 +279,9 @@ mu_vartab_expand (mu_vartab_t vt, const char *str, char 
**pres)
                rc = mu_vartab_getvar (vt, name, &pvalue);
                if (rc == 0)
                  {
-                   mu_stream_sequential_write (vt->stream, str,
-                                               p - str - 1);
-                   mu_stream_sequential_write (vt->stream, pvalue,
-                                               strlen (pvalue));
+                   mu_stream_write (vt->stream, str, p - str - 1, NULL);
+                   mu_stream_write (vt->stream, pvalue, strlen (pvalue),
+                                    NULL);
                    str = p + 1;
                    p = str + 1;
                  }
@@ -301,7 +299,7 @@ mu_vartab_expand (mu_vartab_t vt, const char *str, char 
**pres)
             compatibility with v. prior to 1.2.91 */
          if (*++p == '%')
            {
-             mu_stream_sequential_write (vt->stream, str, p - str);
+             mu_stream_write (vt->stream, str, p - str, NULL);
              str = p + 1;
              p = str + 1;
            }
@@ -312,10 +310,9 @@ mu_vartab_expand (mu_vartab_t vt, const char *str, char 
**pres)
              rc = mu_vartab_getvar (vt, name, &pvalue);
              if (rc == 0)
                {
-                 mu_stream_sequential_write (vt->stream, str,
-                                             p - str - 1);
-                 mu_stream_sequential_write (vt->stream, pvalue,
-                                             strlen (pvalue));
+                 mu_stream_write (vt->stream, str, p - str - 1, NULL);
+                 mu_stream_write (vt->stream, pvalue, strlen (pvalue),
+                                  NULL);
                  str = p + 1;
                  p = str + 1;
                }
@@ -330,13 +327,14 @@ mu_vartab_expand (mu_vartab_t vt, const char *str, char 
**pres)
     }
   
   if (p > str)
-    mu_stream_sequential_write (vt->stream, str, p - str);
+    mu_stream_write (vt->stream, str, p - str, NULL);
 
   mu_stream_size (vt->stream, &size);
   *pres = malloc (size + 1);
   if (!*pres)
     return ENOMEM;
-  mu_stream_read (vt->stream, *pres, size, 0, NULL);
+  mu_stream_seek (vt->stream, 0, MU_SEEK_SET, NULL);
+  mu_stream_read (vt->stream, *pres, size, NULL);
   (*pres)[size] = 0;
   return 0;
 }
diff --git a/mailbox/wicket.c b/mailbox/wicket.c
index 8169edd..82b179b 100644
--- a/mailbox/wicket.c
+++ b/mailbox/wicket.c
@@ -36,8 +36,8 @@
 #include <mailutils/mu_auth.h>
 #include <mailutils/stream.h>
 
-#include <auth0.h>
-#include <url0.h>
+#include <mailutils/sys/auth.h>
+#include <mailutils/sys/url.h>
 
 int
 mu_wicket_create (mu_wicket_t *pwicket)
@@ -260,8 +260,7 @@ get_ticket_url (mu_ticket_t ticket, mu_url_t url, mu_url_t 
*pticket_url)
       size_t bufsize = 0;
       size_t len;
 
-      while ((rc = mu_stream_sequential_getline (stream,
-                                                &buf, &bufsize, &len)) == 0
+      while ((rc = mu_stream_getline (stream, &buf, &bufsize, &len)) == 0
             && len > 0)
        {
          char *p;
@@ -316,7 +315,7 @@ get_ticket_url (mu_ticket_t ticket, mu_url_t url, mu_url_t 
*pticket_url)
       mu_stream_close (stream);
       free (buf);
     }
-  mu_stream_destroy (&stream, NULL);
+  mu_stream_destroy (&stream);
 
   if (rc == 0)
     {
diff --git a/mailbox/xscript-stream.c b/mailbox/xscript-stream.c
new file mode 100644
index 0000000..41f28ec
--- /dev/null
+++ b/mailbox/xscript-stream.c
@@ -0,0 +1,431 @@
+/* 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>
+#include <mailutils/cctype.h>
+#include <mailutils/cstr.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 TRANS_DISABLED 0x4
+#define FLAG_TO_PFX(c) ((c) - 1)
+
+static int
+word_match (const char *buf, size_t len, int n, const char *word,
+           size_t *pos)
+{
+  size_t i = 0;
+  size_t wl = strlen (word);
+  
+  for (;; n--)
+    {
+      /* Skip whitespace separator */
+      for (; i < len && mu_isspace (buf[i]); i++)
+       ;
+
+      if (n == 0)
+       break;
+      
+      /* Skip the argument */
+      if (buf[i] == '"')
+       {
+         for (i++; i < len && buf[i] != '"'; i++)
+           if (buf[i] == '\'')
+             i++;
+       }
+      else
+       {
+         for (; i < len && !mu_isspace (buf[i]); i++)
+           ;
+       }
+    }
+
+  if (i + wl <= len &&
+      mu_c_strncasecmp (buf + i, word, wl) == 0 &&
+      mu_isblank (buf[i + wl]))
+    {
+      *pos = i + wl;
+      return 1;
+    }
+
+  return 0;
+}
+
+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 | TRANS_DISABLED);
+       }
+      
+      if (str->flags & TRANS_DISABLED)
+       return;
+  
+      if (str->level == MU_XSCRIPT_PAYLOAD)
+       {
+         mu_stream_printf (str->logstr, "(data...)\n");
+         str->flags |= TRANS_DISABLED;
+         return;
+       }
+  
+      p = memchr (buf, '\n', size);
+      if (p)
+       {
+         len = p - buf;
+         if (p > buf && p[-1] == '\r')
+           len--;
+
+         if (str->level == MU_XSCRIPT_SECURE)
+           {
+             size_t i;
+             
+             if (word_match (buf, len, 0, "PASS", &i))
+               mu_stream_printf (str->logstr, "PASS ***");
+             else if (word_match (buf, len, 1, "LOGIN", &i))
+               {
+                 /* Skip the whitespace separator */
+                 for (; i < len && mu_isspace (buf[i]); i++)
+                   ;
+                 /* Skip the first argument (presumably the user name) */
+                 if (buf[i] == '"')
+                   {
+                     for (i++; i < len && buf[i] != '"'; i++)
+                       if (buf[i] == '\'')
+                         i++;
+                   }
+                 else
+                   {
+                     for (; i < len && !mu_isspace (buf[i]); i++)
+                       ;
+                   }
+                 mu_stream_write (str->logstr, buf, i, NULL);
+                 mu_stream_write (str->logstr, " \"***\"", 6, NULL);
+               }
+             else
+               mu_stream_write (str->logstr, buf, len, NULL);
+           }
+         else
+           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;
+  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;
+  int status = 0;
+  
+  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;
+
+    case MU_IOCTL_SWAP_STREAM:
+      if (!arg)
+       return EINVAL;
+      if (!sp->transport)
+       status = ENOSYS;
+      else
+       status = mu_stream_ioctl (sp->transport, op, arg);
+      if (status == EINVAL || status == ENOSYS)
+       {
+         mu_stream_t *pstr = arg;
+         mu_stream_t tmp;
+
+         if (pstr[0] != pstr[1])
+           return EINVAL; /* FIXME */
+         tmp = pstr[0];
+         pstr[0] = sp->transport;
+         pstr[1] = sp->transport;
+         sp->transport = tmp;
+         if (!(str->flags & MU_STREAM_AUTOCLOSE))
+           {
+             if (pstr[0])
+               mu_stream_unref (pstr[0]);
+             if (tmp)
+               mu_stream_ref (tmp);
+           }
+         if (tmp)
+           mu_stream_ref (tmp);
+         status = 0;
+       }
+      break;
+
+    case MU_IOCTL_LEVEL:
+      if (!arg)
+       return EINVAL;
+      else
+       {
+         int oldlev = sp->level;
+         sp->level = *(int*)arg;
+         sp->flags = TRANS_READ | TRANS_WRITE;
+         *(int*)arg = oldlev;
+       }
+      break;
+      
+    default:
+      return mu_stream_ioctl (sp->transport, op, arg);
+    }
+  return status;
+}
+
+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;
+
+  if (!(flags & MU_STREAM_AUTOCLOSE))
+    {
+      mu_stream_ref (transport);
+      mu_stream_ref (logstr);
+    }
+  sp->transport = transport;
+  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/messages/messages.c b/messages/messages.c
index 292f59c..62c38b8 100644
--- a/messages/messages.c
+++ b/messages/messages.c
@@ -31,7 +31,6 @@
 
 static int messages_count (const char *);
 
-const char *program_version = "messages (" PACKAGE_STRING ")";
 static char doc[] = N_("GNU messages -- count the number of messages in a 
mailbox");
 static char args_doc[] = N_("[mailbox...]");
 
@@ -112,7 +111,7 @@ main (int argc, char **argv)
 #ifdef WITH_TLS
   mu_gocs_register ("tls", mu_tls_module_init);
 #endif
-  mu_argp_init (program_version, NULL);
+  mu_argp_init (NULL, NULL);
   if (mu_app_init (&argp, argp_capa, NULL, argc, argv, 0, NULL, &args))
     exit (1);
 
diff --git a/mh/ali.c b/mh/ali.c
index 088bd35..0c357cf 100644
--- a/mh/ali.c
+++ b/mh/ali.c
@@ -26,7 +26,6 @@
 #include <sys/ioctl.h>
 #include <sys/stat.h>
 
-const char *program_version = "ali (" PACKAGE_STRING ")";
 static char doc[] = N_("GNU MH ali")"\v"
 N_("Use -help to obtain the list of traditional MH options.");
 static char args_doc[] = N_("aliases ...");
@@ -43,8 +42,6 @@ static struct argp_option options[] = {
    N_("try to determine the official hostname for each address") },
   {"user", ARG_USER, N_("BOOL"),  OPTION_ARG_OPTIONAL,
    N_("list the aliases that expand to given addresses") },
-  {"license", ARG_LICENSE, 0,      0,
-   N_("display software license"), -1},
   { 0 }
 };
 
@@ -68,10 +65,6 @@ opt_handler (int key, char *arg, struct argp_state *state)
 {
   switch (key)
     {
-    case ARG_LICENSE:
-      mh_license (argp_program_version);
-      break;
-
     case ARG_ALIAS:
       mh_alias_read (arg, 1);
       break;
@@ -194,7 +187,7 @@ main (int argc, char **argv)
   /* Native Language Support */
   MU_APP_INIT_NLS ();
 
-  mh_argp_init (program_version);
+  mh_argp_init ();
   mh_argp_parse (&argc, &argv, 0, options, mh_option, args_doc, doc,
                 opt_handler, NULL, &index);
 
diff --git a/mh/anno.c b/mh/anno.c
index 8b3319a..efc22d3 100644
--- a/mh/anno.c
+++ b/mh/anno.c
@@ -21,7 +21,6 @@
 
 #include <mh.h>
 
-const char *program_version = "anno (" PACKAGE_STRING ")";
 static char doc[] = N_("GNU MH anno")"\v"
 N_("Options marked with `*' are not yet implemented.\n\
 Use -help to obtain the list of traditional MH options.");
@@ -41,8 +40,6 @@ static struct argp_option options[] = {
    N_("add this FIELD to the message header") },
   {"text", ARG_TEXT, N_("STRING"), 0,
    N_("field value for the component") },
-  {"license", ARG_LICENSE, 0,      0,
-   N_("display software license"), -1},
   { NULL }
 };
 
@@ -94,10 +91,6 @@ opt_handler (int key, char *arg, struct argp_state *state)
       mh_quote (arg, &anno_text);
       break;
 
-    case ARG_LICENSE:
-      mh_license (argp_program_version);
-      break;
-
     default:
       return ARGP_ERR_UNKNOWN;
     }
@@ -121,7 +114,7 @@ main (int argc, char **argv)
   
   MU_APP_INIT_NLS ();
 
-  mh_argp_init (program_version);
+  mh_argp_init ();
   mh_argp_parse (&argc, &argv, 0, options, mh_option, args_doc, doc,
                 opt_handler, NULL, &index);
 
diff --git a/mh/burst.c b/mh/burst.c
index ae02501..1bd99c3 100644
--- a/mh/burst.c
+++ b/mh/burst.c
@@ -24,7 +24,6 @@
 #define obstack_chunk_free free
 #include <obstack.h>
 
-const char *program_version = "burst (" PACKAGE_STRING ")";
 static char doc[] = N_("GNU MH burst")"\v"
 N_("Options marked with `*' are not yet implemented.\n\
 Use -help to obtain the list of traditional MH options.");
@@ -48,8 +47,6 @@ static struct argp_option options[] = {
   {"norecursive",  ARG_NORECURSIVE,  0, OPTION_HIDDEN, ""},
   {"length",       ARG_LENGTH,       N_("NUMBER"), 0,
    N_("set minimal length of digest encapsulation boundary (default 1)") },
-  {"license",      ARG_LICENSE, 0,      0,
-   N_("display software license"), -1},
   { NULL }
 };
 
@@ -93,10 +90,6 @@ opt_handler (int key, char *arg, struct argp_state *state)
        eb_min_length = 1;
       break;
       
-    case ARG_LICENSE:
-      mh_license (argp_program_version);
-      break;
-
     case ARG_VERBOSE:
       verbose = is_true (arg);
       break;
@@ -230,13 +223,13 @@ static void
 finish_stream (mu_stream_t *pstr)
 {
   mu_message_t msg;
-  mu_stream_seek (*pstr, 0, SEEK_SET);
+  mu_stream_seek (*pstr, 0, SEEK_SET, NULL);
   msg = mh_stream_to_message (*pstr);
   if (!map.first)
     mu_mailbox_uidnext (tmpbox, &map.first);
   burst_or_copy (msg, recursive, 1);
   mu_stream_close (*pstr);
-  mu_stream_destroy (pstr, mu_stream_get_owner (*pstr));
+  mu_stream_destroy (pstr);
 }  
 
 static void
@@ -254,7 +247,7 @@ flush_stream (mu_stream_t *pstr, char *buf, size_t size)
                mu_strerror (rc));
       exit (1);
     }
-  rc = mu_stream_sequential_write (*pstr, buf, size);
+  rc = mu_stream_write (*pstr, buf, size, NULL);
   if (rc)
     {
       mu_error (_("error writing temporary stream: %s"),
@@ -286,9 +279,8 @@ burst_digest (mu_message_t msg)
       exit (1);
     }
 
-  mu_message_get_stream (msg, &is);
-
-  while (mu_stream_sequential_read (is, buf, bufsize, &n) == 0
+  mu_message_get_streamref (msg, &is);
+  while (mu_stream_read (is, buf, bufsize, &n) == 0
         && n > 0)
     {
       size_t start, i;
@@ -339,7 +331,8 @@ burst_digest (mu_message_t msg)
 
       flush_stream (&os, buf + start, i - start);
     }
-
+  mu_stream_destroy (&is);
+  
   free (buf);
   if (os)
     {
@@ -348,7 +341,7 @@ burst_digest (mu_message_t msg)
       else
        {
          mu_stream_close (os);
-         mu_stream_destroy (&os, mu_stream_get_owner (os));
+         mu_stream_destroy (&os);
        }
     }
   return count > 0;
@@ -390,8 +383,10 @@ burst_or_copy (mu_message_t msg, int recursive, int copy)
              mu_body_t body;
              
              mu_message_get_body (msg, &body);
-             mu_body_get_stream (body, &str);
-
+             mu_body_get_streamref (body, &str);
+             /* FIXME: Check if str is actually destroyed.
+                See mailbox/message_stream.c
+             */
              msg = mh_stream_to_message (str);
            }
          free (value);
@@ -487,8 +482,6 @@ msg_copy (size_t num, const char *file)
   mu_attribute_t attr = NULL;
   mu_stream_t istream, ostream;
   int rc;
-  size_t n;
-  char buf[512];
   
   if ((rc = mu_file_stream_create (&ostream,
                                   file,
@@ -501,16 +494,19 @@ msg_copy (size_t num, const char *file)
     }
 
   mu_mailbox_get_message (tmpbox, num, &msg);
-  mu_message_get_stream (msg, &istream);
-
-  while (rc == 0
-        && mu_stream_sequential_read (istream, buf, sizeof buf, &n) == 0
-        && n > 0)
-    /* FIXME: Implement RFC 934 FSA? */
-    rc = mu_stream_sequential_write (ostream, buf, n);
+  mu_message_get_streamref (msg, &istream);
+  /* FIXME: Implement RFC 934 FSA? */
+  rc = mu_stream_copy (ostream, istream, 0, NULL);
+  if (rc)
+    {
+      mu_error (_("copy stream error: %s"), mu_strerror (rc));
+      exit (1);
+    }
+  
+  mu_stream_destroy (&istream);
   
   mu_stream_close (ostream);
-  mu_stream_destroy (&ostream, mu_stream_get_owner (ostream));
+  mu_stream_destroy (&ostream);
 
   /* Mark message as deleted */
   mu_message_get_attribute (msg, &attr);
@@ -551,7 +547,7 @@ main (int argc, char **argv)
   /* Native Language Support */
   MU_APP_INIT_NLS ();
 
-  mh_argp_init (program_version);
+  mh_argp_init ();
   mh_argp_parse (&argc, &argv, 0, options, mh_option, args_doc, doc,
                 opt_handler, NULL, &index);
 
diff --git a/mh/comp.c b/mh/comp.c
index bcc0067..935f114 100644
--- a/mh/comp.c
+++ b/mh/comp.c
@@ -23,7 +23,6 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 
-const char *program_version = "comp (" PACKAGE_STRING ")";
 static char doc[] = N_("GNU MH comp")"\v"
 N_("Options marked with `*' are not yet implemented.\n"
 "Use -help to obtain the list of traditional MH options.");
@@ -56,8 +55,6 @@ static struct argp_option options[] = {
   {"use",           ARG_USE, N_("BOOL"), OPTION_ARG_OPTIONAL,
    N_("use draft file preserved after the last session") },
   {"nouse",         ARG_NOUSE, NULL, OPTION_HIDDEN, ""},
-  {"license",       ARG_LICENSE, 0,      0,
-   N_("display software license"), -1},
   { 0 }
 };
 
@@ -143,10 +140,6 @@ opt_handler (int key, char *arg, struct argp_state *state)
       mh_opt_notimpl ("-[no]whatnowproc");
       break;
 
-    case ARG_LICENSE:
-      mh_license (argp_program_version);
-      break;
-
     default:
       return ARGP_ERR_UNKNOWN;
     }
@@ -160,48 +153,30 @@ copy_message (mu_mailbox_t mbox, size_t n, const char 
*file)
   mu_stream_t in;
   mu_stream_t out;
   int rc;
-  size_t size;
-  char *buffer;
-  size_t bufsize, rdsize;
   
   mu_mailbox_get_message (mbox, n, &msg);
-  mu_message_size (msg, &size);
-
-  for (bufsize = size; bufsize > 0 && (buffer = malloc (bufsize)) == 0;
-       bufsize /= 2)
-    ;
-
-  if (!bufsize)
-    mh_err_memory (1);
-
-  mu_message_get_stream (msg, &in);
+  mu_message_get_streamref (msg, &in);
   
   if ((rc = mu_file_stream_create (&out,
-                               file, MU_STREAM_RDWR|MU_STREAM_CREAT)) != 0
+                                  file, MU_STREAM_RDWR|MU_STREAM_CREAT)) != 0
       || (rc = mu_stream_open (out)))
     {
       mu_error (_("cannot open output file \"%s\": %s"),
                file, mu_strerror (rc));
-      free (buffer);
-      return 1;
-    }
-
-  while (size > 0
-        && (rc = mu_stream_sequential_read (in, buffer, bufsize, &rdsize)) == 0
-        && rdsize > 0)
-    {
-      if ((rc = mu_stream_sequential_write (out, buffer, rdsize)) != 0)
-       {
-         mu_error (_("error writing to \"%s\": %s"),
-                   file, mu_strerror (rc));
-         break;
-       }
-      size -= rdsize;
+      mu_stream_destroy (&in);
+      return rc;
     }
 
+  rc = mu_stream_copy (out, in, 0, NULL);
+  mu_stream_destroy (&in);
   mu_stream_close (out);
-  mu_stream_destroy (&out, mu_stream_get_owner (out));
+  mu_stream_destroy (&out);
   
+  if (rc)
+    {
+      mu_error (_("error copying to \"%s\": %s"),
+               file, mu_strerror (rc));
+    }
   return rc;
 }
 
@@ -213,7 +188,7 @@ main (int argc, char **argv)
   /* Native Language Support */
   MU_APP_INIT_NLS ();
 
-  mh_argp_init (program_version);
+  mh_argp_init ();
   mh_argp_parse (&argc, &argv, 0, options, mh_option, args_doc, doc,
                 opt_handler, NULL, &index);
 
diff --git a/mh/compcommon.c b/mh/compcommon.c
index 88d4285..666ef17 100644
--- a/mh/compcommon.c
+++ b/mh/compcommon.c
@@ -62,11 +62,11 @@ mh_comp_draft (const char *formfile, const char 
*defformfile,
              exit (1);
            }
          
-         rc = mu_stream_sequential_write (stream, 
-                                       default_format_str,
-                                       strlen (default_format_str));
+         rc = mu_stream_write (stream, 
+                               default_format_str,
+                               strlen (default_format_str), NULL);
          mu_stream_close (stream);
-         mu_stream_destroy (&stream, mu_stream_get_owner (stream));
+         mu_stream_destroy (&stream);
 
          if (rc)
            {
diff --git a/mh/fmtcheck.c b/mh/fmtcheck.c
index 3d50ae8..33c456a 100644
--- a/mh/fmtcheck.c
+++ b/mh/fmtcheck.c
@@ -21,7 +21,6 @@
 
 #include <mh.h>
 
-const char *program_version = "fmtcheck (" PACKAGE_STRING ")";
 static char doc[] = N_("GNU MH fmtcheck")"\v"
 N_("Use -help to obtain the list of traditional MH options.");
 static char args_doc[] = "";
@@ -36,8 +35,6 @@ static struct argp_option options[] = {
    N_("dump the listing of compiled format code")},
   { "debug",  ARG_DEBUG, NULL,     0,
     N_("enable parser debugging output"),},
-  {"license", ARG_LICENSE, 0,      0,
-   N_("display software license"), -1},
 
   { 0 }
 };
@@ -89,10 +86,6 @@ opt_handler (int key, char *arg, struct argp_state *state)
       mh_format_debug (1);
       break;
       
-    case ARG_LICENSE:
-      mh_license (argp_program_version);
-      break;
-
     default:
       return ARGP_ERR_UNKNOWN;
     }
@@ -105,7 +98,7 @@ main (int argc, char **argv)
   /* Native Language Support */
   MU_APP_INIT_NLS ();
 
-  mh_argp_init (program_version);
+  mh_argp_init ();
   mh_argp_parse (&argc, &argv, 0, options, mh_option, args_doc, doc,
                 opt_handler, NULL, NULL);
 
diff --git a/mh/folder.c b/mh/folder.c
index b13e373..c2baf4c 100644
--- a/mh/folder.c
+++ b/mh/folder.c
@@ -34,7 +34,6 @@
 #define obstack_chunk_free free
 #include <obstack.h>
 
-const char *program_version = "folder (" PACKAGE_STRING ")";
 static char doc[] = N_("GNU MH folder")"\v"
 N_("Use -help to obtain the list of traditional MH options.");
 static char args_doc[] = N_("[action] [msg]");
@@ -81,9 +80,6 @@ static struct argp_option options[] = {
   {"dry-run", ARG_DRY_RUN, NULL, 0,
    N_("do nothing, print what would be done (with --pack)"), 3},
    
-  {"license", ARG_LICENSE, 0,      0,
-   N_("display software license"), -1},
-
   {NULL},
 };
 
@@ -225,10 +221,6 @@ opt_handler (int key, char *arg, struct argp_state *state)
       mh_set_current_folder (arg);
       break;
       
-    case ARG_LICENSE:
-      mh_license (argp_program_version);
-      break;
-
     case ARG_VERBOSE:
       verbose++;
       break;
@@ -939,7 +931,7 @@ main (int argc, char **argv)
   /* Native Language Support */
   MU_APP_INIT_NLS ();
 
-  mh_argp_init (program_version);
+  mh_argp_init ();
   mh_argp_parse (&argc, &argv, 0, options, mh_option, args_doc, doc,
                 opt_handler, NULL, &index);
 
diff --git a/mh/forw.c b/mh/forw.c
index 9597cfb..8d331ec 100644
--- a/mh/forw.c
+++ b/mh/forw.c
@@ -21,7 +21,6 @@
 
 #include <mh.h>
 
-const char *program_version = "forw (" PACKAGE_STRING ")";
 static char doc[] = N_("GNU MH forw")"\v"
 N_("Options marked with `*' are not yet implemented.\n\
 Use -help to obtain the list of traditional MH options.");
@@ -70,9 +69,6 @@ static struct argp_option options[] = {
    N_("use draft file preserved after the last session") },
   {"nouse",         ARG_NOUSE,         N_("BOOL"), OPTION_HIDDEN, "" },
 
-  {"license", ARG_LICENSE, 0,      0,
-   N_("display software license"), -1},
-
   {NULL},
 };
 
@@ -212,10 +208,6 @@ opt_handler (int key, char *arg, struct argp_state *state)
       mh_opt_notimpl ("-[no]whatnowproc");
       break;
  
-    case ARG_LICENSE:
-      mh_license (argp_program_version);
-      break;
-
     default:
       return ARGP_ERR_UNKNOWN;
     }
@@ -249,12 +241,11 @@ msg_copy (mu_message_t msg, mu_stream_t ostream)
   char buf[512];
   enum rfc934_state state = S1;
   
-  rc = mu_message_get_stream (msg, &istream);
+  rc = mu_message_get_streamref (msg, &istream);
   if (rc)
     return rc;
-  mu_stream_seek (istream, 0, SEEK_SET);
   while (rc == 0
-        && mu_stream_sequential_read (istream, buf, sizeof buf, &n) == 0
+        && mu_stream_read (istream, buf, sizeof buf, &n) == 0
         && n > 0)
     {
       size_t start, i;
@@ -265,11 +256,11 @@ msg_copy (mu_message_t msg, mu_stream_t ostream)
          case S1:
            if (buf[i] == '-')
              {
-               rc = mu_stream_sequential_write (ostream, buf + start,
-                                                i - start + 1);
+               rc = mu_stream_write (ostream, buf + start,
+                                     i - start + 1, NULL);
                if (rc)
                  return rc;
-               rc = mu_stream_sequential_write (ostream, " -", 2);
+               rc = mu_stream_write (ostream, " -", 2, NULL);
                if (rc)
                  return rc;
                start = i + 1;
@@ -284,8 +275,9 @@ msg_copy (mu_message_t msg, mu_stream_t ostream)
              state = S1;
          }
       if (i > start)
-       rc = mu_stream_sequential_write (ostream, buf + start, i  - start);
+       rc = mu_stream_write (ostream, buf + start, i  - start, NULL);
     }
+  mu_stream_destroy (&istream);
   return rc;
 }
 
@@ -302,7 +294,7 @@ format_message (mu_mailbox_t mbox, mu_message_t msg, size_t 
num, void *data)
   if (fp->num)
     {
       asprintf (&s, "\n------- Message %d\n", fp->num++);
-      rc = mu_stream_sequential_write (fp->stream, s, strlen (s));
+      rc = mu_stream_write (fp->stream, s, strlen (s), NULL);
       free (s);
     }
 
@@ -348,7 +340,7 @@ finish_draft ()
       exit (1);
     }
 
-  mu_stream_seek (stream, 0, SEEK_END);
+  mu_stream_seek (stream, 0, SEEK_END, NULL);
 
   if (annotate)
     {
@@ -369,7 +361,7 @@ finish_draft ()
       if (memcmp (mbox_path, "mh:", 3) == 0)
        mbox_path += 3;
       asprintf (&str, "#forw [] +%s", mbox_path);
-      rc = mu_stream_sequential_write (stream, str, strlen (str));
+      rc = mu_stream_write (stream, str, strlen (str), NULL);
       free (str);
       for (i = 0; rc == 0 && i < msgset.count; i++)
        {
@@ -381,13 +373,13 @@ finish_draft ()
            mu_list_append (wh_env.anno_list, msg);
          mh_message_number (msg, &num);
           p = mu_umaxtostr (0, num);
-          rc = mu_stream_sequential_write (stream, p, strlen (p));
+          rc = mu_stream_write (stream, p, strlen (p), NULL);
        }
     }
   else
     {
       str = "\n------- ";
-      rc = mu_stream_sequential_write (stream, str, strlen (str));
+      rc = mu_stream_write (stream, str, strlen (str), NULL);
 
       if (msgset.count == 1)
        {
@@ -400,25 +392,25 @@ finish_draft ()
          str = (char*) _("Forwarded messages\n");
        }
   
-      rc = mu_stream_sequential_write (stream, str, strlen (str));
+      rc = mu_stream_write (stream, str, strlen (str), NULL);
       fd.stream = stream;
       fd.format = format;
       rc = mh_iterate (mbox, &msgset, format_message, &fd);
       
       str = "\n------- ";
-      rc = mu_stream_sequential_write (stream, str, strlen (str));
+      rc = mu_stream_write (stream, str, strlen (str), NULL);
       
       if (msgset.count == 1)
        str = (char*) _("End of Forwarded message");
       else
        str = (char*) _("End of Forwarded messages");
       
-      rc = mu_stream_sequential_write (stream, str, strlen (str));
+      rc = mu_stream_write (stream, str, strlen (str), NULL);
     }
   
-  rc = mu_stream_sequential_write (stream, "\n\n", 2);
+  rc = mu_stream_write (stream, "\n\n", 2, NULL);
   mu_stream_close (stream);
-  mu_stream_destroy (&stream, mu_stream_get_owner (stream));
+  mu_stream_destroy (&stream);
 }
 
 int
@@ -429,7 +421,7 @@ main (int argc, char **argv)
   /* Native Language Support */
   MU_APP_INIT_NLS ();
 
-  mh_argp_init (program_version);
+  mh_argp_init ();
   mh_argp_parse (&argc, &argv, 0, options, mh_option, args_doc, doc,
                 opt_handler, NULL, &index);
 
diff --git a/mh/inc.c b/mh/inc.c
index 4dc9117..184a056 100644
--- a/mh/inc.c
+++ b/mh/inc.c
@@ -21,7 +21,6 @@
 
 #include <mh.h>
 
-const char *program_version = "inc (" PACKAGE_STRING ")";
 static char doc[] = N_("GNU MH inc")"\v"
 N_("Use -help to obtain the list of traditional MH options.");
 static char args_doc[] = N_("[+folder]");
@@ -50,8 +49,6 @@ static struct argp_option options[] = {
    N_("set output width")},
   {"quiet",   ARG_QUIET, 0,        0,
    N_("be quiet")},
-  {"license", ARG_LICENSE, 0,      0,
-   N_("display software license"), -1},
   { 0 }
 };
 
@@ -142,10 +139,6 @@ opt_handler (int key, char *arg, struct argp_state *state)
       quiet = 1;
       break;
 
-    case ARG_LICENSE:
-      mh_license (argp_program_version);
-      break;
-
     default:
       return ARGP_ERR_UNKNOWN;
     }
@@ -181,7 +174,7 @@ main (int argc, char **argv)
   /* Native Language Support */
   MU_APP_INIT_NLS ();
 
-  mh_argp_init (program_version);
+  mh_argp_init ();
   mh_argp_parse (&argc, &argv, 0, options, mh_option, args_doc, doc,
                 opt_handler, NULL, NULL);
 
diff --git a/mh/install-mh.c b/mh/install-mh.c
index fd88631..a563c5f 100644
--- a/mh/install-mh.c
+++ b/mh/install-mh.c
@@ -19,7 +19,6 @@
 
 #include <mh.h>
 
-const char *program_version = "install-mh (" PACKAGE_STRING ")";
 static char doc[] = N_("GNU MH install-mh")"\v"
 N_("Use -help to obtain the list of traditional MH options.");
 static char args_doc[] = "";
@@ -28,8 +27,6 @@ static char args_doc[] = "";
 static struct argp_option options[] = {
   {"auto",  ARG_AUTO, NULL, 0, N_("do not ask for anything")},
   {"compat", ARG_COMPAT, NULL, OPTION_HIDDEN, ""},
-  {"license", ARG_LICENSE, 0,      0,
-   N_("display software license"), -1},
   {NULL}
 };
 
@@ -53,10 +50,6 @@ opt_handler (int key, char *arg, struct argp_state *state)
     case ARG_COMPAT:
       break;
 
-    case ARG_LICENSE:
-      mh_license (argp_program_version);
-      break;
-
     default:
       return ARGP_ERR_UNKNOWN;
     }
@@ -72,7 +65,7 @@ main (int argc, char **argv)
   /* Native Language Support */
   MU_APP_INIT_NLS ();
 
-  mh_argp_init (program_version);
+  mh_argp_init ();
   mh_auto_install = 0;
   mh_argp_parse (&argc, &argv, 0, options, mh_option, args_doc, doc,
                 opt_handler, NULL, NULL);
diff --git a/mh/mark.c b/mh/mark.c
index f5c6cd3..5f67a63 100644
--- a/mh/mark.c
+++ b/mh/mark.c
@@ -19,7 +19,6 @@
 
 #include <mh.h>
 
-const char *program_version = "mark (" PACKAGE_STRING ")";
 static char doc[] = N_("GNU MH mark")"\v"
 N_("Use -help to obtain the list of traditional MH options.");
 static char args_doc[] = "[msgs...]";
@@ -42,8 +41,6 @@ static struct argp_option options[] = {
   {"zero", ARG_ZERO, N_("BOOL"), OPTION_ARG_OPTIONAL,
    N_("empty the sequence before adding messages")},
   {"nozero", ARG_NOZERO, NULL, OPTION_HIDDEN, "" },
-  {"license", ARG_LICENSE, 0,      0,
-   N_("display software license"), -1},
   {NULL}
 };
 
@@ -116,10 +113,6 @@ opt_handler (int key, char *arg, struct argp_state *state)
       seq_flags &= ~SEQ_ZERO;
       break;
       
-    case ARG_LICENSE:
-      mh_license (argp_program_version);
-      break;
-
     default:
       return ARGP_ERR_UNKNOWN;
     }
@@ -195,7 +188,7 @@ main (int argc, char **argv)
   mu_url_t url;
   
   MU_APP_INIT_NLS ();
-  mh_argp_init (program_version);
+  mh_argp_init ();
   mh_argp_parse (&argc, &argv, 0, options, mh_option, args_doc, doc,
                 opt_handler, NULL, &index);
 
diff --git a/mh/mh_argp.c b/mh/mh_argp.c
index fa5e514..be7ed16 100644
--- a/mh/mh_argp.c
+++ b/mh/mh_argp.c
@@ -28,6 +28,9 @@
 #include <string.h>
 #include <mailutils/argcv.h>
 #include "argp.h"
+#ifdef MU_ALPHA_RELEASE
+# include <git-describe.h>
+#endif
 
 static error_t
 parse_opt (int key, char *arg, struct argp_state *state)
@@ -93,11 +96,49 @@ my_argp_parse (struct argp *argp, int argc, char **argv, 
int flags,
   return rc;
 }
 
+const char version_etc_copyright[] =
+  /* Do *not* mark this string for translation.  %s is a copyright
+     symbol suitable for this locale, and %d is the copyright
+     year.  */
+  "Copyright %s 2010 Free Software Foundation, inc.";
+
+/* This is almost the same as mu_program_version_hook from muinit.c,
+   except for different formatting of the first line. MH uses:
+
+      progname (GNU Mailutils X.Y.Z)
+
+   where X.Y.Z stands for the version number. Emacs MH-E uses this
+   to determine Mailutils presence and its version number (see
+   lisp/mh-e/mh-e.el, function mh-variant-mu-mh-info). */
+static void
+mh_program_version_hook (FILE *stream, struct argp_state *state)
+{
+#ifdef GIT_DESCRIBE
+  fprintf (stream, "%s (%s %s) [%s]\n",
+          mu_program_name, PACKAGE_NAME, PACKAGE_VERSION, GIT_DESCRIBE);
+#else
+  fprintf (stream, "%s (%s %s)\n", mu_program_name,
+          PACKAGE_NAME, PACKAGE_VERSION);
+#endif
+  /* TRANSLATORS: Translate "(C)" to the copyright symbol
+     (C-in-a-circle), if this symbol is available in the user's
+     locale.  Otherwise, do not translate "(C)"; leave it as-is.  */
+  fprintf (stream, version_etc_copyright, _("(C)"));
+
+  fputs (_("\
+\n\
+License GPLv3+: GNU GPL version 3 or later 
<http://gnu.org/licenses/gpl.html>\nThis is free software: you are free to 
change and redistribute it.\n\
+There is NO WARRANTY, to the extent permitted by law.\n\
+\n\
+"),
+        stream);
+}
+
 void
-mh_argp_init (const char *vers)
+mh_argp_init ()
 {
-  argp_program_version = vers ? vers : PACKAGE_STRING;
   argp_program_bug_address =  "<" PACKAGE_BUGREPORT ">";
+  argp_program_version_hook = mh_program_version_hook;
 }
 
 
diff --git a/mh/mh_ctx.c b/mh/mh_ctx.c
index 1c2c951..0b4795d 100644
--- a/mh/mh_ctx.c
+++ b/mh/mh_ctx.c
@@ -49,7 +49,7 @@ mh_context_destroy (mh_context_t **pctx)
   
   free ((char*) ctx->name);
   if (ctx->header)
-    mu_header_destroy (&ctx->header, mu_header_get_owner (ctx->header));
+    mu_header_destroy (&ctx->header);
   free (ctx);
   *pctx = NULL;
 }
@@ -121,7 +121,7 @@ mh_context_read (mh_context_t *ctx)
     }
   fclose (fp);
 
-  status = mu_header_create (&ctx->header, blurb, p - blurb, NULL);
+  status = mu_header_create (&ctx->header, blurb, p - blurb);
   free (blurb);
 
   return status;
@@ -132,7 +132,7 @@ mh_context_write (mh_context_t *ctx)
 {
   mu_stream_t stream;
   char buffer[512];
-  size_t off = 0, n;
+  size_t n;
   FILE *fp;
   
   if (!ctx)
@@ -145,17 +145,16 @@ mh_context_write (mh_context_t *ctx)
                ctx->name, strerror (errno));
       return MU_ERR_FAILURE;
     }
-  
-  mu_header_get_stream (ctx->header, &stream);
 
-  while (mu_stream_read (stream, buffer, sizeof buffer - 1, off, &n) == 0
+  /* FIXME: Use mu_stream+copy */
+  mu_header_get_streamref (ctx->header, &stream);
+  while (mu_stream_read (stream, buffer, sizeof buffer - 1, &n) == 0
         && n != 0)
     {
       buffer[n] = '\0';
       fprintf (fp, "%s", buffer);
-      off += n;
     }
-
+  mu_stream_destroy (&stream);
   fclose (fp);
   return 0;
 }
@@ -178,7 +177,7 @@ mh_context_set_value (mh_context_t *ctx, const char *name, 
const char *value)
   if (!ctx->header)
     {
       int rc;
-      if ((rc = mu_header_create (&ctx->header, NULL, 0, NULL)) != 0)
+      if ((rc = mu_header_create (&ctx->header, NULL, 0)) != 0)
        {
          mu_error (_("cannot create context %s: %s"),
                    ctx->name,
diff --git a/mh/mh_format.c b/mh/mh_format.c
index a804667..7d548c0 100644
--- a/mh/mh_format.c
+++ b/mh/mh_format.c
@@ -603,14 +603,16 @@ mh_format (mh_format_t *fmt, mu_message_t msg, size_t 
msgno,
          {
            mu_body_t body = NULL;
            mu_stream_t stream = NULL;
-           size_t size = 0, off, str_off, nread;
+           size_t size = 0, str_off, nread;
            size_t rest = DFLWIDTH (&mach);
 
            strobj_free (&mach.arg_str);
            mu_message_get_body (mach.message, &body);
            mu_body_size (body, &size);
-           mu_body_get_stream (body, &stream);
-           if (size == 0 || !stream)
+           if (size == 0)
+             break;
+           mu_body_get_streamref (body, &stream);
+           if (!stream)
              break;
            if (size > rest)
              size = rest;
@@ -618,18 +620,17 @@ mh_format (mh_format_t *fmt, mu_message_t msg, size_t 
msgno,
            mach.arg_str.ptr = xmalloc (size+1);
            mach.arg_str.size = size;
            
-           off = 0;
            str_off = 0;
            while (!mu_stream_read (stream, mach.arg_str.ptr + str_off,
-                                mach.arg_str.size - str_off, off, &nread)
+                                   mach.arg_str.size - str_off, &nread)
                   && nread != 0
                   && str_off < size)
              {
-               off += nread;
                 COMPRESS_WS (&mach, mach.arg_str.ptr + str_off, &nread);
                if (nread)
                  str_off += nread;
              }
+           mu_stream_destroy (&stream);
            mach.arg_str.ptr[str_off] = 0;
          }
          break;
diff --git a/mh/mh_getopt.h b/mh/mh_getopt.h
index b930cf3..beb6fff 100644
--- a/mh/mh_getopt.h
+++ b/mh/mh_getopt.h
@@ -89,7 +89,6 @@ enum mh_arg {
   ARG_INTERACTIVE,     
   ARG_LBRACE,          
   ARG_LENGTH,          
-  ARG_LICENSE,         
   ARG_LIMIT,           
   ARG_LINK,            
   ARG_LIST,            
@@ -184,7 +183,7 @@ enum mh_arg {
   ARG_ZERO
 };
 
-void mh_argp_init (const char *vers);
+void mh_argp_init (void);
 void mh_argv_preproc (int argc, char **argv, struct mh_argp_data *data);
 int mh_getopt (int argc, char **argv, struct mh_option *mh_opt, const char 
*doc);
 int mh_argp_parse (int *argc, char **argv[],
diff --git a/mh/mh_init.c b/mh/mh_init.c
index 3dd69ad..776e450 100644
--- a/mh/mh_init.c
+++ b/mh/mh_init.c
@@ -613,15 +613,15 @@ mh_file_copy (const char *from, const char *to)
                to, mu_strerror (rc));
       free (buffer);
       mu_stream_close (in);
-      mu_stream_destroy (&in, mu_stream_get_owner (in));
+      mu_stream_destroy (&in);
       return 1;
     }
 
   while (st.st_size > 0
-        && (rc = mu_stream_sequential_read (in, buffer, bufsize, &rdsize)) == 0
+        && (rc = mu_stream_read (in, buffer, bufsize, &rdsize)) == 0
         && rdsize > 0)
     {
-      if ((rc = mu_stream_sequential_write (out, buffer, rdsize)) != 0)
+      if ((rc = mu_stream_write (out, buffer, rdsize, NULL)) != 0)
        {
          mu_error (_("write error on `%s': %s"),
                    to, mu_strerror (rc));
@@ -634,8 +634,8 @@ mh_file_copy (const char *from, const char *to)
 
   mu_stream_close (in);
   mu_stream_close (out);
-  mu_stream_destroy (&in, mu_stream_get_owner (in));
-  mu_stream_destroy (&out, mu_stream_get_owner (out));
+  mu_stream_destroy (&in);
+  mu_stream_destroy (&out);
   
   return rc;
 }
@@ -664,7 +664,7 @@ _file_to_message (const char *file_name)
     {
       mu_error (_("cannot open input stream (file %s): %s"),
                file_name, mu_strerror (rc));
-      mu_stream_destroy (&instream, mu_stream_get_owner (instream));
+      mu_stream_destroy (&instream);
       return NULL;
     }
 
diff --git a/mh/mh_list.c b/mh/mh_list.c
index 6d8c651..4df743f 100644
--- a/mh/mh_list.c
+++ b/mh/mh_list.c
@@ -532,8 +532,8 @@ ovf_print (struct eval_env *env, char *str, int size, int 
nloff)
          if (env->svar[S_OVERFLOWTEXT])
            {
              int l = strlen (env->svar[S_OVERFLOWTEXT]);
-             mu_stream_sequential_write (env->output,
-                                      env->svar[S_OVERFLOWTEXT], l);
+             mu_stream_write (env->output,
+                              env->svar[S_OVERFLOWTEXT], l, NULL);
              env->pos += l;
            }
        }
@@ -543,8 +543,8 @@ ovf_print (struct eval_env *env, char *str, int size, int 
nloff)
            {
              goto_offset (env, env->ivar[I_OFFSET]);
              
-             mu_stream_sequential_write (env->output, env->prefix,
-                                      strlen (env->prefix));
+             mu_stream_write (env->output, env->prefix,
+                              strlen (env->prefix), NULL);
              env->pos += strlen (env->prefix);
              
              goto_offset (env, nloff);
@@ -557,7 +557,7 @@ ovf_print (struct eval_env *env, char *str, int size, int 
nloff)
          len = env->ivar[I_WIDTH] - env->pos;
        }
       
-      mu_stream_sequential_write (env->output, str, len);
+      mu_stream_write (env->output, str, len, NULL);
       env->pos += len;
       if (env->pos >= env->ivar[I_WIDTH])
        newline (env);
@@ -595,15 +595,15 @@ print (struct eval_env *env, char *str, int nloff)
 static void
 newline (struct eval_env *env)
 {
-  mu_stream_sequential_write (env->output, "\n", 1);
+  mu_stream_write (env->output, "\n", 1, NULL);
   env->pos = 0;
   if (env->ivar[I_LENGTH] && ++env->nlines >= env->ivar[I_LENGTH])
     {
       /* FIXME: Better to write it directly on the terminal */
       if (env->bvar[B_BELL])
-       mu_stream_sequential_write (env->output, "\a", 1);
+       mu_stream_write (env->output, "\a", 1, NULL);
       if (env->bvar[B_CLEARSCREEN])
-       mu_stream_sequential_write (env->output, "\f", 1);
+       mu_stream_write (env->output, "\f", 1, NULL);
       env->nlines = 0;
     }
 }
@@ -612,7 +612,7 @@ static void
 goto_offset (struct eval_env *env, int count)
 {
   for (; env->pos < count; env->pos++)
-    mu_stream_sequential_write (env->output, " ", 1);
+    mu_stream_write (env->output, " ", 1, NULL);
 }
 
 int
@@ -687,7 +687,7 @@ eval_body (struct eval_env *env)
   env->prefix = env->svar[S_COMPONENT];
 
   mu_message_get_body (env->msg, &body);
-  mu_body_get_stream (body, &input);
+  mu_body_get_streamref (body, &input);
 
   if (env->bvar[B_DECODE])
     {
@@ -698,24 +698,22 @@ eval_body (struct eval_env *env)
       mu_header_aget_value (hdr, MU_HEADER_CONTENT_TRANSFER_ENCODING, 
&encoding);
       if (encoding)
        {
-         int rc = mu_filter_create(&dstr, input, encoding,
-                                   MU_FILTER_DECODE, 
-                                   MU_STREAM_READ | MU_STREAM_NO_CLOSE);
+         int rc = mu_filter_create (&dstr, input, encoding,
+                                    MU_FILTER_DECODE, 
+                                    MU_STREAM_READ);
          if (rc == 0)
            input = dstr;
          free (encoding);
        }
     }
   
-  mu_stream_seek (input, 0, SEEK_SET);
-  while (mu_stream_sequential_readline (input, buf, sizeof buf, &n) == 0
+  while (mu_stream_readline (input, buf, sizeof buf, &n) == 0
         && n > 0)
     {
       buf[n] = 0;
       print (env, buf, 0);
     }
-  if (dstr)
-    mu_stream_destroy (&dstr, mu_stream_get_owner (dstr));
+  mu_stream_destroy (&input);
   return 0;
 }
 
diff --git a/mh/mh_whatnow.c b/mh/mh_whatnow.c
index f4ecfea..8652fc0 100644
--- a/mh/mh_whatnow.c
+++ b/mh/mh_whatnow.c
@@ -189,7 +189,6 @@ display_file (const char *name)
     {
       mu_stream_t stream;
       int rc;
-      size_t off = 0;
       size_t n;
       char buffer[512];
       
@@ -205,15 +204,15 @@ display_file (const char *name)
          mu_error ("mu_stream_open: %s", mu_strerror (rc));
          return;
        } 
-      
-      while (mu_stream_read (stream, buffer, sizeof buffer - 1, off, &n) == 0
+
+      mu_stream_seek (stream, 0, MU_SEEK_SET, NULL);
+      while (mu_stream_read (stream, buffer, sizeof buffer - 1, &n) == 0
             && n != 0)
        {
          buffer[n] = '\0';
          printf ("%s", buffer);
-         off += n;
        }
-      mu_stream_destroy (&stream, NULL);
+      mu_stream_destroy (&stream);
     }
 }      
 
diff --git a/mh/mhl.c b/mh/mhl.c
index daf9910..6a7024d 100644
--- a/mh/mhl.c
+++ b/mh/mhl.c
@@ -23,7 +23,6 @@
 #include <sys/stat.h>
 #include <unistd.h>
 
-const char *program_version = "mhl (" PACKAGE_STRING ")";
 static char doc[] = N_("GNU MH mhl")"\v"
 N_("Use -help to obtain the list of traditional MH options.");
 static char args_doc[] = N_("[files]");
@@ -48,8 +47,6 @@ static struct argp_option options[] = {
    N_("use given PROG instead of the default") },
   {"nomoreproc", ARG_NOMOREPROC, NULL, 0,
    N_("disable use of moreproc program") },
-  {"license", ARG_LICENSE, 0,      0,
-   N_("display software license"), -1},
   { NULL }
 };
    
@@ -133,10 +130,6 @@ opt_handler (int key, char *arg, struct argp_state *state)
       nomoreproc = 1;
       break;
       
-    case ARG_LICENSE:
-      mh_license (argp_program_version);
-      break;
-
     default:
       return ARGP_ERR_UNKNOWN;
     }
@@ -160,7 +153,7 @@ open_output ()
   if (moreproc)
     rc = mu_prog_stream_create (&output, moreproc, MU_STREAM_WRITE);
   else
-    rc = mu_stdio_stream_create (&output, stdout, MU_STREAM_WRITE);
+    rc = mu_stdio_stream_create (&output, MU_STDOUT_FD, MU_STREAM_WRITE);
 
   if (rc)
     {
@@ -184,7 +177,7 @@ list_message (char *name, mu_stream_t output)
   mu_message_t msg;
 
   if (!name)
-    rc = mu_stdio_stream_create (&input, stdin, MU_STREAM_SEEKABLE);
+    rc = mu_stdio_stream_create (&input, MU_STDIN_FD, MU_STREAM_SEEK);
   else
     rc = mu_file_stream_create (&input, name, MU_STREAM_READ);
   if (rc)
@@ -196,7 +189,7 @@ list_message (char *name, mu_stream_t output)
   if ((rc = mu_stream_open (input)))
     {
       mu_error (_("cannot open input stream: %s"), mu_strerror (rc));
-      mu_stream_destroy (&input, mu_stream_get_owner (input));
+      mu_stream_destroy (&input);
       return;
     }
 
@@ -206,7 +199,7 @@ list_message (char *name, mu_stream_t output)
       mu_error (_("input stream %s is not a message (%s)"),
                name, mu_strerror (rc));
       mu_stream_close (input);
-      mu_stream_destroy (&input, mu_stream_get_owner (input));
+      mu_stream_destroy (&input);
     }
   else
     {
@@ -224,7 +217,7 @@ main (int argc, char **argv)
   interactive = isatty (1) && isatty (0);
   
   MU_APP_INIT_NLS ();
-  mh_argp_init (program_version);
+  mh_argp_init ();
   mh_argp_parse (&argc, &argv, 0, options, mh_option, args_doc, doc,
                 opt_handler, NULL, &index);
 
diff --git a/mh/mhn.c b/mh/mhn.c
index b764e97..356f886 100644
--- a/mh/mhn.c
+++ b/mh/mhn.c
@@ -26,7 +26,6 @@
 #define obstack_chunk_free free
 #include <obstack.h>
 
-const char *program_version = "mhn (" PACKAGE_STRING ")";
 static char doc[] = N_("GNU MH mhn")"\v"
 N_("Options marked with `*' are not yet implemented.\n\
 Use -help to obtain the list of traditional MH options.");
@@ -87,8 +86,6 @@ static struct argp_option options[] = {
   {"noverbose",    ARG_NOVERBOSE,   NULL, OPTION_HIDDEN, "", 41 },
   {"quiet",        ARG_QUIET, 0, 0,
    N_("be quiet")},
-  {"license", ARG_LICENSE, 0,      0,
-   N_("display software license"), -1},
   {NULL}
 };
 
@@ -398,10 +395,6 @@ opt_handler (int key, char *arg, struct argp_state *state)
       mode_options |= OPT_QUIET;
       break;
        
-    case ARG_LICENSE:
-      mh_license (argp_program_version);
-      break;
-
     case ARG_CHARSET:
       charset = arg;
       break;
@@ -962,6 +955,7 @@ _free_env (char **env)
   free (env);
 }
 
+/* FIXME: Use mimehdr.c functions instead */
 int
 get_extbody_params (mu_message_t msg, char **content, char **descr)
 {
@@ -972,11 +966,10 @@ get_extbody_params (mu_message_t msg, char **content, 
char **descr)
   size_t n;
        
   mu_message_get_body (msg, &body);
-  mu_body_get_stream (body, &stream);
-  mu_stream_seek (stream, 0, SEEK_SET);
+  mu_body_get_streamref (body, &stream);
 
   while (rc == 0
-        && mu_stream_sequential_readline (stream, buf, sizeof buf, &n) == 0
+        && mu_stream_readline (stream, buf, sizeof buf, &n) == 0
         && n > 0)
     {
       char *p;
@@ -1006,6 +999,7 @@ get_extbody_params (mu_message_t msg, char **content, char 
**descr)
          *content = strdup (p);
        }
     }
+  mu_stream_destroy (&stream);
   return 0;
 }
 
@@ -1113,7 +1107,7 @@ mhn_message_size (mu_message_t msg, size_t *psize)
     {
       mu_stream_t dstr = NULL, bstr = NULL;
 
-      if (mu_body_get_stream (body, &bstr) == 0)
+      if (mu_body_get_streamref (body, &bstr) == 0)
        {
          mu_header_t hdr;
          char *encoding;
@@ -1125,21 +1119,22 @@ mhn_message_size (mu_message_t msg, size_t *psize)
 
          rc = mu_filter_create (&dstr, bstr, encoding,
                                 MU_FILTER_DECODE, 
-                                MU_STREAM_READ | MU_STREAM_NO_CLOSE);
+                                MU_STREAM_READ);
          free (encoding);
          if (rc == 0)
            {
              char buf[512];
              size_t n;
-             
-             while (mu_stream_sequential_read (dstr, buf, sizeof buf, &n) == 0
+
+             while (mu_stream_read (dstr, buf, sizeof buf, &n) == 0
                     && n > 0)
                size += n;
 
-             mu_stream_destroy (&dstr, NULL);
+             mu_stream_destroy (&dstr);
              *psize = size;
              return 0;
            }
+         mu_stream_destroy (&bstr);
        }
     }
 
@@ -1245,20 +1240,6 @@ mhn_list ()
 
 static mu_list_t mhl_format;
 
-void
-cat_message (mu_stream_t out, mu_stream_t in)
-{
-  int rc = 0;
-  char buf[512];
-  size_t n;
-
-  mu_stream_seek (in, 0, SEEK_SET);
-  while (rc == 0
-        && mu_stream_sequential_read (in, buf, sizeof buf, &n) == 0
-        && n > 0)
-    rc = mu_stream_sequential_write (out, buf, n);
-}
-
 int
 show_internal (mu_message_t msg, msg_part_t part, char *encoding, mu_stream_t 
out)
 {
@@ -1273,15 +1254,14 @@ show_internal (mu_message_t msg, msg_part_t part, char 
*encoding, mu_stream_t ou
                mu_strerror (rc));
       return 0;
     }
-  mu_body_get_stream (body, &bstr);
+  mu_body_get_streamref (body, &bstr);
   rc = mu_filter_create (&dstr, bstr, encoding,
-                        MU_FILTER_DECODE, MU_STREAM_READ | MU_STREAM_NO_CLOSE);
+                        MU_FILTER_DECODE, MU_STREAM_READ);
   if (rc == 0)
     bstr = dstr;
-  cat_message (out, bstr);
-  if (dstr)
-    mu_stream_destroy (&dstr, mu_stream_get_owner (dstr));
-  return 0;
+  rc = mu_stream_copy (out, bstr, 0, NULL);
+  mu_stream_destroy (&bstr);
+  return rc;
 }
   
 int
@@ -1313,7 +1293,7 @@ exec_internal (mu_message_t msg, msg_part_t part, char 
*encoding,
   if ((rc = mhn_exec (&tmp, cmd, flags)))
     return rc;
   show_internal (msg, part, encoding, tmp);      
-  mu_stream_destroy (&tmp, mu_stream_get_owner (tmp));
+  mu_stream_destroy (&tmp);
   return rc;
 }
 
@@ -1355,12 +1335,12 @@ mhn_run_command (mu_message_t msg, msg_part_t part,
        {
          mu_error (_("cannot open temporary stream (file %s): %s"),
                    tempfile, mu_strerror (rc));
-         mu_stream_destroy (&tmp, mu_stream_get_owner (tmp));
+         mu_stream_destroy (&tmp);
          mu_argcv_free (argc, argv);
          return rc;
        }
       show_internal (msg, part, encoding, tmp);      
-      mu_stream_destroy (&tmp, mu_stream_get_owner (tmp));
+      mu_stream_destroy (&tmp);
       rc = mu_spawnvp (argv[0], argv, &status);
       if (status)
        rc = status;
@@ -1382,13 +1362,13 @@ show_handler (mu_message_t msg, msg_part_t part, char 
*type, char *encoding,
   int fd = 1;
   char *tempfile = NULL;
   int ismime;
-  mu_transport_t trans;
+  mu_transport_t trans[2];
  
   if (mu_message_is_multipart (msg, &ismime) == 0 && ismime)
     return 0;
 
-  mu_stream_get_transport (out, &trans);
-  fd = (int) trans; /* FIXME */
+  mu_stream_ioctl (out, MU_IOCTL_GET_TRANSPORT, trans);
+  fd = (int) trans[0]; /* FIXME */
 
   if (mode_options & OPT_PAUSE)
     flags |= MHN_CONFIRM;
@@ -1402,16 +1382,16 @@ show_handler (mu_message_t msg, msg_part_t part, char 
*type, char *encoding,
       size_t size = 0;
 
       str = (char*) _("part ");
-      mu_stream_sequential_write (out, str, strlen (str));
+      mu_stream_write (out, str, strlen (str), NULL);
       str = msg_part_format (part);
-      mu_stream_sequential_write (out, str, strlen (str));
+      mu_stream_write (out, str, strlen (str), NULL);
       free (str);
-      mu_stream_sequential_write (out, " ", 1);
-      mu_stream_sequential_write (out, type, strlen (type));
+      mu_stream_write (out, " ", 1, NULL);
+      mu_stream_write (out, type, strlen (type), NULL);
       mhn_message_size (msg, &size);
       p = mu_umaxtostr (0, size);
-      mu_stream_sequential_write (out, p, strlen (p));
-      mu_stream_sequential_write (out, "\n", 1);
+      mu_stream_write (out, p, strlen (p), NULL);
+      mu_stream_write (out, "\n", 1, NULL);
       mu_stream_flush (out);
     }
 
@@ -1476,7 +1456,7 @@ mhn_show ()
   int rc;
   mu_stream_t ostr;
   
-  rc = mu_stdio_stream_create (&ostr, stdout, 0);
+  rc = mu_stdio_stream_create (&ostr, MU_STDOUT_FD, 0);
   if (rc)
     {
       mu_error (_("cannot create output stream: %s"), mu_strerror (rc));
@@ -1668,12 +1648,12 @@ store_handler (mu_message_t msg, msg_part_t part, char 
*type, char *encoding,
       mu_error (_("cannot open output stream (file %s): %s"),
                name, mu_strerror (rc));
       free (name);
-      mu_stream_destroy (&out, mu_stream_get_owner (out));
+      mu_stream_destroy (&out);
       return rc;
     }
   show_internal (msg, part, encoding, out);      
 
-  mu_stream_destroy (&out, mu_stream_get_owner (out));
+  mu_stream_destroy (&out);
   free (name);
   
   return 0;
@@ -1719,39 +1699,6 @@ mhn_store ()
 
 /* ***************************** Compose Mode **************************** */
 
-int
-stream_getline (mu_stream_t str, char **buf, size_t *bufsize, size_t *pnum)
-{
-  int rc;
-  size_t numread, n;
-
-  if (!*buf)
-    {
-      *bufsize = 128;
-      *buf = xmalloc (*bufsize);
-    }
-  numread = 0;
-  while ((rc = mu_stream_sequential_readline (str, *buf + numread,
-                                          *bufsize - numread, &n)) == 0
-        && n > 0)
-    {
-      numread += n;
-      if ((*buf)[numread - 1] != '\n')
-       {
-         if (numread + 1 == *bufsize)
-           {
-             *bufsize += 128;
-             *buf = xrealloc (*buf, *bufsize);
-           }
-         continue;
-       }
-      break;
-    }
-  if (pnum)
-    *pnum = numread;
-  return rc;
-}
-
 struct compose_env {
   mu_stream_t input;
   mu_mime_t mime;
@@ -1997,14 +1944,15 @@ copy_header_to_stream (mu_message_t msg, mu_stream_t 
stream)
   size_t bufsize = 0, n = 0;
   
   mu_message_get_header (msg, &hdr);
-  mu_header_get_stream (hdr, &in);
-  mu_stream_seek (in, 0, SEEK_SET);
-  while (stream_getline (in, &buf, &bufsize, &n) == 0 && n > 0)
+  mu_header_get_streamref (hdr, &in);
+  /* FIXME: Use mu_stream_copy */
+  while (mu_stream_getline (in, &buf, &bufsize, &n) == 0 && n > 0)
     {
       if (n == 1 && buf[0] == '\n')
        break;
-      mu_stream_sequential_write (stream, buf, n);
+      mu_stream_write (stream, buf, n, NULL);
     }
+  mu_stream_destroy (&in);
   free (buf);
 }
 
@@ -2042,29 +1990,29 @@ finish_text_msg (struct compose_env *env, mu_message_t 
*msg, int ascii)
       
       mu_message_create (&newmsg, NULL);
       mu_message_get_header (newmsg, &hdr);
-      mu_header_get_stream (hdr, &output);
       copy_header (*msg, hdr);
       mu_header_set_value (hdr, MU_HEADER_CONTENT_TRANSFER_ENCODING,
                           "quoted-printable", 0);
       
       mu_message_get_body (newmsg, &body);
-      mu_body_get_stream (body, &output);
-      mu_stream_seek (output, 0, SEEK_SET);
+      mu_body_get_streamref (body, &output);
 
       mu_message_get_body (*msg, &body);
-      mu_body_get_stream (body, &input);
+      mu_body_get_streamref (body, &input);
       rc = mu_filter_create (&fstr, input, "quoted-printable",
                             MU_FILTER_ENCODE, 
-                            MU_STREAM_READ | MU_STREAM_NO_CLOSE);
+                            MU_STREAM_READ);
       if (rc == 0)
        {
-         cat_message (output, fstr);
-         mu_stream_destroy (&fstr, NULL);
+         mu_stream_copy (output, fstr, 0, NULL);
+         mu_stream_destroy (&fstr);
          mu_message_unref (*msg);
          *msg = newmsg;
        }
       else
        mu_message_destroy (&newmsg, NULL);
+      mu_stream_destroy (&input);
+      mu_stream_destroy (&output);
     }
   finish_msg (env, msg);
 }
@@ -2085,7 +2033,7 @@ edit_extern (char *cmd, struct compose_env *env, 
mu_message_t *msg, int level)
   if (!*msg)
     mu_message_create (msg, NULL);
   
-  if ((rc = mu_header_create (&hdr2, NULL, 0, NULL)) != 0)
+  if ((rc = mu_header_create (&hdr2, NULL, 0)) != 0)
     {
       mu_error (_("cannot create header: %s"),
                mu_strerror (rc));
@@ -2108,19 +2056,20 @@ edit_extern (char *cmd, struct compose_env *env, 
mu_message_t *msg, int level)
     return 1;
 
   mu_message_get_body (*msg, &body);
-  mu_body_get_stream (body, &out);
-  mu_stream_seek (out, 0, SEEK_SET);
+  mu_body_get_streamref (body, &out);
 
   if (!id)
     id = mh_create_message_id (env->subpart);
   mu_header_set_value (hdr2, MU_HEADER_CONTENT_ID, id, 1);
   free (id);
 
-  mu_header_get_stream (hdr2, &in);
-  mu_stream_seek (in, 0, SEEK_SET);
-  cat_message (out, in);
+  mu_header_get_streamref (hdr2, &in);
+  mu_stream_copy (out, in, 0, NULL);
+  mu_stream_destroy (&in);
   mu_stream_close (out);
-  mu_header_destroy (&hdr2, mu_header_get_owner (hdr2));
+  mu_stream_destroy (&out);
+  
+  mu_header_destroy (&hdr2);
 
   finish_msg (env, msg);
   return 0;
@@ -2302,7 +2251,7 @@ edit_mime (char *cmd, struct compose_env *env, 
mu_message_t *msg, int level)
        {
          mu_error (_("cannot open input stream (file %s): %s"),
                    cmd, mu_strerror (rc));
-         mu_stream_destroy (&in, mu_stream_get_owner (in));
+         mu_stream_destroy (&in);
          return rc;
        }
     }
@@ -2327,7 +2276,8 @@ edit_mime (char *cmd, struct compose_env *env, 
mu_message_t *msg, int level)
       free (subtype);
     }
 
-  rc = mu_filter_create (&fstr, in, encoding, MU_FILTER_ENCODE, 
MU_STREAM_READ);
+  rc = mu_filter_create (&fstr, in, encoding, MU_FILTER_ENCODE,
+                         MU_STREAM_READ | MU_STREAM_AUTOCLOSE);
   if (rc)
     {
       fstr = in;
@@ -2344,12 +2294,12 @@ edit_mime (char *cmd, struct compose_env *env, 
mu_message_t *msg, int level)
     }
   
   mu_message_get_body (*msg, &body);
-  mu_body_get_stream (body, &out);
-  cat_message (out, fstr);
+  mu_body_get_streamref (body, &out);
+  mu_stream_copy (out, fstr, 0, NULL);
 
   mu_stream_close (out);
-  
-  mu_stream_destroy (&fstr, mu_stream_get_owner (fstr));
+  mu_stream_destroy (&out);
+  mu_stream_destroy (&fstr);
   finish_msg (env, msg);
   return rc;
 }
@@ -2371,24 +2321,27 @@ mhn_edit (struct compose_env *env, int level)
   char *buf = NULL;
   size_t bufsize = 0, n;
   mu_body_t body;
-  mu_stream_t output;
+  mu_stream_t output = NULL;
   mu_message_t msg = NULL;
   size_t line_count = 0;
   int ascii_buf;
   
   while (status == 0
-        && stream_getline (env->input, &buf, &bufsize, &n) == 0 && n > 0)
+        && mu_stream_getline (env->input, &buf, &bufsize, &n) == 0 && n > 0)
     {
       env->line++;
       if (!msg)
        {
          mu_header_t hdr;
+
+         /* Destroy old stream */
+         mu_stream_destroy (&output);
+         
          /* Create new message */
          mu_message_create (&msg, NULL);
          mu_message_get_header (msg, &hdr);
          mu_message_get_body (msg, &body);
-         mu_body_get_stream (body, &output);
-         mu_stream_seek (output, 0, SEEK_SET);
+         mu_body_get_streamref (body, &output);
          line_count = 0;
          ascii_buf = 1; /* Suppose it is ascii */
          env->subpart++;
@@ -2397,7 +2350,7 @@ mhn_edit (struct compose_env *env, int level)
       if (buf[0] == '#')
        {
          if (buf[1] == '#')
-           mu_stream_sequential_write (output, buf+1, n-1);
+           mu_stream_write (output, buf+1, n-1, NULL);
          else
            {
              char *b2 = NULL;
@@ -2407,7 +2360,7 @@ mhn_edit (struct compose_env *env, int level)
              /* Collect the whole line */
              while (n > 2 && buf[n-2] == '\\')
                {
-                 int rc = stream_getline (env->input, &b2, &bs, &n2);
+                 int rc = mu_stream_getline (env->input, &b2, &bs, &n2);
                  env->line++;
                  if (rc == 0 && n2 > 0)
                    {
@@ -2423,6 +2376,8 @@ mhn_edit (struct compose_env *env, int level)
              free (b2);
 
              mu_stream_close (output);
+             mu_stream_destroy (&output);
+             
              if (line_count)
                /* Close and append the previous part */
                finish_text_msg (env, &msg, ascii_buf);
@@ -2491,7 +2446,7 @@ mhn_edit (struct compose_env *env, int level)
        {
          if (ascii_buf && has_nonascii (buf, n))
            ascii_buf = 0;
-         mu_stream_sequential_write (output, buf, n);
+         mu_stream_write (output, buf, n, NULL);
          line_count++;
        }
     }
@@ -2505,6 +2460,7 @@ mhn_edit (struct compose_env *env, int level)
       else
        mu_message_unref (msg);
     }
+  mu_stream_destroy (&output);
   
   return status;
 }
@@ -2653,14 +2609,14 @@ mhn_compose ()
   mu_mime_create (&mime, NULL, 0);
 
   mu_message_get_body (message, &body);
-  mu_body_get_stream (body, &stream);
-  mu_stream_seek (stream, 0, SEEK_SET);
+  mu_body_get_streamref (body, &stream);
 
   env.mime = mime;
   env.input = stream;
   env.subpart = 0;
   env.line = 0;
   rc = mhn_edit (&env, 0);
+  mu_stream_destroy (&stream);
   if (rc)
     return rc;
 
@@ -2697,16 +2653,17 @@ mhn_compose ()
       mu_error (_("cannot open output stream (file %s): %s"),
                name, mu_strerror (rc));
       free (name);
-      mu_stream_destroy (&stream, mu_stream_get_owner (stream));
+      mu_stream_destroy (&stream);
       return rc;
     }
 
   mhn_header (message, msg);
   copy_header_to_stream (message, stream);
-  mu_message_get_stream (msg, &in);
-  cat_message (stream, in);
-  mu_stream_destroy (&stream, mu_stream_get_owner (stream));
-
+  mu_message_get_streamref (msg, &in);
+  mu_stream_copy (stream, in, 0, NULL);
+  mu_stream_destroy (&in);
+  mu_stream_destroy (&stream);
+  
   /* Preserve the backup copy and replace the draft */
   unlink (backup);
   rename (input_file, backup);
@@ -2728,7 +2685,7 @@ main (int argc, char **argv)
   
   MU_APP_INIT_NLS ();
   
-  mh_argp_init (program_version);
+  mh_argp_init ();
   mh_argp_parse (&argc, &argv, 0, options, mh_option, args_doc, doc,
                 opt_handler, NULL, &index);
 
diff --git a/mh/mhparam.c b/mh/mhparam.c
index 85a28b2..f9b7a23 100644
--- a/mh/mhparam.c
+++ b/mh/mhparam.c
@@ -21,7 +21,6 @@
 
 #include <mh.h>
 
-const char *program_version = "mhparam (" PACKAGE_STRING ")";
 static char doc[] = N_("GNU MH mhparam")"\v"
 N_("Use -help to obtain the list of traditional MH options.");
 static char args_doc[] = N_("[components]");
@@ -32,8 +31,6 @@ static struct argp_option options[] = {
    N_("display all components from the MH profile. All other arguments are 
ignored")},
   {"component", ARG_COMPONENT, N_("BOOL"),   OPTION_ARG_OPTIONAL,
    N_("always display the component name") },
-  {"license", ARG_LICENSE, 0,      0,
-   N_("display software license"), -1},
   { 0 }
 };
 
@@ -60,10 +57,6 @@ opt_handler (int key, char *arg, struct argp_state *state)
       display_comp_name = is_true (arg);
       break;
       
-    case ARG_LICENSE:
-      mh_license (argp_program_version);
-      break;
-
     default:
       return ARGP_ERR_UNKNOWN;
     }
@@ -126,7 +119,7 @@ main (int argc, char **argv)
   /* Native Language Support */
   MU_APP_INIT_NLS ();
 
-  mh_argp_init (program_version);
+  mh_argp_init ();
   mh_argp_parse (&argc, &argv, 0, options, mh_option, args_doc, doc,
                 opt_handler, NULL, &index);
 
diff --git a/mh/mhpath.c b/mh/mhpath.c
index c222fc7..04d58f8 100644
--- a/mh/mhpath.c
+++ b/mh/mhpath.c
@@ -21,7 +21,6 @@
 
 #include <mh.h>
 
-const char *program_version = "mhpath (" PACKAGE_STRING ")";
 static char doc[] = N_("GNU MH mhpath")"\v"
 N_("Use -help to obtain the list of traditional MH options.");
 static char args_doc[] = N_("[+folder] [msgs]");
@@ -30,8 +29,6 @@ static char args_doc[] = N_("[+folder] [msgs]");
 static struct argp_option options[] = {
   {"folder",  ARG_FOLDER, N_("FOLDER"), 0,
    N_("specify folder to operate upon")},
-  {"license", ARG_LICENSE, 0,      0,
-   N_("display software license"), -1},
   { 0 }
 };
 
@@ -49,10 +46,6 @@ opt_handler (int key, char *arg, struct argp_state *state)
       mh_set_current_folder (arg);
       break;
       
-    case ARG_LICENSE:
-      mh_license (argp_program_version);
-      break;
-
     default:
       return ARGP_ERR_UNKNOWN;
     }
@@ -83,7 +76,7 @@ main (int argc, char **argv)
   /* Native Language Support */
   MU_APP_INIT_NLS ();
 
-  mh_argp_init (program_version);
+  mh_argp_init ();
   mh_argp_parse (&argc, &argv, 0, options, mh_option, args_doc, doc,
                 opt_handler, NULL, &index);
 
diff --git a/mh/pick.c b/mh/pick.c
index ecf3f8a..f51a386 100644
--- a/mh/pick.c
+++ b/mh/pick.c
@@ -27,7 +27,6 @@
 #define obstack_chunk_free free
 #include <obstack.h>
 
-const char *program_version = "pick (" PACKAGE_STRING ")";
 static char doc[] = N_("GNU MH pick")"\v"
 N_("Use -help to obtain the list of traditional MH options.");
 static char args_doc[] = N_("[messages]");
@@ -90,8 +89,6 @@ static struct argp_option options[] = {
   {"zero",     ARG_ZERO,     N_("BOOL"), OPTION_ARG_OPTIONAL,
    N_("empty the sequence before adding messages"), 4},
   {"nozero", ARG_NOZERO, NULL, OPTION_HIDDEN, "", 4 },
-  {"license", ARG_LICENSE, 0,      0,
-   N_("display software license"), -1},
   {NULL},
 };
 
@@ -285,10 +282,6 @@ opt_handler (int key, char *arg, struct argp_state *state)
       pick_add_token (&lexlist, T_STRING, p);
       break;
 
-    case ARG_LICENSE:
-      mh_license (argp_program_version);
-      break;
-
     default:
       return ARGP_ERR_UNKNOWN;
     }
@@ -348,7 +341,7 @@ main (int argc, char **argv)
 
   flags = mh_interactive_mode_p () ? 0 : ARGP_NO_ERRS;
   MU_APP_INIT_NLS ();
-  mh_argp_init (program_version);
+  mh_argp_init ();
   mh_argp_parse (&argc, &argv, flags, options, mh_option,
                 args_doc, doc, opt_handler, NULL, &index);
   if (pick_parse (lexlist))
diff --git a/mh/pick.y b/mh/pick.y
index 7b7af20..64248ec 100644
--- a/mh/pick.y
+++ b/mh/pick.y
@@ -324,15 +324,15 @@ match_message (mu_message_t msg, regex_t *regex)
   char buf[128];
   size_t n;
   
-  mu_message_get_stream (msg, &str);
-  mu_stream_seek (str, 0, SEEK_SET);
-  while (mu_stream_sequential_readline (str, buf, sizeof buf, &n) == 0
+  mu_message_get_streamref (msg, &str);
+  while (mu_stream_readline (str, buf, sizeof buf, &n) == 0
         && n > 0)
     {
       buf[n] = 0;
       if (regexec (regex, buf, 0, NULL, 0) == 0)
        return 1;
     }
+  mu_stream_destroy (&str);
   return 0;
 }
 
diff --git a/mh/refile.c b/mh/refile.c
index 5bf2faa..f244e70 100644
--- a/mh/refile.c
+++ b/mh/refile.c
@@ -26,7 +26,6 @@
 #include <errno.h>
 #include <fcntl.h>
 
-const char *program_version = "refile (" PACKAGE_STRING ")";
 static char doc[] = N_("GNU MH refile")"\v"
 N_("Options marked with `*' are not yet implemented.\n\
 Use -help to obtain the list of traditional MH options.");
@@ -47,8 +46,6 @@ static struct argp_option options[] = {
    N_("specify source folder; it will become the current folder after the 
program exits")},
   {"src", 0, NULL, OPTION_ALIAS, NULL},
   {"file", ARG_FILE, N_("FILE"), 0, N_("use FILE as the source message")},
-  {"license", ARG_LICENSE, 0,      0,
-   N_("display software license"), -1},
   { 0 }
 };
 
@@ -180,10 +177,6 @@ opt_handler (int key, char *arg, struct argp_state *state)
       source_file = arg;
       break;
       
-    case ARG_LICENSE:
-      mh_license (argp_program_version);
-      break;
-
     default:
       return ARGP_ERR_UNKNOWN;
     }
@@ -233,7 +226,7 @@ main (int argc, char **argv)
   /* Native Language Support */
   MU_APP_INIT_NLS ();
 
-  mh_argp_init (program_version);
+  mh_argp_init ();
   mh_argp_parse (&argc, &argv, 0, options, mh_option, args_doc, doc,
                 opt_handler, NULL, &index);
 
diff --git a/mh/repl.c b/mh/repl.c
index 73fba50..9f0f5e5 100644
--- a/mh/repl.c
+++ b/mh/repl.c
@@ -24,7 +24,6 @@
 #include <sys/stat.h>
 #include <unistd.h>
 
-const char *program_version = "reply (" PACKAGE_STRING ")";
 static char doc[] = N_("GNU MH repl")"\v"
 N_("Options marked with `*' are not yet implemented.\n\
 Use -help to obtain the list of traditional MH options.");
@@ -68,8 +67,6 @@ static struct argp_option options[] = {
   {"nowhatnowproc", ARG_NOWHATNOWPROC, NULL, 0,
    N_("* ignore whatnowproc variable; use standard `whatnow' shell instead")},
   {"use", ARG_USE, N_("BOOL"), OPTION_ARG_OPTIONAL, N_("use draft file 
preserved after the last session") },
-  {"license", ARG_LICENSE, 0,      0,
-   N_("display software license"), -1},
   { 0 }
 };
 
@@ -264,10 +261,6 @@ opt_handler (int key, char *arg, struct argp_state *state)
       mh_opt_notimpl ("-[no]whatnowproc");
       break;
 
-    case ARG_LICENSE:
-      mh_license (argp_program_version);
-      break;
-
     case ARGP_KEY_FINI:
       if (!format_str)
        format_str = default_format_str;
@@ -335,7 +328,7 @@ make_draft (mu_mailbox_t mbox, int disp, struct 
mh_whatnow_env *wh)
       char *buf;
       
       rc = mu_file_stream_create (&str, wh->file,
-                              MU_STREAM_WRITE|MU_STREAM_CREAT);
+                                 MU_STREAM_WRITE|MU_STREAM_CREAT);
       if (rc)
        {
          mu_error (_("cannot create draft file stream %s: %s"),
@@ -366,7 +359,7 @@ make_draft (mu_mailbox_t mbox, int disp, struct 
mh_whatnow_env *wh)
       else
        mh_format (&format, msg, msgset.list[0], width, &buf);
       
-      mu_stream_sequential_write (str, buf, strlen (buf));
+      mu_stream_write (str, buf, strlen (buf), NULL);
 
       if (mhl_filter)
        {
@@ -377,7 +370,7 @@ make_draft (mu_mailbox_t mbox, int disp, struct 
mh_whatnow_env *wh)
          mhl_format_destroy (&filter);
        }
 
-      mu_stream_destroy (&str, mu_stream_get_owner (str));
+      mu_stream_destroy (&str);
       free (buf);
     }
 
@@ -409,7 +402,7 @@ main (int argc, char **argv)
   /* Native Language Support */
   MU_APP_INIT_NLS ();
 
-  mh_argp_init (program_version);
+  mh_argp_init ();
 
   mh_argp_parse (&argc, &argv, 0, options, mh_option, args_doc, doc,
                 opt_handler, NULL, &index);
diff --git a/mh/rmf.c b/mh/rmf.c
index 3aa7c80..31fb44e 100644
--- a/mh/rmf.c
+++ b/mh/rmf.c
@@ -30,7 +30,6 @@
 
 #include <dirent.h>
 
-const char *program_version = "rmf (" PACKAGE_STRING ")";
 static char doc[] = N_("GNU MH rmf")"\v"
 N_("Use -help to obtain the list of traditional MH options.");
 static char args_doc[] = N_("[+folder]");
@@ -45,8 +44,6 @@ static struct argp_option options[] = {
   {"recursive", ARG_RECURSIVE, NULL, 0,
    N_("recursively delete all subfolders")},
   {"norecursive", ARG_NORECURSIVE, NULL, OPTION_HIDDEN, ""},
-  {"license", ARG_LICENSE, 0,      0,
-   N_("display software license"), -1},
   { 0 }
 };
 
@@ -90,10 +87,6 @@ opt_handler (int key, char *arg, struct argp_state *state)
       recurse = 0;
       break;
 
-    case ARG_LICENSE:
-      mh_license (argp_program_version);
-      break;
-
     default:
       return ARGP_ERR_UNKNOWN;
     }
@@ -195,7 +188,7 @@ main (int argc, char **argv)
   /* Native Language Support */
   MU_APP_INIT_NLS ();
 
-  mh_argp_init (program_version);
+  mh_argp_init ();
   mh_argp_parse (&argc, &argv, 0, options, mh_option, args_doc, doc,
                 opt_handler, NULL, NULL);
 
diff --git a/mh/rmm.c b/mh/rmm.c
index 68562d6..e82ac79 100644
--- a/mh/rmm.c
+++ b/mh/rmm.c
@@ -21,7 +21,6 @@
 
 #include <mh.h>
 
-const char *program_version = "rmm (" PACKAGE_STRING ")";
 static char doc[] = N_("GNU MH rmm")"\v"
 N_("Use -help to obtain the list of traditional MH options.");
 static char args_doc[] = N_("[+folder] [msgs]");
@@ -30,8 +29,6 @@ static char args_doc[] = N_("[+folder] [msgs]");
 static struct argp_option options[] = {
   {"folder",  ARG_FOLDER, N_("FOLDER"), 0,
    N_("specify folder to operate upon")},
-  {"license", ARG_LICENSE, 0,      0,
-   N_("display software license"), -1},
   { 0 }
 };
 
@@ -49,10 +46,6 @@ opt_handler (int key, char *arg, struct argp_state *state)
       mh_set_current_folder (arg);
       break;
       
-    case ARG_LICENSE:
-      mh_license (argp_program_version);
-      break;
-
     default:
       return ARGP_ERR_UNKNOWN;
     }
@@ -78,7 +71,7 @@ main (int argc, char **argv)
   /* Native Language Support */
   MU_APP_INIT_NLS ();
 
-  mh_argp_init (program_version);
+  mh_argp_init ();
   mh_argp_parse (&argc, &argv, 0, options, mh_option, args_doc, doc,
                 opt_handler, NULL, &index);
 
diff --git a/mh/scan.c b/mh/scan.c
index 36081a8..308d772 100644
--- a/mh/scan.c
+++ b/mh/scan.c
@@ -28,7 +28,6 @@
 #include <time.h>
 #include <mailutils/observer.h>
 
-const char *program_version = "scan (" PACKAGE_STRING ")";
 static char doc[] = N_("GNU MH scan")"\v"
 N_("Use -help to obtain the list of traditional MH options.");
 static char args_doc[] = N_("[+folder] [msgs]");
@@ -54,9 +53,6 @@ static struct argp_option options[] = {
   {"file",    ARG_FILE, N_("FILE"),   0,
    N_("[not yet implemented]")},
   
-  {"license", ARG_LICENSE, 0,        0,
-   N_("display software license"), -1},
-
   { 0 }
 };
 
@@ -137,10 +133,6 @@ opt_handler (int key, char *arg, struct argp_state *state)
       mh_opt_notimpl ("-file");
       break;
       
-    case ARG_LICENSE:
-      mh_license (argp_program_version);
-      break;
-      
     default:
       return ARGP_ERR_UNKNOWN;
     }
@@ -178,7 +170,7 @@ main (int argc, char **argv)
   /* Native Language Support */
   MU_APP_INIT_NLS ();
 
-  mh_argp_init (program_version);
+  mh_argp_init ();
   mh_argp_parse (&argc, &argv, 0, options, mh_option, args_doc, doc,
                 opt_handler, NULL, &index);
 
diff --git a/mh/send.c b/mh/send.c
index 3f92c9d..6ba5c46 100644
--- a/mh/send.c
+++ b/mh/send.c
@@ -25,7 +25,6 @@
 #include <stdarg.h>
 #include <pwd.h>
 
-const char *program_version = "send (" PACKAGE_STRING ")";
 static char doc[] = N_("GNU MH send")"\v"
 N_("Options marked with `*' are not yet implemented.\n\
 Use -help to obtain the list of traditional MH options.");
@@ -77,8 +76,6 @@ static struct argp_option options[] = {
   {"nowatch",       ARG_NOWATCH,       NULL, OPTION_HIDDEN, "" },
   {"width",         ARG_WIDTH,         N_("NUMBER"), 0,
    N_("* make header fields no longer than NUMBER columns") },
-  {"license", ARG_LICENSE, 0,      0,
-   N_("display software license"), -1},
   { 0 }
 };
 
@@ -263,10 +260,6 @@ opt_handler (int key, char *arg, struct argp_state *state)
        }
       break;
       
-    case ARG_LICENSE:
-      mh_license (argp_program_version);
-      break;
-
     default:
       return ARGP_ERR_UNKNOWN;
     }
@@ -758,7 +751,7 @@ main (int argc, char **argv)
   
   MU_APP_INIT_NLS ();
   
-  mh_argp_init (program_version);
+  mh_argp_init ();
   mh_argp_parse (&argc, &argv, 0, options, mh_option, args_doc, doc,
                 opt_handler, NULL, &index);
 
diff --git a/mh/sortm.c b/mh/sortm.c
index 68b95c3..cdea0bd 100644
--- a/mh/sortm.c
+++ b/mh/sortm.c
@@ -24,7 +24,6 @@
 #include <unistd.h>
 #include <signal.h>
 
-const char *program_version = "sortm (" PACKAGE_STRING ")";
 static char doc[] = N_("GNU MH sortm")"\v"
 N_("Use -help to obtain the list of traditional MH options.");
 static char args_doc[] = N_("[msgs]");
@@ -76,9 +75,6 @@ static struct argp_option options[] = {
   {"quicksort", ARG_QUICKSORT,  0, 0,
    N_("use quicksort algorithm (default)"), 40 },
 
-  {"license", ARG_LICENSE, 0,      0,
-   N_("display software license"), -1},
-
   { NULL },
 };
 
@@ -191,10 +187,6 @@ opt_handler (int key, char *arg, struct argp_state *state)
       algorithm = key;
       break;
       
-    case ARG_LICENSE:
-      mh_license (argp_program_version);
-      break;
-
     default:
       return ARGP_ERR_UNKNOWN;
     }
@@ -558,7 +550,7 @@ main (int argc, char **argv)
   mu_url_t url;
   
   MU_APP_INIT_NLS ();
-  mh_argp_init (program_version);
+  mh_argp_init ();
   mh_argp_parse (&argc, &argv, 0, options, mh_option,
                 args_doc, doc, opt_handler, NULL, &index);
   if (!oplist)
diff --git a/mh/whatnow.c b/mh/whatnow.c
index 7b3e666..3075d5a 100644
--- a/mh/whatnow.c
+++ b/mh/whatnow.c
@@ -20,7 +20,6 @@
 
 #include <mh.h>
 
-const char *program_version = "whatnow (" PACKAGE_STRING ")";
 static char doc[] = "GNU MH whatnow";
 static char args_doc[] = N_("[FILE]");
 
@@ -36,9 +35,6 @@ static struct argp_option options[] = {
   {"noedit", ARG_NOEDIT, 0, 0, N_("suppress the initial edit")},
   {"prompt", ARG_PROMPT, N_("STRING"), 0, N_("set the prompt")},
 
-  {"license", ARG_LICENSE, 0,      0,
-   N_("display software license"), -1},
-
   { NULL }
 };
 
@@ -91,10 +87,6 @@ opt_handler (int key, char *arg, struct argp_state *state)
       wh_env.prompt = arg;
       break;
       
-    case ARG_LICENSE:
-      mh_license (argp_program_version);
-      break;
-
     default:
       return ARGP_ERR_UNKNOWN;
     }
@@ -108,7 +100,7 @@ main (int argc, char **argv)
   
   MU_APP_INIT_NLS ();
 
-  mh_argp_init (program_version);
+  mh_argp_init ();
   mh_argp_parse (&argc, &argv, 0, options, mh_option, args_doc, doc,
                 opt_handler, NULL, &index);
   argc -= index;
diff --git a/mh/whom.c b/mh/whom.c
index 893fe8e..9db8446 100644
--- a/mh/whom.c
+++ b/mh/whom.c
@@ -19,7 +19,6 @@
 
 #include <mh.h>
 
-const char *program_version = "whom (" PACKAGE_STRING ")";
 static char doc[] = N_("GNU MH whom")"\v"
 N_("Use -help to obtain the list of traditional MH options.");
 static char args_doc[] = "[file]";
@@ -40,9 +39,6 @@ static struct argp_option options[] = {
    N_("check if addresses are deliverable") },
   {"nocheck",       ARG_NOCHECK,       NULL, OPTION_HIDDEN, "" },
 
-  {"license",       ARG_LICENSE,       0,    0,
-   N_("display software license"), -1},
-
   {NULL}
 };
 
@@ -96,10 +92,6 @@ opt_handler (int key, char *arg, struct argp_state *state)
       check_recipients = 0;
       break;
 
-    case ARG_LICENSE:
-      mh_license (argp_program_version);
-      break;
-
     default:
       return ARGP_ERR_UNKNOWN;
     }
@@ -114,7 +106,7 @@ main (int argc, char **argv)
   
   MU_APP_INIT_NLS ();
   
-  mh_argp_init (program_version);
+  mh_argp_init ();
   mh_argp_parse (&argc, &argv, 0, options, mh_option, args_doc, doc,
                 opt_handler, NULL, &index);
 
diff --git a/mimeview/mimeview.c b/mimeview/mimeview.c
index 45945e4..ed90703 100644
--- a/mimeview/mimeview.c
+++ b/mimeview/mimeview.c
@@ -25,13 +25,14 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/wait.h>
+#include <unistd.h>
+#include <fcntl.h>
 
 #include "mailutils/libargp.h"
 #include "mailutils/argcv.h"
 
 #include "mailcap.h"
 
-const char *program_version = "mimeview (" PACKAGE_STRING ")";
 static char doc[] = N_("GNU mimeview -- display files, using mailcap 
mechanism.")
 "\v"     
 N_("Default mime.types file is ") DEFAULT_CUPS_CONFDIR "/mime.types"
@@ -251,13 +252,14 @@ display_file (const char *type)
       char *text;
 
       asprintf (&text, "Content-Type: %s\n", type);
-      status = mu_header_create (&hdr, text, strlen (text), NULL);
+      status = mu_header_create (&hdr, text, strlen (text));
       if (status)
        mu_error (_("cannot create header: %s"), mu_strerror (status));
       else
        {
-         mu_stdio_stream_create (&stream, mimeview_fp,
-                              
MU_STREAM_READ|MU_STREAM_SEEKABLE|MU_STREAM_NO_CLOSE);
+         mu_stdio_stream_create (&stream, fileno (mimeview_fp),
+                                 MU_STREAM_READ|
+                                 MU_STREAM_SEEK);
          mu_stream_open (stream);
          
          display_stream_mailcap (mimeview_file, stream, hdr,
@@ -265,9 +267,9 @@ display_file (const char *type)
                                  debug_level);
          
          mu_stream_close (stream);
-         mu_stream_destroy (&stream, mu_stream_get_owner (stream));
+         mu_stream_destroy (&stream);
 
-         mu_header_destroy (&hdr, mu_header_get_owner (hdr));
+         mu_header_destroy (&hdr);
        }
     }
 }
@@ -278,7 +280,7 @@ main (int argc, char **argv)
   int index;
   
   MU_APP_INIT_NLS ();
-  mu_argp_init (program_version, NULL);
+  mu_argp_init (NULL, NULL);
   if (mu_app_init (&argp, capa, mimeview_cfg_param, 
                   argc, argv, 0, &index, NULL))
     exit (1);
diff --git a/movemail/movemail.c b/movemail/movemail.c
index 3c91093..9bc8d18 100644
--- a/movemail/movemail.c
+++ b/movemail/movemail.c
@@ -33,7 +33,6 @@
 #include "mailutils/libargp.h"
 #include <muaux.h>
 
-const char *program_version = "movemail (" PACKAGE_STRING ")";
 static char doc[] = N_("GNU movemail -- move messages across mailboxes.");
 static char args_doc[] = N_("inbox-url destfile [POP-password]");
 
@@ -744,7 +743,7 @@ main (int argc, char **argv)
 #ifdef WITH_TLS
   mu_gocs_register ("tls", mu_tls_module_init);
 #endif
-  mu_argp_init (program_version, NULL);
+  mu_argp_init (NULL, NULL);
   if (mu_app_init (&argp, movemail_capa, movemail_cfg_param, 
                   argc, argv, 0, &index, NULL))
     exit (1);
diff --git a/mu-aux/generr.awk b/mu-aux/generr.awk
index 5a4054b..a40690c 100644
--- a/mu-aux/generr.awk
+++ b/mu-aux/generr.awk
@@ -67,6 +67,7 @@ ARGIND == 2 && $1 == "$MESSAGE_DEFS" {
   for (i = 0; i < defno; i++) {
     print "#define " def[i] " (MU_ERR_BASE+" i ")"
   }
+  print "#define MU_ERR_LAST (MU_ERR_BASE+" defno ")"
   total += defno;
   next
 }
diff --git a/pop3d/apop.c b/pop3d/apop.c
index 632bffb..dca748e 100644
--- a/pop3d/apop.c
+++ b/pop3d/apop.c
@@ -41,11 +41,11 @@
 char *
 pop3d_apopuser (const char *user)
 {
-  char *password;
-  char buf[POP_MAXCMDLEN];
-
+  char *password = NULL;
+  
 #ifdef USE_DBM
   {
+    size_t len;
     DBM_FILE db;
     DBM_DATUM key, data;
 
@@ -60,11 +60,8 @@ pop3d_apopuser (const char *user)
     memset (&key, 0, sizeof key);
     memset (&data, 0, sizeof data);
 
-    strncpy (buf, user, sizeof buf);
-    /* strncpy () is lame and does not NULL terminate.  */
-    buf[sizeof (buf) - 1] = '\0';
-    MU_DATUM_PTR(key) = buf;
-    MU_DATUM_SIZE(key) = strlen (buf);
+    MU_DATUM_PTR (key) = (void*) user;
+    MU_DATUM_SIZE (key) = strlen (user);
 
     rc = mu_dbm_fetch (db, key, &data);
     mu_dbm_close (db);
@@ -74,21 +71,23 @@ pop3d_apopuser (const char *user)
                        _("cannot fetch APOP data: %s"), mu_strerror (errno));
        return NULL;
       }
-    password = calloc (MU_DATUM_SIZE(data) + 1, sizeof (*password));
+    len = MU_DATUM_SIZE (data);
+    password = malloc (len + 1);
     if (password == NULL)
       {
        mu_dbm_datum_free (&data);
        return NULL;
       }
-    
-    sprintf (password, "%.*s", (int) MU_DATUM_SIZE(data),
-            (char*) MU_DATUM_PTR(data));
+    memcpy (password, MU_DATUM_PTR (data), len);
+    password[len] = 0;
     mu_dbm_datum_free (&data);
     return password;
   }
 #else /* !USE_DBM */
   {
-    char *tmp;
+    char *buf = NULL;
+    size_t size = 0;
+    size_t ulen;
     FILE *apop_file;
 
     if (mu_check_perm (APOP_PASSFILE, 0600))
@@ -101,44 +100,32 @@ pop3d_apopuser (const char *user)
     apop_file = fopen (APOP_PASSFILE, "r");
     if (apop_file == NULL)
       {
-       mu_diag_output (MU_DIAG_INFO, _("unable to open APOP password file %s"),
-               strerror (errno));
+       mu_diag_output (MU_DIAG_INFO,
+                       _("unable to open APOP password file %s: %s"),
+                       APOP_PASSFILE, mu_strerror (errno));
        return NULL;
       }
 
-    password = calloc (APOP_DIGEST, sizeof (*password));
-    if (password == NULL)
+    ulen = strlen (user);
+    while (getline (&buf, &size, apop_file) > 0)
       {
-       fclose (apop_file);
-       pop3d_abquit (ERR_NO_MEM);
-      }
+       char *p, *start = mu_str_stripws (buf);
 
-    while (fgets (buf, sizeof (buf) - 1, apop_file) != NULL)
-      {
-       tmp = strchr (buf, ':');
-       if (tmp == NULL)
+       if (!*start || *start == '#')
          continue;
-       *tmp++ = '\0';
-
-       if (strncmp (user, buf, strlen (user)))
+       p = strchr (start, ':');
+       if (!p)
          continue;
-
-       strncpy (password, tmp, APOP_DIGEST);
-       /* strncpy () is lame and does not NULL terminate.  */
-       password[APOP_DIGEST - 1] = '\0';
-       tmp = strchr (password, '\n');
-       if (tmp)
-         *tmp = '\0';
-       break;
+       if (p - start == ulen && memcmp (user, start, ulen) == 0)
+         {
+           p = mu_str_skip_class (p + 1, MU_CTYPE_SPACE);
+           if (*p)
+             password = strdup (p);
+           break;
+         }
       }
 
     fclose (apop_file);
-    if (*password == '\0')
-      {
-       free (password);
-       return NULL;
-      }
-
     return password;
   }
 #endif
@@ -147,11 +134,12 @@ pop3d_apopuser (const char *user)
 int
 pop3d_apop (char *arg)
 {
-  char *tmp, *password, *user_digest, *user;
-  char buf[POP_MAXCMDLEN];
+  char *p, *password, *user_digest, *user;
   struct mu_md5_ctx md5context;
   unsigned char md5digest[16];
-
+  char buf[2 * 16 + 1];
+  size_t i;
+  
   if (state != AUTHORIZATION)
     return ERR_WRONG_STATE;
 
@@ -159,11 +147,6 @@ pop3d_apop (char *arg)
     return ERR_BAD_ARGS;
 
   pop3d_parse_command (arg, &user, &user_digest);
-  if (strlen (user) > (POP_MAXCMDLEN - APOP_DIGEST))
-    {
-      mu_diag_output (MU_DIAG_INFO, _("user name too long: %s"), user);
-      return ERR_BAD_ARGS;
-    }
 
   password = pop3d_apopuser (user);
   if (password == NULL)
@@ -180,14 +163,9 @@ pop3d_apop (char *arg)
   free (password);
   mu_md5_finish_ctx (&md5context, md5digest);
 
-  {
-    int i;
-    tmp = buf;
-    for (i = 0; i < 16; i++, tmp += 2)
-      sprintf (tmp, "%02x", md5digest[i]);
-  }
-
-  *tmp++ = '\0';
+  for (i = 0, p = buf; i < 16; i++, p += 2)
+      sprintf (p, "%02x", md5digest[i]);
+  *p = 0;
 
   if (strcmp (user_digest, buf))
     {
diff --git a/pop3d/capa.c b/pop3d/capa.c
index 688b09d..38d5fed 100644
--- a/pop3d/capa.c
+++ b/pop3d/capa.c
@@ -32,33 +32,30 @@ pop3d_capa (char *arg)
   if (strlen (arg) != 0)
     return ERR_BAD_ARGS;
 
-  if (state != initial_state && state != TRANSACTION)
-    return ERR_WRONG_STATE;
-
-  pop3d_outf ("+OK Capability list follows\r\n");
-  pop3d_outf ("TOP\r\n");
-  pop3d_outf ("USER\r\n");
-  pop3d_outf ("UIDL\r\n");
-  pop3d_outf ("RESP-CODES\r\n");
-  pop3d_outf ("PIPELINING\r\n");
+  pop3d_outf ("+OK Capability list follows\n");
+  pop3d_outf ("TOP\n");
+  pop3d_outf ("USER\n");
+  pop3d_outf ("UIDL\n");
+  pop3d_outf ("RESP-CODES\n");
+  pop3d_outf ("PIPELINING\n");
 
 #ifdef WITH_TLS
   if (tls_available && tls_done == 0)
-    pop3d_outf ("STLS\r\n");
+    pop3d_outf ("STLS\n");
 #endif /* WITH_TLS */
 
   login_delay_capa ();
   /* This can be implemented by setting an header field on the message.  */
   if (expire == EXPIRE_NEVER)
-    pop3d_outf ("EXPIRE NEVER\r\n");
+    pop3d_outf ("EXPIRE NEVER\n");
   else 
-    pop3d_outf ("EXPIRE %s\r\n", mu_umaxtostr (0, expire));
+    pop3d_outf ("EXPIRE %s\n", mu_umaxtostr (0, expire));
 
   if (state == INITIAL)
-    pop3d_outf ("XTLSREQUIRED\r\n");
+    pop3d_outf ("XTLSREQUIRED\n");
   
   if (state == TRANSACTION)    /* let's not advertise to just anyone */
-    pop3d_outf ("IMPLEMENTATION %s\r\n", PACKAGE_STRING);
-  pop3d_outf (".\r\n");
+    pop3d_outf ("IMPLEMENTATION %s\n", PACKAGE_STRING);
+  pop3d_outf (".\n");
   return OK;
 }
diff --git a/pop3d/dele.c b/pop3d/dele.c
index f838f59..08e3ac1 100644
--- a/pop3d/dele.c
+++ b/pop3d/dele.c
@@ -39,6 +39,6 @@ pop3d_dele (char *arg)
 
   mu_message_get_attribute (msg, &attr);
   pop3d_mark_deleted (attr);
-  pop3d_outf ("+OK Message %s marked\r\n", mu_umaxtostr (0, num));
+  pop3d_outf ("+OK Message %s marked\n", mu_umaxtostr (0, num));
   return OK;
 }
diff --git a/pop3d/extra.c b/pop3d/extra.c
index 60b009c..380435d 100644
--- a/pop3d/extra.c
+++ b/pop3d/extra.c
@@ -20,7 +20,7 @@
 #include "pop3d.h"
 #include "mailutils/libargp.h"
 
-static mu_stream_t istream, ostream;
+mu_stream_t iostream;
 
 void
 pop3d_parse_command (char *cmd, char **pcmd, char **parg)
@@ -61,7 +61,7 @@ pop3d_abquit (int reason)
     {
     case ERR_NO_MEM:
       code = EX_SOFTWARE;
-      pop3d_outf ("-ERR %s\r\n", pop3d_error_string (reason));
+      pop3d_outf ("-ERR %s\n", pop3d_error_string (reason));
       mu_diag_output (MU_DIAG_ERROR, _("not enough memory"));
       break;
 
@@ -77,7 +77,7 @@ pop3d_abquit (int reason)
 
     case ERR_TIMEOUT:
       code = EX_TEMPFAIL;
-      pop3d_outf ("-ERR %s\r\n", pop3d_error_string (reason));
+      pop3d_outf ("-ERR %s\n", pop3d_error_string (reason));
       if (state == TRANSACTION)
        mu_diag_output (MU_DIAG_INFO, _("session timed out for user: %s"),
                        username);
@@ -111,12 +111,12 @@ pop3d_abquit (int reason)
                      _("mailbox was updated by other party: %s"),
                      username);
       pop3d_outf
-       ("-ERR [OUT-SYNC] Mailbox updated by other party or corrupt\r\n");
+       ("-ERR [OUT-SYNC] Mailbox updated by other party or corrupt\n");
       break;
 
     default:
       code = EX_SOFTWARE;
-      pop3d_outf ("-ERR Quitting: %s\r\n", pop3d_error_string (reason));
+      pop3d_outf ("-ERR Quitting: %s\n", pop3d_error_string (reason));
       mu_diag_output (MU_DIAG_ERROR, _("quitting (numeric reason %d)"),
                      reason);
       break;
@@ -129,52 +129,109 @@ pop3d_abquit (int reason)
 void
 pop3d_setio (FILE *in, FILE *out)
 {
+  mu_stream_t str, istream, ostream;
+  
   if (!in)
     pop3d_abquit (ERR_NO_IFILE);
   if (!out)
     pop3d_abquit (ERR_NO_OFILE);
 
-  setvbuf (in, NULL, _IOLBF, 0);
-  setvbuf (out, NULL, _IOLBF, 0);
-  if (mu_stdio_stream_create (&istream, in, MU_STREAM_NO_CLOSE))
+  if (mu_stdio_stream_create (&istream, fileno (in), 
+                              MU_STREAM_READ | MU_STREAM_AUTOCLOSE))
     pop3d_abquit (ERR_NO_IFILE);
-  if (mu_stdio_stream_create (&ostream, out, MU_STREAM_NO_CLOSE))
+  mu_stream_set_buffer (istream, mu_buffer_line, 1024);
+  
+  if (mu_stdio_stream_create (&ostream, fileno (out), 
+                              MU_STREAM_WRITE | MU_STREAM_AUTOCLOSE))
     pop3d_abquit (ERR_NO_OFILE);
+
+  /* Combine the two streams into an I/O one. */
+  if (mu_iostream_create (&str, istream, ostream))
+    pop3d_abquit (ERR_FILE);
+
+  /* Convert all writes to CRLF form.
+     There is no need to convert reads, as the code ignores extra \r anyway.
+  */
+  if (mu_filter_create (&iostream, str, "CRLF", MU_FILTER_ENCODE,
+                       MU_STREAM_WRITE | MU_STREAM_RDTHRU))
+    pop3d_abquit (ERR_NO_IFILE);
+  /* Change buffering scheme: filter streams are fully buffered by default. */
+  mu_stream_set_buffer (iostream, mu_buffer_line, 1024);
+  
+  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, 0);
+      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
+           {
+             mu_stream_unref (iostream);
+             iostream = xstr;
+           }
+       }
+    }
 }
 
 #ifdef WITH_TLS
 int
 pop3d_init_tls_server ()
 {
-  mu_stream_t stream;
+  mu_stream_t tlsstream, stream[2];
   int rc;
- 
-  rc = mu_tls_stream_create (&stream, istream, ostream, 0);
-  if (rc)
-    return 0;
 
-  if (mu_stream_open (stream))
+  stream[0] = stream[1] = NULL;
+  rc = mu_stream_ioctl (iostream, MU_IOCTL_SWAP_STREAM, stream);
+  if (rc)
     {
-      const char *p;
-      mu_stream_strerror (stream, &p);
-      mu_diag_output (MU_DIAG_ERROR, _("cannot open TLS stream: %s"), p);
-      return 0;
+      mu_error (_("%s failed: %s"), "MU_IOCTL_SWAP_STREAM",
+               mu_stream_strerror (iostream, rc));
+      return 1;
     }
   
-  istream = ostream = stream;
-  return 1;
+  rc = mu_tls_server_stream_create (&tlsstream, stream[0], stream[1], 0);
+  if (rc)
+    return 1;
+
+  rc = mu_stream_open (tlsstream);
+  if (rc)
+    {
+      mu_diag_output (MU_DIAG_ERROR, _("cannot open TLS stream: %s"),
+                     mu_stream_strerror (tlsstream, rc));
+      mu_stream_destroy (&tlsstream);
+      return 1;
+    }
+  else
+    stream[0] = stream[1] = tlsstream;
+
+  rc = mu_stream_ioctl (iostream, MU_IOCTL_SWAP_STREAM, stream);
+  if (rc)
+    {
+      mu_error (_("%s failed: %s"), "MU_IOCTL_SWAP_STREAM",
+               mu_stream_strerror (iostream, rc));
+      pop3d_abquit (ERR_IO);
+    }
+  return 0;
 }
 #endif
 
 void
 pop3d_bye ()
 {
-  if (istream == ostream)
-    {
-      mu_stream_close (istream);
-      mu_stream_destroy (&istream, mu_stream_get_owner (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 ();
@@ -184,56 +241,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_sequential_write (ostream, buf, strlen (buf));
-  free (buf);
   if (rc)
     {
-      const char *p;
-
-      if (mu_stream_strerror (ostream, &p))
-       p = strerror (errno);
-      mu_diag_output (MU_DIAG_ERROR, _("write failed: %s"), p);
+      mu_diag_output (MU_DIAG_ERROR, _("Write failed: %s"),
+                     mu_stream_strerror (iostream, rc));
       pop3d_abquit (ERR_IO);
     }
 }
@@ -246,16 +275,13 @@ pop3d_readline (char *buffer, size_t size)
   size_t nbytes;
   
   alarm (idle_timeout);
-  rc = mu_stream_sequential_readline (istream, buffer, size, &nbytes);
+  rc = mu_stream_readline (iostream, buffer, size, &nbytes);
   alarm (0);
 
   if (rc)
     {
-      const char *p;
-
-      if (mu_stream_strerror (ostream, &p))
-       p = strerror (errno);
-      mu_diag_output (MU_DIAG_ERROR, _("read failed: %s"), p);
+      mu_diag_output (MU_DIAG_ERROR, _("Read failed: %s"),
+                     mu_stream_strerror (iostream, rc));
       pop3d_abquit (ERR_IO);
     }
   else if (nbytes == 0)
@@ -269,8 +295,6 @@ pop3d_readline (char *buffer, size_t size)
       pop3d_abquit (ERR_PROTO);
     }
 
-  transcript ("recv", buffer);
-
   return buffer;
 }
 
@@ -314,3 +338,23 @@ pop3d_undelete_all ()
        mu_attribute_unset_deleted (attr);
     }
 }
+
+int
+set_xscript_level (int xlev)
+{
+  if (pop3d_transcript)
+    {
+      if (xlev != MU_XSCRIPT_NORMAL)
+       {
+         mu_log_level_t n = xlev == MU_XSCRIPT_SECURE ?
+                             MU_DEBUG_TRACE6 : MU_DEBUG_TRACE7;
+         
+         if (mu_global_debug_level ("pop3") & MU_DEBUG_LEVEL_MASK (n))
+           return MU_XSCRIPT_NORMAL;
+       }
+
+      if (mu_stream_ioctl (iostream, MU_IOCTL_LEVEL, &xlev) == 0)
+       return xlev;
+    }
+  return 0;
+}
diff --git a/pop3d/list.c b/pop3d/list.c
index b192875..a212e41 100644
--- a/pop3d/list.c
+++ b/pop3d/list.c
@@ -37,7 +37,7 @@ pop3d_list (char *arg)
   if (strlen (arg) == 0)
     {
       size_t total = 0;
-      pop3d_outf ("+OK\r\n");
+      pop3d_outf ("+OK\n");
       mu_mailbox_messages_count (mbox, &total);
       for (mesgno = 1; mesgno <= total; mesgno++)
        {
@@ -47,12 +47,12 @@ pop3d_list (char *arg)
            {
              mu_message_size (msg, &size);
              mu_message_lines (msg, &lines);
-             pop3d_outf ("%s %s\r\n", 
+             pop3d_outf ("%s %s\n", 
                           mu_umaxtostr (0, mesgno), 
                           mu_umaxtostr (1, size + lines));
            }
        }
-      pop3d_outf (".\r\n");
+      pop3d_outf (".\n");
     }
   else
     {
@@ -64,7 +64,7 @@ pop3d_list (char *arg)
        return ERR_MESG_DELE;
       mu_message_size (msg, &size);
       mu_message_lines (msg, &lines);
-      pop3d_outf ("+OK %s %s\r\n", 
+      pop3d_outf ("+OK %s %s\n", 
                   mu_umaxtostr (0, mesgno),
                   mu_umaxtostr (1, size + lines));
     }
diff --git a/pop3d/logindelay.c b/pop3d/logindelay.c
index 9c8020d..5cab22c 100644
--- a/pop3d/logindelay.c
+++ b/pop3d/logindelay.c
@@ -126,7 +126,7 @@ login_delay_capa ()
   
   if (login_delay && open_stat_db (&db, MU_STREAM_RDWR) == 0)
     {
-      pop3d_outf ("LOGIN-DELAY %s\r\n", mu_umaxtostr (0, login_delay));
+      pop3d_outf ("LOGIN-DELAY %s\n", mu_umaxtostr (0, login_delay));
       mu_dbm_close (db);
     }
 }
diff --git a/pop3d/noop.c b/pop3d/noop.c
index a3d8e64..55ecf18 100644
--- a/pop3d/noop.c
+++ b/pop3d/noop.c
@@ -26,6 +26,6 @@ pop3d_noop (char *arg)
     return ERR_BAD_ARGS;
   if (state != TRANSACTION)
     return ERR_WRONG_STATE;
-  pop3d_outf ("+OK\r\n");
+  pop3d_outf ("+OK\n");
   return OK;
 }
diff --git a/pop3d/pop3d.c b/pop3d/pop3d.c
index d0e7b60..6b70f55 100644
--- a/pop3d/pop3d.c
+++ b/pop3d/pop3d.c
@@ -248,7 +248,7 @@ pop3d_mainloop (int fd, FILE *infile, FILE *outfile)
   }
 
   /* Lets boogie.  */
-  pop3d_outf ("+OK POP3 Ready %s\r\n", md5shared);
+  pop3d_outf ("+OK POP3 Ready %s\n", md5shared);
 
   while (state != UPDATE && state != ABORT)
     {
@@ -261,11 +261,6 @@ pop3d_mainloop (int fd, FILE *infile, FILE *outfile)
       buf = pop3d_readline (buffer, sizeof (buffer));
       pop3d_parse_command (buf, &cmd, &arg);
 
-      /* The mailbox size needs to be check to make sure that we are in
-        sync.  Some other applications may not respect the *.lock or
-        the lock may be stale because downloading on slow modem.
-        We rely on the size of the mailbox for the check and bail if out
-        of sync.  */
       if (state == TRANSACTION && !mu_mailbox_is_updated (mbox))
        {
          static mu_off_t mailbox_size;
@@ -281,17 +276,13 @@ pop3d_mainloop (int fd, FILE *infile, FILE *outfile)
       /* Refresh the Lock.  */
       pop3d_touchlock ();
 
-      if (strlen (arg) > POP_MAXCMDLEN || strlen (cmd) > POP_MAXCMDLEN)
-       status = ERR_TOO_LONG;
-      else if (strlen (cmd) > 4)
-       status = ERR_BAD_CMD;
-      else if ((handler = pop3d_find_command (cmd)) != NULL)
+      if ((handler = pop3d_find_command (cmd)) != NULL)
        status = handler (arg);
       else
        status = ERR_BAD_CMD;
 
       if (status != OK)
-       pop3d_outf ("-ERR %s\r\n", pop3d_error_string (status));
+       pop3d_outf ("-ERR %s\n", pop3d_error_string (status));
     }
 
   pop3d_bye ();
@@ -338,7 +329,7 @@ main (int argc, char **argv)
   mu_acl_cfg_init ();
   mu_m_server_cfg_init ();
   
-  mu_argp_init (program_version, NULL);
+  mu_argp_init (NULL, NULL);
        
   mu_m_server_create (&server, program_version);
   mu_m_server_set_conn (server, pop3d_connection);
diff --git a/pop3d/pop3d.h b/pop3d/pop3d.h
index 1c1c7d6..d831a3e 100644
--- a/pop3d/pop3d.h
+++ b/pop3d/pop3d.h
@@ -23,6 +23,8 @@
 #ifdef HAVE_CONFIG_H
 # include <config.h>
 #endif
+#include <mailutils/types.h>
+#include <mailutils/stream.h>
 #include <mu_dbm.h>
 #include <mu_asprintf.h>
 #include <mu_umaxtostr.h>
@@ -65,16 +67,9 @@ extern int expire_on_exit;
 /* Size of the MD5 digest for APOP */
 #define APOP_DIGEST    70
 
-/* Longest legal POP command */
-#define POP_MAXCMDLEN  255
-
-/* Buffer size to use for output */
-#define BUFFERSIZE     1024
-
 #ifndef _GNU_SOURCE
 # define _GNU_SOURCE
 #endif
-#define _QNX_SOURCE
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -123,6 +118,7 @@ extern int expire_on_exit;
 #include <mailutils/md5.h>
 #include <mailutils/acl.h>
 #include <mailutils/server.h>
+#include <mailutils/filter.h>
 
 /* For Berkley DB2 APOP password file */
 #ifdef HAVE_DB_H
@@ -186,6 +182,7 @@ struct pop3d_command
   pop3d_command_handler_t handler;
 };
 
+extern mu_stream_t iostream;
 extern mu_pop_server_t pop3srv;
 extern mu_mailbox_t mbox;
 extern int state;
@@ -268,4 +265,6 @@ extern int set_bulletin_source (const char *source);
 extern int pop3d_begin_session (void);
 extern const char *pop3d_error_string (int code);
 
+extern int set_xscript_level (int xlev);
+
 #endif /* _POP3D_H */
diff --git a/pop3d/popauth.c b/pop3d/popauth.c
index bc8c443..9f73d60 100644
--- a/pop3d/popauth.c
+++ b/pop3d/popauth.c
@@ -56,14 +56,11 @@ int (*ftab[]) (struct action_data *) = {
   action_chpass
 };
 
-const char *program_version = "popauth (" PACKAGE_STRING ")";
 static char doc[] = N_("GNU popauth -- manage pop3 authentication database");
 static error_t popauth_parse_opt  (int key, char *arg,
                                   struct argp_state *astate);
 
 void popauth_version (FILE *stream, struct argp_state *state);
-void (*argp_program_version_hook) (FILE *stream, struct argp_state *state) =
-                                   popauth_version;
 
 static struct argp_option options[] = 
 {
@@ -202,7 +199,8 @@ main(int argc, char **argv)
   /* Native Language Support */
   MU_APP_INIT_NLS ();
 
-  mu_argp_init (program_version, NULL);
+  mu_argp_init (NULL, NULL);
+  argp_program_version_hook = popauth_version;
   if (mu_app_init (&argp, popauth_argp_capa, NULL,
                   argc, argv, 0, NULL, &adata))
     exit (EX_USAGE);
@@ -600,7 +598,7 @@ popauth_version (FILE *stream, struct argp_state *state)
 #elif defined(WITH_TOKYOCABINET)
 # define FORMAT "Tokyo Cabinet"
 #endif
-  printf ("%s\n", argp_program_version);
+  mu_program_version_hook (stream, state);
   printf (_("Database format: %s\n"), FORMAT);
   printf (_("Database location: %s\n"), APOP_PASSFILE);
   exit (EX_OK);
diff --git a/pop3d/quit.c b/pop3d/quit.c
index 94857cb..0b0ca15 100644
--- a/pop3d/quit.c
+++ b/pop3d/quit.c
@@ -53,7 +53,7 @@ pop3d_quit (char *arg)
   free (md5shared);
 
   if (err == OK)
-    pop3d_outf ("+OK\r\n");
+    pop3d_outf ("+OK\n");
   return err;
 }
 
diff --git a/pop3d/retr.c b/pop3d/retr.c
index 9f4a222..0ffcd24 100644
--- a/pop3d/retr.c
+++ b/pop3d/retr.c
@@ -22,13 +22,11 @@
 int
 pop3d_retr (char *arg)
 {
-  size_t mesgno, n;
-  char buf[BUFFERSIZE];
+  size_t mesgno;
   mu_message_t msg = NULL;
   mu_attribute_t attr = NULL;
-  mu_stream_t stream = NULL;
-  mu_off_t off;
-  int prev_nl;
+  mu_stream_t stream;
+  int xscript_level;
   
   if ((strlen (arg) == 0) || (strchr (arg, ' ') != NULL))
     return ERR_BAD_ARGS;
@@ -45,41 +43,22 @@ pop3d_retr (char *arg)
   if (pop3d_is_deleted (attr))
     return ERR_MESG_DELE;
 
-  mu_message_get_stream (msg, &stream);
-  pop3d_outf ("+OK\r\n");
-
-  off = n = 0;
-
-  prev_nl = 1;
-  while (mu_stream_readline (stream, buf, sizeof(buf), off, &n) == 0
-        && n > 0)
-    {
-      if (prev_nl && buf[0] == '.')
-       pop3d_outf (".");
-      
-      if (buf[n - 1] == '\n')
-       {
-         buf[n - 1] = '\0';
-         pop3d_outf ("%s\r\n", buf);
-         prev_nl = 1;
-       }
-      else
-       {
-         pop3d_outf ("%s", buf);
-         prev_nl = 0;
-       }
-      off += n;
-    }
-
-  if (!prev_nl)
-    pop3d_outf ("\r\n");
+  if (mu_message_get_streamref (msg, &stream))
+    return ERR_UNKNOWN;
+  
+  pop3d_outf ("+OK\n");
+  xscript_level = set_xscript_level (MU_XSCRIPT_PAYLOAD);
+  mu_stream_copy (iostream, stream, 0, NULL);
+  mu_stream_destroy (&stream);
 
   if (!mu_attribute_is_read (attr))
     mu_attribute_set_read (attr);
 
   pop3d_mark_retr (attr);
 
-  pop3d_outf (".\r\n");
+  pop3d_outf (".\n");
+
+  set_xscript_level (xscript_level);
 
   return OK;
 }
diff --git a/pop3d/rset.c b/pop3d/rset.c
index 4a03acf..48df589 100644
--- a/pop3d/rset.c
+++ b/pop3d/rset.c
@@ -41,6 +41,6 @@ pop3d_rset (char *arg)
       mu_message_get_attribute (msg, &attr);
       pop3d_unset_deleted (attr);
     }
-  pop3d_outf ("+OK\r\n");
+  pop3d_outf ("+OK\n");
   return OK;
 }
diff --git a/pop3d/stat.c b/pop3d/stat.c
index 0b4699c..9daf3ed 100644
--- a/pop3d/stat.c
+++ b/pop3d/stat.c
@@ -57,7 +57,7 @@ pop3d_stat (char *arg)
          num++;
        }
     }
-  pop3d_outf ("+OK %s %s\r\n", mu_umaxtostr (0, num), mu_umaxtostr (1, tsize));
+  pop3d_outf ("+OK %s %s\n", mu_umaxtostr (0, num), mu_umaxtostr (1, tsize));
 
   return OK;
 }
diff --git a/pop3d/stls.c b/pop3d/stls.c
index 0e35ba7..6a8bbf6 100644
--- a/pop3d/stls.c
+++ b/pop3d/stls.c
@@ -32,10 +32,10 @@ pop3d_stls (char *arg)
   if (tls_done)
     return ERR_TLS_ACTIVE;
 
-  pop3d_outf ("+OK Begin TLS negotiation\r\n");
+  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 64e9244..6e295bb 100644
--- a/pop3d/top.c
+++ b/pop3d/top.c
@@ -23,17 +23,15 @@ int
 pop3d_top (char *arg)
 {
   size_t mesgno;
-  int lines;
+  unsigned long lines;
   mu_message_t msg;
   mu_attribute_t attr;
   mu_header_t hdr;
   mu_body_t body;
   mu_stream_t stream;
-  char *mesgc, *linesc;
-  char buf[BUFFERSIZE];
-  size_t n;
-  off_t off;
-
+  char *mesgc, *linesc, *p;
+  int xscript_level;
+  
   if (strlen (arg) == 0)
     return ERR_BAD_ARGS;
 
@@ -41,11 +39,14 @@ pop3d_top (char *arg)
     return ERR_WRONG_STATE;
 
   pop3d_parse_command (arg, &mesgc, &linesc);
+  if (linesc[0] == 0)
+    return ERR_BAD_ARGS;
   
-  mesgno = strtoul (mesgc, NULL, 10);
-  lines = *linesc ? strtol (linesc, NULL, 10) : -1;
-
-  if (lines < 0)
+  mesgno = strtoul (mesgc, &p, 10);
+  if (*p)
+    return ERR_BAD_ARGS;
+  lines = strtoul (linesc, &p, 10);
+  if (*p)
     return ERR_BAD_ARGS;
 
   if (mu_mailbox_get_message (mbox, mesgno, &msg) != 0)
@@ -56,59 +57,38 @@ pop3d_top (char *arg)
     return ERR_MESG_DELE;
   pop3d_mark_retr (attr);
   
-  pop3d_outf ("+OK\r\n");
-
   /* Header.  */
   mu_message_get_header (msg, &hdr);
-  mu_header_get_stream (hdr, &stream);
-  off = n = 0;
-  while (mu_stream_readline (stream, buf, sizeof(buf), off, &n) == 0
-        && n > 0)
-    {
-      /* Nuke the trainline newline.  */
-      if (buf[n - 1] == '\n')
-       {
-         buf[n - 1] = '\0';
-         pop3d_outf ("%s\r\n", buf);
-       }
-      else
-       pop3d_outf ("%s", buf);
-      off += n;
-    }
+  if (mu_header_get_streamref (hdr, &stream))
+    return ERR_UNKNOWN;
+  pop3d_outf ("+OK\n");
 
-  /* Lines of body.  */
-  if (lines)
-    {
-      int prev_nl = 1;
+  xscript_level = set_xscript_level (MU_XSCRIPT_PAYLOAD);
 
-      mu_message_get_body (msg, &body);
-      mu_body_get_stream (body, &stream);
-      n = off = 0;
-      while (mu_stream_readline (stream, buf, sizeof(buf), off, &n) == 0
-            && n > 0 && lines > 0)
+  mu_stream_copy (iostream, stream, 0, NULL);
+  pop3d_outf ("\n");
+  mu_stream_destroy (&stream);
+  
+  mu_message_get_body (msg, &body);
+  if (mu_body_get_streamref (body, &stream) == 0)
+    {
+      char *buf = NULL;
+      size_t size = 0, n;
+      for (; lines > 0 &&
+            mu_stream_getline (stream, &buf, &size, &n) == 0 &&
+            n > 0; lines--)
        {
-         if (prev_nl && buf[0] == '.')
+         if (buf[0] == '.')
            pop3d_outf (".");
-      
-         if (buf[n - 1] == '\n')
-           {
-             buf[n - 1] = '\0';
-             pop3d_outf ("%s\r\n", buf);
-             prev_nl = 1;
-             lines--;
-           }
-         else
-           {
-             pop3d_outf ("%s", buf);
-             prev_nl = 0;
-           }
-         off += n;
+         pop3d_outf ("%s", buf);
        }
-      if (!prev_nl)
-       pop3d_outf ("\r\n");
+      mu_stream_destroy (&stream);
+      free (buf);
     }
 
-  pop3d_outf (".\r\n");
+  pop3d_outf (".\n");
+
+  set_xscript_level (xscript_level);
 
   return OK;
 }
diff --git a/pop3d/uidl.c b/pop3d/uidl.c
index d52cc41..fa3e248 100644
--- a/pop3d/uidl.c
+++ b/pop3d/uidl.c
@@ -34,7 +34,7 @@ pop3d_uidl (char *arg)
   if (strlen (arg) == 0)
     {
       size_t total = 0;
-      pop3d_outf ("+OK\r\n");
+      pop3d_outf ("+OK\n");
       mu_mailbox_messages_count (mbox, &total);
       for (mesgno = 1; mesgno <= total; mesgno++)
         {
@@ -43,10 +43,10 @@ pop3d_uidl (char *arg)
           if (!pop3d_is_deleted (attr))
             {
               mu_message_get_uidl (msg, uidl, sizeof (uidl), NULL);
-              pop3d_outf ("%s %s\r\n", mu_umaxtostr (0, mesgno), uidl);
+              pop3d_outf ("%s %s\n", mu_umaxtostr (0, mesgno), uidl);
             }
         }
-      pop3d_outf (".\r\n");
+      pop3d_outf (".\n");
     }
   else
     {
@@ -57,7 +57,7 @@ pop3d_uidl (char *arg)
       if (pop3d_is_deleted (attr))
         return ERR_MESG_DELE;
       mu_message_get_uidl (msg, uidl, sizeof (uidl), NULL);
-      pop3d_outf ("+OK %s %s\r\n", mu_umaxtostr (0, mesgno), uidl);
+      pop3d_outf ("+OK %s %s\n", mu_umaxtostr (0, mesgno), uidl);
     }
 
   return OK;
diff --git a/pop3d/user.c b/pop3d/user.c
index 6cb130c..e6801b0 100644
--- a/pop3d/user.c
+++ b/pop3d/user.c
@@ -63,7 +63,7 @@ pop3d_begin_session ()
     pop3d_abquit (ERR_NO_MEM);
   state = TRANSACTION;
 
-  pop3d_outf ("+OK opened mailbox for %s\r\n", username);
+  pop3d_outf ("+OK opened mailbox for %s\n", username);
 
   if (undelete_on_startup)
     pop3d_undelete_all ();
@@ -89,8 +89,9 @@ pop3d_begin_session ()
 int
 pop3d_user (char *arg)
 {
-  char *buf, pass[POP_MAXCMDLEN], *tmp, *cmd;
+  char *buf, *pass, *cmd;
   char buffer[512];
+  int xscript_level;
   
   if (state != AUTHORIZATION)
     return ERR_WRONG_STATE;
@@ -98,21 +99,14 @@ pop3d_user (char *arg)
   if ((strlen (arg) == 0) || (strchr (arg, ' ') != NULL))
     return ERR_BAD_ARGS;
 
-  pop3d_outf ("+OK\r\n");
+  pop3d_outf ("+OK\n");
   pop3d_flush_output ();
 
+  xscript_level = set_xscript_level (MU_XSCRIPT_SECURE);
   buf = pop3d_readline (buffer, sizeof (buffer));
-  pop3d_parse_command (buf, &cmd, &tmp);
-
-  if (strlen (tmp) > POP_MAXCMDLEN)
-    return ERR_TOO_LONG;
-  else
-    {
-      strncpy (pass, tmp, POP_MAXCMDLEN);
-      /* strncpy () is lame, make sure the string is null terminated.  */
-      pass[POP_MAXCMDLEN - 1] = '\0';
-    }
-
+  pop3d_parse_command (buf, &cmd, &pass);
+  set_xscript_level (xscript_level);
+  
   if (mu_c_strcasecmp (cmd, "PASS") == 0)
     {
       int rc;
@@ -122,7 +116,8 @@ pop3d_user (char *arg)
       tmp = pop3d_apopuser (arg);
       if (tmp != NULL)
        {
-         mu_diag_output (MU_DIAG_INFO, _("APOP user %s tried to log in with 
USER"), arg);
+         mu_diag_output (MU_DIAG_INFO,
+                         _("APOP user %s tried to log in with USER"), arg);
          return ERR_BAD_LOGIN;
        }
 #endif
diff --git a/readmsg/msglist.c b/readmsg/msglist.c
index 267ca55..b42e325 100644
--- a/readmsg/msglist.c
+++ b/readmsg/msglist.c
@@ -118,26 +118,31 @@ msglist (mu_mailbox_t mbox, int show_all, int argc, char 
**argv,
          int found = 0;
          for (j = 1; j <= total; j++)
            {
+             int status;
              char buf[128];
              size_t len = 0;
-             mu_off_t offset = 0;
              mu_message_t msg = NULL;
              mu_stream_t stream = NULL;
 
              mu_mailbox_get_message (mbox, j, &msg);
-             mu_message_get_stream (msg, &stream);
-             while (mu_stream_readline (stream, buf, sizeof buf,
-                                        offset, &len) == 0 && len > 0)
+             status = mu_message_get_streamref (msg, &stream);
+             if (status)
+               mu_error (_("cannot read message: %s"),
+                         mu_strerror (status));
+             else
                {
-                 if (strstr (buf, argv[i]) != NULL)
+                 while (mu_stream_readline (stream, buf, sizeof buf, &len) == 0
+                        && len > 0)
                    {
-                     addset (set, n, j);
-                     found = 1;
-                     break;
+                     if (strstr (buf, argv[i]) != NULL)
+                       {
+                         addset (set, n, j);
+                         found = 1;
+                         break;
+                       }
                    }
-                 offset += len;
+                 mu_stream_destroy (&stream);
                }
-             mu_stream_destroy (&stream, NULL);
              if (found && !show_all)
                break;
            }
diff --git a/readmsg/readmsg.c b/readmsg/readmsg.c
index b3e79dd..7fdc63b 100644
--- a/readmsg/readmsg.c
+++ b/readmsg/readmsg.c
@@ -33,7 +33,6 @@ static void print_header (mu_message_t, int, int, char **);
 static void print_body (mu_message_t);
 static int  string_starts_with (const char * s1, const char *s2);
 
-const char *program_version = "readmsg (" PACKAGE_STRING ")";
 static char doc[] = N_("GNU readmsg -- print messages.");
 static error_t readmsg_parse_opt  (int key, char *arg, struct argp_state 
*astate);
 
@@ -208,26 +207,33 @@ print_header (mu_message_t message, int unix_header, int 
weedc, char **weedv)
   if (weedc == 0)
     {
       mu_stream_t stream = NULL;
-      off_t offset = 0;
       size_t len = 0;
       char buf[128];
 
-      mu_header_get_stream (header, &stream);
-      while (mu_stream_read (stream, buf, sizeof (buf) - 1, offset, &len) == 0
+      /* FIXME: Use mu_stream_copy */
+      mu_header_get_streamref (header, &stream);
+      while (mu_stream_read (stream, buf, sizeof (buf) - 1, &len) == 0
             && len != 0)
        {
          buf[len] = '\0';
          printf ("%s", buf);
-         offset += len;
        }
+      mu_stream_destroy (&stream);
     }
   else
     {
+      int status;
       size_t count;
       size_t i;
 
-      mu_header_get_field_count (header, &count);
-
+      status = mu_header_get_field_count (header, &count);
+      if (status)
+       {
+         mu_error (_("cannot get number of headers: %s"),
+                   mu_strerror (status));
+         return;
+       }
+      
       for (i = 1; i <= count; i++)
        {
          int j;
@@ -260,21 +266,28 @@ print_header (mu_message_t message, int unix_header, int 
weedc, char **weedv)
 static void
 print_body (mu_message_t message)
 {
+  int status;
   char buf[128];
   mu_body_t body = NULL;
   mu_stream_t stream = NULL;
-  off_t offset = 0;
   size_t len = 0;
   mu_message_get_body (message, &body);
-  mu_body_get_stream (body, &stream);
 
-  while (mu_stream_read (stream, buf, sizeof (buf) - 1, offset, &len) == 0
+  /* FIXME: Use mu_stream_copy */
+  status = mu_body_get_streamref (body, &stream);
+  if (status)
+    {
+      mu_error (_("cannot get body stream: %s"), mu_strerror (status));
+      return;
+    }
+
+  while (mu_stream_read (stream, buf, sizeof (buf) - 1, &len) == 0
         && len != 0)
     {
       buf[len] = '\0';
       printf ("%s", buf);
-      offset += len;
     }
+  mu_stream_destroy (&stream);
 }
 
 int
@@ -300,7 +313,7 @@ main (int argc, char **argv)
 #ifdef WITH_TLS
   mu_gocs_register ("tls", mu_tls_module_init);
 #endif
-  mu_argp_init (program_version, NULL);
+  mu_argp_init (NULL, NULL);
   if (mu_app_init (&argp, readmsg_argp_capa, readmsg_cfg_param, 
                   argc, argv, 0, &index, NULL))
     exit (1);
diff --git a/sieve/sieve.c b/sieve/sieve.c
index ce8b9c6..1e1d395 100644
--- a/sieve/sieve.c
+++ b/sieve/sieve.c
@@ -48,8 +48,6 @@
 
 #include "mailutils/libargp.h"
 
-const char *program_version = "sieve (" PACKAGE_STRING ")";
-
 static char doc[] =
 N_("GNU sieve -- a mail filtering tool.")
 "\v"
@@ -361,7 +359,7 @@ sieve_message (mu_sieve_machine_t mach)
   mu_message_t msg;
   mu_attribute_t attr;
 
-  rc = mu_stdio_stream_create (&instr, stdin, MU_STREAM_SEEKABLE);
+  rc = mu_stdio_stream_create (&instr, MU_STDIN_FD, MU_STREAM_SEEK);
   if (rc)
     {
       mu_error (_("cannot create stream: %s"), mu_strerror (rc));
@@ -480,7 +478,7 @@ main (int argc, char *argv[])
   /* Native Language Support */
   MU_APP_INIT_NLS ();
 
-  mu_argp_init (program_version, NULL);
+  mu_argp_init (NULL, NULL);
 #ifdef WITH_TLS
   mu_gocs_register ("tls", mu_tls_module_init);
 #endif
diff --git a/sieve/testsuite/Redirect b/sieve/testsuite/Redirect
index 806d86f..3063f3a 100644
--- a/sieve/testsuite/Redirect
+++ b/sieve/testsuite/Redirect
@@ -26,62 +26,56 @@ PATTERN END
 FILE BEGIN
 ENVELOPE FROM: address@hidden
 ENVELOPE TO: <address@hidden>
--re
-   0: X-Authentication-Warning: [^ \t]+ set sender using -f flag
-   1: X-Loop-Prevention: address@hidden
-   2: From: address@hidden
-   3: To: address@hidden
-   4: Subject: I have a present for you
-   5: X-Caffeine: C8H10N4O2
-   6: 
-   7: Look, I'm sorry about the whole anvil thing, and I really
-   8: didn't mean to try and drop it on you from the top of the
-   9: cliff.  I want to try to make it up to you.  I've got some
-  10: great birdseed over here at my place--top of the line
-  11: stuff--and if you come by, I'll have it all wrapped up
-  12: for you.  I'm really sorry for all the problems I've caused
-  13: for you over the years, but I know we can work this out.
-  14: 
-  15: -- 
-  16: Wile E. Coyote   "Super Genius"   address@hidden
-  17: 
+   0: X-Loop-Prevention: address@hidden
+   1: From: address@hidden
+   2: To: address@hidden
+   3: Subject: I have a present for you
+   4: X-Caffeine: C8H10N4O2
+   5: 
+   6: Look, I'm sorry about the whole anvil thing, and I really
+   7: didn't mean to try and drop it on you from the top of the
+   8: cliff.  I want to try to make it up to you.  I've got some
+   9: great birdseed over here at my place--top of the line
+  10: stuff--and if you come by, I'll have it all wrapped up
+  11: for you.  I'm really sorry for all the problems I've caused
+  12: for you over the years, but I know we can work this out.
+  13: 
+  14: -- 
+  15: Wile E. Coyote   "Super Genius"   address@hidden
+  16:
 END OF MESSAGE
 ENVELOPE FROM: address@hidden
 ENVELOPE TO: <address@hidden>
--re
-   0: X-Authentication-Warning: [^ \t]+ set sender using -f flag
-   1: X-Loop-Prevention: address@hidden
-   2: From: address@hidden
-   3: To: address@hidden
-   4: Subject: $$$ YOU, TOO, CAN BE A MILLIONAIRE! $$$
-   5: Date: TBD
-   6: X-Number: 0015
-   7:
-   8: YOU MAY HAVE ALREADY WON TEN MILLION DOLLARS, BUT I DOUBT
-   9: IT!  SO JUST POST THIS TO SIX HUNDRED NEWSGROUPS!  IT WILL
-  10: GUARANTEE THAT YOU GET AT LEAST FIVE RESPONSES WITH MONEY!
-  11: MONEY! MONEY! COLD HARD CASH!  YOU WILL RECEIVE OVER
-  12: $20,000 IN LESS THAN TWO MONTHS!  AND IT'S LEGAL!!!!!!!!!
-  13: !!!!!!!!!!!!!!!!!!111111111!!!!!!!11111111111!!1  JUST
-  14: SEND $5 IN SMALL, UNMARKED BILLS TO THE ADDRESSES BELOW!
-  15: 
+   0: X-Loop-Prevention: address@hidden
+   1: From: address@hidden
+   2: To: address@hidden
+   3: Subject: $$$ YOU, TOO, CAN BE A MILLIONAIRE! $$$
+   4: Date: TBD
+   5: X-Number: 0015
+   6:
+   7: YOU MAY HAVE ALREADY WON TEN MILLION DOLLARS, BUT I DOUBT
+   8: IT!  SO JUST POST THIS TO SIX HUNDRED NEWSGROUPS!  IT WILL
+   9: GUARANTEE THAT YOU GET AT LEAST FIVE RESPONSES WITH MONEY!
+  10: MONEY! MONEY! COLD HARD CASH!  YOU WILL RECEIVE OVER
+  11: $20,000 IN LESS THAN TWO MONTHS!  AND IT'S LEGAL!!!!!!!!!
+  12: !!!!!!!!!!!!!!!!!!111111111!!!!!!!11111111111!!1  JUST
+  13: SEND $5 IN SMALL, UNMARKED BILLS TO THE ADDRESSES BELOW!
+  14: 
 END OF MESSAGE
 ENVELOPE FROM: address@hidden
 ENVELOPE TO: <address@hidden>
--re
-   0: X-Authentication-Warning: [^ \t]+ set sender using -f flag
-   1: X-Loop-Prevention: address@hidden
-   2: Received: (from address@hidden)
-   3:  by dontmailme.org id fERKR9N16790
-   4:  for address@hidden; Fri, 28 Dec 2001 22:18:08 +0200
-   5: Date: Fri, 28 Dec 2001 23:28:08 +0200
-   6: From: Bar <address@hidden>
-   7: To: Foo Bar <address@hidden>
-   8: Message-Id: <address@hidden>
-   9: Subject: Coffee
-  10: 
-  11: How about some coffee?
-  12: 
+   0: X-Loop-Prevention: address@hidden
+   1: Received: (from address@hidden)
+   2:  by dontmailme.org id fERKR9N16790
+   3:  for address@hidden; Fri, 28 Dec 2001 22:18:08 +0200
+   4: Date: Fri, 28 Dec 2001 23:28:08 +0200
+   5: From: Bar <address@hidden>
+   6: To: Foo Bar <address@hidden>
+   7: Message-Id: <address@hidden>
+   8: Subject: Coffee
+   9: 
+  10: How about some coffee?
+  11: 
 END OF MESSAGE
 FILE END
 TEST END
diff --git a/sieve/testsuite/Reject b/sieve/testsuite/Reject
index d8ed5e8..0794cd3 100644
--- a/sieve/testsuite/Reject
+++ b/sieve/testsuite/Reject
@@ -26,179 +26,173 @@ PATTERN END
 FILE BEGIN
 ENVELOPE FROM: address@hidden
 ENVELOPE TO: <address@hidden>
-   0: To: <address@hidden>
--re
-   1: X-Authentication-Warning: [^ \t]+ set sender using -f flag
--re
-   2: Content-Type: multipart/mixed; boundary="[0-9:=-]+"
-   3: MIME-Version: 1.0
-   4:
--re
-   5: [0-9:=-]+
-   6: Content-Type: text/plain;charset=UTF-8
-   7: Content-Transfer-Encoding: 8bit
-   8:
--re
-   9: The original message was received at [A-Z][a-z][a-z], [A-Z][a-z][a-z] [ 
0-3][0-9] [ 0-2][0-9]:[0-6][0-9]:[0-6][0-9] [0-9][0-9][0-9][0-9] [a-zA-Z0-9]* 
from address@hidden
-  10: Message was refused by recipient's mail filtering program.
-  11: Reason given was as follows:
-  12: 
-  13: I don't want to read these messages.
-  14: 
-  15: Regards.
-  16:
--re
-  17: [0-9:=-]+
-  18: Content-Type: message/delivery-status
-  19:
--re
-  20: Reporting-UA: sieve; GNU Mailutils [0-9][0-9.]*
--re
-  21: Arrival-Date: [A-Z][a-z][a-z], [A-Z][a-z][a-z] [ 0-3][0-9] [ 
0-2][0-9]:[0-6][0-9]:[0-6][0-9] [0-9][0-9][0-9][0-9] [a-zA-Z0-9]*
-  22: Final-Recipient: RFC822; address@hidden
-  23: Action: deleted
-  24: Disposition: automatic-action/MDN-sent-automatically;deleted
--re
-  25: Last-Attempt-Date: [A-Z][a-z][a-z], [A-Z][a-z][a-z] [ 0-3][0-9] [ 
0-2][0-9]:[0-6][0-9]:[0-6][0-9] [0-9][0-9][0-9][0-9] [a-zA-Z0-9]*
-  26:
--re
-  27: [0-9:=-]+
-  28: Content-Type: message/rfc822
-  29: 
-  30: From: address@hidden
-  31: To: address@hidden
-  32: Subject: I have a present for you
-  33: X-Caffeine: C8H10N4O2
-  34: 
-  35: Look, I'm sorry about the whole anvil thing, and I really
-  36: didn't mean to try and drop it on you from the top of the
-  37: cliff.  I want to try to make it up to you.  I've got some
-  38: great birdseed over here at my place--top of the line
-  39: stuff--and if you come by, I'll have it all wrapped up
-  40: for you.  I'm really sorry for all the problems I've caused
-  41: for you over the years, but I know we can work this out.
-  42: 
-  43: -- 
-  44: Wile E. Coyote   "Super Genius"   address@hidden
-  45:
--re
-  46: [0-9:=-]+
-  47: 
+   0: To: address@hidden
+-re
+   1: Content-Type: multipart/mixed; boundary="[0-9:=-]+"
+   2: MIME-Version: 1.0
+   3:
+-re
+   4: [0-9:=-]+
+   5: Content-Type: text/plain;charset=UTF-8
+   6: Content-Transfer-Encoding: 8bit
+   7:
+-re
+   8: The original message was received at [A-Z][a-z][a-z], [A-Z][a-z][a-z] [ 
0-3][0-9] [ 0-2][0-9]:[0-6][0-9]:[0-6][0-9] [0-9][0-9][0-9][0-9] [a-zA-Z0-9]* 
from address@hidden
+   9: Message was refused by recipient's mail filtering program.
+  10: Reason given was as follows:
+  11: 
+  12: I don't want to read these messages.
+  13: 
+  14: Regards.
+  15:
+-re
+  16: [0-9:=-]+
+  17: Content-Type: message/delivery-status
+  18:
+-re
+  19: Reporting-UA: sieve; GNU Mailutils [0-9][0-9.]*
+-re
+  20: Arrival-Date: [A-Z][a-z][a-z], [A-Z][a-z][a-z] [ 0-3][0-9] [ 
0-2][0-9]:[0-6][0-9]:[0-6][0-9] [0-9][0-9][0-9][0-9] [a-zA-Z0-9]*
+  21: Final-Recipient: RFC822; address@hidden
+  22: Action: deleted
+  23: Disposition: automatic-action/MDN-sent-automatically;deleted
+-re
+  24: Last-Attempt-Date: [A-Z][a-z][a-z], [A-Z][a-z][a-z] [ 0-3][0-9] [ 
0-2][0-9]:[0-6][0-9]:[0-6][0-9] [0-9][0-9][0-9][0-9] [a-zA-Z0-9]*
+  25:
+-re
+  26: [0-9:=-]+
+  27: Content-Type: message/rfc822
+  28: 
+  29: From: address@hidden
+  30: To: address@hidden
+  31: Subject: I have a present for you
+  32: X-Caffeine: C8H10N4O2
+  33: 
+  34: Look, I'm sorry about the whole anvil thing, and I really
+  35: didn't mean to try and drop it on you from the top of the
+  36: cliff.  I want to try to make it up to you.  I've got some
+  37: great birdseed over here at my place--top of the line
+  38: stuff--and if you come by, I'll have it all wrapped up
+  39: for you.  I'm really sorry for all the problems I've caused
+  40: for you over the years, but I know we can work this out.
+  41: 
+  42: -- 
+  43: Wile E. Coyote   "Super Genius"   address@hidden
+  44:
+-re
+  45: [0-9:=-]+
+  46: 
 END OF MESSAGE
 ENVELOPE FROM: address@hidden
 ENVELOPE TO: <address@hidden>
-   0: To: <address@hidden>
--re
-   1: X-Authentication-Warning: [^ \t]+ set sender using -f flag
--re
-   2: Content-Type: multipart/mixed; boundary="[0-9:=-]+"
-   3: MIME-Version: 1.0
-   4:
--re
-   5: [0-9:=-]+
-   6: Content-Type: text/plain;charset=UTF-8
-   7: Content-Transfer-Encoding: 8bit
-   8:
--re
-   9: The original message was received at [A-Z][a-z][a-z], [A-Z][a-z][a-z] [ 
0-3][0-9] [ 0-2][0-9]:[0-6][0-9]:[0-6][0-9] [0-9][0-9][0-9][0-9] [a-zA-Z0-9]* 
from address@hidden
-  10: Message was refused by recipient's mail filtering program.
-  11: Reason given was as follows:
-  12: 
-  13: I don't want to read these messages.
-  14: 
-  15: Regards.
-  16:
--re
-  17: [0-9:=-]+
-  18: Content-Type: message/delivery-status
-  19:
--re
-  20: Reporting-UA: sieve; GNU Mailutils [0-9][0-9.]*
--re
-  21: Arrival-Date: [A-Z][a-z][a-z], [A-Z][a-z][a-z] [ 0-3][0-9] [ 
0-2][0-9]:[0-6][0-9]:[0-6][0-9] [0-9][0-9][0-9][0-9] [a-zA-Z0-9]*
-  22: Final-Recipient: RFC822; address@hidden
-  23: Action: deleted
-  24: Disposition: automatic-action/MDN-sent-automatically;deleted
--re
-  25: Last-Attempt-Date: [A-Z][a-z][a-z], [A-Z][a-z][a-z] [ 0-3][0-9] [ 
0-2][0-9]:[0-6][0-9]:[0-6][0-9] [0-9][0-9][0-9][0-9] [a-zA-Z0-9]*
-  26:
--re
-  27: [0-9:=-]+
-  28: Content-Type: message/rfc822
-  29: 
-  30: From: address@hidden
-  31: To: address@hidden
-  32: Subject: $$$ YOU, TOO, CAN BE A MILLIONAIRE! $$$
-  33: Date: TBD
-  34: X-Number: 0015
-  35:
-  36: YOU MAY HAVE ALREADY WON TEN MILLION DOLLARS, BUT I DOUBT
-  37: IT!  SO JUST POST THIS TO SIX HUNDRED NEWSGROUPS!  IT WILL
-  38: GUARANTEE THAT YOU GET AT LEAST FIVE RESPONSES WITH MONEY!
-  39: MONEY! MONEY! COLD HARD CASH!  YOU WILL RECEIVE OVER
-  40: $20,000 IN LESS THAN TWO MONTHS!  AND IT'S LEGAL!!!!!!!!!
-  41: !!!!!!!!!!!!!!!!!!111111111!!!!!!!11111111111!!1  JUST
-  42: SEND $5 IN SMALL, UNMARKED BILLS TO THE ADDRESSES BELOW!
-  43:
--re
-  44: [0-9:=-]+
-  45:
+   0: To: address@hidden
+-re
+   1: Content-Type: multipart/mixed; boundary="[0-9:=-]+"
+   2: MIME-Version: 1.0
+   3:
+-re
+   4: [0-9:=-]+
+   5: Content-Type: text/plain;charset=UTF-8
+   6: Content-Transfer-Encoding: 8bit
+   7:
+-re
+   8: The original message was received at [A-Z][a-z][a-z], [A-Z][a-z][a-z] [ 
0-3][0-9] [ 0-2][0-9]:[0-6][0-9]:[0-6][0-9] [0-9][0-9][0-9][0-9] [a-zA-Z0-9]* 
from address@hidden
+   9: Message was refused by recipient's mail filtering program.
+  10: Reason given was as follows:
+  11: 
+  12: I don't want to read these messages.
+  13: 
+  14: Regards.
+  15:
+-re
+  16: [0-9:=-]+
+  17: Content-Type: message/delivery-status
+  18:
+-re
+  19: Reporting-UA: sieve; GNU Mailutils [0-9][0-9.]*
+-re
+  20: Arrival-Date: [A-Z][a-z][a-z], [A-Z][a-z][a-z] [ 0-3][0-9] [ 
0-2][0-9]:[0-6][0-9]:[0-6][0-9] [0-9][0-9][0-9][0-9] [a-zA-Z0-9]*
+  21: Final-Recipient: RFC822; address@hidden
+  22: Action: deleted
+  23: Disposition: automatic-action/MDN-sent-automatically;deleted
+-re
+  24: Last-Attempt-Date: [A-Z][a-z][a-z], [A-Z][a-z][a-z] [ 0-3][0-9] [ 
0-2][0-9]:[0-6][0-9]:[0-6][0-9] [0-9][0-9][0-9][0-9] [a-zA-Z0-9]*
+  25:
+-re
+  26: [0-9:=-]+
+  27: Content-Type: message/rfc822
+  28: 
+  29: From: address@hidden
+  30: To: address@hidden
+  31: Subject: $$$ YOU, TOO, CAN BE A MILLIONAIRE! $$$
+  32: Date: TBD
+  33: X-Number: 0015
+  34:
+  35: YOU MAY HAVE ALREADY WON TEN MILLION DOLLARS, BUT I DOUBT
+  36: IT!  SO JUST POST THIS TO SIX HUNDRED NEWSGROUPS!  IT WILL
+  37: GUARANTEE THAT YOU GET AT LEAST FIVE RESPONSES WITH MONEY!
+  38: MONEY! MONEY! COLD HARD CASH!  YOU WILL RECEIVE OVER
+  39: $20,000 IN LESS THAN TWO MONTHS!  AND IT'S LEGAL!!!!!!!!!
+  40: !!!!!!!!!!!!!!!!!!111111111!!!!!!!11111111111!!1  JUST
+  41: SEND $5 IN SMALL, UNMARKED BILLS TO THE ADDRESSES BELOW!
+  42:
+-re
+  43: [0-9:=-]+
+  44:
 END OF MESSAGE
 ENVELOPE FROM: address@hidden
 ENVELOPE TO: <address@hidden>
-   0: To: <address@hidden>
--re
-   1: X-Authentication-Warning: [^ \t]+ set sender using -f flag
--re
-   2: Content-Type: multipart/mixed; boundary="[0-9:=-]+"
-   3: MIME-Version: 1.0
-   4:
--re
-   5: [0-9:=-]+
-   6: Content-Type: text/plain;charset=UTF-8
-   7: Content-Transfer-Encoding: 8bit
-   8:
--re
-   9: The original message was received at [A-Z][a-z][a-z], [A-Z][a-z][a-z] [ 
0-3][0-9] [ 0-2][0-9]:[0-6][0-9]:[0-6][0-9] [0-9][0-9][0-9][0-9] [a-zA-Z0-9]* 
from address@hidden
-  10: Message was refused by recipient's mail filtering program.
-  11: Reason given was as follows:
-  12: 
-  13: I don't want to read these messages.
-  14: 
-  15: Regards.
-  16:
--re
-  17: [0-9:=-]+
-  18: Content-Type: message/delivery-status
-  19:
--re
-  20: Reporting-UA: sieve; GNU Mailutils [0-9][0-9.]*
--re
-  21: Arrival-Date: [A-Z][a-z][a-z], [A-Z][a-z][a-z] [ 0-3][0-9] [ 
0-2][0-9]:[0-6][0-9]:[0-6][0-9] [0-9][0-9][0-9][0-9] [a-zA-Z0-9]*
-  22: Final-Recipient: RFC822; address@hidden
-  23: Action: deleted
-  24: Disposition: automatic-action/MDN-sent-automatically;deleted
--re
-  25: Last-Attempt-Date: [A-Z][a-z][a-z], [A-Z][a-z][a-z] [ 0-3][0-9] [ 
0-2][0-9]:[0-6][0-9]:[0-6][0-9] [0-9][0-9][0-9][0-9] [a-zA-Z0-9]*
-  26:
--re
-  27: [0-9:=-]+
-  28: Content-Type: message/rfc822
-  29: 
-  30: Received: (from address@hidden)
-  31:  by dontmailme.org id fERKR9N16790
-  32:  for address@hidden; Fri, 28 Dec 2001 22:18:08 +0200
-  33: Date: Fri, 28 Dec 2001 23:28:08 +0200
-  34: From: Bar <address@hidden>
-  35: To: Foo Bar <address@hidden>
-  36: Message-Id: <address@hidden>
-  37: Subject: Coffee
-  38: 
-  39: How about some coffee?
-  40:
--re
-  41: [0-9:=-]+
-  42: 
+   0: To: address@hidden
+-re
+   1: Content-Type: multipart/mixed; boundary="[0-9:=-]+"
+   2: MIME-Version: 1.0
+   3:
+-re
+   4: [0-9:=-]+
+   5: Content-Type: text/plain;charset=UTF-8
+   6: Content-Transfer-Encoding: 8bit
+   7:
+-re
+   8: The original message was received at [A-Z][a-z][a-z], [A-Z][a-z][a-z] [ 
0-3][0-9] [ 0-2][0-9]:[0-6][0-9]:[0-6][0-9] [0-9][0-9][0-9][0-9] [a-zA-Z0-9]* 
from address@hidden
+   9: Message was refused by recipient's mail filtering program.
+  10: Reason given was as follows:
+  11: 
+  12: I don't want to read these messages.
+  13: 
+  14: Regards.
+  15:
+-re
+  16: [0-9:=-]+
+  17: Content-Type: message/delivery-status
+  18:
+-re
+  19: Reporting-UA: sieve; GNU Mailutils [0-9][0-9.]*
+-re
+  20: Arrival-Date: [A-Z][a-z][a-z], [A-Z][a-z][a-z] [ 0-3][0-9] [ 
0-2][0-9]:[0-6][0-9]:[0-6][0-9] [0-9][0-9][0-9][0-9] [a-zA-Z0-9]*
+  21: Final-Recipient: RFC822; address@hidden
+  22: Action: deleted
+  23: Disposition: automatic-action/MDN-sent-automatically;deleted
+-re
+  24: Last-Attempt-Date: [A-Z][a-z][a-z], [A-Z][a-z][a-z] [ 0-3][0-9] [ 
0-2][0-9]:[0-6][0-9]:[0-6][0-9] [0-9][0-9][0-9][0-9] [a-zA-Z0-9]*
+  25:
+-re
+  26: [0-9:=-]+
+  27: Content-Type: message/rfc822
+  28: 
+  29: Received: (from address@hidden)
+  30:  by dontmailme.org id fERKR9N16790
+  31:  for address@hidden; Fri, 28 Dec 2001 22:18:08 +0200
+  32: Date: Fri, 28 Dec 2001 23:28:08 +0200
+  33: From: Bar <address@hidden>
+  34: To: Foo Bar <address@hidden>
+  35: Message-Id: <address@hidden>
+  36: Subject: Coffee
+  37: 
+  38: How about some coffee?
+  39:
+-re
+  40: [0-9:=-]+
+  41: 
 END OF MESSAGE
 FILE END
 TEST END


hooks/post-receive
-- 
GNU Mailutils



reply via email to

[Prev in Thread] Current Thread [Next in Thread]