[evolution-data-server] Add CamelIMAPXInputStream.



commit 1f332afde98dc5245fbb4ff51360bf56dbb8befe
Author: Matthew Barnes <mbarnes redhat com>
Date:   Thu Feb 6 15:51:04 2014 -0500

    Add CamelIMAPXInputStream.
    
    Replaces the input side of CamelIMAPXStream.
    
    Currently derived from only GFilterInputStream to keep the code changes
    to a minimum until I can verify this works, but eventually would like to
    derive from GDataInputStream for reading and buffering whole lines.
    
    Unfortunately this requires switching all of IMAPX over at once, so this
    is a rather large commit.

 camel/providers/imapx/Makefile.am                  |    2 +
 camel/providers/imapx/camel-imapx-input-stream.c   |  948 ++++++++++++++++++++
 camel/providers/imapx/camel-imapx-input-stream.h   |  158 ++++
 camel/providers/imapx/camel-imapx-list-response.c  |   55 +-
 camel/providers/imapx/camel-imapx-list-response.h  |    4 +-
 .../imapx/camel-imapx-namespace-response.c         |   28 +-
 .../imapx/camel-imapx-namespace-response.h         |    2 +-
 camel/providers/imapx/camel-imapx-server.c         |  631 ++++++-------
 camel/providers/imapx/camel-imapx-server.h         |   13 +-
 .../providers/imapx/camel-imapx-status-response.c  |   51 +-
 .../providers/imapx/camel-imapx-status-response.h  |    4 +-
 camel/providers/imapx/camel-imapx-utils.c          |  715 ++++++++++------
 camel/providers/imapx/camel-imapx-utils.h          |   32 +-
 docs/reference/camel/camel-sections.txt            |   36 +-
 docs/reference/camel/camel.types                   |    2 +
 15 files changed, 1999 insertions(+), 682 deletions(-)
---
diff --git a/camel/providers/imapx/Makefile.am b/camel/providers/imapx/Makefile.am
index 6f5dd77..9ac7d59 100644
--- a/camel/providers/imapx/Makefile.am
+++ b/camel/providers/imapx/Makefile.am
@@ -24,6 +24,8 @@ libcamelimapx_la_SOURCES = \
        camel-imapx-command.h \
        camel-imapx-folder.c \
        camel-imapx-folder.h \
+       camel-imapx-input-stream.c \
+       camel-imapx-input-stream.h \
        camel-imapx-job.c \
        camel-imapx-job.h \
        camel-imapx-list-response.c \
diff --git a/camel/providers/imapx/camel-imapx-input-stream.c 
b/camel/providers/imapx/camel-imapx-input-stream.c
new file mode 100644
index 0000000..748137c
--- /dev/null
+++ b/camel/providers/imapx/camel-imapx-input-stream.c
@@ -0,0 +1,948 @@
+/*
+ * camel-imapx-input-stream.h
+ *
+ * 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.
+ *
+ * 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 General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "camel-imapx-input-stream.h"
+
+#include <config.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include <glib/gi18n-lib.h>
+
+#include <camel/camel.h>
+
+#include "camel-imapx-utils.h"
+
+#define CAMEL_IMAPX_INPUT_STREAM_GET_PRIVATE(obj) \
+       (G_TYPE_INSTANCE_GET_PRIVATE \
+       ((obj), CAMEL_TYPE_IMAPX_INPUT_STREAM, CamelIMAPXInputStreamPrivate))
+
+struct _CamelIMAPXInputStreamPrivate {
+       guchar *buf, *ptr, *end;
+       guint literal;
+
+       guint unget;
+       camel_imapx_token_t unget_tok;
+       guchar *unget_token;
+       guint unget_len;
+
+       guchar *tokenbuf;
+       guint bufsize;
+};
+
+/* Forward Declarations */
+static void    camel_imapx_input_stream_pollable_init
+                               (GPollableInputStreamInterface *interface);
+
+G_DEFINE_TYPE_WITH_CODE (
+       CamelIMAPXInputStream,
+       camel_imapx_input_stream,
+       G_TYPE_FILTER_INPUT_STREAM,
+       G_IMPLEMENT_INTERFACE (
+               G_TYPE_POLLABLE_INPUT_STREAM,
+               camel_imapx_input_stream_pollable_init))
+
+static gint
+imapx_input_stream_fill (CamelIMAPXInputStream *is,
+                         GCancellable *cancellable,
+                         GError **error)
+{
+       GInputStream *base_stream;
+       gint left = 0;
+
+       base_stream = g_filter_input_stream_get_base_stream (
+               G_FILTER_INPUT_STREAM (is));
+
+       left = is->priv->end - is->priv->ptr;
+       memcpy (is->priv->buf, is->priv->ptr, left);
+       is->priv->end = is->priv->buf + left;
+       is->priv->ptr = is->priv->buf;
+       left = g_input_stream_read (
+               base_stream,
+               is->priv->end,
+               is->priv->bufsize - (is->priv->end - is->priv->buf),
+               cancellable, error);
+       if (left > 0) {
+               is->priv->end += left;
+               return is->priv->end - is->priv->ptr;
+       } else {
+               /* If returning zero, camel_stream_read() doesn't consider
+                * that to be an error. But we do -- we should only be here
+                * if we *know* there are data to receive. So set the error
+                * accordingly */
+               if (!left)
+                       g_set_error (
+                               error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
+                               _("Source stream returned no data"));
+               return -1;
+       }
+}
+
+static void
+imapx_input_stream_finalize (GObject *object)
+{
+       CamelIMAPXInputStreamPrivate *priv;
+
+       priv = CAMEL_IMAPX_INPUT_STREAM_GET_PRIVATE (object);
+
+       g_free (priv->buf);
+       g_free (priv->tokenbuf);
+
+       /* Chain up to parent's finalize() method. */
+       G_OBJECT_CLASS (camel_imapx_input_stream_parent_class)->
+               finalize (object);
+}
+
+static gssize
+imapx_input_stream_read (GInputStream *stream,
+                         gpointer buffer,
+                         gsize count,
+                         GCancellable *cancellable,
+                         GError **error)
+{
+       CamelIMAPXInputStreamPrivate *priv;
+       GInputStream *base_stream;
+       gssize max;
+
+       priv = CAMEL_IMAPX_INPUT_STREAM_GET_PRIVATE (stream);
+
+       base_stream = g_filter_input_stream_get_base_stream (
+               G_FILTER_INPUT_STREAM (stream));
+
+       if (priv->literal == 0 || count == 0)
+               return 0;
+
+       max = priv->end - priv->ptr;
+       if (max > 0) {
+               max = MIN (max, priv->literal);
+               max = MIN (max, count);
+               memcpy (buffer, priv->ptr, max);
+               priv->ptr += max;
+       } else {
+               max = MIN (priv->literal, count);
+               max = g_input_stream_read (
+                       base_stream, buffer, max, cancellable, error);
+               if (max <= 0)
+                       return max;
+       }
+
+       priv->literal -= max;
+
+       return max;
+}
+
+static gboolean
+imapx_input_stream_can_poll (GPollableInputStream *pollable_stream)
+{
+       GInputStream *base_stream;
+
+       base_stream = g_filter_input_stream_get_base_stream (
+               G_FILTER_INPUT_STREAM (pollable_stream));
+
+       pollable_stream = G_POLLABLE_INPUT_STREAM (base_stream);
+
+       return g_pollable_input_stream_can_poll (pollable_stream);
+}
+
+static gboolean
+imapx_input_stream_is_readable (GPollableInputStream *pollable_stream)
+{
+       GInputStream *base_stream;
+
+       base_stream = g_filter_input_stream_get_base_stream (
+               G_FILTER_INPUT_STREAM (pollable_stream));
+
+       pollable_stream = G_POLLABLE_INPUT_STREAM (base_stream);
+
+       return g_pollable_input_stream_is_readable (pollable_stream);
+}
+
+static GSource *
+imapx_input_stream_create_source (GPollableInputStream *pollable_stream,
+                                  GCancellable *cancellable)
+{
+       GInputStream *base_stream;
+
+       base_stream = g_filter_input_stream_get_base_stream (
+               G_FILTER_INPUT_STREAM (pollable_stream));
+
+       pollable_stream = G_POLLABLE_INPUT_STREAM (base_stream);
+
+       return g_pollable_input_stream_create_source (
+               pollable_stream, cancellable);
+}
+
+static gssize
+imapx_input_stream_read_nonblocking (GPollableInputStream *pollable_stream,
+                                     gpointer buffer,
+                                     gsize count,
+                                     GError **error)
+{
+       GInputStream *base_stream;
+
+       base_stream = g_filter_input_stream_get_base_stream (
+               G_FILTER_INPUT_STREAM (pollable_stream));
+
+       pollable_stream = G_POLLABLE_INPUT_STREAM (base_stream);
+
+       /* XXX The function takes a GCancellable but the class method
+        *     does not.  Should be okay to pass NULL here since this
+        *     is just a pass-through. */
+       return g_pollable_input_stream_read_nonblocking (
+               pollable_stream, buffer, count, NULL, error);
+}
+
+static void
+camel_imapx_input_stream_class_init (CamelIMAPXInputStreamClass *class)
+{
+       GObjectClass *object_class;
+       GInputStreamClass *input_stream_class;
+
+       g_type_class_add_private (
+               class, sizeof (CamelIMAPXInputStreamPrivate));
+
+       object_class = G_OBJECT_CLASS (class);
+       object_class->finalize = imapx_input_stream_finalize;
+
+       input_stream_class = G_INPUT_STREAM_CLASS (class);
+       input_stream_class->read_fn = imapx_input_stream_read;
+}
+
+static void
+camel_imapx_input_stream_pollable_init (GPollableInputStreamInterface *interface)
+{
+       interface->can_poll = imapx_input_stream_can_poll;
+       interface->is_readable = imapx_input_stream_is_readable;
+       interface->create_source = imapx_input_stream_create_source;
+       interface->read_nonblocking = imapx_input_stream_read_nonblocking;
+}
+
+static void
+camel_imapx_input_stream_init (CamelIMAPXInputStream *is)
+{
+       is->priv = CAMEL_IMAPX_INPUT_STREAM_GET_PRIVATE (is);
+
+       /* +1 is room for appending a 0 if we need to for a token */
+       is->priv->bufsize = 4096;
+       is->priv->buf = g_malloc (is->priv->bufsize + 1);
+       is->priv->ptr = is->priv->end = is->priv->buf;
+       is->priv->tokenbuf = g_malloc (is->priv->bufsize + 1);
+}
+
+static void
+camel_imapx_input_stream_grow (CamelIMAPXInputStream *is,
+                               guint len,
+                               guchar **bufptr,
+                               guchar **tokptr)
+{
+       guchar *oldtok = is->priv->tokenbuf;
+       guchar *oldbuf = is->priv->buf;
+
+       do {
+               is->priv->bufsize <<= 1;
+       } while (is->priv->bufsize <= len);
+
+       is->priv->tokenbuf = g_realloc (
+               is->priv->tokenbuf,
+               is->priv->bufsize + 1);
+       if (tokptr)
+               *tokptr = is->priv->tokenbuf + (*tokptr - oldtok);
+       if (is->priv->unget)
+               is->priv->unget_token =
+                       is->priv->tokenbuf +
+                       (is->priv->unget_token - oldtok);
+
+       is->priv->buf = g_realloc (is->priv->buf, is->priv->bufsize + 1);
+       is->priv->ptr = is->priv->buf + (is->priv->ptr - oldbuf);
+       is->priv->end = is->priv->buf + (is->priv->end - oldbuf);
+       if (bufptr)
+               *bufptr = is->priv->buf + (*bufptr - oldbuf);
+}
+
+#if 0
+G_DEFINE_QUARK (camel-imapx-error-quark, camel_imapx_error)
+#endif
+
+/**
+ * camel_imapx_input_stream_new:
+ * @base_stream: a pollable #GInputStream
+ *
+ * Creates a new #CamelIMAPXInputStream which wraps @base_stream and
+ * parses incoming IMAP lines into tokens.
+ *
+ * Returns: a #CamelIMAPXInputStream
+ *
+ * Since: 3.12
+ **/
+GInputStream *
+camel_imapx_input_stream_new (GInputStream *base_stream)
+{
+       /* We implement GPollableInputStream by forwarding method calls
+        * to the base stream, so the base stream needs to be pollable. */
+       g_return_val_if_fail (G_IS_POLLABLE_INPUT_STREAM (base_stream), NULL);
+
+       return g_object_new (
+               CAMEL_TYPE_IMAPX_INPUT_STREAM,
+               "base-stream", base_stream, NULL);
+}
+
+/* Returns if there is any data buffered that is ready for processing */
+gint
+camel_imapx_input_stream_buffered (CamelIMAPXInputStream *is)
+{
+       g_return_val_if_fail (CAMEL_IS_IMAPX_INPUT_STREAM (is), 0);
+
+       return is->priv->end - is->priv->ptr;
+}
+
+/* FIXME: these should probably handle it themselves,
+ * and get rid of the token interface? */
+gboolean
+camel_imapx_input_stream_atom (CamelIMAPXInputStream *is,
+                               guchar **data,
+                               guint *lenp,
+                               GCancellable *cancellable,
+                               GError **error)
+{
+       camel_imapx_token_t tok;
+       guchar *p, c;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_INPUT_STREAM (is), FALSE);
+       g_return_val_if_fail (data != NULL, FALSE);
+       g_return_val_if_fail (lenp != NULL, FALSE);
+
+       /* this is only 'approximate' atom */
+       tok = camel_imapx_input_stream_token (is, data, lenp, cancellable, error);
+
+       switch (tok) {
+               case IMAPX_TOK_ERROR:
+                       return FALSE;
+
+               case IMAPX_TOK_TOKEN:
+                       p = *data;
+                       while ((c = *p))
+                               *p++ = toupper(c);
+                       return TRUE;
+
+               case IMAPX_TOK_INT:
+                       return TRUE;
+
+               default:
+                       g_set_error (
+                               error, CAMEL_IMAPX_ERROR, 1,
+                               "expecting atom");
+                       return FALSE;
+       }
+}
+
+/* gets an atom, a quoted_string, or a literal */
+gboolean
+camel_imapx_input_stream_astring (CamelIMAPXInputStream *is,
+                                  guchar **data,
+                                  GCancellable *cancellable,
+                                  GError **error)
+{
+       camel_imapx_token_t tok;
+       guchar *p, *start;
+       guint len, inlen;
+       gint ret;
+
+       g_return_val_if_fail (CAMEL_IMAPX_INPUT_STREAM (is), FALSE);
+       g_return_val_if_fail (data != NULL, FALSE);
+
+       tok = camel_imapx_input_stream_token (is, data, &len, cancellable, error);
+
+       switch (tok) {
+               case IMAPX_TOK_ERROR:
+                       return FALSE;
+
+               case IMAPX_TOK_TOKEN:
+               case IMAPX_TOK_STRING:
+               case IMAPX_TOK_INT:
+                       return TRUE;
+
+               case IMAPX_TOK_LITERAL:
+                       if (len >= is->priv->bufsize)
+                               camel_imapx_input_stream_grow (is, len, NULL, NULL);
+                       p = is->priv->tokenbuf;
+                       camel_imapx_input_stream_set_literal (is, len);
+                       do {
+                               ret = camel_imapx_input_stream_getl (
+                                       is, &start, &inlen, cancellable, error);
+                               if (ret < 0)
+                                       return FALSE;
+                               memcpy (p, start, inlen);
+                               p += inlen;
+                       } while (ret > 0);
+                       *p = 0;
+                       *data = is->priv->tokenbuf;
+                       return TRUE;
+
+               default:
+                       g_set_error (
+                               error, CAMEL_IMAPX_ERROR, 1,
+                               "expecting astring");
+                       return FALSE;
+       }
+}
+
+/* check for NIL or (small) quoted_string or literal */
+gboolean
+camel_imapx_input_stream_nstring (CamelIMAPXInputStream *is,
+                                  guchar **data,
+                                  GCancellable *cancellable,
+                                  GError **error)
+{
+       camel_imapx_token_t tok;
+       guchar *p, *start;
+       guint len, inlen;
+       gint ret;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_INPUT_STREAM (is), FALSE);
+       g_return_val_if_fail (data != NULL, FALSE);
+
+       tok = camel_imapx_input_stream_token (is, data, &len, cancellable, error);
+
+       switch (tok) {
+               case IMAPX_TOK_ERROR:
+                       return FALSE;
+
+               case IMAPX_TOK_STRING:
+                       return TRUE;
+
+               case IMAPX_TOK_LITERAL:
+                       if (len >= is->priv->bufsize)
+                               camel_imapx_input_stream_grow (is, len, NULL, NULL);
+                       p = is->priv->tokenbuf;
+                       camel_imapx_input_stream_set_literal (is, len);
+                       do {
+                               ret = camel_imapx_input_stream_getl (
+                                       is, &start, &inlen, cancellable, error);
+                               if (ret < 0)
+                                       return FALSE;
+                               memcpy (p, start, inlen);
+                               p += inlen;
+                       } while (ret > 0);
+                       *p = 0;
+                       *data = is->priv->tokenbuf;
+                       return TRUE;
+
+               case IMAPX_TOK_TOKEN:
+                       p = *data;
+                       if (toupper (p[0]) == 'N' &&
+                           toupper (p[1]) == 'I' &&
+                           toupper (p[2]) == 'L' &&
+                           p[3] == 0) {
+                               *data = NULL;
+                               return TRUE;
+                       }
+                       /* fall through */
+
+               default:
+                       g_set_error (
+                               error, CAMEL_IMAPX_ERROR, 1,
+                               "expecting nstring");
+                       return FALSE;
+       }
+}
+
+/* parse an nstring as a GBytes */
+gboolean
+camel_imapx_input_stream_nstring_bytes (CamelIMAPXInputStream *is,
+                                        GBytes **out_bytes,
+                                        GCancellable *cancellable,
+                                        GError **error)
+{
+       camel_imapx_token_t tok;
+       guchar *token;
+       guint len;
+       GOutputStream *output_stream;
+       gssize bytes_written;
+       gboolean success;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_INPUT_STREAM (is), FALSE);
+       g_return_val_if_fail (out_bytes != NULL, FALSE);
+
+       *out_bytes = NULL;
+
+       tok = camel_imapx_input_stream_token (
+               is, &token, &len, cancellable, error);
+
+       switch (tok) {
+               case IMAPX_TOK_ERROR:
+                       return FALSE;
+
+               case IMAPX_TOK_STRING:
+                       *out_bytes = g_bytes_new (token, len);
+                       return TRUE;
+
+               case IMAPX_TOK_LITERAL:
+                       /* If len is big, we could
+                        * automatically use a file backing. */
+                       camel_imapx_input_stream_set_literal (is, len);
+                       output_stream =
+                               g_memory_output_stream_new_resizable ();
+                       bytes_written = g_output_stream_splice (
+                               output_stream,
+                               G_INPUT_STREAM (is),
+                               G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
+                               cancellable, error);
+                       success = (bytes_written >= 0);
+                       if (success) {
+                               *out_bytes =
+                                       g_memory_output_stream_steal_as_bytes (
+                                       G_MEMORY_OUTPUT_STREAM (output_stream));
+                       }
+                       g_object_unref (output_stream);
+                       return success;
+
+               case IMAPX_TOK_TOKEN:
+                       if (toupper (token[0]) == 'N' &&
+                           toupper (token[1]) == 'I' &&
+                           toupper (token[2]) == 'L' &&
+                           token[3] == 0) {
+                               *out_bytes = NULL;
+                               return TRUE;
+                       }
+                       /* fall through */
+
+               default:
+                       g_set_error (
+                               error, CAMEL_IMAPX_ERROR, 1,
+                               "nstring: token not string");
+                       return FALSE;
+       }
+}
+
+gboolean
+camel_imapx_input_stream_number (CamelIMAPXInputStream *is,
+                                 guint64 *number,
+                                 GCancellable *cancellable,
+                                 GError **error)
+{
+       camel_imapx_token_t tok;
+       guchar *token;
+       guint len;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_INPUT_STREAM (is), FALSE);
+       g_return_val_if_fail (number != NULL, FALSE);
+
+       tok = camel_imapx_input_stream_token (
+               is, &token, &len, cancellable, error);
+
+       switch (tok) {
+               case IMAPX_TOK_ERROR:
+                       return FALSE;
+
+               case IMAPX_TOK_INT:
+                       *number = g_ascii_strtoull ((gchar *) token, 0, 10);
+                       return TRUE;
+
+               default:
+                       g_set_error (
+                               error, CAMEL_IMAPX_ERROR, 1,
+                               "expecting number");
+                       return FALSE;
+       }
+}
+
+gboolean
+camel_imapx_input_stream_text (CamelIMAPXInputStream *is,
+                               guchar **text,
+                               GCancellable *cancellable,
+                               GError **error)
+{
+       GByteArray *build = g_byte_array_new ();
+       guchar *token;
+       guint len;
+       gint tok;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_INPUT_STREAM (is), FALSE);
+       g_return_val_if_fail (text != NULL, FALSE);
+
+       while (is->priv->unget > 0) {
+               switch (is->priv->unget_tok) {
+                       case IMAPX_TOK_TOKEN:
+                       case IMAPX_TOK_STRING:
+                       case IMAPX_TOK_INT:
+                               g_byte_array_append (
+                                       build, (guint8 *)
+                                       is->priv->unget_token,
+                                       is->priv->unget_len);
+                               g_byte_array_append (
+                                       build, (guint8 *) " ", 1);
+                       default: /* invalid, but we'll ignore */
+                               break;
+               }
+               is->priv->unget--;
+       }
+
+       do {
+               tok = camel_imapx_input_stream_gets (
+                       is, &token, &len, cancellable, error);
+               if (tok < 0) {
+                       *text = NULL;
+                       g_byte_array_free (build, TRUE);
+                       return FALSE;
+               }
+               if (len)
+                       g_byte_array_append (build, token, len);
+       } while (tok > 0);
+
+       g_byte_array_append (build, (guint8 *) "", 1);
+       *text = build->data;
+       g_byte_array_free (build, FALSE);
+
+       return TRUE;
+}
+
+/* Get one token from the imap stream */
+camel_imapx_token_t
+camel_imapx_input_stream_token (CamelIMAPXInputStream *is,
+                                guchar **data,
+                                guint *len,
+                                GCancellable *cancellable,
+                                GError **error)
+{
+       register guchar c, *oe;
+       guchar *o, *p, *e;
+       guint literal;
+       gint digits;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_INPUT_STREAM (is), IMAPX_TOK_ERROR);
+       g_return_val_if_fail (data != NULL, IMAPX_TOK_ERROR);
+       g_return_val_if_fail (len != NULL, IMAPX_TOK_ERROR);
+
+       if (is->priv->unget > 0) {
+               is->priv->unget--;
+               *data = is->priv->unget_token;
+               *len = is->priv->unget_len;
+               return is->priv->unget_tok;
+       }
+
+       if (is->priv->literal > 0)
+               g_warning (
+                       "stream_token called with literal %d",
+                       is->priv->literal);
+
+       p = is->priv->ptr;
+       e = is->priv->end;
+
+       /* skip whitespace/prefill buffer */
+       do {
+               while (p >= e ) {
+                       is->priv->ptr = p;
+                       if (imapx_input_stream_fill (is, cancellable, error) == IMAPX_TOK_ERROR)
+                               return IMAPX_TOK_ERROR;
+                       p = is->priv->ptr;
+                       e = is->priv->end;
+               }
+               c = *p++;
+       } while (c == ' ' || c == '\r');
+
+       /*strchr("\n*()[]+", c)*/
+       if (imapx_is_token_char (c)) {
+               is->priv->ptr = p;
+               return c;
+       } else if (c == '{') {
+               literal = 0;
+               *data = p;
+               while (1) {
+                       while (p < e) {
+                               c = *p++;
+                               if (isdigit (c) && literal < (UINT_MAX / 10)) {
+                                       literal = literal * 10 + (c - '0');
+                               } else if (c == '}') {
+                                       while (1) {
+                                               while (p < e) {
+                                                       c = *p++;
+                                                       if (c == '\n') {
+                                                               *len = literal;
+                                                               is->priv->ptr = p;
+                                                               is->priv->literal = literal;
+                                                               return IMAPX_TOK_LITERAL;
+                                                       }
+                                               }
+                                               is->priv->ptr = p;
+                                               if (imapx_input_stream_fill (is, cancellable, error) == 
IMAPX_TOK_ERROR)
+                                                       return IMAPX_TOK_ERROR;
+                                               p = is->priv->ptr;
+                                               e = is->priv->end;
+                                       }
+                               } else {
+                                       goto protocol_error;
+                               }
+                       }
+                       is->priv->ptr = p;
+                       if (imapx_input_stream_fill (is, cancellable, error) == IMAPX_TOK_ERROR)
+                               return IMAPX_TOK_ERROR;
+                       p = is->priv->ptr;
+                       e = is->priv->end;
+               }
+       } else if (c == '"') {
+               o = is->priv->tokenbuf;
+               oe = is->priv->tokenbuf + is->priv->bufsize - 1;
+               while (1) {
+                       while (p < e) {
+                               c = *p++;
+                               if (c == '\\') {
+                                       while (p >= e) {
+                                               is->priv->ptr = p;
+                                               if (imapx_input_stream_fill (is, cancellable, error) == 
IMAPX_TOK_ERROR)
+                                                       return IMAPX_TOK_ERROR;
+                                               p = is->priv->ptr;
+                                               e = is->priv->end;
+                                       }
+                                       c = *p++;
+                               } else if (c == '\"') {
+                                       is->priv->ptr = p;
+                                       *o = 0;
+                                       *data = is->priv->tokenbuf;
+                                       *len = o - is->priv->tokenbuf;
+                                       return IMAPX_TOK_STRING;
+                               }
+                               if (c == '\n' || c == '\r')
+                                       goto protocol_error;
+                               if (o >= oe) {
+                                       camel_imapx_input_stream_grow (is, 0, &p, &o);
+                                       oe = is->priv->tokenbuf + is->priv->bufsize - 1;
+                                       e = is->priv->end;
+                               }
+                               *o++ = c;
+                       }
+                       is->priv->ptr = p;
+                       if (imapx_input_stream_fill (is, cancellable, error) == IMAPX_TOK_ERROR)
+                               return IMAPX_TOK_ERROR;
+                       p = is->priv->ptr;
+                       e = is->priv->end;
+               }
+       } else {
+               o = is->priv->tokenbuf;
+               oe = is->priv->tokenbuf + is->priv->bufsize - 1;
+               digits = isdigit (c);
+               *o++ = c;
+               while (1) {
+                       while (p < e) {
+                               c = *p++;
+                               /*if (strchr(" \r\n*()[]+", c) != NULL) {*/
+                               if (imapx_is_notid_char (c)) {
+                                       if (c == ' ' || c == '\r')
+                                               is->priv->ptr = p;
+                                       else
+                                               is->priv->ptr = p - 1;
+                                       *o = 0;
+                                       *data = is->priv->tokenbuf;
+                                       *len = o - is->priv->tokenbuf;
+                                       return digits ? IMAPX_TOK_INT : IMAPX_TOK_TOKEN;
+                               }
+
+                               if (o >= oe) {
+                                       camel_imapx_input_stream_grow (is, 0, &p, &o);
+                                       oe = is->priv->tokenbuf + is->priv->bufsize - 1;
+                                       e = is->priv->end;
+                               }
+                               digits &= isdigit (c);
+                               *o++ = c;
+                       }
+                       is->priv->ptr = p;
+                       if (imapx_input_stream_fill (is, cancellable, error) == IMAPX_TOK_ERROR)
+                               return IMAPX_TOK_ERROR;
+                       p = is->priv->ptr;
+                       e = is->priv->end;
+               }
+       }
+
+protocol_error:
+
+       /* Protocol error, skip until next lf? */
+       if (c == '\n')
+               is->priv->ptr = p - 1;
+       else
+               is->priv->ptr = p;
+
+       g_set_error (error, CAMEL_IMAPX_ERROR, 1, "protocol error");
+
+       return IMAPX_TOK_ERROR;
+}
+
+void
+camel_imapx_input_stream_ungettoken (CamelIMAPXInputStream *is,
+                                     camel_imapx_token_t tok,
+                                     guchar *token,
+                                     guint len)
+{
+       g_return_if_fail (CAMEL_IS_IMAPX_INPUT_STREAM (is));
+
+       is->priv->unget_tok = tok;
+       is->priv->unget_token = token;
+       is->priv->unget_len = len;
+       is->priv->unget++;
+}
+
+/* returns -1 on error, 0 if last lot of data, >0 if more remaining */
+gint
+camel_imapx_input_stream_gets (CamelIMAPXInputStream *is,
+                               guchar **start,
+                               guint *len,
+                               GCancellable *cancellable,
+                               GError **error)
+{
+       gint max;
+       guchar *end;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_INPUT_STREAM (is), -1);
+       g_return_val_if_fail (start != NULL, -1);
+       g_return_val_if_fail (len != NULL, -1);
+
+       *len = 0;
+
+       max = is->priv->end - is->priv->ptr;
+       if (max == 0) {
+               max = imapx_input_stream_fill (is, cancellable, error);
+               if (max <= 0)
+                       return max;
+       }
+
+       *start = is->priv->ptr;
+       end = memchr (is->priv->ptr, '\n', max);
+       if (end)
+               max = (end - is->priv->ptr) + 1;
+       *start = is->priv->ptr;
+       *len = max;
+       is->priv->ptr += max;
+
+       return end == NULL ? 1 : 0;
+}
+
+void
+camel_imapx_input_stream_set_literal (CamelIMAPXInputStream *is,
+                                      guint literal)
+{
+       g_return_if_fail (CAMEL_IS_IMAPX_INPUT_STREAM (is));
+
+       is->priv->literal = literal;
+}
+
+/* returns -1 on erorr, 0 if last data, >0 if more data left */
+gint
+camel_imapx_input_stream_getl (CamelIMAPXInputStream *is,
+                               guchar **start,
+                               guint *len,
+                               GCancellable *cancellable,
+                               GError **error)
+{
+       gint max;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_INPUT_STREAM (is), -1);
+       g_return_val_if_fail (start != NULL, -1);
+       g_return_val_if_fail (len != NULL, -1);
+
+       *len = 0;
+
+       if (is->priv->literal > 0) {
+               max = is->priv->end - is->priv->ptr;
+               if (max == 0) {
+                       max = imapx_input_stream_fill (is, cancellable, error);
+                       if (max <= 0)
+                               return max;
+               }
+
+               max = MIN (max, is->priv->literal);
+               *start = is->priv->ptr;
+               *len = max;
+               is->priv->ptr += max;
+               is->priv->literal -= max;
+       }
+
+       if (is->priv->literal > 0)
+               return 1;
+
+       return 0;
+}
+
+/* skip the rest of the line of tokens */
+gboolean
+camel_imapx_input_stream_skip (CamelIMAPXInputStream *is,
+                               GCancellable *cancellable,
+                               GError **error)
+{
+       camel_imapx_token_t tok;
+       guchar *token;
+       guint len;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_INPUT_STREAM (is), FALSE);
+
+       do {
+               tok = camel_imapx_input_stream_token (
+                       is, &token, &len, cancellable, error);
+
+               if (tok == IMAPX_TOK_ERROR)
+                       return FALSE;
+
+               if (tok == IMAPX_TOK_LITERAL) {
+                       camel_imapx_input_stream_set_literal (is, len);
+                       do {
+                               tok = camel_imapx_input_stream_getl (
+                                       is, &token, &len, cancellable, error);
+                       } while (tok > 0);
+               }
+       } while (tok != '\n' && tok >= 0);
+
+       return (tok != IMAPX_TOK_ERROR);
+}
+
+gboolean
+camel_imapx_input_stream_skip_until (CamelIMAPXInputStream *is,
+                                     const gchar *delimiters,
+                                     GCancellable *cancellable,
+                                     GError **error)
+{
+       register guchar c;
+       guchar *p, *e;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_INPUT_STREAM (is), FALSE);
+
+       if (is->priv->unget > 0) {
+               is->priv->unget--;
+               return TRUE;
+       }
+
+       if (is->priv->literal > 0) {
+               is->priv->literal--;
+               return TRUE;
+       }
+
+       p = is->priv->ptr;
+       e = is->priv->end;
+
+       do {
+               while (p >= e ) {
+                       is->priv->ptr = p;
+                       if (imapx_input_stream_fill (is, cancellable, error) == IMAPX_TOK_ERROR)
+                               return FALSE;
+                       p = is->priv->ptr;
+                       e = is->priv->end;
+               }
+               c = *p++;
+       } while (c && c != ' ' && c != '\r' && c != '\n' && (!delimiters || !strchr (delimiters, c)));
+
+       is->priv->ptr = p;
+
+       return TRUE;
+}
diff --git a/camel/providers/imapx/camel-imapx-input-stream.h 
b/camel/providers/imapx/camel-imapx-input-stream.h
new file mode 100644
index 0000000..50afcf0
--- /dev/null
+++ b/camel/providers/imapx/camel-imapx-input-stream.h
@@ -0,0 +1,158 @@
+/*
+ * camel-imapx-input-stream.h
+ *
+ * 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.
+ *
+ * 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 General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef CAMEL_IMAPX_INPUT_STREAM_H
+#define CAMEL_IMAPX_INPUT_STREAM_H
+
+#include <gio/gio.h>
+
+/* XXX temporary */
+#include "camel-imapx-stream.h"
+
+/* Standard GObject macros */
+#define CAMEL_TYPE_IMAPX_INPUT_STREAM \
+       (camel_imapx_input_stream_get_type ())
+#define CAMEL_IMAPX_INPUT_STREAM(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), CAMEL_TYPE_IMAPX_INPUT_STREAM, CamelIMAPXInputStream))
+#define CAMEL_IMAPX_INPUT_STREAM_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), CAMEL_TYPE_IMAPX_INPUT_STREAM, CamelIMAPXInputStreamClass))
+#define CAMEL_IS_IMAPX_INPUT_STREAM(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), CAMEL_TYPE_IMAPX_INPUT_STREAM))
+#define CAMEL_IS_IMAPX_INPUT_STREAM_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((cls), CAMEL_TYPE_IMAPX_INPUT_STREAM))
+#define CAMEL_IMAPX_INPUT_STREAM_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS \
+       ((obj), CAMEL_TYPE_IMAPX_INPUT_STREAM, CamelIMAPXInputStreamClass))
+
+#define CAMEL_IMAPX_ERROR \
+       (camel_imapx_error_quark ())
+
+G_BEGIN_DECLS
+
+typedef struct _CamelIMAPXInputStream CamelIMAPXInputStream;
+typedef struct _CamelIMAPXInputStreamClass CamelIMAPXInputStreamClass;
+typedef struct _CamelIMAPXInputStreamPrivate CamelIMAPXInputStreamPrivate;
+
+#if 0
+typedef enum {
+       IMAPX_TOK_ERROR = -1,
+       IMAPX_TOK_TOKEN = 256,
+       IMAPX_TOK_STRING,
+       IMAPX_TOK_INT,
+       IMAPX_TOK_LITERAL,
+} camel_imapx_token_t;
+#endif
+
+struct _CamelIMAPXInputStream {
+       GFilterInputStream parent;
+       CamelIMAPXInputStreamPrivate *priv;
+};
+
+struct _CamelIMAPXInputStreamClass {
+       GFilterInputStreamClass parent_class;
+};
+
+#if 0
+GQuark         camel_imapx_error_quark         (void) G_GNUC_CONST;
+#endif
+GType          camel_imapx_input_stream_get_type
+                                               (void) G_GNUC_CONST;
+GInputStream * camel_imapx_input_stream_new    (GInputStream *base_stream);
+gint           camel_imapx_input_stream_buffered
+                                               (CamelIMAPXInputStream *is);
+
+camel_imapx_token_t
+               camel_imapx_input_stream_token  (CamelIMAPXInputStream *is,
+                                                guchar **start,
+                                                guint *len,
+                                                GCancellable *cancellable,
+                                                GError **error);
+
+void           camel_imapx_input_stream_ungettoken
+                                               (CamelIMAPXInputStream *is,
+                                                camel_imapx_token_t tok,
+                                                guchar *token,
+                                                guint len);
+void           camel_imapx_input_stream_set_literal
+                                               (CamelIMAPXInputStream *is,
+                                                guint literal);
+gint           camel_imapx_input_stream_gets   (CamelIMAPXInputStream *is,
+                                                guchar **start,
+                                                guint *len,
+                                                GCancellable *cancellable,
+                                                GError **error);
+gint            camel_imapx_input_stream_getl  (CamelIMAPXInputStream *is,
+                                                guchar **start,
+                                                guint *len,
+                                                GCancellable *cancellable,
+                                                GError **error);
+
+/* gets an atom, upper-cases */
+gboolean       camel_imapx_input_stream_atom   (CamelIMAPXInputStream *is,
+                                                guchar **start,
+                                                guint *len,
+                                                GCancellable *cancellable,
+                                                GError **error);
+/* gets an atom or string */
+gboolean       camel_imapx_input_stream_astring
+                                               (CamelIMAPXInputStream *is,
+                                                guchar **start,
+                                                GCancellable *cancellable,
+                                                GError **error);
+/* gets a NIL or a string, start==NULL if NIL */
+gboolean       camel_imapx_input_stream_nstring
+                                               (CamelIMAPXInputStream *is,
+                                                guchar **start,
+                                                GCancellable *cancellable,
+                                                GError **error);
+/* gets a NIL or string into a GBytes, bytes==NULL if NIL */
+gboolean       camel_imapx_input_stream_nstring_bytes
+                                               (CamelIMAPXInputStream *is,
+                                                GBytes **out_bytes,
+                                                GCancellable *cancellable,
+                                                GError **error);
+/* gets 'text' */
+gboolean       camel_imapx_input_stream_text   (CamelIMAPXInputStream *is,
+                                                guchar **text,
+                                                GCancellable *cancellable,
+                                                GError **error);
+
+/* gets a 'number' */
+gboolean        camel_imapx_input_stream_number
+                                               (CamelIMAPXInputStream *is,
+                                                guint64 *number,
+                                                GCancellable *cancellable,
+                                                GError **error);
+
+/* skips the rest of a line, including literals, etc */
+gboolean       camel_imapx_input_stream_skip   (CamelIMAPXInputStream *is,
+                                                GCancellable *cancellable,
+                                                GError **error);
+
+gboolean       camel_imapx_input_stream_skip_until
+                                               (CamelIMAPXInputStream *is,
+                                                const gchar *delimiters,
+                                                GCancellable *cancellable,
+                                                GError **error);
+
+G_END_DECLS
+
+#endif /* CAMEL_IMAPX_INPUT_STREAM_H */
diff --git a/camel/providers/imapx/camel-imapx-list-response.c 
b/camel/providers/imapx/camel-imapx-list-response.c
index 9a04bee..f4ee92d 100644
--- a/camel/providers/imapx/camel-imapx-list-response.c
+++ b/camel/providers/imapx/camel-imapx-list-response.c
@@ -131,7 +131,7 @@ camel_imapx_list_response_init (CamelIMAPXListResponse *response)
 
 /* Helper for camel_imapx_list_response_new() */
 static GVariant *
-imapx_list_response_parse_childinfo (CamelIMAPXStream *stream,
+imapx_list_response_parse_childinfo (CamelIMAPXInputStream *stream,
                                      CamelIMAPXListResponse *response,
                                      GCancellable *cancellable,
                                      GError **error)
@@ -141,10 +141,11 @@ imapx_list_response_parse_childinfo (CamelIMAPXStream *stream,
        camel_imapx_token_t tok;
        guchar *token;
        guint len;
+       gboolean success;
 
        g_variant_builder_init (&builder, G_VARIANT_TYPE_STRING_ARRAY);
 
-       tok = camel_imapx_stream_token (
+       tok = camel_imapx_input_stream_token (
                stream, &token, &len, cancellable, error);
        if (tok == IMAPX_TOK_ERROR)
                goto fail;
@@ -156,18 +157,21 @@ imapx_list_response_parse_childinfo (CamelIMAPXStream *stream,
        }
 
 repeat:
-       if (!camel_imapx_stream_astring (stream, &token, cancellable, error))
+       success = camel_imapx_input_stream_astring (
+               stream, &token, cancellable, error);
+
+       if (!success)
                goto fail;
 
        value = g_variant_new_string ((gchar *) token);
        g_variant_builder_add_value (&builder, value);
 
-       tok = camel_imapx_stream_token (
+       tok = camel_imapx_input_stream_token (
                stream, &token, &len, cancellable, error);
        if (tok == IMAPX_TOK_ERROR)
                goto fail;
        if (tok != ')') {
-               camel_imapx_stream_ungettoken (stream, tok, token, len);
+               camel_imapx_input_stream_ungettoken (stream, tok, token, len);
                goto repeat;
        }
 
@@ -181,7 +185,7 @@ fail:
 
 /* Helper for camel_imapx_list_response_new() */
 static GVariant *
-imapx_list_response_parse_oldname (CamelIMAPXStream *stream,
+imapx_list_response_parse_oldname (CamelIMAPXInputStream *stream,
                                    CamelIMAPXListResponse *response,
                                    GCancellable *cancellable,
                                    GError **error)
@@ -191,7 +195,7 @@ imapx_list_response_parse_oldname (CamelIMAPXStream *stream,
        guint len;
        gchar *mailbox_name = NULL;
 
-       tok = camel_imapx_stream_token (
+       tok = camel_imapx_input_stream_token (
                stream, &token, &len, cancellable, error);
        if (tok == IMAPX_TOK_ERROR)
                goto fail;
@@ -208,7 +212,7 @@ imapx_list_response_parse_oldname (CamelIMAPXStream *stream,
        if (mailbox_name == NULL)
                goto fail;
 
-       tok = camel_imapx_stream_token (
+       tok = camel_imapx_input_stream_token (
                stream, &token, &len, cancellable, error);
        if (tok == IMAPX_TOK_ERROR)
                goto fail;
@@ -229,7 +233,7 @@ fail:
 
 /* Helper for camel_imapx_list_response_new() */
 static gboolean
-imapx_list_response_parse_extended_item (CamelIMAPXStream *stream,
+imapx_list_response_parse_extended_item (CamelIMAPXInputStream *stream,
                                          CamelIMAPXListResponse *response,
                                          GCancellable *cancellable,
                                          GError **error)
@@ -241,7 +245,10 @@ imapx_list_response_parse_extended_item (CamelIMAPXStream *stream,
 
        /* Parse the extended item tag. */
 
-       if (!camel_imapx_stream_astring (stream, &token, cancellable, error))
+       success = camel_imapx_input_stream_astring (
+               stream, &token, cancellable, error);
+
+       if (!success)
                return FALSE;
 
        item_tag = g_strdup ((gchar *) token);
@@ -268,7 +275,7 @@ imapx_list_response_parse_extended_item (CamelIMAPXStream *stream,
                success = (item_value != NULL);
 
        } else {
-               success = camel_imapx_stream_skip_until (
+               success = camel_imapx_input_stream_skip_until (
                        stream, ")", cancellable, error);
        }
 
@@ -286,7 +293,7 @@ imapx_list_response_parse_extended_item (CamelIMAPXStream *stream,
 
 /**
  * camel_imapx_list_response_new:
- * @stream: a #CamelIMAPXStream
+ * @stream: a #CamelIMAPXInputStream
  * @cancellable: a #GCancellable
  * @error: return location for a #GError, or %NULL
  *
@@ -299,7 +306,7 @@ imapx_list_response_parse_extended_item (CamelIMAPXStream *stream,
  * Since: 3.10
  **/
 CamelIMAPXListResponse *
-camel_imapx_list_response_new (CamelIMAPXStream *stream,
+camel_imapx_list_response_new (CamelIMAPXInputStream *stream,
                                GCancellable *cancellable,
                                GError **error)
 {
@@ -308,14 +315,15 @@ camel_imapx_list_response_new (CamelIMAPXStream *stream,
        guchar *token;
        guint len;
        const gchar *attribute;
+       gboolean success;
 
-       g_return_val_if_fail (CAMEL_IS_IMAPX_STREAM (stream), NULL);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_INPUT_STREAM (stream), NULL);
 
        response = g_object_new (CAMEL_TYPE_IMAPX_LIST_RESPONSE, NULL);
 
        /* Parse attributes. */
 
-       tok = camel_imapx_stream_token (
+       tok = camel_imapx_input_stream_token (
                stream, &token, &len, cancellable, error);
        if (tok == IMAPX_TOK_ERROR)
                goto fail;
@@ -326,12 +334,12 @@ camel_imapx_list_response_new (CamelIMAPXStream *stream,
                goto fail;
        }
 
-       tok = camel_imapx_stream_token (
+       tok = camel_imapx_input_stream_token (
                stream, &token, &len, cancellable, error);
        while (tok == IMAPX_TOK_STRING || tok == IMAPX_TOK_TOKEN) {
                camel_imapx_list_response_add_attribute (
                        response, (gchar *) token);
-               tok = camel_imapx_stream_token (
+               tok = camel_imapx_input_stream_token (
                        stream, &token, &len, cancellable, error);
        }
 
@@ -362,7 +370,10 @@ camel_imapx_list_response_new (CamelIMAPXStream *stream,
 
        /* Parse separator. */
 
-       if (!camel_imapx_stream_nstring (stream, &token, cancellable, error))
+       success = camel_imapx_input_stream_nstring (
+               stream, &token, cancellable, error);
+
+       if (!success)
                goto fail;
 
        if (token != NULL)
@@ -379,7 +390,7 @@ camel_imapx_list_response_new (CamelIMAPXStream *stream,
 
        /* Parse extended info (optional). */
 
-       tok = camel_imapx_stream_token (
+       tok = camel_imapx_input_stream_token (
                stream, &token, &len, cancellable, error);
        if (tok == IMAPX_TOK_ERROR)
                goto fail;
@@ -392,18 +403,18 @@ extended_item_repeat:
                if (!success)
                        goto fail;
 
-               tok = camel_imapx_stream_token (
+               tok = camel_imapx_input_stream_token (
                        stream, &token, &len, cancellable, error);
                if (tok == IMAPX_TOK_ERROR)
                        goto fail;
                if (tok != ')') {
-                       camel_imapx_stream_ungettoken (
+                       camel_imapx_input_stream_ungettoken (
                                stream, tok, token, len);
                        goto extended_item_repeat;
                }
 
        } else if (tok == '\n') {
-               camel_imapx_stream_ungettoken (stream, tok, token, len);
+               camel_imapx_input_stream_ungettoken (stream, tok, token, len);
 
        } else {
                g_set_error (
diff --git a/camel/providers/imapx/camel-imapx-list-response.h 
b/camel/providers/imapx/camel-imapx-list-response.h
index 59441b1..34de109 100644
--- a/camel/providers/imapx/camel-imapx-list-response.h
+++ b/camel/providers/imapx/camel-imapx-list-response.h
@@ -20,7 +20,7 @@
 
 #include <gio/gio.h>
 
-#include "camel-imapx-stream.h"
+#include "camel-imapx-input-stream.h"
 
 /* Standard GObject macros */
 #define CAMEL_TYPE_IMAPX_LIST_RESPONSE \
@@ -90,7 +90,7 @@ GType         camel_imapx_list_response_get_type
                                        (void) G_GNUC_CONST;
 CamelIMAPXListResponse *
                camel_imapx_list_response_new
-                                       (CamelIMAPXStream *stream,
+                                       (CamelIMAPXInputStream *stream,
                                         GCancellable *cancellable,
                                         GError **error);
 guint          camel_imapx_list_response_hash
diff --git a/camel/providers/imapx/camel-imapx-namespace-response.c 
b/camel/providers/imapx/camel-imapx-namespace-response.c
index 3018412..3295d10 100644
--- a/camel/providers/imapx/camel-imapx-namespace-response.c
+++ b/camel/providers/imapx/camel-imapx-namespace-response.c
@@ -91,7 +91,7 @@ camel_imapx_namespace_response_init (CamelIMAPXNamespaceResponse *response)
 }
 
 static gboolean
-imapx_namespace_response_parse_namespace (CamelIMAPXStream *stream,
+imapx_namespace_response_parse_namespace (CamelIMAPXInputStream *stream,
                                           CamelIMAPXNamespaceResponse *response,
                                           CamelIMAPXNamespaceCategory category,
                                           GCancellable *cancellable,
@@ -102,8 +102,9 @@ imapx_namespace_response_parse_namespace (CamelIMAPXStream *stream,
        guint len;
        gchar *prefix;
        gchar separator;
+       gboolean success;
 
-       tok = camel_imapx_stream_token (
+       tok = camel_imapx_input_stream_token (
                stream, &token, &len, cancellable, error);
        if (tok == IMAPX_TOK_ERROR)
                return FALSE;
@@ -122,7 +123,7 @@ imapx_namespace_response_parse_namespace (CamelIMAPXStream *stream,
        }
 
 repeat:
-       tok = camel_imapx_stream_token (
+       tok = camel_imapx_input_stream_token (
                stream, &token, &len, cancellable, error);
        if (tok == IMAPX_TOK_ERROR)
                return FALSE;
@@ -133,7 +134,7 @@ repeat:
                return FALSE;
        }
 
-       tok = camel_imapx_stream_token (
+       tok = camel_imapx_input_stream_token (
                stream, &token, &len, cancellable, error);
        if (tok == IMAPX_TOK_ERROR)
                return FALSE;
@@ -146,7 +147,10 @@ repeat:
 
        prefix = g_strdup ((gchar *) token);
 
-       if (!camel_imapx_stream_nstring (stream, &token, cancellable, error)) {
+       success = camel_imapx_input_stream_nstring (
+               stream, &token, cancellable, error);
+
+       if (!success) {
                g_free (prefix);
                return FALSE;
        }
@@ -159,7 +163,7 @@ repeat:
 
        /* FIXME Parse any namespace response extensions. */
 
-       tok = camel_imapx_stream_token (
+       tok = camel_imapx_input_stream_token (
                stream, &token, &len, cancellable, error);
        if (tok == IMAPX_TOK_ERROR)
                return FALSE;
@@ -170,12 +174,12 @@ repeat:
                return FALSE;
        }
 
-       tok = camel_imapx_stream_token (
+       tok = camel_imapx_input_stream_token (
                stream, &token, &len, cancellable, error);
        if (tok == IMAPX_TOK_ERROR)
                return FALSE;
        if (tok == '(') {
-               camel_imapx_stream_ungettoken (stream, tok, token, len);
+               camel_imapx_input_stream_ungettoken (stream, tok, token, len);
                goto repeat;
        }
        if (tok != ')') {
@@ -190,7 +194,7 @@ repeat:
 
 /**
  * camel_imapx_namespace_response_new:
- * @stream: a #CamelIMAPXStream
+ * @stream: a #CamelIMAPXInputStream
  * @cancellable: optional #GCancellable object, or %NULL
  * @error: return location for a #GError, or %NULL
  *
@@ -203,14 +207,14 @@ repeat:
  * Since: 3.12
  **/
 CamelIMAPXNamespaceResponse *
-camel_imapx_namespace_response_new (CamelIMAPXStream *stream,
+camel_imapx_namespace_response_new (CamelIMAPXInputStream *stream,
                                     GCancellable *cancellable,
                                     GError **error)
 {
        CamelIMAPXNamespaceResponse *response;
        gint ii;
 
-       g_return_val_if_fail (CAMEL_IS_IMAPX_STREAM (stream), NULL);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_INPUT_STREAM (stream), NULL);
 
        response = g_object_new (CAMEL_TYPE_IMAPX_NAMESPACE_RESPONSE, NULL);
 
@@ -239,7 +243,7 @@ camel_imapx_namespace_response_new (CamelIMAPXStream *stream,
        }
 
        /* Eat the newline. */
-       if (!camel_imapx_stream_skip (stream, cancellable, error))
+       if (!camel_imapx_input_stream_skip (stream, cancellable, error))
                goto fail;
 
        return response;
diff --git a/camel/providers/imapx/camel-imapx-namespace-response.h 
b/camel/providers/imapx/camel-imapx-namespace-response.h
index becae59..9b5e0e0 100644
--- a/camel/providers/imapx/camel-imapx-namespace-response.h
+++ b/camel/providers/imapx/camel-imapx-namespace-response.h
@@ -67,7 +67,7 @@ GType         camel_imapx_namespace_response_get_type
                                        (void) G_GNUC_CONST;
 CamelIMAPXNamespaceResponse *
                camel_imapx_namespace_response_new
-                                       (CamelIMAPXStream *stream,
+                                       (CamelIMAPXInputStream *stream,
                                         GCancellable *cancellable,
                                         GError **error);
 CamelIMAPXNamespaceResponse *
diff --git a/camel/providers/imapx/camel-imapx-server.c b/camel/providers/imapx/camel-imapx-server.c
index fa7bb17..1661b27 100644
--- a/camel/providers/imapx/camel-imapx-server.c
+++ b/camel/providers/imapx/camel-imapx-server.c
@@ -38,13 +38,12 @@
 
 #include "camel-imapx-server.h"
 
-#include "camel-imapx-command.h"
 #include "camel-imapx-folder.h"
+#include "camel-imapx-input-stream.h"
 #include "camel-imapx-job.h"
 #include "camel-imapx-logger.h"
 #include "camel-imapx-settings.h"
 #include "camel-imapx-store.h"
-#include "camel-imapx-stream.h"
 #include "camel-imapx-summary.h"
 #include "camel-imapx-utils.h"
 
@@ -195,71 +194,71 @@ struct _CamelIMAPXServerUntaggedContext {
 
 /* internal untagged handler prototypes */
 static gboolean        imapx_untagged_bye              (CamelIMAPXServer *is,
-                                                CamelIMAPXStream *stream,
+                                                GInputStream *input_stream,
                                                 GCancellable *cancellable,
                                                 GError **error);
 static gboolean        imapx_untagged_capability       (CamelIMAPXServer *is,
-                                                CamelIMAPXStream *stream,
+                                                GInputStream *input_stream,
                                                 GCancellable *cancellable,
                                                 GError **error);
 static gboolean        imapx_untagged_exists           (CamelIMAPXServer *is,
-                                                CamelIMAPXStream *stream,
+                                                GInputStream *input_stream,
                                                 GCancellable *cancellable,
                                                 GError **error);
 static gboolean        imapx_untagged_expunge          (CamelIMAPXServer *is,
-                                                CamelIMAPXStream *stream,
+                                                GInputStream *input_stream,
                                                 GCancellable *cancellable,
                                                 GError **error);
 static gboolean        imapx_untagged_fetch            (CamelIMAPXServer *is,
-                                                CamelIMAPXStream *stream,
+                                                GInputStream *input_stream,
                                                 GCancellable *cancellable,
                                                 GError **error);
 static gboolean        imapx_untagged_flags            (CamelIMAPXServer *is,
-                                                CamelIMAPXStream *stream,
+                                                GInputStream *input_stream,
                                                 GCancellable *cancellable,
                                                 GError **error);
 static gboolean        imapx_untagged_list             (CamelIMAPXServer *is,
-                                                CamelIMAPXStream *stream,
+                                                GInputStream *input_stream,
                                                 GCancellable *cancellable,
                                                 GError **error);
 static gboolean        imapx_untagged_lsub             (CamelIMAPXServer *is,
-                                                CamelIMAPXStream *stream,
+                                                GInputStream *input_stream,
                                                 GCancellable *cancellable,
                                                 GError **error);
 static gboolean        imapx_untagged_namespace        (CamelIMAPXServer *is,
-                                                CamelIMAPXStream *stream,
+                                                GInputStream *input_stream,
                                                 GCancellable *cancellable,
                                                 GError **error);
 static gboolean        imapx_untagged_ok_no_bad        (CamelIMAPXServer *is,
-                                                CamelIMAPXStream *stream,
+                                                GInputStream *input_stream,
                                                 GCancellable *cancellable,
                                                 GError **error);
 static gboolean        imapx_untagged_preauth          (CamelIMAPXServer *is,
-                                                CamelIMAPXStream *stream,
+                                                GInputStream *input_stream,
                                                 GCancellable *cancellable,
                                                 GError **error);
 static gboolean        imapx_untagged_quota            (CamelIMAPXServer *is,
-                                                CamelIMAPXStream *stream,
+                                                GInputStream *input_stream,
                                                 GCancellable *cancellable,
                                                 GError **error);
 static gboolean        imapx_untagged_quotaroot        (CamelIMAPXServer *is,
-                                                CamelIMAPXStream *stream,
+                                                GInputStream *input_stream,
                                                 GCancellable *cancellable,
                                                 GError **error);
 static gboolean        imapx_untagged_recent           (CamelIMAPXServer *is,
-                                                CamelIMAPXStream *stream,
+                                                GInputStream *input_stream,
                                                 GCancellable *cancellable,
                                                 GError **error);
 static gboolean        imapx_untagged_search           (CamelIMAPXServer *is,
-                                                CamelIMAPXStream *stream,
+                                                GInputStream *input_stream,
                                                 GCancellable *cancellable,
                                                 GError **error);
 static gboolean        imapx_untagged_status           (CamelIMAPXServer *is,
-                                                CamelIMAPXStream *stream,
+                                                GInputStream *input_stream,
                                                 GCancellable *cancellable,
                                                 GError **error);
 static gboolean        imapx_untagged_vanished         (CamelIMAPXServer *is,
-                                                CamelIMAPXStream *stream,
+                                                GInputStream *input_stream,
                                                 GCancellable *cancellable,
                                                 GError **error);
 
@@ -335,9 +334,9 @@ struct _CamelIMAPXServerPrivate {
        GHashTable *untagged_handlers;
 
        /* The 'stream_lock' also guards the GSubprocess. */
-       CamelIMAPXStream *stream;
        GInputStream *input_stream;
        GOutputStream *output_stream;
+       GIOStream *connection;
 #if GLIB_CHECK_VERSION(2,39,0)
        GSubprocess *subprocess;
 #endif
@@ -400,7 +399,6 @@ struct _CamelIMAPXServerPrivate {
 enum {
        PROP_0,
        PROP_NAMESPACES,
-       PROP_STREAM,
        PROP_STORE
 };
 
@@ -425,15 +423,14 @@ static gint       imapx_uidset_add                (struct _uidset_state *ss,
                                                 const gchar *uid);
 
 static gboolean        imapx_command_idle_stop         (CamelIMAPXServer *is,
-                                                GOutputStream *output_stream,
                                                 GError **error);
 static gboolean        imapx_continuation              (CamelIMAPXServer *is,
-                                                CamelIMAPXStream *stream,
+                                                GInputStream *input_stream,
                                                 GOutputStream *output_stream,
                                                 gboolean litplus,
                                                 GCancellable *cancellable,
                                                 GError **error);
-static gboolean        imapx_disconnect                (CamelIMAPXServer *is);
+static void    imapx_disconnect                (CamelIMAPXServer *is);
 static gboolean        imapx_is_command_queue_empty    (CamelIMAPXServer *is);
 static gint    imapx_uid_cmp                   (gconstpointer ap,
                                                 gconstpointer bp,
@@ -537,7 +534,6 @@ static gboolean     imapx_use_idle          (CamelIMAPXServer *is);
 static void    imapx_start_idle                (CamelIMAPXServer *is);
 static CamelIMAPXIdleStopResult
                imapx_stop_idle                 (CamelIMAPXServer *is,
-                                                GOutputStream *output_stream,
                                                 GError **error);
 static gboolean        camel_imapx_server_idle         (CamelIMAPXServer *is,
                                                 CamelIMAPXMailbox *mailbox,
@@ -960,27 +956,19 @@ imapx_server_inactivity_timeout_cb (gpointer data)
                /* Do nothing. */
 
        } else if (imapx_in_idle (is)) {
-               GOutputStream *output_stream;
 
                /* Stop and restart the IDLE command. */
+               switch (imapx_stop_idle (is, NULL)) {
+                       case IMAPX_IDLE_STOP_SUCCESS:
+                               imapx_start_idle (is);
+                               /* fall through */
 
-               output_stream = camel_imapx_server_ref_output_stream (is);
-
-               if (output_stream != NULL) {
-                       switch (imapx_stop_idle (is, output_stream, NULL)) {
-                               case IMAPX_IDLE_STOP_SUCCESS:
-                                       imapx_start_idle (is);
-                                       /* fall through */
-
-                               case IMAPX_IDLE_STOP_NOOP:
-                                       result = G_SOURCE_CONTINUE;
-                                       break;
-
-                               default:
-                                       break;
-                       }
+                       case IMAPX_IDLE_STOP_NOOP:
+                               result = G_SOURCE_CONTINUE;
+                               break;
 
-                       g_object_unref (output_stream);
+                       default:
+                               break;
                }
 
        } else {
@@ -1270,8 +1258,8 @@ static void
 imapx_command_start (CamelIMAPXServer *is,
                      CamelIMAPXCommand *ic)
 {
-       CamelIMAPXStream *stream;
        CamelIMAPXCommandPart *cp;
+       GInputStream *input_stream;
        GOutputStream *output_stream;
        GCancellable *cancellable;
        gboolean cp_continuation;
@@ -1298,11 +1286,11 @@ imapx_command_start (CamelIMAPXServer *is,
 
        camel_imapx_command_queue_push_tail (is->active, ic);
 
-       stream = camel_imapx_server_ref_stream (is);
+       input_stream = camel_imapx_server_ref_input_stream (is);
        output_stream = camel_imapx_server_ref_output_stream (is);
        cancellable = g_weak_ref_get (&is->priv->parser_cancellable);
 
-       if (stream == NULL) {
+       if (output_stream == NULL) {
                local_error = g_error_new_literal (
                        CAMEL_IMAPX_ERROR, 1,
                        "Cannot issue command, no stream available");
@@ -1332,7 +1320,7 @@ imapx_command_start (CamelIMAPXServer *is,
        while (is->literal == ic && cp_literal_plus) {
                /* Sent LITERAL+ continuation immediately */
                imapx_continuation (
-                       is, stream, output_stream,
+                       is, input_stream, output_stream,
                        TRUE, cancellable, &local_error);
                if (local_error != NULL)
                        goto fail;
@@ -1358,7 +1346,7 @@ fail:
        g_error_free (local_error);
 
 exit:
-       g_clear_object (&stream);
+       g_clear_object (&input_stream);
        g_clear_object (&output_stream);
        g_clear_object (&cancellable);
 }
@@ -1509,21 +1497,7 @@ imapx_command_start_next (CamelIMAPXServer *is)
                        imapx_is_command_queue_empty (is);
 
                if (stop_idle) {
-                       GOutputStream *output_stream;
-                       CamelIMAPXIdleStopResult stop_result;
-
-                       stop_result = IMAPX_IDLE_STOP_NOOP;
-
-                       output_stream =
-                               camel_imapx_server_ref_output_stream (is);
-
-                       if (output_stream != NULL) {
-                               stop_result = imapx_stop_idle (
-                                       is, output_stream, NULL);
-                               g_object_unref (output_stream);
-                       }
-
-                       switch (stop_result) {
+                       switch (imapx_stop_idle (is, NULL)) {
                                /* Proceed with the next queued command. */
                                case IMAPX_IDLE_STOP_NOOP:
                                        break;
@@ -1934,7 +1908,7 @@ imapx_expunge_uid_from_summary (CamelIMAPXServer *is,
 
 static gboolean
 imapx_untagged_capability (CamelIMAPXServer *is,
-                           CamelIMAPXStream *stream,
+                           GInputStream *input_stream,
                            GCancellable *cancellable,
                            GError **error)
 {
@@ -1943,7 +1917,9 @@ imapx_untagged_capability (CamelIMAPXServer *is,
        if (is->cinfo != NULL)
                imapx_free_capability (is->cinfo);
 
-       is->cinfo = imapx_parse_capability (stream, cancellable, error);
+       is->cinfo = imapx_parse_capability (
+               CAMEL_IMAPX_INPUT_STREAM (input_stream), cancellable, error);
+
        if (is->cinfo == NULL)
                return FALSE;
 
@@ -1956,7 +1932,7 @@ imapx_untagged_capability (CamelIMAPXServer *is,
 
 static gboolean
 imapx_untagged_expunge (CamelIMAPXServer *is,
-                        CamelIMAPXStream *stream,
+                        GInputStream *input_stream,
                         GCancellable *cancellable,
                         GError **error)
 {
@@ -1999,7 +1975,7 @@ imapx_untagged_expunge (CamelIMAPXServer *is,
 
 static gboolean
 imapx_untagged_vanished (CamelIMAPXServer *is,
-                         CamelIMAPXStream *stream,
+                         GInputStream *input_stream,
                          GCancellable *cancellable,
                          GError **error)
 {
@@ -2015,24 +1991,29 @@ imapx_untagged_vanished (CamelIMAPXServer *is,
 
        g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
 
-       tok = camel_imapx_stream_token (
-               stream, &token, &len, cancellable, error);
+       tok = camel_imapx_input_stream_token (
+               CAMEL_IMAPX_INPUT_STREAM (input_stream),
+               &token, &len, cancellable, error);
        if (tok < 0)
                return FALSE;
        if (tok == '(') {
                unsolicited = FALSE;
                while (tok != ')') {
                        /* We expect this to be 'EARLIER' */
-                       tok = camel_imapx_stream_token (
-                               stream, &token, &len, cancellable, error);
+                       tok = camel_imapx_input_stream_token (
+                               CAMEL_IMAPX_INPUT_STREAM (input_stream),
+                               &token, &len, cancellable, error);
                        if (tok < 0)
                                return FALSE;
                }
        } else {
-               camel_imapx_stream_ungettoken (stream, tok, token, len);
+               camel_imapx_input_stream_ungettoken (
+                       CAMEL_IMAPX_INPUT_STREAM (input_stream),
+                       tok, token, len);
        }
 
-       uids = imapx_parse_uids (stream, cancellable, error);
+       uids = imapx_parse_uids (
+               CAMEL_IMAPX_INPUT_STREAM (input_stream), cancellable, error);
        if (uids == NULL)
                return FALSE;
 
@@ -2100,7 +2081,7 @@ imapx_untagged_vanished (CamelIMAPXServer *is,
 
 static gboolean
 imapx_untagged_namespace (CamelIMAPXServer *is,
-                          CamelIMAPXStream *stream,
+                          GInputStream *input_stream,
                           GCancellable *cancellable,
                           GError **error)
 {
@@ -2109,7 +2090,8 @@ imapx_untagged_namespace (CamelIMAPXServer *is,
        g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
 
        response = camel_imapx_namespace_response_new (
-               stream, cancellable, error);
+               CAMEL_IMAPX_INPUT_STREAM (input_stream), cancellable, error);
+
        if (response == NULL)
                return FALSE;
 
@@ -2127,7 +2109,7 @@ imapx_untagged_namespace (CamelIMAPXServer *is,
 
 static gboolean
 imapx_untagged_exists (CamelIMAPXServer *is,
-                       CamelIMAPXStream *stream,
+                       GInputStream *input_stream,
                        GCancellable *cancellable,
                        GError **error)
 {
@@ -2157,20 +2139,9 @@ imapx_untagged_exists (CamelIMAPXServer *is,
 
                count = camel_folder_summary_count (folder->summary);
                if (count < exists) {
-                       GOutputStream *output_stream;
                        CamelIMAPXIdleStopResult stop_result;
 
-                       stop_result = IMAPX_IDLE_STOP_NOOP;
-
-                       output_stream =
-                               camel_imapx_server_ref_output_stream (is);
-
-                       if (output_stream != NULL) {
-                               stop_result = imapx_stop_idle (
-                                       is, output_stream, error);
-                               g_object_unref (output_stream);
-                       }
-
+                       stop_result = imapx_stop_idle (is, error);
                        success = (stop_result != IMAPX_IDLE_STOP_ERROR);
                }
        }
@@ -2183,7 +2154,7 @@ imapx_untagged_exists (CamelIMAPXServer *is,
 
 static gboolean
 imapx_untagged_flags (CamelIMAPXServer *is,
-                      CamelIMAPXStream *stream,
+                      GInputStream *input_stream,
                       GCancellable *cancellable,
                       GError **error)
 {
@@ -2193,7 +2164,8 @@ imapx_untagged_flags (CamelIMAPXServer *is,
        g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
 
        success = imapx_parse_flags (
-               stream, &flags, NULL, cancellable, error);
+               CAMEL_IMAPX_INPUT_STREAM (input_stream),
+               &flags, NULL, cancellable, error);
 
        c (is->tagprefix, "flags: %08x\n", flags);
 
@@ -2202,7 +2174,7 @@ imapx_untagged_flags (CamelIMAPXServer *is,
 
 static gboolean
 imapx_untagged_fetch (CamelIMAPXServer *is,
-                      CamelIMAPXStream *stream,
+                      GInputStream *input_stream,
                       GCancellable *cancellable,
                       GError **error)
 {
@@ -2211,7 +2183,8 @@ imapx_untagged_fetch (CamelIMAPXServer *is,
 
        g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
 
-       finfo = imapx_parse_fetch (stream, cancellable, error);
+       finfo = imapx_parse_fetch (
+               CAMEL_IMAPX_INPUT_STREAM (input_stream), cancellable, error);
        if (finfo == NULL) {
                imapx_free_fetch (finfo);
                return FALSE;
@@ -2532,7 +2505,7 @@ imapx_untagged_fetch (CamelIMAPXServer *is,
 
 static gboolean
 imapx_untagged_lsub (CamelIMAPXServer *is,
-                     CamelIMAPXStream *stream,
+                     GInputStream *input_stream,
                      GCancellable *cancellable,
                      GError **error)
 {
@@ -2545,7 +2518,8 @@ imapx_untagged_lsub (CamelIMAPXServer *is,
        g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
 
        /* LSUB response is syntactically compatible with LIST response. */
-       response = camel_imapx_list_response_new (stream, cancellable, error);
+       response = camel_imapx_list_response_new (
+               CAMEL_IMAPX_INPUT_STREAM (input_stream), cancellable, error);
        if (response == NULL)
                return FALSE;
 
@@ -2596,7 +2570,7 @@ imapx_untagged_lsub (CamelIMAPXServer *is,
 
 static gboolean
 imapx_untagged_list (CamelIMAPXServer *is,
-                     CamelIMAPXStream *stream,
+                     GInputStream *input_stream,
                      GCancellable *cancellable,
                      GError **error)
 {
@@ -2611,7 +2585,8 @@ imapx_untagged_list (CamelIMAPXServer *is,
 
        g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
 
-       response = camel_imapx_list_response_new (stream, cancellable, error);
+       response = camel_imapx_list_response_new (
+               CAMEL_IMAPX_INPUT_STREAM (input_stream), cancellable, error);
        if (response == NULL)
                return FALSE;
 
@@ -2675,7 +2650,7 @@ imapx_untagged_list (CamelIMAPXServer *is,
 
 static gboolean
 imapx_untagged_quota (CamelIMAPXServer *is,
-                      CamelIMAPXStream *stream,
+                      GInputStream *input_stream,
                       GCancellable *cancellable,
                       GError **error)
 {
@@ -2684,7 +2659,8 @@ imapx_untagged_quota (CamelIMAPXServer *is,
        gboolean success;
 
        success = camel_imapx_parse_quota (
-               stream, cancellable, &quota_root_name, &quota_info, error);
+               CAMEL_IMAPX_INPUT_STREAM (input_stream),
+               cancellable, &quota_root_name, &quota_info, error);
 
        /* Sanity check */
        g_return_val_if_fail (
@@ -2708,7 +2684,7 @@ imapx_untagged_quota (CamelIMAPXServer *is,
 
 static gboolean
 imapx_untagged_quotaroot (CamelIMAPXServer *is,
-                          CamelIMAPXStream *stream,
+                          GInputStream *input_stream,
                           GCancellable *cancellable,
                           GError **error)
 {
@@ -2718,7 +2694,8 @@ imapx_untagged_quotaroot (CamelIMAPXServer *is,
        gboolean success;
 
        success = camel_imapx_parse_quotaroot (
-               stream, cancellable, &mailbox_name, &quota_roots, error);
+               CAMEL_IMAPX_INPUT_STREAM (input_stream),
+               cancellable, &mailbox_name, &quota_roots, error);
 
        /* Sanity check */
        g_return_val_if_fail (
@@ -2748,7 +2725,7 @@ imapx_untagged_quotaroot (CamelIMAPXServer *is,
 
 static gboolean
 imapx_untagged_recent (CamelIMAPXServer *is,
-                       CamelIMAPXStream *stream,
+                       GInputStream *input_stream,
                        GCancellable *cancellable,
                        GError **error)
 {
@@ -2775,7 +2752,7 @@ imapx_untagged_recent (CamelIMAPXServer *is,
 
 static gboolean
 imapx_untagged_search (CamelIMAPXServer *is,
-                       CamelIMAPXStream *stream,
+                       GInputStream *input_stream,
                        GCancellable *cancellable,
                        GError **error)
 {
@@ -2789,18 +2766,26 @@ imapx_untagged_search (CamelIMAPXServer *is,
        search_results = g_array_new (FALSE, FALSE, sizeof (guint64));
 
        while (TRUE) {
+               gboolean success;
+
                /* Peek at the next token, and break
                 * out of the loop if we get a newline. */
-               tok = camel_imapx_stream_token (
-                       stream, &token, &len, cancellable, error);
+               tok = camel_imapx_input_stream_token (
+                       CAMEL_IMAPX_INPUT_STREAM (input_stream),
+                       &token, &len, cancellable, error);
                if (tok == '\n')
                        break;
                if (tok == IMAPX_TOK_ERROR)
                        goto exit;
-               camel_imapx_stream_ungettoken (stream, tok, token, len);
+               camel_imapx_input_stream_ungettoken (
+                       CAMEL_IMAPX_INPUT_STREAM (input_stream),
+                       tok, token, len);
+
+               success = camel_imapx_input_stream_number (
+                       CAMEL_IMAPX_INPUT_STREAM (input_stream),
+                       &number, cancellable, error);
 
-               if (!camel_imapx_stream_number (
-                       stream, &number, cancellable, error))
+               if (!success)
                        goto exit;
 
                g_array_append_val (search_results, number);
@@ -2825,7 +2810,7 @@ exit:
 
 static gboolean
 imapx_untagged_status (CamelIMAPXServer *is,
-                       CamelIMAPXStream *stream,
+                       GInputStream *input_stream,
                        GCancellable *cancellable,
                        GError **error)
 {
@@ -2836,7 +2821,8 @@ imapx_untagged_status (CamelIMAPXServer *is,
        g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
 
        response = camel_imapx_status_response_new (
-               stream, is->priv->inbox_separator, cancellable, error);
+               CAMEL_IMAPX_INPUT_STREAM (input_stream),
+               is->priv->inbox_separator, cancellable, error);
        if (response == NULL)
                return FALSE;
 
@@ -2857,7 +2843,7 @@ imapx_untagged_status (CamelIMAPXServer *is,
 
 static gboolean
 imapx_untagged_bye (CamelIMAPXServer *is,
-                    CamelIMAPXStream *stream,
+                    GInputStream *input_stream,
                     GCancellable *cancellable,
                     GError **error)
 {
@@ -2865,10 +2851,17 @@ imapx_untagged_bye (CamelIMAPXServer *is,
        CamelService *service;
        CamelServiceConnectionStatus status;
        guchar *token = NULL;
+       gboolean success;
 
        g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
 
-       if (camel_imapx_stream_text (stream, &token, cancellable, error)) {
+       success = camel_imapx_input_stream_text (
+               CAMEL_IMAPX_INPUT_STREAM (input_stream),
+               &token, cancellable, error);
+
+       /* XXX It's weird to be setting an error on success,
+        *     but it's to indicate the server hung up on us. */
+       if (success) {
                c (is->tagprefix, "BYE: %s\n", token);
                g_set_error (
                        error, CAMEL_IMAPX_ERROR, 1,
@@ -2897,7 +2890,7 @@ imapx_untagged_bye (CamelIMAPXServer *is,
 
 static gboolean
 imapx_untagged_preauth (CamelIMAPXServer *is,
-                        CamelIMAPXStream *stream,
+                        GInputStream *input_stream,
                         GCancellable *cancellable,
                         GError **error)
 {
@@ -2912,7 +2905,7 @@ imapx_untagged_preauth (CamelIMAPXServer *is,
 
 static gboolean
 imapx_untagged_ok_no_bad (CamelIMAPXServer *is,
-                          CamelIMAPXStream *stream,
+                          GInputStream *input_stream,
                           GCancellable *cancellable,
                           GError **error)
 {
@@ -2922,16 +2915,17 @@ imapx_untagged_ok_no_bad (CamelIMAPXServer *is,
 
        /* TODO: validate which ones of these can happen as unsolicited responses */
        /* TODO: handle bye/preauth differently */
-       camel_imapx_stream_ungettoken (
-               stream,
+       camel_imapx_input_stream_ungettoken (
+               CAMEL_IMAPX_INPUT_STREAM (input_stream),
                is->priv->context->tok,
                is->priv->context->token,
                is->priv->context->len);
 
        mailbox = camel_imapx_server_ref_selected (is);
 
-       is->priv->context->sinfo =
-               imapx_parse_status (stream, mailbox, cancellable, error);
+       is->priv->context->sinfo = imapx_parse_status (
+               CAMEL_IMAPX_INPUT_STREAM (input_stream),
+               mailbox, cancellable, error);
 
        g_clear_object (&mailbox);
 
@@ -3048,7 +3042,7 @@ imapx_untagged_ok_no_bad (CamelIMAPXServer *is,
 /* handle any untagged responses */
 static gboolean
 imapx_untagged (CamelIMAPXServer *is,
-                CamelIMAPXStream *stream,
+                GInputStream *input_stream,
                 GCancellable *cancellable,
                 GError **error)
 {
@@ -3075,8 +3069,8 @@ imapx_untagged (CamelIMAPXServer *is,
 
        e (is->tagprefix, "got untagged response\n");
        is->priv->context->id = 0;
-       is->priv->context->tok = camel_imapx_stream_token (
-               stream,
+       is->priv->context->tok = camel_imapx_input_stream_token (
+               CAMEL_IMAPX_INPUT_STREAM (input_stream),
                &(is->priv->context->token),
                &(is->priv->context->len),
                cancellable, error);
@@ -3086,8 +3080,8 @@ imapx_untagged (CamelIMAPXServer *is,
        if (is->priv->context->tok == IMAPX_TOK_INT) {
                is->priv->context->id = strtoul (
                        (gchar *) is->priv->context->token, NULL, 10);
-               is->priv->context->tok = camel_imapx_stream_token (
-                       stream,
+               is->priv->context->tok = camel_imapx_input_stream_token (
+                       CAMEL_IMAPX_INPUT_STREAM (input_stream),
                        &(is->priv->context->token),
                        &(is->priv->context->len),
                        cancellable, error);
@@ -3124,7 +3118,7 @@ imapx_untagged (CamelIMAPXServer *is,
                }
 
                /* call the handler function */
-               success = desc->handler (is, stream, cancellable, error);
+               success = desc->handler (is, input_stream, cancellable, error);
                if (!success)
                        goto exit;
 
@@ -3147,7 +3141,8 @@ imapx_untagged (CamelIMAPXServer *is,
                        goto exit;
        }
 
-       success = camel_imapx_stream_skip (stream, cancellable, error);
+       success = camel_imapx_input_stream_skip (
+               CAMEL_IMAPX_INPUT_STREAM (input_stream), cancellable, error);
 
 exit:
        g_free (is->priv->context);
@@ -3160,7 +3155,7 @@ exit:
  * either data continuations, or auth continuation */
 static gboolean
 imapx_continuation (CamelIMAPXServer *is,
-                    CamelIMAPXStream *stream,
+                    GInputStream *input_stream,
                     GOutputStream *output_stream,
                     gboolean litplus,
                     GCancellable *cancellable,
@@ -3170,13 +3165,18 @@ imapx_continuation (CamelIMAPXServer *is,
        CamelIMAPXCommandPart *cp;
        GList *link;
        gssize n_bytes_written;
+       gboolean success;
 
        /* The 'literal' pointer is like a write-lock, nothing else
         * can write while we have it ... so we dont need any
         * ohter lock here.  All other writes go through
         * queue-lock */
        if (imapx_in_idle (is)) {
-               if (!camel_imapx_stream_skip (stream, cancellable, error))
+               success = camel_imapx_input_stream_skip (
+                       CAMEL_IMAPX_INPUT_STREAM (input_stream),
+                       cancellable, error);
+
+               if (!success)
                        return FALSE;
 
                c (is->tagprefix, "Got continuation response for IDLE \n");
@@ -3188,7 +3188,7 @@ imapx_continuation (CamelIMAPXServer *is,
                        /* IDLE got cancelled after we sent the command, while
                         * we were waiting for this continuation. Send DONE
                         * immediately. */
-                       if (!imapx_command_idle_stop (is, output_stream, error)) {
+                       if (!imapx_command_idle_stop (is, error)) {
                                g_mutex_unlock (&is->priv->idle_lock);
                                return FALSE;
                        }
@@ -3212,8 +3212,9 @@ imapx_continuation (CamelIMAPXServer *is,
        if (!litplus) {
                if (ic == NULL) {
                        c (is->tagprefix, "got continuation response with no outstanding continuation 
requests?\n");
-                       return camel_imapx_stream_skip (
-                               stream, cancellable, error);
+                       return camel_imapx_input_stream_skip (
+                               CAMEL_IMAPX_INPUT_STREAM (input_stream),
+                               cancellable, error);
                }
                c (is->tagprefix, "got continuation response for data\n");
        } else {
@@ -3238,8 +3239,11 @@ imapx_continuation (CamelIMAPXServer *is,
                gchar *resp;
                guchar *token;
 
-               if (!camel_imapx_stream_text (
-                       stream, &token, cancellable, error))
+               success = camel_imapx_input_stream_text (
+                       CAMEL_IMAPX_INPUT_STREAM (input_stream),
+                       &token, cancellable, error);
+
+               if (!success)
                        return FALSE;
 
                resp = camel_sasl_challenge_base64_sync (
@@ -3265,22 +3269,29 @@ imapx_continuation (CamelIMAPXServer *is,
                goto noskip;
                break; }
        case CAMEL_IMAPX_COMMAND_FILE: {
-               CamelStream *file;
+               GFile *file;
+               GFileInputStream *file_input_stream;
 
                c (is->tagprefix, "writing file '%s' to literal\n", (gchar *) cp->ob);
 
-               // FIXME: errors
-               if (cp->ob && (file = camel_stream_fs_new_with_name (cp->ob, O_RDONLY, 0, NULL))) {
-                       n_bytes_written = camel_stream_write_to_stream (
-                               file, CAMEL_STREAM (stream),
-                               cancellable, error);
-                       g_object_unref (file);
+               file = g_file_new_for_path (cp->ob);
+               file_input_stream = g_file_read (file, cancellable, error);
+               g_object_unref (file);
+
+               if (file_input_stream == NULL)
+                       return FALSE;
+
+               n_bytes_written = g_output_stream_splice (
+                       output_stream,
+                       G_INPUT_STREAM (file_input_stream),
+                       G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE,
+                       cancellable, error);
+
+               g_object_unref (file_input_stream);
+
+               if (n_bytes_written < 0)
+                       return FALSE;
 
-                       if (n_bytes_written < 0)
-                               return FALSE;
-               } else if (cp->ob_size > 0) {
-                       // Server is expecting data ... ummm, send it zeros?  abort?
-               }
                break; }
        case CAMEL_IMAPX_COMMAND_STRING:
                n_bytes_written = g_output_stream_write_all (
@@ -3299,7 +3310,11 @@ imapx_continuation (CamelIMAPXServer *is,
        }
 
        if (!litplus) {
-               if (!camel_imapx_stream_skip (stream, cancellable, error))
+               success = camel_imapx_input_stream_skip (
+                       CAMEL_IMAPX_INPUT_STREAM (input_stream),
+                       cancellable, error);
+
+               if (!success)
                        return FALSE;
        }
 
@@ -3344,7 +3359,7 @@ noskip:
 /* handle a completion line */
 static gboolean
 imapx_completion (CamelIMAPXServer *is,
-                  CamelIMAPXStream *stream,
+                  GInputStream *input_stream,
                   guchar *token,
                   gint len,
                   GCancellable *cancellable,
@@ -3429,7 +3444,9 @@ imapx_completion (CamelIMAPXServer *is,
 
        mailbox = camel_imapx_server_ref_selected (is);
 
-       ic->status = imapx_parse_status (stream, mailbox, cancellable, error);
+       ic->status = imapx_parse_status (
+               CAMEL_IMAPX_INPUT_STREAM (input_stream),
+               mailbox, cancellable, error);
 
        g_clear_object (&mailbox);
 
@@ -3453,19 +3470,23 @@ exit:
 
 static gboolean
 imapx_step (CamelIMAPXServer *is,
-            CamelIMAPXStream *stream,
-            GOutputStream *output_stream,
+            GInputStream *input_stream,
             GCancellable *cancellable,
             GError **error)
 {
+       GOutputStream *output_stream;
        guint len;
        guchar *token;
        gint tok;
        gboolean success = FALSE;
 
        // poll ? wait for other stuff? loop?
-       tok = camel_imapx_stream_token (
-               stream, &token, &len, cancellable, error);
+       tok = camel_imapx_input_stream_token (
+               CAMEL_IMAPX_INPUT_STREAM (input_stream),
+               &token, &len, cancellable, error);
+
+       output_stream = camel_imapx_server_ref_output_stream (is);
+       g_return_val_if_fail (output_stream != NULL, FALSE);
 
        switch (tok) {
                case IMAPX_TOK_ERROR:
@@ -3473,15 +3494,16 @@ imapx_step (CamelIMAPXServer *is,
                        break;
                case '*':
                        success = imapx_untagged (
-                               is, stream, cancellable, error);
+                               is, input_stream, cancellable, error);
                        break;
                case IMAPX_TOK_TOKEN:
                        success = imapx_completion (
-                               is, stream, token, len, cancellable, error);
+                               is, input_stream,
+                               token, len, cancellable, error);
                        break;
                case '+':
                        success = imapx_continuation (
-                               is, stream, output_stream,
+                               is, input_stream, output_stream,
                                FALSE, cancellable, error);
                        break;
                default:
@@ -3491,6 +3513,8 @@ imapx_step (CamelIMAPXServer *is,
                        break;
        }
 
+       g_clear_object (&output_stream);
+
        return success;
 }
 
@@ -3502,15 +3526,11 @@ imapx_command_run (CamelIMAPXServer *is,
                    GCancellable *cancellable,
                    GError **error)
 {
-       CamelIMAPXStream *stream;
-       GOutputStream *output_stream;
+       GInputStream *input_stream;
        gboolean success = TRUE;
 
-       stream = camel_imapx_server_ref_stream (is);
-       g_return_val_if_fail (stream != NULL, FALSE);
-
-       output_stream = camel_imapx_server_ref_output_stream (is);
-       g_return_val_if_fail (output_stream != NULL, FALSE);
+       input_stream = camel_imapx_server_ref_input_stream (is);
+       g_return_val_if_fail (input_stream != NULL, FALSE);
 
        camel_imapx_command_close (ic);
 
@@ -3518,11 +3538,8 @@ imapx_command_run (CamelIMAPXServer *is,
        imapx_command_start (is, ic);
        QUEUE_UNLOCK (is);
 
-       while (success && ic->status == NULL) {
-               success = imapx_step (
-                       is, stream, output_stream,
-                       cancellable, error);
-       }
+       while (success && ic->status == NULL)
+               success = imapx_step (is, input_stream, cancellable, error);
 
        if (is->literal == ic)
                is->literal = NULL;
@@ -3531,8 +3548,7 @@ imapx_command_run (CamelIMAPXServer *is,
        camel_imapx_command_queue_remove (is->active, ic);
        QUEUE_UNLOCK (is);
 
-       g_object_unref (stream);
-       g_object_unref (output_stream);
+       g_object_unref (input_stream);
 
        return success;
 }
@@ -3607,14 +3623,16 @@ imapx_command_run_sync (CamelIMAPXServer *is,
 /*TODO handle negative cases sanely */
 static gboolean
 imapx_command_idle_stop (CamelIMAPXServer *is,
-                         GOutputStream *output_stream,
                          GError **error)
 {
+       GOutputStream *output_stream;
        GCancellable *cancellable;
        gboolean success;
 
        g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
-       g_return_val_if_fail (G_IS_OUTPUT_STREAM (output_stream), FALSE);
+
+       output_stream = camel_imapx_server_ref_output_stream (is);
+       g_return_val_if_fail (output_stream != NULL, FALSE);
 
        cancellable = g_weak_ref_get (&is->priv->parser_cancellable);
 
@@ -3629,6 +3647,7 @@ imapx_command_idle_stop (CamelIMAPXServer *is,
        }
 
        g_clear_object (&cancellable);
+       g_clear_object (&output_stream);
 
        return success;
 }
@@ -3878,11 +3897,9 @@ imapx_idle_thread (gpointer data)
 
 static CamelIMAPXIdleStopResult
 imapx_stop_idle (CamelIMAPXServer *is,
-                 GOutputStream *output_stream,
                  GError **error)
 {
        CamelIMAPXIdleStopResult result = IMAPX_IDLE_STOP_NOOP;
-       gboolean success;
        time_t now;
 
        time (&now);
@@ -3899,9 +3916,7 @@ imapx_stop_idle (CamelIMAPXServer *is,
                        break;
 
                case IMAPX_IDLE_STARTED:
-                       success = imapx_command_idle_stop (
-                               is, output_stream, error);
-                       if (success) {
+                       if (imapx_command_idle_stop (is, error)) {
                                result = IMAPX_IDLE_STOP_SUCCESS;
                        } else {
                                result = IMAPX_IDLE_STOP_ERROR;
@@ -4236,16 +4251,27 @@ imapx_server_set_streams (CamelIMAPXServer *is,
 {
        GConverter *logger;
 
-       /* Wrapper the streams for debugging output. */
-
        if (input_stream != NULL) {
+               GInputStream *temp_stream;
+
+               /* The logger produces debugging output. */
                logger = camel_imapx_logger_new (is->tagprefix);
                input_stream = g_converter_input_stream_new (
                        input_stream, logger);
                g_clear_object (&logger);
+
+               /* Buffer the input stream for parsing. */
+               temp_stream = camel_imapx_input_stream_new (input_stream);
+               g_object_bind_property (
+                       temp_stream, "close-base-stream",
+                       input_stream, "close-base-stream",
+                       G_BINDING_SYNC_CREATE);
+               g_object_unref (input_stream);
+               input_stream = temp_stream;
        }
 
        if (output_stream != NULL) {
+               /* The logger produces debugging output. */
                logger = camel_imapx_logger_new (is->tagprefix);
                output_stream = g_converter_output_stream_new (
                        output_stream, logger);
@@ -4447,11 +4473,9 @@ imapx_connect_to_server (CamelIMAPXServer *is,
 {
        CamelNetworkSettings *network_settings;
        CamelNetworkSecurityMethod method;
-       CamelStream *stream = NULL;
-       CamelStream *imapx_stream = NULL;
        CamelIMAPXStore *store;
        CamelSettings *settings;
-       GIOStream *base_stream;
+       GIOStream *connection = NULL;
        GIOStream *tls_stream;
        GSocket *socket;
        guint len;
@@ -4492,55 +4516,47 @@ imapx_connect_to_server (CamelIMAPXServer *is,
                        goto exit;
        }
 
-       base_stream = camel_network_service_connect_sync (
+       connection = camel_network_service_connect_sync (
                CAMEL_NETWORK_SERVICE (store), cancellable, error);
 
-       if (base_stream != NULL) {
+       if (connection != NULL) {
                GInputStream *input_stream;
                GOutputStream *output_stream;
 
-               input_stream = g_io_stream_get_input_stream (base_stream);
-               output_stream = g_io_stream_get_output_stream (base_stream);
+               /* Disable the Nagle algorithm with TCP_NODELAY, since IMAP
+                * commands should be issued immediately even we've not yet
+                * received a response to a previous command. */
+               socket = g_socket_connection_get_socket (
+                       G_SOCKET_CONNECTION (connection));
+               g_socket_set_option (
+                       socket, IPPROTO_TCP, TCP_NODELAY, 1, &local_error);
+               if (local_error != NULL) {
+                       /* Failure to set the socket option is non-fatal. */
+                       g_warning ("%s: %s", G_STRFUNC, local_error->message);
+                       g_clear_error (&local_error);
+               }
+
+               g_mutex_lock (&is->priv->stream_lock);
+               g_warn_if_fail (is->priv->connection == NULL);
+               is->priv->connection = g_object_ref (connection);
+               g_mutex_unlock (&is->priv->stream_lock);
+
+               input_stream = g_io_stream_get_input_stream (connection);
+               output_stream = g_io_stream_get_output_stream (connection);
 
                imapx_server_set_streams (is, input_stream, output_stream);
 
-               stream = camel_stream_new (base_stream);
-               g_object_unref (base_stream);
+               /* Hang on to the connection reference in case we need to
+                * issue STARTTLS below. */
        } else {
                success = FALSE;
                goto exit;
        }
 
-       /* Disable the Nagle algorithm with TCP_NODELAY, since IMAP
-        * commands should be issued immediately even we've not yet
-        * received a response to a previous command. */
-       socket = g_socket_connection_get_socket (
-               G_SOCKET_CONNECTION (base_stream));
-       g_socket_set_option (
-               socket, IPPROTO_TCP, TCP_NODELAY, 1, &local_error);
-       if (local_error != NULL) {
-               /* Failure to set the socket option is non-fatal. */
-               g_warning ("%s: %s", G_STRFUNC, local_error->message);
-               g_clear_error (&local_error);
-       }
-
-       imapx_stream = camel_imapx_stream_new (stream);
-
-       /* CamelIMAPXServer takes ownership of the IMAPX stream.
-        * We need to set this right away for imapx_command_run()
-        * to work, but we delay emitting a "notify" signal until
-        * we're fully connected. */
-       g_mutex_lock (&is->priv->stream_lock);
-       g_warn_if_fail (is->priv->stream == NULL);
-       is->priv->stream = CAMEL_IMAPX_STREAM (imapx_stream);
-       g_mutex_unlock (&is->priv->stream_lock);
-
-       g_object_unref (stream);
-
- connected:
-       CAMEL_IMAPX_STREAM (imapx_stream)->tagprefix = is->tagprefix;
-
+connected:
        while (1) {
+               GInputStream *input_stream;
+
                // poll ? wait for other stuff? loop?
                if (camel_application_is_exiting) {
                        g_set_error (
@@ -4551,32 +4567,40 @@ imapx_connect_to_server (CamelIMAPXServer *is,
                        goto exit;
                }
 
-               tok = camel_imapx_stream_token (
-                       CAMEL_IMAPX_STREAM (imapx_stream),
+               input_stream = camel_imapx_server_ref_input_stream (is);
+
+               tok = camel_imapx_input_stream_token (
+                       CAMEL_IMAPX_INPUT_STREAM (input_stream),
                        &token, &len, cancellable, error);
+
                if (tok < 0) {
                        success = FALSE;
-                       goto exit;
-               }
 
-               if (tok == '*') {
+               } else if (tok == '*') {
                        success = imapx_untagged (
-                               is, CAMEL_IMAPX_STREAM (imapx_stream),
-                               cancellable, error);
-                       if (!success)
-                               goto exit;
-                       break;
+                               is, input_stream, cancellable, error);
+
+                       if (success) {
+                               g_object_unref (input_stream);
+                               break;
+                       }
+
+               } else {
+                       camel_imapx_input_stream_ungettoken (
+                               CAMEL_IMAPX_INPUT_STREAM (input_stream),
+                               tok, token, len);
+
+                       success = camel_imapx_input_stream_text (
+                               CAMEL_IMAPX_INPUT_STREAM (input_stream),
+                               &token, cancellable, error);
+
+                       g_free (token);
                }
-               camel_imapx_stream_ungettoken (
-                       CAMEL_IMAPX_STREAM (imapx_stream), tok, token, len);
 
-               success = camel_imapx_stream_text (
-                       CAMEL_IMAPX_STREAM (imapx_stream),
-                       &token, cancellable, error);
+               g_object_unref (input_stream);
+
                if (!success)
                        goto exit;
-               e (is->tagprefix, "Got unexpected line before greeting:  '%s'\n", token);
-               g_free (token);
        }
 
        if (!is->cinfo) {
@@ -4643,15 +4667,18 @@ imapx_connect_to_server (CamelIMAPXServer *is,
                if (!success)
                        goto exit;
 
-               base_stream = camel_stream_ref_base_stream (stream);
                tls_stream = camel_network_service_starttls (
-                       CAMEL_NETWORK_SERVICE (store), base_stream, error);
-               g_object_unref (base_stream);
+                       CAMEL_NETWORK_SERVICE (store), connection, error);
 
                if (tls_stream != NULL) {
                        GInputStream *input_stream;
                        GOutputStream *output_stream;
 
+                       g_mutex_lock (&is->priv->stream_lock);
+                       g_object_unref (is->priv->connection);
+                       is->priv->connection = g_object_ref (tls_stream);
+                       g_mutex_unlock (&is->priv->stream_lock);
+
                        input_stream =
                                g_io_stream_get_input_stream (tls_stream);
                        output_stream =
@@ -4660,7 +4687,6 @@ imapx_connect_to_server (CamelIMAPXServer *is,
                        imapx_server_set_streams (
                                is, input_stream, output_stream);
 
-                       camel_stream_set_base_stream (stream, tls_stream);
                        g_object_unref (tls_stream);
                } else {
                        g_prefix_error (
@@ -4684,15 +4710,15 @@ imapx_connect_to_server (CamelIMAPXServer *is,
        }
 
 exit:
-       if (success) {
-               g_object_notify (G_OBJECT (is), "stream");
-       } else {
+       if (!success) {
                g_mutex_lock (&is->priv->stream_lock);
 
-               if (is->priv->stream != NULL) {
-                       g_object_unref (is->priv->stream);
-                       is->priv->stream = NULL;
-               }
+               g_clear_object (&is->priv->input_stream);
+               g_clear_object (&is->priv->output_stream);
+               g_clear_object (&is->priv->connection);
+#if GLIB_CHECK_VERSION(2,39,0)
+               g_clear_object (&is->priv->subprocess);
+#endif
 
                if (is->cinfo != NULL) {
                        imapx_free_capability (is->cinfo);
@@ -4704,7 +4730,8 @@ exit:
 
        g_free (host);
 
-       g_object_unref (store);
+       g_clear_object (&connection);
+       g_clear_object (&store);
 
        return success;
 }
@@ -7542,38 +7569,26 @@ static gboolean
 imapx_ready_to_read (GInputStream *input_stream,
                      CamelIMAPXServer *is)
 {
-       CamelIMAPXStream *stream;
        GOutputStream *output_stream;
        GCancellable *cancellable;
        GError *local_error = NULL;
 
-       /* XXX Still need to retrieve the CamelStream until IMAPX can
-        *     be ported to use GInputStream / GOutputStream directly. */
-       stream = camel_imapx_server_ref_stream (is);
+       /* XXX Don't use the passed in GInputStream because that's
+        *     the CamelIMAPXInputStream base stream.  We need the
+        *     CamelIMAPXInputStream itself. */
+
+       input_stream = camel_imapx_server_ref_input_stream (is);
        output_stream = camel_imapx_server_ref_output_stream (is);
 
        cancellable = g_weak_ref_get (&is->priv->parser_cancellable);
 
-       if (stream != NULL) {
-               gboolean success;
-
-               success = imapx_step (
-                       is, stream, output_stream,
-                       cancellable, &local_error);
+       while (imapx_step (is, input_stream, cancellable, &local_error)) {
+               gint bytes_buffered;
 
-               while (success) {
-                       if (camel_imapx_stream_buffered (stream) == 0)
-                               break;
-
-                       success = imapx_step (
-                               is, stream, output_stream,
-                               cancellable, &local_error);
-               }
-       } else {
-               local_error = g_error_new_literal (
-                       CAMEL_SERVICE_ERROR,
-                       CAMEL_SERVICE_ERROR_NOT_CONNECTED,
-                       _("Lost connection to IMAP server"));
+               bytes_buffered = camel_imapx_input_stream_buffered (
+                       CAMEL_IMAPX_INPUT_STREAM (input_stream));
+               if (bytes_buffered == 0)
+                       break;
        }
 
        if (g_cancellable_is_cancelled (cancellable)) {
@@ -7593,7 +7608,7 @@ imapx_ready_to_read (GInputStream *input_stream,
                }
        }
 
-       g_clear_object (&stream);
+       g_clear_object (&input_stream);
        g_clear_object (&output_stream);
        g_clear_object (&cancellable);
 
@@ -7619,9 +7634,7 @@ imapx_parser_thread (gpointer user_data)
 {
        CamelIMAPXServer *is;
        CamelIMAPXStore *store;
-       CamelIMAPXStream *stream;
-       GIOStream *base_stream = NULL;
-       GInputStream *input_stream = NULL;
+       GInputStream *input_stream;
        GCancellable *cancellable;
        GSource *pollable_source;
 
@@ -7635,27 +7648,11 @@ imapx_parser_thread (gpointer user_data)
        cancellable = g_cancellable_new ();
        g_weak_ref_set (&is->priv->parser_cancellable, cancellable);
 
-       stream = camel_imapx_server_ref_stream (is);
-       g_return_val_if_fail (stream != NULL, NULL);
+       input_stream = camel_imapx_server_ref_input_stream (is);
+       g_return_val_if_fail (input_stream != NULL, NULL);
 
        g_main_context_push_thread_default (is->priv->parser_main_context);
 
-#if GLIB_CHECK_VERSION(2,39,0)
-       if (is->priv->subprocess != NULL) {
-               input_stream =
-                       g_subprocess_get_stdout_pipe (is->priv->subprocess);
-       }
-#endif
-
-       if (input_stream == NULL) {
-               CamelStream *source_stream;
-
-               source_stream = camel_imapx_stream_ref_source (stream);
-               base_stream = camel_stream_ref_base_stream (source_stream);
-               input_stream = g_io_stream_get_input_stream (base_stream);
-               g_object_unref (source_stream);
-       }
-
        pollable_source = g_pollable_input_stream_create_source (
                G_POLLABLE_INPUT_STREAM (input_stream), cancellable);
        g_source_set_callback (
@@ -7669,8 +7666,7 @@ imapx_parser_thread (gpointer user_data)
        g_source_unref (pollable_source);
 
        g_clear_object (&cancellable);
-       g_clear_object (&base_stream);
-       g_clear_object (&stream);
+       g_clear_object (&input_stream);
 
        g_main_loop_run (is->priv->parser_main_loop);
 
@@ -7731,13 +7727,6 @@ imapx_server_get_property (GObject *object,
                                CAMEL_IMAPX_SERVER (object)));
                        return;
 
-               case PROP_STREAM:
-                       g_value_take_object (
-                               value,
-                               camel_imapx_server_ref_stream (
-                               CAMEL_IMAPX_SERVER (object)));
-                       return;
-
                case PROP_STORE:
                        g_value_take_object (
                                value,
@@ -7947,17 +7936,6 @@ camel_imapx_server_class_init (CamelIMAPXServerClass *class)
 
        g_object_class_install_property (
                object_class,
-               PROP_STREAM,
-               g_param_spec_object (
-                       "stream",
-                       "Stream",
-                       "IMAP network stream",
-                       CAMEL_TYPE_IMAPX_STREAM,
-                       G_PARAM_READABLE |
-                       G_PARAM_STATIC_STRINGS));
-
-       g_object_class_install_property (
-               object_class,
                PROP_STORE,
                g_param_spec_object (
                        "store",
@@ -8114,23 +8092,6 @@ camel_imapx_server_ref_settings (CamelIMAPXServer *server)
        return CAMEL_IMAPX_SETTINGS (settings);
 }
 
-CamelIMAPXStream *
-camel_imapx_server_ref_stream (CamelIMAPXServer *server)
-{
-       CamelIMAPXStream *stream = NULL;
-
-       g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), NULL);
-
-       g_mutex_lock (&server->priv->stream_lock);
-
-       if (server->priv->stream != NULL)
-               stream = g_object_ref (server->priv->stream);
-
-       g_mutex_unlock (&server->priv->stream_lock);
-
-       return stream;
-}
-
 /**
  * camel_imapx_server_ref_input_stream:
  * @is: a #CamelIMAPXServer
@@ -8341,25 +8302,17 @@ camel_imapx_server_list_mailboxes (CamelIMAPXServer *is,
        return list;
 }
 
-static gboolean
+static void
 imapx_disconnect (CamelIMAPXServer *is)
 {
-       gboolean ret = TRUE;
-
        g_mutex_lock (&is->priv->stream_lock);
 
-       if (is->priv->stream != NULL) {
-               CamelStream *stream = CAMEL_STREAM (is->priv->stream);
-
-               if (camel_stream_close (stream, NULL, NULL) == -1)
-                       ret = FALSE;
-
-               g_object_unref (is->priv->stream);
-               is->priv->stream = NULL;
-       }
-
        g_clear_object (&is->priv->input_stream);
        g_clear_object (&is->priv->output_stream);
+       g_clear_object (&is->priv->connection);
+#if GLIB_CHECK_VERSION(2,39,0)
+       g_clear_object (&is->priv->subprocess);
+#endif
 
        g_mutex_unlock (&is->priv->stream_lock);
 
@@ -8375,10 +8328,6 @@ imapx_disconnect (CamelIMAPXServer *is)
        }
 
        is->state = IMAPX_DISCONNECTED;
-
-       g_object_notify (G_OBJECT (is), "stream");
-
-       return ret;
 }
 
 /* Client commands */
diff --git a/camel/providers/imapx/camel-imapx-server.h b/camel/providers/imapx/camel-imapx-server.h
index abddad8..f429292 100644
--- a/camel/providers/imapx/camel-imapx-server.h
+++ b/camel/providers/imapx/camel-imapx-server.h
@@ -23,7 +23,6 @@
 #include "camel-imapx-command.h"
 #include "camel-imapx-mailbox.h"
 #include "camel-imapx-namespace-response.h"
-#include "camel-imapx-stream.h"
 #include "camel-imapx-store-summary.h"
 
 /* Standard GObject macros */
@@ -58,10 +57,10 @@ typedef struct _CamelIMAPXServerPrivate CamelIMAPXServerPrivate;
 /* untagged response handling */
 typedef gboolean
                (*CamelIMAPXUntaggedRespHandler)
-                                               (CamelIMAPXServer *server,
-                                                CamelIMAPXStream *stream,
-                                                GCancellable *cancellable,
-                                                GError **error);
+                                       (CamelIMAPXServer *server,
+                                        GInputStream *input_stream,
+                                        GCancellable *cancellable,
+                                        GError **error);
 
 /**
  * CamelIMAPXUntaggedRespHandlerDesc:
@@ -75,7 +74,7 @@ typedef gboolean
  *                 running @handler. If not NULL, @skip_stream_when_done
  *                 for the current handler has no effect
  * @skip_stream_when_done: whether or not to skip the current IMAP
- *                         untagged response in the #CamelIMAPXStream.
+ *                         untagged response in the #GInputStream.
  *                         Set to TRUE if your handler does not eat
  *                         the stream up to the next response token
  *
@@ -143,8 +142,6 @@ struct _CamelIMAPXStore *
                camel_imapx_server_ref_store    (CamelIMAPXServer *is);
 struct _CamelIMAPXSettings *
                camel_imapx_server_ref_settings (CamelIMAPXServer *is);
-CamelIMAPXStream *
-               camel_imapx_server_ref_stream   (CamelIMAPXServer *is);
 GInputStream * camel_imapx_server_ref_input_stream
                                                (CamelIMAPXServer *is);
 GOutputStream *        camel_imapx_server_ref_output_stream
diff --git a/camel/providers/imapx/camel-imapx-status-response.c 
b/camel/providers/imapx/camel-imapx-status-response.c
index 41b566e..5278ec0 100644
--- a/camel/providers/imapx/camel-imapx-status-response.c
+++ b/camel/providers/imapx/camel-imapx-status-response.c
@@ -90,7 +90,7 @@ camel_imapx_status_response_init (CamelIMAPXStatusResponse *response)
 
 /**
  * camel_imapx_status_response_new:
- * @stream: a #CamelIMAPXStream
+ * @stream: a #CamelIMAPXInputStream
  * @inbox_separator: the separator character for INBOX
  * @cancellable: a #GCancellable
  * @error: return location for a #GError, or %NULL
@@ -104,7 +104,7 @@ camel_imapx_status_response_init (CamelIMAPXStatusResponse *response)
  * Since: 3.10
  **/
 CamelIMAPXStatusResponse *
-camel_imapx_status_response_new (CamelIMAPXStream *stream,
+camel_imapx_status_response_new (CamelIMAPXInputStream *stream,
                                  gchar inbox_separator,
                                  GCancellable *cancellable,
                                  GError **error)
@@ -114,7 +114,7 @@ camel_imapx_status_response_new (CamelIMAPXStream *stream,
        guchar *token;
        guint len;
 
-       g_return_val_if_fail (CAMEL_IS_IMAPX_STREAM (stream), NULL);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_INPUT_STREAM (stream), NULL);
 
        response = g_object_new (CAMEL_TYPE_IMAPX_STATUS_RESPONSE, NULL);
 
@@ -127,8 +127,9 @@ camel_imapx_status_response_new (CamelIMAPXStream *stream,
 
        /* Parse status attributes. */
 
-       tok = camel_imapx_stream_token (
-               stream, &token, &len, cancellable, error);
+       tok = camel_imapx_input_stream_token (
+               CAMEL_IMAPX_INPUT_STREAM (stream),
+               &token, &len, cancellable, error);
        if (tok == IMAPX_TOK_ERROR)
                goto fail;
        if (tok != '(') {
@@ -138,8 +139,9 @@ camel_imapx_status_response_new (CamelIMAPXStream *stream,
                goto fail;
        }
 
-       tok = camel_imapx_stream_token (
-               stream, &token, &len, cancellable, error);
+       tok = camel_imapx_input_stream_token (
+               CAMEL_IMAPX_INPUT_STREAM (stream),
+               &token, &len, cancellable, error);
 
        while (tok == IMAPX_TOK_TOKEN) {
                guint64 number;
@@ -147,44 +149,50 @@ camel_imapx_status_response_new (CamelIMAPXStream *stream,
 
                switch (imapx_tokenise ((gchar *) token, len)) {
                        case IMAPX_MESSAGES:
-                               success = camel_imapx_stream_number (
-                                       stream, &number, cancellable, error);
+                               success = camel_imapx_input_stream_number (
+                                       CAMEL_IMAPX_INPUT_STREAM (stream),
+                                       &number, cancellable, error);
                                response->priv->messages = (guint32) number;
                                response->priv->have_messages = TRUE;
                                break;
 
                        case IMAPX_RECENT:
-                               success = camel_imapx_stream_number (
-                                       stream, &number, cancellable, error);
+                               success = camel_imapx_input_stream_number (
+                                       CAMEL_IMAPX_INPUT_STREAM (stream),
+                                       &number, cancellable, error);
                                response->priv->recent = (guint32) number;
                                response->priv->have_recent = TRUE;
                                break;
 
                        case IMAPX_UNSEEN:
-                               success = camel_imapx_stream_number (
-                                       stream, &number, cancellable, error);
+                               success = camel_imapx_input_stream_number (
+                                       CAMEL_IMAPX_INPUT_STREAM (stream),
+                                       &number, cancellable, error);
                                response->priv->unseen = (guint32) number;
                                response->priv->have_unseen = TRUE;
                                break;
 
                        case IMAPX_UIDNEXT:
-                               success = camel_imapx_stream_number (
-                                       stream, &number, cancellable, error);
+                               success = camel_imapx_input_stream_number (
+                                       CAMEL_IMAPX_INPUT_STREAM (stream),
+                                       &number, cancellable, error);
                                response->priv->uidnext = (guint32) number;
                                response->priv->have_uidnext = TRUE;
                                break;
 
                        case IMAPX_UIDVALIDITY:
-                               success = camel_imapx_stream_number (
-                                       stream, &number, cancellable, error);
+                               success = camel_imapx_input_stream_number (
+                                       CAMEL_IMAPX_INPUT_STREAM (stream),
+                                       &number, cancellable, error);
                                response->priv->uidvalidity = (guint32) number;
                                response->priv->have_uidvalidity = TRUE;
                                break;
 
                        /* See RFC 4551 section 3.6 */
                        case IMAPX_HIGHESTMODSEQ:
-                               success = camel_imapx_stream_number (
-                                       stream, &number, cancellable, error);
+                               success = camel_imapx_input_stream_number (
+                                       CAMEL_IMAPX_INPUT_STREAM (stream),
+                                       &number, cancellable, error);
                                response->priv->highestmodseq = number;
                                response->priv->have_highestmodseq = TRUE;
                                break;
@@ -200,8 +208,9 @@ camel_imapx_status_response_new (CamelIMAPXStream *stream,
                if (!success)
                        goto fail;
 
-               tok = camel_imapx_stream_token (
-                       stream, &token, &len, cancellable, error);
+               tok = camel_imapx_input_stream_token (
+                       CAMEL_IMAPX_INPUT_STREAM (stream),
+                       &token, &len, cancellable, error);
        }
 
        if (tok == IMAPX_TOK_ERROR)
diff --git a/camel/providers/imapx/camel-imapx-status-response.h 
b/camel/providers/imapx/camel-imapx-status-response.h
index 3ade01b..03f700b 100644
--- a/camel/providers/imapx/camel-imapx-status-response.h
+++ b/camel/providers/imapx/camel-imapx-status-response.h
@@ -20,7 +20,7 @@
 
 #include <gio/gio.h>
 
-#include "camel-imapx-stream.h"
+#include "camel-imapx-input-stream.h"
 
 /* Standard GObject macros */
 #define CAMEL_TYPE_IMAPX_STATUS_RESPONSE \
@@ -68,7 +68,7 @@ GType         camel_imapx_status_response_get_type
                                        (void) G_GNUC_CONST;
 CamelIMAPXStatusResponse *
                camel_imapx_status_response_new
-                                       (CamelIMAPXStream *stream,
+                                       (CamelIMAPXInputStream *stream,
                                         gchar inbox_separator,
                                         GCancellable *cancellable,
                                         GError **error);
diff --git a/camel/providers/imapx/camel-imapx-utils.c b/camel/providers/imapx/camel-imapx-utils.c
index 251cce7..6a63856 100644
--- a/camel/providers/imapx/camel-imapx-utils.c
+++ b/camel/providers/imapx/camel-imapx-utils.c
@@ -98,7 +98,7 @@ static struct {
  * should this be part of imapx-driver? */
 /* maybe this should be a stream op? */
 gboolean
-imapx_parse_flags (CamelIMAPXStream *stream,
+imapx_parse_flags (CamelIMAPXInputStream *stream,
                    guint32 *flagsp,
                    CamelFlag **user_flagsp,
                    GCancellable *cancellable,
@@ -109,9 +109,11 @@ imapx_parse_flags (CamelIMAPXStream *stream,
        guchar *token;
        guint32 flags = 0;
 
+       g_return_val_if_fail (CAMEL_IS_IMAPX_INPUT_STREAM (stream), FALSE);
+
        *flagsp = flags;
 
-       tok = camel_imapx_stream_token (
+       tok = camel_imapx_input_stream_token (
                stream, &token, &len, cancellable, error);
 
        if (tok == IMAPX_TOK_ERROR)
@@ -125,7 +127,7 @@ imapx_parse_flags (CamelIMAPXStream *stream,
        }
 
        do {
-               tok = camel_imapx_stream_token (
+               tok = camel_imapx_input_stream_token (
                        stream, &token, &len, cancellable, error);
 
                if (tok == IMAPX_TOK_ERROR)
@@ -161,7 +163,7 @@ imapx_parse_flags (CamelIMAPXStream *stream,
                } else if (tok != ')') {
                        gboolean success;
 
-                       success = camel_imapx_stream_skip_until (
+                       success = camel_imapx_input_stream_skip_until (
                                stream, ")", cancellable, error);
                        if (!success)
                                return FALSE;
@@ -474,7 +476,7 @@ create_initial_capabilities_table (void)
 }
 
 struct _capability_info *
-imapx_parse_capability (CamelIMAPXStream *stream,
+imapx_parse_capability (CamelIMAPXInputStream *stream,
                         GCancellable *cancellable,
                         GError **error)
 {
@@ -486,15 +488,23 @@ imapx_parse_capability (CamelIMAPXStream *stream,
        GError *local_error = NULL;
 
        cinfo = g_malloc0 (sizeof (*cinfo));
-       cinfo->auth_types = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, NULL);
+
+       cinfo->auth_types = g_hash_table_new_full (
+               (GHashFunc) g_str_hash,
+               (GEqualFunc) g_str_equal,
+               (GDestroyNotify) g_free,
+               (GDestroyNotify) NULL);
 
        /* FIXME: handle auth types */
-       while ((tok = camel_imapx_stream_token (stream, &token, &len, cancellable, &local_error)) != '\n' &&
-               local_error == NULL) {
+       tok = camel_imapx_input_stream_token (
+               stream, &token, &len, cancellable, &local_error);
+
+       while (tok != '\n' && local_error == NULL) {
                switch (tok) {
                        case ']':
                                /* Put it back so that imapx_untagged() isn't unhappy */
-                               camel_imapx_stream_ungettoken (stream, tok, token, len);
+                               camel_imapx_input_stream_ungettoken (
+                                       stream, tok, token, len);
                                return cinfo;
                        case 43:
                                token = (guchar *) g_strconcat ((gchar *) token, "+", NULL);
@@ -513,7 +523,6 @@ imapx_parse_capability (CamelIMAPXStream *stream,
                                        break;
                                }
                        case IMAPX_TOK_INT:
-                               d (stream->tagprefix, " cap: '%s'\n", token);
                                cinfo->capa |= imapx_lookup_capability ((gchar *) token);
                                if (free_token) {
                                        g_free (token);
@@ -522,9 +531,14 @@ imapx_parse_capability (CamelIMAPXStream *stream,
                                free_token = FALSE;
                                break;
                        default:
-                               g_set_error (error, CAMEL_IMAPX_ERROR, 1, "capability: expecting name");
+                               g_set_error (
+                                       error, CAMEL_IMAPX_ERROR, 1,
+                                       "capability: expecting name");
                                break;
                }
+
+               tok = camel_imapx_input_stream_token (
+                       stream, &token, &len, cancellable, &local_error);
        }
 
        /* Some capabilities are extensions of other capabilities.
@@ -753,7 +767,7 @@ imapx_free_body (struct _CamelMessageContentInfo *cinfo)
 }
 
 gboolean
-imapx_parse_param_list (CamelIMAPXStream *is,
+imapx_parse_param_list (CamelIMAPXInputStream *stream,
                         struct _camel_header_param **plist,
                         GCancellable *cancellable,
                         GError **error)
@@ -764,22 +778,30 @@ imapx_parse_param_list (CamelIMAPXStream *is,
        gchar *param;
        gsize param_len;
 
-       p (is->tagprefix, "body_fld_param\n");
-
        /* body_fld_param  ::= "(" 1#(string SPACE string) ")" / nil */
-       tok = camel_imapx_stream_token (is, &token, &len, cancellable, NULL);
+       tok = camel_imapx_input_stream_token (
+               stream, &token, &len, cancellable, NULL);
        if (tok == '(') {
                while (1) {
-                       tok = camel_imapx_stream_token (is, &token, &len, cancellable, NULL);
+                       tok = camel_imapx_input_stream_token (
+                               stream, &token, &len, cancellable, NULL);
+
                        if (tok == ')')
                                break;
-                       camel_imapx_stream_ungettoken (is, tok, token, len);
 
-                       camel_imapx_stream_astring (is, &token, cancellable, NULL);
+                       camel_imapx_input_stream_ungettoken (
+                               stream, tok, token, len);
+
+                       camel_imapx_input_stream_astring (
+                               stream, &token, cancellable, NULL);
+
                        param_len = strlen ((gchar *) token) + 1;
                        param = alloca (param_len);
                        g_strlcpy (param, (gchar *) token, param_len);
-                       camel_imapx_stream_astring (is, &token, cancellable, NULL);
+
+                       camel_imapx_input_stream_astring (
+                               stream, &token, cancellable, NULL);
+
                        camel_header_set_param (plist, param, (gchar *) token);
                }
        } /* else check nil?  no need */
@@ -788,7 +810,7 @@ imapx_parse_param_list (CamelIMAPXStream *is,
 }
 
 struct _CamelContentDisposition *
-imapx_parse_ext_optional (CamelIMAPXStream *is,
+imapx_parse_ext_optional (CamelIMAPXInputStream *stream,
                           GCancellable *cancellable,
                           GError **error)
 {
@@ -815,47 +837,56 @@ imapx_parse_ext_optional (CamelIMAPXStream *is,
 
        /* body_fld_dsp    ::= "(" string SPACE body_fld_param ")" / nil */
 
-       tok = camel_imapx_stream_token (is, &token, &len, cancellable, NULL);
+       tok = camel_imapx_input_stream_token (
+               stream, &token, &len, cancellable, NULL);
        switch (tok) {
                case '(':
                        dinfo = g_malloc0 (sizeof (*dinfo));
                        dinfo->refcount = 1;
                        /* should be string */
-                       camel_imapx_stream_astring (is, &token, cancellable, NULL);
+                       camel_imapx_input_stream_astring (
+                               stream, &token, cancellable, NULL);
 
                        dinfo->disposition = g_strdup ((gchar *) token);
-                       imapx_parse_param_list (is, &dinfo->params, cancellable, NULL);
+                       imapx_parse_param_list (
+                               stream, &dinfo->params, cancellable, NULL);
                        break;
                case IMAPX_TOK_TOKEN:
-                       d (is->tagprefix, "body_fld_dsp: NIL\n");
                        break;
                default:
-                       g_set_error (error, CAMEL_IMAPX_ERROR, 1, "body_fld_disp: expecting nil or list");
+                       g_set_error (
+                               error, CAMEL_IMAPX_ERROR, 1,
+                               "body_fld_disp: expecting nil or list");
                        return NULL;
        }
 
-       p (is->tagprefix, "body_fld_lang\n");
-
        /* body_fld_lang   ::= nstring / "(" 1#string ")" */
 
        /* we just drop the lang string/list, save it somewhere? */
 
-       tok = camel_imapx_stream_token (is, &token, &len, cancellable, &local_error);
+       tok = camel_imapx_input_stream_token (
+               stream, &token, &len, cancellable, &local_error);
+
        switch (tok) {
                case '(':
                        while (1) {
-                               tok = camel_imapx_stream_token (is, &token, &len, cancellable, &local_error);
+                               tok = camel_imapx_input_stream_token (
+                                       stream, &token, &len,
+                                       cancellable, &local_error);
+
                                if (tok == ')') {
                                        break;
                                } else if (tok != IMAPX_TOK_STRING) {
                                        g_clear_error (&local_error);
-                                       g_set_error (&local_error, CAMEL_IMAPX_ERROR, 1, "expecting string");
+                                       g_set_error (
+                                               &local_error,
+                                               CAMEL_IMAPX_ERROR, 1,
+                                               "expecting string");
                                        break;
                                }
                        }
                        break;
                case IMAPX_TOK_TOKEN:
-                       d (is->tagprefix, "body_fld_lang = nil\n");
                        /* treat as 'nil' */
                        break;
                case IMAPX_TOK_STRING:
@@ -863,9 +894,9 @@ imapx_parse_ext_optional (CamelIMAPXStream *is,
                        break;
                case IMAPX_TOK_LITERAL:
                        /* we have a literal string */
-                       camel_imapx_stream_set_literal (is, len);
-                       while (camel_imapx_stream_getl (is, &token, &len, cancellable, NULL) > 0) {
-                               d (is->tagprefix, "Skip literal data '%.*s'\n", (gint) len, token);
+                       camel_imapx_input_stream_set_literal (stream, len);
+                       while (camel_imapx_input_stream_getl (stream, &token, &len, cancellable, NULL) > 0) {
+                               /* Skip over it. */
                        }
                        break;
 
@@ -882,7 +913,7 @@ imapx_parse_ext_optional (CamelIMAPXStream *is,
 }
 
 struct _CamelMessageContentInfo *
-imapx_parse_body_fields (CamelIMAPXStream *is,
+imapx_parse_body_fields (CamelIMAPXInputStream *stream,
                          GCancellable *cancellable,
                          GError **error)
 {
@@ -891,46 +922,74 @@ imapx_parse_body_fields (CamelIMAPXStream *is,
        gsize type_len;
        guint64 number;
        struct _CamelMessageContentInfo *cinfo;
+       gboolean success;
 
        /* body_fields     ::= body_fld_param SPACE body_fld_id SPACE
         * body_fld_desc SPACE body_fld_enc SPACE
         * body_fld_octets */
 
-       p (is->tagprefix, "body_fields\n");
-
        cinfo = g_malloc0 (sizeof (*cinfo));
 
        /* this should be string not astring */
-       if (!camel_imapx_stream_astring (is, &token, cancellable, error))
+       success = camel_imapx_input_stream_astring (
+               stream, &token, cancellable, error);
+
+       if (!success)
                goto error;
+
        type_len = strlen ((gchar *) token) + 1;
        type = alloca (type_len);
        g_strlcpy (type, (gchar *) token, type_len);
-       if (!camel_imapx_stream_astring (is, &token, cancellable, error))
+
+       success = camel_imapx_input_stream_astring (
+               stream, &token, cancellable, error);
+
+       if (!success)
                goto error;
+
        cinfo->type = camel_content_type_new (type, (gchar *) token);
-       if (!imapx_parse_param_list (is, &cinfo->type->params, cancellable, error))
+
+       success = imapx_parse_param_list (
+               stream, &cinfo->type->params, cancellable, error);
+
+       if (!success)
                goto error;
 
        /* body_fld_id     ::= nstring */
-       if (!camel_imapx_stream_nstring (is, &token, cancellable, error))
+       success = camel_imapx_input_stream_nstring (
+               stream, &token, cancellable, error);
+
+       if (!success)
                goto error;
+
        cinfo->id = g_strdup ((gchar *) token);
 
        /* body_fld_desc   ::= nstring */
-       if (!camel_imapx_stream_nstring (is, &token, cancellable, error))
+       success = camel_imapx_input_stream_nstring (
+               stream, &token, cancellable, error);
+
+       if (!success)
                goto error;
+
        cinfo->description = g_strdup ((gchar *) token);
 
        /* body_fld_enc    ::= (<"> ("7BIT" / "8BIT" / "BINARY" / "BASE64"/
         * "QUOTED-PRINTABLE") <">) / string */
-       if (!camel_imapx_stream_astring (is, &token, cancellable, error))
+       success = camel_imapx_input_stream_astring (
+               stream, &token, cancellable, error);
+
+       if (!success)
                goto error;
+
        cinfo->encoding = g_strdup ((gchar *) token);
 
        /* body_fld_octets ::= number */
-       if (!camel_imapx_stream_number (is, &number, cancellable, error))
+       success = camel_imapx_input_stream_number (
+               stream, &number, cancellable, error);
+
+       if (!success)
                goto error;
+
        cinfo->size = number;
 
        return cinfo;
@@ -942,10 +1001,9 @@ error:
 }
 
 struct _camel_header_address *
-imapx_parse_address_list (CamelIMAPXStream *is,
+imapx_parse_address_list (CamelIMAPXInputStream *stream,
                           GCancellable *cancellable,
                           GError **error)
-/* throws PARSE,IO exception */
 {
        gint tok;
        guint len;
@@ -956,28 +1014,36 @@ imapx_parse_address_list (CamelIMAPXStream *is,
 
        /* "(" 1*address ")" / nil */
 
-       tok = camel_imapx_stream_token (is, &token, &len, cancellable, &local_error);
+       tok = camel_imapx_input_stream_token (
+               stream, &token, &len, cancellable, &local_error);
+
        if (tok == '(') {
                struct _camel_header_address *addr, *group = NULL;
                while (1) {
                        /* address         ::= "(" addr_name SPACE addr_adl SPACE addr_mailbox
                         * SPACE addr_host ")" */
-                       tok = camel_imapx_stream_token (is, &token, &len, cancellable, &local_error);
+                       tok = camel_imapx_input_stream_token (
+                               stream, &token, &len, cancellable, &local_error);
+
                        if (tok == ')')
                                break;
                        if (tok != '(') {
                                g_clear_error (&local_error);
                                camel_header_address_list_clear (&list);
-                               g_set_error (error, CAMEL_IMAPX_ERROR, 1, "missing '(' for address");
+                               g_set_error (
+                                       error, CAMEL_IMAPX_ERROR, 1,
+                                       "missing '(' for address");
                                return NULL;
                        }
 
                        addr = camel_header_address_new ();
                        addr->type = CAMEL_HEADER_ADDRESS_NAME;
-                       camel_imapx_stream_nstring (is, &token, cancellable, &local_error);
+                       camel_imapx_input_stream_nstring (
+                               stream, &token, cancellable, &local_error);
                        addr->name = g_strdup ((gchar *) token);
                        /* we ignore the route, nobody uses it in the real world */
-                       camel_imapx_stream_nstring (is, &token, cancellable, &local_error);
+                       camel_imapx_input_stream_nstring (
+                               stream, &token, cancellable, &local_error);
 
                        /* [RFC-822] group syntax is indicated by a special
                         * form of address structure in which the host name
@@ -987,14 +1053,19 @@ imapx_parse_address_list (CamelIMAPXStream *is,
                         * non-NIL, this is a start of group marker, and the
                         * mailbox name field holds the group name phrase. */
 
-                       camel_imapx_stream_nstring (is,(guchar **) &mbox, cancellable, &local_error);
+                       camel_imapx_input_stream_nstring (
+                               stream, (guchar **) &mbox,
+                               cancellable, &local_error);
+
                        mbox = g_strdup (mbox);
-                       camel_imapx_stream_nstring (is, &host, cancellable, &local_error);
+
+                       camel_imapx_input_stream_nstring (
+                               stream, &host, cancellable, &local_error);
+
                        if (host == NULL) {
                                if (mbox == NULL) {
                                        group = NULL;
                                } else {
-                                       d (is->tagprefix, "adding group '%s'\n", mbox);
                                        g_free (addr->name);
                                        addr->name = mbox;
                                        addr->type = CAMEL_HEADER_ADDRESS_GROUP;
@@ -1002,20 +1073,21 @@ imapx_parse_address_list (CamelIMAPXStream *is,
                                        group = addr;
                                }
                        } else {
-                               addr->v.addr = g_strdup_printf ("%s %s", mbox? mbox :"", (const gchar *) 
host);
+                               addr->v.addr = g_strdup_printf (
+                                       "%s %s", mbox ? mbox : "",
+                                       (const gchar *) host);
                                g_free (mbox);
-                               d (is->tagprefix, "adding address '%s'\n", addr->v.addr);
                                if (group != NULL)
                                        camel_header_address_add_member (group, addr);
                                else
                                        camel_header_address_list_append (&list, addr);
                        }
                        do {
-                               tok = camel_imapx_stream_token (is, &token, &len, cancellable, &local_error);
+                               tok = camel_imapx_input_stream_token (
+                                       stream, &token, &len,
+                                       cancellable, &local_error);
                        } while (tok != ')');
                }
-       } else {
-               d (is->tagprefix, "empty, nil '%s'\n", token);
        }
 
        /* CHEN TODO handle exception at required places */
@@ -1026,7 +1098,7 @@ imapx_parse_address_list (CamelIMAPXStream *is,
 }
 
 struct _CamelMessageInfo *
-imapx_parse_envelope (CamelIMAPXStream *is,
+imapx_parse_envelope (CamelIMAPXInputStream *stream,
                       GCancellable *cancellable,
                       GError **error)
 {
@@ -1043,11 +1115,11 @@ imapx_parse_envelope (CamelIMAPXStream *is,
         * SPACE env_cc SPACE env_bcc SPACE env_in_reply_to
         * SPACE env_message_id ")" */
 
-       p (is->tagprefix, "envelope\n");
-
        minfo = (CamelMessageInfoBase *) camel_message_info_new (NULL);
 
-       tok = camel_imapx_stream_token (is, &token, &len, cancellable, &local_error);
+       tok = camel_imapx_input_stream_token (
+               stream, &token, &len, cancellable, &local_error);
+
        if (tok != '(') {
                g_clear_error (&local_error);
                camel_message_info_unref (minfo);
@@ -1056,26 +1128,24 @@ imapx_parse_envelope (CamelIMAPXStream *is,
        }
 
        /* env_date        ::= nstring */
-       camel_imapx_stream_nstring (is, &token, cancellable, &local_error);
+       camel_imapx_input_stream_nstring (
+               stream, &token, cancellable, &local_error);
        minfo->date_sent = camel_header_decode_date ((gchar *) token, NULL);
 
        /* env_subject     ::= nstring */
-       camel_imapx_stream_nstring (is, &token, cancellable, &local_error);
+       camel_imapx_input_stream_nstring (
+               stream, &token, cancellable, &local_error);
        minfo->subject = camel_pstring_strdup ((gchar *) token);
 
        /* we merge from/sender into from, append should probably merge more smartly? */
 
        /* env_from        ::= "(" 1*address ")" / nil */
-       addr_from = imapx_parse_address_list (is, cancellable, &local_error);
+       addr_from = imapx_parse_address_list (stream, cancellable, &local_error);
 
        /* env_sender      ::= "(" 1*address ")" / nil */
-       addr = imapx_parse_address_list (is, cancellable, &local_error);
+       addr = imapx_parse_address_list (stream, cancellable, &local_error);
        if (addr_from) {
                camel_header_address_list_clear (&addr);
-#if 0
-               if (addr)
-                       camel_header_address_list_append_list (&addr_from, &addr);
-#endif
        } else {
                if (addr)
                        addr_from = addr;
@@ -1091,11 +1161,11 @@ imapx_parse_envelope (CamelIMAPXStream *is,
        /* we dont keep reply_to */
 
        /* env_reply_to    ::= "(" 1*address ")" / nil */
-       addr = imapx_parse_address_list (is, cancellable, &local_error);
+       addr = imapx_parse_address_list (stream, cancellable, &local_error);
        camel_header_address_list_clear (&addr);
 
        /* env_to          ::= "(" 1*address ")" / nil */
-       addr = imapx_parse_address_list (is, cancellable, &local_error);
+       addr = imapx_parse_address_list (stream, cancellable, &local_error);
        if (addr) {
                addrstr = camel_header_address_list_format (addr);
                minfo->to = camel_pstring_strdup (addrstr);
@@ -1104,7 +1174,7 @@ imapx_parse_envelope (CamelIMAPXStream *is,
        }
 
        /* env_cc          ::= "(" 1*address ")" / nil */
-       addr = imapx_parse_address_list (is, cancellable, &local_error);
+       addr = imapx_parse_address_list (stream, cancellable, &local_error);
        if (addr) {
                addrstr = camel_header_address_list_format (addr);
                minfo->cc = camel_pstring_strdup (addrstr);
@@ -1115,20 +1185,24 @@ imapx_parse_envelope (CamelIMAPXStream *is,
        /* we dont keep bcc either */
 
        /* env_bcc         ::= "(" 1*address ")" / nil */
-       addr = imapx_parse_address_list (is, cancellable, &local_error);
+       addr = imapx_parse_address_list (stream, cancellable, &local_error);
        camel_header_address_list_clear (&addr);
 
        /* FIXME: need to put in-reply-to into references hash list */
 
        /* env_in_reply_to ::= nstring */
-       camel_imapx_stream_nstring (is, &token, cancellable, &local_error);
+       camel_imapx_input_stream_nstring (
+               stream, &token, cancellable, &local_error);
 
        /* FIXME: need to put message-id into message-id hash */
 
        /* env_message_id  ::= nstring */
-       camel_imapx_stream_nstring (is, &token, cancellable, &local_error);
+       camel_imapx_input_stream_nstring (
+               stream, &token, cancellable, &local_error);
+
+       tok = camel_imapx_input_stream_token (
+               stream, &token, &len, cancellable, &local_error);
 
-       tok = camel_imapx_stream_token (is, &token, &len, cancellable, &local_error);
        if (tok != ')') {
                g_clear_error (&local_error);
                camel_message_info_unref (minfo);
@@ -1144,7 +1218,7 @@ imapx_parse_envelope (CamelIMAPXStream *is,
 }
 
 struct _CamelMessageContentInfo *
-imapx_parse_body (CamelIMAPXStream *is,
+imapx_parse_body (CamelIMAPXInputStream *stream,
                   GCancellable *cancellable,
                   GError **error)
 {
@@ -1158,17 +1232,20 @@ imapx_parse_body (CamelIMAPXStream *is,
 
        /* body            ::= "(" body_type_1part / body_type_mpart ")" */
 
-       p (is->tagprefix, "body\n");
-
-       tok = camel_imapx_stream_token (is, &token, &len, cancellable, &local_error);
+       tok = camel_imapx_input_stream_token (
+               stream, &token, &len, cancellable, &local_error);
        if (tok != '(') {
-               g_set_error (error, CAMEL_IMAPX_ERROR, 1, "body: expecting '('");
+               g_set_error (
+                       error, CAMEL_IMAPX_ERROR, 1,
+                       "body: expecting '('");
                return NULL;
        }
 
        /* 1*body (optional for multiparts) */
-       tok = camel_imapx_stream_token (is, &token, &len, cancellable, &local_error);
-       camel_imapx_stream_ungettoken (is, tok, token, len);
+       tok = camel_imapx_input_stream_token (
+               stream, &token, &len, cancellable, &local_error);
+       camel_imapx_input_stream_ungettoken (stream, tok, token, len);
+
        if (tok == '(') {
                /* body_type_mpart ::= 1*body SPACE media_subtype
                [SPACE body_ext_mpart] */
@@ -1176,18 +1253,23 @@ imapx_parse_body (CamelIMAPXStream *is,
                cinfo = g_malloc0 (sizeof (*cinfo));
                last = (struct _CamelMessageContentInfo *) &cinfo->childs;
                do {
-                       subinfo = imapx_parse_body (is, cancellable, &local_error);
+                       subinfo = imapx_parse_body (
+                               stream, cancellable, &local_error);
                        last->next = subinfo;
                        last = subinfo;
                        subinfo->parent = cinfo;
-                       tok = camel_imapx_stream_token (is, &token, &len, cancellable, &local_error);
-                       camel_imapx_stream_ungettoken (is, tok, token, len);
+                       tok = camel_imapx_input_stream_token (
+                               stream, &token, &len,
+                               cancellable, &local_error);
+                       camel_imapx_input_stream_ungettoken (
+                               stream, tok, token, len);
                } while (tok == '(');
 
-               d (is->tagprefix, "media_subtype\n");
+               camel_imapx_input_stream_astring (
+                       stream, &token, cancellable, &local_error);
 
-               camel_imapx_stream_astring (is, &token, cancellable, &local_error);
-               cinfo->type = camel_content_type_new ("multipart", (gchar *) token);
+               cinfo->type = camel_content_type_new (
+                       "multipart", (gchar *) token);
 
                /* body_ext_mpart  ::= body_fld_param
                 * [SPACE body_fld_dsp SPACE body_fld_lang
@@ -1195,22 +1277,29 @@ imapx_parse_body (CamelIMAPXStream *is,
                 *    ;; MUST NOT be returned on non-extensible
                 *    ;; "BODY" fetch */
 
-               d (is->tagprefix, "body_ext_mpart\n");
+               tok = camel_imapx_input_stream_token (
+                       stream, &token, &len, cancellable, &local_error);
+               camel_imapx_input_stream_ungettoken (stream, tok, token, len);
 
-               tok = camel_imapx_stream_token (is, &token, &len, cancellable, &local_error);
-               camel_imapx_stream_ungettoken (is, tok, token, len);
                if (tok == '(') {
-                       imapx_parse_param_list (is, &cinfo->type->params, cancellable, &local_error);
+                       imapx_parse_param_list (
+                               stream, &cinfo->type->params,
+                               cancellable, &local_error);
 
                        /* body_fld_dsp    ::= "(" string SPACE body_fld_param ")" / nil */
 
-                       tok = camel_imapx_stream_token (is, &token, &len, cancellable, &local_error);
-                       camel_imapx_stream_ungettoken (is, tok, token, len);
+                       tok = camel_imapx_input_stream_token (
+                               stream, &token, &len, cancellable, &local_error);
+                       camel_imapx_input_stream_ungettoken (
+                               stream, tok, token, len);
+
                        if (tok == '(' || tok == IMAPX_TOK_TOKEN) {
-                               dinfo = imapx_parse_ext_optional (is, cancellable, &local_error);
+                               dinfo = imapx_parse_ext_optional (
+                                       stream, cancellable, &local_error);
                                /* other extension fields?, soaked up below */
                        } else {
-                               camel_imapx_stream_ungettoken (is, tok, token, len);
+                               camel_imapx_input_stream_ungettoken (
+                                       stream, tok, token, len);
                        }
                }
        } else {
@@ -1222,36 +1311,33 @@ imapx_parse_body (CamelIMAPXStream *is,
                 * body_type_msg   ::= media_message SPACE body_fields SPACE envelope
                 * SPACE body SPACE body_fld_lines */
 
-               d (is->tagprefix, "Single part body\n");
-
-               cinfo = imapx_parse_body_fields (is, cancellable, &local_error);
-
-               d (is->tagprefix, "envelope?\n");
+               cinfo = imapx_parse_body_fields (
+                       stream, cancellable, &local_error);
 
                /* do we have an envelope following */
-               tok = camel_imapx_stream_token (is, &token, &len, cancellable, &local_error);
-               camel_imapx_stream_ungettoken (is, tok, token, len);
+               tok = camel_imapx_input_stream_token (
+                       stream, &token, &len, cancellable, &local_error);
+               camel_imapx_input_stream_ungettoken (stream, tok, token, len);
                if (tok == '(') {
                        struct _CamelMessageInfo * minfo = NULL;
 
                        /* what do we do with the envelope?? */
-                       minfo = imapx_parse_envelope (is, cancellable, &local_error);
+                       minfo = imapx_parse_envelope (
+                               stream, cancellable, &local_error);
                        /* what do we do with the message content info?? */
-                       //((CamelMessageInfoBase *) minfo)->content = imapx_parse_body (is);
+                       //((CamelMessageInfoBase *) minfo)->content = imapx_parse_body (stream);
                        camel_message_info_unref (minfo);
                        minfo = NULL;
-                       d (is->tagprefix, "Scanned envelope - what do i do with it?\n");
                }
 
-               d (is->tagprefix, "fld_lines?\n");
-
                /* do we have fld_lines following? */
-               tok = camel_imapx_stream_token (is, &token, &len, cancellable, &local_error);
+               tok = camel_imapx_input_stream_token (
+                       stream, &token, &len, cancellable, &local_error);
                if (tok == IMAPX_TOK_INT) {
-                       d (is->tagprefix, "field lines: %s\n", token);
-                       tok = camel_imapx_stream_token (is, &token, &len, cancellable, &local_error);
+                       tok = camel_imapx_input_stream_token (
+                               stream, &token, &len, cancellable, &local_error);
                }
-               camel_imapx_stream_ungettoken (is, tok, token, len);
+               camel_imapx_input_stream_ungettoken (stream, tok, token, len);
 
                /* body_ext_1part  ::= body_fld_md5 [SPACE body_fld_dsp
                [SPACE body_fld_lang
@@ -1259,19 +1345,19 @@ imapx_parse_body (CamelIMAPXStream *is,
                 * ;; MUST NOT be returned on non - extensible
                 * ;; "BODY" fetch */
 
-               d (is->tagprefix, "extension data?\n");
-
                if (tok != ')') {
-                       camel_imapx_stream_nstring (is, &token, cancellable, &local_error);
-
-                       d (is->tagprefix, "md5: %s\n", token ? (gchar *) token:"NIL");
+                       camel_imapx_input_stream_nstring (
+                               stream, &token, cancellable, &local_error);
 
                        /* body_fld_dsp    ::= "(" string SPACE body_fld_param ")" / nil */
 
-                       tok = camel_imapx_stream_token (is, &token, &len, cancellable, &local_error);
-                       camel_imapx_stream_ungettoken (is, tok, token, len);
+                       tok = camel_imapx_input_stream_token (
+                               stream, &token, &len, cancellable, &local_error);
+                       camel_imapx_input_stream_ungettoken (
+                               stream, tok, token, len);
                        if (tok == '(' || tok == IMAPX_TOK_TOKEN) {
-                               dinfo = imapx_parse_ext_optional (is, cancellable, &local_error);
+                               dinfo = imapx_parse_ext_optional (
+                                       stream, cancellable, &local_error);
                                /* then other extension fields, soaked up below */
                        }
                }
@@ -1280,10 +1366,8 @@ imapx_parse_body (CamelIMAPXStream *is,
        /* soak up any other extension fields that may be present */
        /* there should only be simple tokens, no lists */
        do {
-               tok = camel_imapx_stream_token (is, &token, &len, cancellable, &local_error);
-               if (tok != ')') {
-                       d (is->tagprefix, "Dropping extension data '%s'\n", token);
-               }
+               tok = camel_imapx_input_stream_token (
+                       stream, &token, &len, cancellable, &local_error);
        } while (tok != ')');
 
        /* CHEN TODO handle exceptions better */
@@ -1304,7 +1388,7 @@ imapx_parse_body (CamelIMAPXStream *is,
 }
 
 gchar *
-imapx_parse_section (CamelIMAPXStream *is,
+imapx_parse_section (CamelIMAPXInputStream *stream,
                      GCancellable *cancellable,
                      GError **error)
 {
@@ -1324,20 +1408,28 @@ imapx_parse_section (CamelIMAPXStream *is,
         * SPACE header_list / "TEXT"
         */
 
-       tok = camel_imapx_stream_token (is, &token, &len, cancellable, NULL);
+       tok = camel_imapx_input_stream_token (
+               stream, &token, &len, cancellable, NULL);
+
        if (tok != '[') {
-               g_set_error (error, CAMEL_IMAPX_ERROR, 1, "section: expecting '['");
+               g_set_error (
+                       error, CAMEL_IMAPX_ERROR, 1,
+                       "section: expecting '['");
                return NULL;
        }
 
-       tok = camel_imapx_stream_token (is, &token, &len, cancellable, NULL);
+       tok = camel_imapx_input_stream_token (
+               stream, &token, &len, cancellable, NULL);
+
        if (tok == IMAPX_TOK_INT || tok == IMAPX_TOK_TOKEN)
                section = g_strdup ((gchar *) token);
        else if (tok == ']') {
                section = g_strdup ("");
-               camel_imapx_stream_ungettoken (is, tok, token, len);
+               camel_imapx_input_stream_ungettoken (stream, tok, token, len);
        } else {
-               g_set_error (error, CAMEL_IMAPX_ERROR, 1, "section: expecting token");
+               g_set_error (
+                       error, CAMEL_IMAPX_ERROR, 1,
+                       "section: expecting token");
                return NULL;
        }
 
@@ -1345,23 +1437,33 @@ imapx_parse_section (CamelIMAPXStream *is,
         * header_fld_name ::= astring */
 
        /* we dont need the header specifiers */
-       tok = camel_imapx_stream_token (is, &token, &len, cancellable, NULL);
+       tok = camel_imapx_input_stream_token (
+               stream, &token, &len, cancellable, NULL);
+
        if (tok == '(') {
                do {
-                       tok = camel_imapx_stream_token (is, &token, &len, cancellable, NULL);
+                       tok = camel_imapx_input_stream_token (
+                               stream, &token, &len, cancellable, NULL);
+
                        if (tok == IMAPX_TOK_STRING || tok == IMAPX_TOK_TOKEN || tok == IMAPX_TOK_INT) {
                                /* ?do something? */
                        } else if (tok != ')') {
-                               g_set_error (error, CAMEL_IMAPX_ERROR, 1, "section: header fields: expecting 
string");
+                               g_set_error (
+                                       error, CAMEL_IMAPX_ERROR, 1,
+                                       "section: header fields: expecting string");
                                g_free (section);
                                return NULL;
                        }
                } while (tok != ')');
-               tok = camel_imapx_stream_token (is, &token, &len, cancellable, NULL);
+
+               tok = camel_imapx_input_stream_token (
+                       stream, &token, &len, cancellable, NULL);
        }
 
        if (tok != ']') {
-               g_set_error (error, CAMEL_IMAPX_ERROR, 1, "section: expecting ']'");
+               g_set_error (
+                       error, CAMEL_IMAPX_ERROR, 1,
+                       "section: expecting ']'");
                g_free (section);
                return NULL;
        }
@@ -1370,7 +1472,7 @@ imapx_parse_section (CamelIMAPXStream *is,
 }
 
 static guint64
-imapx_parse_modseq (CamelIMAPXStream *is,
+imapx_parse_modseq (CamelIMAPXInputStream *stream,
                     GCancellable *cancellable,
                     GError **error)
 {
@@ -1378,8 +1480,10 @@ imapx_parse_modseq (CamelIMAPXStream *is,
        gint tok;
        guint len;
        guchar *token;
+       gboolean success;
 
-       tok = camel_imapx_stream_token (is, &token, &len, cancellable, error);
+       tok = camel_imapx_input_stream_token (
+               stream, &token, &len, cancellable, error);
 
        if (tok == CAMEL_IMAPX_ERROR)
                return 0;
@@ -1391,10 +1495,14 @@ imapx_parse_modseq (CamelIMAPXStream *is,
                return 0;
        }
 
-       if (!camel_imapx_stream_number (is, &modseq, cancellable, error))
+       success = camel_imapx_input_stream_number (
+               stream, &modseq, cancellable, error);
+
+       if (!success)
                return 0;
 
-       tok = camel_imapx_stream_token (is, &token, &len, cancellable, error);
+       tok = camel_imapx_input_stream_token (
+               stream, &token, &len, cancellable, error);
 
        if (tok == CAMEL_IMAPX_ERROR)
                return 0;
@@ -1503,7 +1611,7 @@ imapx_dump_fetch (struct _fetch_info *finfo)
 }
 
 static gboolean
-imapx_parse_fetch_body (CamelIMAPXStream *is,
+imapx_parse_fetch_body (CamelIMAPXInputStream *stream,
                         struct _fetch_info *finfo,
                         GCancellable *cancellable,
                         GError **error)
@@ -1512,15 +1620,16 @@ imapx_parse_fetch_body (CamelIMAPXStream *is,
        guchar *token;
        guint len;
 
-       tok = camel_imapx_stream_token (is, &token, &len, cancellable, error);
+       tok = camel_imapx_input_stream_token (
+               stream, &token, &len, cancellable, error);
 
        if (tok == IMAPX_TOK_ERROR)
                return FALSE;
 
-       camel_imapx_stream_ungettoken (is, tok, token, len);
+       camel_imapx_input_stream_ungettoken (stream, tok, token, len);
 
        if (tok == '(') {
-               finfo->cinfo = imapx_parse_body (is, cancellable, error);
+               finfo->cinfo = imapx_parse_body (stream, cancellable, error);
 
                if (finfo->cinfo != NULL)
                        finfo->got |= FETCH_CINFO;
@@ -1531,15 +1640,16 @@ imapx_parse_fetch_body (CamelIMAPXStream *is,
        if (tok == '[') {
                gboolean success;
 
-               finfo->section = imapx_parse_section (is, cancellable, error);
+               finfo->section = imapx_parse_section (
+                       stream, cancellable, error);
 
                if (finfo->section == NULL)
                        return FALSE;
 
                finfo->got |= FETCH_SECTION;
 
-               tok = camel_imapx_stream_token (
-                       is, &token, &len, cancellable, error);
+               tok = camel_imapx_input_stream_token (
+                       stream, &token, &len, cancellable, error);
 
                if (tok == IMAPX_TOK_ERROR)
                        return FALSE;
@@ -1548,11 +1658,12 @@ imapx_parse_fetch_body (CamelIMAPXStream *is,
                        finfo->offset = g_ascii_strtoull (
                                (gchar *) token + 1, NULL, 10);
                } else {
-                       camel_imapx_stream_ungettoken (is, tok, token, len);
+                       camel_imapx_input_stream_ungettoken (
+                               stream, tok, token, len);
                }
 
-               success = camel_imapx_stream_nstring_bytes (
-                       is, &finfo->body, cancellable, error);
+               success = camel_imapx_input_stream_nstring_bytes (
+                       stream, &finfo->body, cancellable, error);
 
                /* Sanity check. */
                g_return_val_if_fail (
@@ -1573,12 +1684,12 @@ imapx_parse_fetch_body (CamelIMAPXStream *is,
 }
 
 static gboolean
-imapx_parse_fetch_bodystructure (CamelIMAPXStream *is,
+imapx_parse_fetch_bodystructure (CamelIMAPXInputStream *stream,
                                  struct _fetch_info *finfo,
                                  GCancellable *cancellable,
                                  GError **error)
 {
-       finfo->cinfo = imapx_parse_body (is, cancellable, error);
+       finfo->cinfo = imapx_parse_body (stream, cancellable, error);
 
        if (finfo->cinfo != NULL)
                finfo->got |= FETCH_CINFO;
@@ -1587,12 +1698,12 @@ imapx_parse_fetch_bodystructure (CamelIMAPXStream *is,
 }
 
 static gboolean
-imapx_parse_fetch_envelope (CamelIMAPXStream *is,
+imapx_parse_fetch_envelope (CamelIMAPXInputStream *stream,
                             struct _fetch_info *finfo,
                             GCancellable *cancellable,
                             GError **error)
 {
-       finfo->minfo = imapx_parse_envelope (is, cancellable, error);
+       finfo->minfo = imapx_parse_envelope (stream, cancellable, error);
 
        if (finfo->minfo != NULL)
                finfo->got |= FETCH_MINFO;
@@ -1601,7 +1712,7 @@ imapx_parse_fetch_envelope (CamelIMAPXStream *is,
 }
 
 static gboolean
-imapx_parse_fetch_flags (CamelIMAPXStream *is,
+imapx_parse_fetch_flags (CamelIMAPXInputStream *stream,
                          struct _fetch_info *finfo,
                          GCancellable *cancellable,
                          GError **error)
@@ -1609,7 +1720,8 @@ imapx_parse_fetch_flags (CamelIMAPXStream *is,
        gboolean success;
 
        success = imapx_parse_flags (
-               is, &finfo->flags, &finfo->user_flags, cancellable, error);
+               stream, &finfo->flags, &finfo->user_flags,
+               cancellable, error);
 
        if (success)
                finfo->got |= FETCH_FLAGS;
@@ -1618,14 +1730,18 @@ imapx_parse_fetch_flags (CamelIMAPXStream *is,
 }
 
 static gboolean
-imapx_parse_fetch_internaldate (CamelIMAPXStream *is,
+imapx_parse_fetch_internaldate (CamelIMAPXInputStream *stream,
                                 struct _fetch_info *finfo,
                                 GCancellable *cancellable,
                                 GError **error)
 {
        guchar *token;
+       gboolean success;
 
-       if (!camel_imapx_stream_nstring (is, &token, cancellable, error))
+       success = camel_imapx_input_stream_nstring (
+               stream, &token, cancellable, error);
+
+       if (!success)
                return FALSE;
 
        /* XXX Convert to Camel format? */
@@ -1636,12 +1752,12 @@ imapx_parse_fetch_internaldate (CamelIMAPXStream *is,
 }
 
 static gboolean
-imapx_parse_fetch_modseq (CamelIMAPXStream *is,
+imapx_parse_fetch_modseq (CamelIMAPXInputStream *stream,
                           struct _fetch_info *finfo,
                           GCancellable *cancellable,
                           GError **error)
 {
-       finfo->modseq = imapx_parse_modseq (is, cancellable, error);
+       finfo->modseq = imapx_parse_modseq (stream, cancellable, error);
 
        if (finfo->modseq > 0)
                finfo->got |= FETCH_MODSEQ;
@@ -1650,15 +1766,15 @@ imapx_parse_fetch_modseq (CamelIMAPXStream *is,
 }
 
 static gboolean
-imapx_parse_fetch_rfc822_header (CamelIMAPXStream *is,
+imapx_parse_fetch_rfc822_header (CamelIMAPXInputStream *stream,
                                  struct _fetch_info *finfo,
                                  GCancellable *cancellable,
                                  GError **error)
 {
        gboolean success;
 
-       success = camel_imapx_stream_nstring_bytes (
-               is, &finfo->header, cancellable, error);
+       success = camel_imapx_input_stream_nstring_bytes (
+               stream, &finfo->header, cancellable, error);
 
        /* Sanity check. */
        g_return_val_if_fail (
@@ -1672,14 +1788,18 @@ imapx_parse_fetch_rfc822_header (CamelIMAPXStream *is,
 }
 
 static gboolean
-imapx_parse_fetch_rfc822_size (CamelIMAPXStream *is,
+imapx_parse_fetch_rfc822_size (CamelIMAPXInputStream *stream,
                                struct _fetch_info *finfo,
                                GCancellable *cancellable,
                                GError **error)
 {
        guint64 number;
+       gboolean success;
 
-       if (!camel_imapx_stream_number (is, &number, cancellable, error))
+       success = camel_imapx_input_stream_number (
+               stream, &number, cancellable, error);
+
+       if (!success)
                return FALSE;
 
        finfo->size = (guint32) number;
@@ -1689,15 +1809,15 @@ imapx_parse_fetch_rfc822_size (CamelIMAPXStream *is,
 }
 
 static gboolean
-imapx_parse_fetch_rfc822_text (CamelIMAPXStream *is,
+imapx_parse_fetch_rfc822_text (CamelIMAPXInputStream *stream,
                                struct _fetch_info *finfo,
                                GCancellable *cancellable,
                                GError **error)
 {
        gboolean success;
 
-       success = camel_imapx_stream_nstring_bytes (
-               is, &finfo->text, cancellable, error);
+       success = camel_imapx_input_stream_nstring_bytes (
+               stream, &finfo->text, cancellable, error);
 
        /* Sanity check. */
        g_return_val_if_fail (
@@ -1711,7 +1831,7 @@ imapx_parse_fetch_rfc822_text (CamelIMAPXStream *is,
 }
 
 static gboolean
-imapx_parse_fetch_uid (CamelIMAPXStream *is,
+imapx_parse_fetch_uid (CamelIMAPXInputStream *stream,
                        struct _fetch_info *finfo,
                        GCancellable *cancellable,
                        GError **error)
@@ -1720,7 +1840,8 @@ imapx_parse_fetch_uid (CamelIMAPXStream *is,
        guchar *token;
        guint len;
 
-       tok = camel_imapx_stream_token (is, &token, &len, cancellable, error);
+       tok = camel_imapx_input_stream_token (
+               stream, &token, &len, cancellable, error);
 
        if (tok == IMAPX_TOK_ERROR)
                return FALSE;
@@ -1739,7 +1860,7 @@ imapx_parse_fetch_uid (CamelIMAPXStream *is,
 }
 
 struct _fetch_info *
-imapx_parse_fetch (CamelIMAPXStream *is,
+imapx_parse_fetch (CamelIMAPXInputStream *stream,
                    GCancellable *cancellable,
                    GError **error)
 {
@@ -1750,7 +1871,8 @@ imapx_parse_fetch (CamelIMAPXStream *is,
 
        finfo = g_malloc0 (sizeof (*finfo));
 
-       tok = camel_imapx_stream_token (is, &token, &len, cancellable, NULL);
+       tok = camel_imapx_input_stream_token (
+               stream, &token, &len, cancellable, error);
 
        if (tok == IMAPX_TOK_ERROR)
                goto fail;
@@ -1762,7 +1884,8 @@ imapx_parse_fetch (CamelIMAPXStream *is,
                goto fail;
        }
 
-       tok = camel_imapx_stream_token (is, &token, &len, cancellable, error);
+       tok = camel_imapx_input_stream_token (
+               stream, &token, &len, cancellable, error);
 
        while (tok == IMAPX_TOK_TOKEN) {
                gboolean success = FALSE;
@@ -1774,52 +1897,52 @@ imapx_parse_fetch (CamelIMAPXStream *is,
                switch (imapx_tokenise ((gchar *) token, len)) {
                        case IMAPX_BODY:
                                success = imapx_parse_fetch_body (
-                                       is, finfo, cancellable, error);
+                                       stream, finfo, cancellable, error);
                                break;
 
                        case IMAPX_BODYSTRUCTURE:
                                success = imapx_parse_fetch_bodystructure (
-                                       is, finfo, cancellable, error);
+                                       stream, finfo, cancellable, error);
                                break;
 
                        case IMAPX_ENVELOPE:
                                success = imapx_parse_fetch_envelope (
-                                       is, finfo, cancellable, error);
+                                       stream, finfo, cancellable, error);
                                break;
 
                        case IMAPX_FLAGS:
                                success = imapx_parse_fetch_flags (
-                                       is, finfo, cancellable, error);
+                                       stream, finfo, cancellable, error);
                                break;
 
                        case IMAPX_INTERNALDATE:
                                success = imapx_parse_fetch_internaldate (
-                                       is, finfo, cancellable, error);
+                                       stream, finfo, cancellable, error);
                                break;
 
                        case IMAPX_MODSEQ:
                                success = imapx_parse_fetch_modseq (
-                                       is, finfo, cancellable, error);
+                                       stream, finfo, cancellable, error);
                                break;
 
                        case IMAPX_RFC822_HEADER:
                                success = imapx_parse_fetch_rfc822_header (
-                                       is, finfo, cancellable, error);
+                                       stream, finfo, cancellable, error);
                                break;
 
                        case IMAPX_RFC822_SIZE:
                                success = imapx_parse_fetch_rfc822_size (
-                                       is, finfo, cancellable, error);
+                                       stream, finfo, cancellable, error);
                                break;
 
                        case IMAPX_RFC822_TEXT:
                                success = imapx_parse_fetch_rfc822_text (
-                                       is, finfo, cancellable, error);
+                                       stream, finfo, cancellable, error);
                                break;
 
                        case IMAPX_UID:
                                success = imapx_parse_fetch_uid (
-                                       is, finfo, cancellable, error);
+                                       stream, finfo, cancellable, error);
                                break;
 
                        default:
@@ -1832,8 +1955,8 @@ imapx_parse_fetch (CamelIMAPXStream *is,
                if (!success)
                        goto fail;
 
-               tok = camel_imapx_stream_token (
-                       is, &token, &len, cancellable, error);
+               tok = camel_imapx_input_stream_token (
+                       stream, &token, &len, cancellable, error);
        }
 
        if (tok == IMAPX_TOK_ERROR)
@@ -1857,7 +1980,7 @@ exit:
 }
 
 GArray *
-imapx_parse_uids (CamelIMAPXStream *is,
+imapx_parse_uids (CamelIMAPXInputStream *stream,
                   GCancellable *cancellable,
                   GError **error)
 {
@@ -1867,7 +1990,10 @@ imapx_parse_uids (CamelIMAPXStream *is,
        guint len, str_len;
        gint tok, ii;
 
-       tok = camel_imapx_stream_token (is, &token, &len, cancellable, error);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_INPUT_STREAM (stream), NULL);
+
+       tok = camel_imapx_input_stream_token (
+               stream, &token, &len, cancellable, error);
        if (tok < 0)
                return NULL;
 
@@ -1899,19 +2025,26 @@ imapx_parse_uids (CamelIMAPXStream *is,
 }
 
 static gboolean
-imapx_parse_status_appenduid (CamelIMAPXStream *is,
+imapx_parse_status_appenduid (CamelIMAPXInputStream *stream,
                               struct _status_info *sinfo,
                               GCancellable *cancellable,
                               GError **error)
 {
        guint64 number;
+       gboolean success;
 
-       if (!camel_imapx_stream_number (is, &number, cancellable, error))
+       success = camel_imapx_input_stream_number (
+               stream, &number, cancellable, error);
+
+       if (!success)
                return FALSE;
 
        sinfo->u.appenduid.uidvalidity = number;
 
-       if (!camel_imapx_stream_number (is, &number, cancellable, error))
+       success = camel_imapx_input_stream_number (
+               stream, &number, cancellable, error);
+
+       if (!success)
                return FALSE;
 
        sinfo->u.appenduid.uid = (guint32) number;
@@ -1920,37 +2053,41 @@ imapx_parse_status_appenduid (CamelIMAPXStream *is,
 }
 
 static gboolean
-imapx_parse_status_capability (CamelIMAPXStream *is,
+imapx_parse_status_capability (CamelIMAPXInputStream *stream,
                                struct _status_info *sinfo,
                                GCancellable *cancellable,
                                GError **error)
 {
-       sinfo->u.cinfo = imapx_parse_capability (is, cancellable, error);
+       sinfo->u.cinfo = imapx_parse_capability (stream, cancellable, error);
 
        return (sinfo->u.cinfo != NULL);
 }
 
 static gboolean
-imapx_parse_status_copyuid (CamelIMAPXStream *is,
+imapx_parse_status_copyuid (CamelIMAPXInputStream *stream,
                             struct _status_info *sinfo,
                             GCancellable *cancellable,
                             GError **error)
 {
        GArray *uids;
        guint64 number;
+       gboolean success;
+
+       success = camel_imapx_input_stream_number (
+               stream, &number, cancellable, error);
 
-       if (!camel_imapx_stream_number (is, &number, cancellable, error))
+       if (!success)
                return FALSE;
 
        sinfo->u.copyuid.uidvalidity = number;
 
-       uids = imapx_parse_uids (is, cancellable, error);
+       uids = imapx_parse_uids (stream, cancellable, error);
        if (uids == NULL)
                return FALSE;
 
        sinfo->u.copyuid.uids = uids;
 
-       uids = imapx_parse_uids (is, cancellable, error);
+       uids = imapx_parse_uids (stream, cancellable, error);
        if (uids == NULL)
                return FALSE;
 
@@ -1960,14 +2097,18 @@ imapx_parse_status_copyuid (CamelIMAPXStream *is,
 }
 
 static gboolean
-imapx_parse_status_highestmodseq (CamelIMAPXStream *is,
+imapx_parse_status_highestmodseq (CamelIMAPXInputStream *stream,
                                   CamelIMAPXMailbox *mailbox,
                                   GCancellable *cancellable,
                                   GError **error)
 {
        guint64 number;
+       gboolean success;
+
+       success = camel_imapx_input_stream_number (
+               stream, &number, cancellable, error);
 
-       if (!camel_imapx_stream_number (is, &number, cancellable, error))
+       if (!success)
                return FALSE;
 
        camel_imapx_mailbox_set_highestmodseq (mailbox, number);
@@ -1976,21 +2117,28 @@ imapx_parse_status_highestmodseq (CamelIMAPXStream *is,
 }
 
 static gboolean
-imapx_parse_status_newname (CamelIMAPXStream *is,
+imapx_parse_status_newname (CamelIMAPXInputStream *stream,
                             struct _status_info *sinfo,
                             GCancellable *cancellable,
                             GError **error)
 {
        guchar *token;
+       gboolean success;
 
        /* XXX The RFC doesn't specify the BNF grammer for this. */
 
-       if (!camel_imapx_stream_astring (is, &token, cancellable, error))
+       success = camel_imapx_input_stream_astring (
+               stream, &token, cancellable, error);
+
+       if (!success)
                return FALSE;
 
        sinfo->u.newname.oldname = g_strdup ((gchar *) token);
 
-       if (!camel_imapx_stream_astring (is, &token, cancellable, error))
+       success = camel_imapx_input_stream_astring (
+               stream, &token, cancellable, error);
+
+       if (!success)
                return FALSE;
 
        sinfo->u.newname.newname = g_strdup ((gchar *) token);
@@ -1999,7 +2147,7 @@ imapx_parse_status_newname (CamelIMAPXStream *is,
 }
 
 static gboolean
-imapx_parse_status_permanentflags (CamelIMAPXStream *is,
+imapx_parse_status_permanentflags (CamelIMAPXInputStream *stream,
                                    struct _status_info *sinfo,
                                    GCancellable *cancellable,
                                    GError **error)
@@ -2007,7 +2155,7 @@ imapx_parse_status_permanentflags (CamelIMAPXStream *is,
        guint32 flags;
 
        /* We only care about \* for permanent flags, not user flags. */
-       if (!imapx_parse_flags (is, &flags, NULL, cancellable, error))
+       if (!imapx_parse_flags (stream, &flags, NULL, cancellable, error))
                return FALSE;
 
        sinfo->u.permanentflags = flags;
@@ -2016,14 +2164,18 @@ imapx_parse_status_permanentflags (CamelIMAPXStream *is,
 }
 
 static gboolean
-imapx_parse_status_uidnext (CamelIMAPXStream *is,
+imapx_parse_status_uidnext (CamelIMAPXInputStream *stream,
                             CamelIMAPXMailbox *mailbox,
                             GCancellable *cancellable,
                             GError **error)
 {
        guint64 number;
+       gboolean success;
 
-       if (!camel_imapx_stream_number (is, &number, cancellable, error))
+       success = camel_imapx_input_stream_number (
+               stream, &number, cancellable, error);
+
+       if (!success)
                return FALSE;
 
        camel_imapx_mailbox_set_uidnext (mailbox, (guint32) number);
@@ -2032,14 +2184,18 @@ imapx_parse_status_uidnext (CamelIMAPXStream *is,
 }
 
 static gboolean
-imapx_parse_status_uidvalidity (CamelIMAPXStream *is,
+imapx_parse_status_uidvalidity (CamelIMAPXInputStream *stream,
                                 CamelIMAPXMailbox *mailbox,
                                 GCancellable *cancellable,
                                 GError **error)
 {
        guint64 number;
+       gboolean success;
 
-       if (!camel_imapx_stream_number (is, &number, cancellable, error))
+       success = camel_imapx_input_stream_number (
+               stream, &number, cancellable, error);
+
+       if (!success)
                return FALSE;
 
        camel_imapx_mailbox_set_uidvalidity (mailbox, (guint32) number);
@@ -2048,14 +2204,18 @@ imapx_parse_status_uidvalidity (CamelIMAPXStream *is,
 }
 
 static gboolean
-imapx_parse_status_unseen (CamelIMAPXStream *is,
+imapx_parse_status_unseen (CamelIMAPXInputStream *stream,
                            CamelIMAPXMailbox *mailbox,
                            GCancellable *cancellable,
                            GError **error)
 {
        guint64 number;
+       gboolean success;
 
-       if (!camel_imapx_stream_number (is, &number, cancellable, error))
+       success = camel_imapx_input_stream_number (
+               stream, &number, cancellable, error);
+
+       if (!success)
                return FALSE;
 
        camel_imapx_mailbox_set_unseen (mailbox, (guint32) number);
@@ -2066,7 +2226,7 @@ imapx_parse_status_unseen (CamelIMAPXStream *is,
 /* rfc 2060 section 7.1 Status Responses */
 /* should this start after [ or before the [? token_unget anyone? */
 struct _status_info *
-imapx_parse_status (CamelIMAPXStream *is,
+imapx_parse_status (CamelIMAPXInputStream *stream,
                     CamelIMAPXMailbox *mailbox,
                     GCancellable *cancellable,
                     GError **error)
@@ -2075,8 +2235,14 @@ imapx_parse_status (CamelIMAPXStream *is,
        guint len;
        guchar *token;
        struct _status_info *sinfo;
+       gboolean success;
 
-       if (!camel_imapx_stream_atom (is, &token, &len, cancellable, error))
+       g_return_val_if_fail (CAMEL_IS_IMAPX_INPUT_STREAM (stream), NULL);
+
+       success = camel_imapx_input_stream_atom (
+               stream, &token, &len, cancellable, error);
+
+       if (!success)
                return NULL;
 
        sinfo = g_malloc0 (sizeof (*sinfo));
@@ -2106,16 +2272,19 @@ imapx_parse_status (CamelIMAPXStream *is,
                        goto fail;
        }
 
-       tok = camel_imapx_stream_token (is, &token, &len, cancellable, error);
+       tok = camel_imapx_input_stream_token (
+               stream, &token, &len, cancellable, error);
 
        if (tok == IMAPX_TOK_ERROR)
                goto fail;
 
        if (tok == '[') {
-               gboolean success = TRUE;
+               gboolean success;
+
+               success = camel_imapx_input_stream_atom (
+                       stream, &token, &len, cancellable, error);
 
-               if (!camel_imapx_stream_atom (
-                       is, &token, &len, cancellable, error))
+               if (!success)
                        goto fail;
 
                sinfo->condition = imapx_tokenise ((gchar *) token, len);
@@ -2132,47 +2301,47 @@ imapx_parse_status (CamelIMAPXStream *is,
 
                        case IMAPX_APPENDUID:
                                success = imapx_parse_status_appenduid (
-                                       is, sinfo, cancellable, error);
+                                       stream, sinfo, cancellable, error);
                                break;
 
                        case IMAPX_CAPABILITY:
                                success = imapx_parse_status_capability (
-                                       is, sinfo, cancellable, error);
+                                       stream, sinfo, cancellable, error);
                                break;
 
                        case IMAPX_COPYUID:
                                success = imapx_parse_status_copyuid (
-                                       is, sinfo, cancellable, error);
+                                       stream, sinfo, cancellable, error);
                                break;
 
                        case IMAPX_HIGHESTMODSEQ:
                                success = imapx_parse_status_highestmodseq (
-                                       is, mailbox, cancellable, error);
+                                       stream, mailbox, cancellable, error);
                                break;
 
                        case IMAPX_NEWNAME:
                                success = imapx_parse_status_newname (
-                                       is, sinfo, cancellable, error);
+                                       stream, sinfo, cancellable, error);
                                break;
 
                        case IMAPX_PERMANENTFLAGS:
                                success = imapx_parse_status_permanentflags (
-                                       is, sinfo, cancellable, error);
+                                       stream, sinfo, cancellable, error);
                                break;
 
                        case IMAPX_UIDNEXT:
                                success = imapx_parse_status_uidnext (
-                                       is, mailbox, cancellable, error);
+                                       stream, mailbox, cancellable, error);
                                break;
 
                        case IMAPX_UIDVALIDITY:
                                success = imapx_parse_status_uidvalidity (
-                                       is, mailbox, cancellable, error);
+                                       stream, mailbox, cancellable, error);
                                break;
 
                        case IMAPX_UNSEEN:
                                success = imapx_parse_status_unseen (
-                                       is, mailbox, cancellable, error);
+                                       stream, mailbox, cancellable, error);
                                break;
 
                        /* RFC 5530 Response Codes */
@@ -2197,7 +2366,6 @@ imapx_parse_status (CamelIMAPXStream *is,
 
                        default:
                                sinfo->condition = IMAPX_UNKNOWN;
-                               d (is->tagprefix, "Got unknown response code: %s: ignored\n", token);
                }
 
                if (!success)
@@ -2205,7 +2373,8 @@ imapx_parse_status (CamelIMAPXStream *is,
 
                /* ignore anything we dont know about */
                do {
-                       tok = camel_imapx_stream_token (is, &token, &len, cancellable, NULL);
+                       tok = camel_imapx_input_stream_token (
+                               stream, &token, &len, cancellable, NULL);
                        if (tok == '\n' || tok < 0) {
                                g_set_error (
                                        error, CAMEL_IMAPX_ERROR, 1,
@@ -2214,12 +2383,14 @@ imapx_parse_status (CamelIMAPXStream *is,
                        }
                } while (tok != ']');
        } else {
-               camel_imapx_stream_ungettoken (is, tok, token, len);
+               camel_imapx_input_stream_ungettoken (stream, tok, token, len);
        }
 
        /* and take the human readable response */
-       if (!camel_imapx_stream_text (
-               is, (guchar **) &sinfo->text, cancellable, error))
+       success = camel_imapx_input_stream_text (
+               stream, (guchar **) &sinfo->text, cancellable, error);
+
+       if (!success)
                goto fail;
 
        goto exit;
@@ -2413,12 +2584,12 @@ exit:
 
 /**
  * camel_imapx_parse_mailbox:
- * @is: a #CamelIMAPXStream
+ * @stream: a #CamelIMAPXInputStream
  * @separator: the mailbox separator character
  * @cancellable: optional #GCancellable object, or %NULL
  * @error: return location for a #GError, or %NULL
  *
- * Parses a "mailbox" token from @is, with the special case for INBOX as
+ * Parses a "mailbox" token from @stream, with the special case for INBOX as
  * described in <ulink url="http://tools.ietf.org/html/rfc3501#section-5.1";>
  * RFC 3501 section 5.1</ulink>.
  *
@@ -2436,17 +2607,21 @@ exit:
  * Since: 3.10
  **/
 gchar *
-camel_imapx_parse_mailbox (CamelIMAPXStream *is,
+camel_imapx_parse_mailbox (CamelIMAPXInputStream *stream,
                            gchar separator,
                            GCancellable *cancellable,
                            GError **error)
 {
        guchar *token;
        gchar *mailbox_name;
+       gboolean success;
 
-       g_return_val_if_fail (CAMEL_IS_IMAPX_STREAM (is), NULL);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_INPUT_STREAM (stream), NULL);
 
-       if (!camel_imapx_stream_astring (is, &token, cancellable, error))
+       success = camel_imapx_input_stream_astring (
+               stream, &token, cancellable, error);
+
+       if (!success)
                return NULL;
 
        mailbox_name = camel_utf7_utf8 ((gchar *) token);
@@ -2586,7 +2761,7 @@ camel_imapx_folder_path_to_mailbox (const gchar *folder_path,
 }
 
 gboolean
-camel_imapx_parse_quota (CamelIMAPXStream *is,
+camel_imapx_parse_quota (CamelIMAPXInputStream *stream,
                          GCancellable *cancellable,
                          gchar **out_quota_root_name,
                          CamelFolderQuotaInfo **out_quota_info,
@@ -2602,8 +2777,9 @@ camel_imapx_parse_quota (CamelIMAPXStream *is,
        gchar *resource_name = NULL;
        guint64 resource_usage;
        guint64 resource_limit;
+       gboolean success;
 
-       g_return_val_if_fail (CAMEL_IS_IMAPX_STREAM (is), FALSE);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_INPUT_STREAM (stream), FALSE);
        g_return_val_if_fail (out_quota_root_name != NULL, FALSE);
        g_return_val_if_fail (out_quota_info != NULL, FALSE);
 
@@ -2611,12 +2787,16 @@ camel_imapx_parse_quota (CamelIMAPXStream *is,
         * quota_list      ::= "(" #quota_resource ")"
         * quota_resource  ::= atom SP number SP number */
 
-       if (!camel_imapx_stream_astring (is, &token, cancellable, error))
+       success = camel_imapx_input_stream_astring (
+               stream, &token, cancellable, error);
+
+       if (!success)
                goto fail;
 
        quota_root_name = g_strdup ((gchar *) token);
 
-       tok = camel_imapx_stream_token (is, &token, &len, cancellable, error);
+       tok = camel_imapx_input_stream_token (
+               stream, &token, &len, cancellable, error);
        switch (tok) {
                case IMAPX_TOK_ERROR:
                        goto fail;
@@ -2631,17 +2811,24 @@ camel_imapx_parse_quota (CamelIMAPXStream *is,
 
 quota_resource:
 
-       if (!camel_imapx_stream_atom (is, &token, &len, cancellable, error))
+       success = camel_imapx_input_stream_atom (
+               stream, &token, &len, cancellable, error);
+
+       if (!success)
                goto fail;
 
        resource_name = g_strdup ((gchar *) token);
 
-       if (!camel_imapx_stream_number (
-               is, &resource_usage, cancellable, error))
+       success = camel_imapx_input_stream_number (
+               stream, &resource_usage, cancellable, error);
+
+       if (!success)
                goto fail;
 
-       if (!camel_imapx_stream_number (
-               is, &resource_limit, cancellable, error))
+       success = camel_imapx_input_stream_number (
+               stream, &resource_limit, cancellable, error);
+
+       if (!success)
                goto fail;
 
        info = camel_folder_quota_info_new (
@@ -2651,19 +2838,24 @@ quota_resource:
        g_free (resource_name);
        resource_name = NULL;
 
-       tok = camel_imapx_stream_token (is, &token, &len, cancellable, error);
+       tok = camel_imapx_input_stream_token (
+               stream, &token, &len, cancellable, error);
        switch (tok) {
                case IMAPX_TOK_ERROR:
                        goto fail;
                case ')':
                        break;
                default:
-                       camel_imapx_stream_ungettoken (is, tok, token, len);
+                       camel_imapx_input_stream_ungettoken (
+                               stream, tok, token, len);
                        goto quota_resource;
        }
 
        /* Eat the newline. */
-       if (!camel_imapx_stream_skip (is, cancellable, error))
+       success = camel_imapx_input_stream_skip (
+               stream, cancellable, error);
+
+       if (!success)
                goto fail;
 
        /* String together all the CamelFolderQuotaInfo structs. */
@@ -2694,7 +2886,7 @@ fail:
 }
 
 gboolean
-camel_imapx_parse_quotaroot (CamelIMAPXStream *is,
+camel_imapx_parse_quotaroot (CamelIMAPXInputStream *stream,
                              GCancellable *cancellable,
                              gchar **out_mailbox_name,
                              gchar ***out_quota_roots,
@@ -2706,15 +2898,20 @@ camel_imapx_parse_quotaroot (CamelIMAPXStream *is,
        guchar *token;
        gchar *mailbox_name = NULL;
        gchar **quota_roots = NULL;
+       gboolean success;
        gint ii = 0;
 
-       g_return_val_if_fail (CAMEL_IS_IMAPX_STREAM (is), FALSE);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_INPUT_STREAM (stream), FALSE);
        g_return_val_if_fail (out_mailbox_name != NULL, FALSE);
        g_return_val_if_fail (out_quota_roots != NULL, FALSE);
 
        /* quotaroot_response ::= "QUOTAROOT" SP astring *(SP astring) */
 
-       if (!camel_imapx_stream_astring (is, &token, cancellable, error))
+       success = camel_imapx_input_stream_astring (
+               CAMEL_IMAPX_INPUT_STREAM (stream),
+               &token, cancellable, error);
+
+       if (!success)
                goto fail;
 
        mailbox_name = camel_utf7_utf8 ((gchar *) token);
@@ -2722,16 +2919,22 @@ camel_imapx_parse_quotaroot (CamelIMAPXStream *is,
        while (TRUE) {
                /* Peek at the next token, and break
                 * out of the loop if we get a newline. */
-               tok = camel_imapx_stream_token (
-                       is, &token, &len, cancellable, error);
+               tok = camel_imapx_input_stream_token (
+                       CAMEL_IMAPX_INPUT_STREAM (stream),
+                       &token, &len, cancellable, error);
                if (tok == '\n')
                        break;
                if (tok == IMAPX_TOK_ERROR)
                        goto fail;
-               camel_imapx_stream_ungettoken (is, tok, token, len);
+               camel_imapx_input_stream_ungettoken (
+                       CAMEL_IMAPX_INPUT_STREAM (stream),
+                       tok, token, len);
 
-               if (!camel_imapx_stream_astring (
-                       is, &token, cancellable, error))
+               success = camel_imapx_input_stream_astring (
+                       CAMEL_IMAPX_INPUT_STREAM (stream),
+                       &token, cancellable, error);
+
+               if (!success)
                        goto fail;
 
                g_queue_push_tail (&queue, g_strdup ((gchar *) token));
diff --git a/camel/providers/imapx/camel-imapx-utils.h b/camel/providers/imapx/camel-imapx-utils.h
index c26bcc5..fff969b 100644
--- a/camel/providers/imapx/camel-imapx-utils.h
+++ b/camel/providers/imapx/camel-imapx-utils.h
@@ -20,6 +20,7 @@
 
 #include <camel/camel.h>
 
+#include "camel-imapx-input-stream.h"
 #include "camel-imapx-mailbox.h"
 
 G_BEGIN_DECLS
@@ -28,7 +29,6 @@ G_BEGIN_DECLS
  *       enum/struct definitions and helper macros, so we don't
  *       have these conflicting header dependencies. */
 struct _CamelIMAPXCommand;
-struct _CamelIMAPXStream;
 struct _CamelFlag;
 struct _CamelIMAPXStore;
 
@@ -130,10 +130,10 @@ enum {
 
 /* ********************************************************************** */
 
-GArray *       imapx_parse_uids                (struct _CamelIMAPXStream *is,
+GArray *       imapx_parse_uids                (CamelIMAPXInputStream *stream,
                                                 GCancellable *cancellable,
                                                 GError **error);
-gboolean       imapx_parse_flags               (struct _CamelIMAPXStream *is,
+gboolean       imapx_parse_flags               (CamelIMAPXInputStream *stream,
                                                 guint32 *flagsp,
                                                 struct _CamelFlag **user_flagsp,
                                                 GCancellable *cancellable,
@@ -194,38 +194,38 @@ struct _capability_info {
 };
 
 struct _capability_info *
-               imapx_parse_capability          (struct _CamelIMAPXStream *is,
+               imapx_parse_capability          (CamelIMAPXInputStream *stream,
                                                 GCancellable *cancellable,
                                                 GError **error);
 void           imapx_free_capability           (struct _capability_info *);
 guint32                imapx_register_capability       (const gchar *capability);
 guint32                imapx_lookup_capability         (const gchar *capability);
 
-gboolean       imapx_parse_param_list          (struct _CamelIMAPXStream *is,
+gboolean       imapx_parse_param_list          (CamelIMAPXInputStream *stream,
                                                 struct _camel_header_param **plist,
                                                 GCancellable *cancellable,
                                                 GError **error);
 struct _CamelContentDisposition *
-               imapx_parse_ext_optional        (struct _CamelIMAPXStream *is,
+               imapx_parse_ext_optional        (CamelIMAPXInputStream *stream,
                                                 GCancellable *cancellable,
                                                 GError **error);
 struct _CamelMessageContentInfo *
-               imapx_parse_body_fields         (struct _CamelIMAPXStream *is,
+               imapx_parse_body_fields         (CamelIMAPXInputStream *stream,
                                                 GCancellable *cancellable,
                                                 GError **error);
 struct _camel_header_address *
-               imapx_parse_address_list        (struct _CamelIMAPXStream *is,
+               imapx_parse_address_list        (CamelIMAPXInputStream *stream,
                                                 GCancellable *cancellable,
                                                 GError **error);
 struct _CamelMessageInfo *
-               imapx_parse_envelope            (struct _CamelIMAPXStream *is,
+               imapx_parse_envelope            (CamelIMAPXInputStream *stream,
                                                 GCancellable *cancellable,
                                                 GError **error);
 struct _CamelMessageContentInfo *
-               imapx_parse_body                (struct _CamelIMAPXStream *is,
+               imapx_parse_body                (CamelIMAPXInputStream *stream,
                                                 GCancellable *cancellable,
                                                 GError **error);
-gchar *                imapx_parse_section             (struct _CamelIMAPXStream *is,
+gchar *                imapx_parse_section             (CamelIMAPXInputStream *stream,
                                                 GCancellable *cancellable,
                                                 GError **error);
 void           imapx_free_body                 (struct _CamelMessageContentInfo *cinfo);
@@ -264,7 +264,7 @@ struct _fetch_info {
 #define FETCH_MODSEQ (1 << 11)
 
 struct _fetch_info *
-               imapx_parse_fetch               (struct _CamelIMAPXStream *is,
+               imapx_parse_fetch               (CamelIMAPXInputStream *stream,
                                                 GCancellable *cancellable,
                                                 GError **error);
 void           imapx_free_fetch                (struct _fetch_info *finfo);
@@ -298,7 +298,7 @@ struct _status_info {
 };
 
 struct _status_info *
-               imapx_parse_status              (struct _CamelIMAPXStream *is,
+               imapx_parse_status              (CamelIMAPXInputStream *stream,
                                                 CamelIMAPXMailbox *mailbox,
                                                 GCancellable *cancellable,
                                                 GError **error);
@@ -314,7 +314,7 @@ gboolean    camel_imapx_command_add_qresync_parameter
 
 /* ********************************************************************** */
 
-gchar *                camel_imapx_parse_mailbox       (struct _CamelIMAPXStream *is,
+gchar *                camel_imapx_parse_mailbox       (CamelIMAPXInputStream *stream,
                                                 gchar separator,
                                                 GCancellable *cancellable,
                                                 GError **error);
@@ -330,12 +330,12 @@ gchar *           camel_imapx_folder_path_to_mailbox
 
 /* ********************************************************************** */
 
-gboolean       camel_imapx_parse_quota         (struct _CamelIMAPXStream *is,
+gboolean       camel_imapx_parse_quota         (CamelIMAPXInputStream *stream,
                                                 GCancellable *cancellable,
                                                 gchar **out_quota_root_name,
                                                 CamelFolderQuotaInfo **out_quota_info,
                                                 GError **error);
-gboolean       camel_imapx_parse_quotaroot     (struct _CamelIMAPXStream *is,
+gboolean       camel_imapx_parse_quotaroot     (CamelIMAPXInputStream *stream,
                                                 GCancellable *cancellable,
                                                 gchar **out_mailbox_name,
                                                 gchar ***out_quota_roots,
diff --git a/docs/reference/camel/camel-sections.txt b/docs/reference/camel/camel-sections.txt
index 012c9c5..0ae22f3 100644
--- a/docs/reference/camel/camel-sections.txt
+++ b/docs/reference/camel/camel-sections.txt
@@ -3379,6 +3379,41 @@ CamelIMAPXFolderPrivate
 </SECTION>
 
 <SECTION>
+<FILE>camel-imapx-input-stream</FILE>
+<TITLE>CamelIMAPXInputStream</TITLE>
+CAMEL_IMAPX_ERROR
+CamelIMAPXInputStream
+camel_imapx_input_stream_new
+camel_imapx_input_stream_buffered
+camel_imapx_token_t
+camel_imapx_input_stream_token
+camel_imapx_input_stream_ungettoken
+camel_imapx_input_stream_set_literal
+camel_imapx_input_stream_gets
+camel_imapx_input_stream_getl
+camel_imapx_input_stream_atom
+camel_imapx_input_stream_astring
+camel_imapx_input_stream_nstring
+camel_imapx_input_stream_nstring_bytes
+camel_imapx_input_stream_text
+camel_imapx_input_stream_number
+camel_imapx_input_stream_skip
+camel_imapx_input_stream_skip_until
+<SUBSECTION Standard>
+CAMEL_IMAPX_INPUT_STREAM
+CAMEL_IS_IMAPX_INPUT_STREAM
+CAMEL_TYPE_IMAPX_INPUT_STREAM
+CAMEL_IMAPX_INPUT_STREAM_CLASS
+CAMEL_IS_IMAPX_INPUT_STREAM_CLASS
+CAMEL_IMAPX_INPUT_STREAM_GET_CLASS
+CamelIMAPXInputStreamClass
+camel_imapx_input_stream_get_type
+<SUBSECTION Private>
+CamelIMAPXInputStreamPrivate
+camel_imapx_error_quark
+</SECTION>
+
+<SECTION>
 <FILE>camel-imapx-job</FILE>
 <TITLE>CamelIMAPXJob</TITLE>
 CAMEL_IS_IMAPX_JOB
@@ -3588,7 +3623,6 @@ CamelIMAPXServer
 camel_imapx_server_new
 camel_imapx_server_ref_store
 camel_imapx_server_ref_settings
-camel_imapx_server_ref_stream
 camel_imapx_server_ref_input_stream
 camel_imapx_server_ref_output_stream
 camel_imapx_server_ref_namespaces
diff --git a/docs/reference/camel/camel.types b/docs/reference/camel/camel.types
index 7c9dd93..0fc6946 100644
--- a/docs/reference/camel/camel.types
+++ b/docs/reference/camel/camel.types
@@ -19,6 +19,7 @@
 #include <local/camel-spool-summary.h>
 
 #include <imapx/camel-imapx-folder.h>
+#include <imapx/camel-imapx-input-stream.h>
 #include <imapx/camel-imapx-list-response.h>
 #include <imapx/camel-imapx-logger.h>
 #include <imapx/camel-imapx-mailbox.h>
@@ -164,6 +165,7 @@ camel_spool_store_get_type
 camel_spool_summary_get_type
 
 camel_imapx_folder_get_type
+camel_imapx_input_stream_get_type
 camel_imapx_list_response_get_type
 camel_imapx_logger_get_type
 camel_imapx_mailbox_get_type


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