[gvfs] udisks2: Port GVfsUDisks2Mount to GTask
- From: Ondrej Holy <oholy src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gvfs] udisks2: Port GVfsUDisks2Mount to GTask
- Date: Tue, 28 Nov 2017 13:53:00 +0000 (UTC)
commit 83bde0cc6e0296c25cad05bb63b70b8a153b1700
Author: Ondrej Holy <oholy redhat com>
Date: Mon Jul 25 11:29:35 2016 +0200
udisks2: Port GVfsUDisks2Mount to GTask
GSimpleAsyncResult is deprecated in favour of GTask and should be replaced.
https://bugzilla.gnome.org/show_bug.cgi?id=747412
monitor/udisks2/gvfsudisks2mount.c | 366 +++++++++++++++--------------------
1 files changed, 157 insertions(+), 209 deletions(-)
---
diff --git a/monitor/udisks2/gvfsudisks2mount.c b/monitor/udisks2/gvfsudisks2mount.c
index ead65c9..a4ce057 100644
--- a/monitor/udisks2/gvfsudisks2mount.c
+++ b/monitor/udisks2/gvfsudisks2mount.c
@@ -525,19 +525,11 @@ gvfs_udisks2_mount_can_eject (GMount *_mount)
typedef struct
{
- volatile gint ref_count;
- GSimpleAsyncResult *simple;
gboolean in_progress;
- gboolean completed;
- gboolean failed;
-
- GVfsUDisks2Mount *mount;
UDisksEncrypted *encrypted;
UDisksFilesystem *filesystem;
- GCancellable *cancellable;
-
GMountOperation *mount_operation;
GMountUnmountFlags flags;
@@ -549,39 +541,24 @@ typedef struct
gboolean reply_set;
} UnmountData;
-static UnmountData *
-unmount_data_ref (UnmountData *data)
-{
- g_atomic_int_inc (&data->ref_count);
- return data;
-}
-
static void
-unmount_data_unref (UnmountData *data)
+unmount_data_free (UnmountData *data)
{
- if (g_atomic_int_dec_and_test (&data->ref_count))
+ if (data->mount_op_reply_handler_id > 0)
{
- g_object_unref (data->simple);
-
- if (data->mount_op_reply_handler_id > 0)
- {
- /* make the operation dialog go away */
- g_signal_emit_by_name (data->mount_operation, "aborted");
- g_signal_handler_disconnect (data->mount_operation, data->mount_op_reply_handler_id);
- }
- if (data->retry_unmount_timer_id > 0)
- {
- g_source_remove (data->retry_unmount_timer_id);
- data->retry_unmount_timer_id = 0;
- }
-
- g_clear_object (&data->mount);
- g_clear_object (&data->cancellable);
- g_clear_object (&data->mount_operation);
- g_clear_object (&data->encrypted);
- g_clear_object (&data->filesystem);
- g_free (data);
+ /* make the operation dialog go away */
+ g_signal_emit_by_name (data->mount_operation, "aborted");
+ g_signal_handler_disconnect (data->mount_operation, data->mount_op_reply_handler_id);
+ }
+ if (data->retry_unmount_timer_id > 0)
+ {
+ g_source_remove (data->retry_unmount_timer_id);
+ data->retry_unmount_timer_id = 0;
}
+
+ g_clear_object (&data->mount_operation);
+ g_clear_object (&data->encrypted);
+ g_clear_object (&data->filesystem);
}
static gboolean
@@ -597,30 +574,26 @@ unmount_operation_is_stop (GMountOperation *op)
}
static void
-unmount_data_complete (UnmountData *data,
- gboolean complete_idle)
+umount_completed (GObject *object,
+ GParamSpec *pspec,
+ gpointer user_data)
{
+ GTask *task = G_TASK (object);
+ UnmountData *data = g_task_get_task_data (task);
+
if (data->mount_operation &&
!unmount_operation_is_eject (data->mount_operation) &&
!unmount_operation_is_stop (data->mount_operation))
- gvfs_udisks2_unmount_notify_stop (data->mount_operation, data->failed);
-
- if (complete_idle)
- g_simple_async_result_complete_in_idle (data->simple);
- else
- g_simple_async_result_complete (data->simple);
-
- data->in_progress = FALSE;
- data->completed = TRUE;
- unmount_data_unref (data);
+ gvfs_udisks2_unmount_notify_stop (data->mount_operation, g_task_had_error (task));
}
-static void unmount_do (UnmountData *data, gboolean force);
+static void unmount_do (GTask *task, gboolean force);
static gboolean
on_retry_timer_cb (gpointer user_data)
{
- UnmountData *data = user_data;
+ GTask *task = G_TASK (user_data);
+ UnmountData *data = g_task_get_task_data (task);
if (data->retry_unmount_timer_id == 0)
goto out;
@@ -628,19 +601,20 @@ on_retry_timer_cb (gpointer user_data)
/* we're removing the timeout */
data->retry_unmount_timer_id = 0;
- if (data->completed || data->in_progress)
+ if (g_task_get_completed (task) || data->in_progress)
goto out;
/* timeout expired => try again */
- unmount_do (data, FALSE);
+ unmount_do (task, FALSE);
out:
return FALSE; /* remove timeout */
}
static void
-mount_op_reply_handle (UnmountData *data)
+mount_op_reply_handle (GTask *task)
{
+ UnmountData *data = g_task_get_task_data (task);
data->reply_set = FALSE;
if (data->reply_result == G_MOUNT_OPERATION_ABORTED ||
@@ -648,30 +622,23 @@ mount_op_reply_handle (UnmountData *data)
data->reply_choice == 1))
{
/* don't show an error dialog here */
- g_simple_async_result_set_error (data->simple,
- G_IO_ERROR,
- G_IO_ERROR_FAILED_HANDLED,
- "GMountOperation aborted (user should never see this "
- "error since it is G_IO_ERROR_FAILED_HANDLED)");
- data->failed = TRUE;
- unmount_data_complete (data, TRUE);
+ g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED_HANDLED,
+ "GMountOperation aborted");
+ g_object_unref (task);
}
else if (data->reply_result == G_MOUNT_OPERATION_HANDLED)
{
/* user chose force unmount => try again with force_unmount==TRUE */
- unmount_do (data, TRUE);
+ unmount_do (task, TRUE);
}
else
{
/* result == G_MOUNT_OPERATION_UNHANDLED => GMountOperation instance doesn't
* support :show-processes signal
*/
- g_simple_async_result_set_error (data->simple,
- G_IO_ERROR,
- G_IO_ERROR_BUSY,
- _("One or more programs are preventing the unmount operation."));
- data->failed = TRUE;
- unmount_data_complete (data, TRUE);
+ g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_BUSY,
+ _("One or more programs are preventing the unmount operation."));
+ g_object_unref (task);
}
}
@@ -680,7 +647,8 @@ on_mount_op_reply (GMountOperation *mount_operation,
GMountOperationResult result,
gpointer user_data)
{
- UnmountData *data = user_data;
+ GTask *task = G_TASK (user_data);
+ UnmountData *data = g_task_get_task_data (task);
gint choice;
/* disconnect the signal handler */
@@ -693,8 +661,8 @@ on_mount_op_reply (GMountOperation *mount_operation,
data->reply_result = result;
data->reply_choice = choice;
data->reply_set = TRUE;
- if (!data->completed && !data->in_progress)
- mount_op_reply_handle (data);
+ if (!g_task_get_completed (task) && !data->in_progress)
+ mount_op_reply_handle (task);
}
static void
@@ -702,7 +670,8 @@ lsof_command_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
- UnmountData *data = user_data;
+ GTask *task = G_TASK (user_data);
+ UnmountData *data = g_task_get_task_data (task);
GError *error;
gint exit_status;
GArray *processes;
@@ -751,7 +720,7 @@ lsof_command_cb (GObject *source_object,
}
out:
- if (!data->completed)
+ if (!g_task_get_completed (task))
{
gboolean is_eject;
gboolean is_stop;
@@ -771,7 +740,7 @@ lsof_command_cb (GObject *source_object,
data->mount_op_reply_handler_id = g_signal_connect (data->mount_operation,
"reply",
G_CALLBACK (on_mount_op_reply),
- data);
+ task);
}
if (is_eject || is_stop)
{
@@ -799,19 +768,20 @@ lsof_command_cb (GObject *source_object,
{
data->retry_unmount_timer_id = g_timeout_add_seconds (2,
on_retry_timer_cb,
- data);
+ task);
}
g_array_free (processes, TRUE);
g_free (standard_output);
}
- unmount_data_unref (data); /* return ref */
+ g_object_unref (task); /* return ref */
}
static void
-unmount_show_busy (UnmountData *data,
+unmount_show_busy (GTask *task,
const gchar *mount_point)
{
+ UnmountData *data = g_task_get_task_data (task);
gchar *escaped_mount_point;
data->in_progress = FALSE;
@@ -820,15 +790,15 @@ unmount_show_busy (UnmountData *data,
* Handle the reply now. */
if (data->reply_set)
{
- mount_op_reply_handle (data);
+ mount_op_reply_handle (task);
return;
}
escaped_mount_point = g_strescape (mount_point, NULL);
gvfs_udisks2_utils_spawn (10, /* timeout in seconds */
- data->cancellable,
+ g_task_get_cancellable (task),
lsof_command_cb,
- unmount_data_ref (data),
+ g_object_ref (task),
"lsof -t \"%s\"",
escaped_mount_point);
g_free (escaped_mount_point);
@@ -840,19 +810,18 @@ lock_cb (GObject *source_object,
gpointer user_data)
{
UDisksEncrypted *encrypted = UDISKS_ENCRYPTED (source_object);
- UnmountData *data = user_data;
+ GTask *task = G_TASK (user_data);
GError *error;
error = NULL;
if (!udisks_encrypted_call_lock_finish (encrypted,
res,
&error))
- {
- g_simple_async_result_take_error (data->simple, error);
- data->failed = TRUE;
- }
+ g_task_return_error (task, error);
+ else
+ g_task_return_boolean (task, TRUE);
- unmount_data_complete (data, FALSE);
+ g_object_unref (task);
}
static void
@@ -861,7 +830,9 @@ unmount_cb (GObject *source_object,
gpointer user_data)
{
UDisksFilesystem *filesystem = UDISKS_FILESYSTEM (source_object);
- UnmountData *data = user_data;
+ GTask *task = G_TASK (user_data);
+ UnmountData *data = g_task_get_task_data (task);
+ GVfsUDisks2Mount *mount = g_task_get_source_object (task);
GError *error;
error = NULL;
@@ -874,29 +845,29 @@ unmount_cb (GObject *source_object,
/* if the user passed in a GMountOperation, then do the GMountOperation::show-processes dance ... */
if (error->code == G_IO_ERROR_BUSY && data->mount_operation != NULL)
{
- unmount_show_busy (data, udisks_filesystem_get_mount_points (filesystem)[0]);
- goto out;
+ unmount_show_busy (task, udisks_filesystem_get_mount_points (filesystem)[0]);
+ return;
}
- g_simple_async_result_take_error (data->simple, error);
- data->failed = TRUE;
+
+ g_task_return_error (task, error);
+ g_object_unref (task);
}
else
{
- gvfs_udisks2_volume_monitor_update (data->mount->monitor);
+ gvfs_udisks2_volume_monitor_update (mount->monitor);
if (data->encrypted != NULL)
{
udisks_encrypted_call_lock (data->encrypted,
g_variant_new ("a{sv}", NULL), /* options */
- data->cancellable,
+ g_task_get_cancellable (task),
lock_cb,
- data);
- goto out;
+ task);
+ return;
}
- }
- unmount_data_complete (data, FALSE);
- out:
- ;
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+ }
}
@@ -907,7 +878,8 @@ umount_command_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
- UnmountData *data = user_data;
+ GTask *task = G_TASK (user_data);
+ GVfsUDisks2Mount *mount = g_task_get_source_object (task);
GError *error;
gint exit_status;
gchar *standard_error = NULL;
@@ -919,16 +891,16 @@ umount_command_cb (GObject *source_object,
&standard_error,
&error))
{
- g_simple_async_result_take_error (data->simple, error);
- data->failed = TRUE;
- unmount_data_complete (data, FALSE);
+ g_task_return_error (task, error);
+ g_object_unref (task);
goto out;
}
if (WIFEXITED (exit_status) && WEXITSTATUS (exit_status) == 0)
{
- gvfs_udisks2_volume_monitor_update (data->mount->monitor);
- unmount_data_complete (data, FALSE);
+ gvfs_udisks2_volume_monitor_update (mount->monitor);
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
goto out;
}
@@ -936,42 +908,44 @@ umount_command_cb (GObject *source_object,
(strstr (standard_error, "device is busy") != NULL ||
strstr (standard_error, "target is busy") != NULL))
{
- unmount_show_busy (data, data->mount->mount_path);
+ unmount_show_busy (task, mount->mount_path);
goto out;
}
- g_simple_async_result_set_error (data->simple,
- G_IO_ERROR,
- G_IO_ERROR_FAILED,
- "%s", standard_error);
- data->failed = TRUE;
- unmount_data_complete (data, FALSE);
+ g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "%s", standard_error);
+ g_object_unref (task);
out:
g_free (standard_error);
}
static void
-unmount_do (UnmountData *data,
+unmount_do (GTask *task,
gboolean force)
{
+ UnmountData *data = g_task_get_task_data (task);
+ GVfsUDisks2Mount *mount = g_task_get_source_object (task);
GVariantBuilder builder;
data->in_progress = TRUE;
if (data->mount_operation != NULL)
- gvfs_udisks2_unmount_notify_start (data->mount_operation,
- G_MOUNT (data->mount), NULL);
+ {
+ gvfs_udisks2_unmount_notify_start (data->mount_operation,
+ G_MOUNT (g_task_get_source_object (task)), NULL);
+ g_signal_connect (task, "notify::completed", G_CALLBACK (umount_completed), NULL);
+ }
/* Use the umount(8) command if there is no block device / filesystem */
if (data->filesystem == NULL)
{
gchar *escaped_mount_path;
- escaped_mount_path = g_strescape (data->mount->mount_path, NULL);
+ escaped_mount_path = g_strescape (mount->mount_path, NULL);
gvfs_udisks2_utils_spawn (10, /* timeout in seconds */
- data->cancellable,
+ g_task_get_cancellable (task),
umount_command_cb,
- data,
+ task,
"umount %s \"%s\"",
force ? "-l " : "",
escaped_mount_path);
@@ -995,9 +969,9 @@ unmount_do (UnmountData *data,
g_dbus_proxy_set_default_timeout (G_DBUS_PROXY (data->filesystem), G_MAXINT);
udisks_filesystem_call_unmount (data->filesystem,
g_variant_builder_end (&builder),
- data->cancellable,
+ g_task_get_cancellable (task),
unmount_cb,
- data);
+ task);
out:
;
@@ -1014,44 +988,41 @@ gvfs_udisks2_mount_unmount_with_operation (GMount *_mount,
GVfsUDisks2Mount *mount = GVFS_UDISKS2_MOUNT (_mount);
UnmountData *data;
UDisksBlock *block;
+ GTask *task;
/* first emit the ::mount-pre-unmount signal */
g_signal_emit_by_name (mount->monitor, "mount-pre-unmount", mount);
+ task = g_task_new (_mount, cancellable, callback, user_data);
+ g_task_set_source_tag (task, gvfs_udisks2_mount_unmount_with_operation);
+
data = g_new0 (UnmountData, 1);
- data->ref_count = 1;
- data->simple = g_simple_async_result_new (G_OBJECT (mount),
- callback,
- user_data,
- gvfs_udisks2_mount_unmount_with_operation);
- data->mount = g_object_ref (mount);
- data->cancellable = cancellable != NULL ? g_object_ref (cancellable) : NULL;
data->mount_operation = mount_operation != NULL ? g_object_ref (mount_operation) : NULL;
data->flags = flags;
+ g_task_set_task_data (task, data, (GDestroyNotify)unmount_data_free);
+
if (mount->is_burn_mount)
{
/* burn mounts are really never mounted so complete successfully immediately */
- unmount_data_complete (data, TRUE);
- goto out;
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+ return;
}
block = NULL;
if (mount->volume != NULL)
- block = gvfs_udisks2_volume_get_block (data->mount->volume);
+ block = gvfs_udisks2_volume_get_block (mount->volume);
if (block != NULL)
{
GDBusObject *object;
object = g_dbus_interface_get_object (G_DBUS_INTERFACE (block));
if (object == NULL)
{
- g_simple_async_result_set_error (data->simple,
- G_IO_ERROR,
- G_IO_ERROR_FAILED,
- "No object for D-Bus interface");
- data->failed = TRUE;
- unmount_data_complete (data, FALSE);
- goto out;
+ g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "No object for D-Bus interface");
+ g_object_unref (task);
+ return;
}
data->filesystem = udisks_object_get_filesystem (UDISKS_OBJECT (object));
if (data->filesystem == NULL)
@@ -1061,13 +1032,10 @@ gvfs_udisks2_mount_unmount_with_operation (GMount *_mount,
data->encrypted = udisks_object_get_encrypted (UDISKS_OBJECT (object));
if (data->encrypted == NULL)
{
- g_simple_async_result_set_error (data->simple,
- G_IO_ERROR,
- G_IO_ERROR_FAILED,
- "No filesystem or encrypted interface on D-Bus object");
- data->failed = TRUE;
- unmount_data_complete (data, FALSE);
- goto out;
+ g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "No filesystem or encrypted interface on D-Bus object");
+ g_object_unref (task);
+ return;
}
cleartext_block = udisks_client_get_cleartext_block (gvfs_udisks2_volume_monitor_get_udisks_client
(mount->monitor),
@@ -1078,22 +1046,16 @@ gvfs_udisks2_mount_unmount_with_operation (GMount *_mount,
g_object_unref (cleartext_block);
if (data->filesystem == NULL)
{
- g_simple_async_result_set_error (data->simple,
- G_IO_ERROR,
- G_IO_ERROR_FAILED,
- "No filesystem interface on D-Bus object for cleartext
device");
- data->failed = TRUE;
- unmount_data_complete (data, FALSE);
- goto out;
+ g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "No filesystem interface on D-Bus object for cleartext device");
+ g_object_unref (task);
+ return;
}
}
}
g_assert (data->filesystem != NULL);
}
- unmount_do (data, FALSE /* force */);
-
- out:
- ;
+ unmount_do (task, FALSE /* force */);
}
static gboolean
@@ -1101,7 +1063,10 @@ gvfs_udisks2_mount_unmount_with_operation_finish (GMount *mount,
GAsyncResult *result,
GError **error)
{
- return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error);
+ g_return_val_if_fail (g_task_is_valid (result, mount), FALSE);
+ g_return_val_if_fail (g_async_result_is_tagged (result, gvfs_udisks2_mount_unmount_with_operation), FALSE);
+
+ return g_task_propagate_boolean (G_TASK (result), error);
}
/* ---------------------------------------------------------------------------------------------------- */
@@ -1126,22 +1091,18 @@ gvfs_udisks2_mount_unmount_finish (GMount *mount,
/* ---------------------------------------------------------------------------------------------------- */
-typedef struct
-{
- GObject *object;
- GAsyncReadyCallback callback;
- gpointer user_data;
-} EjectWrapperOp;
-
static void
eject_wrapper_callback (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
- EjectWrapperOp *data = user_data;
- data->callback (data->object, res, data->user_data);
- g_object_unref (data->object);
- g_free (data);
+ GTask *task = G_TASK (user_data);
+ GError *error = NULL;
+
+ if (g_drive_eject_with_operation_finish (G_DRIVE (source_object), res, &error))
+ g_task_return_boolean (task, TRUE);
+ else
+ g_task_return_error (task, error);
}
static void
@@ -1153,33 +1114,25 @@ gvfs_udisks2_mount_eject_with_operation (GMount *_mount,
gpointer user_data)
{
GVfsUDisks2Mount *mount = GVFS_UDISKS2_MOUNT (_mount);
+ GTask *task;
GDrive *drive;
+ task = g_task_new (_mount, cancellable, callback, user_data);
+ g_task_set_source_tag (task, gvfs_udisks2_mount_eject_with_operation);
+
drive = NULL;
if (mount->volume != NULL)
drive = g_volume_get_drive (G_VOLUME (mount->volume));
if (drive != NULL)
{
- EjectWrapperOp *data;
- data = g_new0 (EjectWrapperOp, 1);
- data->object = g_object_ref (mount);
- data->callback = callback;
- data->user_data = user_data;
- g_drive_eject_with_operation (drive, flags, mount_operation, cancellable, eject_wrapper_callback,
data);
- g_object_unref (drive);
+ g_drive_eject_with_operation (drive, flags, mount_operation, cancellable, eject_wrapper_callback,
task);
}
else
{
- GSimpleAsyncResult *simple;
- simple = g_simple_async_result_new_error (G_OBJECT (mount),
- callback,
- user_data,
- G_IO_ERROR,
- G_IO_ERROR_FAILED,
- _("Operation not supported by backend"));
- g_simple_async_result_complete (simple);
- g_object_unref (simple);
+ g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED,
+ _("Operation not supported by backend"));
+ g_object_unref (task);
}
}
@@ -1188,25 +1141,10 @@ gvfs_udisks2_mount_eject_with_operation_finish (GMount *_mount,
GAsyncResult *result,
GError **error)
{
- GVfsUDisks2Mount *mount = GVFS_UDISKS2_MOUNT (_mount);
- gboolean ret = TRUE;
- GDrive *drive;
-
- drive = NULL;
- if (mount->volume != NULL)
- drive = g_volume_get_drive (G_VOLUME (mount->volume));
+ g_return_val_if_fail (g_task_is_valid (result, _mount), FALSE);
+ g_return_val_if_fail (g_async_result_is_tagged (result, gvfs_udisks2_mount_eject_with_operation), FALSE);
- if (drive != NULL)
- {
- ret = g_drive_eject_with_operation_finish (drive, result, error);
- g_object_unref (drive);
- }
- else
- {
- g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error);
- ret = FALSE;
- }
- return ret;
+ return g_task_propagate_boolean (G_TASK (result), error);
}
static void
@@ -1323,13 +1261,20 @@ gvfs_udisks2_mount_guess_content_type (GMount *mount,
GAsyncReadyCallback callback,
gpointer user_data)
{
- GSimpleAsyncResult *simple;
- simple = g_simple_async_result_new (G_OBJECT (mount),
- callback,
- user_data,
- NULL);
- g_simple_async_result_complete (simple);
- g_object_unref (simple);
+ GTask *task;
+ char **type;
+ GError *error = NULL;
+
+ task = g_task_new (mount, cancellable, callback, user_data);
+ g_task_set_source_tag (task, gvfs_udisks2_mount_guess_content_type);
+
+ type = gvfs_udisks2_mount_guess_content_type_sync (mount, FALSE, cancellable, &error);
+ if (error != NULL)
+ g_task_return_error (task, error);
+ else
+ g_task_return_pointer (task, type, (GDestroyNotify)g_strfreev);
+
+ g_object_unref (task);
}
static gchar **
@@ -1337,7 +1282,10 @@ gvfs_udisks2_mount_guess_content_type_finish (GMount *mount,
GAsyncResult *result,
GError **error)
{
- return gvfs_udisks2_mount_guess_content_type_sync (mount, FALSE, NULL, error);
+ g_return_val_if_fail (g_task_is_valid (result, mount), NULL);
+ g_return_val_if_fail (g_async_result_is_tagged (result, gvfs_udisks2_mount_guess_content_type), NULL);
+
+ return g_task_propagate_pointer (G_TASK (result), error);
}
/* ---------------------------------------------------------------------------------------------------- */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]