- Update to 1.1.1
This commit is contained in:
parent
0f32a04c10
commit
5dab70e088
@ -1 +1 @@
|
||||
gvfs-1.0.3.tar.bz2
|
||||
gvfs-1.1.1.tar.bz2
|
||||
|
@ -1,375 +0,0 @@
|
||||
--- trunk/common/gvfsdaemonprotocol.h 2008/09/01 21:22:15 1922
|
||||
+++ trunk/common/gvfsdaemonprotocol.h 2008/09/26 10:44:37 2031
|
||||
@@ -12,6 +12,7 @@
|
||||
#define G_VFS_DBUS_MOUNTTRACKER_INTERFACE "org.gtk.vfs.MountTracker"
|
||||
#define G_VFS_DBUS_MOUNTTRACKER_PATH "/org/gtk/vfs/mounttracker"
|
||||
#define G_VFS_DBUS_MOUNTTRACKER_OP_LOOKUP_MOUNT "lookupMount"
|
||||
+#define G_VFS_DBUS_MOUNTTRACKER_OP_LOOKUP_MOUNT_BY_FUSE_PATH "lookupMountByFusePath"
|
||||
#define G_VFS_DBUS_MOUNTTRACKER_OP_MOUNT_LOCATION "mountLocation"
|
||||
#define G_VFS_DBUS_MOUNTTRACKER_OP_LIST_MOUNTS "listMounts"
|
||||
#define G_VFS_DBUS_MOUNTTRACKER_OP_REGISTER_MOUNT "registerMount"
|
||||
--- trunk/client/gdaemonvfs.h 2008/01/31 16:54:22 1214
|
||||
+++ trunk/client/gdaemonvfs.h 2008/09/26 10:44:37 2031
|
||||
@@ -60,6 +60,8 @@
|
||||
GMountInfo * _g_daemon_vfs_get_mount_info_sync (GMountSpec *spec,
|
||||
const char *path,
|
||||
GError **error);
|
||||
+GMountInfo * _g_daemon_vfs_get_mount_info_by_fuse_sync (const char *fuse_path,
|
||||
+ char **mount_path);
|
||||
GMountSpec * _g_daemon_vfs_get_mount_spec_for_path (GMountSpec *spec,
|
||||
const char *path,
|
||||
const char *new_path);
|
||||
--- trunk/client/gdaemonvfs.c 2008/09/23 19:16:06 2021
|
||||
+++ trunk/client/gdaemonvfs.c 2008/09/26 10:44:37 2031
|
||||
@@ -55,6 +55,8 @@
|
||||
GVfs *wrapped_vfs;
|
||||
GList *mount_cache;
|
||||
|
||||
+ GFile *fuse_root;
|
||||
+
|
||||
GHashTable *from_uri_hash;
|
||||
GHashTable *to_uri_hash;
|
||||
|
||||
@@ -287,6 +289,7 @@
|
||||
const char * const *schemes, * const *mount_types;
|
||||
GVfsUriMapper *mapper;
|
||||
GList *modules;
|
||||
+ char *file;
|
||||
int i;
|
||||
|
||||
bindtextdomain (GETTEXT_PACKAGE, GVFS_LOCALEDIR);
|
||||
@@ -319,6 +322,10 @@
|
||||
|
||||
vfs->wrapped_vfs = g_vfs_get_local ();
|
||||
|
||||
+ file = g_build_filename (g_get_home_dir(), ".gvfs", NULL);
|
||||
+ vfs->fuse_root = g_vfs_get_file_for_path (vfs->wrapped_vfs, file);
|
||||
+ g_free (file);
|
||||
+
|
||||
dbus_connection_set_exit_on_disconnect (vfs->async_bus, FALSE);
|
||||
|
||||
_g_dbus_connection_integrate_with_main (vfs->async_bus);
|
||||
@@ -357,13 +364,42 @@
|
||||
return g_object_new (G_TYPE_DAEMON_VFS, NULL);
|
||||
}
|
||||
|
||||
+/* This unrefs file if its changed */
|
||||
+static GFile *
|
||||
+convert_fuse_path (GVfs *vfs,
|
||||
+ GFile *file)
|
||||
+{
|
||||
+ GFile *fuse_root;
|
||||
+ char *fuse_path, *mount_path;
|
||||
+ GMountInfo *mount_info;
|
||||
+
|
||||
+ fuse_root = ((GDaemonVfs *)vfs)->fuse_root;
|
||||
+ if (g_file_has_prefix (file, fuse_root))
|
||||
+ {
|
||||
+ fuse_path = g_file_get_path (file);
|
||||
+ mount_info = _g_daemon_vfs_get_mount_info_by_fuse_sync (fuse_path, &mount_path);
|
||||
+ g_free (fuse_path);
|
||||
+ if (mount_info)
|
||||
+ {
|
||||
+ g_object_unref (file);
|
||||
+ /* TODO: Do we need to look at the prefix of the mount_spec? */
|
||||
+ file = g_daemon_file_new (mount_info->mount_spec, mount_path);
|
||||
+ g_free (mount_path);
|
||||
+ g_mount_info_unref (mount_info);
|
||||
+ }
|
||||
+ }
|
||||
+ return file;
|
||||
+}
|
||||
+
|
||||
static GFile *
|
||||
g_daemon_vfs_get_file_for_path (GVfs *vfs,
|
||||
const char *path)
|
||||
{
|
||||
- /* TODO: detect fuse paths and convert to daemon vfs GFiles */
|
||||
+ GFile *file;
|
||||
|
||||
- return g_vfs_get_file_for_path (G_DAEMON_VFS (vfs)->wrapped_vfs, path);
|
||||
+ file = g_vfs_get_file_for_path (G_DAEMON_VFS (vfs)->wrapped_vfs, path);
|
||||
+ file = convert_fuse_path (vfs, file);
|
||||
+ return file;
|
||||
}
|
||||
|
||||
static GFile *
|
||||
@@ -711,6 +747,41 @@
|
||||
return info;
|
||||
}
|
||||
|
||||
+static GMountInfo *
|
||||
+lookup_mount_info_by_fuse_path_in_cache (const char *fuse_path,
|
||||
+ char **mount_path)
|
||||
+{
|
||||
+ GMountInfo *info;
|
||||
+ GList *l;
|
||||
+
|
||||
+ G_LOCK (mount_cache);
|
||||
+ info = NULL;
|
||||
+ for (l = the_vfs->mount_cache; l != NULL; l = l->next)
|
||||
+ {
|
||||
+ GMountInfo *mount_info = l->data;
|
||||
+
|
||||
+ if (mount_info->fuse_mountpoint != NULL &&
|
||||
+ g_str_has_prefix (fuse_path, mount_info->fuse_mountpoint))
|
||||
+ {
|
||||
+ int len = strlen (mount_info->fuse_mountpoint);
|
||||
+ if (fuse_path[len] == 0 ||
|
||||
+ fuse_path[len] == '/')
|
||||
+ {
|
||||
+ if (fuse_path[len] == 0)
|
||||
+ *mount_path = g_strdup ("/");
|
||||
+ else
|
||||
+ *mount_path = g_strdup (fuse_path + len);
|
||||
+ info = g_mount_info_ref (mount_info);
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ G_UNLOCK (mount_cache);
|
||||
+
|
||||
+ return info;
|
||||
+}
|
||||
+
|
||||
+
|
||||
void
|
||||
_g_daemon_vfs_invalidate_dbus_id (const char *dbus_id)
|
||||
{
|
||||
@@ -908,6 +979,71 @@
|
||||
return info;
|
||||
}
|
||||
|
||||
+GMountInfo *
|
||||
+_g_daemon_vfs_get_mount_info_by_fuse_sync (const char *fuse_path,
|
||||
+ char **mount_path)
|
||||
+{
|
||||
+ GMountInfo *info;
|
||||
+ DBusConnection *conn;
|
||||
+ DBusMessage *message, *reply;
|
||||
+ DBusMessageIter iter;
|
||||
+ DBusError derror;
|
||||
+ int len;
|
||||
+
|
||||
+ info = lookup_mount_info_by_fuse_path_in_cache (fuse_path,
|
||||
+ mount_path);
|
||||
+ if (info != NULL)
|
||||
+ return info;
|
||||
+
|
||||
+ conn = _g_dbus_connection_get_sync (NULL, NULL);
|
||||
+ if (conn == NULL)
|
||||
+ return NULL;
|
||||
+
|
||||
+ message =
|
||||
+ dbus_message_new_method_call (G_VFS_DBUS_DAEMON_NAME,
|
||||
+ G_VFS_DBUS_MOUNTTRACKER_PATH,
|
||||
+ G_VFS_DBUS_MOUNTTRACKER_INTERFACE,
|
||||
+ G_VFS_DBUS_MOUNTTRACKER_OP_LOOKUP_MOUNT_BY_FUSE_PATH);
|
||||
+ dbus_message_set_auto_start (message, TRUE);
|
||||
+
|
||||
+ dbus_message_iter_init_append (message, &iter);
|
||||
+ _g_dbus_message_iter_append_cstring (&iter, fuse_path);
|
||||
+
|
||||
+ dbus_error_init (&derror);
|
||||
+ reply = dbus_connection_send_with_reply_and_block (conn, message, -1, &derror);
|
||||
+ dbus_message_unref (message);
|
||||
+ if (!reply)
|
||||
+ {
|
||||
+ dbus_error_free (&derror);
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
+ info = handler_lookup_mount_reply (reply, NULL);
|
||||
+ dbus_message_unref (reply);
|
||||
+
|
||||
+ if (info)
|
||||
+ {
|
||||
+ if (info->fuse_mountpoint)
|
||||
+ {
|
||||
+ len = strlen (info->fuse_mountpoint);
|
||||
+ if (fuse_path[len] == 0)
|
||||
+ *mount_path = g_strdup ("/");
|
||||
+ else
|
||||
+ *mount_path = g_strdup (fuse_path + len);
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ /* This could happen if we race with the gvfs fuse mount
|
||||
+ * at startup of gvfsd... */
|
||||
+ g_mount_info_unref (info);
|
||||
+ info = NULL;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+ return info;
|
||||
+}
|
||||
+
|
||||
static GFile *
|
||||
g_daemon_vfs_parse_name (GVfs *vfs,
|
||||
const char *parse_name)
|
||||
@@ -917,8 +1053,8 @@
|
||||
if (g_path_is_absolute (parse_name) ||
|
||||
*parse_name == '~')
|
||||
{
|
||||
- /* TODO: detect fuse paths and convert to daemon vfs GFiles ? */
|
||||
file = g_vfs_parse_name (G_DAEMON_VFS (vfs)->wrapped_vfs, parse_name);
|
||||
+ file = convert_fuse_path (vfs, file);
|
||||
}
|
||||
else
|
||||
{
|
||||
--- trunk/daemon/mount.c 2008/08/02 11:00:07 1847
|
||||
+++ trunk/daemon/mount.c 2008/09/26 10:44:37 2031
|
||||
@@ -43,7 +43,8 @@
|
||||
char *icon;
|
||||
char *prefered_filename_encoding;
|
||||
gboolean user_visible;
|
||||
-
|
||||
+ char *fuse_mountpoint; /* Always set, even if fuse not availible */
|
||||
+
|
||||
/* Daemon object ref */
|
||||
char *dbus_id;
|
||||
char *object_path;
|
||||
@@ -100,6 +101,32 @@
|
||||
}
|
||||
|
||||
static VfsMount *
|
||||
+find_vfs_mount_by_fuse_path (const char *fuse_path)
|
||||
+{
|
||||
+ GList *l;
|
||||
+
|
||||
+ if (!fuse_available)
|
||||
+ return NULL;
|
||||
+
|
||||
+ for (l = mounts; l != NULL; l = l->next)
|
||||
+ {
|
||||
+ VfsMount *mount = l->data;
|
||||
+
|
||||
+ if (mount->fuse_mountpoint != NULL &&
|
||||
+ g_str_has_prefix (fuse_path, mount->fuse_mountpoint))
|
||||
+ {
|
||||
+ int len = strlen (mount->fuse_mountpoint);
|
||||
+ if (fuse_path[len] == 0 ||
|
||||
+ fuse_path[len] == '/')
|
||||
+ return mount;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static VfsMount *
|
||||
match_vfs_mount (GMountSpec *match)
|
||||
{
|
||||
GList *l;
|
||||
@@ -160,6 +187,7 @@
|
||||
g_free (mount->stable_name);
|
||||
g_free (mount->x_content_types);
|
||||
g_free (mount->icon);
|
||||
+ g_free (mount->fuse_mountpoint);
|
||||
g_free (mount->prefered_filename_encoding);
|
||||
g_free (mount->dbus_id);
|
||||
g_free (mount->object_path);
|
||||
@@ -223,21 +251,10 @@
|
||||
&user_visible))
|
||||
_g_dbus_oom ();
|
||||
|
||||
-
|
||||
- fuse_mountpoint = NULL;
|
||||
- if (fuse_available && mount->user_visible)
|
||||
- {
|
||||
- char *fs_name;
|
||||
-
|
||||
- /* Keep in sync with fuse daemon */
|
||||
- fs_name = g_uri_escape_string (mount->stable_name, "+@#$., ", TRUE);
|
||||
-
|
||||
- fuse_mountpoint = g_build_filename (g_get_home_dir(), ".gvfs", fs_name, NULL);
|
||||
- }
|
||||
-
|
||||
- if (fuse_mountpoint == NULL)
|
||||
- fuse_mountpoint = g_strdup ("");
|
||||
|
||||
+ fuse_mountpoint = "";
|
||||
+ if (fuse_available && mount->fuse_mountpoint)
|
||||
+ fuse_mountpoint = mount->fuse_mountpoint;
|
||||
_g_dbus_message_iter_append_cstring (&struct_iter, fuse_mountpoint);
|
||||
|
||||
g_mount_spec_to_dbus (&struct_iter, mount->mount_spec);
|
||||
@@ -699,6 +716,16 @@
|
||||
mount->dbus_id = g_strdup (id);
|
||||
mount->object_path = g_strdup (obj_path);
|
||||
mount->mount_spec = mount_spec;
|
||||
+
|
||||
+ if (user_visible)
|
||||
+ {
|
||||
+ char *fs_name;
|
||||
+
|
||||
+ /* Keep in sync with fuse daemon */
|
||||
+ fs_name = g_uri_escape_string (mount->stable_name, "+@#$., ", TRUE);
|
||||
+
|
||||
+ mount->fuse_mountpoint = g_build_filename (g_get_home_dir(), ".gvfs", fs_name, NULL);
|
||||
+ }
|
||||
|
||||
mounts = g_list_prepend (mounts, mount);
|
||||
|
||||
@@ -835,6 +862,48 @@
|
||||
}
|
||||
|
||||
static void
|
||||
+lookup_mount_by_fuse_path (DBusConnection *connection,
|
||||
+ DBusMessage *message)
|
||||
+{
|
||||
+ VfsMount *mount;
|
||||
+ DBusMessage *reply;
|
||||
+ DBusMessageIter iter;
|
||||
+ char *fuse_path;
|
||||
+
|
||||
+ dbus_message_iter_init (message, &iter);
|
||||
+
|
||||
+ reply = NULL;
|
||||
+ if (_g_dbus_message_iter_get_args (&iter, NULL,
|
||||
+ G_DBUS_TYPE_CSTRING, &fuse_path,
|
||||
+ 0))
|
||||
+ {
|
||||
+ mount = find_vfs_mount_by_fuse_path (fuse_path);
|
||||
+
|
||||
+ if (mount == NULL)
|
||||
+ reply = _dbus_message_new_gerror (message,
|
||||
+ G_IO_ERROR,
|
||||
+ G_IO_ERROR_NOT_MOUNTED,
|
||||
+ _("The specified location is not mounted"));
|
||||
+ else
|
||||
+ {
|
||||
+ reply = dbus_message_new_method_return (message);
|
||||
+ if (reply)
|
||||
+ {
|
||||
+ dbus_message_iter_init_append (reply, &iter);
|
||||
+ vfs_mount_to_dbus (mount, &iter);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ else
|
||||
+ reply = dbus_message_new_error (message,
|
||||
+ DBUS_ERROR_INVALID_ARGS,
|
||||
+ "Invalid arguments");
|
||||
+
|
||||
+ if (reply != NULL)
|
||||
+ dbus_connection_send (connection, reply, NULL);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
list_mounts (DBusConnection *connection,
|
||||
DBusMessage *message)
|
||||
{
|
||||
@@ -1084,6 +1153,10 @@
|
||||
lookup_mount (connection, message, TRUE);
|
||||
else if (dbus_message_is_method_call (message,
|
||||
G_VFS_DBUS_MOUNTTRACKER_INTERFACE,
|
||||
+ G_VFS_DBUS_MOUNTTRACKER_OP_LOOKUP_MOUNT_BY_FUSE_PATH))
|
||||
+ lookup_mount_by_fuse_path (connection, message);
|
||||
+ else if (dbus_message_is_method_call (message,
|
||||
+ G_VFS_DBUS_MOUNTTRACKER_INTERFACE,
|
||||
G_VFS_DBUS_MOUNTTRACKER_OP_LIST_MOUNTS))
|
||||
list_mounts (connection, message);
|
||||
else if (dbus_message_is_method_call (message,
|
@ -1,453 +0,0 @@
|
||||
Index: daemon/obexftp-marshal.list
|
||||
===================================================================
|
||||
--- daemon/obexftp-marshal.list (revision 2022)
|
||||
+++ daemon/obexftp-marshal.list (working copy)
|
||||
@@ -1,2 +1,4 @@
|
||||
+VOID:STRING
|
||||
VOID:STRING,STRING
|
||||
+VOID:STRING,STRING,STRING
|
||||
VOID:STRING,STRING,UINT64
|
||||
Index: daemon/gvfsbackendobexftp.c
|
||||
===================================================================
|
||||
--- daemon/gvfsbackendobexftp.c (revision 2022)
|
||||
+++ daemon/gvfsbackendobexftp.c (working copy)
|
||||
@@ -69,7 +69,7 @@
|
||||
|
||||
char *display_name;
|
||||
char *bdaddr;
|
||||
- guint type;
|
||||
+ char *icon_name;
|
||||
|
||||
DBusGConnection *connection;
|
||||
DBusGProxy *manager_proxy;
|
||||
@@ -96,177 +96,106 @@
|
||||
|
||||
G_DEFINE_TYPE (GVfsBackendObexftp, g_vfs_backend_obexftp, G_VFS_TYPE_BACKEND);
|
||||
|
||||
-/* This should all live in bluez-gnome, and we
|
||||
- * should depend on it */
|
||||
-enum {
|
||||
- BLUETOOTH_TYPE_ANY = 1,
|
||||
- BLUETOOTH_TYPE_PHONE = 1 << 1,
|
||||
- BLUETOOTH_TYPE_MODEM = 1 << 2,
|
||||
- BLUETOOTH_TYPE_COMPUTER = 1 << 3,
|
||||
- BLUETOOTH_TYPE_NETWORK = 1 << 4,
|
||||
- BLUETOOTH_TYPE_HEADSET = 1 << 5,
|
||||
- BLUETOOTH_TYPE_KEYBOARD = 1 << 6,
|
||||
- BLUETOOTH_TYPE_MOUSE = 1 << 7,
|
||||
- BLUETOOTH_TYPE_CAMERA = 1 << 8,
|
||||
- BLUETOOTH_TYPE_PRINTER = 1 << 9
|
||||
-};
|
||||
+static void session_connect_error_cb (DBusGProxy *proxy,
|
||||
+ const char *session_object,
|
||||
+ const gchar *error_name,
|
||||
+ const gchar *error_message,
|
||||
+ gpointer user_data);
|
||||
+static void session_connected_cb (DBusGProxy *proxy,
|
||||
+ const char *session_object,
|
||||
+ gpointer user_data);
|
||||
|
||||
-static const char *
|
||||
-_get_icon_from_type (guint type)
|
||||
+/* Used to detect broken listings from
|
||||
+ * old Nokia 3650s */
|
||||
+static gboolean
|
||||
+_is_nokia_3650 (const char *bdaddr)
|
||||
{
|
||||
- switch (type)
|
||||
- {
|
||||
- case BLUETOOTH_TYPE_PHONE:
|
||||
- return "phone";
|
||||
- break;
|
||||
- case BLUETOOTH_TYPE_MODEM:
|
||||
- return "modem";
|
||||
- break;
|
||||
- case BLUETOOTH_TYPE_COMPUTER:
|
||||
- return "network-server";
|
||||
- break;
|
||||
- case BLUETOOTH_TYPE_NETWORK:
|
||||
- return "network-wireless";
|
||||
- break;
|
||||
- case BLUETOOTH_TYPE_HEADSET:
|
||||
- return "stock_headphones";
|
||||
- break;
|
||||
- case BLUETOOTH_TYPE_KEYBOARD:
|
||||
- return "input-keyboard";
|
||||
- break;
|
||||
- case BLUETOOTH_TYPE_MOUSE:
|
||||
- return "input-mouse";
|
||||
- break;
|
||||
- case BLUETOOTH_TYPE_CAMERA:
|
||||
- return "camera-photo";
|
||||
- break;
|
||||
- case BLUETOOTH_TYPE_PRINTER:
|
||||
- return "printer";
|
||||
- break;
|
||||
- default:
|
||||
- return "bluetooth";
|
||||
- break;
|
||||
- }
|
||||
+ /* Don't ask, Nokia seem to use a Bluetooth
|
||||
+ * HCI from Murata */
|
||||
+ return g_str_has_prefix(bdaddr, "00:60:57");
|
||||
}
|
||||
|
||||
-static int
|
||||
-_get_type_from_class (guint class)
|
||||
+static char *
|
||||
+get_name_and_icon (DBusGProxy *device, char **icon_name)
|
||||
{
|
||||
- switch ((class & 0x1f00) >> 8)
|
||||
+ GHashTable *hash;
|
||||
+
|
||||
+ if (dbus_g_proxy_call (device, "GetProperties", NULL,
|
||||
+ G_TYPE_INVALID, dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE),
|
||||
+ &hash, G_TYPE_INVALID) != FALSE)
|
||||
{
|
||||
- case 0x01:
|
||||
- return BLUETOOTH_TYPE_COMPUTER;
|
||||
- case 0x02:
|
||||
- switch ((class & 0xfc) >> 2)
|
||||
+ GValue *value;
|
||||
+ char *name;
|
||||
+
|
||||
+ value = g_hash_table_lookup (hash, "Name");
|
||||
+ name = value ? g_value_dup_string(value) : NULL;
|
||||
+
|
||||
+ value = g_hash_table_lookup (hash, "Icon");
|
||||
+ if (value)
|
||||
{
|
||||
- case 0x01:
|
||||
- case 0x02:
|
||||
- case 0x03:
|
||||
- case 0x05:
|
||||
- return BLUETOOTH_TYPE_PHONE;
|
||||
- case 0x04:
|
||||
- return BLUETOOTH_TYPE_MODEM;
|
||||
+ *icon_name = g_value_dup_string (value);
|
||||
}
|
||||
- break;
|
||||
- case 0x03:
|
||||
- return BLUETOOTH_TYPE_NETWORK;
|
||||
- case 0x04:
|
||||
- switch ((class & 0xfc) >> 2)
|
||||
+ else
|
||||
{
|
||||
- case 0x01:
|
||||
- return BLUETOOTH_TYPE_HEADSET;
|
||||
+ *icon_name = g_strdup ("bluetooth");
|
||||
}
|
||||
- break;
|
||||
- case 0x05:
|
||||
- switch ((class & 0xc0) >> 6)
|
||||
- {
|
||||
- case 0x01:
|
||||
- return BLUETOOTH_TYPE_KEYBOARD;
|
||||
- case 0x02:
|
||||
- return BLUETOOTH_TYPE_MOUSE;
|
||||
- }
|
||||
- break;
|
||||
- case 0x06:
|
||||
- if (class & 0x80)
|
||||
- return BLUETOOTH_TYPE_PRINTER;
|
||||
- if (class & 0x20)
|
||||
- return BLUETOOTH_TYPE_CAMERA;
|
||||
- break;
|
||||
+ g_hash_table_destroy (hash);
|
||||
+ return name;
|
||||
}
|
||||
|
||||
- return BLUETOOTH_TYPE_ANY;
|
||||
+ return NULL;
|
||||
}
|
||||
|
||||
-/* Used to detect broken listings from
|
||||
- * old Nokia 3650s */
|
||||
-static gboolean
|
||||
-_is_nokia_3650 (const char *bdaddr)
|
||||
-{
|
||||
- /* Don't ask, Nokia seem to use a Bluetooth
|
||||
- * HCI from Murata */
|
||||
- return g_str_has_prefix(bdaddr, "00:60:57");
|
||||
-}
|
||||
-
|
||||
static gchar *
|
||||
-_get_device_properties (const char *bdaddr, guint32 *type)
|
||||
+_get_device_properties (const char *bdaddr, char **icon_name)
|
||||
{
|
||||
DBusGConnection *connection;
|
||||
DBusGProxy *manager;
|
||||
- gchar *name, **adapters;
|
||||
+ GPtrArray *adapters;
|
||||
+ gchar *name;
|
||||
guint i;
|
||||
|
||||
name = NULL;
|
||||
|
||||
connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, NULL);
|
||||
if (connection == NULL)
|
||||
- return NULL;
|
||||
+ return name;
|
||||
|
||||
manager = dbus_g_proxy_new_for_name (connection, "org.bluez",
|
||||
- "/org/bluez", "org.bluez.Manager");
|
||||
+ "/", "org.bluez.Manager");
|
||||
if (manager == NULL)
|
||||
{
|
||||
dbus_g_connection_unref (connection);
|
||||
- return NULL;
|
||||
+ return name;
|
||||
}
|
||||
|
||||
- if (dbus_g_proxy_call (manager, "ListAdapters", NULL, G_TYPE_INVALID, G_TYPE_STRV, &adapters, G_TYPE_INVALID) == FALSE)
|
||||
+ if (dbus_g_proxy_call (manager, "ListAdapters", NULL, G_TYPE_INVALID, dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH), &adapters, G_TYPE_INVALID) == FALSE)
|
||||
{
|
||||
g_object_unref (manager);
|
||||
dbus_g_connection_unref (connection);
|
||||
- return NULL;
|
||||
+ return name;
|
||||
}
|
||||
|
||||
- for (i = 0; adapters[i] != NULL; i++)
|
||||
+ for (i = 0; i < adapters->len && name == NULL; i++)
|
||||
{
|
||||
DBusGProxy *adapter;
|
||||
+ char *device_path;
|
||||
|
||||
adapter = dbus_g_proxy_new_for_name (connection, "org.bluez",
|
||||
- adapters[i], "org.bluez.Adapter");
|
||||
- if (dbus_g_proxy_call (adapter, "GetRemoteName", NULL,
|
||||
+ g_ptr_array_index (adapters, i), "org.bluez.Adapter");
|
||||
+ if (dbus_g_proxy_call (adapter, "FindDevice", NULL,
|
||||
G_TYPE_STRING, bdaddr, G_TYPE_INVALID,
|
||||
- G_TYPE_STRING, &name, G_TYPE_INVALID) != FALSE)
|
||||
+ DBUS_TYPE_G_OBJECT_PATH, &device_path, G_TYPE_INVALID) != FALSE)
|
||||
{
|
||||
- if (name != NULL && name[0] != '\0')
|
||||
- {
|
||||
- guint32 class;
|
||||
-
|
||||
- if (dbus_g_proxy_call(adapter, "GetRemoteClass", NULL,
|
||||
- G_TYPE_STRING, bdaddr, G_TYPE_INVALID,
|
||||
- G_TYPE_UINT, &class, G_TYPE_INVALID) != FALSE)
|
||||
- {
|
||||
- *type = _get_type_from_class (class);
|
||||
- }
|
||||
- else
|
||||
- {
|
||||
- *type = BLUETOOTH_TYPE_ANY;
|
||||
- }
|
||||
- g_object_unref (adapter);
|
||||
- break;
|
||||
- }
|
||||
+ DBusGProxy *device;
|
||||
+ device = dbus_g_proxy_new_for_name (connection, "org.bluez", device_path, "org.bluez.Device");
|
||||
+ name = get_name_and_icon (device, icon_name);
|
||||
+ g_object_unref (device);
|
||||
}
|
||||
g_object_unref (adapter);
|
||||
}
|
||||
|
||||
+ g_ptr_array_free (adapters, TRUE);
|
||||
g_object_unref (manager);
|
||||
dbus_g_connection_unref (connection);
|
||||
|
||||
@@ -282,6 +211,7 @@
|
||||
|
||||
g_free (backend->display_name);
|
||||
g_free (backend->bdaddr);
|
||||
+ g_free (backend->icon_name);
|
||||
g_free (backend->files_listing);
|
||||
g_free (backend->directory);
|
||||
|
||||
@@ -312,6 +242,15 @@
|
||||
"org.openobex",
|
||||
"/org/openobex",
|
||||
"org.openobex.Manager");
|
||||
+
|
||||
+ dbus_g_proxy_add_signal(backend->manager_proxy, "SessionConnectError",
|
||||
+ DBUS_TYPE_G_OBJECT_PATH, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID);
|
||||
+ dbus_g_proxy_connect_signal(backend->manager_proxy, "SessionConnectError",
|
||||
+ G_CALLBACK(session_connect_error_cb), backend, NULL);
|
||||
+ dbus_g_proxy_add_signal(backend->manager_proxy, "SessionConnected",
|
||||
+ DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID);
|
||||
+ dbus_g_proxy_connect_signal(backend->manager_proxy, "SessionConnected",
|
||||
+ G_CALLBACK(session_connected_cb), backend, NULL);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -437,8 +376,7 @@
|
||||
g_file_info_set_file_type (info, G_FILE_TYPE_DIRECTORY);
|
||||
g_file_info_set_content_type (info, "inode/directory");
|
||||
g_file_info_set_name (info, "/");
|
||||
- g_vfs_backend_set_icon_name (backend,
|
||||
- _get_icon_from_type (op_backend->type));
|
||||
+ g_vfs_backend_set_icon_name (backend, op_backend->icon_name);
|
||||
display = g_strdup_printf (_("%s on %s"), "/", op_backend->display_name);
|
||||
g_file_info_set_display_name (info, display);
|
||||
g_free (display);
|
||||
@@ -531,6 +469,37 @@
|
||||
}
|
||||
|
||||
static void
|
||||
+session_connect_error_cb (DBusGProxy *proxy,
|
||||
+ const char *session_object,
|
||||
+ const gchar *error_name,
|
||||
+ const gchar *error_message,
|
||||
+ gpointer user_data)
|
||||
+{
|
||||
+ GVfsBackendObexftp *op_backend = G_VFS_BACKEND_OBEXFTP (user_data);
|
||||
+
|
||||
+ g_mutex_lock (op_backend->mutex);
|
||||
+ op_backend->status = ASYNC_ERROR;
|
||||
+ op_backend->error = g_error_new_literal (DBUS_GERROR,
|
||||
+ DBUS_GERROR_REMOTE_EXCEPTION,
|
||||
+ error_message);
|
||||
+ g_cond_signal (op_backend->cond);
|
||||
+ g_mutex_unlock (op_backend->mutex);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+session_connected_cb (DBusGProxy *proxy,
|
||||
+ const char *session_object,
|
||||
+ gpointer user_data)
|
||||
+{
|
||||
+ GVfsBackendObexftp *op_backend = G_VFS_BACKEND_OBEXFTP (user_data);
|
||||
+
|
||||
+ g_mutex_lock (op_backend->mutex);
|
||||
+ op_backend->status = ASYNC_SUCCESS;
|
||||
+ g_cond_signal (op_backend->cond);
|
||||
+ g_mutex_unlock (op_backend->mutex);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
cancelled_cb (DBusGProxy *proxy, gpointer user_data)
|
||||
{
|
||||
GVfsBackendObexftp *op_backend = G_VFS_BACKEND_OBEXFTP (user_data);
|
||||
@@ -559,24 +528,6 @@
|
||||
_exit (1);
|
||||
}
|
||||
|
||||
-static int
|
||||
-is_connected (DBusGProxy *session_proxy, GVfsJob *job)
|
||||
-{
|
||||
- GError *error = NULL;
|
||||
- gboolean connected;
|
||||
-
|
||||
- if (dbus_g_proxy_call (session_proxy, "IsConnected", &error,
|
||||
- G_TYPE_INVALID,
|
||||
- G_TYPE_BOOLEAN, &connected, G_TYPE_INVALID) == FALSE)
|
||||
- {
|
||||
- g_vfs_job_failed_from_error (job, error);
|
||||
- g_error_free (error);
|
||||
- return -1;
|
||||
- }
|
||||
-
|
||||
- return connected;
|
||||
-}
|
||||
-
|
||||
static void
|
||||
do_mount (GVfsBackend *backend,
|
||||
GVfsJobMount *job,
|
||||
@@ -590,7 +541,7 @@
|
||||
const gchar *path = NULL;
|
||||
char *server;
|
||||
GMountSpec *obexftp_mount_spec;
|
||||
- gboolean connected;
|
||||
+ guint count;
|
||||
|
||||
g_print ("+ do_mount\n");
|
||||
|
||||
@@ -616,10 +567,11 @@
|
||||
}
|
||||
|
||||
/* FIXME, Have a way for the mount to be cancelled, see:
|
||||
- * http://bugs.muiline.com/view.php?id=51 */
|
||||
+ * Use CancelSessionConnect */
|
||||
+ op_backend->status = ASYNC_PENDING;
|
||||
|
||||
if (dbus_g_proxy_call (op_backend->manager_proxy, "CreateBluetoothSession", &error,
|
||||
- G_TYPE_STRING, op_backend->bdaddr, G_TYPE_STRING, "ftp", G_TYPE_INVALID,
|
||||
+ G_TYPE_STRING, op_backend->bdaddr, G_TYPE_STRING, "00:00:00:00:00:00", G_TYPE_STRING, "ftp", G_TYPE_INVALID,
|
||||
DBUS_TYPE_G_OBJECT_PATH, &path, G_TYPE_INVALID) == FALSE)
|
||||
{
|
||||
g_free (op_backend->bdaddr);
|
||||
@@ -636,14 +588,13 @@
|
||||
path,
|
||||
"org.openobex.Session");
|
||||
|
||||
- op_backend->display_name = _get_device_properties (op_backend->bdaddr, &op_backend->type);
|
||||
+ op_backend->display_name = _get_device_properties (op_backend->bdaddr, &op_backend->icon_name);
|
||||
if (!op_backend->display_name)
|
||||
op_backend->display_name = g_strdup (op_backend->bdaddr);
|
||||
|
||||
g_vfs_backend_set_display_name (G_VFS_BACKEND (op_backend),
|
||||
op_backend->display_name);
|
||||
- g_vfs_backend_set_icon_name (G_VFS_BACKEND (op_backend),
|
||||
- _get_icon_from_type (op_backend->type));
|
||||
+ g_vfs_backend_set_icon_name (G_VFS_BACKEND (op_backend), op_backend->icon_name);
|
||||
|
||||
obexftp_mount_spec = g_mount_spec_new ("obex");
|
||||
server = g_strdup_printf ("[%s]", op_backend->bdaddr);
|
||||
@@ -676,14 +627,20 @@
|
||||
G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT64, G_TYPE_INVALID);
|
||||
|
||||
/* Now wait until the device is connected */
|
||||
- connected = is_connected (op_backend->session_proxy, G_VFS_JOB (job));
|
||||
- while (connected == FALSE)
|
||||
- {
|
||||
- g_usleep (G_USEC_PER_SEC / 100);
|
||||
- connected = is_connected (op_backend->session_proxy, G_VFS_JOB (job));
|
||||
- }
|
||||
+ count = 0;
|
||||
+ g_mutex_lock (op_backend->mutex);
|
||||
|
||||
- if (connected < 0)
|
||||
+ while (op_backend->status == ASYNC_PENDING && count < 100) {
|
||||
+ GTimeVal val;
|
||||
+ g_get_current_time (&val);
|
||||
+ g_time_val_add (&val, 100000);
|
||||
+ count++;
|
||||
+ if (g_cond_timed_wait (op_backend->cond, op_backend->mutex, &val) != FALSE)
|
||||
+ break;
|
||||
+ }
|
||||
+ g_mutex_unlock (op_backend->mutex);
|
||||
+
|
||||
+ if (op_backend->status == ASYNC_ERROR || op_backend->status == ASYNC_PENDING)
|
||||
{
|
||||
g_message ("mount failed, didn't connect");
|
||||
|
||||
@@ -694,12 +651,17 @@
|
||||
g_object_unref (op_backend->session_proxy);
|
||||
op_backend->session_proxy = NULL;
|
||||
|
||||
- g_vfs_job_failed (G_VFS_JOB (job),
|
||||
- G_IO_ERROR, G_IO_ERROR_BUSY,
|
||||
- _("Connection to the device lost"));
|
||||
+ if (op_backend->status != ASYNC_PENDING)
|
||||
+ g_vfs_job_failed_from_error (G_VFS_JOB (job), op_backend->error);
|
||||
+ else
|
||||
+ g_vfs_job_failed (G_VFS_JOB (job),
|
||||
+ G_IO_ERROR, G_IO_ERROR_BUSY,
|
||||
+ _("Connection to the device lost"));
|
||||
return;
|
||||
}
|
||||
|
||||
+ op_backend->status = ASYNC_PENDING;
|
||||
+
|
||||
g_vfs_job_succeeded (G_VFS_JOB (job));
|
||||
|
||||
g_print ("- do_mount\n");
|
||||
@@ -1482,6 +1444,12 @@
|
||||
/* TransferStarted */
|
||||
dbus_g_object_register_marshaller(obexftp_marshal_VOID__STRING_STRING_UINT64,
|
||||
G_TYPE_NONE, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT64, G_TYPE_INVALID);
|
||||
+ /* SessionConnected */
|
||||
+ dbus_g_object_register_marshaller(obexftp_marshal_VOID__STRING,
|
||||
+ G_TYPE_NONE, DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID);
|
||||
+ /* SessionConnectError */
|
||||
+ dbus_g_object_register_marshaller (obexftp_marshal_VOID__STRING_STRING_STRING,
|
||||
+ G_TYPE_NONE, DBUS_TYPE_G_OBJECT_PATH, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID);
|
||||
}
|
||||
|
||||
/*
|
@ -1,146 +0,0 @@
|
||||
Index: daemon/libsmb-compat.h
|
||||
===================================================================
|
||||
--- daemon/libsmb-compat.h (revision 2084)
|
||||
+++ daemon/libsmb-compat.h (working copy)
|
||||
@@ -94,8 +94,16 @@
|
||||
const char *fname,
|
||||
mode_t mode);
|
||||
|
||||
+typedef int (*smbc_chmod_fn)(SMBCCTX *c,
|
||||
+ const char *fname,
|
||||
+ mode_t mode);
|
||||
|
||||
+typedef int (*smbc_utimes_fn)(SMBCCTX *c,
|
||||
+ const char *fname,
|
||||
+ struct timeval *tbuf);
|
||||
|
||||
+
|
||||
+
|
||||
#define smbc_getOptionUserData(ctx) \
|
||||
smbc_option_get (ctx, "user_data")
|
||||
|
||||
@@ -184,6 +192,9 @@
|
||||
|
||||
#define smbc_getFunctionMkdir(ctx) ctx->mkdir
|
||||
|
||||
+#define smbc_getFunctionChmod(ctx) ctx->chmod
|
||||
|
||||
+#define smbc_getFunctionUtimes(ctx) ctx->utimes
|
||||
|
||||
+
|
||||
#endif
|
||||
Index: daemon/gvfsbackendsmb.c
|
||||
===================================================================
|
||||
--- daemon/gvfsbackendsmb.c (revision 2084)
|
||||
+++ daemon/gvfsbackendsmb.c (working copy)
|
||||
@@ -1499,13 +1499,26 @@
|
||||
|
||||
list = g_file_attribute_info_list_new ();
|
||||
|
||||
- /* TODO: Add all settable attributes here */
|
||||
- /*
|
||||
+ /* TODO: Add all settable attributes here -- bug #559586 */
|
||||
+ /* TODO: xattrs support? */
|
||||
+
|
||||
g_file_attribute_info_list_add (list,
|
||||
- "smb:test",
|
||||
- G_FILE_ATTRIBUTE_TYPE_UINT32);
|
||||
- */
|
||||
+ G_FILE_ATTRIBUTE_TIME_MODIFIED,
|
||||
+ G_FILE_ATTRIBUTE_TYPE_UINT64,
|
||||
+ G_FILE_ATTRIBUTE_INFO_COPY_WITH_FILE |
|
||||
+ G_FILE_ATTRIBUTE_INFO_COPY_WHEN_MOVED);
|
||||
|
||||
+#if 0
|
||||
+/* FIXME: disabled; despite setting is supported, it makes no sense on samba shares and
|
||||
+ libsmbclient lacks proper API to return unix mode.
|
||||
+ The struct stat->st_mode member is used for special Windows attributes. */
|
||||
+ g_file_attribute_info_list_add (list,
|
||||
+ G_FILE_ATTRIBUTE_UNIX_MODE,
|
||||
+ G_FILE_ATTRIBUTE_TYPE_UINT32,
|
||||
+ G_FILE_ATTRIBUTE_INFO_COPY_WITH_FILE |
|
||||
+ G_FILE_ATTRIBUTE_INFO_COPY_WHEN_MOVED);
|
||||
+#endif
|
||||
+
|
||||
g_vfs_job_query_attributes_set_list (job, list);
|
||||
g_vfs_job_succeeded (G_VFS_JOB (job));
|
||||
|
||||
@@ -1514,6 +1527,70 @@
|
||||
}
|
||||
|
||||
static void
|
||||
+do_set_attribute (GVfsBackend *backend,
|
||||
+ GVfsJobSetAttribute *job,
|
||||
+ const char *filename,
|
||||
+ const char *attribute,
|
||||
+ GFileAttributeType type,
|
||||
+ gpointer value_p,
|
||||
+ GFileQueryInfoFlags flags)
|
||||
+{
|
||||
+ GVfsBackendSmb *op_backend;
|
||||
+ char *uri;
|
||||
+ int res, errsv;
|
||||
+ struct timeval tbuf[2];
|
||||
+ smbc_utimes_fn smbc_utimes;
|
||||
+#if 0
|
||||
+ smbc_chmod_fn smbc_chmod;
|
||||
+#endif
|
||||
+
|
||||
+
|
||||
+ op_backend = G_VFS_BACKEND_SMB (backend);
|
||||
+
|
||||
+ if (strcmp (attribute, G_FILE_ATTRIBUTE_TIME_MODIFIED) != 0
|
||||
+#if 0
|
||||
+ && strcmp (attribute, G_FILE_ATTRIBUTE_UNIX_MODE) != 0
|
||||
+#endif
|
||||
+ )
|
||||
+ {
|
||||
+ g_vfs_job_failed (G_VFS_JOB (job),
|
||||
+ G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
|
||||
+ _("Operation unsupported"));
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ uri = create_smb_uri (op_backend->server, op_backend->share, filename);
|
||||
+ res = -1;
|
||||
+
|
||||
+ if (strcmp (attribute, G_FILE_ATTRIBUTE_TIME_MODIFIED) == 0)
|
||||
+ {
|
||||
+ smbc_utimes = smbc_getFunctionUtimes (op_backend->smb_context);
|
||||
+ tbuf[1].tv_sec = (*(guint64 *)value_p); /* mtime */
|
||||
+ tbuf[1].tv_usec = 0;
|
||||
+ /* atime = mtime (atimes are usually disabled on desktop systems) */
|
||||
+ tbuf[0].tv_sec = tbuf[1].tv_sec;
|
||||
+ tbuf[0].tv_usec = 0;
|
||||
+ res = smbc_utimes (op_backend->smb_context, uri, &tbuf[0]);
|
||||
+ }
|
||||
+#if 0
|
||||
+ else
|
||||
+ if (strcmp (attribute, G_FILE_ATTRIBUTE_UNIX_MODE) == 0)
|
||||
+ {
|
||||
+ smbc_chmod = smbc_getFunctionChmod (op_backend->smb_context);
|
||||
+ res = smbc_chmod (op_backend->smb_context, uri, (*(guint32 *)value_p) & 0777);
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
+ errsv = errno;
|
||||
+ g_free (uri);
|
||||
+
|
||||
+ if (res != 0)
|
||||
+ g_vfs_job_failed_from_errno (G_VFS_JOB (job), errsv);
|
||||
+ else
|
||||
+ g_vfs_job_succeeded (G_VFS_JOB (job));
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
do_enumerate (GVfsBackend *backend,
|
||||
GVfsJobEnumerate *job,
|
||||
const char *filename,
|
||||
@@ -1914,6 +1991,7 @@
|
||||
backend_class->make_directory = do_make_directory;
|
||||
backend_class->move = do_move;
|
||||
backend_class->try_query_settable_attributes = try_query_settable_attributes;
|
||||
+ backend_class->set_attribute = do_set_attribute;
|
||||
|
||||
#ifdef HAVE_GCONF
|
||||
gclient = gconf_client_get_default ();
|
17
gvfs.spec
17
gvfs.spec
@ -1,6 +1,6 @@
|
||||
Summary: Backends for the gio framework in GLib
|
||||
Name: gvfs
|
||||
Version: 1.0.3
|
||||
Version: 1.1.1
|
||||
Release: 1%{?dist}
|
||||
License: LGPLv2+
|
||||
Group: System Environment/Libraries
|
||||
@ -8,7 +8,7 @@ URL: http://www.gtk.org
|
||||
Source: http://download.gnome.org/sources/gvfs/1.0/gvfs-%{version}.tar.bz2
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
|
||||
BuildRequires: pkgconfig
|
||||
BuildRequires: glib2-devel >= 2.19.1-2
|
||||
BuildRequires: glib2-devel >= 2.19.2
|
||||
BuildRequires: dbus-glib-devel
|
||||
BuildRequires: /usr/bin/ssh
|
||||
BuildRequires: libcdio-devel >= 0.78.2
|
||||
@ -30,13 +30,6 @@ BuildRequires: automake autoconf
|
||||
BuildRequires: libtool
|
||||
Patch1: gvfs-0.99.2-archive-integration.patch
|
||||
|
||||
Patch2: gvfs-obexftp-updated-apis-3.patch
|
||||
|
||||
# http://bugzilla.gnome.org/show_bug.cgi?id=530654
|
||||
Patch4: gvfs-1.1.1-reverse-map-fuse-paths.patch
|
||||
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=461505
|
||||
Patch7: gvfs-smb-timestamp-support-2.patch
|
||||
|
||||
%description
|
||||
The gvfs package provides backend implementations for the gio
|
||||
@ -119,9 +112,6 @@ media players (Media Transfer Protocol) to applications using gvfs.
|
||||
%prep
|
||||
%setup -q
|
||||
%patch1 -p0 -b .archive-integration
|
||||
%patch2 -p0 -b .bluez-ods
|
||||
%patch4 -p1 -b .reverse-map-fuse-paths.patch
|
||||
%patch7 -p0 -b .smb-timestamps
|
||||
|
||||
%build
|
||||
|
||||
@ -259,6 +249,9 @@ update-desktop-database &> /dev/null ||:
|
||||
|
||||
|
||||
%changelog
|
||||
* Tue Dec 2 2008 Tomas Bzatek <tbzatek@redhat.com> - 1.1.1-1
|
||||
- Update to 1.1.1
|
||||
|
||||
* Mon Dec 1 2008 Tomas Bzatek <tbzatek@redhat.com> - 1.0.3-1
|
||||
- Update to 1.0.3
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user