/* * Factory for specialized TpChannel subclasses. * * Copyright © 2011 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 */ /** * SECTION:automatic-client-factory * @title: TpAutomaticClientFactory * @short_description: Factory for specialized #TpChannel subclasses. * @see_also: #TpSimpleClientFactory * * This factory overrides some #TpSimpleClientFactory virtual methods to * create specialized #TpChannel subclasses. * * #TpAutomaticClientFactory will currently create #TpChannel objects * as follows: * * * * a #TpStreamTubeChannel, if the channel is of type * %TP_IFACE_CHANNEL_TYPE_STREAM_TUBE; * * * a #TpDBusTubeChannel, if the channel is of type * %TP_IFACE_CHANNEL_TYPE_DBUS_TUBE; * * * a #TpTextChannel, if the channel is of type * %TP_IFACE_CHANNEL_TYPE_TEXT and implements * %TP_IFACE_CHANNEL_INTERFACE_MESSAGES; * * * a #TpFileTransferChannel, if the channel is of type * %TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER; * * * a #TpCallChannel, if the channel is of type * %TP_IFACE_CHANNEL_TYPE_CALL; * * * a plain #TpChannel, otherwise * * * * It is guaranteed that the objects returned by future versions * will be either the class that is currently used, or a more specific * subclass of that class. * * This factory asks to prepare the following features: * * * * %TP_CHANNEL_FEATURE_CORE, %TP_CHANNEL_FEATURE_GROUP * and %TP_CHANNEL_FEATURE_PASSWORD for all * type of channels. * * * %TP_TEXT_CHANNEL_FEATURE_INCOMING_MESSAGES and * %TP_TEXT_CHANNEL_FEATURE_SMS for #TpTextChannel * * * %TP_FILE_TRANSFER_CHANNEL_FEATURE_CORE * for #TpFileTransferChannel * * * %TP_CALL_CHANNEL_FEATURE_CORE * for #TpCallChannel * * * %TP_DBUS_TUBE_CHANNEL_FEATURE_CORE * for #TpDBusTubeChannel * * * * Since: 0.15.5 */ /** * TpAutomaticClientFactory: * * Data structure representing a #TpAutomaticClientFactory * * Since: 0.15.5 */ /** * TpAutomaticClientFactoryClass: * @parent_class: the parent class * * The class of a #TpAutomaticClientFactory. * * Since: 0.15.5 */ #include "config.h" #include "telepathy-glib/automatic-client-factory.h" #include #include #define DEBUG_FLAG TP_DEBUG_CLIENT #include "telepathy-glib/debug-internal.h" #include "telepathy-glib/automatic-client-factory-internal.h" G_DEFINE_TYPE (TpAutomaticClientFactory, tp_automatic_client_factory, TP_TYPE_SIMPLE_CLIENT_FACTORY) #define chainup ((TpSimpleClientFactoryClass *) \ tp_automatic_client_factory_parent_class) typedef gboolean (*CheckPropertiesFunc) ( const gchar *object_path, const GHashTable *properties); typedef TpChannel *(*NewFunc) ( TpSimpleClientFactory *client, TpConnection *conn, const gchar *object_path, const GHashTable *properties, GError **error); typedef struct { const gchar *channel_type; GType gtype; CheckPropertiesFunc check_properties; NewFunc new_func; /* 0-terminated. All of a sudden, 3 is not such a scary number. */ GQuark features[3]; } ChannelTypeMapping; static ChannelTypeMapping *channel_type_mapping = NULL; static gboolean check_for_messages ( const gchar *object_path, const GHashTable *properties) { /* Create a TpTextChannel only if the channel supports Messages */ const gchar * const * interfaces; interfaces = tp_asv_get_strv (properties, TP_PROP_CHANNEL_INTERFACES); if (!tp_strv_contains (interfaces, TP_IFACE_CHANNEL_INTERFACE_MESSAGES)) { DEBUG ("channel %s doesn't implement Messages so we can't create " "a TpTextChannel", object_path); return FALSE; } return TRUE; } static void build_channel_type_mapping (void) { ChannelTypeMapping i_hate_c[] = { { TP_IFACE_CHANNEL_TYPE_STREAM_TUBE, TP_TYPE_STREAM_TUBE_CHANNEL, NULL, (NewFunc) _tp_stream_tube_channel_new_with_factory, { 0 }, }, { TP_IFACE_CHANNEL_TYPE_DBUS_TUBE, TP_TYPE_DBUS_TUBE_CHANNEL, NULL, (NewFunc) _tp_dbus_tube_channel_new_with_factory, { TP_DBUS_TUBE_CHANNEL_FEATURE_CORE, 0 }, }, { TP_IFACE_CHANNEL_TYPE_TEXT, TP_TYPE_TEXT_CHANNEL, check_for_messages, (NewFunc) _tp_text_channel_new_with_factory, { TP_TEXT_CHANNEL_FEATURE_INCOMING_MESSAGES, TP_TEXT_CHANNEL_FEATURE_SMS, 0 }, }, { TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER, TP_TYPE_FILE_TRANSFER_CHANNEL, NULL, (NewFunc) _tp_file_transfer_channel_new_with_factory, { TP_FILE_TRANSFER_CHANNEL_FEATURE_CORE, 0 }, }, { TP_IFACE_CHANNEL_TYPE_CALL, TP_TYPE_CALL_CHANNEL, NULL, (NewFunc) _tp_call_channel_new_with_factory, { TP_CALL_CHANNEL_FEATURE_CORE, 0 }, }, { NULL } }; g_return_if_fail (channel_type_mapping == NULL); channel_type_mapping = g_memdup (i_hate_c, sizeof i_hate_c); } static TpChannel * create_channel_impl (TpSimpleClientFactory *self, TpConnection *conn, const gchar *object_path, const GHashTable *properties, GError **error) { const gchar *chan_type; ChannelTypeMapping *m; chan_type = tp_asv_get_string (properties, TP_PROP_CHANNEL_CHANNEL_TYPE); for (m = channel_type_mapping; m->channel_type != NULL; m++) { if (tp_strdiff (chan_type, m->channel_type)) continue; if (m->check_properties != NULL && !m->check_properties (object_path, properties)) break; return m->new_func (self, conn, object_path, properties, error); } /* Chainup on parent implementation as fallback */ return chainup->create_channel (self, conn, object_path, properties, error); } static GArray * dup_channel_features_impl (TpSimpleClientFactory *self, TpChannel *channel) { GArray *features; GQuark standard_features[] = { TP_CHANNEL_FEATURE_GROUP, TP_CHANNEL_FEATURE_PASSWORD, }; ChannelTypeMapping *m; /* Chainup to get desired features for all channel types */ features = chainup->dup_channel_features (self, channel); g_array_append_vals (features, standard_features, G_N_ELEMENTS (standard_features)); for (m = channel_type_mapping; m->channel_type != NULL; m++) { if (G_TYPE_CHECK_INSTANCE_TYPE (channel, m->gtype)) { guint j; for (j = 0; m->features[j] != 0; j++) g_array_append_val (features, m->features[j]); break; } } return features; } static void tp_automatic_client_factory_init (TpAutomaticClientFactory *self) { } static void tp_automatic_client_factory_class_init (TpAutomaticClientFactoryClass *cls) { TpSimpleClientFactoryClass *simple_class = (TpSimpleClientFactoryClass *) cls; simple_class->create_channel = create_channel_impl; simple_class->dup_channel_features = dup_channel_features_impl; build_channel_type_mapping (); } /** * tp_automatic_client_factory_new: * @dbus: (allow-none): a #TpDBusDaemon, or %NULL * * Returns a new #TpAutomaticClientFactory instance. If @dbus is %NULL, * tp_dbus_daemon_dup() will be used. * * Returns: a new #TpAutomaticClientFactory * * Since: 0.15.5 */ TpAutomaticClientFactory * tp_automatic_client_factory_new (TpDBusDaemon *dbus) { return g_object_new (TP_TYPE_AUTOMATIC_CLIENT_FACTORY, "dbus-daemon", dbus, NULL); }