[evolution-data-server] Avoid camel_store_summary_index().



commit c23a9b0842d98430f4585ec5e83358acbf18d310
Author: Matthew Barnes <mbarnes redhat com>
Date:   Fri Aug 16 12:23:28 2013 -0400

    Avoid camel_store_summary_index().
    
    camel_store_summary_index() is only called when looping over summary
    items from 0 to camel_store_summary_count().  But this pattern is not
    thread-safe, because another thread could add or remove summary items
    while the loop is in progress.
    
    Use camel_store_summary_array() instead to avoid these issues.

 camel/camel-imapx-store-summary.c               |   46 ++++++---
 camel/camel-imapx-store.c                       |  130 ++++++++++++-----------
 camel/providers/nntp/camel-nntp-store-summary.c |   30 ++++--
 camel/providers/nntp/camel-nntp-store.c         |  127 ++++++++++++----------
 4 files changed, 189 insertions(+), 144 deletions(-)
---
diff --git a/camel/camel-imapx-store-summary.c b/camel/camel-imapx-store-summary.c
index 95674af..d921fb2 100644
--- a/camel/camel-imapx-store-summary.c
+++ b/camel/camel-imapx-store-summary.c
@@ -120,24 +120,40 @@ CamelIMAPXStoreInfo *
 camel_imapx_store_summary_full_name (CamelIMAPXStoreSummary *s,
                                      const gchar *full_name)
 {
-       gint count, i;
-       CamelIMAPXStoreInfo *info;
-       gboolean is_inbox;
-
-       is_inbox = camel_imapx_mailbox_is_inbox (full_name);
-
-       count = camel_store_summary_count ((CamelStoreSummary *) s);
-       for (i = 0; i < count; i++) {
-               info = (CamelIMAPXStoreInfo *) camel_store_summary_index ((CamelStoreSummary *) s, i);
-               if (info) {
-                       if (strcmp (info->full_name, full_name) == 0 ||
-                           (is_inbox && g_ascii_strcasecmp (info->full_name, full_name) == 0))
-                               return info;
-                       camel_store_summary_info_unref ((CamelStoreSummary *) s, (CamelStoreInfo *) info);
+       CamelStoreInfo *match = NULL;
+       GPtrArray *array;
+       gboolean find_inbox;
+       guint ii;
+
+       find_inbox = camel_imapx_mailbox_is_inbox (full_name);
+
+       array = camel_store_summary_array (CAMEL_STORE_SUMMARY (s));
+
+       for (ii = 0; ii < array->len; ii++) {
+               CamelIMAPXStoreInfo *info;
+               gboolean is_inbox;
+
+               info = g_ptr_array_index (array, ii);
+               is_inbox = camel_imapx_mailbox_is_inbox (info->full_name);
+
+               if (find_inbox && is_inbox) {
+                       match = camel_store_summary_info_ref (
+                               CAMEL_STORE_SUMMARY (s),
+                               (CamelStoreInfo *) info);
+                       break;
+               }
+
+               if (g_str_equal (info->full_name, full_name)) {
+                       match = camel_store_summary_info_ref (
+                               CAMEL_STORE_SUMMARY (s),
+                               (CamelStoreInfo *) info);
+                       break;
                }
        }
 
-       return NULL;
+       camel_store_summary_array_free (CAMEL_STORE_SUMMARY (s), array);
+
+       return (CamelIMAPXStoreInfo *) match;
 }
 
 gchar *
diff --git a/camel/camel-imapx-store.c b/camel/camel-imapx-store.c
index c413249..140650d 100644
--- a/camel/camel-imapx-store.c
+++ b/camel/camel-imapx-store.c
@@ -503,15 +503,15 @@ get_folder_offline (CamelStore *store,
        CamelFolder *new_folder = NULL;
        CamelStoreInfo *si;
        CamelService *service;
-       CamelStoreSummary *summary;
+       CamelStoreSummary *store_summary;
        const gchar *user_cache_dir;
        gboolean is_inbox;
 
        service = CAMEL_SERVICE (store);
        user_cache_dir = camel_service_get_user_cache_dir (service);
 
-       summary = CAMEL_STORE_SUMMARY (imapx_store->summary);
-       si = camel_store_summary_path (summary, folder_name);
+       store_summary = CAMEL_STORE_SUMMARY (imapx_store->summary);
+       si = camel_store_summary_path (store_summary, folder_name);
        is_inbox = camel_imapx_mailbox_is_inbox (folder_name);
 
        if (si == NULL && is_inbox)
@@ -539,7 +539,7 @@ get_folder_offline (CamelStore *store,
                g_free (folder_dir);
                g_free (base_dir);
 
-               camel_store_summary_info_unref (summary, si);
+               camel_store_summary_info_unref (store_summary, si);
        } else {
                g_set_error (
                        error, CAMEL_STORE_ERROR,
@@ -853,45 +853,50 @@ rename_folder_info (CamelIMAPXStore *imapx_store,
                     const gchar *old_name,
                     const gchar *new_name)
 {
-       CamelStoreSummary *summary;
-       gint i, count;
-       CamelStoreInfo *si;
+       CamelStoreSummary *store_summary;
+       GPtrArray *array;
        gint olen = strlen (old_name);
-       const gchar *path;
-       gchar *npath, *nfull;
+       guint ii;
 
-       summary = CAMEL_STORE_SUMMARY (imapx_store->summary);
+       store_summary = CAMEL_STORE_SUMMARY (imapx_store->summary);
 
-       count = camel_store_summary_count (summary);
-       for (i = 0; i < count; i++) {
-               si = camel_store_summary_index (summary, i);
-               if (si == NULL)
-                       continue;
-               path = camel_store_info_path (summary, si);
-               if (strncmp (path, old_name, olen) == 0) {
-                       if (strlen (path) > olen)
-                               npath = g_strdup_printf ("%s/%s", new_name, path + olen + 1);
-                       else
-                               npath = g_strdup (new_name);
-                       nfull = camel_imapx_store_summary_path_to_full (
-                               imapx_store->summary, npath,
-                               imapx_store->dir_sep);
+       array = camel_store_summary_array (store_summary);
 
-                       camel_store_info_set_string (
-                               summary, si,
-                               CAMEL_STORE_INFO_PATH, npath);
-                       camel_store_info_set_string (
-                               summary, si,
-                               CAMEL_IMAPX_STORE_INFO_FULL_NAME, nfull);
+       for (ii = 0; ii < array->len; ii++) {
+               CamelStoreInfo *si;
+               const gchar *path;
+               gchar *new_path;
+               gchar *new_full;
 
-                       camel_store_summary_touch (summary);
+               si = g_ptr_array_index (array, ii);
+               path = camel_store_info_path (store_summary, si);
 
-                       g_free (nfull);
-                       g_free (npath);
-               }
+               if (strncmp (path, old_name, olen) != 0)
+                       continue;
 
-               camel_store_summary_info_unref (summary, si);
+               if (strlen (path) > olen)
+                       new_path = g_strdup_printf (
+                               "%s/%s", new_name, path + olen + 1);
+               else
+                       new_path = g_strdup (new_name);
+               new_full = camel_imapx_store_summary_path_to_full (
+                       imapx_store->summary, new_path,
+                       imapx_store->dir_sep);
+
+               camel_store_info_set_string (
+                       store_summary, si,
+                       CAMEL_STORE_INFO_PATH, new_path);
+               camel_store_info_set_string (
+                       store_summary, si,
+                       CAMEL_IMAPX_STORE_INFO_FULL_NAME, new_full);
+
+               camel_store_summary_touch (store_summary);
+
+               g_free (new_full);
+               g_free (new_path);
        }
+
+       camel_store_summary_array_free (store_summary, array);
 }
 
 static void
@@ -937,13 +942,15 @@ get_folder_info_offline (CamelStore *store,
        CamelIMAPXStore *imapx_store = CAMEL_IMAPX_STORE (store);
        CamelService *service;
        CamelSettings *settings;
+       CamelStoreSummary *store_summary;
        gboolean include_inbox = FALSE;
        CamelFolderInfo *fi;
        GPtrArray *folders;
+       GPtrArray *array;
        gchar *pattern, *name;
        gboolean use_namespace;
        gboolean use_subscriptions;
-       gint i;
+       guint ii;
 
        service = CAMEL_SERVICE (store);
 
@@ -999,21 +1006,23 @@ get_folder_info_offline (CamelStore *store,
         * the moment. So let it do the right thing by bailing out if it's
         * not a folder we're explicitly interested in. */
 
-       for (i = 0; i < camel_store_summary_count ((CamelStoreSummary *) imapx_store->summary); i++) {
-               CamelStoreInfo *si = camel_store_summary_index ((CamelStoreSummary *) imapx_store->summary, 
i);
+       store_summary = CAMEL_STORE_SUMMARY (imapx_store->summary);
+
+       array = camel_store_summary_array (store_summary);
+
+       for (ii = 0; ii < array->len; ii++) {
+               CamelStoreInfo *si;
                const gchar *full_name;
                CamelIMAPXStoreNamespace *ns;
 
-               if (si == NULL)
-                       continue;
+               si = g_ptr_array_index (array, ii);
 
                full_name = ((CamelIMAPXStoreInfo *) si)->full_name;
-               if (!full_name || !*full_name) {
-                       camel_store_summary_info_unref ((CamelStoreSummary *) imapx_store->summary, si);
+               if (full_name == NULL || *full_name == '\0')
                        continue;
-               }
 
-               ns = camel_imapx_store_summary_namespace_find_full (imapx_store->summary, full_name);
+               ns = camel_imapx_store_summary_namespace_find_full (
+                       imapx_store->summary, full_name);
 
                /* Modify the checks to see match the namespaces from preferences */
                if ((g_str_equal (name, full_name)
@@ -1024,7 +1033,7 @@ get_folder_info_offline (CamelStore *store,
                        || (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED)
                        || (flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIPTION_LIST) != 0)) {
 
-                       fi = imapx_build_folder_info (imapx_store, camel_store_info_path ((CamelStoreSummary 
*) imapx_store->summary, si));
+                       fi = imapx_build_folder_info (imapx_store, camel_store_info_path (store_summary, si));
                        fi->unread = si->unread;
                        fi->total = si->total;
                        if ((fi->flags & CAMEL_FOLDER_TYPE_MASK) != 0)
@@ -1045,8 +1054,10 @@ get_folder_info_offline (CamelStore *store,
                                fi->flags |= CAMEL_FOLDER_NOCHILDREN;
                        g_ptr_array_add (folders, fi);
                }
-               camel_store_summary_info_unref ((CamelStoreSummary *) imapx_store->summary, si);
        }
+
+       camel_store_summary_array_free (store_summary, array);
+
        g_free (pattern);
 
        fi = camel_folder_info_build (folders, top, '/', TRUE);
@@ -1285,8 +1296,9 @@ sync_folders (CamelIMAPXStore *imapx_store,
        CamelSettings *settings;
        CamelStoreSummary *store_summary;
        GHashTable *folders_from_server;
+       GPtrArray *array;
        gboolean notify_all;
-       gint ii, total;
+       guint ii;
 
        store_summary = CAMEL_STORE_SUMMARY (imapx_store->summary);
 
@@ -1301,9 +1313,9 @@ sync_folders (CamelIMAPXStore *imapx_store,
                CAMEL_IMAPX_SETTINGS (settings));
        g_object_unref (settings);
 
-       total = camel_store_summary_count (store_summary);
+       array = camel_store_summary_array (store_summary);
 
-       for (ii = 0; ii < total; ii++) {
+       for (ii = 0; ii < array->len; ii++) {
                CamelStoreInfo *si;
                CamelFolderInfo *fi;
                CamelIMAPXStoreNamespace *ns;
@@ -1311,13 +1323,11 @@ sync_folders (CamelIMAPXStore *imapx_store,
                const gchar *si_path;
                gboolean pattern_match;
 
-               si = camel_store_summary_index (store_summary, ii);
-               if (si == NULL)
-                       continue;
+               si = g_ptr_array_index (array, ii);
 
                full_name = ((CamelIMAPXStoreInfo *) si)->full_name;
                if (full_name == NULL || *full_name == '\0')
-                       goto endloop;
+                       continue;
 
                ns = camel_imapx_store_summary_namespace_find_full (
                        imapx_store->summary, full_name);
@@ -1326,7 +1336,7 @@ sync_folders (CamelIMAPXStore *imapx_store,
                        (pattern == NULL) || (*pattern == '\0') ||
                        imapx_match_pattern (ns, pattern, full_name);
                if (!pattern_match)
-                       goto endloop;
+                       continue;
 
                si_path = camel_store_info_path (store_summary, si);
                fi = g_hash_table_lookup (folders_from_server, si_path);
@@ -1362,15 +1372,11 @@ sync_folders (CamelIMAPXStore *imapx_store,
                        } else {
                                camel_store_summary_remove (store_summary, si);
                        }
-
-                       total--;
-                       ii--;
                }
-
-endloop:
-               camel_store_summary_info_unref (store_summary, si);
        }
 
+       camel_store_summary_array_free (store_summary, array);
+
        g_hash_table_destroy (folders_from_server);
 
        return TRUE;
diff --git a/camel/providers/nntp/camel-nntp-store-summary.c b/camel/providers/nntp/camel-nntp-store-summary.c
index afb8a5d..cbf0548 100644
--- a/camel/providers/nntp/camel-nntp-store-summary.c
+++ b/camel/providers/nntp/camel-nntp-store-summary.c
@@ -108,20 +108,28 @@ CamelNNTPStoreInfo *
 camel_nntp_store_summary_full_name (CamelNNTPStoreSummary *s,
                                     const gchar *full_name)
 {
-       gint count, i;
-       CamelNNTPStoreInfo *info;
+       CamelStoreInfo *match = NULL;
+       GPtrArray *array;
+       guint ii;
+
+       array = camel_store_summary_array (CAMEL_STORE_SUMMARY (s));
+
+       for (ii = 0; ii < array->len; ii++) {
+               CamelNNTPStoreInfo *info;
 
-       count = camel_store_summary_count ((CamelStoreSummary *) s);
-       for (i = 0; i < count; i++) {
-               info = (CamelNNTPStoreInfo *) camel_store_summary_index ((CamelStoreSummary *) s, i);
-               if (info) {
-                       if (strcmp (info->full_name, full_name) == 0)
-                               return info;
-                       camel_store_summary_info_unref ((CamelStoreSummary *) s, (CamelStoreInfo *) info);
+               info = g_ptr_array_index (array, ii);
+
+               if (g_str_equal (info->full_name, full_name)) {
+                       match = camel_store_summary_info_ref (
+                               CAMEL_STORE_SUMMARY (s),
+                               (CamelStoreInfo *) info);
+                       break;
                }
        }
 
-       return NULL;
+       camel_store_summary_array_free (CAMEL_STORE_SUMMARY (s), array);
+
+       return (CamelNNTPStoreInfo *) match;
 }
 
 gchar *
diff --git a/camel/providers/nntp/camel-nntp-store.c b/camel/providers/nntp/camel-nntp-store.c
index e9689bf..395f7e6 100644
--- a/camel/providers/nntp/camel-nntp-store.c
+++ b/camel/providers/nntp/camel-nntp-store.c
@@ -736,7 +736,7 @@ nntp_folder_info_from_name (CamelNNTPStore *store,
 }
 
 /* handle list/newgroups response */
-static CamelNNTPStoreInfo *
+static CamelStoreInfo *
 nntp_store_info_update (CamelNNTPStore *nntp_store,
                         gchar *line)
 {
@@ -802,7 +802,7 @@ nntp_store_info_update (CamelNNTPStore *nntp_store,
 
        g_clear_object (&nntp_store_summary);
 
-       return si;
+       return (CamelStoreInfo *) si;
 }
 
 static CamelFolderInfo *
@@ -817,8 +817,9 @@ nntp_store_get_subscribed_folder_info (CamelNNTPStore *nntp_store,
        CamelService *service;
        CamelSettings *settings;
        CamelFolderInfo *first = NULL, *last = NULL, *fi = NULL;
+       GPtrArray *array;
        gboolean short_folder_names;
-       guint ii, store_summary_count;
+       guint ii;
 
        /* 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)
@@ -836,56 +837,60 @@ nntp_store_get_subscribed_folder_info (CamelNNTPStore *nntp_store,
        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++) {
+       array = camel_store_summary_array (store_summary);
+
+       for (ii = 0; ii < array->len; ii++) {
                CamelStoreInfo *si;
 
-               si = camel_store_summary_index (store_summary, ii);
-               if (si == NULL)
+               si = g_ptr_array_index (array, ii);
+
+               if ((si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) == 0)
                        continue;
 
-               if (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) {
-                       /* slow mode?  open and update the folder, always! this will implictly update
-                        * our storeinfo too; in a very round-about way */
-                       if ((flags & CAMEL_STORE_FOLDER_INFO_FAST) == 0) {
-                               CamelNNTPFolder *folder;
-                               gchar *line;
-
-                               folder = (CamelNNTPFolder *)
-                                       camel_store_get_folder_sync (
-                                       (CamelStore *) nntp_store, si->path,
-                                       0, cancellable, NULL);
-                               if (folder) {
-                                       CamelFolderChangeInfo *changes = NULL;
-
-                                       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 ();
-                                               }
+               /* slow mode?  open and update the folder, always! this will
+                * implictly update our storeinfo too; in a very round-about
+                * way */
+               if ((flags & CAMEL_STORE_FOLDER_INFO_FAST) == 0) {
+                       CamelNNTPFolder *folder;
+                       gchar *line;
+
+                       folder = (CamelNNTPFolder *)
+                               camel_store_get_folder_sync (
+                               (CamelStore *) nntp_store, si->path,
+                               0, cancellable, NULL);
+                       if (folder) {
+                               CamelFolderChangeInfo *changes = NULL;
+
+                               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 ();
                                        }
-                                       if (changes) {
-                                               camel_folder_changed (CAMEL_FOLDER (folder), changes);
-                                               camel_folder_change_info_free (changes);
-                                       }
-                                       g_object_unref (folder);
                                }
+                               if (changes) {
+                                       camel_folder_changed (CAMEL_FOLDER (folder), changes);
+                                       camel_folder_change_info_free (changes);
+                               }
+                               g_object_unref (folder);
                        }
-                       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_unref (store_summary, si);
+
+               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_array_free (store_summary, array);
+
        g_clear_object (&nntp_store_summary);
 
        return first;
@@ -983,6 +988,7 @@ nntp_store_get_cached_folder_info (CamelNNTPStore *nntp_store,
        CamelSettings *settings;
        CamelFolderInfo *first = NULL, *last = NULL, *fi = NULL;
        GHashTable *known; /* folder name to folder info */
+       GPtrArray *array;
        gboolean folder_hierarchy_relative;
        gchar *tmpname;
        gchar *top = g_strconcat (orig_top ? orig_top:"", ".", NULL);
@@ -991,7 +997,7 @@ nntp_store_get_cached_folder_info (CamelNNTPStore *nntp_store,
        gint root_or_flag;
        gint recursive_flag;
        gint is_folder_list;
-       guint ii, store_summary_count;
+       guint ii;
 
        subscribed_or_flag =
                (flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED) ? 0 : 1;
@@ -1017,14 +1023,13 @@ nntp_store_get_cached_folder_info (CamelNNTPStore *nntp_store,
        known = g_hash_table_new (g_str_hash, g_str_equal);
 
        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++) {
+       array = camel_store_summary_array (store_summary);
+
+       for (ii = 0; ii < array->len; ii++) {
                CamelStoreInfo *si;
 
-               si = camel_store_summary_index (store_summary, ii);
-               if (si == NULL)
-                       continue;
+               si = g_ptr_array_index (array, ii);
 
                if ((subscribed_or_flag || (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED))
                    && (root_or_flag || strncmp (si->path, top, toplen) == 0)) {
@@ -1084,13 +1089,12 @@ nntp_store_get_cached_folder_info (CamelNNTPStore *nntp_store,
                        }
                } else if (subscribed_or_flag && first) {
                        /* we have already added subitems, but this item is no longer a subitem */
-                       camel_store_summary_info_unref (store_summary, si);
                        break;
                }
-
-               camel_store_summary_info_unref (store_summary, si);
        }
 
+       camel_store_summary_array_free (store_summary, array);
+
        g_hash_table_destroy (known);
        g_free (top);
 
@@ -1163,7 +1167,6 @@ nntp_store_get_folder_info_all (CamelNNTPStore *nntp_store,
 {
        CamelNNTPStream *nntp_stream = NULL;
        CamelNNTPStoreSummary *nntp_store_summary;
-       CamelNNTPStoreInfo *si;
        guint len;
        guchar *line;
        gint ret = -1;
@@ -1201,8 +1204,11 @@ nntp_store_get_folder_info_all (CamelNNTPStore *nntp_store,
                        while ((ret = camel_nntp_stream_line (nntp_stream, &line, &len, cancellable, error)) 
0)
                                nntp_store_info_update (nntp_store, (gchar *) line);
                } else {
+                       CamelStoreSummary *store_summary;
+                       CamelStoreInfo *si;
+                       GPtrArray *array;
                        GHashTable *all;
-                       gint i;
+                       guint ii;
 
                do_complete_list:
                        /* seems we do need a complete list */
@@ -1221,14 +1227,23 @@ 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 
(CAMEL_STORE_SUMMARY (nntp_store_summary), i)); i++)
-                               g_hash_table_insert (all, si->info.path, si);
+
+                       store_summary = CAMEL_STORE_SUMMARY (nntp_store_summary);
+                       array = camel_store_summary_array (store_summary);
+
+                       for (ii = 0; ii < array->len; ii++) {
+                               si = g_ptr_array_index (array, ii);
+                               camel_store_summary_info_ref (store_summary, si);
+                               g_hash_table_insert (all, si->path, si);
+                       }
+
+                       camel_store_summary_array_free (store_summary, array);
 
                        nntp_stream = camel_nntp_store_ref_stream (nntp_store);
 
                        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_remove (all, si->path);
                        }
 
                        g_hash_table_foreach (


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