diff -r 000000000000 -r d0f3a028347a libtelepathy/src/tp-chan.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libtelepathy/src/tp-chan.c Tue Feb 02 01:10:06 2010 +0200 @@ -0,0 +1,649 @@ +/* tp-chan.c + * + * Copyright (C) 2005 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include "tp-chan.h" +#include "tp-chan-signals-marshal.h" +#include "tp-props-iface.h" +#include "tp-helpers.h" + +#ifdef EMULATOR +#include "libtelepathy_wsd_solution.h" +#endif + +#ifdef EMULATOR + + GET_STATIC_VAR_FROM_TLS(parent_class,tp_chan,GObjectClass *) + #define parent_class (*GET_WSD_VAR_NAME(parent_class,tp_chan,s)()) + + GET_STATIC_VAR_FROM_TLS(type1,tp_chan,GType) + #define type1 (*GET_WSD_VAR_NAME(type1,tp_chan,s)()) + + GET_STATIC_VAR_FROM_TLS(ret1,tp_chan,GQuark) + #define ret1 (*GET_WSD_VAR_NAME(ret1,tp_chan,s)()) + + GET_STATIC_VAR_FROM_TLS(ret2,tp_chan,GQuark) + #define ret2 (*GET_WSD_VAR_NAME(ret2,tp_chan,s)()) + + GET_STATIC_VAR_FROM_TLS(ret3,tp_chan,GQuark) + #define ret3 (*GET_WSD_VAR_NAME(ret3,tp_chan,s)()) + + GET_STATIC_VAR_FROM_TLS(ret4,tp_chan,GQuark) + #define ret4 (*GET_WSD_VAR_NAME(ret4,tp_chan,s)()) + + GET_STATIC_VAR_FROM_TLS(ret5,tp_chan,GQuark) + #define ret5 (*GET_WSD_VAR_NAME(ret5,tp_chan,s)()) + + GET_STATIC_VAR_FROM_TLS(ret6,tp_chan,GQuark) + #define ret6 (*GET_WSD_VAR_NAME(ret6,tp_chan,s)()) + + GET_STATIC_VAR_FROM_TLS(ret7,tp_chan,GQuark) + #define ret7 (*GET_WSD_VAR_NAME(ret7,tp_chan,s)()) + + GET_STATIC_VAR_FROM_TLS(ret8,tp_chan,GQuark) + #define ret8 (*GET_WSD_VAR_NAME(ret8,tp_chan,s)()) + + GET_STATIC_VAR_FROM_TLS(ret9,tp_chan,GQuark) + #define ret9 (*GET_WSD_VAR_NAME(ret9,tp_chan,s)()) + + GET_STATIC_VAR_FROM_TLS(ret10,tp_chan,GQuark) + #define ret10 (*GET_WSD_VAR_NAME(ret10,tp_chan,s)()) + + GET_STATIC_VAR_FROM_TLS(ret11,tp_chan,GQuark) + #define ret11 (*GET_WSD_VAR_NAME(ret11,tp_chan,s)()) + + +#else + static GObjectClass *parent_class = NULL; +#endif + +static void synthesize_closed(TpChan *chan); + +static void _tp_chan_register_signal_marshallers() +{ + /* Register marshaller for the Close signal */ + dbus_g_object_register_marshaller(tp_chan_signals_marshal_VOID__VOID, + G_TYPE_NONE, G_TYPE_INVALID); +} + +static void _tp_chan_register_interface_signal_marshallers() +{ + + /* Register marshaller for ContactSearch interface signal + SearchResultReceived*/ + + dbus_g_object_register_marshaller(tp_ifaces_signals_marshal_VOID__UINT_BOXED, + G_TYPE_NONE, G_TYPE_UINT, G_TYPE_BOXED, G_TYPE_INVALID); + + /* Register marshaller for ContactSearch interface signal + * SearchStateChanged */ + + dbus_g_object_register_marshaller(tp_ifaces_signals_marshal_VOID__UINT, + G_TYPE_NONE, G_TYPE_UINT, G_TYPE_INVALID); + + /* Register marshaller for StreamedMedia interface signal + ReceivedMediaParameters */ + dbus_g_object_register_marshaller(tp_ifaces_signals_marshal_VOID__UINT_STRING_STRING, G_TYPE_NONE, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_INVALID); + /* Register marshaller for StreamedMedia interface signal + StreamStateChanged */ + + dbus_g_object_register_marshaller(tp_ifaces_signals_marshal_VOID__UINT_UINT_UINT, G_TYPE_NONE, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_INVALID); + + /* Register marshaller for RoomList interface signal GotRooms */ + + dbus_g_object_register_marshaller(tp_ifaces_signals_marshal_VOID__BOXED, + G_TYPE_NONE, G_TYPE_BOXED, G_TYPE_INVALID); + + /* Register marshaller for RoomList interface signal ListingRooms */ + dbus_g_object_register_marshaller(tp_ifaces_signals_marshal_VOID__BOOLEAN, + G_TYPE_NONE, G_TYPE_BOOLEAN, + G_TYPE_INVALID); + + /* Register marshaller for channel type Text interface signal Received */ + dbus_g_object_register_marshaller(tp_ifaces_signals_marshal_VOID__UINT_UINT_UINT_UINT_UINT_STRING, G_TYPE_NONE, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, + G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING, + G_TYPE_INVALID); + + /* Register marshaller for channel type Text interface Sent */ + dbus_g_object_register_marshaller(tp_ifaces_signals_marshal_VOID__UINT_UINT_STRING, G_TYPE_NONE, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_INVALID); + + /* Register marshaller used by the following iface/signal pairs: + * DTFM/ReceivedDTMF, Group/GroupFlagsChanged, Hold/HoldStateChanged, + * Password/PasswordFlagsChanged, Subject/SubjectFlagsChanged */ + dbus_g_object_register_marshaller(tp_ifaces_signals_marshal_VOID__UINT_UINT, + G_TYPE_NONE, G_TYPE_UINT, G_TYPE_UINT, + G_TYPE_INVALID); + /* Register marshaller for Group interface signal MembersChanged */ + + dbus_g_object_register_marshaller(tp_ifaces_signals_marshal_VOID__STRING_BOXED_BOXED_BOXED_BOXED_UINT_UINT, G_TYPE_NONE, G_TYPE_STRING, G_TYPE_BOXED, + G_TYPE_BOXED, G_TYPE_BOXED, G_TYPE_BOXED, + G_TYPE_UINT, G_TYPE_UINT,G_TYPE_INVALID); + + /* Register marshaller for Text Channel interface signal SendError */ + dbus_g_object_register_marshaller(tp_ifaces_signals_marshal_VOID__UINT_UINT_UINT_STRING, G_TYPE_NONE, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_INVALID); + + /* Register marshaller for IceSignalling interface signal + NewIceSessionHandler */ + + dbus_g_object_register_marshaller(tp_ifaces_signals_marshal_VOID__OBJECT_STRING, G_TYPE_NONE, DBUS_TYPE_G_OBJECT_PATH, G_TYPE_STRING, G_TYPE_INVALID); + +} + + +/* We initialize the list of signatures here, so that we can use + * it to add them for new interface instances later.*/ + +/* FIXME: This should be replaced by a more automatic way of doing + * this. The reason for using a set of function pointers is that there is no + * apparent cleaner way of doing this, unless DBusGProxy gains a non-varargs + * version of dbus_g_proxy_add_signal... + */ + + +static void _tp_chan_init_interface_signal_signatures(GData **signal_sigs) +{ + g_datalist_init(signal_sigs); + + + /* Create and store contact search iface signal signatures */ + g_datalist_id_set_data(signal_sigs, TELEPATHY_CHAN_IFACE_CONTACTSEARCH_QUARK, + (gpointer)tp_chan_set_contactsearch_signatures); + + /* Store streamed media iface signal signatures */ + g_datalist_id_set_data(signal_sigs, + TELEPATHY_CHAN_IFACE_STREAMED_QUARK, + (gpointer)tp_chan_set_streamedmedia_signatures); + /* Store roomlist signal iface signal parameters */ + g_datalist_id_set_data(signal_sigs, TELEPATHY_CHAN_IFACE_ROOMLIST_QUARK, + (gpointer)tp_chan_set_roomlist_signatures); + /* Store text iface signal signatures */ + g_datalist_id_set_data(signal_sigs, TELEPATHY_CHAN_IFACE_TEXT_QUARK, + (gpointer)tp_chan_set_text_signatures); + /* Store DTMF iface signal signatures */ + g_datalist_id_set_data(signal_sigs, TELEPATHY_CHAN_IFACE_DTMF_QUARK, + (gpointer)tp_chan_set_dtmf_signatures); + /* Store group iface signal signatures */ + g_datalist_id_set_data(signal_sigs, TELEPATHY_CHAN_IFACE_GROUP_QUARK, + (gpointer)tp_chan_set_group_signatures); + /* Store hold iface signatures */ + g_datalist_id_set_data(signal_sigs, TELEPATHY_CHAN_IFACE_HOLD_QUARK, + (gpointer)tp_chan_set_hold_signatures); + /* Store password iface signatures */ + g_datalist_id_set_data(signal_sigs, TELEPATHY_CHAN_IFACE_PASSWORD_QUARK, + (gpointer)tp_chan_set_password_signatures); +} + +static void tp_chan_init(GTypeInstance *instance, gpointer g_class) +{ + TpChan *self = TELEPATHY_CHAN(instance); + self->type = NULL; + self->first_run = TRUE; +} + + +static void tp_chan_dispose(GObject *obj) +{ + TpChan *self = TELEPATHY_CHAN(obj); + + if (self->first_run) + { + self->first_run = FALSE; + synthesize_closed(self); + g_datalist_clear(&(self->interface_list)); + } + + /* Chain up to the parent class dispose */ + if (G_OBJECT_CLASS(parent_class)->dispose) + { + G_OBJECT_CLASS(parent_class)->dispose(obj); + } + +} + + +static void tp_chan_finalize(GObject *obj) +{ + TpChan *self = TELEPATHY_CHAN(obj); + + if (self->type) + { + g_free(self->type); + } + + if (G_OBJECT_CLASS(parent_class)->finalize) + { + G_OBJECT_CLASS(parent_class)->finalize(obj); + } +} + + +static void tp_chan_class_init(TpChanClass *klass) +{ + GObjectClass *obj = G_OBJECT_CLASS(klass); + parent_class = g_type_class_peek_parent(klass); + + obj->set_property = parent_class->set_property; + obj->get_property = parent_class->get_property; + obj->dispose = tp_chan_dispose; + obj->finalize = tp_chan_finalize; + _tp_chan_register_signal_marshallers(); + _tp_chan_register_interface_signal_marshallers(); + _tp_chan_init_interface_signal_signatures(&(klass->iface_signal_sigs)); +} + + +GType tp_chan_get_type(void) +{ +#ifndef EMULATOR + static GType type1 = 0; +#endif + + if (type1 == 0) + { + static const GTypeInfo info = + { + sizeof(TpChanClass), + NULL, + NULL, + (GClassInitFunc)tp_chan_class_init, + NULL, + NULL, + sizeof(TpChan), + 0, + (GInstanceInitFunc)tp_chan_init + }; + type1 = g_type_register_static(DBUS_TYPE_G_PROXY, + "TpChan", &info, 0); + } + return type1; +} + + + +/* Public functions begin */ + +GQuark tp_get_chan_interface() +{ +#ifndef EMULATOR + static GQuark ret1 = 0; +#endif + + if (ret1 == 0) + { + ret1 = g_quark_from_static_string(TP_IFACE_CHANNEL_INTERFACE); + } + + return ret1; +} + +GQuark tp_get_chan_contactlist_interface() +{ +#ifndef EMULATOR + static GQuark ret2 = 0; +#endif + + if (ret2 == 0) + { + ret2 = g_quark_from_static_string(TP_IFACE_CHANNEL_TYPE_CONTACT_LIST); + } + + return ret2; +} + + +#ifdef SYMBIAN +EXPORT_C +#endif +GQuark tp_get_chan_contactsearch_interface() +{ +#ifndef EMULATOR + static GQuark ret3 = 0; +#endif + + if (ret3 == 0) + { + ret3 = g_quark_from_static_string(TP_IFACE_CHANNEL_TYPE_CONTACT_SEARCH); + } + + return ret3; +} + + +GQuark tp_get_chan_streamed_interface() +{ +#ifndef EMULATOR + static GQuark ret4 = 0; +#endif + + if (ret4 == 0) + { + ret4 = g_quark_from_static_string(TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA); + } + + return ret4; +} + + +GQuark tp_get_chan_roomlist_interface() +{ +#ifndef EMULATOR + static GQuark ret5 = 0; +#endif + + if (ret5 == 0) + { + ret5 = g_quark_from_static_string(TP_IFACE_CHANNEL_TYPE_ROOM_LIST); + } + + return ret5; +} + +#ifdef SYMBIAN +EXPORT_C +#endif +GQuark tp_get_chan_text_interface() +{ +#ifndef EMULATOR + static GQuark ret6 = 0; +#endif + + if (ret6 == 0) + { + ret6 = g_quark_from_static_string(TP_IFACE_CHANNEL_TYPE_TEXT); + } + + return ret6; +} + + +GQuark tp_get_chan_dtmf_interface() +{ +#ifndef EMULATOR + static GQuark ret7 = 0; +#endif + + if (ret7 == 0) + { + ret7 = g_quark_from_static_string(TP_IFACE_CHANNEL_INTERFACE_DTMF); + } + + return ret7; +} + + +#ifdef SYMBIAN +EXPORT_C +#endif +GQuark tp_get_chan_group_interface() +{ +#ifndef EMULATOR + static GQuark ret8 = 0; +#endif + + if (ret8 == 0) + { + ret8 = g_quark_from_static_string(TP_IFACE_CHANNEL_INTERFACE_GROUP); + } + + return ret8; +} + + +GQuark tp_get_chan_hold_interface() +{ +#ifndef EMULATOR + static GQuark ret9 = 0; +#endif + + if (ret9 == 0) + { + ret9 = g_quark_from_static_string(TP_IFACE_CHANNEL_INTERFACE_HOLD); + } + + return ret9; +} + + +GQuark tp_get_chan_password_interface() +{ +#ifndef EMULATOR + static GQuark ret10 = 0; +#endif + + if (ret10 == 0) + { + ret10 = g_quark_from_static_string(TP_IFACE_CHANNEL_INTERFACE_PASSWORD); + } + + return ret10; +} + +GQuark tp_get_chan_transfer_interface() +{ +#ifndef EMULATOR + static GQuark ret11 = 0; +#endif + + if (ret11 == 0) + { + ret11 = g_quark_from_static_string(TP_IFACE_CHANNEL_INTERFACE_TRANSFER); + } + + return ret11; +} + + +#ifdef SYMBIAN +EXPORT_C +#endif +TpChan *tp_chan_new(DBusGConnection *connection, const gchar *bus_name, + const gchar *object_path, const gchar *type, + guint handle_type, guint handle) +{ + GError *error = NULL; + gchar *unique_name; + gchar **interfaces; + TpChan *chan; + g_return_val_if_fail(connection != NULL, NULL); + g_return_val_if_fail(bus_name != NULL, NULL); + g_return_val_if_fail(object_path != NULL, NULL); + g_return_val_if_fail(type != NULL, NULL); + + if (!dbus_g_proxy_call (tp_get_bus_proxy (), + "GetNameOwner", &error, G_TYPE_STRING, bus_name, + G_TYPE_INVALID, G_TYPE_STRING, &unique_name, + G_TYPE_INVALID)) + { + g_warning("tp_chan_new: getting unique name failed: %s", error->message); + g_error_free(error); + return NULL; + } + + /* Create the channel object */ + chan = g_object_new(TELEPATHY_CHAN_TYPE, + "name", unique_name, "path", object_path, + "interface", TP_IFACE_CHANNEL_INTERFACE, + "connection", connection, NULL); + + g_free(unique_name); + + dbus_g_proxy_add_signal(DBUS_G_PROXY(chan), "Closed", G_TYPE_INVALID); + + g_datalist_init(&(chan->interface_list)); + + /* Store interface information for the channel */ + if (tp_chan_get_interfaces(DBUS_G_PROXY(chan), &interfaces, &error)) + { + tp_chan_local_set_interfaces(chan, interfaces); + + /* Free the strings used for interface object creation */ + g_strfreev(interfaces); + } + else + { + g_warning("GetInterfaces for channel failed: %s\n", error->message); + g_error_free(error); + } + + /* Store necessary information for this object */ + chan->type = g_strdup(type); + chan->handle_type = handle_type; + chan->handle = handle; + + return chan; +} + + +void tp_chan_local_set_interfaces(TpChan *self, gchar **interfaces) +{ + gchar **temp_ifaces; + gchar *chan_type = NULL; + GError *error = NULL; + GData **sig_list = &(TELEPATHY_CHAN_GET_CLASS(self)->iface_signal_sigs); + void (*signature_setter_func)(DBusGProxy *proxy); + DBusGConnection *connection; + /*const*/ gchar *name, *path; + + if (interfaces == NULL) + { + return; + } + + /* Create and store proxy objects corresponding to the + interfaces */ + + g_object_get (G_OBJECT(self), + "connection", &connection, + "name", &name, + "path", &path, + NULL); + + g_debug ("%s: %p, %s, %s", G_STRFUNC, connection, name, path); + + for (temp_ifaces = interfaces; *temp_ifaces; temp_ifaces++) + { + GQuark key = g_quark_from_string(*temp_ifaces); + DBusGProxy *if_proxy; + + if (key == TELEPATHY_PROPS_IFACE_QUARK) + { + if_proxy = DBUS_G_PROXY (tp_props_iface_new (connection, name, path)); + } + else + { + if_proxy = dbus_g_proxy_new_for_name (connection, name, + path, *temp_ifaces); + + if (if_proxy != NULL) + { + /* Does the interface have signals? If yes, add their signatures + for the interface instance by calling the + corresponding setter function */ + + signature_setter_func = + g_datalist_id_get_data(sig_list, key); + + if (signature_setter_func != NULL) + { + (*signature_setter_func)(if_proxy); + } + } + } + if (if_proxy != NULL) + { + g_datalist_id_set_data_full(&(self->interface_list), key, + if_proxy, g_object_unref); + } + } + + /* Finally, add the channel type interface */ + + if (!tp_chan_get_channel_type(DBUS_G_PROXY(self), &chan_type, &error)) + { + g_warning("GetChannelType failed: %s\n", error->message); + g_error_free(error); + } + else + { + DBusGProxy *chan_proxy = + dbus_g_proxy_new_from_proxy(DBUS_G_PROXY(self), chan_type, NULL); + + g_datalist_id_set_data(&(self->interface_list), + g_quark_from_string(chan_type), chan_proxy); + + /* If the particular channel type interface has signals defined, + call the corresponding setter function */ + + signature_setter_func = + g_datalist_id_get_data(sig_list, g_quark_from_string(chan_type)); + + if (signature_setter_func != NULL) + { + (*signature_setter_func)(chan_proxy); + } + + g_free(chan_type); + } + + g_free (name); + g_free (path); + dbus_g_connection_unref (connection); +} + +#ifdef SYMBIAN +EXPORT_C +#endif +DBusGProxy *tp_chan_get_interface(TpChan *self, GQuark iface_quark) +{ + DBusGProxy *iface_proxy = NULL; + + iface_proxy = (DBusGProxy *)g_datalist_id_get_data(&(self->interface_list), + iface_quark); + return iface_proxy; +} + +static void synthesize_closed(TpChan *chan) +{ + DBusMessage *msg = NULL; + GArray *closed_signal_types = g_array_new(FALSE, FALSE, sizeof(GType)); + + if (!closed_signal_types) + { + g_warning("%s: Could not allocate the type array for Closed signal", + G_STRFUNC); + return; + } + + msg = dbus_message_new_signal(dbus_g_proxy_get_path(DBUS_G_PROXY(chan)), + TP_IFACE_CHANNEL_INTERFACE, "Closed"); + if (!msg) + { + g_warning("%s: Could not create the synthetic Closed signal message.", + G_STRFUNC); + g_array_free(closed_signal_types, FALSE); + return; + } + g_signal_emit_by_name(DBUS_G_PROXY(chan), + TP_IFACE_CHAN_SIGNAL_CLOSED_SYNTHESIZED, msg, + closed_signal_types); + g_array_free(closed_signal_types, FALSE); + dbus_message_unref(msg); +}