Bug #646898 - IMAPX should invalidated cache when uidvalidity changes
authorMilan Crha <mcrha@redhat.com>
Tue, 17 May 2011 09:30:38 +0000 (11:30 +0200)
committerMilan Crha <mcrha@redhat.com>
Tue, 17 May 2011 09:30:38 +0000 (11:30 +0200)
camel/camel-data-cache.c
camel/camel-data-cache.h
camel/providers/imapx/camel-imapx-server.c

index e3ecd5f..57029e6 100644 (file)
@@ -265,11 +265,10 @@ camel_data_cache_set_expire_access (CamelDataCache *cdc, time_t when)
 }
 
 static void
-data_cache_expire (CamelDataCache *cdc, const gchar *path, const gchar *keep, time_t now)
+data_cache_expire (CamelDataCache *cdc, const gchar *path, const gchar *keep, time_t now, gboolean expire_all)
 {
        GDir *dir;
        const gchar *dname;
-       GString *s;
        struct stat st;
        CamelStream *stream;
 
@@ -277,25 +276,29 @@ data_cache_expire (CamelDataCache *cdc, const gchar *path, const gchar *keep, ti
        if (dir == NULL)
                return;
 
-       s = g_string_new("");
        while ((dname = g_dir_read_name (dir))) {
-               if (strcmp (dname, keep) == 0)
+               gchar *dpath;
+
+               if (keep && strcmp (dname, keep) == 0)
                        continue;
 
-               g_string_printf (s, "%s/%s", path, dname);
-               if (g_stat (s->str, &st) == 0
+               dpath = g_build_filename (path, dname, NULL);
+
+               if (g_stat (dpath, &st) == 0
                    && S_ISREG (st.st_mode)
-                   && ((cdc->priv->expire_age != -1 && st.st_mtime + cdc->priv->expire_age < now)
+                   && (expire_all
+                       || (cdc->priv->expire_age != -1 && st.st_mtime + cdc->priv->expire_age < now)
                        || (cdc->priv->expire_access != -1 && st.st_atime + cdc->priv->expire_access < now))) {
-                       g_unlink (s->str);
-                       stream = camel_object_bag_get (cdc->priv->busy_bag, s->str);
+                       g_unlink (dpath);
+                       stream = camel_object_bag_get (cdc->priv->busy_bag, dpath);
                        if (stream) {
                                camel_object_bag_remove (cdc->priv->busy_bag, stream);
                                g_object_unref (stream);
                        }
                }
+
+               g_free (dpath);
        }
-       g_string_free (s, TRUE);
        g_dir_close (dir);
 }
 
@@ -314,11 +317,7 @@ data_cache_path (CamelDataCache *cdc, gint create, const gchar *path, const gcha
        dir = alloca (strlen (cdc->priv->path) + strlen (path) + 8);
        sprintf(dir, "%s/%s/%02x", cdc->priv->path, path, hash);
 
-#ifdef G_OS_WIN32
        if (g_access (dir, F_OK) == -1) {
-#else
-       if (access (dir, F_OK) == -1) {
-#endif
                if (create)
                        g_mkdir_with_parents (dir, 0700);
        } else if (cdc->priv->expire_age != -1 || cdc->priv->expire_access != -1) {
@@ -328,7 +327,7 @@ data_cache_path (CamelDataCache *cdc, gint create, const gchar *path, const gcha
                now = time (NULL);
                if (cdc->priv->expire_last[hash] + CAMEL_DATA_CACHE_CYCLE_TIME < now) {
                        cdc->priv->expire_last[hash] = now;
-                       data_cache_expire (cdc, dir, key, now);
+                       data_cache_expire (cdc, dir, key, now, FALSE);
                }
        }
 
@@ -505,3 +504,47 @@ camel_data_cache_remove (CamelDataCache *cdc,
        return ret;
 }
 
+/**
+ * camel_data_cache_clear:
+ * @cdc: a #CamelDataCache
+ * @path: Path to the (sub) cache the item exists in.
+ *
+ * Clear cache's content in @path.
+ **/
+void
+camel_data_cache_clear (CamelDataCache *cdc, const gchar *path)
+{
+       gchar *base_dir;
+       GDir *dir;
+       const gchar *dname;
+       struct stat st;
+
+       g_return_if_fail (cdc != NULL);
+       g_return_if_fail (path != NULL);
+
+       base_dir = g_build_filename (cdc->priv->path, path, NULL);
+
+       dir = g_dir_open (base_dir, 0, NULL);
+       if (dir == NULL) {
+               g_free (base_dir);
+               return;
+       }
+
+       while ((dname = g_dir_read_name (dir))) {
+               gchar *dpath;
+
+               dpath = g_build_filename (base_dir, dname, NULL);
+
+               if (g_stat (dpath, &st) == 0
+                   && S_ISDIR (st.st_mode)
+                   && !g_str_equal (dname, ".")
+                   && !g_str_equal (dname, "..")) {
+                       data_cache_expire (cdc, dpath, NULL, -1, TRUE);
+               }
+
+               g_free (dpath);
+       }
+
+       g_dir_close (dir);
+       g_free (base_dir);
+}
index 559b8b0..8b3e454 100644 (file)
@@ -90,6 +90,8 @@ gchar *               camel_data_cache_get_filename   (CamelDataCache *cdc,
                                                 const gchar *path,
                                                 const gchar *key,
                                                 GError **error);
+void           camel_data_cache_clear          (CamelDataCache *cdc,
+                                                const gchar *path);
 
 G_END_DECLS
 
index 79157e7..c4640f7 100644 (file)
@@ -1236,6 +1236,43 @@ imapx_expunge_uid_from_summary (CamelIMAPXServer *imap, gchar *uid, gboolean uns
        }
 }
 
+static void
+invalidate_local_cache (CamelIMAPXFolder *ifolder, guint64 new_uidvalidity)
+{
+       CamelFolder *cfolder;
+       CamelFolderChangeInfo *changes;
+       GPtrArray *uids;
+       gint ii;
+
+       g_return_if_fail (ifolder != NULL);
+
+       cfolder = CAMEL_FOLDER (ifolder);
+       g_return_if_fail (cfolder != NULL);
+
+       changes = camel_folder_change_info_new ();
+
+       uids = camel_folder_summary_array (cfolder->summary);
+       for (ii = 0; uids && ii < uids->len; ii++) {
+               const gchar *uid = uids->pdata[ii];
+
+               if (uid)
+                       camel_folder_change_info_change_uid (changes, uid);
+       }
+
+       g_ptr_array_foreach (uids, (GFunc) camel_pstring_free, NULL);
+       g_ptr_array_free (uids, TRUE);
+
+       CAMEL_IMAPX_SUMMARY (cfolder->summary)->validity = new_uidvalidity;
+       camel_folder_summary_touch (cfolder->summary);
+       camel_folder_summary_save_to_db (cfolder->summary, NULL);
+
+       camel_data_cache_clear (ifolder->cache, "cache");
+       camel_data_cache_clear (ifolder->cache, "cur");
+
+       camel_folder_changed (cfolder, changes);
+       camel_folder_change_info_free (changes);
+}
+
 /* handle any untagged responses */
 static gint
 imapx_untagged (CamelIMAPXServer *imap,
@@ -1637,11 +1674,15 @@ imapx_untagged (CamelIMAPXServer *imap,
                                }
                        }
                        if (ifolder) {
+                               CamelFolder *cfolder = CAMEL_FOLDER (ifolder);
+
                                ifolder->unread_on_server = sinfo->unseen;
                                ifolder->exists_on_server = sinfo->messages;
                                ifolder->modseq_on_server = sinfo->highestmodseq;
                                ifolder->uidnext_on_server = sinfo->uidnext;
                                ifolder->uidvalidity_on_server = sinfo->uidvalidity;
+                               if (sinfo->uidvalidity && sinfo->uidvalidity != ((CamelIMAPXSummary *) cfolder->summary)->validity)
+                                       invalidate_local_cache (ifolder, sinfo->uidvalidity);
                        } else {
                                c(imap->tagprefix, "Received STATUS for unknown folder '%s'\n", sinfo->name);
                        }
@@ -2491,6 +2532,8 @@ imapx_command_select_done (CamelIMAPXServer *is, CamelIMAPXCommand *ic)
                is->state = IMAPX_INITIALISED;
        } else {
                CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *) is->select_pending;
+               CamelFolder *cfolder = is->select_pending;
+
                c(is->tagprefix, "Select ok!\n");
 
                if (!is->select_folder) {
@@ -2508,11 +2551,11 @@ imapx_command_select_done (CamelIMAPXServer *is, CamelIMAPXCommand *ic)
                }
                ifolder->uidvalidity_on_server = is->uidvalidity;
                selected_folder = camel_folder_get_full_name (is->select_folder);
-#if 0
-               /* This must trigger a complete index rebuild! */
-               if (is->uidvalidity && is->uidvalidity != ((CamelIMAPXSummary *) is->select_folder->summary)->uidvalidity)
-                       g_warning("uidvalidity doesn't match!");
 
+               if (is->uidvalidity && is->uidvalidity != ((CamelIMAPXSummary *) cfolder->summary)->validity)
+                       invalidate_local_cache (ifolder, is->uidvalidity);
+
+#if 0
                /* This should trigger a new messages scan */
                if (is->exists != is->select_folder->summary->root_view->total_count)
                        g_warning("exists is %d our summary is %d and summary exists is %d\n", is->exists,
@@ -4078,6 +4121,11 @@ imapx_job_refresh_info_start (CamelIMAPXServer *is,
 #endif
        total = camel_folder_summary_count (folder->summary);
 
+       if (ifolder->uidvalidity_on_server && isum->validity && isum->validity != ifolder->uidvalidity_on_server) {
+               invalidate_local_cache (ifolder, ifolder->uidvalidity_on_server);
+               need_rescan = TRUE;
+       }
+
        /* We don't have valid unread count or modseq for currently-selected server
           (unless we want to re-SELECT it). We fake unread count when fetching
           message flags, but don't depend on modseq for the selected folder */