From e16911e38022d67e96a5527774388d37595b8e08 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Fri, 4 May 2012 19:08:59 +0100 Subject: [PATCH] TpChannelFilter: add This is the object-oriented/GVariant-flavoured version of GHashTable-based filtering. Also use it in code examples, for much simplification. --- docs/reference/telepathy-glib-sections.txt | 40 ++ examples/client/approver.c | 32 +- examples/client/dbus-tubes/accepter.c | 19 +- examples/client/media-observer.c | 8 +- examples/client/python/ft-handler.py | 11 +- examples/client/python/text-handler.py | 9 +- examples/client/stream-tubes/accepter.c | 19 +- examples/client/text-handler.c | 13 +- telepathy-glib/Makefile.am | 3 + telepathy-glib/base-client.c | 174 +++++++++ telepathy-glib/base-client.h | 21 ++ telepathy-glib/channel-filter-internal.h | 33 ++ telepathy-glib/channel-filter.c | 560 ++++++++++++++++++++++++++++ telepathy-glib/channel-filter.h | 105 ++++++ telepathy-glib/file-transfer-channel.c | 14 +- telepathy-glib/introspection.am | 1 + telepathy-glib/simple-approver.c | 6 +- telepathy-glib/simple-handler.c | 6 +- telepathy-glib/simple-observer.c | 6 +- telepathy-glib/telepathy-glib.h | 1 + tests/Makefile.am | 8 + tests/channel-filter.c | 212 +++++++++++ tests/dbus/base-client.c | 77 ++-- 23 files changed, 1232 insertions(+), 146 deletions(-) create mode 100644 telepathy-glib/channel-filter-internal.h create mode 100644 telepathy-glib/channel-filter.c create mode 100644 telepathy-glib/channel-filter.h create mode 100644 tests/channel-filter.c diff --git a/docs/reference/telepathy-glib-sections.txt b/docs/reference/telepathy-glib-sections.txt index ca2a4ec..887c765 100644 --- a/docs/reference/telepathy-glib-sections.txt +++ b/docs/reference/telepathy-glib-sections.txt @@ -5629,12 +5629,16 @@ TpDebugSenderPrivate base-client TpBaseClient TpBaseClientClass +tp_base_client_add_observer_filter_object +tp_base_client_take_observer_filter_object tp_base_client_add_observer_filter tp_base_client_take_observer_filter tp_base_client_set_observer_recover tp_base_client_set_observer_delay_approvers TpBaseClientClassObserveChannelsImpl tp_base_client_implement_observe_channels +tp_base_client_add_approver_filter_object +tp_base_client_take_approver_filter_object tp_base_client_add_approver_filter tp_base_client_take_approver_filter TpBaseClientClassAddDispatchOperationImpl @@ -5642,6 +5646,8 @@ tp_base_client_implement_add_dispatch_operation tp_base_client_add_handler_capabilities tp_base_client_add_handler_capabilities_varargs tp_base_client_add_handler_capability +tp_base_client_add_handler_filter_object +tp_base_client_take_handler_filter_object tp_base_client_add_handler_filter tp_base_client_take_handler_filter tp_base_client_be_a_handler @@ -7323,3 +7329,37 @@ tp_room_info_get_type TpRoomInfoPriv + +
+channel-filter +channel-filter +telepathy-glib/telepathy-glib.h +TpChannelFilter +tp_channel_filter_new +tp_channel_filter_new_for_calls +tp_channel_filter_new_for_dbus_tubes +tp_channel_filter_new_for_file_transfers +tp_channel_filter_new_for_stream_tubes +tp_channel_filter_new_for_text_chatrooms +tp_channel_filter_new_for_text_chats + +tp_channel_filter_require_channel_type +tp_channel_filter_require_locally_requested + +tp_channel_filter_require_no_target +tp_channel_filter_require_target_is_contact +tp_channel_filter_require_target_is_room +tp_channel_filter_require_target_type + +tp_channel_filter_require_property + +tp_channel_filter_get_type +TpChannelFilterClass +TpChannelFilterPrivate +TP_CHANNEL_FILTER +TP_CHANNEL_FILTER_CLASS +TP_CHANNEL_FILTER_GET_CLASS +TP_IS_CHANNEL_FILTER +TP_IS_CHANNEL_FILTER_CLASS +TP_TYPE_CHANNEL_FILTER +
diff --git a/examples/client/approver.c b/examples/client/approver.c index cbe4801..1eafbf9 100644 --- a/examples/client/approver.c +++ b/examples/client/approver.c @@ -153,36 +153,20 @@ main (int argc, FALSE, add_dispatch_operation_cb, NULL, NULL); /* contact text chat */ - tp_base_client_take_approver_filter (approver, tp_asv_new ( - TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, - TP_IFACE_CHANNEL_TYPE_TEXT, - TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, - TP_HANDLE_TYPE_CONTACT, - NULL)); + tp_base_client_take_approver_filter_object (approver, + tp_channel_filter_new_for_text_chats ()); /* call */ - tp_base_client_take_approver_filter (approver, tp_asv_new ( - TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, - TP_IFACE_CHANNEL_TYPE_CALL, - TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, - TP_HANDLE_TYPE_CONTACT, - NULL)); + tp_base_client_take_approver_filter_object (approver, + tp_channel_filter_new_for_calls (TP_HANDLE_TYPE_CONTACT)); /* room text chat */ - tp_base_client_take_approver_filter (approver, tp_asv_new ( - TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, - TP_IFACE_CHANNEL_TYPE_TEXT, - TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, - TP_HANDLE_TYPE_ROOM, - NULL)); + tp_base_client_take_approver_filter_object (approver, + tp_channel_filter_new_for_text_chatrooms ()); /* file transfer */ - tp_base_client_take_approver_filter (approver, tp_asv_new ( - TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, - TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER, - TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, - TP_HANDLE_TYPE_CONTACT, - NULL)); + tp_base_client_take_approver_filter_object (approver, + tp_channel_filter_new_for_file_transfers (NULL)); if (!tp_base_client_register (approver, &error)) { diff --git a/examples/client/dbus-tubes/accepter.c b/examples/client/dbus-tubes/accepter.c index e9c3835..163d63c 100644 --- a/examples/client/dbus-tubes/accepter.c +++ b/examples/client/dbus-tubes/accepter.c @@ -181,6 +181,7 @@ main (int argc, { TpAccountManager *manager; TpBaseClient *handler; + TpChannelFilter *filter; GError *error = NULL; g_type_init (); @@ -189,20 +190,10 @@ main (int argc, handler = tp_simple_handler_new_with_am (manager, FALSE, FALSE, "ExampleServiceHandler", FALSE, handle_channels, NULL, NULL); - tp_base_client_take_handler_filter (handler, tp_asv_new ( - TP_PROP_CHANNEL_CHANNEL_TYPE, - G_TYPE_STRING, - TP_IFACE_CHANNEL_TYPE_DBUS_TUBE, - - TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, - G_TYPE_UINT, - TP_HANDLE_TYPE_CONTACT, - - TP_PROP_CHANNEL_TYPE_DBUS_TUBE_SERVICE_NAME, - G_TYPE_STRING, - EXAMPLE_SERVICE_NAME, - - NULL)); + filter = tp_channel_filter_new_for_dbus_tubes (EXAMPLE_SERVICE_NAME); + tp_channel_filter_require_locally_requested (filter, FALSE); + tp_channel_filter_require_target_is_contact (filter); + tp_base_client_take_handler_filter_object (handler, filter); tp_base_client_register (handler, &error); g_assert_no_error (error); diff --git a/examples/client/media-observer.c b/examples/client/media-observer.c index 3c2ebe8..f2b86c2 100644 --- a/examples/client/media-observer.c +++ b/examples/client/media-observer.c @@ -85,12 +85,8 @@ main (int argc, observer = tp_simple_observer_new_with_am (manager, FALSE, "ExampleMediaObserver", FALSE, observe_channels_cb, NULL, NULL); - tp_base_client_take_observer_filter (observer, tp_asv_new ( - TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, - TP_IFACE_CHANNEL_TYPE_CALL, - TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, - TP_HANDLE_TYPE_CONTACT, - NULL)); + tp_base_client_take_observer_filter_object (observer, + tp_channel_filter_new_for_calls (TP_HANDLE_TYPE_CONTACT)); if (!tp_base_client_register (observer, &error)) { diff --git a/examples/client/python/ft-handler.py b/examples/client/python/ft-handler.py index 2e042f7..e43842d 100644 --- a/examples/client/python/ft-handler.py +++ b/examples/client/python/ft-handler.py @@ -52,13 +52,10 @@ if __name__ == '__main__': handler = TelepathyGLib.SimpleHandler.new(dbus, False, False, 'ExampleFTHandler', False, handle_channels_cb, filename) - handler.add_handler_filter({ - TelepathyGLib.PROP_CHANNEL_CHANNEL_TYPE: - TelepathyGLib.IFACE_CHANNEL_TYPE_FILE_TRANSFER, - TelepathyGLib.PROP_CHANNEL_TARGET_HANDLE_TYPE: - int(TelepathyGLib.HandleType.CONTACT), - TelepathyGLib.PROP_CHANNEL_REQUESTED: False - }) + channel_filter = TelepathyGLib.ChannelFilter.new_for_file_transfers() + channel_filter.require_locally_requested(FALSE) + channel_filter.require_target_is_contact() + handler.add_handler_filter_object(channel_filter) handler.register() diff --git a/examples/client/python/text-handler.py b/examples/client/python/text-handler.py index 352d819..62b0dfa 100755 --- a/examples/client/python/text-handler.py +++ b/examples/client/python/text-handler.py @@ -55,12 +55,9 @@ if __name__ == '__main__': handler = TelepathyGLib.SimpleHandler.new(dbus, False, False, 'ExampleHandler', False, handle_channels_cb, None) - handler.add_handler_filter({ - TelepathyGLib.PROP_CHANNEL_CHANNEL_TYPE: TelepathyGLib.IFACE_CHANNEL_TYPE_TEXT, - # bgo #637466 - TelepathyGLib.PROP_CHANNEL_TARGET_HANDLE_TYPE: int(TelepathyGLib.HandleType.CONTACT), - TelepathyGLib.PROP_CHANNEL_REQUESTED: False, - }) + channel_filter = TelepathyGLib.ChannelFilter.new_for_text_chats() + channel_filter.require_locally_requested(FALSE) + handler.add_handler_filter_object(channel_filter) handler.register() diff --git a/examples/client/stream-tubes/accepter.c b/examples/client/stream-tubes/accepter.c index 79e8eff..7c7055c 100644 --- a/examples/client/stream-tubes/accepter.c +++ b/examples/client/stream-tubes/accepter.c @@ -142,6 +142,7 @@ main (int argc, { TpAccountManager *manager; TpBaseClient *handler; + TpChannelFilter *filter; GError *error = NULL; g_type_init (); @@ -150,20 +151,10 @@ main (int argc, handler = tp_simple_handler_new_with_am (manager, FALSE, FALSE, "ExampleServiceHandler", FALSE, _handle_channels, NULL, NULL); - tp_base_client_take_handler_filter (handler, tp_asv_new ( - TP_PROP_CHANNEL_CHANNEL_TYPE, - G_TYPE_STRING, - TP_IFACE_CHANNEL_TYPE_STREAM_TUBE, - - TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, - G_TYPE_UINT, - TP_HANDLE_TYPE_CONTACT, - - TP_PROP_CHANNEL_TYPE_STREAM_TUBE_SERVICE, - G_TYPE_STRING, - "ExampleService", - - NULL)); + filter = tp_channel_filter_new_for_stream_tubes ("ExampleService"); + tp_channel_filter_require_locally_requested (filter, FALSE); + tp_channel_filter_require_target_is_contact (filter); + tp_base_client_take_handler_filter_object (handler, filter); tp_base_client_register (handler, &error); g_assert_no_error (error); diff --git a/examples/client/text-handler.c b/examples/client/text-handler.c index d2c0aa2..be230ce 100644 --- a/examples/client/text-handler.c +++ b/examples/client/text-handler.c @@ -123,6 +123,7 @@ main (int argc, TpAccountManager *manager; GError *error = NULL; TpBaseClient *handler; + TpChannelFilter *filter; g_type_init (); tp_debug_set_flags (g_getenv ("EXAMPLE_DEBUG")); @@ -131,13 +132,11 @@ main (int argc, handler = tp_simple_handler_new_with_am (manager, FALSE, FALSE, "ExampleHandler", FALSE, handle_channels_cb, NULL, NULL); - tp_base_client_take_handler_filter (handler, tp_asv_new ( - TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, - TP_IFACE_CHANNEL_TYPE_TEXT, - TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, - TP_HANDLE_TYPE_CONTACT, - TP_PROP_CHANNEL_REQUESTED, G_TYPE_BOOLEAN, FALSE, - NULL)); + /* be a handler for 1-1 text chats which are initiated by the other + * contact */ + filter = tp_channel_filter_new_for_text_chats (); + tp_channel_filter_require_locally_requested (filter, FALSE); + tp_base_client_take_handler_filter_object (handler, filter); if (!tp_base_client_register (handler, &error)) { diff --git a/telepathy-glib/Makefile.am b/telepathy-glib/Makefile.am index 30efdb6..1091e2a 100644 --- a/telepathy-glib/Makefile.am +++ b/telepathy-glib/Makefile.am @@ -54,6 +54,7 @@ our_headers = \ channel-dispatcher.h \ channel-dispatch-operation.h \ channel-factory-iface.h \ + channel-filter.h \ channel-manager.h \ channel-request.h \ client.h \ @@ -205,6 +206,8 @@ libtelepathy_glib_internal_la_SOURCES = \ call-stream-endpoint.c \ channel.c \ channel-contacts.c \ + channel-filter.c \ + channel-filter-internal.h \ channel-group.c \ channel-internal.h \ channel-dispatcher.c \ diff --git a/telepathy-glib/base-client.c b/telepathy-glib/base-client.c index 0704e2e..2efcbbc 100644 --- a/telepathy-glib/base-client.c +++ b/telepathy-glib/base-client.c @@ -188,6 +188,7 @@ #include #include #include +#include #include #include #include @@ -372,6 +373,75 @@ tp_base_client_add_observer_filter (TpBaseClient *self, } /** + * tp_base_client_add_observer_filter_object: + * @self: a #TpBaseClient + * @filter: a filter + * + * Register a new filter to match channels as an Observer. + * + * The #TpBaseClientClass.observe_channels virtual method will be called + * whenever a new channel's properties match the ones in @filter. + * + * This method can be called more than once. If it is, the client will + * be an Observer for any channel that matches any of the filters. + * For instance, this Client: + * + * |[ + * filter = tp_channel_filter_new (); + * tp_channel_filter_require_type_is_text (filter); + * tp_base_client_add_observer_filter_object (client, filter); + * g_object_unref (filter); + * + * filter = tp_channel_filter_new (); + * tp_channel_filter_require_target_is_contact (filter); + * tp_channel_filter_require_type_is_call (filter); + * tp_channel_filter_require_requested (filter, FALSE); + * tp_base_client_add_observer_filter_object (client, filter); + * g_object_unref (filter); + * ]| + * + * will be notified about all Text channels, and also about 1-1 incoming + * Call channels. + * + * This method may only be called before tp_base_client_register() is + * called, and may only be called on objects whose class implements + * #TpBaseClientClass.observe_channels. + * + * Since: 0.UNRELEASED + */ +void +tp_base_client_add_observer_filter_object (TpBaseClient *self, + TpChannelFilter *filter) +{ + g_return_if_fail (TP_IS_CHANNEL_FILTER (filter)); + tp_base_client_add_observer_filter (self, _tp_channel_filter_use (filter)); +} + +/** + * tp_base_client_take_observer_filter_object: (skip) + * @self: a #TpBaseClient + * @filter: (transfer full): a filter + * + * The same as tp_base_client_add_observer_filter_object(), but also + * takes ownership of the filter. This makes it more convenient to call + * in simple situations: + * + * |[ + * tp_base_client_take_observer_filter_object (client, + * tp_channel_filter_new_for_text_chats ()); + * ]| + * + * Since: 0.UNRELEASED + */ +void +tp_base_client_take_observer_filter_object (TpBaseClient *self, + TpChannelFilter *filter) +{ + tp_base_client_add_observer_filter_object (self, filter); + g_object_unref (filter); +} + +/** * tp_base_client_take_observer_filter: (skip) * @self: a client * @filter: (transfer full) (element-type utf8 GObject.Value): @@ -518,6 +588,34 @@ tp_base_client_add_approver_filter (TpBaseClient *self, } /** + * tp_base_client_add_approver_filter_object: + * @self: a #TpBaseClient + * @filter: a filter + * + * Register a new filter to match channels as an Approver. + * + * The #TpBaseClientClass.add_dispatch_operation virtual method will be called + * whenever a new channel's properties match the ones in @filter. + * + * This method can be called more than once. If it is, the client will + * be an Approver for any channel that matches any of the filters. + * See tp_base_client_add_observer_filter_object(). + * + * This method may only be called before tp_base_client_register() is + * called, and may only be called on objects whose class implements + * #TpBaseClientClass.add_dispatch_operation. + * + * Since: 0.UNRELEASED + */ +void +tp_base_client_add_approver_filter_object (TpBaseClient *self, + TpChannelFilter *filter) +{ + g_return_if_fail (TP_IS_CHANNEL_FILTER (filter)); + tp_base_client_add_approver_filter (self, _tp_channel_filter_use (filter)); +} + +/** * tp_base_client_take_approver_filter: (skip) * @self: a client * @filter: (transfer full) (element-type utf8 GObject.Value): @@ -553,6 +651,30 @@ tp_base_client_take_approver_filter (TpBaseClient *self, } /** + * tp_base_client_take_approver_filter_object: (skip) + * @self: a #TpBaseClient + * @filter: (transfer full): a filter + * + * The same as tp_base_client_add_approver_filter_object(), but also + * takes ownership of the filter. This makes it more convenient to call + * in simple situations: + * + * |[ + * tp_base_client_take_approver_filter_object (client, + * tp_channel_filter_new_for_text_chats ()); + * ]| + * + * Since: 0.UNRELEASED + */ +void +tp_base_client_take_approver_filter_object (TpBaseClient *self, + TpChannelFilter *filter) +{ + tp_base_client_add_approver_filter_object (self, filter); + g_object_unref (filter); +} + +/** * tp_base_client_be_a_handler: * @self: a #TpBaseClient * @@ -605,6 +727,34 @@ tp_base_client_add_handler_filter (TpBaseClient *self, } /** + * tp_base_client_add_handler_filter_object: + * @self: a #TpBaseClient + * @filter: a filter + * + * Register a new filter to match channels as a Handler. + * + * The #TpBaseClientClass.handle_channels virtual method will be called + * whenever a new channel's properties match the ones in @filter. + * + * This method can be called more than once. If it is, the client will + * be a Handler for any channel that matches any of the filters. + * See tp_base_client_add_observer_filter_object(). + * + * This method may only be called before tp_base_client_register() is + * called, and may only be called on objects whose class implements + * #TpBaseClientClass.handle_channels. + * + * Since: 0.UNRELEASED + */ +void +tp_base_client_add_handler_filter_object (TpBaseClient *self, + TpChannelFilter *filter) +{ + g_return_if_fail (TP_IS_CHANNEL_FILTER (filter)); + tp_base_client_add_handler_filter (self, _tp_channel_filter_use (filter)); +} + +/** * tp_base_client_take_handler_filter: (skip) * @self: a #TpBaseClient * @filter: (transfer full) (element-type utf8 GObject.Value): @@ -640,6 +790,30 @@ tp_base_client_take_handler_filter (TpBaseClient *self, } /** + * tp_base_client_take_handler_filter_object: (skip) + * @self: a #TpBaseClient + * @filter: (transfer full): a filter + * + * The same as tp_base_client_add_handler_filter_object(), but also + * takes ownership of the filter. This makes it more convenient to call + * in simple situations: + * + * |[ + * tp_base_client_take_handler_filter_object (client, + * tp_channel_filter_new_for_text_chats ()); + * ]| + * + * Since: 0.UNRELEASED + */ +void +tp_base_client_take_handler_filter_object (TpBaseClient *self, + TpChannelFilter *filter) +{ + tp_base_client_add_handler_filter_object (self, filter); + g_object_unref (filter); +} + +/** * tp_base_client_set_handler_bypass_approval: * @self: a #TpBaseClient * @bypass_approval: the value of the Handler.BypassApproval property diff --git a/telepathy-glib/base-client.h b/telepathy-glib/base-client.h index 9550b42..38232ee 100644 --- a/telepathy-glib/base-client.h +++ b/telepathy-glib/base-client.h @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -108,9 +109,17 @@ void tp_base_client_implement_handle_channels (TpBaseClientClass *klass, void tp_base_client_add_observer_filter (TpBaseClient *self, GHashTable *filter); +_TP_AVAILABLE_IN_0_20 +void tp_base_client_add_observer_filter_object (TpBaseClient *self, + TpChannelFilter *filter); + void tp_base_client_take_observer_filter (TpBaseClient *self, GHashTable *filter); +_TP_AVAILABLE_IN_0_20 +void tp_base_client_take_observer_filter_object (TpBaseClient *self, + TpChannelFilter *filter); + void tp_base_client_set_observer_recover (TpBaseClient *self, gboolean recover); void tp_base_client_set_observer_delay_approvers (TpBaseClient *self, @@ -118,15 +127,27 @@ void tp_base_client_set_observer_delay_approvers (TpBaseClient *self, void tp_base_client_add_approver_filter (TpBaseClient *self, GHashTable *filter); +_TP_AVAILABLE_IN_0_20 +void tp_base_client_add_approver_filter_object (TpBaseClient *self, + TpChannelFilter *filter); void tp_base_client_take_approver_filter (TpBaseClient *self, GHashTable *filter); +_TP_AVAILABLE_IN_0_20 +void tp_base_client_take_approver_filter_object (TpBaseClient *self, + TpChannelFilter *filter); void tp_base_client_be_a_handler (TpBaseClient *self); void tp_base_client_add_handler_filter (TpBaseClient *self, GHashTable *filter); +_TP_AVAILABLE_IN_0_20 +void tp_base_client_add_handler_filter_object (TpBaseClient *self, + TpChannelFilter *filter); void tp_base_client_take_handler_filter (TpBaseClient *self, GHashTable *filter); +_TP_AVAILABLE_IN_0_20 +void tp_base_client_take_handler_filter_object (TpBaseClient *self, + TpChannelFilter *filter); void tp_base_client_set_handler_bypass_approval (TpBaseClient *self, gboolean bypass_approval); diff --git a/telepathy-glib/channel-filter-internal.h b/telepathy-glib/channel-filter-internal.h new file mode 100644 index 0000000..fdf5475 --- /dev/null +++ b/telepathy-glib/channel-filter-internal.h @@ -0,0 +1,33 @@ +/**/ +/* + * A filter matching certain channels. + * + * Copyright © 2010-2012 Collabora Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef TP_CHANNEL_FILTER_INTERNAL_H +#define TP_CHANNEL_FILTER_INTERNAL_H + +#include + +G_BEGIN_DECLS + +GHashTable *_tp_channel_filter_use (TpChannelFilter *self); + +G_END_DECLS + +#endif diff --git a/telepathy-glib/channel-filter.c b/telepathy-glib/channel-filter.c new file mode 100644 index 0000000..2fc54fc --- /dev/null +++ b/telepathy-glib/channel-filter.c @@ -0,0 +1,560 @@ +/* + * A filter matching certain channels. + * + * Copyright © 2010-2012 Collabora Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include +#include + +#define DEBUG_FLAG TP_DEBUG_MISC +#include "debug-internal.h" + +#include +#include +#include + +/** + * SECTION:channel-filter + * @title: TpChannelFilter + * @short_description: a filter matching certain channels + * @see_also: #TpBaseClient, #TpSimpleApprover, #TpSimpleHandler, + * #TpSimpleObserver + * + * Telepathy clients are notified about "interesting" #TpChannels + * by the Channel Dispatcher. To do this efficiently, the clients have + * lists of "channel filters", describing the channels that each client + * considers to be "interesting". + * + * In telepathy-glib, these lists take the form of lists of #TpChannelFilter + * objects. Each #TpChannelFilter matches certain properties of the channel, + * and the channel dispatcher dispatches a channel to a client if that + * channel matches any of the filters in the client's list: + * + * |[ + * channel is interesting to this client = ( + * ((channel matches property A from filter 1) && + * (channel matches property B from filter 1) && ...) + * || + * ((channel matches property P from filter 2) && + * (channel matches property Q from filter 2) && ...) + * || ...) + * ]| + * + * An empty list of filters does not match any channels, but a list + * containing an empty filter matches every channel. + * + * To construct a filter, either create an empty filter with + * tp_channel_filter_new(), or create a pre-populated filter with + * certain properties using one of the convenience constructors like + * tp_channel_filter_new_for_text_chats(). + * + * After creating a filter, you can make it more specific by using + * methods like tp_channel_filter_require_locally_requested(), if + * required. + * + * Finally, add it to a #TpBaseClient using + * tp_base_client_add_observer_filter_object(), + * tp_base_client_add_approver_filter_object() and/or + * tp_base_client_add_handler_filter_object() (depending on the type + * of client required), and release the filter object with g_object_unref(). + * + * If you would like the #TpBaseClient to act on particular channels in + * more than one role - for instance, an Approver for Text channels which + * is also a Handler for Text channels - you can add the same + * #TpChannelFilter object via more than one method. + * + * Once you have added a filter object to a #TpBaseClient, you may not + * modify it further. + */ + +/** + * TpChannelFilterClass: + * + * The class of a #TpChannelFilter. + */ + +struct _TpChannelFilterClass { + /**/ + GObjectClass parent_class; +}; + +/** + * TpChannelFilter: + * + * A filter matching certain channels. + */ + +struct _TpChannelFilter { + /**/ + GObject parent; + TpChannelFilterPrivate *priv; +}; + +struct _TpChannelFilterPrivate { + /* dup'd string => slice-allocated GValue + * + * Do not use tp_asv_new() and friends, because they expect static + * string keys. */ + GHashTable *asv; + + gboolean already_used; +}; + +G_DEFINE_TYPE (TpChannelFilter, tp_channel_filter, G_TYPE_OBJECT) + +static void +tp_channel_filter_init (TpChannelFilter *self) +{ + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, TP_TYPE_CHANNEL_FILTER, + TpChannelFilterPrivate); + + self->priv->asv = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, (GDestroyNotify) tp_g_value_slice_free); + + self->priv->already_used = FALSE; +} + +static void +tp_channel_filter_dispose (GObject *object) +{ + TpChannelFilter *self = TP_CHANNEL_FILTER (object); + + tp_clear_pointer (&self->priv->asv, g_hash_table_unref); + + G_OBJECT_CLASS (tp_channel_filter_parent_class)->dispose (object); +} + +static void +tp_channel_filter_class_init (TpChannelFilterClass *cls) +{ + GObjectClass *object_class = G_OBJECT_CLASS (cls); + + g_type_class_add_private (cls, sizeof (TpChannelFilterPrivate)); + + object_class->dispose = tp_channel_filter_dispose; +} + +/** + * tp_channel_filter_new: + * + * Return a channel filter that matches every channel. + * + * You can make the filter more restrictive by setting properties. In + * practice, to make a filter useful, you should set at least a channel + * type (text, call, file transfer etc.) and a target type + * (contact, chatroom, etc.). + */ +TpChannelFilter * +tp_channel_filter_new (void) +{ + return g_object_new (TP_TYPE_CHANNEL_FILTER, + NULL); +} + +/** + * tp_channel_filter_new_for_text_chats: + * + * Return a channel filter that matches 1-1 text chats, + * such as #TpTextChannels carrying private messages or SMSs. + * + * It is not necessary to call tp_channel_filter_require_target_is_room() + * on the returned filter. + */ +TpChannelFilter * +tp_channel_filter_new_for_text_chats (void) +{ + TpChannelFilter *self = tp_channel_filter_new (); + + tp_channel_filter_require_target_is_contact (self); + tp_channel_filter_require_channel_type (self, TP_IFACE_CHANNEL_TYPE_TEXT); + return self; +} + +/** + * tp_channel_filter_new_for_text_chatrooms: + * + * Return a channel filter that matches participation in named text + * chatrooms, such as #TpTextChannels communicating with + * an XMPP Multi-User Chat room or an IRC channel. + * + * It is not necessary to call tp_channel_filter_require_target_is_room() + * on the returned filter. + */ +TpChannelFilter * +tp_channel_filter_new_for_text_chatrooms (void) +{ + TpChannelFilter *self = tp_channel_filter_new (); + + tp_channel_filter_require_target_is_room (self); + tp_channel_filter_require_channel_type (self, TP_IFACE_CHANNEL_TYPE_TEXT); + return self; +} + +/** + * tp_channel_filter_require_target_is_contact: + * @self: a channel filter + * + * Narrow @self to require that the channel communicates with a single + * #TpContact. + * + * For instance, the filter would match #TpTextChannels carrying private + * messages or SMSs, #TpCallChannels for ordinary 1-1 audio and/or video calls, + * #TpFileTransferChannels for file transfers to or from a contact, and so on. + * + * It would not match channels communicating with a chatroom, ad-hoc + * chatrooms with no name, or conference-calls (in protocols that can tell + * the difference between a conference call and an ordinary 1-1 call). + * + * It is an error to call this method if the channel filter has already + * been passed to a #TpBaseClient. + */ +void +tp_channel_filter_require_target_is_contact (TpChannelFilter *self) +{ + tp_channel_filter_require_target_type (self, TP_HANDLE_TYPE_CONTACT); +} + +/** + * tp_channel_filter_require_target_is_room: + * @self: a channel filter + * + * Narrow @self to require that the channel communicates with a named + * chatroom. + * + * For instance, this filter would match #TpTextChannels communicating with + * an XMPP Multi-User Chat room or an IRC channel. It would also match + * #TpDBusTubeChannels or #TpStreamTubeChannels that communicate through + * a chatroom, and multi-user audio and/or video calls that use a named, + * chatroom-like object on the server. + * + * It is an error to call this method if the channel filter has already + * been passed to a #TpBaseClient. + */ +void +tp_channel_filter_require_target_is_room (TpChannelFilter *self) +{ + tp_channel_filter_require_target_type (self, TP_HANDLE_TYPE_ROOM); +} + +/** + * tp_channel_filter_require_no_target: + * @self: a channel filter + * + * Narrow @self to require that the channel communicates with an + * ad-hoc, unnamed group of contacts. + * + * For instance, among other things, this filter would match #TpCallChannels + * for conference calls in cellular telephony. + * + * This is equivalent to tp_channel_filter_require_target_type() + * with argument %TP_HANDLE_TYPE_NONE. + * + * It is an error to call this method if the channel filter has already + * been passed to a #TpBaseClient. + */ +void +tp_channel_filter_require_no_target (TpChannelFilter *self) +{ + tp_channel_filter_require_target_type (self, TP_HANDLE_TYPE_NONE); +} + +/** + * tp_channel_filter_require_target_type: + * @self: a channel filter + * @target_type: the desired value for #TpChannel:handle-type + * + * Narrow @self to require a particular target handle type. + * + * For instance, setting @target_type to %TP_HANDLE_TYPE_CONTACT + * is equivalent to tp_channel_filter_require_target_is_contact(). + * + * It is an error to call this method if the channel filter has already + * been passed to a #TpBaseClient. + */ +void +tp_channel_filter_require_target_type (TpChannelFilter *self, + TpHandleType target_type) +{ + g_return_if_fail (TP_IS_CHANNEL_FILTER (self)); + g_return_if_fail (((guint) target_type) < TP_NUM_HANDLE_TYPES); + + g_hash_table_insert (self->priv->asv, + g_strdup (TP_PROP_CHANNEL_TARGET_HANDLE_TYPE), + tp_g_value_slice_new_uint (target_type)); +} + +/** + * tp_channel_filter_new_for_calls: + * @handle_type: the desired handle type + * + * Return a channel filter that matches audio and video calls, + * including VoIP and telephony. + * + * @handle_type is passed to tp_channel_filter_require_target_type(). + * Use %TP_HANDLE_TYPE_CONTACT for ordinary 1-1 calls. + */ +TpChannelFilter * +tp_channel_filter_new_for_calls (TpHandleType handle_type) +{ + TpChannelFilter *self = tp_channel_filter_new (); + + tp_channel_filter_require_target_type (self, handle_type); + tp_channel_filter_require_channel_type (self, TP_IFACE_CHANNEL_TYPE_CALL); + return self; +} + +/** + * tp_channel_filter_require_channel_type: + * @self: a channel filter + * @channel_type: the desired value for #TpChannel:channel-type + * + * Narrow @self to require a particular channel type, given as a D-Bus + * interface name. + * + * It is an error to call this method if the channel filter has already + * been passed to a #TpBaseClient. + */ +void +tp_channel_filter_require_channel_type (TpChannelFilter *self, + const gchar *channel_type) +{ + g_return_if_fail (TP_IS_CHANNEL_FILTER (self)); + g_return_if_fail (g_dbus_is_interface_name (channel_type)); + + g_hash_table_insert (self->priv->asv, + g_strdup (TP_PROP_CHANNEL_CHANNEL_TYPE), + tp_g_value_slice_new_string (channel_type)); +} + +/** + * tp_channel_filter_new_for_stream_tubes: + * @service: (allow-none): the desired value of #TpStreamTubeChannel:service, + * or %NULL to match any service + * + * Return a channel filter that matches stream tube channels, as used by + * #TpStreamTubeChannel, and optionally also match a particular service. + * This filter can be narrowed further via other methods. + * + * For instance, to match RFB display-sharing being offered by another + * participant in a chatroom: + * + * |[ + * filter = tp_channel_filter_new_for_stream_tubes ("rfb"); + * tp_channel_filter_require_target_is_room (filter); + * tp_channel_filter_require_locally_requested (filter, FALSE); + * ]| + */ +TpChannelFilter * +tp_channel_filter_new_for_stream_tubes (const gchar *service) +{ + TpChannelFilter *self = tp_channel_filter_new (); + + tp_channel_filter_require_channel_type (self, + TP_IFACE_CHANNEL_TYPE_STREAM_TUBE); + + if (service != NULL) + g_hash_table_insert (self->priv->asv, + g_strdup (TP_PROP_CHANNEL_TYPE_STREAM_TUBE_SERVICE), + tp_g_value_slice_new_string (service)); + + return self; +} + +/** + * tp_channel_filter_new_for_dbus_tubes: + * @service: (allow-none): the desired value of + * #TpDBusTubeChannel:service-name, or %NULL to match any service + * + * Return a channel filter that matches D-Bus tube channels, as used by + * #TpDBusTubeChannel, and optionally also match a particular service. + * This filter can be narrowed further via other methods. + * + * For instance, to match a "com.example.Chess" tube being offered by + * the local user to a peer: + * + * |[ + * filter = tp_channel_filter_new_for_dbus_tube ("com.example.Chess"); + * tp_channel_filter_require_target_is_contact (filter); + * tp_channel_filter_require_locally_requested (filter, TRUE); + * ]| + */ +TpChannelFilter * +tp_channel_filter_new_for_dbus_tubes (const gchar *service) +{ + TpChannelFilter *self = tp_channel_filter_new (); + + tp_channel_filter_require_channel_type (self, + TP_IFACE_CHANNEL_TYPE_DBUS_TUBE); + + if (service != NULL) + g_hash_table_insert (self->priv->asv, + g_strdup (TP_PROP_CHANNEL_TYPE_DBUS_TUBE_SERVICE_NAME), + tp_g_value_slice_new_string (service)); + + return self; +} + +/** + * tp_channel_filter_new_for_file_transfers: + * @service: (allow-none): a service name, or %NULL + * + * Return a channel filter that matches file transfer channels with + * a #TpContact, as used by #TpFileTransferChannel. + * + * At the time of writing, file transfers with other types of target + * (like chatrooms) have not been implemented. If they are, they will + * use a different filter. + * + * Using this method will match both incoming and outgoing file transfers. + * If you only want to match one direction, use + * tp_channel_filter_require_locally_requested() to select it. + * + * For instance, to match outgoing file transfers (sending a file to + * a contact), you can use: + * + * |[ + * filter = tp_channel_filter_new_for_file_transfer (NULL); + * tp_channel_filter_require_locally_requested (filter, TRUE); + * ]| + * + * @service can be used by collaborative applications to match a particular + * #TpFileTransferChannel:service-name. For instance, if an application + * wants to be the handler for incoming file transfers that are marked + * as belonging to that application, it could use a filter like this: + * + * |[ + * filter = tp_channel_filter_new_for_file_transfer ("com.example.MyApp"); + * tp_channel_filter_require_locally_requested (filter, FALSE); + * tp_base_client_take_handler_filter_object (client, filter); + * ]| + */ +TpChannelFilter * +tp_channel_filter_new_for_file_transfers (const gchar *service) +{ + TpChannelFilter *self = tp_channel_filter_new (); + + tp_channel_filter_require_target_is_contact (self); + tp_channel_filter_require_channel_type (self, + TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER); + + if (service != NULL) + g_hash_table_insert (self->priv->asv, + g_strdup (TP_PROP_CHANNEL_INTERFACE_FILE_TRANSFER_METADATA_SERVICE_NAME), + tp_g_value_slice_new_string (service)); + + return self; +} + +/** + * tp_channel_filter_require_locally_requested: + * @self: a channel filter + * @requested: the desired value for tp_channel_get_requested() + * + * Narrow @self to require that the channel was requested by the local + * user, or to require that the channel was not + * requested by the local user, depending on the value of @requested. + * + * For instance, to match an outgoing (locally-requested) 1-1 call: + * + * |[ + * filter = tp_channel_filter_new_for_calls (TP_HANDLE_TYPE_CONTACT); + * tp_channel_filter_require_locally_requested (filter, TRUE); + * ]| + * + * or to match an incoming (not locally-requested) file transfer: + * + * |[ + * filter = tp_channel_filter_new_for_file_transfer (); + * tp_channel_filter_require_locally_requested (filter, FALSE); + * ]| + * + * It is an error to call this method if the channel filter has already + * been passed to a #TpBaseClient. + */ +void +tp_channel_filter_require_locally_requested (TpChannelFilter *self, + gboolean requested) +{ + g_return_if_fail (TP_IS_CHANNEL_FILTER (self)); + g_return_if_fail (!self->priv->already_used); + + /* Do not use tp_asv_set_uint32 or similar - the key is dup'd */ + g_hash_table_insert (self->priv->asv, + g_strdup (TP_PROP_CHANNEL_REQUESTED), + tp_g_value_slice_new_boolean (requested)); +} + +/** + * tp_channel_filter_require_property: + * @self: a channel filter + * @name: a fully-qualified D-Bus property name (in the format + * "interface.name.propertyname") as described by the Telepathy + * D-Bus API Specification + * @value: the value required for @name + * + * Narrow @self to require that the immutable channel property @name + * has the given value. + * + * If @value is a floating reference, this method will take ownership + * of it. + * + * @value must not contain any GVariant extensions not supported by + * dbus-glib, such as %G_VARIANT_TYPE_UNIT or %G_VARIANT_TYPE_HANDLE. + * + * For instance, tp_channel_filter_require_target_is_contact() is equivalent + * to: + * + * |[ + * tp_channel_filter_require_property (filter, + * TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, + * g_variant_new_uint32 (TP_HANDLE_TYPE_CONTACT)); + * ]| + * + * It is an error to call this method if the channel filter has already + * been passed to a #TpBaseClient. + */ +void +tp_channel_filter_require_property (TpChannelFilter *self, + const gchar *name, + GVariant *value) +{ + GValue *gvalue; + + g_return_if_fail (TP_IS_CHANNEL_FILTER (self)); + g_return_if_fail (!self->priv->already_used); + g_return_if_fail (name != NULL); + + g_variant_ref_sink (value); + + gvalue = g_slice_new0 (GValue); + dbus_g_value_parse_g_variant (value, gvalue); + + g_variant_unref (value); + + g_hash_table_insert (self->priv->asv, g_strdup (name), gvalue); +} + +GHashTable * +_tp_channel_filter_use (TpChannelFilter *self) +{ + g_return_val_if_fail (TP_IS_CHANNEL_FILTER (self), NULL); + + self->priv->already_used = TRUE; + return self->priv->asv; +} diff --git a/telepathy-glib/channel-filter.h b/telepathy-glib/channel-filter.h new file mode 100644 index 0000000..2e9a2d1 --- /dev/null +++ b/telepathy-glib/channel-filter.h @@ -0,0 +1,105 @@ +/* + * A filter matching certain channels. + * + * Copyright © 2010-2012 Collabora Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef TP_CHANNEL_FILTER_H +#define TP_CHANNEL_FILTER_H + +#include +#include +#include + +#include +#include + +G_BEGIN_DECLS + +typedef struct _TpChannelFilter TpChannelFilter; +typedef struct _TpChannelFilterClass TpChannelFilterClass; +typedef struct _TpChannelFilterPrivate TpChannelFilterPrivate; + +GType tp_channel_filter_get_type (void); + +#define TP_TYPE_CHANNEL_FILTER \ + (tp_channel_filter_get_type ()) +#define TP_CHANNEL_FILTER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), TP_TYPE_CHANNEL_FILTER, \ + TpChannelFilter)) +#define TP_CHANNEL_FILTER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), TP_TYPE_CHANNEL_FILTER, \ + TpChannelFilterClass)) +#define TP_IS_CHANNEL_FILTER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TP_TYPE_CHANNEL_FILTER)) +#define TP_IS_CHANNEL_FILTER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), TP_TYPE_CHANNEL_FILTER)) +#define TP_CHANNEL_FILTER_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), TP_TYPE_CHANNEL_FILTER, \ + TpChannelFilterClass)) + +_TP_AVAILABLE_IN_UNRELEASED G_GNUC_WARN_UNUSED_RESULT +TpChannelFilter *tp_channel_filter_new (void); + +_TP_AVAILABLE_IN_UNRELEASED G_GNUC_WARN_UNUSED_RESULT +TpChannelFilter *tp_channel_filter_new_for_text_chats (void); + +_TP_AVAILABLE_IN_UNRELEASED G_GNUC_WARN_UNUSED_RESULT +TpChannelFilter *tp_channel_filter_new_for_text_chatrooms (void); + +_TP_AVAILABLE_IN_UNRELEASED G_GNUC_WARN_UNUSED_RESULT +TpChannelFilter *tp_channel_filter_new_for_calls (TpHandleType handle_type); + +_TP_AVAILABLE_IN_UNRELEASED G_GNUC_WARN_UNUSED_RESULT +TpChannelFilter *tp_channel_filter_new_for_stream_tubes (const gchar *service); + +_TP_AVAILABLE_IN_UNRELEASED G_GNUC_WARN_UNUSED_RESULT +TpChannelFilter *tp_channel_filter_new_for_dbus_tubes (const gchar *service); + +_TP_AVAILABLE_IN_UNRELEASED G_GNUC_WARN_UNUSED_RESULT +TpChannelFilter *tp_channel_filter_new_for_file_transfers ( + const gchar *service); + +_TP_AVAILABLE_IN_UNRELEASED +void tp_channel_filter_require_target_is_contact (TpChannelFilter *self); + +_TP_AVAILABLE_IN_UNRELEASED +void tp_channel_filter_require_target_is_room (TpChannelFilter *self); + +_TP_AVAILABLE_IN_UNRELEASED +void tp_channel_filter_require_no_target (TpChannelFilter *self); + +_TP_AVAILABLE_IN_UNRELEASED +void tp_channel_filter_require_target_type (TpChannelFilter *self, + TpHandleType target_type); + +_TP_AVAILABLE_IN_UNRELEASED +void tp_channel_filter_require_locally_requested (TpChannelFilter *self, + gboolean requested); + +_TP_AVAILABLE_IN_UNRELEASED +void tp_channel_filter_require_channel_type (TpChannelFilter *self, + const gchar *channel_type); + +_TP_AVAILABLE_IN_UNRELEASED +void tp_channel_filter_require_property (TpChannelFilter *self, + const gchar *name, + GVariant *value); + +G_END_DECLS + +#endif diff --git a/telepathy-glib/file-transfer-channel.c b/telepathy-glib/file-transfer-channel.c index db39bff..e5438bc 100644 --- a/telepathy-glib/file-transfer-channel.c +++ b/telepathy-glib/file-transfer-channel.c @@ -935,17 +935,9 @@ tp_file_transfer_channel_class_init (TpFileTransferChannelClass *klass) * contact who also supports the metadata extension; see the * requestable channel classes for said contact), this property will * be set to the same value on the remote incoming channel and - * handlers can match on this in their handler filter. For example, - * a remote handler could call the following: - * - * |[ - * tp_base_client_take_handler_filter (handler, tp_asv_new ( - * TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER, - * TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, TP_HANDLE_TYPE_CONTACT, - * TP_PROP_CHANNEL_REQUESTED, G_TYPE_BOOLEAN, FALSE, - * TP_PROP_CHANNEL_INTERFACE_FILE_TRANSFER_METADATA_SERVICE_NAME, G_TYPE_STRING, "service.name", - * NULL)); - * ]| + * handlers can match on this in their handler filter by passing + * a non-%NULL @service argument to + * tp_channel_filter_new_for_file_transfers(). * * The %TP_FILE_TRANSFER_CHANNEL_FEATURE_CORE feature has to be * prepared for this property to be meaningful. diff --git a/telepathy-glib/introspection.am b/telepathy-glib/introspection.am index f55520f..a25018d 100644 --- a/telepathy-glib/introspection.am +++ b/telepathy-glib/introspection.am @@ -20,6 +20,7 @@ TelepathyGLib_0_12_gir_FILES = \ $(srcdir)/automatic-client-factory.c $(srcdir)/automatic-client-factory.h \ $(srcdir)/automatic-proxy-factory.c $(srcdir)/automatic-proxy-factory.h \ $(srcdir)/basic-proxy-factory.c $(srcdir)/basic-proxy-factory.h \ + $(srcdir)/channel-filter.c $(srcdir)/channel-filter.h \ $(srcdir)/client-channel-factory.c $(srcdir)/client-channel-factory.h \ $(srcdir)/connection.c $(srcdir)/connection.h \ $(srcdir)/connection-contact-list.c $(srcdir)/connection-contact-list.h \ diff --git a/telepathy-glib/simple-approver.c b/telepathy-glib/simple-approver.c index da9666d..e2c6c28 100644 --- a/telepathy-glib/simple-approver.c +++ b/telepathy-glib/simple-approver.c @@ -49,10 +49,8 @@ * my_add_dispatch_operation, user_data); * g_object_unref (factory); * - * tp_base_client_take_approver_filter (client, tp_asv_new ( - * TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, TP_IFACE_CHANNEL_TYPE_TEXT, - * TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, TP_HANDLE_TYPE_CONTACT, - * NULL)); + * tp_base_client_take_approver_filter_object (client, + * tp_channel_filter_new_for_text_chats ()); * * tp_base_client_register (client, NULL); * ]| diff --git a/telepathy-glib/simple-handler.c b/telepathy-glib/simple-handler.c index 0fcba4a..e761ec2 100644 --- a/telepathy-glib/simple-handler.c +++ b/telepathy-glib/simple-handler.c @@ -50,10 +50,8 @@ * "MyHandler", FALSE, my_handle_channels, user_data); * g_object_unref (factory); * - * tp_base_client_take_handler_filter (client, tp_asv_new ( - * TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, TP_IFACE_CHANNEL_TYPE_TEXT, - * TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, TP_HANDLE_TYPE_CONTACT, - * NULL)); + * tp_base_client_take_handler_filter_object (client, + * tp_channel_filter_new_for_text_chats ()); * * tp_base_client_register (client, NULL); * ]| diff --git a/telepathy-glib/simple-observer.c b/telepathy-glib/simple-observer.c index ee74a84..9725bca 100644 --- a/telepathy-glib/simple-observer.c +++ b/telepathy-glib/simple-observer.c @@ -49,10 +49,8 @@ * FALSE, my_observe_channels, user_data); * g_object_unref (factory); * - * tp_base_client_take_observer_filter (client, tp_asv_new ( - * TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, TP_IFACE_CHANNEL_TYPE_TEXT, - * TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, TP_HANDLE_TYPE_CONTACT, - * NULL)); + * tp_base_client_take_observer_filter_object (client, + * tp_channel_filter_new_for_text_chats ()); * * tp_base_client_register (client, NULL); * ]| diff --git a/telepathy-glib/telepathy-glib.h b/telepathy-glib/telepathy-glib.h index 2af1f72..3762f61 100644 --- a/telepathy-glib/telepathy-glib.h +++ b/telepathy-glib/telepathy-glib.h @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include diff --git a/tests/Makefile.am b/tests/Makefile.am index 63abac5..69b9244 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -7,6 +7,7 @@ SUBDIRS = \ programs_list = \ test-asv \ test-capabilities \ + test-channel-filter \ test-availability-cmp \ test-dtmf-player \ test-enums \ @@ -81,6 +82,13 @@ test_capabilities_LDADD = \ $(GLIB_LIBS) # this one uses internal ABI +test_channel_filter_SOURCES = \ + channel-filter.c +test_channel_filter_LDADD = \ + $(top_builddir)/telepathy-glib/libtelepathy-glib-internal.la \ + $(GLIB_LIBS) + +# this one uses internal ABI test_contact_search_result_SOURCES = \ contact-search-result.c test_contact_search_result_LDADD = \ diff --git a/tests/channel-filter.c b/tests/channel-filter.c new file mode 100644 index 0000000..41cd945 --- /dev/null +++ b/tests/channel-filter.c @@ -0,0 +1,212 @@ +#include "config.h" + +#include "telepathy-glib/channel-filter-internal.h" + +#include "tests/lib/util.h" + +typedef struct { + TpChannelFilter *filter; +} Fixture; + +static void +setup (Fixture *f, + gconstpointer data) +{ + g_type_init (); + tp_debug_set_flags ("all"); +} + +static void +test_basics (Fixture *f, + gconstpointer data) +{ + const GHashTable *asv; + gboolean valid; + guint i; + TpHandleType call_handle_types[] = { TP_HANDLE_TYPE_CONTACT, + TP_HANDLE_TYPE_ROOM, + TP_HANDLE_TYPE_NONE }; + + f->filter = tp_channel_filter_new (); + asv = _tp_channel_filter_use (f->filter); + g_assert_cmpuint (tp_asv_size (asv), ==, 0); + g_clear_object (&f->filter); + + f->filter = tp_channel_filter_new_for_text_chats (); + asv = _tp_channel_filter_use (f->filter); + g_assert_cmpuint (tp_asv_size (asv), ==, 2); + g_assert_cmpstr (tp_asv_get_string (asv, + TP_PROP_CHANNEL_CHANNEL_TYPE), ==, TP_IFACE_CHANNEL_TYPE_TEXT); + g_assert_cmpuint (tp_asv_get_uint32 (asv, + TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, &valid), + ==, TP_HANDLE_TYPE_CONTACT); + g_assert (valid); + g_clear_object (&f->filter); + + f->filter = tp_channel_filter_new_for_text_chatrooms (); + asv = _tp_channel_filter_use (f->filter); + g_assert_cmpuint (tp_asv_size (asv), ==, 2); + g_assert_cmpstr (tp_asv_get_string (asv, + TP_PROP_CHANNEL_CHANNEL_TYPE), ==, TP_IFACE_CHANNEL_TYPE_TEXT); + g_assert_cmpuint (tp_asv_get_uint32 (asv, + TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, &valid), + ==, TP_HANDLE_TYPE_ROOM); + g_assert (valid); + g_clear_object (&f->filter); + + for (i = 0; i < G_N_ELEMENTS (call_handle_types); i++) + { + f->filter = tp_channel_filter_new_for_calls (call_handle_types[i]); + asv = _tp_channel_filter_use (f->filter); + g_assert_cmpuint (tp_asv_size (asv), ==, 2); + g_assert_cmpstr (tp_asv_get_string (asv, + TP_PROP_CHANNEL_CHANNEL_TYPE), ==, TP_IFACE_CHANNEL_TYPE_CALL); + g_assert_cmpuint (tp_asv_get_uint32 (asv, + TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, &valid), + ==, call_handle_types[i]); + g_assert (valid); + g_clear_object (&f->filter); + } + + f->filter = tp_channel_filter_new_for_stream_tubes ("rfb"); + asv = _tp_channel_filter_use (f->filter); + g_assert_cmpuint (tp_asv_size (asv), ==, 2); + g_assert_cmpstr (tp_asv_get_string (asv, + TP_PROP_CHANNEL_CHANNEL_TYPE), ==, TP_IFACE_CHANNEL_TYPE_STREAM_TUBE); + g_assert_cmpstr (tp_asv_get_string (asv, + TP_PROP_CHANNEL_TYPE_STREAM_TUBE_SERVICE), ==, "rfb"); + g_clear_object (&f->filter); + + f->filter = tp_channel_filter_new_for_dbus_tubes ("com.example.Chess"); + asv = _tp_channel_filter_use (f->filter); + g_assert_cmpuint (tp_asv_size (asv), ==, 2); + g_assert_cmpstr (tp_asv_get_string (asv, + TP_PROP_CHANNEL_CHANNEL_TYPE), ==, TP_IFACE_CHANNEL_TYPE_DBUS_TUBE); + g_assert_cmpstr (tp_asv_get_string (asv, + TP_PROP_CHANNEL_TYPE_DBUS_TUBE_SERVICE_NAME), ==, "com.example.Chess"); + g_clear_object (&f->filter); + + f->filter = tp_channel_filter_new_for_file_transfers (NULL); + asv = _tp_channel_filter_use (f->filter); + g_assert_cmpuint (tp_asv_size (asv), ==, 2); + g_assert_cmpstr (tp_asv_get_string (asv, + TP_PROP_CHANNEL_CHANNEL_TYPE), ==, TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER); + g_assert_cmpuint (tp_asv_get_uint32 (asv, + TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, &valid), + ==, TP_HANDLE_TYPE_CONTACT); + g_assert (valid); + g_clear_object (&f->filter); + + f->filter = tp_channel_filter_new_for_file_transfers ("com.example.AbiWord"); + asv = _tp_channel_filter_use (f->filter); + g_assert_cmpuint (tp_asv_size (asv), ==, 3); + g_assert_cmpstr (tp_asv_get_string (asv, + TP_PROP_CHANNEL_CHANNEL_TYPE), ==, TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER); + g_assert_cmpstr (tp_asv_get_string (asv, + /* our constant naming strategy is unstoppable */ + TP_PROP_CHANNEL_INTERFACE_FILE_TRANSFER_METADATA_SERVICE_NAME), ==, + "com.example.AbiWord"); + g_assert_cmpuint (tp_asv_get_uint32 (asv, + TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, &valid), + ==, TP_HANDLE_TYPE_CONTACT); + g_assert (valid); + g_clear_object (&f->filter); + + f->filter = tp_channel_filter_new (); + tp_channel_filter_require_target_is_contact (f->filter); + asv = _tp_channel_filter_use (f->filter); + g_assert_cmpuint (tp_asv_size (asv), ==, 1); + g_assert_cmpuint (tp_asv_get_uint32 (asv, + TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, &valid), + ==, TP_HANDLE_TYPE_CONTACT); + g_assert (valid); + g_clear_object (&f->filter); + + f->filter = tp_channel_filter_new (); + tp_channel_filter_require_target_is_room (f->filter); + asv = _tp_channel_filter_use (f->filter); + g_assert_cmpuint (tp_asv_size (asv), ==, 1); + g_assert_cmpuint (tp_asv_get_uint32 (asv, + TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, &valid), + ==, TP_HANDLE_TYPE_ROOM); + g_assert (valid); + g_clear_object (&f->filter); + + f->filter = tp_channel_filter_new (); + tp_channel_filter_require_no_target (f->filter); + asv = _tp_channel_filter_use (f->filter); + g_assert_cmpuint (tp_asv_size (asv), ==, 1); + g_assert_cmpuint (tp_asv_get_uint32 (asv, + TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, &valid), + ==, TP_HANDLE_TYPE_NONE); + g_assert (valid); + g_clear_object (&f->filter); + + f->filter = tp_channel_filter_new (); + tp_channel_filter_require_target_type (f->filter, TP_HANDLE_TYPE_ROOM); + asv = _tp_channel_filter_use (f->filter); + g_assert_cmpuint (tp_asv_size (asv), ==, 1); + g_assert_cmpuint (tp_asv_get_uint32 (asv, + TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, &valid), + ==, TP_HANDLE_TYPE_ROOM); + g_assert (valid); + g_clear_object (&f->filter); + + f->filter = tp_channel_filter_new (); + tp_channel_filter_require_channel_type (f->filter, "com.example.Bees"); + asv = _tp_channel_filter_use (f->filter); + g_assert_cmpuint (tp_asv_size (asv), ==, 1); + g_assert_cmpstr (tp_asv_get_string (asv, + TP_PROP_CHANNEL_CHANNEL_TYPE), ==, "com.example.Bees"); + g_clear_object (&f->filter); + + f->filter = tp_channel_filter_new (); + tp_channel_filter_require_locally_requested (f->filter, TRUE); + asv = _tp_channel_filter_use (f->filter); + g_assert_cmpuint (tp_asv_size (asv), ==, 1); + g_assert_cmpuint (tp_asv_get_boolean (asv, + TP_PROP_CHANNEL_REQUESTED, &valid), ==, TRUE); + g_assert (valid); + g_clear_object (&f->filter); + + f->filter = tp_channel_filter_new (); + tp_channel_filter_require_locally_requested (f->filter, FALSE); + asv = _tp_channel_filter_use (f->filter); + g_assert_cmpuint (tp_asv_size (asv), ==, 1); + g_assert_cmpuint (tp_asv_get_boolean (asv, + TP_PROP_CHANNEL_REQUESTED, &valid), ==, FALSE); + g_assert (valid); + g_clear_object (&f->filter); + + f->filter = tp_channel_filter_new (); + tp_channel_filter_require_property (f->filter, + "com.example.Answer", g_variant_new_uint32 (42)); + asv = _tp_channel_filter_use (f->filter); + g_assert_cmpuint (tp_asv_size (asv), ==, 1); + g_assert_cmpuint (tp_asv_get_uint32 (asv, + "com.example.Answer", &valid), ==, 42); + g_assert (valid); + g_clear_object (&f->filter); +} + +static void +teardown (Fixture *f, + gconstpointer data) +{ + g_clear_object (&f->filter); +} + +int +main (int argc, + char **argv) +{ +#define TEST_PREFIX "/channel-filter/" + + g_test_init (&argc, &argv, NULL); + g_test_bug_base ("http://bugs.freedesktop.org/show_bug.cgi?id="); + + g_test_add (TEST_PREFIX "basics", Fixture, NULL, setup, test_basics, + teardown); + + return g_test_run (); +} diff --git a/tests/dbus/base-client.c b/tests/dbus/base-client.c index 8433915..7501802 100644 --- a/tests/dbus/base-client.c +++ b/tests/dbus/base-client.c @@ -494,24 +494,20 @@ static void test_observer (Test *test, gconstpointer data G_GNUC_UNUSED) { - GHashTable *filter; + TpChannelFilter *filter; GPtrArray *channels, *requests_satisified; GHashTable *info; TpChannel *chan; - filter = tp_asv_new ( - TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, TP_IFACE_CHANNEL_TYPE_TEXT, - NULL); - - tp_base_client_add_observer_filter (test->base_client, filter); - g_hash_table_unref (filter); + filter = tp_channel_filter_new (); + tp_channel_filter_require_channel_type (filter, TP_IFACE_CHANNEL_TYPE_TEXT); + tp_base_client_add_observer_filter_object (test->base_client, filter); + g_object_unref (filter); - tp_base_client_take_observer_filter (test->base_client, tp_asv_new ( - TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, - TP_IFACE_CHANNEL_TYPE_STREAM_TUBE, - TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, - TP_HANDLE_TYPE_CONTACT, - NULL)); + filter = tp_channel_filter_new_for_stream_tubes (NULL); + tp_channel_filter_require_target_is_contact (filter); + tp_base_client_add_observer_filter_object (test->base_client, filter); + g_object_unref (filter); tp_base_client_set_observer_recover (test->base_client, TRUE); tp_base_client_set_observer_delay_approvers (test->base_client, TRUE); @@ -634,7 +630,7 @@ static void test_approver (Test *test, gconstpointer data G_GNUC_UNUSED) { - GHashTable *filter; + TpChannelFilter *filter; GPtrArray *channels, *chans; GHashTable *properties; static const char *interfaces[] = { NULL }; @@ -642,19 +638,15 @@ test_approver (Test *test, TP_CLIENT_BUS_NAME_BASE ".Badger", NULL, }; guint i; - filter = tp_asv_new ( - TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, TP_IFACE_CHANNEL_TYPE_TEXT, - NULL); - - tp_base_client_add_approver_filter (test->base_client, filter); - g_hash_table_unref (filter); + filter = tp_channel_filter_new (); + tp_channel_filter_require_channel_type (filter, TP_IFACE_CHANNEL_TYPE_TEXT); + tp_base_client_add_approver_filter_object (test->base_client, filter); + g_object_unref (filter); - tp_base_client_take_approver_filter (test->base_client, tp_asv_new ( - TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, - TP_IFACE_CHANNEL_TYPE_STREAM_TUBE, - TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, - TP_HANDLE_TYPE_CONTACT, - NULL)); + filter = tp_channel_filter_new_for_stream_tubes (NULL); + tp_channel_filter_require_target_is_contact (filter); + tp_base_client_add_approver_filter_object (test->base_client, filter); + g_object_unref (filter); tp_base_client_register (test->base_client, &test->error); g_assert_no_error (test->error); @@ -836,7 +828,7 @@ static void test_handler (Test *test, gconstpointer data G_GNUC_UNUSED) { - GHashTable *filter; + TpChannelFilter *filter; const gchar *caps[] = { "mushroom", "snake", NULL }; GPtrArray *channels; GPtrArray *requests_satisified; @@ -844,19 +836,15 @@ test_handler (Test *test, GList *chans; TpTestsSimpleClient *client_2; - filter = tp_asv_new ( - TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, TP_IFACE_CHANNEL_TYPE_TEXT, - NULL); + filter = tp_channel_filter_new (); + tp_channel_filter_require_channel_type (filter, TP_IFACE_CHANNEL_TYPE_TEXT); + tp_base_client_add_handler_filter_object (test->base_client, filter); + g_object_unref (filter); - tp_base_client_add_handler_filter (test->base_client, filter); - g_hash_table_unref (filter); - - tp_base_client_take_handler_filter (test->base_client, tp_asv_new ( - TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, - TP_IFACE_CHANNEL_TYPE_STREAM_TUBE, - TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, - TP_HANDLE_TYPE_CONTACT, - NULL)); + filter = tp_channel_filter_new_for_stream_tubes (NULL); + tp_channel_filter_require_target_is_contact (filter); + tp_base_client_add_handler_filter_object (test->base_client, filter); + g_object_unref (filter); tp_base_client_set_handler_bypass_approval (test->base_client, TRUE); @@ -1028,13 +1016,12 @@ test_handler_requests (Test *test, GHashTable *info; TpChannelRequest *request; GList *requests; + TpChannelFilter *filter; - tp_base_client_take_handler_filter (test->base_client, tp_asv_new ( - TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, - TP_IFACE_CHANNEL_TYPE_STREAM_TUBE, - TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, - TP_HANDLE_TYPE_CONTACT, - NULL)); + filter = tp_channel_filter_new_for_stream_tubes (NULL); + tp_channel_filter_require_target_is_contact (filter); + tp_base_client_add_handler_filter_object (test->base_client, filter); + g_object_unref (filter); tp_base_client_set_handler_request_notification (test->base_client); -- 1.7.10