[evolution-data-server] Make CamelNNTPStore a bit more thread-safe.



commit fbf1ac4ac492951a3d6877e73961004741a0591c
Author: Matthew Barnes <mbarnes redhat com>
Date:   Mon May 20 22:48:40 2013 -0400

    Make CamelNNTPStore a bit more thread-safe.
    
    * Make CamelNNTPStore's public members private.
    
    * Guard the private CamelNNTPStore members with a mutex.
    
    * Add thread-safe accessors:
    
        camel_nntp_store_ref_cache()
        camel_nntp_store_ref_stream()
        camel_nntp_store_ref_summary()
        camel_nntp_store_get_current_group()
        camel_nntp_store_dup_current_group()
        camel_nntp_store_set_current_group()
        camel_nntp_store_add_capabilities()
        camel_nntp_store_has_capabilities()
        camel_nntp_store_remove_capabilities()

 camel/providers/nntp/camel-nntp-folder.c  |  152 ++++--
 camel/providers/nntp/camel-nntp-store.c   |  856 ++++++++++++++++++++++-------
 camel/providers/nntp/camel-nntp-store.h   |   45 +-
 camel/providers/nntp/camel-nntp-stream.c  |   18 +-
 camel/providers/nntp/camel-nntp-stream.h  |    5 +-
 camel/providers/nntp/camel-nntp-summary.c |   84 ++-
 6 files changed, 853 insertions(+), 307 deletions(-)
---
diff --git a/camel/providers/nntp/camel-nntp-folder.c b/camel/providers/nntp/camel-nntp-folder.c
index f1604f1..081859e 100644
--- a/camel/providers/nntp/camel-nntp-folder.c
+++ b/camel/providers/nntp/camel-nntp-folder.c
@@ -111,17 +111,22 @@ nntp_folder_get_property (GObject *object,
 static void
 nntp_folder_dispose (GObject *object)
 {
-       CamelStore *parent_store;
-       CamelNNTPFolder *nntp_folder = CAMEL_NNTP_FOLDER (object);
+       CamelFolder *folder;
+       CamelStore *store;
 
-       camel_folder_summary_save_to_db (
-               CAMEL_FOLDER (nntp_folder)->summary, NULL);
+       folder = CAMEL_FOLDER (object);
+       camel_folder_summary_save_to_db (folder->summary, NULL);
 
-       parent_store = camel_folder_get_parent_store (CAMEL_FOLDER (nntp_folder));
-       if (parent_store) {
+       store = camel_folder_get_parent_store (folder);
+       if (store != NULL) {
+               CamelNNTPStoreSummary *nntp_store_summary;
+
+               nntp_store_summary = camel_nntp_store_ref_summary (
+                       CAMEL_NNTP_STORE (store));
                camel_store_summary_disconnect_folder_summary (
-                       (CamelStoreSummary *) ((CamelNNTPStore *) parent_store)->summary,
-                       CAMEL_FOLDER (nntp_folder)->summary);
+                       CAMEL_STORE_SUMMARY (nntp_store_summary),
+                       folder->summary);
+               g_clear_object (&nntp_store_summary);
        }
 
        /* Chain up to parent's dispose() method. */
@@ -263,8 +268,10 @@ nntp_get_filename (CamelFolder *folder,
                    GError **error)
 {
        CamelStore *parent_store;
+       CamelDataCache *nntp_cache;
        CamelNNTPStore *nntp_store;
        gchar *article, *msgid;
+       gchar *filename;
 
        parent_store = camel_folder_get_parent_store (folder);
        nntp_store = CAMEL_NNTP_STORE (parent_store);
@@ -280,7 +287,11 @@ nntp_get_filename (CamelFolder *folder,
        }
        *msgid++ = 0;
 
-       return camel_data_cache_get_filename (nntp_store->cache, "cache", msgid);
+       nntp_cache = camel_nntp_store_ref_cache (nntp_store);
+       filename = camel_data_cache_get_filename (nntp_cache, "cache", msgid);
+       g_clear_object (&nntp_cache);
+
+       return filename;
 }
 
 static CamelStream *
@@ -292,25 +303,34 @@ nntp_folder_download_message (CamelNNTPFolder *nntp_folder,
 {
        CamelFolder *folder;
        CamelStore *parent_store;
+       CamelDataCache *nntp_cache;
        CamelNNTPStore *nntp_store;
+       CamelNNTPStream *nntp_stream;
        CamelStream *stream = NULL;
        gint ret;
        gchar *line;
 
        folder = CAMEL_FOLDER (nntp_folder);
        parent_store = camel_folder_get_parent_store (folder);
+
        nntp_store = CAMEL_NNTP_STORE (parent_store);
+       nntp_cache = camel_nntp_store_ref_cache (nntp_store);
+       nntp_stream = camel_nntp_store_ref_stream (nntp_store);
+
+       ret = camel_nntp_command (
+               nntp_store, cancellable, error,
+               nntp_folder, &line, "article %s", id);
 
-       ret = camel_nntp_command (nntp_store, cancellable, error, nntp_folder, &line, "article %s", id);
        if (ret == 220) {
-               stream = camel_data_cache_add (nntp_store->cache, "cache", msgid, NULL);
-               if (stream) {
+               stream = camel_data_cache_add (
+                       nntp_cache, "cache", msgid, NULL);
+               if (stream != NULL) {
                        gboolean success;
 
-                       if (camel_stream_write_to_stream ((CamelStream *) nntp_store->stream, stream, 
cancellable, error) == -1)
-                               goto fail;
-
-                       if ((error && *error) || g_cancellable_set_error_if_cancelled (cancellable, error))
+                       success = (camel_stream_write_to_stream (
+                               CAMEL_STREAM (nntp_stream),
+                               stream, cancellable, error) != -1);
+                       if (!success)
                                goto fail;
 
                        success = g_seekable_seek (
@@ -319,26 +339,34 @@ nntp_folder_download_message (CamelNNTPFolder *nntp_folder,
                        if (!success)
                                goto fail;
                } else {
-                       stream = g_object_ref (nntp_store->stream);
+                       stream = g_object_ref (nntp_stream);
                }
+
        } else if (ret == 423 || ret == 430) {
                g_set_error (
                        error, CAMEL_FOLDER_ERROR,
                        CAMEL_FOLDER_ERROR_INVALID_UID,
                        _("Cannot get message %s: %s"), msgid, line);
+
        } else if (ret != -1) {
                g_set_error (
                        error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
                        _("Cannot get message %s: %s"), msgid, line);
        }
 
-       return stream;
+       goto exit;
 
 fail:
-       camel_data_cache_remove (nntp_store->cache, "cache", msgid, NULL);
+       camel_data_cache_remove (nntp_cache, "cache", msgid, NULL);
        g_prefix_error (error, _("Cannot get message %s: "), msgid);
 
-       return NULL;
+       g_clear_object (&stream);
+
+exit:
+       g_clear_object (&nntp_cache);
+       g_clear_object (&nntp_stream);
+
+       return stream;
 }
 
 static gboolean
@@ -461,6 +489,7 @@ nntp_folder_get_message_sync (CamelFolder *folder,
 {
        CamelStore *parent_store;
        CamelMimeMessage *message = NULL;
+       CamelDataCache *nntp_cache;
        CamelNNTPStore *nntp_store;
        CamelFolderChangeInfo *changes;
        CamelNNTPFolder *nntp_folder;
@@ -484,7 +513,10 @@ nntp_folder_get_message_sync (CamelFolder *folder,
        *msgid++ = 0;
 
        /* Lookup in cache, NEWS is global messageid's so use a global cache path */
-       stream = camel_data_cache_get (nntp_store->cache, "cache", msgid, NULL);
+       nntp_cache = camel_nntp_store_ref_cache (nntp_store);
+       stream = camel_data_cache_get (nntp_cache, "cache", msgid, NULL);
+       g_clear_object (&nntp_cache);
+
        if (stream == NULL) {
                if (camel_disco_store_status ((CamelDiscoStore *) nntp_store) == CAMEL_DISCO_STORE_OFFLINE) {
                        g_set_error (
@@ -533,8 +565,8 @@ nntp_folder_append_message_online (CamelFolder *folder,
 {
        CamelStore *parent_store;
        CamelNNTPStore *nntp_store;
+       CamelNNTPStream *nntp_stream;
        CamelStream *filtered_stream;
-       CamelStream *stream;
        CamelMimeFilter *crlffilter;
        gint ret;
        guint u;
@@ -542,15 +574,17 @@ nntp_folder_append_message_online (CamelFolder *folder,
        const gchar *full_name;
        gchar *group, *line;
        gboolean success = TRUE;
+       GError *local_error = NULL;
 
        full_name = camel_folder_get_full_name (folder);
        parent_store = camel_folder_get_parent_store (folder);
 
        nntp_store = CAMEL_NNTP_STORE (parent_store);
-       stream = CAMEL_STREAM (nntp_store->stream);
+       nntp_stream = camel_nntp_store_ref_stream (nntp_store);
 
        /* send 'POST' command */
-       ret = camel_nntp_command (nntp_store, cancellable, error, NULL, &line, "post");
+       ret = camel_nntp_command (
+               nntp_store, cancellable, error, NULL, &line, "post");
        if (ret != 340) {
                if (ret == 440) {
                        g_set_error (
@@ -565,15 +599,17 @@ nntp_folder_append_message_online (CamelFolder *folder,
                                _("Posting failed: %s"), line);
                        success = FALSE;
                }
-               return success;
+               goto exit;
        }
 
        /* the 'Newsgroups: ' header */
        group = g_strdup_printf ("Newsgroups: %s\r\n", full_name);
 
        /* setup stream filtering */
-       crlffilter = camel_mime_filter_crlf_new (CAMEL_MIME_FILTER_CRLF_ENCODE, 
CAMEL_MIME_FILTER_CRLF_MODE_CRLF_DOTS);
-       filtered_stream = camel_stream_filter_new (stream);
+       filtered_stream = camel_stream_filter_new (CAMEL_STREAM (nntp_stream));
+       crlffilter = camel_mime_filter_crlf_new (
+               CAMEL_MIME_FILTER_CRLF_ENCODE,
+               CAMEL_MIME_FILTER_CRLF_MODE_CRLF_DOTS);
        camel_stream_filter_add (
                CAMEL_STREAM_FILTER (filtered_stream), crlffilter);
        g_object_unref (crlffilter);
@@ -598,17 +634,34 @@ nntp_folder_append_message_online (CamelFolder *folder,
        }
 
        /* write the message */
-       if (camel_stream_write (stream, group, strlen (group), cancellable, error) == -1
-           || camel_data_wrapper_write_to_stream_sync (CAMEL_DATA_WRAPPER (mime_message), filtered_stream, 
cancellable, error) == -1
-           || camel_stream_flush (filtered_stream, cancellable, error) == -1
-           || camel_stream_write (stream, "\r\n.\r\n", 5, cancellable, error) == -1
-           || camel_nntp_stream_line (nntp_store->stream, (guchar **) &line, &u, cancellable, error) == -1) {
-               g_prefix_error (error, _("Posting failed: "));
-               success = FALSE;
-       } else if (atoi (line) != 240) {
-               g_set_error (
-                       error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
-                       _("Posting failed: %s"), line);
+       if (local_error == NULL)
+               camel_stream_write (
+                       CAMEL_STREAM (nntp_stream),
+                       group, strlen (group),
+                       cancellable, &local_error);
+       if (local_error == NULL)
+               camel_data_wrapper_write_to_stream_sync (
+                       CAMEL_DATA_WRAPPER (mime_message),
+                       filtered_stream, cancellable, &local_error);
+       if (local_error == NULL)
+               camel_stream_flush (
+                       filtered_stream, cancellable, &local_error);
+       if (local_error == NULL)
+               camel_stream_write (
+                       CAMEL_STREAM (nntp_stream),
+                       "\r\n.\r\n", 5,
+                       cancellable, &local_error);
+       if (local_error == NULL)
+               camel_nntp_stream_line (
+                       nntp_stream, (guchar **) &line,
+                       &u, cancellable, &local_error);
+       if (local_error == NULL && atoi (line) != 240)
+               local_error = g_error_new_literal (
+                       CAMEL_ERROR, CAMEL_ERROR_GENERIC, line);
+
+       if (local_error != NULL) {
+               g_propagate_prefixed_error (
+                       error, local_error, _("Posting failed: "));
                success = FALSE;
        }
 
@@ -616,6 +669,9 @@ nntp_folder_append_message_online (CamelFolder *folder,
        g_free (group);
        header->next = savedhdrs;
 
+exit:
+       g_clear_object (&nntp_stream);
+
        return success;
 }
 
@@ -759,6 +815,8 @@ camel_nntp_folder_new (CamelStore *parent,
 {
        CamelFolder *folder;
        CamelNNTPFolder *nntp_folder;
+       CamelNNTPStore *nntp_store;
+       CamelNNTPStoreSummary *nntp_store_summary;
        gchar *root;
        CamelService *service;
        CamelSettings *settings;
@@ -803,16 +861,24 @@ camel_nntp_folder_new (CamelStore *parent,
 
        camel_folder_summary_load_from_db (folder->summary, NULL);
 
-       si = camel_store_summary_path ((CamelStoreSummary *) ((CamelNNTPStore *) parent)->summary, 
folder_name);
-       if (si) {
-               subscribed = (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) != 0;
-               camel_store_summary_info_free ((CamelStoreSummary *) ((CamelNNTPStore *) parent)->summary, 
si);
+       nntp_store = CAMEL_NNTP_STORE (parent);
+       nntp_store_summary = camel_nntp_store_ref_summary (nntp_store);
+
+       si = camel_store_summary_path (
+               CAMEL_STORE_SUMMARY (nntp_store_summary), folder_name);
+       if (si != NULL) {
+               subscribed =
+                       (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) != 0;
+               camel_store_summary_info_free (
+                       CAMEL_STORE_SUMMARY (nntp_store_summary), si);
        }
 
        camel_store_summary_connect_folder_summary (
-               (CamelStoreSummary *) ((CamelNNTPStore *) parent)->summary,
+               CAMEL_STORE_SUMMARY (nntp_store_summary),
                folder_name, folder->summary);
 
+       g_clear_object (&nntp_store_summary);
+
        if (subscribed && !camel_folder_refresh_info_sync (
                        folder, cancellable, error)) {
                g_object_unref (folder);
diff --git a/camel/providers/nntp/camel-nntp-store.c b/camel/providers/nntp/camel-nntp-store.c
index 2a8162c..0605401 100644
--- a/camel/providers/nntp/camel-nntp-store.c
+++ b/camel/providers/nntp/camel-nntp-store.c
@@ -48,6 +48,10 @@
 #include <ws2tcpip.h>
 #endif
 
+#define CAMEL_NNTP_STORE_GET_PRIVATE(obj) \
+       (G_TYPE_INSTANCE_GET_PRIVATE \
+       ((obj), CAMEL_TYPE_NNTP_STORE, CamelNNTPStorePrivate))
+
 #define w(x)
 #define dd(x) (camel_debug("nntp")?(x):0)
 
@@ -56,6 +60,15 @@
 
 #define DUMP_EXTENSIONS
 
+struct _CamelNNTPStorePrivate {
+       GMutex property_lock;
+       CamelDataCache *cache;
+       CamelNNTPStream *stream;
+       CamelNNTPStoreSummary *summary;
+       CamelNNTPCapabilities capabilities;
+       gchar *current_group;
+};
+
 enum {
        PROP_0,
        PROP_CONNECTABLE,
@@ -84,6 +97,26 @@ G_DEFINE_TYPE_WITH_CODE (
                camel_subscribable_init))
 
 static void
+nntp_store_reset_state (CamelNNTPStore *nntp_store,
+                        CamelNNTPStream *nntp_stream)
+{
+       if (nntp_stream != NULL)
+               g_object_ref (nntp_stream);
+
+       g_mutex_lock (&nntp_store->priv->property_lock);
+
+       g_clear_object (&nntp_store->priv->stream);
+       nntp_store->priv->stream = nntp_stream;
+
+       g_free (nntp_store->priv->current_group);
+       nntp_store->priv->current_group = NULL;
+
+       nntp_store->priv->capabilities = 0;
+
+       g_mutex_unlock (&nntp_store->priv->property_lock);
+}
+
+static void
 nntp_store_set_property (GObject *object,
                          guint property_id,
                          const GValue *value,
@@ -128,30 +161,24 @@ nntp_store_get_property (GObject *object,
 static void
 nntp_store_dispose (GObject *object)
 {
-       CamelNNTPStore *nntp_store = CAMEL_NNTP_STORE (object);
-       CamelDiscoStore *disco_store = CAMEL_DISCO_STORE (object);
+       CamelNNTPStorePrivate *priv;
+       CamelDiscoStore *disco_store;
+
+       priv = CAMEL_NNTP_STORE_GET_PRIVATE (object);
 
        /* Only run this the first time. */
-       if (nntp_store->summary != NULL)
+       if (priv->summary != NULL) {
                camel_service_disconnect_sync (
                        CAMEL_SERVICE (object), TRUE, NULL, NULL);
-
-       if (nntp_store->summary != NULL) {
                camel_store_summary_save (
-                       CAMEL_STORE_SUMMARY (nntp_store->summary));
-               g_object_unref (nntp_store->summary);
-               nntp_store->summary = NULL;
+                       CAMEL_STORE_SUMMARY (priv->summary));
        }
 
-       if (nntp_store->stream != NULL) {
-               g_object_unref (nntp_store->stream);
-               nntp_store->stream = NULL;
-       }
+       g_clear_object (&priv->cache);
+       g_clear_object (&priv->stream);
+       g_clear_object (&priv->summary);
 
-       if (nntp_store->cache != NULL) {
-               g_object_unref (nntp_store->cache);
-               nntp_store->cache = NULL;
-       }
+       disco_store = CAMEL_DISCO_STORE (object);
 
        if (disco_store->diary != NULL) {
                g_object_unref (disco_store->diary);
@@ -175,6 +202,8 @@ nntp_store_finalize (GObject *object)
                xover = xn;
        }
 
+       g_mutex_clear (&nntp_store->priv->property_lock);
+
        /* Chain up to parent's finalize() method. */
        G_OBJECT_CLASS (camel_nntp_store_parent_class)->finalize (object);
 }
@@ -186,35 +215,47 @@ nntp_can_work_offline (CamelDiscoStore *store)
 }
 
 static gint
-check_capabilities (CamelNNTPStore *store,
-             GCancellable *cancellable,
-             GError **error)
+check_capabilities (CamelNNTPStore *nntp_store,
+                    GCancellable *cancellable,
+                    GError **error)
 {
+       CamelNNTPStream *nntp_stream;
        gint ret;
        gchar *line;
        guint len;
 
-       store->capabilities = 0;
-
-       ret = camel_nntp_raw_command_auth (store, cancellable, error, &line, "CAPABILITIES");
+       ret = camel_nntp_raw_command_auth (
+               nntp_store, cancellable, error, &line, "CAPABILITIES");
        if (ret != 101)
                return -1;
 
-       while ((ret = camel_nntp_stream_line (store->stream, (guchar **) &line, &len, cancellable, error)) > 
0) {
+       nntp_stream = camel_nntp_store_ref_stream (nntp_store);
+
+       ret = camel_nntp_stream_line (
+               nntp_stream, (guchar **) &line, &len,
+               cancellable, error);
+       while (ret > 0) {
                while (len > 0 && g_ascii_isspace (*line)) {
                        line++;
                        len--;
                }
 
                if (len == 4 && g_ascii_strncasecmp (line, "OVER", len) == 0)
-                       store->capabilities |= NNTP_CAPABILITY_OVER;
+                       camel_nntp_store_add_capabilities (
+                               nntp_store, CAMEL_NNTP_CAPABILITY_OVER);
 
                if (len == 1 && g_ascii_strncasecmp (line, ".", len) == 0) {
                        ret = 0;
                        break;
                }
+
+               ret = camel_nntp_stream_line (
+                       nntp_stream, (guchar **) &line, &len,
+                       cancellable, error);
        }
 
+       g_clear_object (&nntp_stream);
+
        return ret;
 }
 
@@ -231,10 +272,11 @@ static struct {
 };
 
 static gint
-xover_setup (CamelNNTPStore *store,
+xover_setup (CamelNNTPStore *nntp_store,
              GCancellable *cancellable,
              GError **error)
 {
+       CamelNNTPStream *nntp_stream;
        gint ret, i;
        gchar *line;
        guint len;
@@ -242,20 +284,27 @@ xover_setup (CamelNNTPStore *store,
        struct _xover_header *xover, *last;
 
        /* manual override */
-       if (store->xover || getenv ("CAMEL_NNTP_DISABLE_XOVER") != NULL)
+       if (nntp_store->xover || getenv ("CAMEL_NNTP_DISABLE_XOVER") != NULL)
                return 0;
 
-       ret = camel_nntp_raw_command_auth (store, cancellable, error, &line, "list overview.fmt");
+       ret = camel_nntp_raw_command_auth (
+               nntp_store, cancellable, error, &line, "list overview.fmt");
        if (ret == -1) {
                return -1;
-       } else if (ret != 215)
+       } else if (ret != 215) {
                /* unsupported command?  ignore */
                return 0;
+       }
 
-       last = (struct _xover_header *) &store->xover;
+       last = (struct _xover_header *) &nntp_store->xover;
+
+       nntp_stream = camel_nntp_store_ref_stream (nntp_store);
 
        /* supported command */
-       while ((ret = camel_nntp_stream_line (store->stream, (guchar **) &line, &len, cancellable, error)) > 
0) {
+       ret = camel_nntp_stream_line (
+               nntp_stream, (guchar **) &line, &len,
+               cancellable, error);
+       while (ret > 0) {
                p = (guchar *) line;
                xover = g_malloc0 (sizeof (*xover));
                last->next = xover;
@@ -279,8 +328,14 @@ xover_setup (CamelNNTPStore *store,
                                p[-1] = camel_tolower (c);
                        }
                }
+
+               ret = camel_nntp_stream_line (
+                       nntp_stream, (guchar **) &line, &len,
+                       cancellable, error);
        }
 
+       g_clear_object (&nntp_stream);
+
        return ret;
 }
 
@@ -289,17 +344,20 @@ connect_to_server (CamelService *service,
                    GCancellable *cancellable,
                    GError **error)
 {
-       CamelNNTPStore *store = (CamelNNTPStore *) service;
-       CamelDiscoStore *disco_store = (CamelDiscoStore *) service;
+       CamelDiscoStore *disco_store;
+       CamelNNTPStore *nntp_store;
+       CamelNNTPStream *nntp_stream = NULL;
        CamelNetworkSettings *network_settings;
        CamelSettings *settings;
        CamelSession *session;
        CamelStream *tcp_stream;
        const gchar *user_cache_dir;
-       gboolean retval = FALSE;
        guchar *buf;
        guint len;
        gchar *host, *path, *user, *mechanism;
+       gboolean success = FALSE;
+
+       nntp_store = CAMEL_NNTP_STORE (service);
 
        session = camel_service_ref_session (service);
        user_cache_dir = camel_service_get_user_cache_dir (service);
@@ -319,17 +377,13 @@ connect_to_server (CamelService *service,
        if (tcp_stream == NULL)
                goto fail;
 
-       store->stream = (CamelNNTPStream *) camel_nntp_stream_new (tcp_stream);
+       nntp_stream = camel_nntp_stream_new (tcp_stream);
        g_object_unref (tcp_stream);
 
        /* Read the greeting, if any. */
-       if (camel_nntp_stream_line (store->stream, &buf, &len, cancellable, error) == -1) {
+       if (camel_nntp_stream_line (nntp_stream, &buf, &len, cancellable, error) == -1) {
                g_prefix_error (
                        error, _("Could not read greeting from %s: "), host);
-
-               g_object_unref (store->stream);
-               store->stream = NULL;
-
                goto fail;
        }
 
@@ -339,10 +393,6 @@ connect_to_server (CamelService *service,
                        error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
                        _("NNTP server %s returned error code %d: %s"),
                        host, len, buf);
-
-               g_object_unref (store->stream);
-               store->stream = NULL;
-
                goto fail;
        }
 
@@ -364,33 +414,41 @@ connect_to_server (CamelService *service,
                        goto fail;
        }
 
+       nntp_store_reset_state (nntp_store, nntp_stream);
+
        /* set 'reader' mode & ignore return code, also ping the server, inn goes offline very quickly 
otherwise */
-       if (camel_nntp_raw_command_auth (store, cancellable, error, (gchar **) &buf, "mode reader") == -1
-           || camel_nntp_raw_command_auth (store, cancellable, error, (gchar **) &buf, "date") == -1)
+       if (camel_nntp_raw_command_auth (nntp_store, cancellable, error, (gchar **) &buf, "mode reader") == -1
+           || camel_nntp_raw_command_auth (nntp_store, cancellable, error, (gchar **) &buf, "date") == -1)
                goto fail;
 
-       if (xover_setup (store, cancellable, error) == -1)
+       if (xover_setup (nntp_store, cancellable, error) == -1)
                goto fail;
 
-       if (!disco_store->diary) {
+       disco_store = CAMEL_DISCO_STORE (service);
+
+       if (disco_store->diary == NULL) {
                path = g_build_filename (user_cache_dir, ".ev-journal", NULL);
-               disco_store->diary = camel_disco_diary_new (disco_store, path, error);
+               disco_store->diary =
+                       camel_disco_diary_new (disco_store, path, NULL);
                g_free (path);
        }
 
-       retval = TRUE;
+       success = TRUE;
 
-       g_free (store->current_folder);
-       store->current_folder = NULL;
+       goto exit;
 
 fail:
+       nntp_store_reset_state (nntp_store, NULL);
+
+exit:
        g_free (host);
        g_free (user);
        g_free (mechanism);
 
-       g_object_unref (session);
+       g_clear_object (&session);
+       g_clear_object (&nntp_stream);
 
-       return retval;
+       return success;
 }
 
 static gboolean
@@ -398,27 +456,19 @@ nntp_connect_online (CamelService *service,
                      GCancellable *cancellable,
                      GError **error)
 {
-       CamelNNTPStore *store = CAMEL_NNTP_STORE (service);
-       GError *local_error = NULL;
+       CamelNNTPStore *nntp_store;
+
+       nntp_store = CAMEL_NNTP_STORE (service);
 
        if (!connect_to_server (service, cancellable, error))
                return FALSE;
 
-       if (check_capabilities (store, cancellable, &local_error) != -1)
+       if (check_capabilities (nntp_store, cancellable, NULL) != -1)
                return TRUE;
 
-       if (local_error)
-               g_error_free (local_error);
-
-       store->capabilities = 0;
-
        /* disconnect and reconnect without capability check */
 
-       if (store->stream)
-               g_object_unref (store->stream);
-       store->stream = NULL;
-       g_free (store->current_folder);
-       store->current_folder = NULL;
+       nntp_store_reset_state (nntp_store, NULL);
 
        return connect_to_server (service, cancellable, error);
 }
@@ -433,22 +483,10 @@ nntp_connect_offline (CamelService *service,
        const gchar *user_cache_dir;
        gchar *path;
 
-       user_cache_dir = camel_service_get_user_cache_dir (service);
-
-       /* setup store-wide cache */
-       if (nntp_store->cache == NULL) {
-               nntp_store->cache = camel_data_cache_new (user_cache_dir, error);
-               if (nntp_store->cache == NULL)
-                       return FALSE;
-
-               /* Default cache expiry - 2 weeks old, or not visited in 5 days */
-               camel_data_cache_set_expire_age (nntp_store->cache, 60 * 60 * 24 * 14);
-               camel_data_cache_set_expire_access (nntp_store->cache, 60 * 60 * 24 * 5);
-       }
-
        if (disco_store->diary)
                return TRUE;
 
+       user_cache_dir = camel_service_get_user_cache_dir (service);
        path = g_build_filename (user_cache_dir, ".ev-journal", NULL);
        disco_store->diary = camel_disco_diary_new (disco_store, path, error);
        g_free (path);
@@ -465,16 +503,16 @@ nntp_disconnect_online (CamelService *service,
                         GCancellable *cancellable,
                         GError **error)
 {
-       CamelNNTPStore *store = CAMEL_NNTP_STORE (service);
+       CamelNNTPStore *nntp_store;
        gchar *line;
 
+       nntp_store = CAMEL_NNTP_STORE (service);
+
        if (clean)
-               camel_nntp_raw_command (store, cancellable, NULL, &line, "quit");
+               camel_nntp_raw_command (
+                       nntp_store, cancellable, NULL, &line, "quit");
 
-       g_object_unref (store->stream);
-       store->stream = NULL;
-       g_free (store->current_folder);
-       store->current_folder = NULL;
+       nntp_store_reset_state (nntp_store, NULL);
 
        return TRUE;
 }
@@ -699,10 +737,11 @@ nntp_folder_info_from_name (CamelNNTPStore *store,
 
 /* handle list/newgroups response */
 static CamelNNTPStoreInfo *
-nntp_store_info_update (CamelNNTPStore *store,
+nntp_store_info_update (CamelNNTPStore *nntp_store,
                         gchar *line)
 {
-       CamelStoreSummary *summ = (CamelStoreSummary *) store->summary;
+       CamelNNTPStoreSummary *nntp_store_summary;
+       CamelStoreSummary *store_summary;
        CamelNNTPStoreInfo *si, *fsi;
        gchar *relpath, *tmp;
        guint32 last = 0, first = 0, new = 0;
@@ -711,16 +750,22 @@ nntp_store_info_update (CamelNNTPStore *store,
        if (tmp)
                *tmp++ = 0;
 
-       fsi = si = (CamelNNTPStoreInfo *) camel_store_summary_path ((CamelStoreSummary *) store->summary, 
line);
+       nntp_store_summary = camel_nntp_store_ref_summary (nntp_store);
+
+       store_summary = CAMEL_STORE_SUMMARY (nntp_store_summary);
+       fsi = si = (CamelNNTPStoreInfo *)
+               camel_store_summary_path (store_summary, line);
        if (si == NULL) {
-               si = (CamelNNTPStoreInfo *) camel_store_summary_info_new (summ);
+               si = (CamelNNTPStoreInfo *)
+                       camel_store_summary_info_new (store_summary);
 
                relpath = g_alloca (strlen (line) + 2);
                sprintf (relpath, "/%s", line);
 
                si->info.path = g_strdup (line);
                si->full_name = g_strdup (line); /* why do we keep this? */
-               camel_store_summary_add ((CamelStoreSummary *) store->summary, &si->info);
+
+               camel_store_summary_add (store_summary, &si->info);
        } else {
                first = si->first;
                last = si->last;
@@ -750,33 +795,36 @@ nntp_store_info_update (CamelNNTPStore *store,
        si->last = last;
        si->first = first;
 
-       if (fsi)
-               camel_store_summary_info_free ((CamelStoreSummary *) store->summary, &fsi->info);
-       else                    /* TODO see if we really did touch it */
-               camel_store_summary_touch ((CamelStoreSummary *) store->summary);
+       if (fsi != NULL)
+               camel_store_summary_info_free (store_summary, &fsi->info);
+       else /* TODO see if we really did touch it */
+               camel_store_summary_touch (store_summary);
+
+       g_clear_object (&nntp_store_summary);
 
        return si;
 }
 
 static CamelFolderInfo *
-nntp_store_get_subscribed_folder_info (CamelNNTPStore *store,
+nntp_store_get_subscribed_folder_info (CamelNNTPStore *nntp_store,
                                        const gchar *top,
                                        guint flags,
                                        GCancellable *cancellable,
                                        GError **error)
 {
+       CamelNNTPStoreSummary *nntp_store_summary;
+       CamelStoreSummary *store_summary;
        CamelService *service;
        CamelSettings *settings;
-       CamelStoreInfo *si;
        CamelFolderInfo *first = NULL, *last = NULL, *fi = NULL;
        gboolean short_folder_names;
-       gint i;
+       guint ii, store_summary_count;
 
        /* since we do not do a tree, any request that is not for root is sure to give no results */
        if (top != NULL && top[0] != 0)
                return NULL;
 
-       service = CAMEL_SERVICE (store);
+       service = CAMEL_SERVICE (nntp_store);
 
        settings = camel_service_ref_settings (service);
 
@@ -785,8 +833,15 @@ nntp_store_get_subscribed_folder_info (CamelNNTPStore *store,
 
        g_object_unref (settings);
 
-       for (i = 0; i < camel_store_summary_count ((CamelStoreSummary *) store->summary); i++) {
-               si = camel_store_summary_index ((CamelStoreSummary *) store->summary, i);
+       nntp_store_summary = camel_nntp_store_ref_summary (nntp_store);
+
+       store_summary = CAMEL_STORE_SUMMARY (nntp_store_summary);
+       store_summary_count = camel_store_summary_count (store_summary);
+
+       for (ii = 0; ii < store_summary_count; ii++) {
+               CamelStoreInfo *si;
+
+               si = camel_store_summary_index (store_summary, ii);
                if (si == NULL)
                        continue;
 
@@ -799,12 +854,12 @@ nntp_store_get_subscribed_folder_info (CamelNNTPStore *store,
 
                                folder = (CamelNNTPFolder *)
                                        camel_store_get_folder_sync (
-                                       (CamelStore *) store, si->path,
+                                       (CamelStore *) nntp_store, si->path,
                                        0, cancellable, NULL);
                                if (folder) {
                                        CamelFolderChangeInfo *changes = NULL;
 
-                                       if (camel_nntp_command (store, cancellable, NULL, folder, &line, 
NULL) != -1) {
+                                       if (camel_nntp_command (nntp_store, cancellable, NULL, folder, &line, 
NULL) != -1) {
                                                if (camel_folder_change_info_changed (folder->changes)) {
                                                        changes = folder->changes;
                                                        folder->changes = camel_folder_change_info_new ();
@@ -817,17 +872,22 @@ nntp_store_get_subscribed_folder_info (CamelNNTPStore *store,
                                        g_object_unref (folder);
                                }
                        }
-                       fi = nntp_folder_info_from_store_info (store, short_folder_names, si);
-                       fi->flags |= CAMEL_FOLDER_NOINFERIORS | CAMEL_FOLDER_NOCHILDREN | CAMEL_FOLDER_SYSTEM;
+                       fi = nntp_folder_info_from_store_info (nntp_store, short_folder_names, si);
+                       fi->flags |=
+                               CAMEL_FOLDER_NOINFERIORS |
+                               CAMEL_FOLDER_NOCHILDREN |
+                               CAMEL_FOLDER_SYSTEM;
                        if (last)
                                last->next = fi;
                        else
                                first = fi;
                        last = fi;
                }
-               camel_store_summary_info_free ((CamelStoreSummary *) store->summary, si);
+               camel_store_summary_info_free (store_summary, si);
        }
 
+       g_clear_object (&nntp_store_summary);
+
        return first;
 }
 
@@ -912,27 +972,37 @@ nntp_push_to_hierarchy (CamelNNTPStore *store,
  * get folder info, using the information in our StoreSummary
  */
 static CamelFolderInfo *
-nntp_store_get_cached_folder_info (CamelNNTPStore *store,
+nntp_store_get_cached_folder_info (CamelNNTPStore *nntp_store,
                                    const gchar *orig_top,
                                    guint flags,
                                    GError **error)
 {
+       CamelNNTPStoreSummary *nntp_store_summary;
+       CamelStoreSummary *store_summary;
        CamelService *service;
        CamelSettings *settings;
-       gint i;
-       gint subscribed_or_flag = (flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED) ? 0 : 1,
-           root_or_flag = (orig_top == NULL || orig_top[0] == '\0') ? 1 : 0,
-           recursive_flag = flags & CAMEL_STORE_FOLDER_INFO_RECURSIVE,
-           is_folder_list = flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIPTION_LIST;
-       CamelStoreInfo *si;
        CamelFolderInfo *first = NULL, *last = NULL, *fi = NULL;
        GHashTable *known; /* folder name to folder info */
        gboolean folder_hierarchy_relative;
        gchar *tmpname;
        gchar *top = g_strconcat (orig_top ? orig_top:"", ".", NULL);
        gint toplen = strlen (top);
-
-       service = CAMEL_SERVICE (store);
+       gint subscribed_or_flag;
+       gint root_or_flag;
+       gint recursive_flag;
+       gint is_folder_list;
+       guint ii, store_summary_count;
+
+       subscribed_or_flag =
+               (flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED) ? 0 : 1;
+       root_or_flag =
+               (orig_top == NULL || orig_top[0] == '\0') ? 1 : 0;
+       recursive_flag =
+               (flags & CAMEL_STORE_FOLDER_INFO_RECURSIVE);
+       is_folder_list =
+               (flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIPTION_LIST);
+
+       service = CAMEL_SERVICE (nntp_store);
 
        settings = camel_service_ref_settings (service);
 
@@ -942,14 +1012,25 @@ nntp_store_get_cached_folder_info (CamelNNTPStore *store,
 
        g_object_unref (settings);
 
+       nntp_store_summary = camel_nntp_store_ref_summary (nntp_store);
+
        known = g_hash_table_new (g_str_hash, g_str_equal);
 
-       for (i = 0; (si = camel_store_summary_index ((CamelStoreSummary *) store->summary, i)); i++) {
+       store_summary = CAMEL_STORE_SUMMARY (nntp_store_summary);
+       store_summary_count = camel_store_summary_count (store_summary);
+
+       for (ii = 0; ii < store_summary_count; ii++) {
+               CamelStoreInfo *si;
+
+               si = camel_store_summary_index (store_summary, ii);
+               if (si == NULL)
+                       continue;
+
                if ((subscribed_or_flag || (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED))
                    && (root_or_flag || strncmp (si->path, top, toplen) == 0)) {
                        if (recursive_flag || is_folder_list || strchr (si->path + toplen, '.') == NULL) {
                                /* add the item */
-                               fi = nntp_folder_info_from_store_info (store, FALSE, si);
+                               fi = nntp_folder_info_from_store_info (nntp_store, FALSE, si);
                                if (!fi)
                                        continue;
                                if (folder_hierarchy_relative) {
@@ -968,7 +1049,7 @@ nntp_store_get_cached_folder_info (CamelNNTPStore *store,
                                        dot = strchr (tmpname + toplen, '.');
                                        if (dot)
                                                *dot = '\0';
-                                       fi = nntp_folder_info_from_name (store, FALSE, tmpname);
+                                       fi = nntp_folder_info_from_name (nntp_store, FALSE, tmpname);
                                        if (!fi)
                                                continue;
 
@@ -993,7 +1074,7 @@ nntp_store_get_cached_folder_info (CamelNNTPStore *store,
 
                        if (is_folder_list) {
                                /* create a folder hierarchy rather than a flat list */
-                               first = nntp_push_to_hierarchy (store, first, fi, known);
+                               first = nntp_push_to_hierarchy (nntp_store, first, fi, known);
                        } else {
                                if (last)
                                        last->next = fi;
@@ -1003,14 +1084,18 @@ nntp_store_get_cached_folder_info (CamelNNTPStore *store,
                        }
                } else if (subscribed_or_flag && first) {
                        /* we have already added subitems, but this item is no longer a subitem */
-                       camel_store_summary_info_free ((CamelStoreSummary *) store->summary, si);
+                       camel_store_summary_info_free (store_summary, si);
                        break;
                }
-               camel_store_summary_info_free ((CamelStoreSummary *) store->summary, si);
+
+               camel_store_summary_info_free (store_summary, si);
        }
 
        g_hash_table_destroy (known);
        g_free (top);
+
+       g_clear_object (&nntp_store_summary);
+
        return first;
 }
 
@@ -1038,23 +1123,34 @@ nntp_get_date (CamelNNTPStore *nntp_store,
                GCancellable *cancellable,
                GError **error)
 {
+       CamelNNTPStoreSummary *nntp_store_summary;
        guchar *line;
-       gint ret = camel_nntp_command (nntp_store, cancellable, error, NULL, (gchar **) &line, "date");
-       gchar *ptr;
+       gint ret;
+       gboolean success = FALSE;
 
-       nntp_store->summary->last_newslist[0] = 0;
+       ret = camel_nntp_command (
+               nntp_store, cancellable, error, NULL,
+               (gchar **) &line, "date");
+
+       nntp_store_summary = camel_nntp_store_ref_summary (nntp_store);
+       nntp_store_summary->last_newslist[0] = 0;
 
        if (ret == 111) {
+               const gchar *ptr;
+
                ptr = (gchar *) line + 3;
                while (*ptr == ' ' || *ptr == '\t')
                        ptr++;
 
                if (strlen (ptr) == NNTP_DATE_SIZE) {
-                       memcpy (nntp_store->summary->last_newslist, ptr, NNTP_DATE_SIZE);
-                       return TRUE;
+                       memcpy (nntp_store_summary->last_newslist, ptr, NNTP_DATE_SIZE);
+                       success = TRUE;
                }
        }
-       return FALSE;
+
+       g_clear_object (&nntp_store_summary);
+
+       return success;
 }
 
 static CamelFolderInfo *
@@ -1065,23 +1161,27 @@ nntp_store_get_folder_info_all (CamelNNTPStore *nntp_store,
                                 GCancellable *cancellable,
                                 GError **error)
 {
-       CamelNNTPStoreSummary *summary = nntp_store->summary;
+       CamelNNTPStream *nntp_stream;
+       CamelNNTPStoreSummary *nntp_store_summary;
        CamelNNTPStoreInfo *si;
        guint len;
        guchar *line;
        gint ret = -1;
        CamelFolderInfo *fi = NULL;
 
+       nntp_stream = camel_nntp_store_ref_stream (nntp_store);
+       nntp_store_summary = camel_nntp_store_ref_summary (nntp_store);
+
        if (top == NULL)
                top = "";
 
        if (online && (top == NULL || top[0] == 0)) {
                /* we may need to update */
-               if (summary->last_newslist[0] != 0) {
+               if (nntp_store_summary->last_newslist[0] != 0) {
                        gchar date[14];
-                       memcpy (date, summary->last_newslist + 2, 6); /* YYMMDDD */
+                       memcpy (date, nntp_store_summary->last_newslist + 2, 6); /* YYMMDDD */
                        date[6] = ' ';
-                       memcpy (date + 7, summary->last_newslist + 8, 6); /* HHMMSS */
+                       memcpy (date + 7, nntp_store_summary->last_newslist + 8, 6); /* HHMMSS */
                        date[13] = '\0';
 
                        /* Some servers don't support date (!), so fallback if they dont */
@@ -1093,11 +1193,11 @@ nntp_store_get_folder_info_all (CamelNNTPStore *nntp_store,
                                goto error;
                        else if (ret != 231) {
                                /* newgroups not supported :S so reload the complete list */
-                               summary->last_newslist[0] = 0;
+                               nntp_store_summary->last_newslist[0] = 0;
                                goto do_complete_list;
                        }
 
-                       while ((ret = camel_nntp_stream_line (nntp_store->stream, &line, &len, cancellable, 
error)) > 0)
+                       while ((ret = camel_nntp_stream_line (nntp_stream, &line, &len, cancellable, error)) 
0)
                                nntp_store_info_update (nntp_store, (gchar *) line);
                } else {
                        GHashTable *all;
@@ -1120,28 +1220,35 @@ nntp_store_get_folder_info_all (CamelNNTPStore *nntp_store,
                        }
 
                        all = g_hash_table_new (g_str_hash, g_str_equal);
-                       for (i = 0; (si = (CamelNNTPStoreInfo *) camel_store_summary_index 
((CamelStoreSummary *) nntp_store->summary, i)); i++)
+                       for (i = 0; (si = (CamelNNTPStoreInfo *) camel_store_summary_index 
(CAMEL_STORE_SUMMARY (nntp_store_summary), i)); i++)
                                g_hash_table_insert (all, si->info.path, si);
 
-                       while ((ret = camel_nntp_stream_line (nntp_store->stream, &line, &len, cancellable, 
error)) > 0) {
+                       while ((ret = camel_nntp_stream_line (nntp_stream, &line, &len, cancellable, error)) 
0) {
                                si = nntp_store_info_update (nntp_store, (gchar *) line);
                                g_hash_table_remove (all, si->info.path);
                        }
 
-                       g_hash_table_foreach (all, store_info_remove, nntp_store->summary);
+                       g_hash_table_foreach (
+                               all, store_info_remove, nntp_store_summary);
                        g_hash_table_destroy (all);
                }
 
                /* sort the list */
-               g_ptr_array_sort (CAMEL_STORE_SUMMARY (nntp_store->summary)->folders, store_info_sort);
+               g_ptr_array_sort (
+                       CAMEL_STORE_SUMMARY (nntp_store_summary)->folders,
+                       store_info_sort);
                if (ret < 0)
                        goto error;
 
-               camel_store_summary_save ((CamelStoreSummary *) nntp_store->summary);
+               camel_store_summary_save (
+                       CAMEL_STORE_SUMMARY (nntp_store_summary));
        }
 
        fi = nntp_store_get_cached_folder_info (nntp_store, top, flags, error);
+
 error:
+       g_clear_object (&nntp_stream);
+       g_clear_object (&nntp_store_summary);
 
        return fi;
 }
@@ -1315,12 +1422,13 @@ nntp_store_initable_init (GInitable *initable,
                           GCancellable *cancellable,
                           GError **error)
 {
+       CamelDataCache *nntp_cache;
        CamelNNTPStore *nntp_store;
        CamelStore *store;
        CamelService *service;
        const gchar *user_data_dir;
        const gchar *user_cache_dir;
-       gchar *tmp;
+       gchar *filename;
 
        nntp_store = CAMEL_NNTP_STORE (initable);
        store = CAMEL_STORE (initable);
@@ -1345,21 +1453,25 @@ nntp_store_initable_init (GInitable *initable,
                return FALSE;
        }
 
-       tmp = g_build_filename (user_data_dir, ".ev-store-summary", NULL);
-       nntp_store->summary = camel_nntp_store_summary_new ();
-       camel_store_summary_set_filename ((CamelStoreSummary *) nntp_store->summary, tmp);
-       g_free (tmp);
-
-       camel_store_summary_load ((CamelStoreSummary *) nntp_store->summary);
+       filename = g_build_filename (
+               user_data_dir, ".ev-store-summary", NULL);
+       nntp_store->priv->summary = camel_nntp_store_summary_new ();
+       camel_store_summary_set_filename (
+               CAMEL_STORE_SUMMARY (nntp_store->priv->summary), filename);
+       camel_store_summary_load (
+               CAMEL_STORE_SUMMARY (nntp_store->priv->summary));
+       g_free (filename);
 
        /* setup store-wide cache */
-       nntp_store->cache = camel_data_cache_new (user_cache_dir, error);
-       if (nntp_store->cache == NULL)
+       nntp_cache = camel_data_cache_new (user_cache_dir, error);
+       if (nntp_cache == NULL)
                return FALSE;
 
        /* Default cache expiry - 2 weeks old, or not visited in 5 days */
-       camel_data_cache_set_expire_age (nntp_store->cache, 60 * 60 * 24 * 14);
-       camel_data_cache_set_expire_access (nntp_store->cache, 60 * 60 * 24 * 5);
+       camel_data_cache_set_expire_age (nntp_cache, 60 * 60 * 24 * 14);
+       camel_data_cache_set_expire_access (nntp_cache, 60 * 60 * 24 * 5);
+
+       nntp_store->priv->cache = nntp_cache;  /* takes ownership */
 
        return TRUE;
 }
@@ -1406,16 +1518,25 @@ static gboolean
 nntp_store_folder_is_subscribed (CamelSubscribable *subscribable,
                                  const gchar *folder_name)
 {
-       CamelNNTPStore *nntp_store = CAMEL_NNTP_STORE (subscribable);
+       CamelNNTPStore *nntp_store;
+       CamelNNTPStoreSummary *nntp_store_summary;
+       CamelStoreSummary *store_summary;
        CamelStoreInfo *si;
        gint truth = FALSE;
 
-       si = camel_store_summary_path ((CamelStoreSummary *) nntp_store->summary, folder_name);
-       if (si) {
+       nntp_store = CAMEL_NNTP_STORE (subscribable);
+       nntp_store_summary = camel_nntp_store_ref_summary (nntp_store);
+
+       store_summary = CAMEL_STORE_SUMMARY (nntp_store_summary);
+       si = camel_store_summary_path (store_summary, folder_name);
+
+       if (si != NULL) {
                truth = (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) != 0;
-               camel_store_summary_info_free ((CamelStoreSummary *) nntp_store->summary, si);
+               camel_store_summary_info_free (store_summary, si);
        }
 
+       g_clear_object (&nntp_store_summary);
+
        return truth;
 }
 
@@ -1425,11 +1546,12 @@ nntp_store_subscribe_folder_sync (CamelSubscribable *subscribable,
                                   GCancellable *cancellable,
                                   GError **error)
 {
-       CamelNNTPStore *nntp_store = CAMEL_NNTP_STORE (subscribable);
+       CamelNNTPStore *nntp_store;
+       CamelNNTPStoreSummary *nntp_store_summary;
+       CamelStoreSummary *store_summary;
        CamelService *service;
        CamelSettings *settings;
        CamelStoreInfo *si;
-       CamelFolderInfo *fi;
        gboolean short_folder_names;
        gboolean success = TRUE;
 
@@ -1442,8 +1564,13 @@ nntp_store_subscribe_folder_sync (CamelSubscribable *subscribable,
 
        g_object_unref (settings);
 
-       si = camel_store_summary_path (CAMEL_STORE_SUMMARY (nntp_store->summary), folder_name);
-       if (!si) {
+       nntp_store = CAMEL_NNTP_STORE (subscribable);
+       nntp_store_summary = camel_nntp_store_ref_summary (nntp_store);
+
+       store_summary = CAMEL_STORE_SUMMARY (nntp_store_summary);
+       si = camel_store_summary_path (store_summary, folder_name);
+
+       if (si == NULL) {
                g_set_error (
                        error, CAMEL_FOLDER_ERROR,
                        CAMEL_FOLDER_ERROR_INVALID,
@@ -1453,16 +1580,30 @@ nntp_store_subscribe_folder_sync (CamelSubscribable *subscribable,
                success = FALSE;
        } else {
                if (!(si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED)) {
+                       CamelFolderInfo *fi;
+
                        si->flags |= CAMEL_STORE_INFO_FOLDER_SUBSCRIBED;
-                       fi = nntp_folder_info_from_store_info (nntp_store, short_folder_names, si);
-                       fi->flags |= CAMEL_FOLDER_NOINFERIORS | CAMEL_FOLDER_NOCHILDREN;
-                       camel_store_summary_touch ((CamelStoreSummary *) nntp_store->summary);
-                       camel_store_summary_save ((CamelStoreSummary *) nntp_store->summary);
-                       camel_subscribable_folder_subscribed (subscribable, fi);
+
+                       fi = nntp_folder_info_from_store_info (
+                               nntp_store, short_folder_names, si);
+                       fi->flags |=
+                               CAMEL_FOLDER_NOINFERIORS |
+                               CAMEL_FOLDER_NOCHILDREN;
+
+                       camel_store_summary_touch (store_summary);
+                       camel_store_summary_save (store_summary);
+
+                       camel_subscribable_folder_subscribed (
+                               subscribable, fi);
+
                        camel_folder_info_free (fi);
                }
+
+               camel_store_summary_info_free (store_summary, si);
        }
 
+       g_clear_object (&nntp_store_summary);
+
        return success;
 }
 
@@ -1472,11 +1613,12 @@ nntp_store_unsubscribe_folder_sync (CamelSubscribable *subscribable,
                                     GCancellable *cancellable,
                                     GError **error)
 {
-       CamelNNTPStore *nntp_store = CAMEL_NNTP_STORE (subscribable);
+       CamelNNTPStore *nntp_store;
+       CamelNNTPStoreSummary *nntp_store_summary;
+       CamelStoreSummary *store_summary;
        CamelService *service;
        CamelSettings *settings;
-       CamelFolderInfo *fi;
-       CamelStoreInfo *fitem;
+       CamelStoreInfo *si;
        gboolean short_folder_names;
        gboolean success = TRUE;
 
@@ -1489,9 +1631,13 @@ nntp_store_unsubscribe_folder_sync (CamelSubscribable *subscribable,
 
        g_object_unref (settings);
 
-       fitem = camel_store_summary_path (CAMEL_STORE_SUMMARY (nntp_store->summary), folder_name);
+       nntp_store = CAMEL_NNTP_STORE (subscribable);
+       nntp_store_summary = camel_nntp_store_ref_summary (nntp_store);
+
+       store_summary = CAMEL_STORE_SUMMARY (nntp_store_summary);
+       si = camel_store_summary_path (store_summary, folder_name);
 
-       if (!fitem) {
+       if (si == NULL) {
                g_set_error (
                        error, CAMEL_FOLDER_ERROR,
                        CAMEL_FOLDER_ERROR_INVALID,
@@ -1499,16 +1645,28 @@ nntp_store_unsubscribe_folder_sync (CamelSubscribable *subscribable,
                        "newsgroup does not exist!"));
                success = FALSE;
        } else {
-               if (fitem->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) {
-                       fitem->flags &= ~CAMEL_STORE_INFO_FOLDER_SUBSCRIBED;
-                       fi = nntp_folder_info_from_store_info (nntp_store, short_folder_names, fitem);
-                       camel_store_summary_touch ((CamelStoreSummary *) nntp_store->summary);
-                       camel_store_summary_save ((CamelStoreSummary *) nntp_store->summary);
-                       camel_subscribable_folder_unsubscribed (subscribable, fi);
+               if (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) {
+                       CamelFolderInfo *fi;
+
+                       si->flags &= ~CAMEL_STORE_INFO_FOLDER_SUBSCRIBED;
+
+                       fi = nntp_folder_info_from_store_info (
+                               nntp_store, short_folder_names, si);
+
+                       camel_store_summary_touch (store_summary);
+                       camel_store_summary_save (store_summary);
+
+                       camel_subscribable_folder_unsubscribed (
+                               subscribable, fi);
+
                        camel_folder_info_free (fi);
                }
+
+               camel_store_summary_info_free (store_summary, si);
        }
 
+       g_clear_object (&nntp_store_summary);
+
        return success;
 }
 
@@ -1520,6 +1678,8 @@ camel_nntp_store_class_init (CamelNNTPStoreClass *class)
        CamelStoreClass *store_class;
        CamelDiscoStoreClass *disco_store_class;
 
+       g_type_class_add_private (class, sizeof (CamelNNTPStorePrivate));
+
        object_class = G_OBJECT_CLASS (class);
        object_class->set_property = nntp_store_set_property;
        object_class->get_property = nntp_store_get_property;
@@ -1591,20 +1751,248 @@ camel_subscribable_init (CamelSubscribableInterface *interface)
 static void
 camel_nntp_store_init (CamelNNTPStore *nntp_store)
 {
+       nntp_store->priv = CAMEL_NNTP_STORE_GET_PRIVATE (nntp_store);
+
+       g_mutex_init (&nntp_store->priv->property_lock);
+
        /* Clear the default flags.  We don't want a virtual Junk or Trash
         * folder and the user can't create/delete/rename newsgroup folders. */
        CAMEL_STORE (nntp_store)->flags = 0;
 }
 
+/**
+ * camel_nntp_store_ref_cache:
+ * @nntp_store: a #CamelNNTPStore
+ *
+ * Returns the #CamelDataCache for @nntp_store.
+ *
+ * The returned #CamelDataCache is referenced for thread-safety and must
+ * be unreferenced with g_object_unref() when finished with it.
+ *
+ * Returns: a #CamelDataCache
+ **/
+CamelDataCache *
+camel_nntp_store_ref_cache (CamelNNTPStore *nntp_store)
+{
+       CamelDataCache *cache = NULL;
+
+       g_return_val_if_fail (CAMEL_IS_NNTP_STORE (nntp_store), NULL);
+
+       g_mutex_lock (&nntp_store->priv->property_lock);
+
+       if (nntp_store->priv->cache != NULL)
+               cache = g_object_ref (nntp_store->priv->cache);
+
+       g_mutex_unlock (&nntp_store->priv->property_lock);
+
+       return cache;
+}
+
+/**
+ * camel_nntp_store_ref_stream:
+ * @nntp_store: a #CamelNNTPStore
+ *
+ * Returns the #CamelNNTPStream for @nntp_store.
+ *
+ * The returned #CamelNNTPStream is referenced for thread-safety and must
+ * be unreferenced with g_object_unref() when finished with it.
+ *
+ * Returns: a #CamelNNTPStream
+ **/
+CamelNNTPStream *
+camel_nntp_store_ref_stream (CamelNNTPStore *nntp_store)
+{
+       CamelNNTPStream *stream = NULL;
+
+       g_return_val_if_fail (CAMEL_IS_NNTP_STORE (nntp_store), NULL);
+
+       g_mutex_lock (&nntp_store->priv->property_lock);
+
+       if (nntp_store->priv->stream != NULL)
+               stream = g_object_ref (nntp_store->priv->stream);
+
+       g_mutex_unlock (&nntp_store->priv->property_lock);
+
+       return stream;
+}
+
+/**
+ * camel_nntp_store_ref_summary:
+ * @nntp_store: a #CamelNNTPStore
+ *
+ * Returns the #CamelNNTPStoreSummary for @nntp_store.
+ *
+ * The returned #CamelNNTPStoreSummary is referenced for thread-safety and
+ * must be unreferenced with g_object_unref() when finished with it.
+ *
+ * Returns: a #CamelNNTPStoreSummary
+ **/
+CamelNNTPStoreSummary *
+camel_nntp_store_ref_summary (CamelNNTPStore *nntp_store)
+{
+       CamelNNTPStoreSummary *summary = NULL;
+
+       g_return_val_if_fail (CAMEL_IS_NNTP_STORE (nntp_store), NULL);
+
+       g_mutex_lock (&nntp_store->priv->property_lock);
+
+       if (nntp_store->priv->summary != NULL)
+               summary = g_object_ref (nntp_store->priv->summary);
+
+       g_mutex_unlock (&nntp_store->priv->property_lock);
+
+       return summary;
+}
+
+/**
+ * camel_nntp_store_get_current_group:
+ * @nntp_store: a #CamelNNTPStore
+ *
+ * Returns the currently selected newsgroup name, or %NULL if no newsgroup
+ * is selected.
+ *
+ * Returns: the currently selected newsgroup name, or %NULL
+ **/
+const gchar *
+camel_nntp_store_get_current_group (CamelNNTPStore *nntp_store)
+{
+       g_return_val_if_fail (CAMEL_IS_NNTP_STORE (nntp_store), NULL);
+
+       return nntp_store->priv->current_group;
+}
+
+/**
+ * camel_nntp_store_dup_current_group:
+ * @nntp_store: a #CamelNNTPStore
+ *
+ * Thread-safe variation of camel_nntp_store_get_current_group().
+ * Use this function when accessing @nntp_store from multiple threads.
+ *
+ * The returned string should be freed with g_free() when no longer needed.
+ *
+ * Returns: a newly-allocated string, or %NULL
+ **/
+gchar *
+camel_nntp_store_dup_current_group (CamelNNTPStore *nntp_store)
+{
+       const gchar *protected;
+       gchar *duplicate;
+
+       g_return_val_if_fail (CAMEL_IS_NNTP_STORE (nntp_store), NULL);
+
+       g_mutex_lock (&nntp_store->priv->property_lock);
+
+       protected = camel_nntp_store_get_current_group (nntp_store);
+       duplicate = g_strdup (protected);
+
+       g_mutex_unlock (&nntp_store->priv->property_lock);
+
+       return duplicate;
+}
+
+/**
+ * camel_nntp_store_set_current_group:
+ * @nntp_store: a #CamelNNTPStore
+ * @current_group: a newsgroup name
+ *
+ * Sets the name of the currently selected newsgroup.
+ **/
+void
+camel_nntp_store_set_current_group (CamelNNTPStore *nntp_store,
+                                    const gchar *current_group)
+{
+       g_return_if_fail (CAMEL_IS_NNTP_STORE (nntp_store));
+
+       g_mutex_lock (&nntp_store->priv->property_lock);
+
+       if (g_strcmp0 (current_group, nntp_store->priv->current_group) == 0) {
+               g_mutex_unlock (&nntp_store->priv->property_lock);
+               return;
+       }
+
+       g_free (nntp_store->priv->current_group);
+       nntp_store->priv->current_group = g_strdup (current_group);
+
+       g_mutex_unlock (&nntp_store->priv->property_lock);
+}
+
+/**
+ * camel_nntp_store_add_capabilities:
+ * @nntp_store: a #CamelNNTPStore
+ * @caps: #CamelNNTPCapabilities to add
+ *
+ * Adds @caps to the set of known capabilities for @nntp_store.
+ **/
+void
+camel_nntp_store_add_capabilities (CamelNNTPStore *nntp_store,
+                                   CamelNNTPCapabilities caps)
+{
+       g_return_if_fail (CAMEL_IS_NNTP_STORE (nntp_store));
+
+       g_mutex_lock (&nntp_store->priv->property_lock);
+
+       nntp_store->priv->capabilities |= caps;
+
+       g_mutex_unlock (&nntp_store->priv->property_lock);
+}
+
+/**
+ * camel_nntp_store_has_capabilities:
+ * @nntp_store: a #CamelNNTPStore
+ * @caps: #CamelNNTPCapabilities to check
+ *
+ * Returns whether the set of known capabilities for @nntp_store includes
+ * ALL the capabilities specified by @caps.
+ *
+ * Returns: %TRUE if @nntp_store includes ALL capabilities in @caps
+ **/
+gboolean
+camel_nntp_store_has_capabilities (CamelNNTPStore *nntp_store,
+                                   CamelNNTPCapabilities caps)
+{
+       gboolean result;
+
+       g_return_val_if_fail (CAMEL_IS_NNTP_STORE (nntp_store), FALSE);
+
+       g_mutex_lock (&nntp_store->priv->property_lock);
+
+       result = ((nntp_store->priv->capabilities & caps) == caps);
+
+       g_mutex_unlock (&nntp_store->priv->property_lock);
+
+       return result;
+}
+
+/**
+ * camel_nntp_store_remove_capabilities:
+ * @nntp_store: a #CamelNNTPStore
+ * @caps: #CamelNNTPCapabilities to remove
+ *
+ * Removes @caps from the set of known capablities for @nntp_store.
+ **/
+void
+camel_nntp_store_remove_capabilities (CamelNNTPStore *nntp_store,
+                                      CamelNNTPCapabilities caps)
+{
+       g_return_if_fail (CAMEL_IS_NNTP_STORE (nntp_store));
+
+       g_mutex_lock (&nntp_store->priv->property_lock);
+
+       nntp_store->priv->capabilities &= ~caps;
+
+       g_mutex_unlock (&nntp_store->priv->property_lock);
+}
+
 /* Enter owning lock */
 gint
-camel_nntp_raw_commandv (CamelNNTPStore *store,
+camel_nntp_raw_commandv (CamelNNTPStore *nntp_store,
                          GCancellable *cancellable,
                          GError **error,
                          gchar **line,
                          const gchar *fmt,
                          va_list ap)
 {
+       CamelNNTPStream *nntp_stream;
        GString *buffer;
        const guchar *p, *ps;
        guchar c;
@@ -1612,9 +2000,11 @@ camel_nntp_raw_commandv (CamelNNTPStore *store,
        gint d;
        guint u, u2;
 
-       g_assert (store->stream->mode != CAMEL_NNTP_STREAM_DATA);
+       nntp_stream = camel_nntp_store_ref_stream (nntp_store);
+       g_return_val_if_fail (nntp_stream != NULL, -1);
+       g_return_val_if_fail (nntp_stream->mode != CAMEL_NNTP_STREAM_DATA, -1);
 
-       camel_nntp_stream_set_mode (store->stream, CAMEL_NNTP_STREAM_LINE);
+       camel_nntp_stream_set_mode (nntp_stream, CAMEL_NNTP_STREAM_LINE);
 
        p = (const guchar *) fmt;
        ps = (const guchar *) p;
@@ -1671,29 +2061,34 @@ camel_nntp_raw_commandv (CamelNNTPStore *store,
        g_string_append_len (buffer, "\r\n", 2);
 
        if (camel_stream_write (
-               CAMEL_STREAM (store->stream),
+               CAMEL_STREAM (nntp_stream),
                buffer->str, buffer->len,
                cancellable, error) == -1)
                goto ioerror;
 
-       if (camel_nntp_stream_line (store->stream, (guchar **) line, &u, cancellable, error) == -1)
+       if (camel_nntp_stream_line (nntp_stream, (guchar **) line, &u, cancellable, error) == -1)
                goto ioerror;
 
        u = strtoul (*line, NULL, 10);
 
        /* Handle all switching to data mode here, to make callers job easier */
        if (u == 215 || (u >= 220 && u <=224) || (u >= 230 && u <= 231))
-               camel_nntp_stream_set_mode (store->stream, CAMEL_NNTP_STREAM_DATA);
+               camel_nntp_stream_set_mode (nntp_stream, CAMEL_NNTP_STREAM_DATA);
 
-       return u;
+       goto exit;
 
 ioerror:
        g_prefix_error (error, _("NNTP Command failed: "));
-       return -1;
+       u = -1;
+
+exit:
+       g_clear_object (&nntp_stream);
+
+       return u;
 }
 
 gint
-camel_nntp_raw_command (CamelNNTPStore *store,
+camel_nntp_raw_command (CamelNNTPStore *nntp_store,
                         GCancellable *cancellable,
                         GError **error,
                         gchar **line,
@@ -1704,7 +2099,8 @@ camel_nntp_raw_command (CamelNNTPStore *store,
        va_list ap;
 
        va_start (ap, fmt);
-       ret = camel_nntp_raw_commandv (store, cancellable, error, line, fmt, ap);
+       ret = camel_nntp_raw_commandv (
+               nntp_store, cancellable, error, line, fmt, ap);
        va_end (ap);
 
        return ret;
@@ -1712,7 +2108,7 @@ camel_nntp_raw_command (CamelNNTPStore *store,
 
 /* use this where you also need auth to be handled, i.e. most cases where you'd try raw command */
 gint
-camel_nntp_raw_command_auth (CamelNNTPStore *store,
+camel_nntp_raw_command_auth (CamelNNTPStore *nntp_store,
                              GCancellable *cancellable,
                              GError **error,
                              gchar **line,
@@ -1724,7 +2120,7 @@ camel_nntp_raw_command_auth (CamelNNTPStore *store,
        gint ret, retry, go;
        va_list ap;
 
-       service = CAMEL_SERVICE (store);
+       service = CAMEL_SERVICE (nntp_store);
        session = camel_service_ref_session (service);
 
        retry = 0;
@@ -1734,7 +2130,8 @@ camel_nntp_raw_command_auth (CamelNNTPStore *store,
                retry++;
 
                va_start (ap, fmt);
-               ret = camel_nntp_raw_commandv (store, cancellable, error, line, fmt, ap);
+               ret = camel_nntp_raw_commandv (
+                       nntp_store, cancellable, error, line, fmt, ap);
                va_end (ap);
 
                if (ret == NNTP_AUTH_REQUIRED) {
@@ -1751,7 +2148,7 @@ camel_nntp_raw_command_auth (CamelNNTPStore *store,
 }
 
 gint
-camel_nntp_command (CamelNNTPStore *store,
+camel_nntp_command (CamelNNTPStore *nntp_store,
                     GCancellable *cancellable,
                     GError **error,
                     CamelNNTPFolder *folder,
@@ -1759,6 +2156,8 @@ camel_nntp_command (CamelNNTPStore *store,
                     const gchar *fmt,
                     ...)
 {
+       CamelNNTPStream *nntp_stream = NULL;
+       CamelDiscoStore *disco_store;
        CamelService *service;
        CamelSession *session;
        gboolean success;
@@ -1769,14 +2168,16 @@ camel_nntp_command (CamelNNTPStore *store,
        guint u;
        GError *local_error = NULL;
 
-       service = CAMEL_SERVICE (store);
+       service = CAMEL_SERVICE (nntp_store);
 
-       if (((CamelDiscoStore *) store)->status == CAMEL_DISCO_STORE_OFFLINE) {
+       disco_store = CAMEL_DISCO_STORE (nntp_store);
+       if (disco_store->status == CAMEL_DISCO_STORE_OFFLINE) {
                g_set_error (
                        error, CAMEL_SERVICE_ERROR,
                        CAMEL_SERVICE_ERROR_NOT_CONNECTED,
                        _("Not connected."));
-               return -1;
+               ret = -1;
+               goto exit;
        }
 
        if (folder != NULL)
@@ -1784,26 +2185,52 @@ camel_nntp_command (CamelNNTPStore *store,
 
        retry = 0;
        do {
+               gboolean need_group_command;
+               gchar *current_group;
+
                retry++;
 
-               if (store->stream == NULL
-                   && !camel_service_connect_sync (service, cancellable, error))
-                       return -1;
+               nntp_stream = camel_nntp_store_ref_stream (nntp_store);
+
+               if (nntp_stream == NULL) {
+                       gboolean success;
+
+                       success = camel_service_connect_sync (
+                               service, cancellable, error);
+
+                       if (!success) {
+                               ret = -1;
+                               goto exit;
+                       }
+
+                       /* If we successfully connected then
+                        * we should obtain a CamelNNTPStream. */
+                       nntp_stream = camel_nntp_store_ref_stream (nntp_store);
+                       g_return_val_if_fail (nntp_stream != NULL, -1);
+               }
 
                /* Check for unprocessed data, !*/
-               if (store->stream && store->stream->mode == CAMEL_NNTP_STREAM_DATA) {
+               if (nntp_stream->mode == CAMEL_NNTP_STREAM_DATA) {
                        g_warning ("Unprocessed data left in stream, flushing");
-                       while (camel_nntp_stream_getd (store->stream, (guchar **) &p, &u, cancellable, error) 
0)
+                       while (camel_nntp_stream_getd (nntp_stream, (guchar **) &p, &u, cancellable, error) > 
0)
                                ;
                }
-               camel_nntp_stream_set_mode (store->stream, CAMEL_NNTP_STREAM_LINE);
-
-               if (folder != NULL
-                   && (store->current_folder == NULL || strcmp (store->current_folder, full_name) != 0)) {
-                       ret = camel_nntp_raw_command_auth (store, cancellable, &local_error, line, "group 
%s", full_name);
+               camel_nntp_stream_set_mode (nntp_stream, CAMEL_NNTP_STREAM_LINE);
+
+               current_group =
+                       camel_nntp_store_dup_current_group (nntp_store);
+               need_group_command =
+                       (full_name != NULL) &&
+                       (g_strcmp0 (current_group, full_name) != 0);
+               g_free (current_group);
+
+               if (need_group_command) {
+                       ret = camel_nntp_raw_command_auth (
+                               nntp_store, cancellable, &local_error,
+                               line, "group %s", full_name);
                        if (ret == 211) {
-                               g_free (store->current_folder);
-                               store->current_folder = g_strdup (full_name);
+                               camel_nntp_store_set_current_group (
+                                       nntp_store, full_name);
                                if (camel_nntp_folder_selected (folder, *line, NULL, &local_error) < 0) {
                                        ret = -1;
                                        goto error;
@@ -1814,11 +2241,14 @@ camel_nntp_command (CamelNNTPStore *store,
                }
 
                /* dummy fmt, we just wanted to select the folder */
-               if (fmt == NULL)
-                       return 0;
+               if (fmt == NULL) {
+                       ret = 0;
+                       goto exit;
+               }
 
                va_start (ap, fmt);
-               ret = camel_nntp_raw_commandv (store, cancellable, &local_error, line, fmt, ap);
+               ret = camel_nntp_raw_commandv (
+                       nntp_store, cancellable, &local_error, line, fmt, ap);
                va_end (ap);
        error:
                switch (ret) {
@@ -1828,8 +2258,10 @@ camel_nntp_command (CamelNNTPStore *store,
                                session, service, NULL, cancellable, error);
                        g_object_unref (session);
 
-                       if (!success)
-                               return -1;
+                       if (!success) {
+                               ret = -1;
+                               goto exit;
+                       }
                        retry--;
                        ret = -1;
                        continue;
@@ -1838,7 +2270,8 @@ camel_nntp_command (CamelNNTPStore *store,
                                error, CAMEL_FOLDER_ERROR,
                                CAMEL_FOLDER_ERROR_INVALID,
                                _("No such folder: %s"), *line);
-                       return -1;
+                       ret = -1;
+                       goto exit;
                case 400:       /* service discontinued */
                case 401:       /* wrong client state - this should quit but this is what the old code did */
                case 503:       /* information not available - this should quit but this is what the old code 
did (?) */
@@ -1851,12 +2284,19 @@ camel_nntp_command (CamelNNTPStore *store,
                                service, FALSE, cancellable, NULL);
                        if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED) || retry >= 3) {
                                g_propagate_error (error, local_error);
-                               return -1;
+                               ret = -1;
+                               goto exit;
                        }
                        g_clear_error (&local_error);
                        break;
                }
+
+               g_clear_object (&nntp_stream);
+
        } while (ret == -1 && retry < 3);
 
+exit:
+       g_clear_object (&nntp_stream);
+
        return ret;
 }
diff --git a/camel/providers/nntp/camel-nntp-store.h b/camel/providers/nntp/camel-nntp-store.h
index 128b8c5..0b9a4df 100644
--- a/camel/providers/nntp/camel-nntp-store.h
+++ b/camel/providers/nntp/camel-nntp-store.h
@@ -70,24 +70,15 @@ struct _xover_header {
 };
 
 /* names of supported capabilities on the server */
-enum nntp_capabilities {
-       NNTP_CAPABILITY_OVER = (1 << 0)  /* supports OVER command */
-};
+typedef enum {
+       CAMEL_NNTP_CAPABILITY_OVER = 1 << 0  /* supports OVER command */
+} CamelNNTPCapabilities;
 
 struct _CamelNNTPStore {
        CamelDiscoStore parent;
        CamelNNTPStorePrivate *priv;
 
-       struct _CamelNNTPStoreSummary *summary;
-
-       struct _CamelNNTPStream *stream;
-
-       struct _CamelDataCache *cache;
-
-       gchar *current_folder;
-
        struct _xover_header *xover;
-       guint32 capabilities; /* bit-or of nntp_capabilities */
 };
 
 struct _CamelNNTPStoreClass {
@@ -95,25 +86,47 @@ struct _CamelNNTPStoreClass {
 };
 
 GType          camel_nntp_store_get_type       (void);
-gint           camel_nntp_raw_commandv         (CamelNNTPStore *store,
+CamelDataCache *
+               camel_nntp_store_ref_cache      (CamelNNTPStore *nntp_store);
+CamelNNTPStream *
+               camel_nntp_store_ref_stream     (CamelNNTPStore *nntp_store);
+CamelNNTPStoreSummary *
+               camel_nntp_store_ref_summary    (CamelNNTPStore *nntp_store);
+const gchar *  camel_nntp_store_get_current_group
+                                               (CamelNNTPStore *nntp_store);
+gchar *                camel_nntp_store_dup_current_group
+                                               (CamelNNTPStore *nntp_store);
+void           camel_nntp_store_set_current_group
+                                               (CamelNNTPStore *nntp_store,
+                                                const gchar *current_group);
+void           camel_nntp_store_add_capabilities
+                                               (CamelNNTPStore *nntp_store,
+                                                CamelNNTPCapabilities caps);
+gboolean       camel_nntp_store_has_capabilities
+                                               (CamelNNTPStore *nntp_store,
+                                                CamelNNTPCapabilities caps);
+void           camel_nntp_store_remove_capabilities
+                                               (CamelNNTPStore *nntp_store,
+                                                CamelNNTPCapabilities caps);
+gint           camel_nntp_raw_commandv         (CamelNNTPStore *nntp_store,
                                                 GCancellable *cancellable,
                                                 GError **error,
                                                 gchar **line,
                                                 const gchar *fmt,
                                                 va_list ap);
-gint           camel_nntp_raw_command          (CamelNNTPStore *store,
+gint           camel_nntp_raw_command          (CamelNNTPStore *nntp_store,
                                                 GCancellable *cancellable,
                                                 GError **error,
                                                 gchar **line,
                                                 const gchar *fmt,
                                                 ...);
-gint           camel_nntp_raw_command_auth     (CamelNNTPStore *store,
+gint           camel_nntp_raw_command_auth     (CamelNNTPStore *nntp_store,
                                                 GCancellable *cancellable,
                                                 GError **error,
                                                 gchar **line,
                                                 const gchar *fmt,
                                                 ...);
-gint           camel_nntp_command              (CamelNNTPStore *store,
+gint           camel_nntp_command              (CamelNNTPStore *nntp_store,
                                                 GCancellable *cancellable,
                                                 GError **error,
                                                 struct _CamelNNTPFolder *folder,
diff --git a/camel/providers/nntp/camel-nntp-stream.c b/camel/providers/nntp/camel-nntp-stream.c
index 7d17d8d..d09ee6e 100644
--- a/camel/providers/nntp/camel-nntp-stream.c
+++ b/camel/providers/nntp/camel-nntp-stream.c
@@ -246,23 +246,15 @@ camel_nntp_stream_init (CamelNNTPStream *is)
        is->mode = CAMEL_NNTP_STREAM_LINE;
 }
 
-/**
- * camel_nntp_stream_new:
- *
- * Returns a NULL stream.  A null stream is always at eof, and
- * always returns success for all reads and writes.
- *
- * Returns: the stream
- **/
-CamelStream *
+CamelNNTPStream *
 camel_nntp_stream_new (CamelStream *source)
 {
-       CamelNNTPStream *is;
+       CamelNNTPStream *nntp_stream;
 
-       is = g_object_new (CAMEL_TYPE_NNTP_STREAM, NULL);
-       is->source = g_object_ref (source);
+       nntp_stream = g_object_new (CAMEL_TYPE_NNTP_STREAM, NULL);
+       nntp_stream->source = g_object_ref (source);
 
-       return (CamelStream *) is;
+       return nntp_stream;
 }
 
 /* Get one line from the nntp stream */
diff --git a/camel/providers/nntp/camel-nntp-stream.h b/camel/providers/nntp/camel-nntp-stream.h
index 66f22e3..60022b0 100644
--- a/camel/providers/nntp/camel-nntp-stream.h
+++ b/camel/providers/nntp/camel-nntp-stream.h
@@ -70,9 +70,8 @@ struct _CamelNNTPStreamClass {
 };
 
 GType          camel_nntp_stream_get_type      (void);
-
-CamelStream *  camel_nntp_stream_new           (CamelStream *source);
-
+CamelNNTPStream *
+               camel_nntp_stream_new           (CamelStream *source);
 void           camel_nntp_stream_set_mode      (CamelNNTPStream *is,
                                                 camel_nntp_stream_mode_t mode);
 gint           camel_nntp_stream_line          (CamelNNTPStream *is,
diff --git a/camel/providers/nntp/camel-nntp-summary.c b/camel/providers/nntp/camel-nntp-summary.c
index a2189b3..d9b0732 100644
--- a/camel/providers/nntp/camel-nntp-summary.c
+++ b/camel/providers/nntp/camel-nntp-summary.c
@@ -160,13 +160,15 @@ summary_header_to_db (CamelFolderSummary *s,
 /* Note: This will be called from camel_nntp_command, so only use camel_nntp_raw_command */
 static gint
 add_range_xover (CamelNNTPSummary *cns,
-                 CamelNNTPStore *store,
+                 CamelNNTPStore *nntp_store,
                  guint high,
                  guint low,
                  CamelFolderChangeInfo *changes,
                  GCancellable *cancellable,
                  GError **error)
 {
+       CamelNNTPCapabilities capability = CAMEL_NNTP_CAPABILITY_OVER;
+       CamelNNTPStream *nntp_stream;
        CamelNetworkSettings *network_settings;
        CamelSettings *settings;
        CamelService *service;
@@ -185,7 +187,7 @@ add_range_xover (CamelNNTPSummary *cns,
        folder_filter_recent = camel_folder_summary_get_folder (s) &&
                (camel_folder_summary_get_folder (s)->folder_flags & CAMEL_FOLDER_FILTER_RECENT) != 0;
 
-       service = CAMEL_SERVICE (store);
+       service = CAMEL_SERVICE (nntp_store);
 
        settings = camel_service_ref_settings (service);
 
@@ -199,13 +201,17 @@ add_range_xover (CamelNNTPSummary *cns,
 
        g_free (host);
 
-       if ((store->capabilities & NNTP_CAPABILITY_OVER) != 0)
-               ret = camel_nntp_raw_command_auth (store, cancellable, error, &line, "over %r", low, high);
+       if (camel_nntp_store_has_capabilities (nntp_store, capability))
+               ret = camel_nntp_raw_command_auth (
+                       nntp_store, cancellable, error,
+                       &line, "over %r", low, high);
        else
                ret = -1;
        if (ret != 224) {
-               store->capabilities = store->capabilities & (~NNTP_CAPABILITY_OVER);
-               ret = camel_nntp_raw_command_auth (store, cancellable, error, &line, "xover %r", low, high);
+               camel_nntp_store_remove_capabilities (nntp_store, capability);
+               ret = camel_nntp_raw_command_auth (
+                       nntp_store, cancellable, error,
+                       &line, "xover %r", low, high);
        }
 
        if (ret != 224) {
@@ -217,16 +223,18 @@ add_range_xover (CamelNNTPSummary *cns,
                return -1;
        }
 
+       nntp_stream = camel_nntp_store_ref_stream (nntp_store);
+
        count = 0;
        total = high - low + 1;
-       while ((ret = camel_nntp_stream_line (store->stream, (guchar **) &line, &len, cancellable, error)) > 
0) {
+       while ((ret = camel_nntp_stream_line (nntp_stream, (guchar **) &line, &len, cancellable, error)) > 0) 
{
                camel_operation_progress (cancellable, (count * 100) / total);
                count++;
                n = strtoul (line, &tab, 10);
                if (*tab != '\t')
                        continue;
                tab++;
-               xover = store->xover;
+               xover = nntp_store->xover;
                size = 0;
                for (; tab[0] && xover; xover = xover->next) {
                        line = tab;
@@ -282,6 +290,8 @@ add_range_xover (CamelNNTPSummary *cns,
                camel_header_raw_clear (&headers);
        }
 
+       g_clear_object (&nntp_stream);
+
        camel_operation_pop_message (cancellable);
 
        return ret;
@@ -290,13 +300,14 @@ add_range_xover (CamelNNTPSummary *cns,
 /* Note: This will be called from camel_nntp_command, so only use camel_nntp_raw_command */
 static gint
 add_range_head (CamelNNTPSummary *cns,
-                CamelNNTPStore *store,
+                CamelNNTPStore *nntp_store,
                 guint high,
                 guint low,
                 CamelFolderChangeInfo *changes,
                 GCancellable *cancellable,
                 GError **error)
 {
+       CamelNNTPStream *nntp_stream;
        CamelNetworkSettings *network_settings;
        CamelSettings *settings;
        CamelService *service;
@@ -315,7 +326,7 @@ add_range_head (CamelNNTPSummary *cns,
 
        mp = camel_mime_parser_new ();
 
-       service = CAMEL_SERVICE (store);
+       service = CAMEL_SERVICE (nntp_store);
 
        settings = camel_service_ref_settings (service);
 
@@ -329,12 +340,15 @@ add_range_head (CamelNNTPSummary *cns,
 
        g_free (host);
 
+       nntp_stream = camel_nntp_store_ref_stream (nntp_store);
+
        count = 0;
        total = high - low + 1;
        for (i = low; i < high + 1; i++) {
                camel_operation_progress (cancellable, (count * 100) / total);
                count++;
-               ret = camel_nntp_raw_command_auth (store, cancellable, error, &line, "head %u", i);
+               ret = camel_nntp_raw_command_auth (
+                       nntp_store, cancellable, error, &line, "head %u", i);
                /* unknown article, ignore */
                if (ret == 423)
                        continue;
@@ -357,7 +371,7 @@ add_range_head (CamelNNTPSummary *cns,
                        line[1] = 0;
                        cns->priv->uid = g_strdup_printf ("%u,%s\n", n, msgid);
                        if (!camel_folder_summary_check_uid (s, cns->priv->uid)) {
-                               if (camel_mime_parser_init_with_stream (mp, (CamelStream *) store->stream, 
error) == -1)
+                               if (camel_mime_parser_init_with_stream (mp, CAMEL_STREAM (nntp_stream), 
error) == -1)
                                        goto error;
                                mi = camel_folder_summary_add_from_parser (s, mp);
                                while (camel_mime_parser_step (mp, NULL, NULL) != CAMEL_MIME_PARSER_STATE_EOF)
@@ -401,6 +415,8 @@ ioerror:
        }
        g_object_unref (mp);
 
+       g_clear_object (&nntp_stream);
+
        camel_operation_pop_message (cancellable);
 
        return ret;
@@ -416,12 +432,14 @@ camel_nntp_summary_check (CamelNNTPSummary *cns,
                           GCancellable *cancellable,
                           GError **error)
 {
+       CamelNNTPStoreSummary *nntp_store_summary;
+       CamelStoreSummary *store_summary;
        CamelFolderSummary *s;
        gint ret = 0, i;
        guint n, f, l;
        gint count;
        gchar *folder = NULL;
-       CamelNNTPStoreInfo *si;
+       CamelNNTPStoreInfo *si = NULL;
        CamelStore *parent_store;
        GList *del = NULL;
        const gchar *full_name;
@@ -456,8 +474,11 @@ camel_nntp_summary_check (CamelNNTPSummary *cns,
 
        /* Check for messages no longer on the server */
        if (cns->low != f) {
+               CamelDataCache *nntp_cache;
                GPtrArray *known_uids;
 
+               nntp_cache = camel_nntp_store_ref_cache (store);
+
                known_uids = camel_folder_summary_get_array (s);
                if (known_uids) {
                        for (i = 0; i < known_uids->len; i++) {
@@ -476,7 +497,7 @@ camel_nntp_summary_check (CamelNNTPSummary *cns,
                                         * it is a true cache */
                                        msgid = strchr (uid, ',');
                                        if (msgid)
-                                               camel_data_cache_remove (store->cache, "cache", msgid + 1, 
NULL);
+                                               camel_data_cache_remove (nntp_cache, "cache", msgid + 1, 
NULL);
                                        camel_folder_change_info_remove_uid (changes, uid);
                                        del = g_list_prepend (del, (gpointer) camel_pstring_strdup (uid));
 
@@ -492,6 +513,8 @@ camel_nntp_summary_check (CamelNNTPSummary *cns,
                        camel_folder_summary_free_array (known_uids);
                }
                cns->low = f;
+
+               g_clear_object (&nntp_cache);
        }
 
        camel_db_delete_uids (parent_store->cdb_w, full_name, del, NULL);
@@ -518,12 +541,21 @@ camel_nntp_summary_check (CamelNNTPSummary *cns,
 
 update:
        /* update store summary if we have it */
-       if (folder
-           && (si = (CamelNNTPStoreInfo *) camel_store_summary_path ((CamelStoreSummary *) store->summary, 
folder))) {
+
+       nntp_store_summary = camel_nntp_store_ref_summary (store);
+
+       store_summary = CAMEL_STORE_SUMMARY (nntp_store_summary);
+
+       if (folder != NULL)
+               si = (CamelNNTPStoreInfo *)
+                       camel_store_summary_path (store_summary, folder);
+
+       if (si != NULL) {
                guint32 unread = 0;
 
                count = camel_folder_summary_count (s);
-               camel_db_count_unread_message_info (parent_store->cdb_r, full_name, &unread, NULL);
+               camel_db_count_unread_message_info (
+                       parent_store->cdb_r, full_name, &unread, NULL);
 
                if (si->info.unread != unread
                    || si->info.total != count
@@ -533,16 +565,20 @@ update:
                        si->info.total = count;
                        si->first = f;
                        si->last = l;
-                       camel_store_summary_touch ((CamelStoreSummary *) store->summary);
-                       camel_store_summary_save ((CamelStoreSummary *) store->summary);
+                       camel_store_summary_touch (store_summary);
+                       camel_store_summary_save (store_summary);
                }
-               camel_store_summary_info_free ((CamelStoreSummary *) store->summary, (CamelStoreInfo *) si);
+               camel_store_summary_info_free (
+                       store_summary, (CamelStoreInfo *) si);
+
+       } else if (folder != NULL) {
+               g_warning ("Group '%s' not present in summary", folder);
+
        } else {
-               if (folder)
-                       g_warning ("Group '%s' not present in summary", folder);
-               else
-                       g_warning ("Missing group from group response");
+               g_warning ("Missing group from group response");
        }
 
+       g_clear_object (&nntp_store_summary);
+
        return ret;
 }


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